@draekien/create-d9-app 0.0.2 → 0.0.3
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 -1
- package/templates/base/.agents/skills/shadcn/SKILL.md +295 -0
- package/templates/base/.agents/skills/shadcn/agents/openai.yml +5 -0
- package/templates/base/.agents/skills/shadcn/assets/shadcn-small.png +0 -0
- package/templates/base/.agents/skills/shadcn/assets/shadcn.png +0 -0
- package/templates/base/.agents/skills/shadcn/assets/showcase/color-pair.tsx +126 -0
- package/templates/base/.agents/skills/shadcn/assets/showcase/preview-states.css +14 -0
- package/templates/base/.agents/skills/shadcn/assets/showcase/state-matrix.tsx +72 -0
- package/templates/base/.agents/skills/shadcn/cli.md +290 -0
- package/templates/base/.agents/skills/shadcn/customization.md +211 -0
- package/templates/base/.agents/skills/shadcn/design-system-page.md +268 -0
- package/templates/base/.agents/skills/shadcn/design-system.md +386 -0
- package/templates/base/.agents/skills/shadcn/evals/evals.json +126 -0
- package/templates/base/.agents/skills/shadcn/mcp.md +105 -0
- package/templates/base/.agents/skills/shadcn/registry.md +277 -0
- package/templates/base/.agents/skills/shadcn/rules/base-vs-radix.md +306 -0
- package/templates/base/.agents/skills/shadcn/rules/chat.md +250 -0
- package/templates/base/.agents/skills/shadcn/rules/composition.md +213 -0
- package/templates/base/.agents/skills/shadcn/rules/forms.md +192 -0
- package/templates/base/.agents/skills/shadcn/rules/icons.md +101 -0
- package/templates/base/.agents/skills/shadcn/rules/styling.md +185 -0
- package/templates/base/.agents/skills/shadcn/scripts/showcase-coverage.mjs +53 -0
- package/templates/base/.claude/rules/components.md +11 -0
- package/templates/base/.claude/rules/generated-files.md +11 -0
- package/templates/base/.claude/rules/testing.md +13 -0
- package/templates/base/.claude/rules/typescript.md +29 -0
- package/templates/base/.claude/skills/shadcn/SKILL.md +295 -0
- package/templates/base/.claude/skills/shadcn/agents/openai.yml +5 -0
- package/templates/base/.claude/skills/shadcn/assets/shadcn-small.png +0 -0
- package/templates/base/.claude/skills/shadcn/assets/shadcn.png +0 -0
- package/templates/base/.claude/skills/shadcn/assets/showcase/color-pair.tsx +126 -0
- package/templates/base/.claude/skills/shadcn/assets/showcase/preview-states.css +14 -0
- package/templates/base/.claude/skills/shadcn/assets/showcase/state-matrix.tsx +72 -0
- package/templates/base/.claude/skills/shadcn/cli.md +290 -0
- package/templates/base/.claude/skills/shadcn/customization.md +211 -0
- package/templates/base/.claude/skills/shadcn/design-system-page.md +268 -0
- package/templates/base/.claude/skills/shadcn/design-system.md +386 -0
- package/templates/base/.claude/skills/shadcn/evals/evals.json +126 -0
- package/templates/base/.claude/skills/shadcn/mcp.md +105 -0
- package/templates/base/.claude/skills/shadcn/registry.md +277 -0
- package/templates/base/.claude/skills/shadcn/rules/base-vs-radix.md +306 -0
- package/templates/base/.claude/skills/shadcn/rules/chat.md +250 -0
- package/templates/base/.claude/skills/shadcn/rules/composition.md +213 -0
- package/templates/base/.claude/skills/shadcn/rules/forms.md +192 -0
- package/templates/base/.claude/skills/shadcn/rules/icons.md +101 -0
- package/templates/base/.claude/skills/shadcn/rules/styling.md +185 -0
- package/templates/base/.claude/skills/shadcn/scripts/showcase-coverage.mjs +53 -0
- package/templates/base/AGENTS.md +9 -1
- package/templates/base/skills-lock.json +11 -0
- package/templates/tools/biome/.biome/catch-binding-unknown.grit +7 -0
- package/templates/tools/biome/.biome/effect-cleanup.grit +5 -2
- package/templates/tools/biome/.biome/handler-naming.grit +19 -6
- package/templates/tools/biome/.biome/no-class-error-boundary.grit +11 -0
- package/templates/tools/biome/.biome/no-direct-component-call.grit +20 -0
- package/templates/tools/biome/.biome/no-fetch-in-handler.grit +12 -0
- package/templates/tools/biome/.biome/no-impure-render.grit +7 -2
- package/templates/tools/biome/.biome/no-query-client-in-render.grit +4 -1
- package/templates/tools/biome/.biome/no-state-mutation.grit +19 -0
- package/templates/tools/biome/.biome/no-try-around-jsx.grit +6 -2
- package/templates/tools/biome/.biome/use-assert-never.grit +6 -0
- package/templates/tools/biome/biome.json +41 -3
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
# The Design System Page
|
|
2
|
+
|
|
3
|
+
What goes on a design system page, and how to show it. Distilled from Primer, Carbon, Atlassian, GitLab Pajamas, Cloudscape, Twilio Paste, Salesforce Lightning, Material 3, Evergreen and Orbit, and from EightShapes' component documentation guidance.
|
|
4
|
+
|
|
5
|
+
## Contents
|
|
6
|
+
|
|
7
|
+
- Principles
|
|
8
|
+
- Page outline
|
|
9
|
+
- Foundations
|
|
10
|
+
- Components: tiers and block anatomy
|
|
11
|
+
- States without interaction
|
|
12
|
+
- Edge cases
|
|
13
|
+
- Do and Don't
|
|
14
|
+
- Recipes and example screens
|
|
15
|
+
- Helpers
|
|
16
|
+
- Checklist
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Principles
|
|
21
|
+
|
|
22
|
+
1. **Foundations, then components, then compositions.** Every mature system follows this order (Primer, Carbon, Paste, Cloudscape, M3).
|
|
23
|
+
2. **Roles, not palettes.** Show each color as a surface paired with its foreground and the measured contrast. The raw palette comes second.
|
|
24
|
+
3. **Lead with the typical case.** Each component opens with its most common use in real content. Then come variants in priority order, then shared axes (size, icon), then states.
|
|
25
|
+
4. **Pin states so reviewers can see them.** Hover, focus and pressed render side by side without interaction. Use one consistent label, and never put the state name inside the component.
|
|
26
|
+
5. **Don't render every combination.** Primitives get a variant × state matrix. Composed components get a typical example plus additions. Exhaustive combinations belong in tests (Material 3 cut its list kit from 700+ variants to about 45).
|
|
27
|
+
6. **Real content in the brand's voice.** No lorem ipsum. Include the awkward cases: long text, empty, error, loading.
|
|
28
|
+
7. **Composition proves the system.** End with the DESIGN.md's own recipes and one realistic screen built only from the tokens and components.
|
|
29
|
+
8. **Make the DESIGN.md's rules visible.** Turn its Do's and Don'ts into rendered do/don't pairs.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Page Outline
|
|
34
|
+
|
|
35
|
+
| # | Section | Contents |
|
|
36
|
+
| --- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
|
37
|
+
| 1 | Header | System name, "Themed from DESIGN.md", section anchors, light/dark toggle, primary CTA. |
|
|
38
|
+
| 2 | Overview | The DESIGN.md hero recipe: display type, one-line personality, its signature artifact. |
|
|
39
|
+
| 3 | Foundations | Color roles, palette, typography, spacing, radius, elevation, motion (if specified), icons. |
|
|
40
|
+
| 4 | Actions | Button, ButtonGroup, Toggle, ToggleGroup, Badge, Kbd. |
|
|
41
|
+
| 5 | Inputs | Field, Input, InputGroup, Textarea, Select, NativeSelect, Combobox, Checkbox, RadioGroup, Switch, Slider, InputOTP, Calendar, Label. |
|
|
42
|
+
| 6 | Navigation | Tabs, Breadcrumb, Pagination, NavigationMenu, Menubar, Sidebar. |
|
|
43
|
+
| 7 | Data display | Card, Table, Chart, Item, Avatar, Accordion, Collapsible, Carousel, ScrollArea, Resizable, AspectRatio, Separator. |
|
|
44
|
+
| 8 | Feedback | Alert, toast (and Sonner in Base UI projects), Progress, Spinner, Skeleton, Empty. |
|
|
45
|
+
| 9 | Overlays | Dialog, AlertDialog, Sheet, Drawer, Popover, HoverCard, Tooltip, DropdownMenu, ContextMenu, Command. |
|
|
46
|
+
| 10 | Conversation | MessageScroller, Message, Bubble, Attachment, Marker, Questionnaire. See [rules/chat.md](./rules/chat.md). |
|
|
47
|
+
| 11 | Do and Don't | Rendered pairs for the DESIGN.md's rules. |
|
|
48
|
+
| 12 | Recipes and example screen | The DESIGN.md's named components, then one realistic screen. |
|
|
49
|
+
| 13 | Footer | The DESIGN.md footer recipe. |
|
|
50
|
+
|
|
51
|
+
DirectionProvider goes wherever RTL matters (an RTL row in Inputs or Navigation).
|
|
52
|
+
|
|
53
|
+
Alternate section surfaces the way the DESIGN.md paces its bands. Use `className="dark"` on a section to render a dark band with the same components.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Foundations
|
|
58
|
+
|
|
59
|
+
### Color roles
|
|
60
|
+
|
|
61
|
+
A grid of pairs, each rendered as the surface with "Aa" in its foreground color, plus the token names, resolved value and measured contrast (Paste, Material 3, Pajamas):
|
|
62
|
+
|
|
63
|
+
| Pair | Required |
|
|
64
|
+
| ------------------------------------- | ------------ |
|
|
65
|
+
| `background` / `foreground` | Yes |
|
|
66
|
+
| `card` / `card-foreground` | Yes |
|
|
67
|
+
| `popover` / `popover-foreground` | Yes |
|
|
68
|
+
| `primary` / `primary-foreground` | Yes |
|
|
69
|
+
| `secondary` / `secondary-foreground` | Yes |
|
|
70
|
+
| `muted` / `muted-foreground` | Yes |
|
|
71
|
+
| `accent` / `accent-foreground` | Yes |
|
|
72
|
+
| `destructive` on `background` | Yes |
|
|
73
|
+
| Each extra text token on `background` | When defined |
|
|
74
|
+
|
|
75
|
+
Use `ColorPair` from the helpers. It measures contrast live and re-measures when the theme changes. Report any pair below 4.5:1 for body-size text, even when the DESIGN.md specifies it. A brand primary at 3:1 behind 14px labels is a real finding.
|
|
76
|
+
|
|
77
|
+
### Palette
|
|
78
|
+
|
|
79
|
+
Swatches grouped the way the DESIGN.md groups them (brand, surfaces, text, status, accents). Label each with its DESIGN.md name and token, for example "Warm Stone · `surface-warm`". Show `border`, `input`, `ring`, `chart-1…5` and `sidebar-*` here too.
|
|
80
|
+
|
|
81
|
+
### Typography
|
|
82
|
+
|
|
83
|
+
A specimen table, one row per type token (Cloudscape, Carbon, Atlassian):
|
|
84
|
+
|
|
85
|
+
| Column | Content |
|
|
86
|
+
| -------- | ------------------------------------------------- |
|
|
87
|
+
| Token | `type-display-lg` |
|
|
88
|
+
| Spec | size / line height / weight / tracking |
|
|
89
|
+
| Use | "Section heads", taken from the DESIGN.md |
|
|
90
|
+
| Specimen | Real copy set in the token, truncated to one line |
|
|
91
|
+
|
|
92
|
+
Group the rows display → title → body → label/caption → code. Below the table, show one paragraph of running text at body size, with a link and inline code, so line length and rhythm are visible.
|
|
93
|
+
|
|
94
|
+
### Spacing
|
|
95
|
+
|
|
96
|
+
The base unit and the scale as labeled horizontal bars (Carbon, Atlassian), then a semantic ladder: inside a component, between related items, between groups, between sections (Pajamas). Skip it if the DESIGN.md defines no spacing.
|
|
97
|
+
|
|
98
|
+
### Radius
|
|
99
|
+
|
|
100
|
+
The same box at every step, labeled with the token, the value and what uses it (Material 3). Example: `md · 8px · buttons, inputs`.
|
|
101
|
+
|
|
102
|
+
### Elevation
|
|
103
|
+
|
|
104
|
+
Each level as a raised surface with the components that rest there (Pajamas, Material 3): flat for canvas and bands, hairline for cards, soft for popovers and menus, deep for dialogs.
|
|
105
|
+
|
|
106
|
+
### Motion and icons
|
|
107
|
+
|
|
108
|
+
Show motion only if the DESIGN.md defines durations or easings: a table of token, milliseconds and use. For icons, show one row with the icon library at each size used by components, in `foreground` and `muted-foreground`.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Components: Tiers and Block Anatomy
|
|
113
|
+
|
|
114
|
+
### Tiers
|
|
115
|
+
|
|
116
|
+
| Tier | Components | How to show |
|
|
117
|
+
| ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
|
|
118
|
+
| Primitives | Button, Badge, Toggle, ToggleGroup, Input, Textarea, Select, NativeSelect, Checkbox, RadioGroup, Switch, Slider, Tabs | Variant × state matrix, size ladder, icon row. |
|
|
119
|
+
| Fields | Field, InputGroup, Combobox, InputOTP, Calendar, Label | Typical field, then description, error, disabled, required. |
|
|
120
|
+
| Composed | Card, Table, Item, Avatar, Alert, Empty, toast, Sonner, Accordion, Collapsible, Breadcrumb, Pagination, Progress, Skeleton, Spinner, Carousel, Chart, ScrollArea, Resizable, AspectRatio, Separator, Kbd, ButtonGroup | Typical example, then one element added at a time, then edge cases. |
|
|
121
|
+
| Overlays | Dialog, AlertDialog, Sheet, Drawer, Popover, HoverCard, Tooltip, DropdownMenu, ContextMenu, Menubar, NavigationMenu, Command | A real trigger per overlay, labeled with what it opens. |
|
|
122
|
+
| Shell | Sidebar, DirectionProvider | Inline in a framed preview (`collapsible="none"`). |
|
|
123
|
+
| Conversation | MessageScroller, Message, Bubble, Attachment, Marker, Questionnaire | One realistic thread, then variant rows. |
|
|
124
|
+
|
|
125
|
+
### Block anatomy
|
|
126
|
+
|
|
127
|
+
Each component block, in this order. Skip the parts that don't apply:
|
|
128
|
+
|
|
129
|
+
1. **Name and one line on when to use it.** Take the wording from the DESIGN.md recipe when there is one.
|
|
130
|
+
2. **Typical example** in real content.
|
|
131
|
+
3. **Variants** in priority order (primary before secondary before ghost), each with a one-line "when".
|
|
132
|
+
4. **Sizes** as a ladder, smallest to largest.
|
|
133
|
+
5. **With icon**: leading, trailing, icon-only.
|
|
134
|
+
6. **States**: the matrix for primitives, single examples for the rest.
|
|
135
|
+
7. **Edge cases** (see below).
|
|
136
|
+
|
|
137
|
+
Wide components (Table, NavigationMenu, Menubar, Sidebar, Chart, MessageScroller) span the full row.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## States Without Interaction
|
|
142
|
+
|
|
143
|
+
Pin interaction states with a `data-preview` attribute. Override the hover, focus-visible and active variants so each also matches the attribute. Copy [assets/showcase/preview-states.css](./assets/showcase/preview-states.css) into `tailwindCssFile`:
|
|
144
|
+
|
|
145
|
+
```css
|
|
146
|
+
@custom-variant hover {
|
|
147
|
+
@media (hover: hover) {
|
|
148
|
+
&:hover {
|
|
149
|
+
@slot;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
&[data-preview~="hover"] {
|
|
153
|
+
@slot;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
@custom-variant focus-visible (&:focus-visible, &[data-preview~="focus"]);
|
|
157
|
+
@custom-variant active (&:active, &[data-preview~="active"]);
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
If the theme adds an unlayered focus rule (for an outline-style focus), add `[data-preview~="focus"]` to its selector too.
|
|
161
|
+
|
|
162
|
+
Render the matrix with `StateMatrix` and `previewState` from the helpers:
|
|
163
|
+
|
|
164
|
+
```tsx
|
|
165
|
+
const variants = ["default", "secondary", "outline", "ghost", "destructive", "link"] as const
|
|
166
|
+
|
|
167
|
+
<StateMatrix
|
|
168
|
+
rows={variants}
|
|
169
|
+
render={(variant, state) => (
|
|
170
|
+
<Button variant={variant} {...previewState(state)}>
|
|
171
|
+
Save draft
|
|
172
|
+
</Button>
|
|
173
|
+
)}
|
|
174
|
+
/>
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
The columns are default, hover, focus, active and disabled. Add `loading` with Spinner + `disabled` for Button, and `invalid` (`aria-invalid`) for fields:
|
|
178
|
+
|
|
179
|
+
```tsx
|
|
180
|
+
<StateMatrix
|
|
181
|
+
rows={["input"] as const}
|
|
182
|
+
states={["default", "hover", "focus", "disabled", "invalid"]}
|
|
183
|
+
render={(_, state) => (
|
|
184
|
+
<Input
|
|
185
|
+
placeholder="you@company.com"
|
|
186
|
+
aria-invalid={state === "invalid" || undefined}
|
|
187
|
+
{...previewState(state)}
|
|
188
|
+
/>
|
|
189
|
+
)}
|
|
190
|
+
/>
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
If the DESIGN.md says a state doesn't change ("primary darkens on press only"), leave that column identical. The matrix shows the spec is followed.
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Edge Cases
|
|
198
|
+
|
|
199
|
+
Show these next to the component they stress:
|
|
200
|
+
|
|
201
|
+
| Case | Where |
|
|
202
|
+
| ------------- | ------------------------------------------------------------------------- |
|
|
203
|
+
| Long text | Button label, Badge, Item title, Table cell, Breadcrumb (truncation). |
|
|
204
|
+
| Empty | Table with no rows → Empty, Combobox with no matches, empty Command. |
|
|
205
|
+
| Error | Field with FieldError, Alert destructive, Attachment `state="error"`. |
|
|
206
|
+
| Loading | Button with Spinner, Skeleton for Card and Item, Progress, toast loading. |
|
|
207
|
+
| Many items | AvatarGroup with count, Pagination with ellipsis, ScrollArea list. |
|
|
208
|
+
| Missing image | Avatar falling back to AvatarFallback. |
|
|
209
|
+
| Disabled | Every field and its Field `data-disabled`. |
|
|
210
|
+
| RTL | One row inside `DirectionProvider` with `dir="rtl"`. |
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Do and Don't
|
|
215
|
+
|
|
216
|
+
Pick the two to four DESIGN.md rules that are easiest to break and render each as a pair (Primer, Orbit, Carbon):
|
|
217
|
+
|
|
218
|
+
```tsx
|
|
219
|
+
<div className="grid gap-4 md:grid-cols-2">
|
|
220
|
+
<Example title="Do">
|
|
221
|
+
<Button>Get started</Button>
|
|
222
|
+
<Button variant="outline">Contact sales</Button>
|
|
223
|
+
</Example>
|
|
224
|
+
<Example title="Don't">
|
|
225
|
+
<Button>Get started</Button>
|
|
226
|
+
<Button>Contact sales</Button>
|
|
227
|
+
</Example>
|
|
228
|
+
</div>
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Caption each with the rule in one line, for example "One primary action per group." Mark Don't with `destructive` text, not a new color.
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Recipes and Example Screens
|
|
236
|
+
|
|
237
|
+
**Recipes.** Build each named component in the DESIGN.md (`hero-band`, `feature-card`, `pricing-tier-card`, `callout-card-coral`, `footer`) from shadcn components and tokens. These are the spec's acceptance tests. If a recipe can't be built without raw values, the token mapping is incomplete.
|
|
238
|
+
|
|
239
|
+
**Example screen.** One realistic screen in the brand's domain (Cloudscape demos, Paste page templates): a settings page (FieldGroup, Switch, Select, Button) or a list view (Table, Badge, Pagination, Empty). Use only tokens and components.
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Helpers
|
|
244
|
+
|
|
245
|
+
Copy from `assets/showcase/` into the showcase folder:
|
|
246
|
+
|
|
247
|
+
| File | Purpose |
|
|
248
|
+
| -------------------- | -------------------------------------------------------------------------- |
|
|
249
|
+
| `preview-states.css` | Variant overrides that pin hover, focus and active through `data-preview`. |
|
|
250
|
+
| `state-matrix.tsx` | `StateMatrix` (labeled variant × state table) and `previewState(state)`. |
|
|
251
|
+
| `color-pair.tsx` | `ColorPair`: surface + foreground with live contrast ratio and WCAG level. |
|
|
252
|
+
|
|
253
|
+
They import `cn` from `@/lib/utils`. Rewrite that path to the project's `utils` alias.
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Checklist
|
|
258
|
+
|
|
259
|
+
- [ ] Every installed component renders (run the coverage script).
|
|
260
|
+
- [ ] Color roles shown as pairs with contrast; any pair under 4.5:1 is noted in the report.
|
|
261
|
+
- [ ] Type specimen covers every DESIGN.md type token, in real copy.
|
|
262
|
+
- [ ] Radius and elevation ladders name the components that use each step.
|
|
263
|
+
- [ ] Primitives have a state matrix; Button and fields include loading and invalid.
|
|
264
|
+
- [ ] Edge cases: long text, empty, error, loading, missing image.
|
|
265
|
+
- [ ] Do/Don't pairs for the DESIGN.md's key rules.
|
|
266
|
+
- [ ] DESIGN.md recipes rebuilt, plus one example screen.
|
|
267
|
+
- [ ] Page-level theme toggle works, and at least one scoped dark band if the DESIGN.md has dark surfaces.
|
|
268
|
+
- [ ] No lorem ipsum, and no state names inside components.
|
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
# Design Systems from DESIGN.md
|
|
2
|
+
|
|
3
|
+
Build a new app from a preset, install every component, restyle it from a `DESIGN.md`, then render a design system page.
|
|
4
|
+
|
|
5
|
+
Trigger phrases: "build me a design system using <preset>", "apply this DESIGN.md", "create a showcase / design system page", "make shadcn look like <brand>".
|
|
6
|
+
|
|
7
|
+
## Contents
|
|
8
|
+
|
|
9
|
+
- Inputs to confirm
|
|
10
|
+
- Step 1: Scaffold
|
|
11
|
+
- Step 2: Install everything
|
|
12
|
+
- Step 3: Read the DESIGN.md
|
|
13
|
+
- Step 4: Map tokens to the theme
|
|
14
|
+
- Step 5: Map component recipes to variants
|
|
15
|
+
- Step 6: Build the design system page ([design-system-page.md](./design-system-page.md))
|
|
16
|
+
- Step 7: Verify
|
|
17
|
+
- Report back
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Inputs to Confirm
|
|
22
|
+
|
|
23
|
+
| Input | Default | Notes |
|
|
24
|
+
| --------- | ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
|
|
25
|
+
| Preset | Optional | Code (`b0`), style name (`luma`) or URL. Pass it through. Never decode it by hand. Without one, pick a style (see Step 1). |
|
|
26
|
+
| DESIGN.md | Required | A path, URL or pasted content. Copy it into the new app root as `DESIGN.md`. |
|
|
27
|
+
| Template | `vite` | Use `next` when the user says Next.js, App Router or SSR. |
|
|
28
|
+
| App name | Derived from the brand in DESIGN.md | Kebab-case. |
|
|
29
|
+
| Base | `base` | Pass `--base` when no preset code is given. Use `radix` only when the user asks. `info --json` after init decides `render` vs `asChild`. |
|
|
30
|
+
|
|
31
|
+
If the DESIGN.md path can't be read (macOS privacy blocks `~/Downloads` and `~/Desktop` for some hosts), ask the user to copy it into the working directory. Don't guess its contents.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Step 1: Scaffold
|
|
36
|
+
|
|
37
|
+
With a preset code from the user:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx shadcn@latest init --preset <code> --template vite --name <app> --no-monorepo -y
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Without one, pick the style whose geometry is closest to the DESIGN.md and pass it with `--base`:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npx shadcn@latest init --base base --preset <style> --template vite --name <app> --no-monorepo -y
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Then:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
cd <app>
|
|
53
|
+
npx shadcn@latest info --json
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`init` with neither `--preset` nor `--base` stops at an interactive library prompt, even with `-y`. Always pass one of them, plus `--no-monorepo`.
|
|
57
|
+
|
|
58
|
+
### Picking a style
|
|
59
|
+
|
|
60
|
+
The theme gets replaced by the DESIGN.md anyway. The style decides geometry the CSS variables can't reach: control padding, density, how rounded and how raised the components are. Read the DESIGN.md's radius scale, control heights, shadows and layout density, then pick:
|
|
61
|
+
|
|
62
|
+
| Style | Character | Pick when the DESIGN.md has |
|
|
63
|
+
| ------ | ----------------------------------------------------- | ---------------------------------------------------------------------- |
|
|
64
|
+
| `vega` | The classic shadcn/ui look. | Neutral, conventional SaaS geometry; nothing extreme. |
|
|
65
|
+
| `nova` | Reduced padding and margins for compact layouts. | 32–36px controls, 6–8px radius, hairlines over shadows. |
|
|
66
|
+
| `maia` | Soft and rounded, with generous spacing. | 40px+ controls, 12px+ card radius, generous padding, editorial pacing. |
|
|
67
|
+
| `lyra` | Boxy and sharp. | 0–4px radius, hard edges, mono or technical type. |
|
|
68
|
+
| `mira` | Compact. | Dense data UIs, 28–32px controls, tight tables. |
|
|
69
|
+
| `luma` | Rounded geometry, soft elevation, breathable layouts. | Pill buttons, soft layered shadows, glassy or macOS-like surfaces. |
|
|
70
|
+
| `rhea` | Luma, but more compact. | Luma's softness with product-UI density. |
|
|
71
|
+
| `sera` | Editorial and typographic. | Serif display type, editorial pacing, magazine-like hierarchy. |
|
|
72
|
+
|
|
73
|
+
State the choice and the reason in one line ("Picked maia: 40px controls, 12–16px cards, generous padding"). If the user names a style, use it. Read `base`, `style`, `iconLibrary`, `tailwindCssFile` and `aliases` from `info` before writing any code.
|
|
74
|
+
|
|
75
|
+
## Step 2: Install Everything
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npx shadcn@latest add --all -y
|
|
79
|
+
ls <resolvedPaths.ui>/*.tsx | wc -l
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Count the component files on disk. Never quote a component count from memory.
|
|
83
|
+
|
|
84
|
+
Then wire up the providers in the app root:
|
|
85
|
+
|
|
86
|
+
- Wrap the app in `TooltipProvider`.
|
|
87
|
+
- Base UI: wrap the app in `Toaster` from the `toast` component and call `toast.add({ title, description, type })`. Radix: render `<Toaster />` from `sonner`.
|
|
88
|
+
|
|
89
|
+
Then typecheck the app sources. In Vite apps, the root `tsc --noEmit` checks nothing because the root tsconfig only has project references:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
npx tsc -p tsconfig.app.json --noEmit # Vite.
|
|
93
|
+
npx tsc --noEmit # Next.js.
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Fix generated files that fail strict checks (for example, an unused `React` import) before moving on, or `vite build` will fail.
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Step 3: Read the DESIGN.md
|
|
101
|
+
|
|
102
|
+
DESIGN.md files usually carry YAML frontmatter (`colors`, `typography`, `rounded`, `spacing`, `components`) and prose sections (Overview, Colors, Typography, Layout, Elevation, Shapes, Components, Do's and Don'ts, Responsive, Known Gaps). Some only have prose with `{colors.x}` references. Handle both.
|
|
103
|
+
|
|
104
|
+
Long files exceed one read. Grep the headings first, then read frontmatter, **Do's and Don'ts**, **Iteration Guide** and **Known Gaps** in full. Those sections hold the rules that override defaults.
|
|
105
|
+
|
|
106
|
+
Extract into a working table before editing anything:
|
|
107
|
+
|
|
108
|
+
| Extract | Look for |
|
|
109
|
+
| --------------------- | --------------------------------------------------------------------- |
|
|
110
|
+
| Canvas and ink | `canvas`, `surface`, `ink`, "page floor", "body text" |
|
|
111
|
+
| Action color + states | `primary`, `-hover`, `-active`, `-pressed`, `-disabled`, `on-primary` |
|
|
112
|
+
| Secondary actions | `button-secondary` fill, text and border |
|
|
113
|
+
| Surfaces | card fills, soft bands, dark product surfaces |
|
|
114
|
+
| Lines | `hairline`, border alpha, "1px solid" |
|
|
115
|
+
| Focus | outline vs ring, color, width, offset, alpha |
|
|
116
|
+
| Type families | display, body, mono, and the documented **substitutes** |
|
|
117
|
+
| Type scale | size, weight, line height, tracking per token |
|
|
118
|
+
| Radius scale | every value and what it applies to |
|
|
119
|
+
| Elevation | each shadow tier, verbatim |
|
|
120
|
+
| Control heights | button, input, ghost, icon-button heights and padding |
|
|
121
|
+
| Hard rules | every "Don't" and "never" |
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Step 4: Map Tokens to the Theme
|
|
126
|
+
|
|
127
|
+
Edit only `tailwindCssFile`. Keep hex values when the DESIGN.md gives hex. Don't convert them to OKLCH.
|
|
128
|
+
|
|
129
|
+
### Role mapping
|
|
130
|
+
|
|
131
|
+
| DESIGN.md role | shadcn variable |
|
|
132
|
+
| -------------------------------------------- | ----------------------------------------------------------- |
|
|
133
|
+
| canvas / surface / page floor | `--background` |
|
|
134
|
+
| ink / headline text | `--foreground`, `--card-foreground`, `--popover-foreground` |
|
|
135
|
+
| primary CTA fill / on-primary | `--primary` / `--primary-foreground` |
|
|
136
|
+
| primary hover, pressed or active fill | new `--primary-active` (or `--primary-pressed`) |
|
|
137
|
+
| secondary button fill / text | `--secondary` / `--secondary-foreground` |
|
|
138
|
+
| soft band, alternating section | `--muted` |
|
|
139
|
+
| secondary or descriptive text | `--muted-foreground` |
|
|
140
|
+
| ghost hover wash, active tab, menu highlight | `--accent` / `--accent-foreground` |
|
|
141
|
+
| card / feature card fill | `--card` |
|
|
142
|
+
| floating layer (menus, dialogs) | `--popover` (usually the canvas) |
|
|
143
|
+
| hairline / structural border | `--border`, `--input` |
|
|
144
|
+
| focus color | `--ring` |
|
|
145
|
+
| error / validation | `--destructive` |
|
|
146
|
+
| illustration accents | `--chart-1` … `--chart-5`, plus named tokens |
|
|
147
|
+
| sidebar or nav rail surface | `--sidebar-*` |
|
|
148
|
+
|
|
149
|
+
Every token without a shadcn slot gets a variable in `:root` (and `.dark` when it changes) and a registration in `@theme inline`:
|
|
150
|
+
|
|
151
|
+
```css
|
|
152
|
+
:root {
|
|
153
|
+
--primary-active: #a9583e;
|
|
154
|
+
--surface-card: #efe9de;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
@theme inline {
|
|
158
|
+
--color-primary-active: var(--primary-active);
|
|
159
|
+
--color-surface-card: var(--surface-card);
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Radius
|
|
164
|
+
|
|
165
|
+
A DESIGN.md radius scale rarely fits the `--radius` multipliers. Pin each step in `@theme inline` instead. These are the classes base-nova components use:
|
|
166
|
+
|
|
167
|
+
| Class | Used by |
|
|
168
|
+
| ------------- | ----------------------------------------------- |
|
|
169
|
+
| `rounded-sm` | Small accents |
|
|
170
|
+
| `rounded-md` | Menu, select and command items |
|
|
171
|
+
| `rounded-lg` | Buttons, inputs, selects, tabs, popovers, menus |
|
|
172
|
+
| `rounded-xl` | Cards, dialogs, command |
|
|
173
|
+
| `rounded-2xl` | Toasts, large containers |
|
|
174
|
+
| `rounded-4xl` | Badges (pill) |
|
|
175
|
+
|
|
176
|
+
```css
|
|
177
|
+
@theme inline {
|
|
178
|
+
/* DESIGN.md step → Tailwind class used by that component. */
|
|
179
|
+
--radius-sm: 4px; /* xs: accents. */
|
|
180
|
+
--radius-md: 6px; /* sm: menu items. */
|
|
181
|
+
--radius-lg: 8px; /* md: buttons, inputs. */
|
|
182
|
+
--radius-xl: 12px; /* lg: cards, dialogs. */
|
|
183
|
+
--radius-2xl: 16px; /* xl: toasts, hero containers. */
|
|
184
|
+
--radius-3xl: 16px;
|
|
185
|
+
--radius-4xl: 9999px; /* pill: badges. */
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Replace the existing `--radius-*` lines in `@theme inline` rather than adding a second block. Confirm the classes for the installed style:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
grep -ohE "rounded-(\[[^ \"]+\]|[a-z0-9]+)" <ui>/*.tsx | sort | uniq -c
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
`rounded-[min(var(--radius-md),Npx)]` caps small buttons and select triggers. Edit the cap when the DESIGN.md wants rounder small controls.
|
|
196
|
+
|
|
197
|
+
### Elevation
|
|
198
|
+
|
|
199
|
+
Override Tailwind's shadow scale in `@theme`, not `@theme inline`. Copy multi-layer shadows verbatim. Set `--shadow-xs` to `0 0 #0000` when the system is hairline-only, because inputs and outline buttons use it.
|
|
200
|
+
|
|
201
|
+
```css
|
|
202
|
+
@theme {
|
|
203
|
+
--shadow-xs: 0 0 #0000;
|
|
204
|
+
--shadow-sm: 0 1px 3px rgb(20 20 19 / 0.08);
|
|
205
|
+
--shadow-lg: 0 1px 3px rgb(20 20 19 / 0.08), 0 8px 24px rgb(20 20 19 / 0.06);
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Fonts
|
|
210
|
+
|
|
211
|
+
Brand fonts are usually licensed. Use the substitutes the DESIGN.md names, installed from Fontsource with the project's package manager, and import every face you reference at the top of the CSS file:
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
npm install @fontsource-variable/inter @fontsource-variable/cormorant-garamond @fontsource-variable/jetbrains-mono
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
```css
|
|
218
|
+
@import "@fontsource-variable/inter";
|
|
219
|
+
@import "@fontsource-variable/cormorant-garamond";
|
|
220
|
+
@import "@fontsource-variable/jetbrains-mono";
|
|
221
|
+
|
|
222
|
+
@theme inline {
|
|
223
|
+
--font-sans: "Inter Variable", -apple-system, system-ui, sans-serif;
|
|
224
|
+
--font-serif: "Cormorant Garamond Variable", Garamond, serif;
|
|
225
|
+
--font-mono: "JetBrains Mono Variable", ui-monospace, monospace;
|
|
226
|
+
--font-heading: var(--font-sans);
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
`--font-heading` styles small component titles (`CardTitle`, `DialogTitle`, `SheetTitle`). Point it at the display face only when that face reads well at 16px. Otherwise keep it on the sans and use display tokens for page headings.
|
|
231
|
+
|
|
232
|
+
### Type scale
|
|
233
|
+
|
|
234
|
+
Turn every typography token into a `type-*` utility. Don't use `--text-*` theme keys for this, because `cn()` treats unknown `text-*` classes as colors and drops whichever comes first when one sits next to `text-muted-foreground`.
|
|
235
|
+
|
|
236
|
+
```css
|
|
237
|
+
@utility type-display-lg {
|
|
238
|
+
font-family: var(--font-serif);
|
|
239
|
+
font-size: clamp(34px, 3vw + 16px, 48px);
|
|
240
|
+
font-weight: 500;
|
|
241
|
+
line-height: 1.1;
|
|
242
|
+
letter-spacing: -0.021em;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
@utility type-caption-upper {
|
|
246
|
+
font-size: 12px;
|
|
247
|
+
font-weight: 500;
|
|
248
|
+
letter-spacing: 1.5px;
|
|
249
|
+
text-transform: uppercase;
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
- Clamp display sizes so mobile works. Convert pixel tracking to `em` (`-1px / 48px = -0.021em`) so the ratio holds as the size shrinks.
|
|
254
|
+
- Respect the rules on tracking (none below a size) and weight (display never bold).
|
|
255
|
+
|
|
256
|
+
### Dark mode
|
|
257
|
+
|
|
258
|
+
- **DESIGN.md defines dark surfaces** (product mockups, footers): put them in `.dark`. Because shadcn's `@custom-variant dark (&:is(.dark *))` scopes to descendants, `className="dark"` on any section renders every component inside it with dark tokens. Use it for dark bands, featured pricing cards and footers.
|
|
259
|
+
- **DESIGN.md is light-only**: derive `.dark` from the brand's known dark surfaces and tell the user it's derived.
|
|
260
|
+
|
|
261
|
+
### Focus
|
|
262
|
+
|
|
263
|
+
Match the documented focus treatment:
|
|
264
|
+
|
|
265
|
+
- **Ring with alpha** (for example "3px coral at 15%"): replace `ring-ring/50` with the documented alpha on field components (`input`, `textarea`, `input-group`, `select`, `native-select`, `combobox`, `input-otp`).
|
|
266
|
+
- **Solid outline with offset**: add an unlayered rule so it beats `outline-none`, and cancel the ring shadow:
|
|
267
|
+
|
|
268
|
+
```css
|
|
269
|
+
:is(
|
|
270
|
+
button,
|
|
271
|
+
a[href],
|
|
272
|
+
[role="button"],
|
|
273
|
+
[role="tab"],
|
|
274
|
+
[role="checkbox"],
|
|
275
|
+
[role="radio"],
|
|
276
|
+
[role="switch"],
|
|
277
|
+
[role="slider"]
|
|
278
|
+
):focus-visible {
|
|
279
|
+
outline: 2px solid var(--ring);
|
|
280
|
+
outline-offset: 2px;
|
|
281
|
+
--tw-ring-shadow: 0 0 #0000;
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
This covers actions only. Field controls keep their ring. When the DESIGN.md applies the outline to fields too, add `input, textarea, select, [role="combobox"]` to the selector.
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## Step 5: Map Component Recipes to Variants
|
|
290
|
+
|
|
291
|
+
Restyle by editing the `cva` variants in the installed component source. Keep existing variant names so usage stays standard. Add a variant only when the DESIGN.md defines a distinct recipe.
|
|
292
|
+
|
|
293
|
+
| DESIGN.md recipe | shadcn target |
|
|
294
|
+
| ------------------------------------ | -------------------------------------------- |
|
|
295
|
+
| `button-primary` | `Button` `default` |
|
|
296
|
+
| `button-secondary` (tinted fill) | `Button` `secondary` |
|
|
297
|
+
| `button-secondary` (canvas + border) | `Button` `outline` |
|
|
298
|
+
| `button-ghost`, nav links | `Button` `ghost` |
|
|
299
|
+
| text link | `Button` `link` |
|
|
300
|
+
| circular icon button | `Button` `icon*` sizes + `rounded-full` |
|
|
301
|
+
| `badge-pill`, `badge-<accent>` | `Badge` `secondary`, `default`, new variants |
|
|
302
|
+
| `card`, `feature-card` | `Card` (fill, ring, `--card-spacing`) |
|
|
303
|
+
| `text-input`, `-focused` | `Input`, `InputGroup`, `Select`, `Textarea` |
|
|
304
|
+
| `category-tab`, filter row | `Tabs` `default` list + trigger |
|
|
305
|
+
|
|
306
|
+
**Control heights move together.** When the button height changes, change the field controls to match, or forms misalign. In base-nova the 32px default lives in:
|
|
307
|
+
|
|
308
|
+
| File | Class |
|
|
309
|
+
| ------------------- | -------------------------------- |
|
|
310
|
+
| `button.tsx` | `h-8`, `size-8` (icon) |
|
|
311
|
+
| `input.tsx` | `h-8` |
|
|
312
|
+
| `input-group.tsx` | `h-8` |
|
|
313
|
+
| `select.tsx` | `data-[size=default]:h-8` |
|
|
314
|
+
| `native-select.tsx` | `h-8` |
|
|
315
|
+
| `combobox.tsx` | `min-h-8` (chips) |
|
|
316
|
+
| `toggle.tsx` | `h-8 min-w-8` |
|
|
317
|
+
| `input-otp.tsx` | `size-8` (slot) |
|
|
318
|
+
| `tabs.tsx` | `group-data-horizontal/tabs:h-8` |
|
|
319
|
+
| `menubar.tsx` | `h-8` |
|
|
320
|
+
| `command.tsx` | `h-8!` (input group) |
|
|
321
|
+
|
|
322
|
+
Re-grep before editing (`grep -n "\bh-8\b\|size-8\b" <ui>/*.tsx`); other styles use different values.
|
|
323
|
+
|
|
324
|
+
**States.** Follow the documented states exactly. If the DESIGN.md says "darken on press only", use `active:` instead of `hover:`. Keep hover on ghost buttons and menu items even when the spec omits it, and tell the user you did.
|
|
325
|
+
|
|
326
|
+
**Hard rules.** Turn each "Don't" into a check before you finish, for example: no radius outside the scale, no accent color on buttons, no bold display type.
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## Step 6: Build the Design System Page
|
|
331
|
+
|
|
332
|
+
Follow [design-system-page.md](./design-system-page.md). It sets the section outline, how to present each foundation, the component tiers and block anatomy, pinned state matrices, edge cases, do/don't pairs, and recipes.
|
|
333
|
+
|
|
334
|
+
In short:
|
|
335
|
+
|
|
336
|
+
1. Foundations first: color roles as contrast-checked pairs, palette, type specimen table, spacing, radius and elevation ladders.
|
|
337
|
+
2. Components by tier: primitives get a variant × state matrix, size ladder and icon row. Composed components get a typical example, additions and edge cases. Overlays get real triggers.
|
|
338
|
+
3. Then rendered do/don't pairs for the DESIGN.md's rules, the DESIGN.md's named recipes rebuilt from components, and one example screen.
|
|
339
|
+
|
|
340
|
+
Copy the helpers from `assets/showcase/` (`preview-states.css`, `state-matrix.tsx`, `color-pair.tsx`). Put sections in `src/showcase/<section>.tsx` (Vite) or `app/design-system/` (Next.js). Write copy in the brand's voice.
|
|
341
|
+
|
|
342
|
+
### Known traps
|
|
343
|
+
|
|
344
|
+
| Component | Trap | Fix |
|
|
345
|
+
| ------------------- | --------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
|
|
346
|
+
| `Command` inline | cmdk scrolls its first item into view on mount, which jumps the page to it. | Control it: `value={value} onValueChange={setValue}` with initial `"none"`. |
|
|
347
|
+
| `Sidebar` | Default sidebar is `fixed` and escapes the preview frame. | `<SidebarProvider className="min-h-0">` + `<Sidebar collapsible="none">`. |
|
|
348
|
+
| `MessageFooter` | Placed beside `MessageContent`, it becomes a squeezed flex column. | Put it inside `MessageContent`. |
|
|
349
|
+
| `Select` (base) | `SelectValue` shows the raw value. | Pass `items` to `Select`. |
|
|
350
|
+
| `Resizable` | react-resizable-panels v4 dropped `direction` and numeric sizes. | `orientation="horizontal"`, `defaultSize="40%"`. |
|
|
351
|
+
| `DirectionProvider` | Provider alone doesn't flip layout. | Also set `dir="rtl"` on the wrapper. |
|
|
352
|
+
| `NavigationMenu` | The content is clipped by the example frame. | Leave bottom padding in that frame. |
|
|
353
|
+
| Header nav links | `Button` renders a `<button>`. | Base: `nativeButton={false} render={<a href="#…" />}`. Radix: `asChild`. |
|
|
354
|
+
|
|
355
|
+
### Coverage check
|
|
356
|
+
|
|
357
|
+
```bash
|
|
358
|
+
node <skill-dir>/scripts/showcase-coverage.mjs src/components/ui src # Vite.
|
|
359
|
+
node <skill-dir>/scripts/showcase-coverage.mjs components/ui app # Next.js.
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
It lists every component file that no showcase file imports. Fix the list until it's empty. `add --all` installs both `toast` and `sonner` in Base UI projects; show `sonner` in Feedback next to `toast` so the list can reach zero.
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
## Step 7: Verify
|
|
367
|
+
|
|
368
|
+
Start the dev server and check it in a browser:
|
|
369
|
+
|
|
370
|
+
1. App typecheck passes (see Step 2).
|
|
371
|
+
2. No console errors.
|
|
372
|
+
3. Loads at `scrollY === 0`. Anything else means a component is stealing scroll on mount.
|
|
373
|
+
4. No horizontal overflow at 375px and 1280px: `document.documentElement.scrollWidth <= innerWidth`.
|
|
374
|
+
5. Screenshot the hero, Foundations, one form section and one dark band. Compare against the DESIGN.md: canvas color, CTA color, display font, radius, focus ring.
|
|
375
|
+
6. Toggle dark mode once.
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
## Report Back
|
|
380
|
+
|
|
381
|
+
- App path, dev URL, component count from disk.
|
|
382
|
+
- The style picked (when no preset was given) and why.
|
|
383
|
+
- What maps where: colors, fonts (and substitutes), radius, shadows, focus.
|
|
384
|
+
- Contrast pairs under 4.5:1, including ones the DESIGN.md itself specifies.
|
|
385
|
+
- Every component file you edited and why.
|
|
386
|
+
- Every deliberate deviation from the DESIGN.md (derived dark mode, kept hover, substituted fonts).
|