start-vibing 4.2.0 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "start-vibing",
3
- "version": "4.2.0",
4
- "description": "Setup Claude Code with 9 plugins, 6 community skills, and 8 MCP servers. Parallel install, auto-accept, superpowers + ralph-loop.",
3
+ "version": "4.3.0",
4
+ "description": "Setup Claude Code with 9 plugins, 6 community skills, and 8 MCP servers. Parallel install, auto-accept, superpowers + ralph-loop. super-design 0.6: component/flow discovery, 17-category design-intelligence scoring, mobile-native M1-M15 templates.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "start-vibing": "./dist/cli.js"
@@ -43,7 +43,12 @@ You are the UX/a11y/perf auditor. You drive the browser DIRECTLY via Playwright
43
43
  Read in order:
44
44
  1. `.claude/skills/super-design/references/audit-methodology.md` — methodology spine
45
45
  2. `.claude/skills/super-design/references/playwright-mcp-reference.md` — Playwright MCP API
46
- 3. `docs/super-design/market-analysis.md` — context (archetype, audience, category)
46
+ 3. `.claude/skills/super-design/references/component-flow-discovery.md` — Step 2.5 orchestration (modals, flows, component states)
47
+ 4. `.claude/skills/super-design/references/design-intelligence-rubric.md` — Step 3g 17-category scoring
48
+ 5. `.claude/skills/super-design/references/design-skills-catalog.md` — design-skill advisory findings (C16 ≤ 4)
49
+ 6. `.claude/skills/mobile-app-patterns/SKILL.md` — Step 3h mobile-native audit (Duolingo/Linear/Arc/Cash App patterns)
50
+ 7. `.claude/skills/web-design-guidelines/SKILL.md` — 100+ implicit UX/a11y rules (Vercel Labs)
51
+ 8. `docs/super-design/market-analysis.md` — context (archetype, audience, category) + `.cache/evidence/component-comparison.md` for competitor component vocabulary
47
52
 
48
53
  # Non-negotiable rules
49
54
 
@@ -91,9 +96,71 @@ session_dir/
91
96
  ├── network/<slug>_<vp>.json
92
97
  ├── console/<slug>_<vp>.json
93
98
  ├── vitals/<slug>.json
