appllama-app-design-skill
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, navigation, typography, dark mode, or perceived performance. Enforces Apple HIG fidelity, semantic colors, native controls, anti-slop discipline, navigation semantics, purposeful Reanimated motion, a full-motion simulator-verified iteration loop, and a study-real-apps-first workflow.
Install
npx skills add https://github.com/Appllama/appllama-skills --skill appllama-app-design-skillMotion — Reanimated patterns that read as native
Motion quality is judged in the first 10 seconds of using an app. This file is the working reference for gesture-driven and system-driven animation.
The two families of motion
Mixing them up is the #1 tell of non-native motion: a sheet that closes on a fixed 300 ms timing after a fling feels dead; a button that springs for 800 ms on tap feels like a toy.
Springs
- Always pass the gesture velocity into the spring when a gesture releases.
- One spring vocabulary per app. Define
SNAP/POPonce, import everywhere.
Gesture → animation, all on the UI thread
Rules:
- Never read/write React state inside
onChange.scheduleOnRNonly at gesture end, for navigation/effects — and read/write shared values with.get()/.set(), never during render. - Thresholds combine distance OR velocity — a fast flick from 10 px away must dismiss.
- Interruptible: starting a new gesture mid-spring must grab the current animated value, not the destination.
Entrances, exits, layout
- Stagger list entrances by index (
delay(index * 40)), cap the stagger at ~8 items — beyond that, enter as a block. - Exits are always faster than entrances (~0.7×).
layouttransitions on containers whose children reorder/resize — this is what makes filter chips, expanding cards, and reordering lists feel expensive.
Shared-element feel without shared elements
True shared-element transitions are still niche; fake the continuity:
- Keep the tapped thumbnail's position stable while the detail screen fades in
over it (measure with
measure()in a worklet). - Match corner radius and aspect ratio between the origin card and the destination hero so the eye reads them as the same object.
Scroll-linked effects
Standard native behaviors worth reproducing exactly:
- Large title collapses into the nav bar between ~0 and ~52 pt of scroll.
- Content scrolling under a translucent bar gets a fade/blur mask, not a hard clip.
- Overscroll stretch on hero images (
interpolatenegative offsets into scale).
Reduce Motion
Every spatial animation needs its cross-fade fallback. This is an accessibility requirement, not a nice-to-have.
Performance guardrails
- Animate only
transformandopacitywhere possible; animating layout props (width/height/padding) forces layout every frame. - One
useAnimatedStyleper animated node; don't share a giant style across 20 list items. - Never allocate inside a worklet's hot path (no
.map, no object spread per frame). - If a transition stutters: profile first (see performance.md) — the usual culprits are a JS-thread stall from a heavy render committed mid-animation, or an image decode on the UI thread.