baldart 3.10.0 → 3.13.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/CHANGELOG.md +82 -0
- package/README.md +34 -2
- package/VERSION +1 -1
- package/bin/baldart.js +14 -0
- package/framework/.claude/agents/REGISTRY.md +2 -2
- package/framework/.claude/agents/code-reviewer.md +47 -11
- package/framework/.claude/agents/ui-expert.md +355 -43
- package/framework/.claude/commands/design-review.md +7 -0
- package/framework/.claude/skills/design-system-init/SKILL.md +232 -0
- package/framework/.claude/skills/design-system-init/scripts/component-spec.template.md +79 -0
- package/framework/.claude/skills/frontend-design/SKILL.md +124 -0
- package/framework/.claude/skills/motion-design/reference/accessibility-and-modern-apis.md +114 -0
- package/framework/.claude/skills/ui-design/SKILL.md +43 -0
- package/framework/agents/design-review.md +51 -0
- package/framework/agents/design-system-protocol.md +363 -0
- package/framework/agents/index.md +2 -0
- package/framework/docs/UPGRADE-3.12-UI-COHERENCE.md +268 -0
- package/package.json +1 -1
- package/src/commands/configure.js +21 -0
- package/src/commands/doctor.js +54 -2
- package/src/commands/update.js +15 -1
- package/src/commands/version.js +5 -1
- package/src/utils/state.js +27 -0
- package/src/utils/update-notifier.js +181 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: design-system-init
|
|
3
|
+
description: >
|
|
4
|
+
Bootstrap a component registry / design system on a project that doesn't have
|
|
5
|
+
one yet. Scaffolds ${paths.design_system}/INDEX.md (component index +
|
|
6
|
+
Canonical Authority Matrix), tokens-reference.md (extracted from
|
|
7
|
+
${paths.global_styles} / Tailwind config), and a components/<Name>.md spec
|
|
8
|
+
per primitive already present under ${paths.components_primitives}. Then
|
|
9
|
+
flips features.has_design_system: true in baldart.config.yml. Use when the
|
|
10
|
+
user says /design-system-init, "crea design system", "bootstrap design
|
|
11
|
+
system", "inizializza registro componenti", or when configure detected no
|
|
12
|
+
design-system path and the user wants one. Idempotent — refuses to overwrite
|
|
13
|
+
an existing registry, supports incremental re-runs to add specs for new
|
|
14
|
+
components.
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# Design-System Init
|
|
18
|
+
|
|
19
|
+
Scaffold the component registry that the registry-first protocol
|
|
20
|
+
(`framework/agents/design-system-protocol.md`) treats as BLOCKING for every
|
|
21
|
+
UI task. Without a registry, the BLOCKING reads in `ui-design`,
|
|
22
|
+
`frontend-design`, `ui-expert`, and `/design-review` are inert — they have
|
|
23
|
+
nothing to read. This skill creates the missing pieces from the codebase's
|
|
24
|
+
current state so the discipline can kick in immediately.
|
|
25
|
+
|
|
26
|
+
## Project Context
|
|
27
|
+
|
|
28
|
+
**Reads from `baldart.config.yml`:** `paths.design_system`,
|
|
29
|
+
`paths.components_primitives`, `paths.components_root`, `paths.global_styles`,
|
|
30
|
+
`paths.ui_guidelines`, `identity.brand_name`, `identity.design_philosophy`,
|
|
31
|
+
`stack.design_system_signals`.
|
|
32
|
+
|
|
33
|
+
**Gated by features:** none — this skill is the bootstrap mechanism for
|
|
34
|
+
`features.has_design_system`. It refuses to run when a registry is already
|
|
35
|
+
present (`has_design_system: true` AND `paths.design_system/INDEX.md` exists).
|
|
36
|
+
|
|
37
|
+
**Overlay:** loads `.baldart/overlays/design-system-init.md` if present —
|
|
38
|
+
project-specific opinions (e.g. mandated section order in `components/<Name>.md`,
|
|
39
|
+
brand-voice rules to inject into the scaffolded INDEX, custom token extraction
|
|
40
|
+
recipe for non-Tailwind stacks).
|
|
41
|
+
|
|
42
|
+
**On missing keys:** ask the user; do not assume defaults. See
|
|
43
|
+
`framework/agents/project-context.md` § 3.
|
|
44
|
+
|
|
45
|
+
## What This Skill Does
|
|
46
|
+
|
|
47
|
+
1. **Refusal check.** Reads `baldart.config.yml`.
|
|
48
|
+
- If `features.has_design_system: true` AND `${paths.design_system}/INDEX.md`
|
|
49
|
+
exists: stop with "Registry already present at `${paths.design_system}`.
|
|
50
|
+
To extend it, edit it directly or invoke `ui-design` / `frontend-design`
|
|
51
|
+
which know how to propose registry additions."
|
|
52
|
+
- If `has_design_system: true` but the path is missing: warn about the
|
|
53
|
+
drift, offer to re-scaffold at the configured path.
|
|
54
|
+
2. **Resolve target path.** Default `docs/design-system/`. Ask the user to
|
|
55
|
+
confirm or override. Use `${paths.design_system}` if already set in config.
|
|
56
|
+
3. **Inventory existing primitives.** Launch the `codebase-architect` agent
|
|
57
|
+
on `${paths.components_primitives}` (and `${paths.components_root}/shared`
|
|
58
|
+
when present) to extract: file path, exported component name, props
|
|
59
|
+
signature, variants (if discoverable), accessibility hooks used, tokens
|
|
60
|
+
referenced.
|
|
61
|
+
4. **Extract token contract.** Read `${paths.global_styles}` for CSS custom
|
|
62
|
+
properties; read `tailwind.config.{ts,js,mjs,cjs}` for theme extensions;
|
|
63
|
+
read any `tokens.{json,ts,js}` or Style Dictionary output. Group by
|
|
64
|
+
category (color, spacing, shadow, radius, typography, motion).
|
|
65
|
+
5. **Scaffold the files** under the target path:
|
|
66
|
+
- `INDEX.md` — component index, Canonical Authority Matrix (empty
|
|
67
|
+
visual/behavioral/composition columns to be filled by the team),
|
|
68
|
+
pointer to `tokens-reference.md` and `components/`.
|
|
69
|
+
- `tokens-reference.md` — extracted tokens, grouped, with a note that
|
|
70
|
+
`tokens-reference.md` is the SSOT and hardcoded literals are forbidden.
|
|
71
|
+
- `components/<Name>.md` — one file per discovered primitive, generated
|
|
72
|
+
from `scripts/component-spec.template.md`. Fill the fields the inventory
|
|
73
|
+
could resolve; leave clearly-marked TODO sections for the rest.
|
|
74
|
+
- `patterns/.gitkeep` — empty dir for future pattern docs.
|
|
75
|
+
6. **Update config.** Set `features.has_design_system: true` and
|
|
76
|
+
`paths.design_system: <target>` in `baldart.config.yml`. Use the same
|
|
77
|
+
YAML write path as `configure` (preserve user values, never clobber
|
|
78
|
+
unrelated keys).
|
|
79
|
+
7. **Print next-steps.** Authority Matrix to fill, specs to review, suggested
|
|
80
|
+
first follow-up (`/design-review` on a key route to validate the registry).
|
|
81
|
+
|
|
82
|
+
## Workflow
|
|
83
|
+
|
|
84
|
+
1. **Refusal check** — see § What This Skill Does step 1.
|
|
85
|
+
|
|
86
|
+
2. **Target path prompt:**
|
|
87
|
+
```
|
|
88
|
+
Scaffold the registry at: docs/design-system/ [Y/n/custom]
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
3. **Inventory** — launch `codebase-architect` with this prompt skeleton:
|
|
92
|
+
> Enumerate the UI primitives under `${paths.components_primitives}`. For
|
|
93
|
+
> each: file path, exported name, props type (best-effort from TS/JSDoc),
|
|
94
|
+
> variants (e.g. `variant="primary|ghost"`), accessibility attributes
|
|
95
|
+
> (aria-*, role, focus management), design tokens referenced (CSS vars,
|
|
96
|
+
> Tailwind classes that map to tokens). Report as a JSON-friendly list.
|
|
97
|
+
|
|
98
|
+
4. **Token extraction** — for each detected source:
|
|
99
|
+
- CSS custom properties: parse `--*: ...;` declarations and group by prefix.
|
|
100
|
+
- Tailwind theme: parse `theme.extend.{colors,spacing,boxShadow,borderRadius,fontFamily,transitionDuration,transitionTimingFunction}`.
|
|
101
|
+
- Style Dictionary / tokens file: parse the JSON tree.
|
|
102
|
+
- If nothing is found, leave a TODO section in `tokens-reference.md`
|
|
103
|
+
pointing the team to populate it before relying on the SSOT contract.
|
|
104
|
+
|
|
105
|
+
5. **Generate files** using the template in
|
|
106
|
+
`scripts/component-spec.template.md` for each component, and the inline
|
|
107
|
+
templates below for INDEX and tokens-reference.
|
|
108
|
+
|
|
109
|
+
6. **Persist config:**
|
|
110
|
+
```yaml
|
|
111
|
+
paths:
|
|
112
|
+
design_system: docs/design-system # or user-chosen
|
|
113
|
+
features:
|
|
114
|
+
has_design_system: true
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
7. **Output** — short status block (see Output Contract).
|
|
118
|
+
|
|
119
|
+
## Output Contract
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
Design-system bootstrap:
|
|
123
|
+
✓ Created docs/design-system/INDEX.md
|
|
124
|
+
✓ Created docs/design-system/tokens-reference.md (32 tokens extracted)
|
|
125
|
+
✓ Generated 17 component specs under docs/design-system/components/
|
|
126
|
+
⚠ 4 components had no resolvable props — TODO sections marked
|
|
127
|
+
Config updated: baldart.config.yml has_design_system=true, paths.design_system=docs/design-system
|
|
128
|
+
Next: review INDEX.md Authority Matrix, fill TODO sections, run /design-review on a key route.
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## INDEX.md template
|
|
132
|
+
|
|
133
|
+
The generated `INDEX.md` has this skeleton (concrete values substituted from
|
|
134
|
+
the inventory):
|
|
135
|
+
|
|
136
|
+
```markdown
|
|
137
|
+
# ${identity.brand_name} Design System
|
|
138
|
+
|
|
139
|
+
Single source of truth for visual, behavioral, and compositional decisions on
|
|
140
|
+
this product. Read this BEFORE producing or reviewing any UI. The registry-first
|
|
141
|
+
protocol is defined in `framework/agents/design-system-protocol.md`.
|
|
142
|
+
|
|
143
|
+
## Token Contract
|
|
144
|
+
|
|
145
|
+
Tokens live in [`tokens-reference.md`](tokens-reference.md). Hardcoded color /
|
|
146
|
+
shadow / radius / spacing / motion values are FORBIDDEN when these tokens
|
|
147
|
+
cover the use case.
|
|
148
|
+
|
|
149
|
+
## Component Index
|
|
150
|
+
|
|
151
|
+
| Component | File | Purpose | Spec |
|
|
152
|
+
|-----------|------|---------|------|
|
|
153
|
+
| Button | ${paths.components_primitives}/Button.tsx | … | [components/Button.md](components/Button.md) |
|
|
154
|
+
| … | … | … | … |
|
|
155
|
+
|
|
156
|
+
## Canonical Authority Matrix
|
|
157
|
+
|
|
158
|
+
| Dimension | Authority | Override path |
|
|
159
|
+
|--------------------|---------------------------------|---------------|
|
|
160
|
+
| Color / shadow / radius / spacing | `tokens-reference.md` | Propose a new token + ADR |
|
|
161
|
+
| Props / variants / a11y | per-component `components/<Name>.md` | Update the spec in the same change |
|
|
162
|
+
| Composition (patterns) | `patterns/<topic>.md` | New pattern doc + INDEX entry |
|
|
163
|
+
|
|
164
|
+
## Quick MUST Rules
|
|
165
|
+
|
|
166
|
+
- Reuse from the Component Index before inventing a new primitive.
|
|
167
|
+
- Consume tokens via the project's mechanism (CSS vars / Tailwind theme /
|
|
168
|
+
theme provider) — never hardcode literals.
|
|
169
|
+
- Any new primitive ships with its `components/<Name>.md` spec in the same
|
|
170
|
+
change.
|
|
171
|
+
- Authority Matrix violations require a registry update, not a local override.
|
|
172
|
+
|
|
173
|
+
## How to Extend
|
|
174
|
+
|
|
175
|
+
- New primitive → create `components/<Name>.md` (the template lives at
|
|
176
|
+
`.framework/framework/.claude/skills/design-system-init/scripts/component-spec.template.md`
|
|
177
|
+
after `npx baldart add` — copy it, fill it in, drop under
|
|
178
|
+
`${paths.design_system}/components/`),
|
|
179
|
+
implement under `${paths.components_primitives}`, add the row above.
|
|
180
|
+
- New pattern → create `patterns/<topic>.md`, link from this INDEX.
|
|
181
|
+
- New token → add to `tokens-reference.md`, propagate to the project's
|
|
182
|
+
token mechanism.
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## tokens-reference.md template
|
|
186
|
+
|
|
187
|
+
```markdown
|
|
188
|
+
# Token Reference
|
|
189
|
+
|
|
190
|
+
Single source of truth for design tokens. Values below are extracted from
|
|
191
|
+
${paths.global_styles} and tailwind config (when present). DO NOT hardcode
|
|
192
|
+
literals that duplicate these tokens in components.
|
|
193
|
+
|
|
194
|
+
## Color
|
|
195
|
+
- `--color-primary: <value>` — …
|
|
196
|
+
- …
|
|
197
|
+
|
|
198
|
+
## Spacing
|
|
199
|
+
- `--space-1: <value>` — …
|
|
200
|
+
- …
|
|
201
|
+
|
|
202
|
+
## Shadow
|
|
203
|
+
- …
|
|
204
|
+
|
|
205
|
+
## Radius
|
|
206
|
+
- …
|
|
207
|
+
|
|
208
|
+
## Typography
|
|
209
|
+
- …
|
|
210
|
+
|
|
211
|
+
## Motion
|
|
212
|
+
- duration: …
|
|
213
|
+
- easing: …
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Notes
|
|
217
|
+
|
|
218
|
+
- The skill never modifies source components — its only side effects are
|
|
219
|
+
creating files under `${paths.design_system}` and updating
|
|
220
|
+
`baldart.config.yml`.
|
|
221
|
+
- Generated specs are starting points, not final docs. The expected next move
|
|
222
|
+
is human review + filling TODO sections + a `/design-review` pass.
|
|
223
|
+
- Idempotent: re-running detects existing specs and only generates files for
|
|
224
|
+
new primitives (and updates the Component Index table).
|
|
225
|
+
|
|
226
|
+
## See Also
|
|
227
|
+
|
|
228
|
+
- `framework/agents/design-system-protocol.md` — the protocol this skill bootstraps.
|
|
229
|
+
- `framework/agents/project-context.md` — config + overlay contract.
|
|
230
|
+
- `framework/.claude/skills/ui-design/SKILL.md` — primary consumer (reads
|
|
231
|
+
the registry BLOCKING).
|
|
232
|
+
- `scripts/component-spec.template.md` — per-component spec template.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# {{ComponentName}}
|
|
2
|
+
|
|
3
|
+
> Per-component spec. Authoritative for props, variants, accessibility, and
|
|
4
|
+
> anti-patterns. Visual authority (color/shadow/radius/spacing) belongs to
|
|
5
|
+
> [`../tokens-reference.md`](../tokens-reference.md).
|
|
6
|
+
|
|
7
|
+
## Source
|
|
8
|
+
|
|
9
|
+
- File: `{{file_path}}`
|
|
10
|
+
- Exported as: `{{exported_name}}`
|
|
11
|
+
- Used by: <!-- TODO: list 2-3 key consumers, e.g. pages or compound components -->
|
|
12
|
+
|
|
13
|
+
## Purpose
|
|
14
|
+
|
|
15
|
+
<!-- One-sentence statement of what this primitive is for and when to reach
|
|
16
|
+
for it instead of an alternative. -->
|
|
17
|
+
|
|
18
|
+
## Props
|
|
19
|
+
|
|
20
|
+
| Prop | Type | Default | Notes |
|
|
21
|
+
|------|------|---------|-------|
|
|
22
|
+
{{props_table}}
|
|
23
|
+
|
|
24
|
+
<!-- TODO: if props were not auto-resolvable, fill the table from the source
|
|
25
|
+
file. Keep types accurate — drift here is the most common bug. -->
|
|
26
|
+
|
|
27
|
+
## Variants
|
|
28
|
+
|
|
29
|
+
{{variants_section}}
|
|
30
|
+
|
|
31
|
+
<!-- TODO: enumerate every variant the component exposes. For each, describe
|
|
32
|
+
when to use it. Example:
|
|
33
|
+
- `variant="primary"` — primary CTA, one per surface
|
|
34
|
+
- `variant="ghost"` — secondary actions in dense layouts
|
|
35
|
+
- `size="sm" | "md" | "lg"` — bind to spacing tokens
|
|
36
|
+
-->
|
|
37
|
+
|
|
38
|
+
## Tokens consumed
|
|
39
|
+
|
|
40
|
+
{{tokens_section}}
|
|
41
|
+
|
|
42
|
+
<!-- TODO: list the tokens this component reads from tokens-reference.md.
|
|
43
|
+
Color, spacing, shadow, radius, motion. If you find hardcoded literals in
|
|
44
|
+
the source, that's a registry violation — fix at the source. -->
|
|
45
|
+
|
|
46
|
+
## Accessibility
|
|
47
|
+
|
|
48
|
+
- Keyboard: <!-- focus order, shortcuts, escape behavior -->
|
|
49
|
+
- ARIA: <!-- roles, labels, descriptions, live regions -->
|
|
50
|
+
- Touch target: ≥ 44×44px when interactive
|
|
51
|
+
- Color contrast: text ≥ 4.5:1, UI ≥ 3:1 (WCAG 2.1 AA)
|
|
52
|
+
- Reduced motion: respects `prefers-reduced-motion`
|
|
53
|
+
|
|
54
|
+
## Composition
|
|
55
|
+
|
|
56
|
+
<!-- How this primitive composes with others. Patterns it appears in.
|
|
57
|
+
Cross-link to patterns/ docs when applicable. -->
|
|
58
|
+
|
|
59
|
+
## Anti-patterns
|
|
60
|
+
|
|
61
|
+
<!-- Common misuses that should be rejected in code review. Examples:
|
|
62
|
+
- Wrapping in a div with absolute positioning to fake a variant — add a
|
|
63
|
+
variant to the registry instead.
|
|
64
|
+
- Hardcoding a custom color via inline style — add a token and consume it.
|
|
65
|
+
-->
|
|
66
|
+
|
|
67
|
+
## MUST rules
|
|
68
|
+
|
|
69
|
+
<!-- HIGH-severity rules the code-reviewer agent enforces. Examples:
|
|
70
|
+
- MUST consume `--color-primary` for background; never hardcode.
|
|
71
|
+
- MUST set `aria-label` when icon-only.
|
|
72
|
+
-->
|
|
73
|
+
|
|
74
|
+
## Changelog
|
|
75
|
+
|
|
76
|
+
<!-- Track breaking changes to the spec. Bump version when removing a variant
|
|
77
|
+
or changing a default. -->
|
|
78
|
+
|
|
79
|
+
- {{today}} — Spec scaffolded by `/design-system-init`.
|
|
@@ -50,6 +50,11 @@ Remember: Claude is capable of extraordinary creative work. Don't hold back, sho
|
|
|
50
50
|
|
|
51
51
|
## MANDATORY Pre-Work Read (project design-system override)
|
|
52
52
|
|
|
53
|
+
The registry-first cascade below is the consumer view of the SSOT in
|
|
54
|
+
[`framework/agents/design-system-protocol.md`](../../../agents/design-system-protocol.md).
|
|
55
|
+
When the cascade rules diverge between this file and the protocol module,
|
|
56
|
+
the protocol module wins.
|
|
57
|
+
|
|
53
58
|
When operating inside a repo that ships a design-system SSOT, the generic
|
|
54
59
|
creative guidance above is BLOCKED by the project design-system until the
|
|
55
60
|
reads below are complete. MANDATORY pre-work reads (skipping any of them is
|
|
@@ -72,6 +77,125 @@ Within those bounds, creative choices (typography nuance, composition, motion in
|
|
|
72
77
|
|
|
73
78
|
---
|
|
74
79
|
|
|
80
|
+
## Performance Gates (Core Web Vitals 2026)
|
|
81
|
+
|
|
82
|
+
Production-grade frontend is not just "looks good" — it ships within the CWV
|
|
83
|
+
thresholds. Every page / component / route MUST be designed against these
|
|
84
|
+
budgets, not retrofitted after Lighthouse complains.
|
|
85
|
+
|
|
86
|
+
### Thresholds (p75, CrUX dataset)
|
|
87
|
+
|
|
88
|
+
| Metric | Good | Poor | What it measures |
|
|
89
|
+
|---|---|---|---|
|
|
90
|
+
| **LCP** | ≤ 2.5s | > 4.0s | Largest Contentful Paint — usually the hero image or H1 |
|
|
91
|
+
| **INP** | ≤ 200ms | > 500ms | Interaction to Next Paint — replaced FID in Mar 2024 |
|
|
92
|
+
| **CLS** | ≤ 0.1 | > 0.25 | Cumulative Layout Shift |
|
|
93
|
+
| TTFB | ≤ 0.8s | > 1.8s | Subset of LCP (~40% of budget) |
|
|
94
|
+
| FCP | ≤ 1.8s | > 3.0s | Diagnostic only |
|
|
95
|
+
|
|
96
|
+
A page passes CWV when all three (LCP/INP/CLS) are *good* at p75. INP is the
|
|
97
|
+
hardest of the three on JS-heavy apps and the most commonly failed (~43% of
|
|
98
|
+
sites globally).
|
|
99
|
+
|
|
100
|
+
### LCP image: the only correct pattern
|
|
101
|
+
|
|
102
|
+
```html
|
|
103
|
+
<!-- in <head> — preload + fetchpriority for the hero -->
|
|
104
|
+
<link rel="preload" as="image"
|
|
105
|
+
href="/hero.avif"
|
|
106
|
+
imagesrcset="/hero-800.avif 800w, /hero-1600.avif 1600w"
|
|
107
|
+
imagesizes="100vw"
|
|
108
|
+
fetchpriority="high">
|
|
109
|
+
|
|
110
|
+
<!-- in body — picture with AVIF/WebP/fallback + explicit dimensions -->
|
|
111
|
+
<picture>
|
|
112
|
+
<source srcset="/hero.avif" type="image/avif">
|
|
113
|
+
<source srcset="/hero.webp" type="image/webp">
|
|
114
|
+
<img src="/hero.jpg" alt="..."
|
|
115
|
+
fetchpriority="high"
|
|
116
|
+
width="1600" height="900">
|
|
117
|
+
</picture>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**Never** apply `loading="lazy"` to the LCP image. **Never** render the LCP
|
|
121
|
+
image via client-side JS after hydration — server-render it or preload it.
|
|
122
|
+
|
|
123
|
+
### INP fixes
|
|
124
|
+
|
|
125
|
+
- Break any task > 50ms into `await scheduler.yield()` chunks (Chrome 129+;
|
|
126
|
+
fallback `await new Promise(r => setTimeout(r, 0))`).
|
|
127
|
+
- Debounce input handlers to one frame (~16ms) when they trigger expensive
|
|
128
|
+
recomputes. Throttle scroll/resize to `requestAnimationFrame`.
|
|
129
|
+
- Move CPU-bound work (parsing, transforming, encoding) off the main thread
|
|
130
|
+
with Web Workers when latency matters.
|
|
131
|
+
- Avoid `setInterval` polling for data — use SWR / React Query / TanStack
|
|
132
|
+
Query with stale-while-revalidate.
|
|
133
|
+
|
|
134
|
+
### CLS budget — zero unexpected shift
|
|
135
|
+
|
|
136
|
+
- Every `<img>`, `<iframe>`, `<video>` declares `width` + `height` or
|
|
137
|
+
`aspect-ratio` CSS.
|
|
138
|
+
- Web fonts: `font-display: optional` (no FOIT/FOUT shift, accept fallback
|
|
139
|
+
on first load) OR `size-adjust` + matching `ascent-override` /
|
|
140
|
+
`descent-override` / `line-gap-override` to produce a metric-compatible
|
|
141
|
+
fallback font.
|
|
142
|
+
- Skeleton screens mirror the real layout dimensions exactly — a skeleton
|
|
143
|
+
that's the wrong height *causes* CLS instead of preventing it.
|
|
144
|
+
- Inserted UI (banners, cookie notices, ads) must reserve space upfront via
|
|
145
|
+
`min-height` — never push existing content down post-paint.
|
|
146
|
+
|
|
147
|
+
## Modern CSS (2025–2026)
|
|
148
|
+
|
|
149
|
+
Default to platform features instead of JS shims:
|
|
150
|
+
|
|
151
|
+
- **Container queries** (`@container` + `container-type: inline-size`) —
|
|
152
|
+
default for any component that lives in variable-width contexts (sidebar,
|
|
153
|
+
grid cell, modal). Component decides its own breakpoint, independent of
|
|
154
|
+
viewport. Use viewport-based `@media` only for app-shell-level layout.
|
|
155
|
+
- **`:has()`** — collapse `useState` that exists *only for styling*
|
|
156
|
+
(e.g. label color reacting to input invalid state). Never put business
|
|
157
|
+
logic into `:has()` — only visual reactions to DOM state.
|
|
158
|
+
- **View Transitions API** — `document.startViewTransition()` for SPA
|
|
159
|
+
navigation and `view-transition-name` for shared-element morphs. See
|
|
160
|
+
`motion-design/reference/accessibility-and-modern-apis.md` for the full
|
|
161
|
+
pattern.
|
|
162
|
+
- **Subgrid** — children align to the parent grid without re-declaring
|
|
163
|
+
tracks. Fixes the long-standing "card content alignment across rows"
|
|
164
|
+
problem.
|
|
165
|
+
- **Logical properties** — `margin-inline-start` / `padding-block` instead
|
|
166
|
+
of `margin-left` / `padding-top` whenever the project might add RTL or
|
|
167
|
+
vertical-writing-mode locales. Free i18n with zero overhead.
|
|
168
|
+
- **`color-mix()`** — derive hover / focus / disabled states from semantic
|
|
169
|
+
tokens without inventing new tokens
|
|
170
|
+
(`color-mix(in oklch, var(--color-action-primary) 90%, black)`).
|
|
171
|
+
- **`@scope`** — scope CSS to a subtree without selector specificity wars or
|
|
172
|
+
CSS-in-JS. Useful when migrating off CSS Modules / styled-components.
|
|
173
|
+
|
|
174
|
+
## Form quality (always-on requirements)
|
|
175
|
+
|
|
176
|
+
These apply to every form, every project — they are not "nice to have":
|
|
177
|
+
|
|
178
|
+
- `<label>` associated to input via `htmlFor` / `id` (never wrap-only — fails
|
|
179
|
+
some screen readers).
|
|
180
|
+
- `autocomplete=` filled for every personal-data field
|
|
181
|
+
(`email | tel | given-name | family-name | street-address | postal-code |
|
|
182
|
+
cc-number | one-time-code` …). Required by WCAG 2.1 SC 1.3.5.
|
|
183
|
+
- Validation **on blur**, not on every keystroke. Re-validate on submit.
|
|
184
|
+
- Error messages are **actionable** ("Email manca @ — esempio:
|
|
185
|
+
nome@dominio.it"), never generic ("Invalid input").
|
|
186
|
+
- `aria-invalid` + `aria-describedby` linking the input to its error
|
|
187
|
+
element. Error element has `role="alert"` only when it appears
|
|
188
|
+
dynamically.
|
|
189
|
+
- `inputMode=` set when it differs from `type` (e.g. `type="text"
|
|
190
|
+
inputMode="numeric"` for SMS codes — keeps the field text-shaped but
|
|
191
|
+
triggers the numeric keypad).
|
|
192
|
+
- Paste handling normalizes whitespace and format BEFORE validating
|
|
193
|
+
(cc-number without spaces, tel without separators).
|
|
194
|
+
- Submit button disabled only **after** a failed attempt — never blocked
|
|
195
|
+
pre-emptively; users should be allowed to try and receive feedback.
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
75
199
|
## Prototipi Standalone e Demo
|
|
76
200
|
|
|
77
201
|
Quando il task richiede un prototipo HTML interattivo, demo animata, slide deck, mockup iOS/app, o design exploration **NON legato alla codebase Next.js** (nessun contesto `src/app/`), invocare la skill `huashu-design` in aggiunta o al posto di questa skill. Essa fornisce:
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Accessibility & Modern Motion APIs
|
|
2
|
+
|
|
3
|
+
## `prefers-reduced-motion` — collapse, don't disable
|
|
4
|
+
|
|
5
|
+
```css
|
|
6
|
+
:root {
|
|
7
|
+
--motion-duration-fast: 150ms;
|
|
8
|
+
--motion-duration-base: 250ms;
|
|
9
|
+
--motion-duration-slow: 400ms;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@media (prefers-reduced-motion: reduce) {
|
|
13
|
+
:root {
|
|
14
|
+
--motion-duration-fast: 0.01ms;
|
|
15
|
+
--motion-duration-base: 0.01ms;
|
|
16
|
+
--motion-duration-slow: 0.01ms;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Why 0.01ms, not 0?** Some Safari/WebKit versions skip the `transitionend`
|
|
22
|
+
event entirely when duration is exactly `0` — state machines that wait on
|
|
23
|
+
that event hang. `0.01ms` is functionally instant but keeps the event
|
|
24
|
+
pipeline intact.
|
|
25
|
+
|
|
26
|
+
**What stays vs. what goes** when reduced-motion is requested:
|
|
27
|
+
|
|
28
|
+
- KEEP: opacity fades < 200ms (no vestibular impact), color cross-fades,
|
|
29
|
+
scale changes < 5%, subtle elevation changes.
|
|
30
|
+
- COLLAPSE: translate / parallax / scale > 5% / rotate / skew / 3D
|
|
31
|
+
perspective / spring overshoot — anything with apparent motion across the
|
|
32
|
+
viewport.
|
|
33
|
+
|
|
34
|
+
**Don't** apply a global `* { animation: none !important }` reset — that
|
|
35
|
+
breaks loading spinners, focus indicators, and any animation that
|
|
36
|
+
*communicates state*. Token-level collapse is the right primitive.
|
|
37
|
+
|
|
38
|
+
## View Transitions API
|
|
39
|
+
|
|
40
|
+
For same-document navigation (SPA route change, list ↔ detail, tab switch):
|
|
41
|
+
|
|
42
|
+
```js
|
|
43
|
+
function navigate(to) {
|
|
44
|
+
if (!document.startViewTransition) {
|
|
45
|
+
applyDom(to); // graceful fallback — no transition
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
document.startViewTransition(() => applyDom(to));
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
For shared-element morph (hero image survives the route change):
|
|
53
|
+
|
|
54
|
+
```css
|
|
55
|
+
.hero-image {
|
|
56
|
+
view-transition-name: hero-image; /* unique per shared element */
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
::view-transition-old(hero-image),
|
|
60
|
+
::view-transition-new(hero-image) {
|
|
61
|
+
animation-duration: var(--motion-duration-base);
|
|
62
|
+
animation-timing-function: cubic-bezier(0.2, 0, 0, 1); /* emphasized */
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
For cross-document transitions (MPA, Chrome 126+, behind opt-in CSS):
|
|
67
|
+
|
|
68
|
+
```css
|
|
69
|
+
@view-transition { navigation: auto; }
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Accessibility**: View Transitions automatically respect
|
|
73
|
+
`prefers-reduced-motion` when the page exposes the reduced-motion media
|
|
74
|
+
query — no extra wiring needed beyond the token collapse above.
|
|
75
|
+
|
|
76
|
+
**Use it for**: navigation, list ↔ detail morphs, sort / filter reorders,
|
|
77
|
+
modal hero reveal. **Don't use it for**: per-frame interactive feedback
|
|
78
|
+
(hover, focus, drag) — those need direct CSS / spring animations.
|
|
79
|
+
|
|
80
|
+
## Spring vs. timing function — when to pick which
|
|
81
|
+
|
|
82
|
+
| Use case | Pick |
|
|
83
|
+
|---|---|
|
|
84
|
+
| Direct manipulation (drag release, swipe, pull-to-refresh) | Spring |
|
|
85
|
+
| Page / view transition | Cubic-bezier (deterministic, easy to choreograph) |
|
|
86
|
+
| Acknowledgment / tap feedback | Cubic-bezier (short, predictable) |
|
|
87
|
+
| Interruptible animation that should "settle naturally" | Spring |
|
|
88
|
+
| Stagger choreography | Cubic-bezier (timeline easier to reason about) |
|
|
89
|
+
|
|
90
|
+
**Spring rule of thumb**: stiffness 250–350 + damping 18–24 = "standard
|
|
91
|
+
feel". Higher stiffness = snappier; lower damping = more oscillation. Cap
|
|
92
|
+
total settle time at 600ms — beyond that the user perceives "lag", not
|
|
93
|
+
physicality.
|
|
94
|
+
|
|
95
|
+
## Choreography budget
|
|
96
|
+
|
|
97
|
+
- Single-element transition: 100–500ms (see `timing-easing-tables.md`).
|
|
98
|
+
- Stagger of multiple children: each child delay 30–50ms, **total budget
|
|
99
|
+
≤ 600ms** (faster on dense lists — cap at 400ms for >10 items).
|
|
100
|
+
- Page-load sequence: hero ≤ 250ms, secondary content stagger ≤ 400ms
|
|
101
|
+
total. Beyond that the user is staring at incomplete UI.
|
|
102
|
+
|
|
103
|
+
## Animation that communicates state — never collapse these
|
|
104
|
+
|
|
105
|
+
Reduced-motion does NOT mean *no feedback*. Always preserve:
|
|
106
|
+
|
|
107
|
+
- Focus ring appearance (instant is fine — but visible).
|
|
108
|
+
- Loading indicators (a static spinner or skeleton is still feedback).
|
|
109
|
+
- Validation error appearance (color + icon — duration can be 0).
|
|
110
|
+
- Toast / notification appearance (fade-in opacity ≤ 200ms is acceptable
|
|
111
|
+
under reduced-motion).
|
|
112
|
+
|
|
113
|
+
Stripping these leaves users without feedback that an action registered —
|
|
114
|
+
worse than the animation they tried to avoid.
|
|
@@ -32,6 +32,11 @@ Evaluation is always performed by a separate agent with fresh context.
|
|
|
32
32
|
|
|
33
33
|
## Prerequisites — BLOCKING reads before ANY design work
|
|
34
34
|
|
|
35
|
+
The registry-first cascade below is the consumer view of the SSOT in
|
|
36
|
+
[`framework/agents/design-system-protocol.md`](../../../agents/design-system-protocol.md).
|
|
37
|
+
When the cascade rules diverge between this file and the protocol module,
|
|
38
|
+
the protocol module wins.
|
|
39
|
+
|
|
35
40
|
These reads are BLOCKING. Resolve paths from `baldart.config.yml` before opening files. If `features.has_design_system: true`, item 1 is the mandatory entry point and skipping it is a protocol violation.
|
|
36
41
|
|
|
37
42
|
1. **MANDATORY / BLOCKING when `features.has_design_system: true`** — read `${paths.design_system}/INDEX.md` (the design-system entry point: component index, authority matrix, token contract, any project-specific theming pairing rules and overlay decision tree).
|
|
@@ -141,6 +146,43 @@ Read [references/inventory.md](references/inventory.md).
|
|
|
141
146
|
3. Update state file with chosen option, design decisions, component lists.
|
|
142
147
|
4. Clean up `/tmp/prd-design-<slug>/`.
|
|
143
148
|
|
|
149
|
+
### Step H — Registry Coherence Reconciliation (BLOCKING completion gate)
|
|
150
|
+
|
|
151
|
+
When `features.has_design_system: true`, the design is not complete until the
|
|
152
|
+
component registry reflects every primitive the chosen design depends on. Run
|
|
153
|
+
the **Post-Intervention Coherence Check** defined in
|
|
154
|
+
[`framework/agents/design-system-protocol.md`](../../../agents/design-system-protocol.md)
|
|
155
|
+
§ "Post-Intervention Coherence Check".
|
|
156
|
+
|
|
157
|
+
Concretely, walk the UI Element Inventory from Step G and for each item:
|
|
158
|
+
|
|
159
|
+
1. **Registry-hit confirmed**: the primitive exists in `${paths.design_system}/INDEX.md`
|
|
160
|
+
AND its `components/<Name>.md` spec matches the way the design uses it
|
|
161
|
+
(props, variants, accessibility). If the design uses a variant not yet
|
|
162
|
+
documented, update the spec inline.
|
|
163
|
+
2. **Source-tree-hit silent primitive**: the primitive exists under
|
|
164
|
+
`${paths.components_primitives}` but not in `INDEX.md`. Add the INDEX entry
|
|
165
|
+
inline (full spec or stub `status: needs-review`, see decision matrix in the
|
|
166
|
+
protocol).
|
|
167
|
+
3. **New primitive proposed by the design**: it has no source implementation
|
|
168
|
+
AND no spec. Either:
|
|
169
|
+
- scaffold the spec + INDEX entry now as part of the inventory deliverable, OR
|
|
170
|
+
- open a follow-up card and **flag the gap explicitly** in the inventory so
|
|
171
|
+
downstream implementation work cannot proceed without resolution.
|
|
172
|
+
4. **Token additions**: the design introduces a color / spacing / shadow / motion
|
|
173
|
+
value not present in `${paths.design_system}/tokens-reference.md`. Update the
|
|
174
|
+
reference inline OR open a follow-up token-addition card before approval.
|
|
175
|
+
|
|
176
|
+
Surface every finding in the design handoff with the standard codes
|
|
177
|
+
(`DS_INDEX_DRIFT` / `DS_COMPONENT_STALE` / `DS_TOKENS_DRIFT`). Silent
|
|
178
|
+
reconciliation is forbidden — the user must see the drift that was found and
|
|
179
|
+
how it was resolved (inline vs. follow-up card).
|
|
180
|
+
|
|
181
|
+
This step exists because the design phase is where drift is **cheapest to
|
|
182
|
+
prevent**: catching a duplicate primitive at the mockup stage costs minutes,
|
|
183
|
+
catching it after implementation costs a refactor. The weekly `ds-drift`
|
|
184
|
+
routine is a safety net, not a substitute for this check.
|
|
185
|
+
|
|
144
186
|
---
|
|
145
187
|
|
|
146
188
|
## Design Principles (quick reference)
|
|
@@ -153,6 +195,7 @@ These are enforced — read `${paths.ui_guidelines}` for full spec.
|
|
|
153
195
|
- **Multi-tenant theming pairing**: when `features.multi_tenant_theming: true`, themed text-token paired with themed bg-token per the project's theming pattern doc
|
|
154
196
|
- **View State Trinity**: loading (skeletons), error (localized message + retry), empty (CTA). The error language follows `identity.language`.
|
|
155
197
|
- **Separation of concerns**: UI / business logic / data layers stay separate
|
|
198
|
+
- **Registry coherence (BLOCKING)**: when `has_design_system: true`, every primitive in the chosen design is reconciled with `INDEX.md` + `components/<Name>.md` + `tokens-reference.md` before sign-off (Step H). New primitive ⇒ new spec same change. Modified primitive ⇒ updated spec same change. Silent reuse of undocumented primitive ⇒ INDEX entry added now
|
|
156
199
|
|
|
157
200
|
---
|
|
158
201
|
|