94
- └── axe/<slug>_<vp>.json
99
+ ├── axe/<slug>_<vp>.json
100
+ ├── interactive/<slug>_<vp>.json # Step 2.5 Phase A
101
+ ├── snapshots/<slug>_<vp>_<trigger>_open.yaml # Step 2.5 Phase B
102
+ ├── screens/components/<Class>/<state>.png # Step 2.5 Phase D
103
+ ├── flows/<flow_name>/step_NN_<action>.png # Step 2.5 Phase C
104
+ ├── forms/<formId>_<scenario>.png # Step 2.5 Phase E
105
+ ├── component-state-matrix.json # Step 2.5 Phase D
106
+ └── design-intelligence.json # Step 3g
95
107
  ```
96
108
 
109
+ ## Step 2.5 — Component, modal & flow discovery (MANDATORY)
110
+
111
+ **Read `component-flow-discovery.md` now.** A static page snap tells you ~30% of the
112
+ UI surface. Without Step 2.5 you miss every modal, every empty/loading/error
113
+ state, every flow failure mode, every hover/focus variant.
114
+
115
+ For each (page × viewport) already loaded in Step 2, run all five phases
116
+ sequentially in the SAME browser session (never open new tabs):
117
+
118
+ ```
119
+ Phase A — Interactive inventory
120
+ browser_evaluate: enumerate every [role=button|link|tab|switch|checkbox|radio],
121
+ [aria-haspopup], [aria-expanded], [data-trigger|data-state], input, select,
122
+ textarea, summary. Classify as navigation | action | trigger | input |
123
+ state-toggle. Save interactive/<slug>_<vp>.json.
124
+
125
+ Phase B — Modal & overlay enumeration
126
+ For each trigger: click → wait → snapshot → screenshot (full + element) →
127
+ console.error? → run Phase A inside open modal → Tab-trap check → Escape
128
+ dismiss → confirm focus returns → close → re-snapshot.
129
+ Capture: confirm dialogs, date/color pickers, combobox dropdowns, popover
130
+ menus, sheets/drawers, command palette (Cmd+K), tooltips, toasts
131
+ (programmatic), file-upload dialogs, share sheets.
132
+ Broken trigger (nothing appears in 2s) → record "trigger broken" finding.
133
+
134
+ Phase C — Flow exercising
135
+ Auto-discover flows from routes per discovery playbook mapping table
136
+ (/login → login flow, /checkout → checkout flow, list route → CRUD, etc.).
137
+ Per flow: execute step-by-step, screenshot each step, test at least ONE
138
+ error path (invalid input, 500, offline), verify back-button preserves
139
+ state, capture success confirmation.
140
+
141
+ Phase D — Component state matrix
142
+ For each component class (Button, Input, Card, ListRow, Modal, NavItem):
143
+ capture default, hover (@media hover only), focus, focus-visible, active,
144
+ disabled, loading, error, empty, success, selected. Save to
145
+ screens/components/<Class>/<state>.png. Missing states → finding.
146
+ Emit component-state-matrix.json.
147
+
148
+ Phase E — Form state coverage
149
+ Per discovered form, test 10 scenarios: empty submit, per-field invalid,
150
+ all valid, simulated 500, offline, paste into password, autocomplete
151
+ tokens, Tab order vs visual order, Enter submits, mobile input zoom
152
+ (font-size < 16px on iOS Safari).
153
+ ```
154
+
155
+ **Budget rule:** On large apps, cap to top 5 triggers per page (ranked by
156
+ proximity to primary CTA), critical flows only (login + checkout + 1 CRUD),
157
+ and the 3 core components (Button, Input, Modal). Record skipped scope in
158
+ `scope.json`.
159
+
160
+ **Hard rules:** ONE Playwright session reused across all phases. Sequential
161
+ only. Every opened modal has open + closed screenshots. Every flow captures
162
+ at least one error path. Broken triggers never abort the audit.
163
+
97
164
  ## Step 3 — Apply methodology per page × viewport
98
165
 
99
166
  ### 3a. Automated a11y
@@ -114,6 +181,95 @@ Parse `session_dir/vitals/<page>.json`. LCP/INP/CLS/FCP/TTFB/TBT against thresho
114
181
  ### 3f. Implicit criteria (methodology §5)
115
182
  60+ checks: empty/loading/error states, focus restoration after modals, aria-live for toasts, password affordances, autocomplete tokens, touch target spacing, deep linking, back-button in SPAs, scroll restoration, copy-paste tolerance, timeout/offline/5xx, session expiration, i18n edges, print stylesheet. pass/fail/n-a with evidence.
116
183
 
184
+ ### 3g. Design-intelligence scoring (MANDATORY)
185
+
186
+ **Read `design-intelligence-rubric.md` now.** WCAG and Nielsen catch accessibility
187
+ and usability failures; they do NOT catch a dashboard that ships 10 oversized
188
+ metric cards stacked in a flex-col. Design intelligence is the implicit
189
+ best-practice layer that a senior design engineer would spot instantly but
190
+ that checklists ignore. This is non-negotiable — absence of this pass is how
191
+ the beats-market mobile dashboard shipped with cards-in-flex-col and nothing
192
+ flagged it.
193
+
194
+ Per page × viewport, score the 17 rubric categories 0–10:
195
+
196
+ ```
197
+ C1 visual-hierarchy C10 motion-quality
198
+ C2 density C11 navigation-clarity
199
+ C3 consistency-spacing C12 table-on-mobile
200
+ C4 consistency-typography C13 modal-sheet-choice
201
+ C5 consistency-color C14 color-semantics
202
+ C6 whitespace-discipline C15 empty-loading-error-quality
203
+ C7 legibility C16 design-system-coherence
204
+ C8 cta-hierarchy C17 vibecode-smell
205
+ C9 state-feedback
206
+ ```
207
+
208
+ Formula: `DIS = Σ(score × weight) / Σ(weight) × 10` → 0–100.
209
+
210
+ Bands: 80–100 excellent · 65–79 solid · 50–64 MEDIUM · 35–49 WEAK · <35 broken.
211
+
212
+ Emit `design-intelligence.json` per page:
213
+
214
+ ```json
215
+ {
216
+ "page_url": "...",
217
+ "viewport": "mobile",
218
+ "dis_score": 57.5,
219
+ "band": "MEDIUM",
220
+ "categories": {
221
+ "density": { "score": 3, "evidence": "screens/admin_mobile.png", "note": "10 metric cards in flex-col, ~80px each = 800px of scroll for 10 numbers" },
222
+ "design_system_coherence": { "score": 4, "evidence": "...", "recommended_skills": ["typeui-dashboard", "typeui-application"] },
223
+ "...": {}
224
+ }
225
+ }
226
+ ```
227
+
228
+ **Any category ≤ 4 spawns a finding** with `rule: design-intelligence-<category>`,
229
+ severity mapped from score (0-1 → sev 4, 2-3 → sev 3, 4 → sev 2), and
230
+ `template_id` from the M-family (see fix-playbook M1-M15).
231
+
232
+ **C16 ≤ 4 MUST emit an advisory finding** citing `design-skills-catalog.md`
233
+ with `recommended_skills: [...]` populated from the selection matrix. This
234
+ is NEVER auto-applied — design-skill adoption is always HIGH risk.
235
+
236
+ ### 3h. Mobile-specific audit (viewport ≤ 768px ONLY)
237
+
238
+ **Read `mobile-app-patterns/SKILL.md` now.** Desktop-responsive-down is not
239
+ mobile-native. Run the 21-item checklist verbatim against each mobile page:
240
+
241
+ ```
242
+ □ Primary nav is bottom tabs (3-5), not hamburger-only → M1
243
+ □ Dashboards use hero + compact list, not card stack → M2 (cards-in-flex-col)
244
+ □ Tables transformed to card-per-row or compact list → M3 (table-on-mobile)
245
+ □ No input has font-size < 16px → M4 (ios-zoom)
246
+ □ Every interactive target ≥ 44×44 px → M5 (touch-target)
247
+ □ Modals are bottom sheets or full-screen, not centered → M6 (centered-modal)
248
+ □ No hover-only state; every hover has a tap equivalent → M7
249
+ □ Loading states exist for async flows → M8
250
+ □ Empty states exist for zero-data cases → M9
251
+ □ Error states exist for server failures → M10
252
+ □ Safe-area insets respected (iOS notch) → M11
253
+ □ 100svh / 100dvh (not 100vh) for full-height → M12
254
+ □ overscroll-behavior: contain on scroll containers → M13
255
+ □ Pull-to-refresh on primary list views → M14
256
+ □ Swipe actions discoverable (peek on first render) → M15
257
+ □ Back gesture (iOS) works via browser history
258
+ □ Keyboard does not overlap input (visualViewport)
259
+ □ Touch targets 8px+ apart
260
+ □ Long-press fallback for swipe actions
261
+ □ Bottom sheet CTAs sticky above safe area
262
+ □ Content density: 6-8 metrics above the fold (not 2-3)
263
+ ```
264
+
265
+ Each failed item → finding with `rule: mobile-pattern-M<N>`, evidence from
266
+ Step 2.5 artifacts (NOT a fresh snapshot), `template_id: M<N>`.
267
+
268
+ Cross-reference the competitor component vocabulary from
269
+ `.cache/evidence/component-comparison.md` — if every competitor uses bottom
270
+ tabs on mobile and the product uses hamburger-only, density score drops AND
271
+ the M1 finding cites the category norm.
272
+
117
273
  ## Step 4 — Write findings
118
274
 
119
275
  Append to `docs/super-design/findings/F-NNNN.md` (one file per finding) AND `.super-design/sessions/<id>/findings.json`.
@@ -125,14 +281,21 @@ Every finding MUST have:
125
281
  - `snapshot_path` + `snapshot_quote` (verbatim `[ref=eNN]` from YAML)
126
282
  - `dom_selector` (resolves)
127
283
  - `computed_style_excerpt`
128
- - `rule` (e.g., color-contrast, label, button-name, nielsen-h7, baymard-checkout-41, cwv-lcp)
284
+ - `rule` (e.g., color-contrast, label, button-name, nielsen-h7, baymard-checkout-41, cwv-lcp, design-intelligence-density, mobile-pattern-M2)
129
285
  - `wcag_criterion` (if applicable)
130
286
  - `nielsen_heuristic` (if applicable)
287
+ - `dis_category` (if rule is design-intelligence-*: one of the 17 categories)
131
288
  - `severity` (0–4 Nielsen)
132
289
  - `risk_for_fix` (TRIVIAL | LOW | MEDIUM | HIGH per fix-playbook §12)
133
- - `suggested_fix` with `template_id` (fix-playbook §7: A1-A15 a11y / V1-V8 design / U1-U10 ux / P1-P10 perf)
290
+ - `suggested_fix` with `template_id` (fix-playbook §7: A1-A15 a11y / V1-V8 design / U1-U10 ux / P1-P10 perf / M1-M15 mobile / DSC-1 design-skill advisory)
291
+ - `recommended_skills` (array, optional — populated for C16 advisories from design-skills-catalog.md selection matrix)
292
+ - `advisory_only` (bool, default false — true for design-skill recommendations and other HIGH-risk aesthetic suggestions that need human sign-off)
134
293
  - `finding` — one-sentence impact statement
135
294
 
295
+ Additionally, write `design-intelligence.json` (per page × viewport) alongside
296
+ findings.json with the full 17-category score breakdown. sd-synthesis reads
297
+ this to produce the executive DIS summary.
298
+
136
299
  ## Step 5 — Verification snippets
137
300
 
138
301
  ### Web Vitals injection
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: sd-fix
3
- description: Applies surgical fixes for super-design audit findings. Invoked when user explicitly asks for fixes after audit. Classifies risk, applies templates inline (a11y A1-A15, design V1-V8, ux U1-U10, perf P1-P10), commits per-fix with finding IDs, runs two-stage verify (technical + semantic), captures before/after screenshots via Playwright MCP, emits fix-report.md with visual diff, auto-rollback on failure.
3
+ description: Applies surgical fixes for super-design audit findings. Invoked when user explicitly asks for fixes after audit. Classifies risk, applies templates inline (a11y A1-A15, design V1-V8, ux U1-U10, perf P1-P10, mobile M1-M15, design-skill DSC-1 advisory), commits per-fix with finding IDs, runs two-stage verify (technical + semantic), captures before/after screenshots via Playwright MCP, emits fix-report.md with visual diff, auto-rollback on failure.
4
4
  tools:
5
5
  - Read
6
6
  - Edit
@@ -31,7 +31,13 @@ You are sd-fix — the unified fix agent. You apply templates for all four categ
31
31
 
32
32
  # Preflight — always run
33
33
 
34
- Read `.claude/skills/super-design/references/fix-agent-playbook.md`. Then:
34
+ Read in order:
35
+ 1. `.claude/skills/super-design/references/fix-agent-playbook.md`
36
+ 2. `.claude/skills/mobile-app-patterns/SKILL.md` (M-template source — code snippets come from here)
37
+ 3. `.claude/skills/super-design/references/design-skills-catalog.md` (DSC-1 advisory selection)
38
+ 4. `.claude/skills/super-design/references/design-intelligence-rubric.md` (design-intelligence-* finding context)
39
+
40
+ Then:
35
41
 
36
42
  ```bash
