Build store-credible native-feel mobile UI
Change the skin, never the skeleton. Build mobile UI that clears a native-feel bar and
a store-readiness bar — without touching gameplay, navigation routes, state, scoring, or
business logic. Where a redesign implies a structural change ("this should be a sheet, not a
modal"), flag it as a proposal; do not silently implement it.
The three non-negotiable bars
A "premium" mobile surface must clear all three at once — failing any one ships as
not-premium regardless of the others.
- Native feel. Every hybrid/RN screen reads as a mobile website until deliberately
de-websified. Tells to close: centred modals (→ bottom sheets), fade transitions
(→ slide/shared-element), missing swipe-back and hardware-back handling, no haptics on
primary taps, fonts flashing, wrong scroll bounce, ignored safe-area insets, default
launch screen.
- Maturity (indie → store-credible). Tidying a plateau makes the plateau more visible.
Recommit: real type scale, brand chrome (not generic), activated margins, ambient life,
and one named hero detail per screen — the deliberate moment the user remembers.
- Store readiness. Most "wouldn't get approved" intuition is a finite checklist:
tap targets ≥ 44pt, privacy/permission strings present, real launch screen, Dynamic
Type / large-text support, working hardware back (Android), opposite colour scheme,
no placeholder content.
Steps
- Read the lore + brand/tokens first.
search_lore (Memory MCP) and any
BRAND.md/DESIGN.md/tokens file. If a brand/design system exists, extend it in
its idiom (Brand-Respecting Mode) — audit + close gaps; do not re-pitch the aesthetic.
Confirm the stack (RN/Expo or React + Capacitor) and match its component conventions.
- Audit the screen against the three bars: score native-feel per item, diagnose
maturity, pre-screen store-rejection triggers. Note gameplay/logic surfaces to leave alone.
- Respect safe areas. Use the safe-area insets (
react-native-safe-area-context /
the env-inset equivalent) for top/bottom/notch; never hardcode status-bar heights.
- Gestures + navigation feel native. Swipe-back, hardware back (Android), bottom
sheets over centred modals, slide/shared-element transitions over fades. Keep the
navigation routes and actions exactly as they are.
- Haptics + sound hooks on primary interactions (selection, confirm, error) via the
platform haptics API — subtle, consistent, behind a tokenised hook.
- Tokens drive presentation — colour, type scale, spacing, motion, radius. No raw hex
or magic numbers in components; scrolls hide scrollbars, use momentum, and disable global
pull-to-refresh except where intended.
- Performance: keep the main interaction loop at 60fps; animate on the native driver
(
useNativeDriver: true / Reanimated worklets); virtualise long lists (FlatList/
FlashList); avoid layout thrash and oversized images.
- Verify + evidence. Run the repo's tests + lint; a migration ends green — a
failing gameplay test means logic changed (roll back, never edit the test to pass). Add
tests for new visual contracts (component states, screen smoke tests). Record
test_output via record-evidence and submit for review.
Build / Test
- Run the repo's configured test + lint; type-check (
tsc --noEmit) for TS.
- Every screen migration ends green with a successful build; default failing tests to
roll back the migration, never to modifying the test.
- Prefer screenshot/visual checks on a real device or simulator at the supported tiers;
test with Reduce Motion, large text (200%), VoiceOver/TalkBack, and the opposite colour scheme.
- The DoD is verified by the repo's configured commands — record the output as evidence.
Review checklist (a mobile reviewer must check)
- No web-hybrid tells — bottom sheets not centred modals, slide not fade, swipe-back +
hardware-back work, no font flash, scroll bounce/momentum correct.
- Safe-area insets honoured — nothing under the notch / home indicator; no hardcoded bar heights.
- Haptics on primary taps, consistent and subtle.
- Tap targets ≥ 44pt; Dynamic Type / large-text supported; opposite colour scheme holds.
- One hero detail per screen named and present; type scale + chrome are committed, not generic.
- Tokens, not hardcoded colour/spacing/type; no raw hex / magic numbers in components.
- Performance — native-driver animation, virtualised long lists, 60fps on the main loop.
- Skeleton preserved — routes, navigation actions, state, scoring, and component
prop/event contracts unchanged; structural changes raised as proposals, not silently made.
- Store triggers cleared — privacy strings, real launch screen, no placeholder content.
Rules
- Change the skin, never the skeleton — no logic/navigation/state/scoring changes.
- Clear all three bars (native feel, maturity, store readiness) — failing one fails the surface.
- Safe-area insets, native gestures, haptics, native-driver animation — no hardcoded bar heights.
- Tokens for all presentation; structural changes are proposals, not silent edits; tests stay green.
Capture lore
This skill is one of the places durable, reusable knowledge naturally surfaces:
A mobile convention this repo enforces — the design system/tokens, brand voice, a native-feel pattern, a store-submission requirement, or a "never touch" gameplay/logic boundary. That kind of fact is lore. Capture it via the lore-capture
protocol in your brief (CLAUDE.factory.md, step 11 "Memory contribution"):
call the Memory MCP suggest_lore once at the close of your work — reusable
conventions, gotchas, decisions, and boundaries only, never per-ticket trivia.
1---2name: mobile-ui3description: Use when a ticket builds or reworks UI in a React Native / Expo (or React + Capacitor) mobile app and it must feel like a real, store-credible native app — not a wrapped mobile website. Covers the native-feel bar, safe-area/gesture/haptics, store-readiness, and mobile performance. Invoke for "make this screen feel native", "build the mobile X screen", "this feels like a website", "would this get approved", or as the mobile pack for any app-UI change.4---56# Build store-credible native-feel mobile UI78Change the **skin, never the skeleton.** Build mobile UI that clears a native-feel bar and9a store-readiness bar — without touching gameplay, navigation routes, state, scoring, or10business logic. Where a redesign implies a structural change ("this should be a sheet, not a11modal"), flag it as a **proposal**; do not silently implement it.1213## The three non-negotiable bars1415A "premium" mobile surface must clear all three at once — failing any one ships as16not-premium regardless of the others.17181. **Native feel.** Every hybrid/RN screen reads as a mobile website until deliberately19 de-websified. Tells to close: centred modals (→ bottom sheets), fade transitions20 (→ slide/shared-element), missing swipe-back and hardware-back handling, no haptics on21 primary taps, fonts flashing, wrong scroll bounce, ignored safe-area insets, default22 launch screen.232. **Maturity (indie → store-credible).** Tidying a plateau makes the plateau more visible.24 Recommit: real type scale, brand chrome (not generic), activated margins, ambient life,25 and **one named hero detail per screen** — the deliberate moment the user remembers.263. **Store readiness.** Most "wouldn't get approved" intuition is a finite checklist:27 tap targets ≥ 44pt, privacy/permission strings present, real launch screen, Dynamic28 Type / large-text support, working hardware back (Android), opposite colour scheme,29 no placeholder content.3031## Steps32331. **Read the lore + brand/tokens first.** `search_lore` (Memory MCP) and any34 `BRAND.md`/`DESIGN.md`/`tokens` file. If a brand/design system exists, **extend it in35 its idiom** (Brand-Respecting Mode) — audit + close gaps; do not re-pitch the aesthetic.36 Confirm the stack (RN/Expo or React + Capacitor) and match its component conventions.372. **Audit the screen** against the three bars: score native-feel per item, diagnose38 maturity, pre-screen store-rejection triggers. Note gameplay/logic surfaces to leave alone.393. **Respect safe areas.** Use the safe-area insets (`react-native-safe-area-context` /40 the env-inset equivalent) for top/bottom/notch; never hardcode status-bar heights.414. **Gestures + navigation feel native.** Swipe-back, hardware back (Android), bottom42 sheets over centred modals, slide/shared-element transitions over fades. Keep the43 navigation routes and actions exactly as they are.445. **Haptics + sound hooks** on primary interactions (selection, confirm, error) via the45 platform haptics API — subtle, consistent, behind a tokenised hook.466. **Tokens drive presentation** — colour, type scale, spacing, motion, radius. No raw hex47 or magic numbers in components; scrolls hide scrollbars, use momentum, and disable global48 pull-to-refresh except where intended.497. **Performance:** keep the main interaction loop at 60fps; animate on the native driver50 (`useNativeDriver: true` / Reanimated worklets); virtualise long lists (`FlatList`/51 `FlashList`); avoid layout thrash and oversized images.528. **Verify + evidence.** Run the repo's tests + lint; a migration ends **green** — a53 failing gameplay test means logic changed (roll back, never edit the test to pass). Add54 tests for new visual contracts (component states, screen smoke tests). Record55 `test_output` via `record-evidence` and submit for review.5657## Build / Test5859- Run the repo's configured test + lint; type-check (`tsc --noEmit`) for TS.60- Every screen migration ends green with a successful build; default failing tests to61 **roll back the migration**, never to modifying the test.62- Prefer screenshot/visual checks on a real device or simulator at the supported tiers;63 test with Reduce Motion, large text (200%), VoiceOver/TalkBack, and the opposite colour scheme.64- The DoD is verified by the repo's configured commands — record the output as evidence.6566## Review checklist (a mobile reviewer must check)6768- **No web-hybrid tells** — bottom sheets not centred modals, slide not fade, swipe-back +69 hardware-back work, no font flash, scroll bounce/momentum correct.70- **Safe-area insets honoured** — nothing under the notch / home indicator; no hardcoded bar heights.71- **Haptics on primary taps**, consistent and subtle.72- **Tap targets ≥ 44pt**; Dynamic Type / large-text supported; opposite colour scheme holds.73- **One hero detail per screen** named and present; type scale + chrome are committed, not generic.74- **Tokens, not hardcoded** colour/spacing/type; no raw hex / magic numbers in components.75- **Performance** — native-driver animation, virtualised long lists, 60fps on the main loop.76- **Skeleton preserved** — routes, navigation actions, state, scoring, and component77 prop/event contracts unchanged; structural changes raised as proposals, not silently made.78- **Store triggers cleared** — privacy strings, real launch screen, no placeholder content.7980## Rules8182- Change the skin, never the skeleton — no logic/navigation/state/scoring changes.83- Clear all three bars (native feel, maturity, store readiness) — failing one fails the surface.84- Safe-area insets, native gestures, haptics, native-driver animation — no hardcoded bar heights.85- Tokens for all presentation; structural changes are proposals, not silent edits; tests stay green.8687## Capture lore8889This skill is one of the places durable, reusable knowledge naturally surfaces:90**A mobile convention this repo enforces — the design system/tokens, brand voice, a native-feel pattern, a store-submission requirement, or a "never touch" gameplay/logic boundary.** That kind of fact is *lore*. Capture it via the **lore-capture91protocol in your brief** (`CLAUDE.factory.md`, step 11 "Memory contribution"):92call the Memory MCP `suggest_lore` once at the close of your work — reusable93conventions, gotchas, decisions, and boundaries only, never per-ticket trivia.