skill by
@appllamaBuild native-feeling, benchmark-quality mobile app screens (Expo / React Native). Use when designing or implementing any mobile UI — screens, flows, onboarding, paywalls, tab bars, sheets, settings, empty states — or when polishing motion, gestures, navigation, typography, dark mode, or perceived performance. Enforces Apple HIG fidelity, semantic colors, native controls, anti-slop discipline, navigation semantics (push vs replace, modal vs sheet vs overlay, the one-way doors where back must not exist), a strict motion bar (frequency gate, exact springs/curves/durations, UI-thread discipline, haptics), a full-motion simulator-verified iteration loop, and a study-real-apps-first workflow (pairs with the Appllama MCP). Trigger on "build a screen", "make this screen better", "design the onboarding", "wire up this flow", "add a bottom sheet", "polish the UI", "make it feel native", "review the animations", or any mobile design/implementation task.
Permissions
Files
Build native-feeling, benchmark-quality mobile app screens (Expo / React Native). Use when designing or implementing any mobile UI — screens, flows, onboarding, paywalls, tab bars, sheets, settings, empty states — or when polishing motion, gestures, navigation, typography, dark mode, or perceived performance. Enforces Apple HIG fidelity, semantic colors, native controls, anti-slop discipline, navigation semantics (push vs replace, modal vs sheet vs overlay, the one-way doors where back must not exist), a strict motion bar (frequency gate, exact springs/curves/durations, UI-thread discipline, haptics), a full-motion simulator-verified iteration loop, and a study-real-apps-first workflow (pairs with the Appllama MCP). Trigger on "build a screen", "make this screen better", "design the onboarding", "wire up this flow", "add a bottom sheet", "polish the UI", "make it feel native", "review the animations", or any mobile design/implementation task.
Install
It’s free, and every skill you add syncs into every AI tool on your computer, instantly.
Version history
You are building screens that will sit on a phone next to the best-designed apps in the world. The user will compare your output to those apps within seconds of launching it. This skill defines the bar and the method for clearing it.
Never design a screen from imagination when you can study how top apps solved the same screen. Real, shipping, revenue-ranked apps encode thousands of hours of design iteration and A/B testing. Your first move on any screen is research:
appllama-usage skill for the exact
research playbooks). Study 20–30 screens before writing a line of UI code.Default stack assumptions (override only if the project already differs):
formSheet routes, NativeTabs),
React Native, TypeScript.react-native-reanimated 4 + react-native-worklets for motion,
react-native-gesture-handler for gestures, expo-haptics,
react-native-keyboard-controller for anything that tracks the keyboard,
@shopify/flash-list (v2) for any list that can grow.expo-image for images (and SF Symbols via source="sf:name" on iOS),
expo-video / expo-audio (never the deprecated expo-av).react-native-safe-area-context for insets. Never hard-code notch numbers.process.env.EXPO_OS over Platform.OS for compile-time platform checks.npx expo install <pkg> so versions match the SDK; never
hand-roll a component a listed package already solves
(references/native-controls.md has the picks).These are the details that separate "web page in a wrapper" from "native app". Violating any of them is a finding, not a style preference.
Color from expo-router on iOS: Color.ios.label,
Color.ios.secondarySystemBackground; Material dynamic colors on Android).
Every screen must render correctly in light AND dark before it is "done".
Never pass semantic color objects into Reanimated animated styles — resolve
to strings first.expo-image with sf: sources, or expo-symbols); they inherit weight,
optical size, and Dynamic Type behavior. Do not mix three icon families on
one screen.fontVariant: ['tabular-nums']) for anything that counts, times,
or prices. Text selectable on data users may want to copy.borderCurve: 'continuous' on every rounded
rectangle. Squircles are the single cheapest "feels iOS" win that exists.boxShadow, not legacy shadow*/elevation props.
Shadows are for elevation logic, not decoration — one elevation system per
app.gap over margin stacking. ScrollView padding goes in
contentContainerStyle, never on the ScrollView itself.selectionAsync when a value ticks past a
step, light impact when something snaps home or a drag commits,
notification success/error for outcomes. Same frame as the visual, one
per user action, never the only feedback — and never on scroll, never
per frame, never on an entrance the user didn't cause.Navigation is the part of a screen you can't screenshot, and users feel it within ten seconds. Every transition answers three questions: what is the destination to here (deeper → push; a self-contained task → modal; a short interruption → form sheet; must see through → overlay; a replacement of where I am → replace), must the user be able to come back, and what does back do afterwards — chevron, edge swipe, Android hardware back, active-tab re-tap. The full method, verb by verb and case by case, is references/navigation.md. The laws:
router.push when the user will
want to return here; router.replace / <Redirect> when coming back
would land in a state the world has moved past. Don't rely on
navigate to unwind — dismissTo(href) says "finish and land on X".modal with its own stack and its own Cancel/Done; a short interruption
is a formSheet with detents; immersive content is a fullScreenModal
with an explicit Close; something that must sit on top of a visible
screen is a transparentModal overlay; destructive confirms are action
sheets; item actions are context menus; tasks the OS already owns —
share, open a web page, pick a photo, compose mail, rate the app — are
system controllers, never routes. A sheet that grows a second step was a
modal all along. If a link could open it, it is a route.Stack.Protected guards and
replace so back can never re-enter the old state — Android back from
home exits the app, never shows Login; a paid paywall never re-opens.
But keep the user's place: sign-in demanded by one action (save,
follow, buy) is a modal over the screen that closes and completes the
action there — never a replace('/(tabs)') — and a paywall opened from a
feature dismisses back onto the feature, unlocked, not to a tab root.usePreventRemove, never to keep someone in
a funnel. One more case consumes back without blocking it: transient
in-screen state — selection/edit mode, an expanded search field, an
open in-screen sheet — clears on the first back and the next back
leaves the screen (BackHandler in useFocusEffect, returning true
only while that state is up; usePreventRemove when iOS should hold
too). A BackHandler that returns true to keep someone on a screen
is a defect. Everywhere else the iOS edge swipe and Android hardware
back work, always.AI-built apps share a look, and users file it under "template" within seconds. Each of these is a default ban — there is always an override when the brand explicitly asks for the thing AND you can articulate why it fits this product.
Motion is the highest-leverage polish surface and the easiest to overdo. Decisions are made in order — the method, the exact values and the implementation are in references/motion.md; the physics of feel in references/fluid-interfaces.md.
animation value like fade
for an overlay is the platform; a JS-rebuilt transition or a changed
duration is not). Passing this gate with zero lines of code is a success.formSheet for sheets, NativeTabs for tabs, native menus
for menus. transform and opacity only (an absolute, childless element
may animate width); never scale(0).SETTLE { duration: 400, dampingRatio: 1 },
SNAP { 400, 0.8 }, SHEET { 300, 0.8 }; bounce only after momentum.Easing.bezier(0.23, 1, 0.32, 1) to enter/exit, (0.77, 0, 0.175, 1) to
move on screen; never ease-in on an entrance or an on-screen change (a
Material-styled app's exits may use M3's accelerate curve — motion.md §5).
Press feedback 100–150 ms, on press-in, matched to the element class —
scale 0.97 for buttons/cards/tiles, a background highlight (never scale)
for list rows and cells, opacity for bar buttons and plain-text actions.
Exits faster than entrances, along the same path.setState in a gesture or scroll handler, no
scheduleOnRN/runOnJS per frame, no shared-value reads in render, no
PanResponder, no entering on recycled list rows, no animated height
to collapse a header, no JS-rebuilt screen transition.Screens that feel great are screens whose state is boring:
useEffect+fetch.TextInputs for high-frequency typing surfaces; controlled
inputs are a top-3 cause of typing jank.router.prefetch / <Link prefetch>
plus its data), not on navigation-complete.expo-image with recyclingKey in lists,
thumbhash/blurhash placeholders.When a screen calls for illustration, empty-state art, hero imagery, or icons beyond the symbol set:
A screen does not exist until you have seen it running. The loop:
Do not declare a screen finished from code review alone. Do not stop at "looks fine" — stop at "cannot find a flaw at 100% zoom".
Every flow is evaluated as moving pictures in the simulator, never as
stills. Screen-record the entire flow end to end
(xcrun simctl io booted recordVideo flow.mov), exercising ALL of it:
Watch the recording twice: once at full speed for feel, once scrubbing frame by frame. You are hunting:
The whole recording must play like one native piece — smooth end to end, zero UX glitches. One glitchy frame means the flow is not done.
| File | Load when |
|---|---|
| references/navigation.md | Wiring any screen into a flow: push vs replace vs dismissTo, modal vs form sheet vs overlay, tabs, deep links, and the one-way doors where back must not exist — plus the back-stack audit |
| references/native-controls.md | Choosing/wiring iOS+Android native controls, menus, pickers, sheets, forms; the library picks |
| references/motion.md | Any motion: the decision sequence (frequency gate → purpose → tool → properties → spring/curve → thread), exact values, haptics, reduced motion, the never-ship list |
| references/motion-recipes.md | Building a press, a drag-to-dismiss sheet, swipe-to-delete, a collapsing header, list entrances, keyboard-synced UI, a tab indicator, a toast, a threshold haptic |
| references/fluid-interfaces.md | Anything a finger drags, anything translucent, anything that gives feedback: response, interruptibility, velocity hand-off, projection, rubber-banding, materials & depth, the design principles |
| references/motion-review.md | Reviewing a diff's motion, auditing an app's motion into plans, or hunting for (and rejecting) places that could animate |
| references/motion-vocabulary.md | Decoding a loose brief ("make it bouncy") or writing a motion spec with exact terms |
| references/variant-lab.md | An open brief or a hero screen where direction matters: build 3 divergent variants behind a dev-only switcher and let the user pick |
| references/performance.md | Jank, slow TTI, big bundles, memory leaks, profiling method |
| references/image-assets.md | Generating illustrations/icons/hero art with image models |
| references/simulator-loop.md | Final verification checklist (layout, theming, motion, interaction, navigation & back stack, state) + device matrix |
In these kits
More from @appllama
Works with
Claude, Codex, Cursor & morecontentInsetAdjustmentBehavior="automatic". Use useWindowDimensions,
never Dimensions.get().initialRouteName,
withAnchor) so back has somewhere to go; cold start lands by state; a
link or notification tapped while signed out is stashed and replayed
after sign-in; tapped while warm, the target lands on top and back
returns to where the user was.fade — feedback survives;
and no animation targets a height measured at default text size.