37
43
  git status --porcelain
@@ -209,6 +215,85 @@ Source of truth: `references/fix-agent-playbook.md` §7.
209
215
  - Change form submission semantics → needs_human
210
216
  - Introduce new dependency for Undo toast lib → needs_human
211
217
 
218
+ ## mobile templates (M1–M15)
219
+
220
+ Source: `.claude/skills/mobile-app-patterns/SKILL.md` — copy snippets verbatim.
221
+ Apply ONLY when `finding.viewport` is `mobile` (≤768px). Desktop/tablet
222
+ mobile-pattern findings → needs_human (UI architecture decision).
223
+
224
+ | ID | Fix | Risk | Pattern |
225
+ |---|---|---|---|
226
+ | M1 | Hamburger-only nav → `<nav class="fixed inset-x-0 bottom-0 ...">` bottom tab bar (3–5 destinations, fill-icon + label, safe-area-inset-bottom padding) | MEDIUM | needs_human for tab selection |
227
+ | M2 | Metric cards in `flex-col` → `<ul class="divide-y">` compact list rows (py-3 px-4, icon + label on left, tabular-nums value on right). For the hero metric extract into `<section>` with 4xl tabular-nums number + delta chip | LOW | auto when only one metric-card block |
228
+ | M3 | `<table>` at ≤768px → card-per-row (`<article>` with primary text + metadata chips + trailing `[⋯]` menu) OR compact list (avatar + two lines + trailing meta). Preserve sort/filter controls above | MEDIUM | needs_human if >3 columns carry semantic meaning |
229
+ | M4 | Input `font-size < 16px` → `font-size: max(16px, 1rem)` (Tailwind: `text-base` or `text-[max(16px,1rem)]`). Prevents iOS Safari zoom-on-focus | TRIVIAL | auto |
230
+ | M5 | Touch target <44×44 → wrap interactive node in `<button class="size-11 flex items-center justify-center">` keeping inner glyph. Add 8px+ gap to adjacent targets | LOW | auto for isolated buttons |
231
+ | M6 | Centered modal on mobile → migrate to bottom sheet via Vaul/Radix Drawer (`<Drawer.Root>` + `Drawer.Content className="fixed inset-x-0 bottom-0 rounded-t-2xl"`). Full-screen variant for flows | MEDIUM | needs_human — swap affects all call sites |
232
+ | M7 | Hover-only affordance → gate with `@media (hover: hover)`; add tap equivalent (visible button, long-press menu, or always-on chip) | LOW | auto for tooltip-only hovers |
233
+ | M8 | Async action without loading state → apply U2 template (disabled + aria-busy + Spinner + label change + role="status") | TRIVIAL | auto |
234
+ | M9 | Zero-data view without empty state → apply U3 template with mobile-specific illustration+CTA (full-width button) | LOW | auto |
235
+ | M10 | Server failure without error state → apply U4 template; ensure retry button is 44px tall and sticky above safe-area | LOW | auto |
236
+ | M11 | Missing safe-area insets → `padding-top: env(safe-area-inset-top)` on header, `padding-bottom: env(safe-area-inset-bottom)` on bottom nav/CTA. `viewport-fit=cover` in meta viewport | TRIVIAL | auto |
237
+ | M12 | `100vh` anywhere → `100svh` primary, `100dvh` fallback, `-webkit-fill-available` legacy. Replace all occurrences in one file | TRIVIAL | auto |
238
+ | M13 | Inner scroll conflicting with browser pull → `overscroll-behavior: contain` on the inner scroll container | TRIVIAL | auto |
239
+ | M14 | Primary list without pull-to-refresh → propose integration of `react-pull-to-refresh` or Framer gesture; register refresh handler with existing query-key invalidation | MEDIUM | needs_human — new dependency |
240
+ | M15 | Swipe-action row without peek → add `transform: translateX(-8px)` reveal on first render, animate back after 600ms (framer keyframes). Ensure long-press fallback + trailing `[⋯]` menu button | MEDIUM | needs_human if no existing swipe-action library |
241
+
242
+ **Never auto-apply:**
243
+ - Any `M*` fix when finding affects >1 layout component — UI architecture decision
244
+ - Adding a drawer/sheet dependency (Vaul, vaul-drawer) without user confirmation
245
+ - Converting a table to cards when columns drive business logic (sortable compound filters)
246
+ - Replacing existing nav structure — always needs_human
247
+
248
+ ## design-skill advisory (DSC-1)
249
+
250
+ Source: `.claude/skills/super-design/references/design-skills-catalog.md`.
251
+
252
+ **This template never writes code.** When audit emits a finding with
253
+ `rule: design-intelligence-design-system-coherence` and score ≤ 4, or with
254
+ `advisory_only: true` and `recommended_skills: [...]`, sd-fix MUST:
255
+
256
+ 1. Mark finding `status: proposed` (not applied, not skipped).
257
+ 2. Write `.super-design/sessions/<id>/proposals/F-NNNN_design-skill-advisory.md`
258
+ using this structure:
259
+
260
+ ```markdown
261
+ # F-NNNN — Design-skill advisory (NON-FIX)
262
+
263
+ **Rule:** design-intelligence-design-system-coherence
264
+ **Risk:** HIGH (aesthetic change requires human sign-off)
265
+
266
+ ## Current state
267
+ <embedded finding.screenshot_path + finding.finding one-liner>
268
+
269
+ ## Recommended skills
270
+ <for each id in finding.recommended_skills:>
271
+ - **<id>** — <description from design-skills-catalog selection matrix>
272
+ - Visual signature: <catalog signature column>
273
+ - When to recommend: <catalog "When to recommend" column>
274
+
275
+ ## Competitor evidence
276
+ <best-matching competitor screenshots from
277
+ .cache/evidence/<slug>/<viewport>/components/ cited as reference — pick
278
+ the 2 closest to the recommended aesthetic>
279
+
280
+ ## Next step for the user
281
+ Run `/frontend-design` (or re-run super-design with the chosen skill
282
+ active) to apply this direction. sd-fix cannot auto-apply aesthetic
283
+ realignment because every subsequent fix depends on the chosen
284
+ tokens.
285
+ ```
286
+
287
+ 3. Append to fix-report.md under a "Proposed aesthetic direction" section,
288
+ NOT under "Applied fixes" — the image diff format is
289
+ `current state ↔ recommended reference` (competitor screenshot), not
290
+ `before ↔ after`.
291
+
292
+ 4. No commit. No verify. No after-capture.
293
+
294
+ **DSC-1 is the ONLY finding family where sd-fix writes documentation
295
+ without writing code.**
296
+
212
297
  ## perf templates (P1–P10)
