start-vibing 4.1.2 → 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 +2 -2
- package/template/.claude/agents/sd-audit.md +167 -4
- package/template/.claude/agents/sd-fix.md +180 -7
- package/template/.claude/agents/sd-research.md +70 -1
- package/template/.claude/skills/mobile-app-patterns/SKILL.md +237 -0
- package/template/.claude/skills/super-design/SKILL.md +29 -7
- package/template/.claude/skills/super-design/references/component-flow-discovery.md +258 -0
- package/template/.claude/skills/super-design/references/design-intelligence-rubric.md +376 -0
- package/template/.claude/skills/super-design/references/design-skills-catalog.md +102 -0
- package/template/.claude/skills/super-design/templates/fix-history.md.tpl +7 -6
- package/template/.claude/skills/super-design/templates/fix-report.md.tpl +165 -0
|
@@ -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
|
|
@@ -8,7 +8,7 @@ description: >
|
|
|
8
8
|
UX audit (WCAG 2.2 AA, Nielsen heuristics, Baymard, CWV), and synthesized
|
|
9
9
|
overview. Re-audits only what changed since last run. On explicit user request,
|
|
10
10
|
applies surgical fixes with full rollback.
|
|
11
|
-
version: 0.
|
|
11
|
+
version: 0.6.0
|
|
12
12
|
---
|
|
13
13
|
|
|
14
14
|
# super-design
|
|
@@ -18,14 +18,36 @@ version: 0.4.0
|
|
|
18
18
|
Four-phase pipeline with 6 specialist agents:
|
|
19
19
|
|
|
20
20
|
1. **Market research** (sd-research) — auto-detects niche from repo, finds 5–10
|
|
21
|
-
competitors, extracts design language
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
competitors, extracts design language AND component vocabulary (buttons,
|
|
22
|
+
nav, cards, modals, forms, tokens — per competitor × mobile+desktop),
|
|
23
|
+
produces market-analysis.md + component-comparison.md.
|
|
24
|
+
2. **UI/UX audit** (sd-audit) — drives browser via Playwright MCP directly.
|
|
25
|
+
Five layers:
|
|
26
|
+
- Route discovery + static snap (Nielsen + WCAG 2.2 AA + Baymard + CWV)
|
|
27
|
+
- **Step 2.5 component/modal/flow discovery** (Phase A inventory, B modal
|
|
28
|
+
enumeration, C flow exercising, D state matrix, E form coverage) — this
|
|
29
|
+
is where modal contents, empty/loading/error states, and flow errors
|
|
30
|
+
get real evidence instead of "checklist hypothetical".
|
|
31
|
+
- **Step 3g design-intelligence scoring** (17-category rubric → DIS 0–100)
|
|
32
|
+
catches implicit best practices checklists miss (cards-in-flex-col,
|
|
33
|
+
low density, weak CTA hierarchy, vibecode smell).
|
|
34
|
+
- **Step 3h mobile-native audit** (21-item Duolingo/Linear/Arc/Cash-App
|
|
35
|
+
checklist) — replaces "responsive-web-on-a-phone" thinking.
|
|
36
|
+
- C16 ≤ 4 → design-skill advisory finding citing typeui-* selection matrix.
|
|
37
|
+
Produces findings.json + design-intelligence.json with SHOT+QUOTE+SEL+VAL.
|
|
38
|
+
3. **Synthesis** (sd-synthesis) — unifies research + audit + design-intelligence
|
|
39
|
+
into overview.md (per-page DIS table + executive summary).
|
|
26
40
|
4. **Fix** (sd-fix + two-stage verify) — optional. Applies safe fixes with
|
|
27
41
|
technical gates (types/lint/tests) AND semantic verification ("does this
|
|
28
|
-
fix actually resolve the finding, or just mask it?").
|
|
42
|
+
fix actually resolve the finding, or just mask it?"). Template families:
|
|
43
|
+
A1-A15 a11y · V1-V8 design · U1-U10 ux · P1-P10 perf · **M1-M15 mobile**
|
|
44
|
+
(cards-in-flex-col → compact list, table-on-mobile → card-per-row,
|
|
45
|
+
centered-modal → bottom-sheet, etc.) · **DSC-1 design-skill advisory**
|
|
46
|
+
(proposes typeui-* direction, never auto-applies — HIGH risk). After each
|
|
47
|
+
successful fix, re-drives Playwright to capture an after-screenshot (full
|
|
48
|
+
page + element crop) and emits `docs/super-design/sessions/<id>/fix-report.md`:
|
|
49
|
+
a self-contained visual diff with before/after images, file diffs,
|
|
50
|
+
verification status, and commit SHA per finding.
|
|
29
51
|
|
|
30
52
|
## Entry flow
|
|
31
53
|
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
# Component, Modal & Flow Discovery Playbook
|
|
2
|
+
|
|
3
|
+
> How sd-audit systematically exercises EVERY interactive element before
|
|
4
|
+
> running heuristics. Without this, the audit only sees static page snaps
|
|
5
|
+
> and misses modal contents, flow state, hover/focus/active variants, and
|
|
6
|
+
> loading/empty/error states.
|
|
7
|
+
>
|
|
8
|
+
> This playbook runs as **Step 2.5** in sd-audit, after route discovery
|
|
9
|
+
> and before per-viewport heuristic passes.
|
|
10
|
+
|
|
11
|
+
## Why this matters
|
|
12
|
+
|
|
13
|
+
Static screenshots of pages show ~30% of what users interact with. The other 70%
|
|
14
|
+
lives inside modals, drawers, dropdowns, command palettes, error flows, empty
|
|
15
|
+
states, loading states, hover menus, focus rings. A page can score 95/100 on
|
|
16
|
+
Lighthouse and be unusable because its "Create" modal is broken — and the
|
|
17
|
+
auditor never opened it.
|
|
18
|
+
|
|
19
|
+
## Discovery phases
|
|
20
|
+
|
|
21
|
+
### Phase A — Interactive inventory (per page × viewport)
|
|
22
|
+
|
|
23
|
+
After navigating and dismissing banners:
|
|
24
|
+
|
|
25
|
+
```js
|
|
26
|
+
// browser_evaluate
|
|
27
|
+
(() => {
|
|
28
|
+
const roots = [
|
|
29
|
+
'[role="button"]',
|
|
30
|
+
'button',
|
|
31
|
+
'a[href]',
|
|
32
|
+
'[role="link"]',
|
|
33
|
+
'[role="menuitem"]',
|
|
34
|
+
'[role="tab"]',
|
|
35
|
+
'[role="switch"]',
|
|
36
|
+
'[role="checkbox"]',
|
|
37
|
+
'[role="radio"]',
|
|
38
|
+
'[aria-haspopup]',
|
|
39
|
+
'[aria-expanded]',
|
|
40
|
+
'[data-trigger]',
|
|
41
|
+
'[data-state]',
|
|
42
|
+
'input',
|
|
43
|
+
'select',
|
|
44
|
+
'textarea',
|
|
45
|
+
'summary',
|
|
46
|
+
];
|
|
47
|
+
const items = [];
|
|
48
|
+
roots.forEach(sel => {
|
|
49
|
+
document.querySelectorAll(sel).forEach(el => {
|
|
50
|
+
if (!el.offsetParent && getComputedStyle(el).position !== 'fixed') return;
|
|
51
|
+
const r = el.getBoundingClientRect();
|
|
52
|
+
if (r.width === 0 || r.height === 0) return;
|
|
53
|
+
items.push({
|
|
54
|
+
selector: sel,
|
|
55
|
+
tag: el.tagName,
|
|
56
|
+
role: el.getAttribute('role'),
|
|
57
|
+
name: el.getAttribute('aria-label') || el.textContent?.trim().slice(0, 60) || '',
|
|
58
|
+
type: el.getAttribute('type'),
|
|
59
|
+
haspopup: el.getAttribute('aria-haspopup'),
|
|
60
|
+
expanded: el.getAttribute('aria-expanded'),
|
|
61
|
+
disabled: el.disabled || el.getAttribute('aria-disabled') === 'true',
|
|
62
|
+
rect: { x: r.x, y: r.y, w: r.width, h: r.height },
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
return items;
|
|
67
|
+
})()
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Save to `.super-design/sessions/<id>/interactive/<slug>_<vp>.json`.
|
|
71
|
+
|
|
72
|
+
Classify each:
|
|
73
|
+
- **navigation** — links, tabs, back buttons
|
|
74
|
+
- **action** — primary CTAs, submit, delete, save
|
|
75
|
+
- **trigger** — opens modal/drawer/dropdown (`aria-haspopup`, `data-trigger`)
|
|
76
|
+
- **input** — form fields
|
|
77
|
+
- **state-toggle** — switches, checkboxes, expanders
|
|
78
|
+
|
|
79
|
+
### Phase B — Modal & overlay discovery
|
|
80
|
+
|
|
81
|
+
For each trigger from Phase A:
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
1. Pre-click snapshot (already have from Phase 1)
|
|
85
|
+
2. browser_click({ ref }) # click the trigger
|
|
86
|
+
3. browser_wait_for(text="<expected modal content>") or 500ms
|
|
87
|
+
4. browser_snapshot → save as snapshots/<slug>_<vp>_<triggerName>_open.yaml
|
|
88
|
+
5. browser_take_screenshot fullPage + element-scoped → screens/components/
|
|
89
|
+
6. browser_console_messages(level="error") → record
|
|
90
|
+
7. Inside open modal, run Phase A again (nested inventory)
|
|
91
|
+
8. Look for [role="dialog"] or [data-state="open"] to confirm it opened
|
|
92
|
+
9. Exercise modal internals:
|
|
93
|
+
- Tab through to find focus trap
|
|
94
|
+
- Press Escape to confirm dismiss
|
|
95
|
+
- Resize to mobile — check if it becomes bottom-sheet
|
|
96
|
+
10. Close modal (button or Escape)
|
|
97
|
+
11. Re-snapshot → confirm background restored, focus returned to trigger
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Modals a junior agent misses:**
|
|
101
|
+
- Confirmation dialogs (delete confirm, logout confirm)
|
|
102
|
+
- Date pickers (calendar popover)
|
|
103
|
+
- Color pickers
|
|
104
|
+
- Combobox dropdowns (autocomplete search)
|
|
105
|
+
- Popover menus (dropdown with options)
|
|
106
|
+
- Sheet / drawer (slide-in from right or bottom)
|
|
107
|
+
- Command palette (Cmd+K)
|
|
108
|
+
- Tooltips (hover-triggered on desktop)
|
|
109
|
+
- Toast notifications (programmatic — trigger an action that causes one)
|
|
110
|
+
- Error modals (submit invalid form)
|
|
111
|
+
- Share sheets
|
|
112
|
+
- File upload dialogs (click input[type=file])
|
|
113
|
+
|
|
114
|
+
### Phase C — Flow exercising
|
|
115
|
+
|
|
116
|
+
A **flow** is a multi-step user journey. Every app has 3–10 critical flows.
|
|
117
|
+
sd-audit must auto-discover and exercise them.
|
|
118
|
+
|
|
119
|
+
**Auto-discover flows from routes + component names:**
|
|
120
|
+
|
|
121
|
+
| Route / name hint | Flow |
|
|
122
|
+
|---|---|
|
|
123
|
+
| `/login`, `/signin`, `/auth` | Login flow (happy + wrong password + locked account) |
|
|
124
|
+
| `/register`, `/signup` | Registration flow |
|
|
125
|
+
| `/forgot`, `/reset` | Password reset flow |
|
|
126
|
+
| `/onboarding`, `/welcome` | First-run flow |
|
|
127
|
+
| `/checkout`, `/cart` | Checkout flow (incl. errors: declined card, validation) |
|
|
128
|
+
| `/dashboard`, `/home` (authed) | Post-auth landing → primary CTA flow |
|
|
129
|
+
| List route (`/users`, `/orders`) | CRUD — create, edit, view, delete, filter, search, paginate |
|
|
130
|
+
| Detail route (`/users/:id`) | Edit flow, delete flow, related actions |
|
|
131
|
+
| `/settings`, `/profile` | Profile edit, preference toggles, account delete |
|
|
132
|
+
| `/support`, `/help`, `/chat` | Messaging flow |
|
|
133
|
+
|
|
134
|
+
**Per flow:**
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
1. Plan steps (list of expected screens + actions)
|
|
138
|
+
2. Execute step-by-step:
|
|
139
|
+
- Navigate / click to advance
|
|
140
|
+
- Per step: snapshot + screenshot + console
|
|
141
|
+
- Test error path (invalid input, network error via DevTools)
|
|
142
|
+
- Test back button preserves state
|
|
143
|
+
3. Capture final success state (confirmation page, toast, redirect)
|
|
144
|
+
4. If flow depends on creating test data, use burner account
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Save per-flow artifacts under `.super-design/sessions/<id>/flows/<flow_name>/step_NN_<action>.png`.
|
|
148
|
+
|
|
149
|
+
### Phase D — State matrix per component
|
|
150
|
+
|
|
151
|
+
For each UI component class (Button, Input, Card, ListRow, Modal, NavItem…),
|
|
152
|
+
capture:
|
|
153
|
+
|
|
154
|
+
| State | How to trigger |
|
|
155
|
+
|---|---|
|
|
156
|
+
| default | Initial render |
|
|
157
|
+
| hover | `browser_hover` (desktop only, gate `@media hover`) |
|
|
158
|
+
| focus | Tab to element via `browser_press_key(Tab)` until focused |
|
|
159
|
+
| focus-visible | Same as focus (most systems collapse them now) |
|
|
160
|
+
| active | `browser_press_key` Enter/Space while focused |
|
|
161
|
+
| disabled | Find a disabled example (e.g., form before valid) |
|
|
162
|
+
| loading | Submit form → catch transient state; OR throttle network via DevTools |
|
|
163
|
+
| error | Invalid input + submit |
|
|
164
|
+
| empty | Navigate to route with no data (burner account OR delete all) |
|
|
165
|
+
| success | Complete a flow successfully |
|
|
166
|
+
| selected | Click tab / radio / checkbox that shows selected variant |
|
|
167
|
+
|
|
168
|
+
Save per component class:
|
|
169
|
+
```
|
|
170
|
+
.super-design/sessions/<id>/components/
|
|
171
|
+
Button/
|
|
172
|
+
default.png
|
|
173
|
+
hover.png
|
|
174
|
+
focus.png
|
|
175
|
+
active.png
|
|
176
|
+
disabled.png
|
|
177
|
+
loading.png
|
|
178
|
+
Input/...
|
|
179
|
+
Modal/...
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Output `.super-design/sessions/<id>/component-state-matrix.json`:
|
|
183
|
+
|
|
184
|
+
```json
|
|
185
|
+
{
|
|
186
|
+
"Button": {
|
|
187
|
+
"states_captured": ["default", "hover", "focus", "active", "disabled", "loading"],
|
|
188
|
+
"states_missing": ["error"],
|
|
189
|
+
"evidence": { "default": "components/Button/default.png", "..." }
|
|
190
|
+
},
|
|
191
|
+
"...": {}
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**Missing states → finding.**
|
|
196
|
+
|
|
197
|
+
### Phase E — Form state coverage
|
|
198
|
+
|
|
199
|
+
Per form discovered, test:
|
|
200
|
+
1. Empty submit → validation messages
|
|
201
|
+
2. Each field invalid individually → per-field error
|
|
202
|
+
3. All valid → success state
|
|
203
|
+
4. Server error (simulate 500) → error recovery
|
|
204
|
+
5. Network offline → offline handling
|
|
205
|
+
6. Paste into password field → paste NOT blocked
|
|
206
|
+
7. Autocomplete tokens on login fields (`username`, `current-password`, `one-time-code`)
|
|
207
|
+
8. Tab order matches visual order
|
|
208
|
+
9. Submit via Enter key works
|
|
209
|
+
10. Mobile viewport — input zoom behavior (iOS Safari `font-size < 16px`?)
|
|
210
|
+
|
|
211
|
+
Save: `.super-design/sessions/<id>/forms/<formId>_<scenario>.png`
|
|
212
|
+
|
|
213
|
+
## Orchestration summary
|
|
214
|
+
|
|
215
|
+
sd-audit adds this between Step 2 and Step 3:
|
|
216
|
+
|
|
217
|
+
```
|
|
218
|
+
Step 2.5 — Discovery
|
|
219
|
+
For each (page, viewport):
|
|
220
|
+
A. Interactive inventory
|
|
221
|
+
B. Modal/overlay enumeration (click every trigger)
|
|
222
|
+
C. Flow exercising (login, CRUD, checkout if applicable)
|
|
223
|
+
D. Component state matrix
|
|
224
|
+
E. Form state coverage
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
This takes 3–5× longer than static-only audit but produces ~3× the findings,
|
|
228
|
+
each with real evidence of failure conditions (not just hypothetical WCAG
|
|
229
|
+
violations on static markup).
|
|
230
|
+
|
|
231
|
+
## Budget & skipping
|
|
232
|
+
|
|
233
|
+
For very large apps, scope Phase B/C/D to:
|
|
234
|
+
- Top 5 most-clicked triggers per page (ranked by proximity to primary CTA)
|
|
235
|
+
- Critical flows only (login + checkout + 1 CRUD)
|
|
236
|
+
- 3 component classes minimum (Button, Input, Modal) — rest deferred to full-mode audit
|
|
237
|
+
|
|
238
|
+
Record what was skipped in `.super-design/sessions/<id>/scope.json` so later
|
|
239
|
+
runs can close the gap.
|
|
240
|
+
|
|
241
|
+
## Error handling
|
|
242
|
+
|
|
243
|
+
- **Triggered modal doesn't appear within 2s** — record "trigger broken" finding, move on
|
|
244
|
+
- **Console error after click** — record verbatim, still capture whatever rendered
|
|
245
|
+
- **Focus not trapped** — record a11y violation
|
|
246
|
+
- **Modal close fails** — force navigate away, record "close broken" finding
|
|
247
|
+
|
|
248
|
+
Never let a broken trigger abort the full audit — isolate and continue.
|
|
249
|
+
|
|
250
|
+
## Hard rules
|
|
251
|
+
|
|
252
|
+
1. Every Phase A inventory item must be considered for exercising; skips recorded.
|
|
253
|
+
2. Every modal opened must be screenshotted OPEN + CLOSED.
|
|
254
|
+
3. Every flow must capture at least one error path, not just happy path.
|
|
255
|
+
4. Component state matrix must declare which states are MISSING (not just captured).
|
|
256
|
+
5. Form state coverage — 10 scenarios per form; partial completion records which.
|
|
257
|
+
6. Use ONE Playwright session; reuse across phases; `browser_close` only at end.
|
|
258
|
+
7. Sequential, not parallel. Never spawn parallel tabs.
|