← AppllamaCONTENT HISTORY

Update to Appllama

Snapshot Sep 30, 2026 · 22:57 UTC · version 1.0.0

Collection source: not recorded for this historical snapshot.

WHAT CHANGED · RULE-BASED ANALYSIS

First saved snapshot

No earlier snapshot is available to establish a change.

Compare saved observations

Download comparison JSON
Full technical diff · 0 changed fields
Full snapshot data
{
  "name": "appllama-app-design-skill",
  "description": "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 (push vs replace, modal vs sheet vs overlay, the one-way doors where back must not exist), purposeful Reanimated motion, 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\", \"polish the UI\", \"make it feel native\", or any mobile design/implementation task.",
  "included_files": [
    {
      "relative_path": "references/image-assets.md",
      "size_in_bytes": 3622
    },
    {
      "relative_path": "references/motion.md",
      "size_in_bytes": 4469
    },
    {
      "relative_path": "references/native-controls.md",
      "size_in_bytes": 4565
    },
    {
      "relative_path": "references/performance.md",
      "size_in_bytes": 3293
    },
    {
      "relative_path": "references/simulator-loop.md",
      "size_in_bytes": 3971
    }
  ],
  "skill_md_contents": "---\nname: appllama-app-design-skill\ndescription: 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 (push vs replace, modal vs sheet vs overlay, the one-way doors where back must not exist), purposeful Reanimated motion, 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\", \"polish the UI\", \"make it feel native\", or any mobile design/implementation task.\nlicense: MIT\nmetadata:\n  author: Appllama (appllama.io)\n  version: 1.3.0\n---\n\n# Appllama App Design Skill\n\nYou are building screens that will sit on a phone next to the best-designed apps\nin the world. The user will compare your output to those apps within seconds of\nlaunching it. This skill defines the bar and the method for clearing it.\n\n## The Prime Directive: study before you draw\n\nNever design a screen from imagination when you can study how top apps solved\nthe same screen. Real, shipping, revenue-ranked apps encode thousands of hours\nof design iteration and A/B testing. Your first move on any screen is research:\n\n1. If the **Appllama MCP** is connected, pull real screens for the category and\n   screen type you are building (see the `appllama-usage` skill for the exact\n   research playbooks). Study 20–30 screens before writing a line of UI code.\n2. Extract the **pattern, not the pixels**: layout skeleton, information\n   hierarchy, control choices, spacing rhythm, where the primary CTA sits, what\n   gets an illustration vs. plain text, how progress is communicated.\n   Note: every Appllama image and video carries a small Appllama watermark in\n   the top-left corner. It is provenance, not design — ignore it when reading\n   a screen (it may sit over the status bar or a back button) and never\n   reproduce it in anything you build.\n3. Then design **your** screen: same proven skeleton, your product's voice.\n   Copying a competitor's screen 1:1 is both lazy and legally risky; shipping a\n   screen that ignores every convention users already know is worse.\n\n## Platform baseline\n\nDefault stack assumptions (override only if the project already differs):\n\n- **Expo + Expo Router**, React Native, TypeScript.\n- `react-native-reanimated` for motion, `react-native-gesture-handler` for\n  gestures, `@shopify/flash-list` (or FlashList v2) for any list that can grow.\n- `expo-image` for images (and SF Symbols via `source=\"sf:name\"` on iOS),\n  `expo-video` / `expo-audio` (never the deprecated `expo-av`).\n- `react-native-safe-area-context` for insets. Never hard-code notch numbers.\n- `process.env.EXPO_OS` over `Platform.OS` for compile-time platform checks.\n\n## Native fidelity laws\n\nThese are the details that separate \"web page in a wrapper\" from \"native app\".\nViolating any of them is a finding, not a style preference.\n\n1. **Semantic colors, both themes, day one.** Use system/semantic color tokens\n   (e.g. `Color` from `expo-router` on iOS: `Color.ios.label`,\n   `Color.ios.secondarySystemBackground`; Material dynamic colors on Android).\n   Every screen must render correctly in light AND dark before it is \"done\".\n   Never pass semantic color objects into Reanimated animated styles — resolve\n   to strings first.\n2. **Native controls over rebuilt ones.** Switch, Slider, SegmentedControl,\n   context menus, date pickers: use the native control or a faithful wrapper.\n   A rebuilt toggle that animates 50 ms differently than iOS's reads as fake\n   instantly.\n3. **SF Symbols / Material Symbols for iconography.** On iOS prefer SF Symbols\n   (`expo-image` with `sf:` sources, or `expo-symbols`); they inherit weight,\n   optical size, and Dynamic Type behavior. Do not mix three icon families on\n   one screen.\n4. **Typography is hierarchy.** Use the platform type ramp (Large Title / Title\n   / Headline / Body / Footnote on iOS). One display size per screen. Tabular\n   numerals (`fontVariant: ['tabular-nums']`) for anything that counts, times,\n   or prices. `Text selectable` on data users may want to copy.\n5. **Continuous corners.** `borderCurve: 'continuous'` on every rounded\n   rectangle. Squircles are the single cheapest \"feels iOS\" win that exists.\n6. **Shadows via CSS `boxShadow`**, not legacy `shadow*`/`elevation` props.\n   Shadows are for elevation logic, not decoration — one elevation system per\n   app.\n7. **Spacing rhythm.** Pick a base unit (4 or 8) and never leave it. Prefer\n   flexbox `gap` over margin stacking. ScrollView padding goes in\n   `contentContainerStyle`, never on the ScrollView itself.\n8. **Safe areas and the Dynamic Island are part of the design.** Screens must\n   be verified with content scrolled under the island / status bar (does the\n   blur/fade treatment hold?), with the home indicator (does the bottom CTA\n   clear it?), and in landscape if supported.\n9. **Navigation titles belong to the navigator.** Use the stack's native title\n   (and large-title collapse behavior on iOS) rather than a hand-rolled header\n   whenever possible.\n10. **Haptics are punctuation.** Selection tick when a value passes a step,\n    light impact when something snaps home, notification success/error for\n    outcomes — on the same frame as the visual, one per user action, never\n    the only feedback. Never on scroll, never in loops.\n11. **Format numbers like a product, not a database**: 1.4M, 38k, $4.99. Trim\n    trailing zeros. Localize dates.\n12. **Root scroll behavior**: screens that can ever overflow wrap content in a\n    ScrollView (first component in the route) with\n    `contentInsetAdjustmentBehavior=\"automatic\"`. Use `useWindowDimensions`,\n    never `Dimensions.get()`.\n\n## Navigation laws\n\nNavigation is the part of a screen a screenshot can't show, and users feel\nit in ten seconds. Every transition answers three questions: what is the\ndestination to here, must the user be able to come back, and what does back\n(chevron, iOS edge swipe, Android hardware back) do afterwards.\n\n1. **Push goes deeper, replace moves on.** `router.push` when the user will\n   want to return here; `router.replace` / `<Redirect>` when coming back\n   would land in a state the world has moved past; `router.dismissTo(href)`\n   for \"finish this flow and land on X\". Back undoes *navigation*, never\n   *events*.\n2. **Presentation is meaning.** A self-contained task with steps →\n   `presentation: 'modal'` with its own stack and its own Cancel/Done; a\n   short interruption (picker, filters, item options) → `formSheet` with\n   detents, drag-to-dismiss; immersive content → `fullScreenModal` with an\n   explicit Close; something floating over a still-visible screen (confirm\n   card, lightbox, coach mark) → `transparentModal` overlay; destructive\n   confirms → action sheet; item actions → native context menu; share /\n   web / photo picking → the system controller, never a rebuilt route. A\n   sheet that grows a second step was a modal all along; if a link could\n   open it, it is a route, not a `useState` sheet.\n3. **One-way doors leave the stack.** Sign-in on a wall app, finished\n   onboarding (Skip included), a purchase, a completed session: guard with\n   `Stack.Protected` and land with `replace`, so back can never re-enter\n   the old state — Android back from home exits the app, never shows\n   Login; a paid paywall never re-opens. But keep the user's *place*:\n   sign-in demanded by one action (save, follow, buy) is a modal over the\n   screen that completes the action where it was tapped, and a paywall\n   opened from a feature dismisses back onto the feature, unlocked — never\n   `replace('/(tabs)')` from there.\n4. **Back is blocked in exactly two cases** — an irreversible request in\n   flight (seconds, with visible progress) and unsaved work in a modal\n   (ask first), both via `usePreventRemove` on the modal's root screen.\n   Transient in-screen state (selection mode, an expanded search, an open\n   in-screen sheet) consumes the first back, then back leaves. Anything\n   else that traps back — a funnel, a rating prompt — is a defect; the\n   edge swipe works everywhere else.\n5. **Tabs are peers.** No slide between tabs, each tab keeps its own stack,\n   re-tapping the active tab pops to its root; full-attention screens\n   (composer, player, checkout) live in the root stack *above* the tabs.\n   Deep links land with a real stack underneath (`initialRouteName` /\n   `withAnchor`); cold start lands by state, splash held until session\n   state has resolved — never a Login flash before Home.\n6. **Study the grammar, not just the pixels.** Walking a winning flow on\n   Appllama, note what each step *is* — push, modal, sheet — and copy that\n   consistency.\n\n## Anti-slop laws\n\nAI-built apps share a look, and users file it under \"template\" within seconds.\nEach of these is a *default ban* — there is always an override when the brand\nexplicitly asks for the thing AND you can articulate why it fits this product.\n\n1. **No AI-default styling.** Purple/indigo gradient CTAs with a glow,\n   glassmorphism on every card, mesh-gradient heroes, confetti for minor\n   events, sparkles in headings — that is the model's house style, not\n   design. Your palette, materials, and layout come from the reference\n   screens you studied, never from the priors you'd reach for unprompted.\n2. **One accent, locked.** Pick one accent color and it is THE accent on\n   every screen — no blue CTA on one screen and teal on the next, no new hue\n   appearing in screen seven. Neutrals carry the app; the accent is spent\n   where the money is (primary action, active state, progress).\n3. **One grey family.** Warm greys or cool greys — never both in one app.\n4. **Shape lock.** One corner-radius scale, stated as a rule (\"actions are\n   pills, cards 16, inputs 8\") and never violated. Mixed radii without a\n   stated rule read as assembled-from-parts.\n5. **No emoji as iconography.** Icons are SF Symbols / Material Symbols\n   (fidelity law 3). Emoji appear only when the product's voice is genuinely\n   chat-native or playful — sparingly, in content, never in chrome.\n6. **One label per intent.** \"Get started\", \"Start now\", and \"Begin\" are the\n   same intent — pick one phrasing and use it everywhere it appears.\n7. **Emphasis stays in the family.** Emphasize a word with weight or italic\n   of the same typeface; injecting a serif word into a sans headline (or vice\n   versa) for visual interest is amateur.\n8. **Ship full state cycles, not the happy path.** Static-successful-state-\n   only is the default failure mode: skeletons must match the final layout's\n   shape, empty states are composed (and say how to fill them), errors are\n   inline and specific.\n9. **The slop pre-flight is mechanical.** Before any flow reaches the\n   simulator pass, count: distinct accent hues (must be 1), distinct corner\n   radii (all from the stated scale), emoji in UI chrome (0), gradients\n   without a brand reason (0), duplicate labels for one intent (0). A failed\n   count is a fix, not a judgment call.\n\n## Motion laws\n\nMotion is the highest-leverage polish surface and the easiest to overdo.\nDecide in this order:\n\n- **The frequency gate comes first.** Met 100+ times a day (tab switch,\n  keyboard, scroll, back) → the platform default and nothing else; tens a\n  day (press, row select) → near-imperceptible, under 150 ms; occasional\n  (sheets, modals, toasts) → standard motion; delight only on rare,\n  first-time moments. Tabs never slide; screen transitions stay native.\n  Passing this gate with zero lines of code is a success — when unsure,\n  the strongest move is to delete the animation.\n- **Name the purpose in one word** — feedback, spatial continuity, state\n  change, preventing a jarring cut, explanation, delight — or don't build\n  it. Data the user is reading never moves for style.\n- **If a finger was involved, it's a spring.** Start from the live value\n  (capture it on grab), hand the release velocity into the spring, pick\n  the target from projected momentum so a flick commits, rubber-band past\n  boundaries, stay grabbable mid-flight. One vocabulary per app —\n  `{ duration: 400, dampingRatio: 1 }` to settle, `{ 300, 0.8 }` for\n  sheets — and bounce only when the gesture carried momentum.\n- **Everything else is timing, under 300 ms, strong ease-out**\n  (`Easing.bezier(0.23, 1, 0.32, 1)` — built-in curves are too weak; never\n  ease-in on an entrance). Press feedback lands on press-*in*, 100–150 ms:\n  scale 0.97 on buttons and cards, a background highlight (never scale) on\n  list rows, opacity on bar buttons. Exits are faster than entrances and\n  leave the way they came in; enter from `scale(0.95)` + fade, never\n  `scale(0)`; menus grow from their trigger (centered modals exempt).\n- **Gesture → animation never hops the JS thread.** Worklets + shared\n  values (`.get()`/`.set()`; `scheduleOnRN` — Reanimated 4's `runOnJS` —\n  only at gesture end), `transform`/`opacity` only, no `entering` on\n  recycled list rows, never animate a header's height (translate inside a\n  fixed clip), keyboard-tracking UI via `react-native-keyboard-controller`\n  — never a keyboard listener plus a guessed duration.\n- **Respect Reduce Motion**: your spatial motion collapses to cross-fades;\n  native transitions stay the system's.\n- The bar: 60 fps through the hero flow, measured on a **release build on\n  the slowest device you support** — Expo Go and dev builds hide exactly\n  the jank you're hunting\n  ([references/performance.md](references/performance.md)). Watch the\n  recording once for feel, once frame by frame, and again next day with\n  fresh eyes.\n\n## State architecture\n\nScreens that feel great are screens whose state is boring:\n\n- **Server state** in TanStack Query (or the project's equivalent): caching,\n  retries, optimistic updates. Never `useEffect`+`fetch`.\n- **Client state** in a small atomic store (Zustand/Jotai). Broad \"app state\"\n  contexts cause the re-render cascades that make UIs feel heavy.\n- **Ephemeral UI state** (open/closed, focus, scroll) stays local to the\n  component.\n- **Optimistic by default**: taps reflect instantly, reconcile in the\n  background, roll back loudly on failure.\n- Uncontrolled `TextInput`s for high-frequency typing surfaces; controlled\n  inputs are a top-3 cause of typing jank.\n- Persist tiny client state in MMKV, not AsyncStorage, when latency shows.\n\n## Perceived performance\n\n- Skeletons only for content whose shape you know; otherwise progressive\n  reveal. Never a full-screen spinner for a partial update.\n- FlashList for every list; give stable keys.\n- Preload the next screen's data on press-in, not on navigation-complete.\n- Images: right-size sources, `expo-image` with `recyclingKey` in lists,\n  thumbhash/blurhash placeholders.\n- Cold-start TTI and bundle discipline live in\n  [references/performance.md](references/performance.md) — apply the\n  measure → optimize → re-measure loop, never blind memoization.\n\n## Image & illustration assets\n\nWhen a screen calls for illustration, empty-state art, hero imagery, or icons\nbeyond the symbol set:\n\n- Generate assets with the **best image model available to you** (e.g. an\n  imagegen tool or the Higgsfield MCP/CLI if connected) at the **highest\n  quality settings**, then downscale to @1x/@2x/@3x. Never upscale.\n- One visual language per app: pick a style (gradient-mesh, flat-duotone,\n  3D-clay, hand-drawn, mascot style) and generate ALL assets in that same style, same\n  palette, same lighting. A mixed-style asset set reads as template slop.\n- Prompt for **transparent or solid-flat backgrounds** matched to your surface\n  color; composite artifacts (white halos, wrong-color mattes) are an\n  automatic redo.\n- Full asset pipeline and prompt patterns:\n  [references/image-assets.md](references/image-assets.md).\n\n## The simulator loop (non-negotiable)\n\nA screen does not exist until you have seen it running. The loop:\n\n1. Implement → launch in the iOS Simulator (or Android emulator).\n2. Screenshot and **actually look**: alignment, optical centering, spacing\n   rhythm, truncation with long content, dark mode, Dynamic Type at XL.\n3. Run the **full-motion pass** below — screenshots prove layout; they prove\n   nothing about motion.\n4. Fix, relaunch, re-verify. Repeat until you cannot find a defect — then run\n   the checklist in [references/simulator-loop.md](references/simulator-loop.md)\n   once more.\n\nDo not declare a screen finished from code review alone. Do not stop at \"looks\nfine\" — stop at \"cannot find a flaw at 100% zoom\".\n\n### The full-motion pass (mandatory, per flow)\n\nEvery flow is evaluated as **moving pictures in the simulator, never as\nstills**. Screen-record the entire flow end to end\n(`xcrun simctl io booted recordVideo flow.mov`), exercising ALL of it:\n\n- every screen transition, push/pop, tab switch\n- every back path — chevron, edge swipe, Android hardware back — and, after\n  each one-way door (sign-in, onboarding done, purchase, finished session),\n  an attempt to go back that must fail to re-enter the old state\n- every modal and sheet: present, drag, dismiss — and cancel mid-drag\n- the keyboard, both directions: appear (does the layout glide, is the\n  focused input visible?) and dismiss (does anything jump-cut?)\n- every user interaction: press states, gesture follow-through, interrupted\n  gestures, rapid taps, scroll flings at the extremes\n\nWatch the recording **twice**: once at full speed for feel, once scrubbing\nframe by frame. You are hunting:\n\n- dropped or stuttered frames — the bar is a sustained **60 fps** through\n  every transition, measured, not vibed\n- one-frame flashes: white/unstyled first paint, wrong-theme frames mid-\n  transition, color pops where a surface briefly renders the wrong token\n- layout jumps, double-render pops, springs that clip or overshoot into\n  content, elements that reflow after appearing\n\nThe whole recording must play like one native piece — smooth end to end,\nzero UX glitches. One glitchy frame means the flow is not done.\n\n## Definition of done, per screen\n\n- [ ] Studied 10+ real reference screens for this screen type (via Appllama\n      MCP when available) and can name the pattern you adopted\n- [ ] Navigation answered: what this screen *is* (push / modal / sheet /\n      overlay / replace), what back does from it on iOS and Android, and —\n      behind a one-way door — that back cannot re-enter the old state\n- [ ] Light + dark mode verified in the simulator\n- [ ] Safe areas / Dynamic Island / home indicator verified\n- [ ] Long-content, empty, loading, and error states designed — not defaulted\n- [ ] Motion: the full flow screen-recorded and scrubbed — entrances,\n      presses, transitions, modals, keyboard — native feel, zero glitch or\n      wrong-color frames; Reduce Motion respected; 60 fps measured on a\n      release build on the slowest supported device\n- [ ] Dynamic Type XL doesn't break layout; text is selectable where useful\n- [ ] All tap targets ≥ 44pt; contrast passes in both themes\n- [ ] Assets: single style family, crisp at @3x, no compositing halos\n- [ ] List surfaces virtualized; no controlled-input jank; no re-render storms\n      (profiled, not guessed)\n\n## References\n\n| File | Load when |\n|---|---|\n| [references/native-controls.md](references/native-controls.md) | Choosing/wiring iOS+Android native controls, menus, pickers, sheets |\n| [references/motion.md](references/motion.md) | Any Reanimated work: gestures, transitions, springs, layout animations |\n| [references/performance.md](references/performance.md) | Jank, slow TTI, big bundles, memory leaks, profiling method |\n| [references/image-assets.md](references/image-assets.md) | Generating illustrations/icons/hero art with image models |\n| [references/simulator-loop.md](references/simulator-loop.md) | Final verification checklist + device matrix |\n"
}

SHA-256: 472307ae8a99a440af14fa78766a966d7c33fa8d2856b6cc49cf4778006a6bb8