213
298
 
214
299
  | ID | Fix |
@@ -245,6 +330,9 @@ Source of truth: `references/fix-agent-playbook.md` §7.
245
330
  - Never skip Step 5.5 (capture-after) for an applied fix unless the app is unreachable — in which case record `after_capture=skipped` with reason.
246
331
  - Never fabricate after-screenshots. No real browser call → no after image.
247
332
  - Never run Step 5.5 in parallel against the same browser tab.
333
+ - Never auto-apply DSC-1 (design-skill advisory) — write the proposal, then stop.
334
+ - Never auto-apply any M* fix for desktop/tablet viewports — mobile patterns do not generalize upward.
335
+ - Never introduce a mobile-pattern dependency (Vaul, vaul-drawer, react-pull-to-refresh, react-swipeable-list) without user confirmation.
248
336
 
249
337
  # Evidence rule
250
338
 
@@ -24,7 +24,76 @@ Output: exactly one file `docs/super-design/market-analysis.md` + evidence under
24
24
 
25
25
  4. **Discover competitors.** 7-source crawl (playbook §2): WebSearch, Product Hunt, G2/Capterra/TrustRadius, YC directory, awesome-* lists, Reddit+HN Algolia, SimilarWeb/BuiltWith. Dedupe by domain. Rank fame × similarity × design-signal. Finalize 5–10 across category-king/peers/challenger/emerging/enterprise-anchor buckets.
26
26
 
27
- 5. **Audit each competitor via Playwright MCP.** Visit homepage, primary product page, pricing, About. Per playbook §3: screenshot + snapshot + tokens + copy per page. Save to `.cache/evidence/<slug>/`.
27
+ 5. **Audit each competitor via Playwright MCP — at BOTH 390×844 mobile and 1440×900 desktop.** Visit homepage, primary product page, pricing, About, one authenticated-style surface if signup-free (e.g., docs, app tour). Per playbook §3 PLUS component-level extraction per §3bis below. Save to `.cache/evidence/<slug>/<viewport>/`.
28
+
29
+ ### §3bis. Component-level extraction (mandatory, not optional)
30
+
31
+ A competitor page snap tells us nothing about their UI language. Extract the
32
+ actual design vocabulary. Per competitor, per viewport, capture:
33
+
34
+ | Artifact | How |
35
+ |---|---|
36
+ | `home.png`, `pricing.png`, etc. | Full-page screenshots as before |
37
+ | `components/button_primary.png`, `button_secondary.png`, `button_ghost.png` | `browser_take_screenshot({ element, ref })` cropped to each button variant found on home |
38
+ | `components/nav_desktop.png`, `nav_mobile.png` | Navbar/bottom-tab crops |
39
+ | `components/card_feature.png`, `card_metric.png`, `card_testimonial.png` | Card variant crops |
40
+ | `components/list_row.png` | If any list pattern exists, crop one row |
41
+ | `components/input.png`, `input_focus.png` | Form field default + focused (click into it) |
42
+ | `components/modal.png` | Open newsletter/contact/signup modal if present |
43
+ | `components/empty_state.png` | Navigate to filter-empty or search-no-results if possible |
44
+ | `components/loading.png` | Throttle network in `browser_evaluate` during a nav, capture transient state if possible |
45
+ | `components/footer.png` | Footer crop |
46
+ | `tokens.json` | Computed palette (top 8 colors by frequency), typography (family, sizes, weights used), spacing sample, radius sample, shadow sample |
47
+ | `copy.md` | Hero copy, 3 feature headlines, primary CTA label, testimonial snippet |
48
+
49
+ Save under `.cache/evidence/<slug>/<viewport>/components/`.
50
+
51
+ For each competitor, produce `.cache/evidence/<slug>/component-catalog.md`:
52
+
53
+ ```markdown
54
+ # <Competitor> — Component Catalog (<viewport>)
55
+
56
+ ## Buttons
57
+ - Primary: [image] — background: #FF5733, radius 8px, padding 12px 24px, font-weight 600
58
+ - Secondary: [image] — border + transparent bg
59
+ - Ghost: [image] — text only with hover bg
60
+
61
+ ## Navigation
62
+ - Desktop: [image] — fixed top, logo left, nav center, CTA right
63
+ - Mobile: [image] — bottom tabs with 4 destinations + center FAB
64
+
65
+ ## Cards
66
+ - Feature: [image]
67
+ - Pricing: [image]
68
+
69
+ ## Forms
70
+ - Input default: [image]
71
+ - Input focused: [image]
72
+
73
+ ## Modals
74
+ - Signup: [image]
75
+
76
+ ## Design tokens observed
77
+ - Palette: #… #… #…
78
+ - Type: Inter 14/16/20/32, weights 400/500/700
79
+ - Spacing: 4/8/16/24/48
80
+ - Radius: 8/12/24
81
+ - Shadows: 0 1px 2px …
82
+
83
+ ## Copy tone
84
+ - Hero: "…"
85
+ - CTA: "Start free" (action + value)
86
+ - Tone: confident, direct, technical
87
+ ```
88
+
89
+ **Skip rule:** If a competitor has no interactive elements (static marketing
90
+ site only), mark with `components_available: minimal` and note what is missing.
91
+ Never fabricate.
92
+
93
+ **Category synthesis update:** After all competitors cataloged, also produce
94
+ `.cache/evidence/component-comparison.md` — tabulates every competitor's
95
+ button style, nav style, card style side-by-side. This is the input sd-audit
96
+ and sd-fix use to recommend aesthetic direction.
28
97
 
29
98
  6. **Classify each.** Archetype (§4.1), Aaker peak (§4.2), vibe class, NN/g 4D tone (§7.1), hero-pattern.
30
99
 
@@ -0,0 +1,237 @@
1
+ ---
2
+ name: mobile-app-patterns
3
+ description: >
4
+ Best-in-class mobile UI/UX patterns inspired by Duolingo, Linear, Arc, Raycast,
5
+ Notion Mobile, Superhuman. MUST BE USED when designing, auditing, or fixing
6
+ any mobile viewport (≤768px) — especially dashboards, lists, forms, modals,
7
+ nav. Replaces "responsive-web-on-a-phone" thinking with genuine mobile-native
8
+ patterns. Referenced by sd-audit (design-intelligence rubric), sd-fix
9
+ (M-template fixes), and sd-research (component extraction from competitors).
10
+ version: 1.0.0
11
+ ---
12
+
13
+ # mobile-app-patterns
14
+
15
+ ## Philosophy
16
+
17
+ A mobile screen is **not** a shrunken desktop. It is a **thumb-reach device** used in 2–10 second sessions with one hand, often while walking/waiting/scrolling. Every pattern here is derived from apps people actually keep on their home screen.
18
+
19
+ ## Reference apps (study these before designing)
20
+
21
+ | App | Why | Patterns to extract |
22
+ |---|---|---|
23
+ | **Duolingo** | Highest D7 retention in learning category | Compact metric rows, streak flames, XP hero, bottom nav with tab bubbles, full-screen lesson flow, celebration animations |
24
+ | **Linear Mobile** | Fastest feedback SaaS on mobile | Minimal chrome, swipe-to-action on list rows, bottom sheet for create, command-K style quick switcher |
25
+ | **Arc Mobile / Search** | Search-first nav | No bottom tabs — single tap to search/command, gesture stack for back |
26
+ | **Raycast iOS** | Power-user density | Compact list rows with inline metadata, command palette, no decorative chrome |
27
+ | **Notion Mobile** | Heavy content on small screen | Block-based editor, swipe to nest/unnest, floating action button for quick capture |
28
+ | **Superhuman** | Speed as the aesthetic | No loading states visible — optimistic everything, keyboard shortcuts respected on iPad, split-swipe archive/snooze |
29
+ | **Cash App** | Financial density without tables | Big number hero, compact transaction rows (avatar + name + amount + relative time), bottom-sheet send/receive |
30
+ | **Spotify** | Media density | Horizontal scroll rails (not cards in column), sticky now-playing bar, bottom tab nav |
31
+
32
+ ## Core mobile patterns
33
+
34
+ ### 1. Lists over cards (CRITICAL)
35
+
36
+ **Rule:** On mobile dashboards, `role=listitem` rows beat `role=region` cards for metrics, entities, and history. Cards waste 40–60% of viewport height on padding+radius+shadow for a single data point.
37
+
38
+ ```tsx
39
+ // ANTI-PATTERN (what the beats-market admin dashboard did wrong)
40
+ <div className="flex flex-col gap-3">
41
+ <Card><CardHeader>Total Users</CardHeader><CardContent>16</CardContent></Card>
42
+ <Card><CardHeader>Producers</CardHeader><CardContent>5</CardContent></Card>
43
+ <Card><CardHeader>Orders</CardHeader><CardContent>18</CardContent></Card>
44
+ {/* 10+ cards = endless scroll, no density */}
45
+ </div>
46
+
47
+ // GOOD (Duolingo/Linear/Cash App style)
48
+ <ul className="divide-y divide-border">
49
+ {metrics.map(m => (
50
+ <li key={m.id} className="flex items-center justify-between py-3 px-4">
51
+ <div className="flex items-center gap-3">
52
+ <Icon name={m.icon} className="size-5 text-muted-foreground" />
53
+ <span className="text-sm text-muted-foreground">{m.label}</span>
54
+ </div>
55
+ <span className="text-base font-semibold tabular-nums">{m.value}</span>
56
+ </li>
57
+ ))}
58
+ </ul>
59
+
60
+ // EVEN BETTER for a hero metric on mobile (Cash App style)
61
+ <section className="px-4 pt-6 pb-4">
62
+ <p className="text-sm text-muted-foreground">Total revenue</p>
63
+ <h1 className="text-4xl font-bold tabular-nums">R$1.389</h1>
64
+ <p className="text-xs text-muted-foreground mt-1">+12% vs last month</p>
65
+ </section>
66
+ <ul className="divide-y">{/* supporting metrics as compact rows */}</ul>
67
+ ```
68
+
69
+ **Density target:** A mobile viewport (390×844) should fit **at least 6–8 metrics above the fold**, not 2–3.
70
+
71
+ ### 2. Hero + compact list (dashboard pattern)
72
+
73
+ ```
74
+ ┌─────────────────────────┐
75
+ │ ☰ Dashboard 👤 │ Header (56px fixed)
76
+ ├─────────────────────────┤
77
+ │ │
78
+ │ Total Revenue │ HERO: 1 big number
79
+ │ R$ 1,389.00 │ that matters most
80
+ │ +12% this month ↗ │
81
+ │ │
82
+ ├─────────────────────────┤
83
+ │ 👥 Users 16 │ Compact metric rows
84
+ │ 🎵 Producers 5 │ (44px each)
85
+ │ 📦 Active Packs 18 │
86
+ │ 🛒 Orders 18 │
87
+ │ 🔄 Refunds 0 │
88
+ │ 📊 Refund Rate 0.0% │
89
+ │ 🛡️ DMCA Claims 0 │
90
+ │ 💬 Open Tickets 1 │
91
+ ├─────────────────────────┤
92
+ │ [Home][Metrics][Orders] │ Bottom tab nav (56px)
93
+ └─────────────────────────┘
94
+ ```
95
+
96
+ ### 3. Bottom nav (NOT hamburger) for top-level nav
97
+
98
+ - 3–5 tabs max. More → move to secondary screen via "More" tab.
99
+ - Each tab = a destination, not an action.
100
+ - Fixed position, 56–64px tall, with safe-area inset.
101
+ - Active state: fill icon + label always visible (not hidden).
102
+
103
+ ```tsx
104
+ <nav className="fixed inset-x-0 bottom-0 z-40 border-t bg-background pb-[env(safe-area-inset-bottom)]">
105
+ <ul className="flex h-14">
106
+ {tabs.map(t => (
107
+ <li key={t.id} className="flex-1">
108
+ <Link
109
+ href={t.href}
110
+ aria-current={active === t.id ? 'page' : undefined}
111
+ className="flex h-full flex-col items-center justify-center gap-1 text-xs"
112
+ >
113
+ <t.Icon className={cn('size-5', active === t.id ? 'fill-current' : '')} />
114
+ <span className={active === t.id ? 'font-semibold' : 'text-muted-foreground'}>{t.label}</span>
115
+ </Link>
116
+ </li>
117
+ ))}
118
+ </ul>
119
+ </nav>
120
+ ```
121
+
122
+ ### 4. Bottom sheets (NOT centered modals) for actions
123
+
124
+ - Centered dialog on mobile = thumb cannot reach top-right close button.
125
+ - Bottom sheet slides up from the bottom, close via drag-down or button at top.
126
+ - Use `<dialog>` or Vaul/Radix + `vaul-drawer` libs.
127
+
128
+ ### 5. Full-screen flows (NOT multi-step modals)
129
+
130
+ Onboarding, lesson completion, checkout, create-entity — all should be **full-screen pages** that replace the current view, with a close/back in the top-left, not modal overlays.
131
+
132
+ Duolingo lesson = full-screen. Cash App send = full-screen. Linear create-issue = bottom sheet → expand to full. Never a centered modal trying to cram a form.
133
+
134
+ ### 6. Swipe actions on list rows
135
+
136
+ Archive / Delete / Snooze / Complete = left or right swipe on the row. Exposes discoverability via slight peek on first render.
137
+
138
+ Lib: `react-swipeable-list` / custom pointer-events handler. Always provide a long-press or trailing `[…]` button as a11y fallback.
139
+
140
+ ### 7. Pull-to-refresh on scrollable lists
141
+
142
+ Native iOS/Android pattern. Every list that fetches server data should implement it. Lib: `react-pull-to-refresh` or Framer Motion gestures.
143
+
144
+ ### 8. Typography scale for mobile
145
+
146
+ - Body: **16px** (never smaller — iOS triggers zoom on focus for <16px inputs)
147
+ - Meta / captions: 14px minimum, 13px absolute floor for tabular dense lists
148
+ - Headings: 20/24/32/40 — large hero numbers allowed (44–56px)
149
+ - Line-height: 1.4 body, 1.2 headings, 1.5 long-form reading
150
+
151
+ ### 9. Touch targets
152
+
153
+ - **44×44 px minimum** (Apple HIG) or 48dp (Material) — NOT the WCAG 24px floor
154
+ - 8px gap between adjacent targets
155
+ - Full-width list rows: the whole row is the target, not just the text
156
+
157
+ ### 10. Data tables → convert on mobile
158
+
159
+ Tables with >3 columns CANNOT fit at 375px. Transform:
160
+
161
+ | Original desktop | Mobile replacement |
162
+ |---|---|
163
+ | Users table (name, email, role, status, date, actions) | List of rows with avatar + primary text + compact metadata stack + trailing `[⋯]` menu |
164
+ | Orders table (id, buyer, items, total, payment, refund, downloads, actions) | Card per order: buyer + total prominent, metadata as chips, CTA row at bottom |
165
+ | Data grid | Virtualized list OR horizontal scroll with sticky first column (only if truly needed) |
166
+
167
+ ## Mobile anti-patterns (auto-flag in audits)
168
+
169
+ | Anti-pattern | Why bad | Fix |
170
+ |---|---|---|
171
+ | Cards in `flex-col` for metrics | Wastes 40–60% vertical space | Compact list rows with divider |
172
+ | Desktop table <768px | Unreadable microtext or horizontal scroll hell | Card-per-row OR list with primary+meta |
173
+ | Hamburger menu as only nav | Hides primary destinations behind 1+ tap | Bottom tab bar (3–5 tabs) |
174
+ | Centered modal with close in top-right | Unreachable by thumb | Bottom sheet with drag handle |
175
+ | Input `font-size < 16px` | iOS Safari zooms in on focus | Use 16px or `font-size: max(16px, 1rem)` |
176
+ | Fixed header + fixed footer > 25% height | Leaves <75% for content | Collapse header on scroll (framer shrink) |
177
+ | Multi-column layout <600px | Nothing fits | Single column or horizontal rail |
178
+ | Hover-only affordances | Touch has no hover | Gate `@media (hover: hover)` + tap equivalent |
179
+ | Tiny close buttons (<24×24) | Missed taps | 44×44 hit area even if icon is smaller |
180
+ | Toast in top-right | Thumb can't dismiss | Bottom-center toast with swipe-down |
181
+ | 100vh anywhere | iOS Safari URL bar breaks it | `100svh` / `100dvh` with `-webkit-fill-available` fallback |
182
+ | Pull-to-refresh inside inner scroll | Conflicts with browser pull | `overscroll-behavior: contain` |
183
+
184
+ ## Competitor reference for mobile patterns by domain
185
+
186
+ | Your app type | Study these on mobile |
187
+ |---|---|
188
+ | Admin / SaaS dashboard | Linear, Height, Plane, Vercel dashboard |
189
+ | Marketplace (buyer) | Instagram Shop, Depop, Vinted, Mercari |
190
+ | Marketplace (seller) | Shopify Mobile, Etsy Seller, Depop |
191
+ | E-commerce checkout | Shop App, Amazon, Stripe Checkout (in a WebView) |
192
+ | Social / community | Discord, Slack, Twitter (X), BlueSky |
193
+ | Learning / habit | Duolingo, Brilliant, Finch, Streaks |
194
+ | Finance / fintech | Cash App, Revolut, Mercury, Ramp |
195
+ | Productivity | Notion, Linear, Raycast, Things 3 |
196
+ | Media | Spotify, Apple Music, YouTube |
197
+
198
+ ## How to use this skill
199
+
200
+ - **sd-audit** references these anti-patterns as M-category findings (M1–M12).
201
+ - **sd-fix** applies M-templates with code snippets directly from this skill.
202
+ - **sd-research** studies competitors' mobile viewports against this pattern library, not just home pages.
203
+ - **frontend-design** plugin cross-references this skill when generating mobile UI.
204
+
205
+ ## Mandatory mobile audit checklist (≤375px viewport)
206
+
207
+ ```
208
+ □ Primary nav is bottom tabs (3-5), not hamburger-only
209
+ □ Dashboards use hero + compact list, not card stack
210
+ □ Tables transformed to card-per-row or compact list
211
+ □ No input has font-size < 16px
212
+ □ Every interactive target ≥ 44×44 px
213
+ □ Modals are bottom sheets or full-screen, not centered
214
+ □ No hover-only state; every hover has a tap equivalent
215
+ □ Loading states exist for async flows
216
+ □ Empty states exist for zero-data cases
217
+ □ Error states exist for server failures
218
+ □ Safe-area insets respected (iOS notch, home indicator)
219
+ □ Text uses 100svh / 100dvh (not 100vh) for full-height
220
+ □ Scroll containers use overscroll-behavior: contain
221
+ □ Pull-to-refresh implemented on primary list views
222
+ □ Swipe actions discoverable (peek on first render)
223
+ □ Back gesture (iOS) works via browser history
224
+ □ Keyboard does not overlap input (visualViewport API)
225
+ □ Touch targets 8px+ apart
226
+ □ Long-press fallback for swipe actions
227
+ □ Bottom sheet CTAs sticky above safe area
228
+ ```
229
+
230
+ ## References
231
+
232
+ - Linear Method — https://linear.app/method
233
+ - Vercel Design Engineering — https://vercel.com/blog/design-engineering-at-vercel
234
+ - iOS HIG Touch Targets — https://developer.apple.com/design/human-interface-guidelines/layout
235
+ - Material 3 Bottom App Bar — https://m3.material.io/components/bottom-app-bar/overview
236
+ - NN/g Mobile UX — https://www.nngroup.com/topic/mobile-and-tablet-design/
237
+ - Baymard Mobile Checkout — https://baymard.com/checkout-usability