@tekyzinc/gsd-t 2.57.10 → 2.59.10
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 +25 -0
- package/README.md +3 -2
- package/commands/gsd-t-design-decompose.md +264 -0
- package/commands/gsd-t-execute.md +27 -0
- package/commands/gsd-t-help.md +8 -0
- package/commands/gsd-t-quick.md +7 -1
- package/commands/gsd.md +2 -1
- package/docs/GSD-T-README.md +1 -0
- package/package.json +1 -1
- package/templates/CLAUDE-global.md +2 -1
- package/templates/design-chart-taxonomy.md +265 -0
- package/templates/element-contract.md +151 -0
- package/templates/page-contract.md +143 -0
- package/templates/stacks/design-to-code.md +29 -0
- package/templates/widget-contract.md +136 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to GSD-T are documented here. Updated with each release.
|
|
4
4
|
|
|
5
|
+
## [2.59.10] - 2026-04-05
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **Chart & Atom Taxonomy** — `templates/design-chart-taxonomy.md` — closed enumeration of ~70 valid element names across charts, axes, legends, cards, tables, controls, atoms (icons/badges/chips/dividers), typography, and layout primitives. Fixes catastrophic failure mode where agents invented element names and picked wrong chart variants (e.g., `chart-bar-grouped-vertical` when design was `chart-bar-stacked-horizontal-percentage`). `gsd-t-design-decompose` now REQUIRES element names to come from this closed set.
|
|
9
|
+
- **Visual distinguisher decision rules** per chart category (stacked vs grouped vs percentage, pie vs donut vs gauge, line vs area, categorical vs histogram) to prevent near-match pattern-matching.
|
|
10
|
+
- **Atoms taxonomy** — icons, badges, chips, dividers, avatars, status-dots, spinners, tooltips, breadcrumbs, pagination, tags — the most-forgotten element tier.
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- **Element template**: `Test Fixture` section is now MANDATORY with the EXACT labels/values/percentages extracted from the design source. Placeholder data (Calculator/Planner/Tracker instead of real labels) is FORBIDDEN. Verifier compares labels verbatim.
|
|
14
|
+
- **Widget template**: adds mandatory **Card Chrome Slots** section (title, subtitle, header_right_control, kpi_header, body, body_sidebar, footer, footer_legend) — each must be filled or explicitly marked N/A. Fixes the "missing subtitle, missing per-card filter dropdown, missing KPI-above-chart" defect.
|
|
15
|
+
- **Design Verification Agent** (gsd-t-execute Step 5.25 + gsd-t-quick Step 5.25): adds mandatory **Step 0 — Data-Labels Cross-Check** that runs BEFORE visual comparison. Verifies every label/value/percentage from the Test Fixture appears verbatim in the rendered UI. Wrong data = CRITICAL deviation, no visual polish can redeem it.
|
|
16
|
+
- **gsd-t-design-decompose**: MUST ingest existing flat `design-contract.md` when present (especially the `## Verification Status` section from prior verified builds) as ground truth for Test Fixture data — no re-inventing labels.
|
|
17
|
+
|
|
18
|
+
## [2.58.10] - 2026-04-05
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
- **Hierarchical design contracts** — `element` → `widget` → `page` contract hierarchy for design-to-code projects. Element contracts are the single source of truth for visual spec (one contract per visual variant, e.g., `chart-bar-stacked-horizontal` and `chart-bar-stacked-vertical` are separate). Widgets compose elements with layout + data binding. Pages compose widgets with routing + grid layout.
|
|
22
|
+
- **Precedence rule**: element > widget > page. Widgets and pages SELECT and POSITION elements but cannot override element visual spec. Structural drift becomes impossible.
|
|
23
|
+
- **New templates**: `templates/element-contract.md`, `templates/widget-contract.md`, `templates/page-contract.md`
|
|
24
|
+
- **New command**: `/user:gsd-t-design-decompose` — surveys a design (Figma/image/prototype), classifies elements (reuse count ≥2 or non-trivial spec → promoted to element contract), identifies widgets and pages, writes the full contract hierarchy under `.gsd-t/contracts/design/{elements,widgets,pages}/` plus an `INDEX.md` navigation map.
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
- `design-to-code.md` stack rule adds Section 0 explaining flat vs. hierarchical contract modes and detection at execute-time (presence of `.gsd-t/contracts/design/` triggers hierarchical verification: elements first, then widgets, then pages)
|
|
28
|
+
- Command count: 48 GSD-T + 5 utility = 53 total
|
|
29
|
+
|
|
5
30
|
## [2.57.10] - 2026-04-04
|
|
6
31
|
|
|
7
32
|
### Added
|
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ A methodology for reliable, parallelizable development using Claude Code with op
|
|
|
30
30
|
npx @tekyzinc/gsd-t install
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
This installs
|
|
33
|
+
This installs 48 GSD-T commands + 5 utility commands (53 total) to `~/.claude/commands/` and the global CLAUDE.md to `~/.claude/CLAUDE.md`. Works on Windows, Mac, and Linux.
|
|
34
34
|
|
|
35
35
|
### Start Using It
|
|
36
36
|
|
|
@@ -149,6 +149,7 @@ This will replace changed command files, back up your CLAUDE.md if customized, a
|
|
|
149
149
|
| `/user:gsd-t-gap-analysis` | Requirements gap analysis — spec vs. existing code | Manual |
|
|
150
150
|
| `/user:gsd-t-promote-debt` | Convert techdebt items to milestones | Manual |
|
|
151
151
|
| `/user:gsd-t-populate` | Auto-populate docs from existing codebase | Manual |
|
|
152
|
+
| `/user:gsd-t-design-decompose` | Decompose design into element/widget/page contracts | Manual |
|
|
152
153
|
|
|
153
154
|
### Milestone Workflow
|
|
154
155
|
|
|
@@ -338,7 +339,7 @@ get-stuff-done-teams/
|
|
|
338
339
|
├── LICENSE
|
|
339
340
|
├── bin/
|
|
340
341
|
│ └── gsd-t.js # CLI installer
|
|
341
|
-
├── commands/ #
|
|
342
|
+
├── commands/ # 53 slash commands
|
|
342
343
|
│ ├── gsd-t-*.md # 45 GSD-T workflow commands
|
|
343
344
|
│ ├── gsd.md # GSD-T smart router
|
|
344
345
|
│ ├── branch.md # Git branch helper
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# GSD-T: Design Decompose — Hierarchical Contract Extraction
|
|
2
|
+
|
|
3
|
+
You are the lead agent for decomposing a design (Figma file, image, screenshot, or prototype URL) into a hierarchy of element / widget / page contracts.
|
|
4
|
+
|
|
5
|
+
**Output**: A tree of contracts — elements at the bottom (atomic, reusable, variant-per-contract), widgets in the middle (element composition + data binding), pages at the top (widget assembly + layout + routing).
|
|
6
|
+
|
|
7
|
+
**Why hierarchical contracts:** A flat `design-contract.md` makes verification expensive and lets drift accumulate (two donut charts on two pages diverge over time). Hierarchical contracts verify elements in isolation once, then compose — drift is impossible because elements are the single source of truth for visual spec.
|
|
8
|
+
|
|
9
|
+
**When to use this command:**
|
|
10
|
+
- Starting a design-to-code project with multiple pages sharing components
|
|
11
|
+
- Retrofitting an existing flat `design-contract.md` into reusable parts
|
|
12
|
+
- Adding a new page that reuses existing elements/widgets
|
|
13
|
+
|
|
14
|
+
If the project is small (single page, ≤10 elements, nothing reusable), use the flat `design-contract.md` template instead and skip this command.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Step 0: Detect Inputs + Load Taxonomy
|
|
19
|
+
|
|
20
|
+
Run these checks, log results to user inline:
|
|
21
|
+
|
|
22
|
+
1. **Figma MCP available?**
|
|
23
|
+
- If yes → log "Figma MCP detected — will extract exact tokens per element"
|
|
24
|
+
- If no → log "Figma MCP unavailable — using visual analysis (reduced precision)"
|
|
25
|
+
2. **Existing flat contract? — MANDATORY INGESTION if present**
|
|
26
|
+
- If `.gsd-t/contracts/design-contract.md` exists:
|
|
27
|
+
- **READ IT COMPLETELY** — it is the authoritative ground truth for data labels, values, and verification assertions from prior runs
|
|
28
|
+
- Extract: exact category labels, exact data values, exact center values, exact percentages
|
|
29
|
+
- Use these as **Test Fixture** data in every element contract you write (not placeholder data)
|
|
30
|
+
- If the flat contract has a `## Verification Status` section with 30+ rows, that is the GROUND TRUTH for what each element must match — port every row into the relevant element contract's Verification Checklist
|
|
31
|
+
- If not → fresh decomposition from the design source directly
|
|
32
|
+
3. **Design source provided?**
|
|
33
|
+
- Required: Figma URL, image path, or prototype URL in `$ARGUMENTS`
|
|
34
|
+
- If missing → ask user: "Provide the design source (Figma URL, image path, or prototype URL)"
|
|
35
|
+
4. **Load the chart taxonomy (MANDATORY)**
|
|
36
|
+
- READ `templates/design-chart-taxonomy.md` from the GSD-T package (or `~/.claude/` if installed)
|
|
37
|
+
- This is the **CLOSED SET** of valid element names. You MUST pick from this list. Inventing new element names is FORBIDDEN without user approval to extend the taxonomy.
|
|
38
|
+
- Keep the taxonomy in working memory while classifying — every element you identify MUST be matched against it
|
|
39
|
+
|
|
40
|
+
## Step 1: Survey the Design
|
|
41
|
+
|
|
42
|
+
Enumerate every visual element on every page/screen in the design. Use Figma MCP `get_metadata` or `get_design_context` if available; otherwise use visual analysis on the image.
|
|
43
|
+
|
|
44
|
+
Produce an initial flat inventory table:
|
|
45
|
+
|
|
46
|
+
| # | Element on Design | Appears On Pages | Visual Variant |
|
|
47
|
+
|---|------------------------------------|------------------------|--------------------------------------|
|
|
48
|
+
| 1 | Donut chart with center label | Overview, Analytics | chart-donut |
|
|
49
|
+
| 2 | Horizontal stacked bar chart | Analytics | chart-bar-stacked-horizontal |
|
|
50
|
+
| 3 | Vertical legend on right | Overview | legend-vertical-right |
|
|
51
|
+
| 4 | KPI tile with delta indicator | Overview (×4) | stat-card-with-delta |
|
|
52
|
+
| ...
|
|
53
|
+
|
|
54
|
+
**Rule**: distinct visual variants = distinct rows. A horizontal stacked bar and a vertical stacked bar are TWO rows, not one.
|
|
55
|
+
|
|
56
|
+
## Step 2: Classify Each Element (taxonomy-enforced)
|
|
57
|
+
|
|
58
|
+
For each row in the inventory, assign:
|
|
59
|
+
|
|
60
|
+
- **Category** — chart / legend / axis / card / table / control / atom / typography / layout
|
|
61
|
+
- **Element name** — **MUST come from `templates/design-chart-taxonomy.md`** (closed set). If no match found, STOP and ask user to extend the taxonomy with rationale.
|
|
62
|
+
- **Reuse count** — how many times does it appear across the entire design?
|
|
63
|
+
- **Owner layer** — element / widget-internal / page-internal
|
|
64
|
+
|
|
65
|
+
### Visual distinguisher decision rules (consult taxonomy)
|
|
66
|
+
|
|
67
|
+
Before naming an element, apply the visual distinguisher rules from the taxonomy:
|
|
68
|
+
|
|
69
|
+
- **Bar chart?** → is it stacked/grouped, horizontal/vertical, percentage/absolute? These are ALL distinct element contracts.
|
|
70
|
+
- **Circular?** → pie vs donut (hole in center?) vs gauge (partial arc?)
|
|
71
|
+
- **Line?** → single vs multi, stepped vs smooth, with area or without
|
|
72
|
+
|
|
73
|
+
**Anti-pattern to avoid**: "it has bars so it's a bar chart" → WRONG. The failure mode is picking `chart-bar-grouped-vertical` when the design is `chart-bar-stacked-horizontal-percentage`. These render completely differently with completely different data bindings.
|
|
74
|
+
|
|
75
|
+
**Promotion rule**: an item becomes an **element contract** if:
|
|
76
|
+
- It appears ≥2 times across the design, OR
|
|
77
|
+
- It has non-trivial visual spec (≥5 distinct spec properties), OR
|
|
78
|
+
- It has states or interactions beyond "static display"
|
|
79
|
+
|
|
80
|
+
Otherwise, it stays internal to its widget or page (no contract needed).
|
|
81
|
+
|
|
82
|
+
### Atoms are NOT optional
|
|
83
|
+
|
|
84
|
+
Icons, badges, chips, dividers, avatars, status dots, spinners — every small artifact that appears in the design gets an element contract if it meets the promotion rule. These are the #1 most-missed tier and produce the "feels off" verification result.
|
|
85
|
+
|
|
86
|
+
## Step 3: Identify Widgets
|
|
87
|
+
|
|
88
|
+
A **widget** is a reusable composition of elements + data binding that appears as a visual group in the design. Examples: "Revenue Breakdown" (donut + legend + title + filter), "Stat Strip" (4× stat-card-with-delta).
|
|
89
|
+
|
|
90
|
+
For each visual group in the design, determine:
|
|
91
|
+
- Does it appear on ≥2 pages, OR is it clearly a reusable unit conceptually?
|
|
92
|
+
- Yes → widget contract
|
|
93
|
+
- No → page-internal composition (no widget contract needed)
|
|
94
|
+
|
|
95
|
+
Produce a widget inventory:
|
|
96
|
+
|
|
97
|
+
| # | Widget Name | Appears On Pages | Elements Used |
|
|
98
|
+
|---|---------------------------|------------------------|-------------------------------------------------|
|
|
99
|
+
| 1 | revenue-breakdown-widget | Overview, Analytics | chart-donut, legend-vertical-right, heading-h3, select-dropdown |
|
|
100
|
+
| 2 | stat-strip-widget | Overview | stat-card-with-delta (×4) |
|
|
101
|
+
| ...
|
|
102
|
+
|
|
103
|
+
## Step 4: Identify Pages
|
|
104
|
+
|
|
105
|
+
Each page/screen in the design becomes a page contract. Document:
|
|
106
|
+
- Widgets used and grid position
|
|
107
|
+
- Global layout (header, sidebar, main)
|
|
108
|
+
- Route + auth guards
|
|
109
|
+
|
|
110
|
+
## Step 5: Confirm Decomposition With User
|
|
111
|
+
|
|
112
|
+
Present the full hierarchy summary:
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
DECOMPOSITION SUMMARY
|
|
116
|
+
─────────────────────
|
|
117
|
+
Elements: 14 contracts
|
|
118
|
+
Charts: 4 (chart-donut, chart-bar-stacked-horizontal, chart-line, chart-sparkline)
|
|
119
|
+
Legends: 2 (legend-vertical-right, legend-horizontal-bottom)
|
|
120
|
+
Cards: 2 (stat-card, stat-card-with-delta)
|
|
121
|
+
Tables: 1 (table-dense)
|
|
122
|
+
Controls: 5 (button-primary, select-dropdown, input-search, tabs-underline, toggle)
|
|
123
|
+
|
|
124
|
+
Widgets: 6 contracts
|
|
125
|
+
stat-strip-widget, revenue-breakdown-widget, user-growth-widget,
|
|
126
|
+
recent-activity-table-widget, page-header-widget, nav-sidebar-widget
|
|
127
|
+
|
|
128
|
+
Pages: 3 contracts
|
|
129
|
+
dashboard-overview, analytics-detail, settings
|
|
130
|
+
|
|
131
|
+
Total: 23 contracts (vs. flat: ~57 elements in single file)
|
|
132
|
+
|
|
133
|
+
Cost estimate:
|
|
134
|
+
- Decomposition effort: ~{N} hours to write all contracts
|
|
135
|
+
- Verification: elements verified once, reused everywhere → no drift
|
|
136
|
+
- Implementation: widgets become assembly, not reinvention
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Ask user: "Proceed with this decomposition? [y/n/edit]"
|
|
140
|
+
- **y** → Step 6
|
|
141
|
+
- **n** → abort
|
|
142
|
+
- **edit** → accept user revisions to the hierarchy, re-present
|
|
143
|
+
|
|
144
|
+
## Step 6: Write Contracts
|
|
145
|
+
|
|
146
|
+
Create the directory structure:
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
.gsd-t/contracts/design/
|
|
150
|
+
├── elements/
|
|
151
|
+
│ ├── chart-donut.contract.md
|
|
152
|
+
│ ├── chart-bar-stacked-horizontal.contract.md
|
|
153
|
+
│ ├── legend-vertical-right.contract.md
|
|
154
|
+
│ └── ... (one file per element)
|
|
155
|
+
├── widgets/
|
|
156
|
+
│ ├── revenue-breakdown-widget.contract.md
|
|
157
|
+
│ └── ... (one file per widget)
|
|
158
|
+
├── pages/
|
|
159
|
+
│ ├── dashboard-overview.contract.md
|
|
160
|
+
│ └── ... (one file per page)
|
|
161
|
+
└── INDEX.md (hierarchy map + cross-references)
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
For each element contract:
|
|
165
|
+
1. Copy `templates/element-contract.md` as scaffold
|
|
166
|
+
2. Fill in visual spec from Figma MCP (exact values) or visual analysis (estimated values)
|
|
167
|
+
3. Fill in states, interactions, data binding, accessibility, verification checklist
|
|
168
|
+
4. If Figma MCP available → use `get_design_context` per element node to extract tokens
|
|
169
|
+
|
|
170
|
+
For each widget contract:
|
|
171
|
+
1. Copy `templates/widget-contract.md` as scaffold
|
|
172
|
+
2. Reference elements by name in the "Elements Used" table
|
|
173
|
+
3. Define layout, data binding, responsive behavior, widget-level verification
|
|
174
|
+
|
|
175
|
+
For each page contract:
|
|
176
|
+
1. Copy `templates/page-contract.md` as scaffold
|
|
177
|
+
2. Reference widgets in grid positions
|
|
178
|
+
3. Define route, data loading, global states, performance budget
|
|
179
|
+
|
|
180
|
+
Write `INDEX.md` as a navigation map:
|
|
181
|
+
|
|
182
|
+
```markdown
|
|
183
|
+
# Design Contracts: {Project Name}
|
|
184
|
+
|
|
185
|
+
## Elements (14)
|
|
186
|
+
- [chart-donut](elements/chart-donut.contract.md) — used by revenue-breakdown-widget
|
|
187
|
+
- [chart-bar-stacked-horizontal](elements/chart-bar-stacked-horizontal.contract.md) — used by analytics-trend-widget
|
|
188
|
+
- ...
|
|
189
|
+
|
|
190
|
+
## Widgets (6)
|
|
191
|
+
- [revenue-breakdown-widget](widgets/revenue-breakdown-widget.contract.md) — uses chart-donut, legend-vertical-right
|
|
192
|
+
- ...
|
|
193
|
+
|
|
194
|
+
## Pages (3)
|
|
195
|
+
- [dashboard-overview](pages/dashboard-overview.contract.md) — uses stat-strip-widget, revenue-breakdown-widget, user-growth-widget, recent-activity-table-widget
|
|
196
|
+
- ...
|
|
197
|
+
|
|
198
|
+
## Precedence
|
|
199
|
+
element contract > widget contract > page contract
|
|
200
|
+
|
|
201
|
+
Widgets and pages reference elements by name. They CANNOT override element visual spec. To customize, create a new element variant.
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Step 7: Wire Into Partition
|
|
205
|
+
|
|
206
|
+
If `.gsd-t/domains/` exists (project is already partitioned), append to relevant domain's `scope.md`:
|
|
207
|
+
|
|
208
|
+
```markdown
|
|
209
|
+
## Design Contracts
|
|
210
|
+
This domain owns the following design contracts:
|
|
211
|
+
- Elements: chart-donut, legend-vertical-right
|
|
212
|
+
- Widgets: revenue-breakdown-widget
|
|
213
|
+
- Pages: (none — pages owned by page-assembly domain)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
If `.gsd-t/domains/` does NOT exist yet, suggest the user run `/user:gsd-t-partition` next, with a note that design contracts should be partitioned into domains:
|
|
217
|
+
- **design-system domain** owns element contracts
|
|
218
|
+
- **widgets domain** owns widget contracts
|
|
219
|
+
- **pages domain** owns page assembly + routing
|
|
220
|
+
|
|
221
|
+
## Step 8: Update progress.md Decision Log
|
|
222
|
+
|
|
223
|
+
Append:
|
|
224
|
+
```
|
|
225
|
+
- {YYYY-MM-DD HH:MM}: gsd-t-design-decompose — created {N} element / {N} widget / {N} page contracts under .gsd-t/contracts/design/. Hierarchy: elements are single source of truth for visual spec; widgets compose elements; pages compose widgets.
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Step 9: Next Up Hint
|
|
229
|
+
|
|
230
|
+
Display:
|
|
231
|
+
|
|
232
|
+
```
|
|
233
|
+
───────────────────────────────────────────────────────────────
|
|
234
|
+
|
|
235
|
+
## ▶ Next Up
|
|
236
|
+
|
|
237
|
+
**Partition** — decompose project into domains owning the design contracts
|
|
238
|
+
|
|
239
|
+
`/user:gsd-t-partition`
|
|
240
|
+
|
|
241
|
+
**Also available:**
|
|
242
|
+
- `/user:gsd-t-execute` — build element contracts first (they're independently testable)
|
|
243
|
+
- `/user:gsd-t-plan` — plan tasks around the contract hierarchy
|
|
244
|
+
|
|
245
|
+
───────────────────────────────────────────────────────────────
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Document Ripple
|
|
251
|
+
|
|
252
|
+
After writing contracts, update:
|
|
253
|
+
- `.gsd-t/progress.md` — Decision Log entry (Step 8)
|
|
254
|
+
- `docs/architecture.md` — add "Design Contract Hierarchy" section if not present
|
|
255
|
+
- If existing flat `.gsd-t/contracts/design-contract.md` was retrofitted → mark it with a DEPRECATED header pointing to `design/INDEX.md`
|
|
256
|
+
|
|
257
|
+
## Pre-Commit Gate
|
|
258
|
+
|
|
259
|
+
- [ ] All contracts written from templates (element/widget/page)
|
|
260
|
+
- [ ] `INDEX.md` created with full hierarchy + precedence note
|
|
261
|
+
- [ ] Decision Log updated in progress.md
|
|
262
|
+
- [ ] architecture.md updated if this is a new concept for the project
|
|
263
|
+
|
|
264
|
+
$ARGUMENTS
|
|
@@ -632,6 +632,33 @@ each one matches — not assume it does. 'Looks close' is not a verdict.
|
|
|
632
632
|
'Appears to match' is not a verdict. The only valid verdicts are MATCH
|
|
633
633
|
(with proof) or DEVIATION (with specifics).
|
|
634
634
|
|
|
635
|
+
## Step 0: Data-Labels Cross-Check (MANDATORY — run FIRST)
|
|
636
|
+
|
|
637
|
+
Before any visual comparison, verify the built UI is rendering the CORRECT
|
|
638
|
+
DATA from the design. This is the most common failure mode: agents use
|
|
639
|
+
placeholder data (Calculator/Planner/Tracker) while the design shows real
|
|
640
|
+
labels (Steps to Stay Covered/Broker Contact). The verifier then compares
|
|
641
|
+
bar-shapes only and declares MATCH — while the content is catastrophically
|
|
642
|
+
wrong.
|
|
643
|
+
|
|
644
|
+
1. For EACH element contract under .gsd-t/contracts/design/elements/
|
|
645
|
+
(or each section of flat .gsd-t/contracts/design-contract.md):
|
|
646
|
+
a. Read the 'Test Fixture' section — extract every label, value, percentage
|
|
647
|
+
b. Open the built UI in the browser
|
|
648
|
+
c. Inspect the rendered element (via DOM or screenshot OCR)
|
|
649
|
+
d. For EACH label/value/percentage in the Test Fixture:
|
|
650
|
+
- Does it appear verbatim in the rendered UI?
|
|
651
|
+
- If NO → immediate ❌ DEVIATION (severity CRITICAL)
|
|
652
|
+
Log: 'Test Fixture label {X} not found in rendered UI. Found instead: {Y}.'
|
|
653
|
+
- If YES → ✅ MATCH for that specific label/value
|
|
654
|
+
|
|
655
|
+
2. Count: '{N}/{total} labels+values from Test Fixture appear correctly in UI'
|
|
656
|
+
|
|
657
|
+
3. If ANY Test Fixture label or value is missing from the rendered UI:
|
|
658
|
+
The component is rendering WRONG DATA. This is a CRITICAL deviation.
|
|
659
|
+
No amount of visual polish can redeem wrong data. Mark the element
|
|
660
|
+
DEVIATION and continue (do not skip the rest — but flag the severity).
|
|
661
|
+
|
|
635
662
|
## Step 1: Get the Design Reference
|
|
636
663
|
|
|
637
664
|
Read .gsd-t/contracts/design-contract.md for the source reference.
|
package/commands/gsd-t-help.md
CHANGED
|
@@ -60,6 +60,7 @@ UTILITIES Manual
|
|
|
60
60
|
audit Harness self-audit — analyze cost/benefit of enforcement components
|
|
61
61
|
promote-debt Convert techdebt items to milestones
|
|
62
62
|
populate Auto-populate docs from existing codebase
|
|
63
|
+
design-decompose Decompose design into element/widget/page contracts
|
|
63
64
|
log Sync progress Decision Log with recent git activity
|
|
64
65
|
version-update Update GSD-T package to latest version
|
|
65
66
|
version-update-all Update GSD-T package + all registered projects
|
|
@@ -382,6 +383,13 @@ Use these when user asks for help on a specific command:
|
|
|
382
383
|
- **Updates**: `docs/requirements.md`, `docs/architecture.md`, `docs/workflows.md`, `docs/infrastructure.md`, `.gsd-t/progress.md`
|
|
383
384
|
- **Use when**: You have an existing codebase and want to fill docs with real findings instead of placeholders
|
|
384
385
|
|
|
386
|
+
### design-decompose
|
|
387
|
+
- **Summary**: Decompose a design (Figma/image/prototype) into a hierarchy of element → widget → page contracts
|
|
388
|
+
- **Auto-invoked**: No
|
|
389
|
+
- **Creates**: `.gsd-t/contracts/design/elements/*.contract.md`, `.gsd-t/contracts/design/widgets/*.contract.md`, `.gsd-t/contracts/design/pages/*.contract.md`, `.gsd-t/contracts/design/INDEX.md`
|
|
390
|
+
- **Use when**: Starting a design-to-code project with multiple pages/reusable components, or retrofitting a flat design-contract.md
|
|
391
|
+
- **Precedence rule**: element > widget > page. Widgets and pages cannot override element visual spec.
|
|
392
|
+
|
|
385
393
|
### log
|
|
386
394
|
- **Summary**: Sync progress.md Decision Log with recent git activity
|
|
387
395
|
- **Auto-invoked**: No
|
package/commands/gsd-t-quick.md
CHANGED
|
@@ -259,7 +259,13 @@ comparison table. You write ZERO feature code.
|
|
|
259
259
|
|
|
260
260
|
FAIL-BY-DEFAULT: Every visual element starts as UNVERIFIED. Prove each matches.
|
|
261
261
|
|
|
262
|
-
|
|
262
|
+
STEP 0 (MANDATORY FIRST): Data-labels cross-check.
|
|
263
|
+
For each element contract (or design-contract.md section), read the Test Fixture.
|
|
264
|
+
Verify EVERY label, value, percentage from the fixture appears verbatim in the
|
|
265
|
+
rendered UI. If any is missing → CRITICAL DEVIATION (wrong data). Wrong data
|
|
266
|
+
cannot be redeemed by visual polish.
|
|
267
|
+
|
|
268
|
+
1. Read .gsd-t/contracts/design-contract.md (flat) OR .gsd-t/contracts/design/ (hierarchical) for design source reference + Test Fixtures
|
|
263
269
|
2. Get design reference (Figma MCP screenshot, or design images from contract)
|
|
264
270
|
3. Start dev server, open the built frontend in browser (Claude Preview/Chrome MCP/Playwright)
|
|
265
271
|
4. Open the original design reference in a second browser view
|
package/commands/gsd.md
CHANGED
|
@@ -65,7 +65,8 @@ When the request involves UI implementation from a design (Figma, screenshots, m
|
|
|
65
65
|
- **If a milestone exists but no domains** → route to `partition` (creates design contract in Step 3.6)
|
|
66
66
|
- **If domains exist but no tasks** → route to `plan`
|
|
67
67
|
- **If tasks exist** → route to `execute` (design-to-code stack rule will inject)
|
|
68
|
-
- The design-to-code stack rule activates automatically when `.gsd-t/contracts/design-contract.md` exists or Figma MCP is configured — but the **partition step must run first** to create the design contract
|
|
68
|
+
- The design-to-code stack rule activates automatically when `.gsd-t/contracts/design-contract.md` OR `.gsd-t/contracts/design/` exists, or Figma MCP is configured — but the **partition step must run first** to create the design contract
|
|
69
|
+
- **For projects with multiple pages or reusable components** (charts, widgets, design system): route to `design-decompose` BEFORE partition to create the hierarchical contract tree (elements → widgets → pages). Single-page/one-off designs can use flat `design-contract.md` created during partition instead.
|
|
69
70
|
|
|
70
71
|
## Step 3: Confirm and Execute
|
|
71
72
|
|
package/docs/GSD-T-README.md
CHANGED
|
@@ -90,6 +90,7 @@ GSD-T reads all state files and tells you exactly where you left off.
|
|
|
90
90
|
| `/user:gsd-t-gap-analysis` | Requirements gap analysis — spec vs. existing code | Manual |
|
|
91
91
|
| `/user:gsd-t-promote-debt` | Convert techdebt items to milestones | Manual |
|
|
92
92
|
| `/user:gsd-t-populate` | Auto-populate docs from existing codebase | Manual |
|
|
93
|
+
| `/user:gsd-t-design-decompose` | Decompose design into element/widget/page contracts | Manual |
|
|
93
94
|
|
|
94
95
|
### Milestone Workflow
|
|
95
96
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tekyzinc/gsd-t",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.59.10",
|
|
4
4
|
"description": "GSD-T: Contract-Driven Development for Claude Code — 51 slash commands with headless CI/CD mode, graph-powered code analysis, real-time agent dashboard, execution intelligence, task telemetry, doc-ripple enforcement, backlog management, impact analysis, test sync, milestone archival, and PRD generation",
|
|
5
5
|
"author": "Tekyz, Inc.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -63,6 +63,7 @@ PROJECT or FEATURE or SCAN
|
|
|
63
63
|
| `/user:gsd-t-health` | Validate .gsd-t/ structure, optionally repair |
|
|
64
64
|
| `/user:gsd-t-pause` | Save exact position for reliable resume |
|
|
65
65
|
| `/user:gsd-t-populate` | Auto-populate docs from existing codebase |
|
|
66
|
+
| `/user:gsd-t-design-decompose` | Decompose design into element/widget/page contracts |
|
|
66
67
|
| `/user:gsd-t-log` | Sync progress Decision Log with recent git activity |
|
|
67
68
|
| `/user:gsd-t-resume` | Restore context, continue |
|
|
68
69
|
| `/user:gsd-t-version-update` | Update GSD-T to latest version |
|
|
@@ -639,7 +640,7 @@ GSD-T auto-detects project tech stack at subagent spawn time and injects mandato
|
|
|
639
640
|
|
|
640
641
|
**Stack-specific rules**: Injected only when the matching stack is detected (e.g., `react.md` when `"react"` is in `package.json`).
|
|
641
642
|
|
|
642
|
-
**Design-to-code**: Activated when `.gsd-t/contracts/design-contract.md
|
|
643
|
+
**Design-to-code**: Activated when `.gsd-t/contracts/design-contract.md` (flat), `.gsd-t/contracts/design/` (hierarchical element/widget/page contracts — bootstrap via `/user:gsd-t-design-decompose`), `design-tokens.json`, `design-tokens/`, `.figmarc`, or `figma.config.json` exists, OR when Figma MCP is configured in `~/.claude/settings.json`. Auto-bootstrapped during partition when Figma URLs or design references are detected in requirements. Enforces pixel-perfect frontend implementation from designs with: Figma MCP auto-detection, design token extraction protocol, stack capability evaluation (recommends alternatives if stack can't achieve the design), component decomposition, responsive breakpoint strategy, and a mandatory visual verification loop — every implemented screen must be rendered in a real browser, screenshotted at mobile/tablet/desktop breakpoints, and compared pixel-by-pixel against the Figma design. Visual deviations block task completion.
|
|
643
644
|
|
|
644
645
|
**Enforcement**: Stack rule violations have the same weight as contract violations — they are task failures, not warnings.
|
|
645
646
|
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# Design Chart & Atom Taxonomy (Closed Set)
|
|
2
|
+
|
|
3
|
+
When decomposing a design into element contracts, you MUST pick from this enumerated list. DO NOT invent element names. If a design element doesn't fit any of these, STOP and ask the user to extend the taxonomy before proceeding.
|
|
4
|
+
|
|
5
|
+
## Why this is a closed set
|
|
6
|
+
|
|
7
|
+
The catastrophic failure mode is: agent sees "bars" in Figma, picks `chart-bar-grouped-vertical`, but the design is actually `chart-bar-stacked-horizontal-percentage`. Different element, different contract, different data binding. Closed enumeration with visual distinguishers prevents this.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Charts
|
|
12
|
+
|
|
13
|
+
### Bar charts
|
|
14
|
+
|
|
15
|
+
| Element name | Visual distinguisher |
|
|
16
|
+
|------------------------------------------------|--------------------------------------------------------------------------------------|
|
|
17
|
+
| `chart-bar-horizontal-single` | One bar per category, horizontal orientation, single series |
|
|
18
|
+
| `chart-bar-vertical-single` | One bar per category, vertical orientation, single series |
|
|
19
|
+
| `chart-bar-grouped-horizontal` | Multiple bars per category SIDE-BY-SIDE, horizontal, ≥2 series (legend required) |
|
|
20
|
+
| `chart-bar-grouped-vertical` | Multiple bars per category SIDE-BY-SIDE, vertical, ≥2 series (legend required) |
|
|
21
|
+
| `chart-bar-stacked-horizontal` | Segments STACKED in one bar per category, horizontal, ≥2 series with absolute values |
|
|
22
|
+
| `chart-bar-stacked-vertical` | Segments STACKED in one bar per category, vertical, ≥2 series with absolute values |
|
|
23
|
+
| `chart-bar-stacked-horizontal-percentage` | SINGLE horizontal bar, 100% width, segments sum to 100% (distribution viz) |
|
|
24
|
+
| `chart-bar-stacked-vertical-percentage` | SINGLE vertical bar, 100% height, segments sum to 100% |
|
|
25
|
+
| `chart-bar-diverging-horizontal` | Bars extend left AND right from a center axis (sentiment, pos/neg) |
|
|
26
|
+
| `chart-bar-range-horizontal` | Floating bars showing min-max range (no origin axis) |
|
|
27
|
+
| `chart-bar-waterfall-vertical` | Sequential bars showing cumulative change, pos/neg |
|
|
28
|
+
|
|
29
|
+
**Decision rule for bar charts:**
|
|
30
|
+
1. Does the chart show ONE bar with segments that sum to 100%? → `*-stacked-*-percentage`
|
|
31
|
+
2. Does the chart show multiple bars stacked together? → `*-stacked-*` (non-percentage if absolute values shown)
|
|
32
|
+
3. Does the chart show multiple bars side-by-side per category? → `*-grouped-*`
|
|
33
|
+
4. Single-series, one bar per category? → `*-single`
|
|
34
|
+
|
|
35
|
+
### Line / area charts
|
|
36
|
+
|
|
37
|
+
| Element name | Visual distinguisher |
|
|
38
|
+
|----------------------------------|----------------------------------------------------------------------|
|
|
39
|
+
| `chart-line-single` | One line, continuous x-axis |
|
|
40
|
+
| `chart-line-multi` | ≥2 lines, shared x-axis, legend required |
|
|
41
|
+
| `chart-area-single` | Line with filled area below |
|
|
42
|
+
| `chart-area-stacked` | Multiple filled areas stacked (summed) |
|
|
43
|
+
| `chart-area-stacked-percentage` | Multiple filled areas stacked to 100% |
|
|
44
|
+
| `chart-line-step` | Stepped line (no diagonal connectors) |
|
|
45
|
+
| `chart-line-smooth` | Smoothed/curved line (bezier) |
|
|
46
|
+
|
|
47
|
+
### Circular charts
|
|
48
|
+
|
|
49
|
+
| Element name | Visual distinguisher |
|
|
50
|
+
|---------------------------|-----------------------------------------------------------|
|
|
51
|
+
| `chart-pie` | Full circle, no hole |
|
|
52
|
+
| `chart-donut` | Circle with center hole, may show center label/value |
|
|
53
|
+
| `chart-donut-gauge` | Partial donut (half or quarter circle) as gauge/progress |
|
|
54
|
+
| `chart-radial-bar` | Concentric arcs, one per category |
|
|
55
|
+
| `chart-polar` | Radial grid with data plotted by angle |
|
|
56
|
+
|
|
57
|
+
### Distribution / comparison
|
|
58
|
+
|
|
59
|
+
| Element name | Visual distinguisher |
|
|
60
|
+
|---------------------------|-----------------------------------------------------------|
|
|
61
|
+
| `chart-scatter` | Points on x/y plane, no connecting lines |
|
|
62
|
+
| `chart-bubble` | Scatter with variable point size (z-axis) |
|
|
63
|
+
| `chart-heatmap` | Grid of cells with color intensity |
|
|
64
|
+
| `chart-treemap` | Nested rectangles sized by value |
|
|
65
|
+
| `chart-histogram` | Bars showing distribution over continuous range |
|
|
66
|
+
| `chart-boxplot` | Box + whiskers showing quartiles |
|
|
67
|
+
|
|
68
|
+
### Inline / mini
|
|
69
|
+
|
|
70
|
+
| Element name | Visual distinguisher |
|
|
71
|
+
|---------------------------|-----------------------------------------------------------|
|
|
72
|
+
| `chart-sparkline-line` | Tiny inline line chart, no axes |
|
|
73
|
+
| `chart-sparkline-bar` | Tiny inline bar chart, no axes |
|
|
74
|
+
| `chart-sparkline-area` | Tiny inline filled area, no axes |
|
|
75
|
+
| `chart-progress-bar` | Horizontal bar showing % complete |
|
|
76
|
+
| `chart-progress-ring` | Circular ring showing % complete |
|
|
77
|
+
|
|
78
|
+
### Flow / hierarchy
|
|
79
|
+
|
|
80
|
+
| Element name | Visual distinguisher |
|
|
81
|
+
|---------------------------|-----------------------------------------------------------|
|
|
82
|
+
| `chart-sankey` | Flow diagram with weighted links |
|
|
83
|
+
| `chart-funnel` | Decreasing bars/trapezoids showing attrition |
|
|
84
|
+
| `chart-chord` | Circular chord diagram |
|
|
85
|
+
|
|
86
|
+
### Geo
|
|
87
|
+
|
|
88
|
+
| Element name | Visual distinguisher |
|
|
89
|
+
|---------------------------|-----------------------------------------------------------|
|
|
90
|
+
| `chart-choropleth` | Map with regions colored by value |
|
|
91
|
+
| `chart-symbol-map` | Map with points/symbols at locations |
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Axes (referenced by charts via `extends`)
|
|
96
|
+
|
|
97
|
+
| Element name | Visual distinguisher |
|
|
98
|
+
|---------------------------|-----------------------------------------------------------|
|
|
99
|
+
| `axis-x-categorical` | Category labels on x-axis |
|
|
100
|
+
| `axis-x-time` | Time/date labels on x-axis |
|
|
101
|
+
| `axis-x-numeric` | Numeric scale on x-axis |
|
|
102
|
+
| `axis-y-categorical` | Category labels on y-axis |
|
|
103
|
+
| `axis-y-numeric` | Numeric scale on y-axis |
|
|
104
|
+
| `axis-y-log` | Logarithmic y-axis |
|
|
105
|
+
| `axis-y-dual` | Two y-axes (left + right) with different scales |
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Legends
|
|
110
|
+
|
|
111
|
+
| Element name | Visual distinguisher |
|
|
112
|
+
|----------------------------|-----------------------------------------------------------|
|
|
113
|
+
| `legend-horizontal-top` | Horizontal row above chart |
|
|
114
|
+
| `legend-horizontal-bottom` | Horizontal row below chart |
|
|
115
|
+
| `legend-vertical-left` | Vertical column left of chart |
|
|
116
|
+
| `legend-vertical-right` | Vertical column right of chart |
|
|
117
|
+
| `legend-inline` | Labels placed directly on chart (no separate legend area) |
|
|
118
|
+
| `legend-interactive` | Legend items toggle series visibility on click |
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Cards / Containers (widget chrome, but each is itself an element)
|
|
123
|
+
|
|
124
|
+
| Element name | Visual distinguisher |
|
|
125
|
+
|---------------------------------|-------------------------------------------------------------------------|
|
|
126
|
+
| `stat-card` | Label + large value |
|
|
127
|
+
| `stat-card-with-delta` | Label + value + delta indicator (↑↓ + % change) |
|
|
128
|
+
| `stat-card-with-sparkline` | Label + value + inline sparkline |
|
|
129
|
+
| `stat-card-with-icon` | Label + value + icon tile (colored square/circle with icon) |
|
|
130
|
+
| `stat-card-kpi-large` | Large value centered, small label below (used above charts) |
|
|
131
|
+
| `card-bordered` | Generic card with border + padding |
|
|
132
|
+
| `card-elevated` | Generic card with shadow |
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Tables
|
|
137
|
+
|
|
138
|
+
| Element name | Visual distinguisher |
|
|
139
|
+
|---------------------------|-----------------------------------------------------------|
|
|
140
|
+
| `table-dense` | Tight row height, small padding |
|
|
141
|
+
| `table-comfortable` | Standard row height |
|
|
142
|
+
| `table-zebra` | Alternating row backgrounds |
|
|
143
|
+
| `table-striped-header` | Only header row has distinct background |
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Controls
|
|
148
|
+
|
|
149
|
+
| Element name | Visual distinguisher |
|
|
150
|
+
|---------------------------|-----------------------------------------------------------|
|
|
151
|
+
| `button-primary` | Filled, brand color |
|
|
152
|
+
| `button-secondary` | Outlined or muted fill |
|
|
153
|
+
| `button-ghost` | No border/fill, text + hover state only |
|
|
154
|
+
| `button-icon` | Icon-only button |
|
|
155
|
+
| `button-fab` | Floating action button (circular, elevated) |
|
|
156
|
+
| `input-text` | Single-line text input |
|
|
157
|
+
| `input-search` | Text input with leading search icon |
|
|
158
|
+
| `input-textarea` | Multi-line text input |
|
|
159
|
+
| `select-dropdown` | Native-or-custom select with chevron |
|
|
160
|
+
| `select-multi` | Multi-select (tags/chips) |
|
|
161
|
+
| `checkbox` | Square binary toggle |
|
|
162
|
+
| `radio` | Circular exclusive choice |
|
|
163
|
+
| `toggle` | Binary switch |
|
|
164
|
+
| `slider-range` | Continuous range input |
|
|
165
|
+
| `tabs-underline` | Tabs with underline indicator |
|
|
166
|
+
| `tabs-pill` | Tabs rendered as pills |
|
|
167
|
+
| `tabs-segmented` | Connected segmented-control style |
|
|
168
|
+
| `filter-pill` | Removable filter chip |
|
|
169
|
+
| `date-picker` | Date input with calendar popup |
|
|
170
|
+
| `date-range-picker` | Date range input |
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Atoms (small visual artifacts — the often-forgotten tier)
|
|
175
|
+
|
|
176
|
+
| Element name | Visual distinguisher |
|
|
177
|
+
|---------------------------|-----------------------------------------------------------|
|
|
178
|
+
| `icon` | SVG/icon-font glyph — one contract if all icons share spec, multiple variants if styles differ |
|
|
179
|
+
| `icon-outline` | Stroke-only icons (if coexisting with filled variants) |
|
|
180
|
+
| `icon-filled` | Filled icons (if coexisting with outline variants) |
|
|
181
|
+
| `logo` | Brand logo |
|
|
182
|
+
| `avatar` | User profile image/placeholder (circle or rounded-square) |
|
|
183
|
+
| `badge` | Small count indicator (typically on avatar or icon) |
|
|
184
|
+
| `chip` | Rounded container with text (filter, tag, status) |
|
|
185
|
+
| `status-dot` | Colored circle indicator |
|
|
186
|
+
| `divider-horizontal` | Horizontal line separator |
|
|
187
|
+
| `divider-vertical` | Vertical line separator |
|
|
188
|
+
| `spinner` | Loading indicator |
|
|
189
|
+
| `skeleton` | Loading placeholder |
|
|
190
|
+
| `tooltip` | Hover-triggered info bubble |
|
|
191
|
+
| `breadcrumb` | Hierarchical nav trail |
|
|
192
|
+
| `pagination` | Page number navigation |
|
|
193
|
+
| `tag` | Non-removable text label (unlike chip) |
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Typography
|
|
198
|
+
|
|
199
|
+
| Element name | Visual distinguisher |
|
|
200
|
+
|---------------------------|-----------------------------------------------------------|
|
|
201
|
+
| `heading-h1` | Page title |
|
|
202
|
+
| `heading-h2` | Section title |
|
|
203
|
+
| `heading-h3` | Sub-section title / widget title |
|
|
204
|
+
| `heading-h4` | Small heading |
|
|
205
|
+
| `text-body` | Body text |
|
|
206
|
+
| `text-caption` | Small caption/metadata |
|
|
207
|
+
| `text-label` | Form/field label |
|
|
208
|
+
| `text-mono` | Monospaced (code, data) |
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## Layout primitives
|
|
213
|
+
|
|
214
|
+
| Element name | Visual distinguisher |
|
|
215
|
+
|---------------------------|-----------------------------------------------------------|
|
|
216
|
+
| `container-page` | Top-level page container with max-width |
|
|
217
|
+
| `container-card` | Card with padding + radius + optional border/shadow |
|
|
218
|
+
| `stack-horizontal` | Flex row |
|
|
219
|
+
| `stack-vertical` | Flex column |
|
|
220
|
+
| `grid` | CSS grid layout primitive |
|
|
221
|
+
| `divider-section` | Horizontal divider between page sections |
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## Using this taxonomy during decomposition
|
|
226
|
+
|
|
227
|
+
When `gsd-t-design-decompose` runs, for EACH visual element encountered in the design:
|
|
228
|
+
|
|
229
|
+
1. **Identify the category** (chart / legend / axis / card / table / control / atom / typography / layout)
|
|
230
|
+
2. **Pick the EXACT element name from this file** — do not rename, do not abbreviate
|
|
231
|
+
3. **If no match found** → STOP. Report to user: "Element at Figma node {nodeId} does not match any taxonomy entry. Proposed new variant: {name}, because: {rationale}. Should I extend the taxonomy?"
|
|
232
|
+
4. **Never pick a near-match** — "close enough" is exactly how horizontal stacked bar % became grouped vertical bars.
|
|
233
|
+
|
|
234
|
+
### Visual distinguishers for ambiguous cases
|
|
235
|
+
|
|
236
|
+
**"Is this a stacked bar or a grouped bar?"**
|
|
237
|
+
- Do the bars for a single category TOUCH/STACK or sit SIDE-BY-SIDE?
|
|
238
|
+
- Touch/stack → `chart-bar-stacked-*`
|
|
239
|
+
- Side-by-side → `chart-bar-grouped-*`
|
|
240
|
+
|
|
241
|
+
**"Is this stacked-absolute or stacked-percentage?"**
|
|
242
|
+
- Do segments fill a FIXED WIDTH/HEIGHT regardless of data?
|
|
243
|
+
- Yes (all bars are same length) → `*-stacked-*-percentage`
|
|
244
|
+
- No (bars vary in length by total value) → `*-stacked-*` (non-percentage)
|
|
245
|
+
|
|
246
|
+
**"Is this a pie or a donut?"**
|
|
247
|
+
- Is there a hole in the center?
|
|
248
|
+
- Yes → `chart-donut`
|
|
249
|
+
- No → `chart-pie`
|
|
250
|
+
|
|
251
|
+
**"Is this a bar chart or a histogram?"**
|
|
252
|
+
- Are x-axis values CATEGORIES (distinct labels) or BINS (numeric ranges)?
|
|
253
|
+
- Categories → `chart-bar-*`
|
|
254
|
+
- Numeric bins → `chart-histogram`
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## Extending the taxonomy
|
|
259
|
+
|
|
260
|
+
If a new element variant is needed:
|
|
261
|
+
|
|
262
|
+
1. Add it to the relevant section above with a visual distinguisher
|
|
263
|
+
2. If it's a new chart variant, add a decision rule under the chart type
|
|
264
|
+
3. Bump GSD-T version (minor) and document the addition in CHANGELOG.md
|
|
265
|
+
4. Never delete entries — only add (breaking the closed set is destructive)
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# Element Contract: {element-name}
|
|
2
|
+
|
|
3
|
+
Atomic visual unit. One contract per visual variant (e.g., `chart-bar-stacked-horizontal` and `chart-bar-stacked-vertical` are separate contracts). Widgets and pages reference element contracts by name; they CANNOT override the visual spec.
|
|
4
|
+
|
|
5
|
+
## Metadata
|
|
6
|
+
|
|
7
|
+
| Field | Value |
|
|
8
|
+
|----------------|-----------------------------------------------------------|
|
|
9
|
+
| element | {e.g., chart-bar-stacked-horizontal} |
|
|
10
|
+
| category | {chart / legend / axis / card / table / control / layout} |
|
|
11
|
+
| variant_of | {base element name, or `null` if base} |
|
|
12
|
+
| version | {1.0} |
|
|
13
|
+
| extends | {[axis-x-numeric, axis-y-categorical] — or []} |
|
|
14
|
+
| design_source | {Figma node URL or design file path + node id} |
|
|
15
|
+
| extracted_via | {Figma MCP / Visual Analysis / Design Tokens} |
|
|
16
|
+
| extracted_date | {YYYY-MM-DD} |
|
|
17
|
+
|
|
18
|
+
## Purpose
|
|
19
|
+
|
|
20
|
+
{One sentence — what this element is and when to use it. E.g., "Horizontal stacked bar chart for displaying part-to-whole comparisons across categories, with segment labels inside when segment width ≥40px."}
|
|
21
|
+
|
|
22
|
+
## Visual Spec
|
|
23
|
+
|
|
24
|
+
| Property | Value |
|
|
25
|
+
|---------------|-------------------------------------------------------|
|
|
26
|
+
| {dimension_1} | {exact value, referencing design tokens if available} |
|
|
27
|
+
| {dimension_2} | {exact value} |
|
|
28
|
+
|
|
29
|
+
*List every measurable visual property: dimensions, spacing, radii, borders, shadows, opacity. Reference design tokens rather than raw values where possible (`tokens.spacing.4` instead of `16px`).*
|
|
30
|
+
|
|
31
|
+
## Labels / Text (if applicable)
|
|
32
|
+
|
|
33
|
+
| Property | Value |
|
|
34
|
+
|---------------|--------------------------------------------------------------------|
|
|
35
|
+
| font_family | {tokens.font.family.sans} |
|
|
36
|
+
| font_size | {tokens.font.size.sm} |
|
|
37
|
+
| font_weight | {tokens.font.weight.medium} |
|
|
38
|
+
| color | {tokens.color.text.primary} |
|
|
39
|
+
| position | {inside-segment-centered / above-bar / below-bar / left / right} |
|
|
40
|
+
| visibility | {always / conditional: {rule, e.g., `hide if segment width <40px`}} |
|
|
41
|
+
| alignment | {left / center / right / start / end} |
|
|
42
|
+
| truncation | {none / ellipsis / tooltip-on-truncate} |
|
|
43
|
+
|
|
44
|
+
## Colors
|
|
45
|
+
|
|
46
|
+
| Usage | Token |
|
|
47
|
+
|-------------|--------------------------------------|
|
|
48
|
+
| {fill} | {tokens.color.chart.sequence[0..n]} |
|
|
49
|
+
| {stroke} | {tokens.color.chart.border} |
|
|
50
|
+
| {text} | {tokens.color.text.onPrimary} |
|
|
51
|
+
| {hover} | {tokens.color.chart.hover.overlay} |
|
|
52
|
+
|
|
53
|
+
## States
|
|
54
|
+
|
|
55
|
+
| State | Visual Change |
|
|
56
|
+
|-------------|--------------------------------------------------------------------|
|
|
57
|
+
| default | {base appearance} |
|
|
58
|
+
| hover | {e.g., segment opacity 1.0, siblings 0.6, cursor: pointer} |
|
|
59
|
+
| active | {e.g., border 2px tokens.color.accent} |
|
|
60
|
+
| disabled | {e.g., opacity 0.4, cursor: not-allowed} |
|
|
61
|
+
| focus | {e.g., outline 2px tokens.color.focus, offset 2px} |
|
|
62
|
+
| loading | {e.g., skeleton shimmer} |
|
|
63
|
+
| empty | {e.g., placeholder icon + "No data" text} |
|
|
64
|
+
|
|
65
|
+
## Interactions
|
|
66
|
+
|
|
67
|
+
| Event | Behavior |
|
|
68
|
+
|-------------|--------------------------------------------------------------------|
|
|
69
|
+
| hover | {e.g., show tooltip with {category, series, value, percent}} |
|
|
70
|
+
| click | {e.g., emit `onSegmentClick({category, series, value})`} |
|
|
71
|
+
| keyboard | {e.g., Tab focuses, Enter activates, Arrow keys navigate segments} |
|
|
72
|
+
|
|
73
|
+
## Data Binding
|
|
74
|
+
|
|
75
|
+
**Input shape:**
|
|
76
|
+
```typescript
|
|
77
|
+
{
|
|
78
|
+
// Define the minimum data contract required to render this element
|
|
79
|
+
categories: string[];
|
|
80
|
+
series: { name: string; values: number[]; color?: string }[];
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Invariants:**
|
|
85
|
+
- {e.g., All series arrays MUST have length === categories.length}
|
|
86
|
+
- {e.g., Values MUST be non-negative for stacked variants}
|
|
87
|
+
|
|
88
|
+
## Test Fixture (MANDATORY — extracted from design, NOT placeholder)
|
|
89
|
+
|
|
90
|
+
This is the EXACT data from the design source. Verification compares the built component rendered with this fixture against the Figma design. Placeholder data (Lorem, foo/bar, Calculator/Planner) is FORBIDDEN here — the verifier must be able to compare actual labels and values side-by-side.
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"__source__": "{Figma node URL or image file + node id}",
|
|
95
|
+
"__extracted_via__": "{Figma MCP get_design_context | visual analysis}",
|
|
96
|
+
"__extracted_date__": "{YYYY-MM-DD}",
|
|
97
|
+
|
|
98
|
+
"categories": ["{exact label 1 from design}", "{exact label 2}", "..."],
|
|
99
|
+
"series": [
|
|
100
|
+
{
|
|
101
|
+
"name": "{exact series name from design}",
|
|
102
|
+
"values": [{exact value 1}, {exact value 2}, ...]
|
|
103
|
+
}
|
|
104
|
+
],
|
|
105
|
+
|
|
106
|
+
"center_value": "{exact value shown in donut center, if applicable}",
|
|
107
|
+
"center_sublabel": "{exact sublabel, if applicable}",
|
|
108
|
+
"percentages_shown": [{30}, {21}, {20}, {15}, {14}]
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Verification rule**: when the component is rendered with THIS fixture, every label, every value, every percentage shown in the built UI MUST match the design. Any substitution is a DEVIATION.
|
|
113
|
+
|
|
114
|
+
## Responsive Behavior
|
|
115
|
+
|
|
116
|
+
| Breakpoint | Adaptation |
|
|
117
|
+
|------------|---------------------------------------------------------------|
|
|
118
|
+
| mobile | {e.g., labels hidden, tap for tooltip} |
|
|
119
|
+
| tablet | {e.g., reduced label font-size to tokens.font.size.xs} |
|
|
120
|
+
| desktop | {full labels as specified} |
|
|
121
|
+
|
|
122
|
+
## Accessibility
|
|
123
|
+
|
|
124
|
+
- **Role**: {e.g., `img` with descriptive aria-label, or `figure` with `<figcaption>`}
|
|
125
|
+
- **Keyboard**: {e.g., focusable, arrow-key navigation between segments}
|
|
126
|
+
- **Screen reader**: {e.g., announces category, series, value on focus}
|
|
127
|
+
- **Contrast**: {label text contrast ratio ≥4.5:1 against segment fill}
|
|
128
|
+
|
|
129
|
+
## Implementation Notes
|
|
130
|
+
|
|
131
|
+
- **Library**: {e.g., Plotly.js / Recharts / D3 / native SVG}
|
|
132
|
+
- **Component path**: {src/components/charts/BarStackedHorizontal.vue}
|
|
133
|
+
- **Dependencies**: {list of required packages}
|
|
134
|
+
|
|
135
|
+
## Verification Checklist
|
|
136
|
+
|
|
137
|
+
Design Verification Agent uses this list. Every item must resolve to ✅ MATCH or ❌ DEVIATION (with specific values) — never "looks close" or "appears to match".
|
|
138
|
+
|
|
139
|
+
- [ ] {Visual spec property 1 matches design}
|
|
140
|
+
- [ ] {Visual spec property 2 matches design}
|
|
141
|
+
- [ ] Label position/font/color match design
|
|
142
|
+
- [ ] Color sequence matches design tokens
|
|
143
|
+
- [ ] Hover state changes as specified
|
|
144
|
+
- [ ] Focus state visible and correct
|
|
145
|
+
- [ ] Responsive adaptations fire at correct breakpoints
|
|
146
|
+
- [ ] Accessibility attributes present and correct
|
|
147
|
+
|
|
148
|
+
## Examples
|
|
149
|
+
|
|
150
|
+
**Used by widgets:** {list widget contracts that reference this element}
|
|
151
|
+
**Used by pages:** {list page contracts that reference this element directly}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Page Contract: {page-name}
|
|
2
|
+
|
|
3
|
+
Top-level assembly of widgets + global layout + routing + data loading. Pages POSITION widgets in a layout grid; they cannot redefine widget internals or element visual specs.
|
|
4
|
+
|
|
5
|
+
## Metadata
|
|
6
|
+
|
|
7
|
+
| Field | Value |
|
|
8
|
+
|----------------|-------------------------------------------------|
|
|
9
|
+
| page | {e.g., dashboard-overview} |
|
|
10
|
+
| route | {e.g., /dashboard or /dashboard/overview} |
|
|
11
|
+
| version | {1.0} |
|
|
12
|
+
| design_source | {Figma page URL or image reference} |
|
|
13
|
+
| extracted_date | {YYYY-MM-DD} |
|
|
14
|
+
|
|
15
|
+
## Purpose
|
|
16
|
+
|
|
17
|
+
{One sentence — what this page is for and who uses it. E.g., "Primary landing page after login. Displays KPIs, revenue trends, and recent activity for executives scanning performance at-a-glance."}
|
|
18
|
+
|
|
19
|
+
## Widgets Used
|
|
20
|
+
|
|
21
|
+
| Position in Grid | Widget Contract | Notes |
|
|
22
|
+
|----------------------------------|---------------------------------|------------------------------|
|
|
23
|
+
| header | page-header-widget | {sticky} |
|
|
24
|
+
| sidebar | nav-sidebar-widget | {collapsible at <1024px} |
|
|
25
|
+
| grid[row=1, cols=1-4] | stat-strip-widget | {4 KPI tiles} |
|
|
26
|
+
| grid[row=2, col=1-2] | revenue-breakdown-widget | {spans 2 columns} |
|
|
27
|
+
| grid[row=2, col=3-4] | user-growth-widget | {spans 2 columns} |
|
|
28
|
+
| grid[row=3, col=1-4] | recent-activity-table-widget | {full width} |
|
|
29
|
+
|
|
30
|
+
## Layout
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
┌──────────────────────────────────────────────────────┐
|
|
34
|
+
│ page-header-widget │
|
|
35
|
+
├──────────┬───────────────────────────────────────────┤
|
|
36
|
+
│ │ stat-strip-widget │
|
|
37
|
+
│ nav- ├─────────────────────┬─────────────────────┤
|
|
38
|
+
│ sidebar │ revenue-breakdown │ user-growth │
|
|
39
|
+
│ -widget │ │ │
|
|
40
|
+
│ ├─────────────────────┴─────────────────────┤
|
|
41
|
+
│ │ recent-activity-table-widget │
|
|
42
|
+
└──────────┴───────────────────────────────────────────┘
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
| Property | Value |
|
|
46
|
+
|---------------------|------------------------------------------------|
|
|
47
|
+
| layout_type | {grid / flex / fixed-sidebar+fluid-content} |
|
|
48
|
+
| grid_columns | {4} |
|
|
49
|
+
| grid_column_gap | {tokens.spacing.6} |
|
|
50
|
+
| grid_row_gap | {tokens.spacing.6} |
|
|
51
|
+
| page_padding | {tokens.spacing.8} |
|
|
52
|
+
| max_content_width | {1440px} |
|
|
53
|
+
| sidebar_width | {240px (expanded) / 64px (collapsed)} |
|
|
54
|
+
| header_height | {64px} |
|
|
55
|
+
| background | {tokens.color.bg.page} |
|
|
56
|
+
|
|
57
|
+
## Data Loading
|
|
58
|
+
|
|
59
|
+
**Page-level data requirements:**
|
|
60
|
+
```typescript
|
|
61
|
+
{
|
|
62
|
+
stats: Stat[];
|
|
63
|
+
revenue: RevenueData[];
|
|
64
|
+
userGrowth: GrowthData[];
|
|
65
|
+
activity: ActivityRow[];
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Loading strategy:**
|
|
70
|
+
- {e.g., Single API call to `/api/dashboard/overview` on mount}
|
|
71
|
+
- {e.g., Parallel fetches per widget; widgets manage own loading states}
|
|
72
|
+
- {e.g., Server-side rendered with incremental hydration}
|
|
73
|
+
|
|
74
|
+
## Routing & Navigation
|
|
75
|
+
|
|
76
|
+
- **Route**: {/dashboard/overview}
|
|
77
|
+
- **Guards**: {requires authentication, role: user|admin}
|
|
78
|
+
- **Breadcrumbs**: {Home > Dashboard > Overview}
|
|
79
|
+
- **Nav active state**: {highlights "Dashboard" in nav-sidebar}
|
|
80
|
+
|
|
81
|
+
## Global States
|
|
82
|
+
|
|
83
|
+
| State | Page Behavior |
|
|
84
|
+
|------------------|---------------------------------------------------------|
|
|
85
|
+
| unauthenticated | Redirect to /login |
|
|
86
|
+
| page_loading | Skeleton grid with widget placeholders |
|
|
87
|
+
| page_error | Full-page error with retry button |
|
|
88
|
+
| partial_error | Individual widgets show own error states; page persists |
|
|
89
|
+
|
|
90
|
+
## Responsive Behavior
|
|
91
|
+
|
|
92
|
+
| Breakpoint | Adaptation |
|
|
93
|
+
|------------|----------------------------------------------------------------|
|
|
94
|
+
| mobile | Sidebar becomes drawer; grid collapses to 1 column; stats stack vertically |
|
|
95
|
+
| tablet | Sidebar collapses to icon-only; grid becomes 2 columns |
|
|
96
|
+
| desktop | Full layout as specified |
|
|
97
|
+
|
|
98
|
+
## Interactions
|
|
99
|
+
|
|
100
|
+
- {Sidebar toggle persists across sessions (localStorage)}
|
|
101
|
+
- {Widget filter changes do NOT affect other widgets unless explicitly wired}
|
|
102
|
+
- {Clicking KPI tile navigates to detail page}
|
|
103
|
+
|
|
104
|
+
## Performance Budget
|
|
105
|
+
|
|
106
|
+
| Metric | Target |
|
|
107
|
+
|--------------------|-------------------------------------------------|
|
|
108
|
+
| First Contentful Paint | {<1.5s on 4G} |
|
|
109
|
+
| Time to Interactive | {<3.0s on 4G} |
|
|
110
|
+
| JS bundle size | {<200KB gzipped for this route} |
|
|
111
|
+
|
|
112
|
+
## Accessibility
|
|
113
|
+
|
|
114
|
+
- **Landmarks**: `<header>`, `<nav>`, `<main>`, per-widget `<section role="region">`
|
|
115
|
+
- **Skip link**: "Skip to main content" at top, focuses `<main>` on activation
|
|
116
|
+
- **Keyboard order**: header → sidebar → widgets in visual reading order
|
|
117
|
+
- **Page title**: Set via `<title>` per route
|
|
118
|
+
|
|
119
|
+
## Implementation Notes
|
|
120
|
+
|
|
121
|
+
- **Component path**: {src/pages/DashboardOverview.vue or src/routes/dashboard/overview.tsx}
|
|
122
|
+
- **Composes**: {list widget imports}
|
|
123
|
+
- **Router integration**: {vue-router / react-router / next.js app dir}
|
|
124
|
+
- **Data fetching**: {composable / hook / server component}
|
|
125
|
+
|
|
126
|
+
## Verification Checklist
|
|
127
|
+
|
|
128
|
+
Page-level verification runs AFTER all widgets pass their own verification. Page verification only checks assembly — widget and element internals are out of scope.
|
|
129
|
+
|
|
130
|
+
- [ ] All widgets present in correct grid positions
|
|
131
|
+
- [ ] Layout dimensions (gaps, padding, max-width) match design
|
|
132
|
+
- [ ] Header / sidebar / main regions correctly landmarked
|
|
133
|
+
- [ ] Sidebar collapse/expand behavior works
|
|
134
|
+
- [ ] Responsive breakpoints rearrange layout as specified
|
|
135
|
+
- [ ] Data loading strategy produces correct widget inputs
|
|
136
|
+
- [ ] Route guards enforce authentication/roles
|
|
137
|
+
- [ ] Performance budget met (measure with Lighthouse)
|
|
138
|
+
- [ ] Keyboard navigation follows visual reading order
|
|
139
|
+
- [ ] Skip-link and page title present
|
|
140
|
+
|
|
141
|
+
## Composes Elements (direct, not via widgets)
|
|
142
|
+
|
|
143
|
+
{List any element contracts referenced directly by the page (rare — usually everything goes through widgets). E.g., `button-primary` for a floating action button.}
|
|
@@ -6,6 +6,35 @@ These rules apply when implementing a visual design as frontend code. The design
|
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
+
## 0. Contract Structure — Flat or Hierarchical
|
|
10
|
+
|
|
11
|
+
Two contract layouts are supported. Pick the one that fits the project scope:
|
|
12
|
+
|
|
13
|
+
**Flat** (single file: `.gsd-t/contracts/design-contract.md`)
|
|
14
|
+
- Use when: single page, ≤10 distinct elements, nothing reusable across pages
|
|
15
|
+
- Pros: fast to set up; fine for a landing page or one-off screen
|
|
16
|
+
- Cons: no reuse; visual spec repeats; drift between instances is easy
|
|
17
|
+
|
|
18
|
+
**Hierarchical** (directory: `.gsd-t/contracts/design/{elements,widgets,pages}/`)
|
|
19
|
+
- Use when: multiple pages, reusable components (charts, cards, legends), design system in play
|
|
20
|
+
- Pros: element contracts are the single source of truth for visual spec — widgets and pages SELECT and POSITION but cannot override. Drift is structurally impossible.
|
|
21
|
+
- Cons: more contracts to write upfront (elements: ~10-20, widgets: ~5-10, pages: N)
|
|
22
|
+
- Bootstrap via: `/user:gsd-t-design-decompose {Figma URL or image path}`
|
|
23
|
+
- Templates: `templates/element-contract.md`, `templates/widget-contract.md`, `templates/page-contract.md`
|
|
24
|
+
|
|
25
|
+
**Precedence rule (hierarchical only)**:
|
|
26
|
+
```
|
|
27
|
+
element contract > widget contract > page contract
|
|
28
|
+
```
|
|
29
|
+
A widget that uses `chart-donut` cannot change `chart-donut`'s bar-gap, colors, or label positioning. If customization is needed, create a new element variant (`chart-donut-compact.contract.md`) instead.
|
|
30
|
+
|
|
31
|
+
**Detection at execute-time**:
|
|
32
|
+
- If `.gsd-t/contracts/design/` exists → hierarchical mode, verify elements first, then widgets, then pages
|
|
33
|
+
- Else if `.gsd-t/contracts/design-contract.md` exists → flat mode
|
|
34
|
+
- Else → bootstrap flat contract during partition
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
9
38
|
## 1. Design Source Setup
|
|
10
39
|
|
|
11
40
|
```
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Widget Contract: {widget-name}
|
|
2
|
+
|
|
3
|
+
Composition of elements + data binding + layout. Widgets SELECT and POSITION elements; they cannot redefine element visual specs. If a design needs a variant not covered by an existing element, create a new element contract — do not override from the widget.
|
|
4
|
+
|
|
5
|
+
## Metadata
|
|
6
|
+
|
|
7
|
+
| Field | Value |
|
|
8
|
+
|----------------|-------------------------------------------------|
|
|
9
|
+
| widget | {e.g., revenue-breakdown-widget} |
|
|
10
|
+
| version | {1.0} |
|
|
11
|
+
| design_source | {Figma node URL or image reference} |
|
|
12
|
+
| extracted_date | {YYYY-MM-DD} |
|
|
13
|
+
|
|
14
|
+
## Purpose
|
|
15
|
+
|
|
16
|
+
{One sentence — what this widget shows and why. E.g., "Displays revenue breakdown by product category with donut chart and accompanying legend-table, used on the dashboard Overview page and the Analytics detail page."}
|
|
17
|
+
|
|
18
|
+
## Card Chrome Slots (MANDATORY — fill every row or explicitly mark N/A)
|
|
19
|
+
|
|
20
|
+
Every widget is a card with consistent chrome. Missing chrome is the #1 cause of "looks off" verification results. Document EVERY slot, even if empty.
|
|
21
|
+
|
|
22
|
+
| Slot | Element Contract (or N/A) | Content / Behavior |
|
|
23
|
+
|-------------------------|------------------------------------------|--------------------------------------------------|
|
|
24
|
+
| `title` | heading-h3 | {exact title text from design} |
|
|
25
|
+
| `subtitle` | text-caption or N/A | {exact subtitle text — "Which tools members interact with most."} |
|
|
26
|
+
| `header_right_control` | select-dropdown, button-ghost, or N/A | {e.g., "Members ▼" filter dropdown in card header} |
|
|
27
|
+
| `kpi_header` | stat-card-kpi-large or N/A | {e.g., "2.4" + "Avg tools per member" shown above chart} |
|
|
28
|
+
| `body` | {primary element, e.g., chart-donut} | {main visual} |
|
|
29
|
+
| `body_sidebar` | {e.g., legend-vertical-right or N/A} | {element positioned alongside body} |
|
|
30
|
+
| `footer` | {e.g., text-caption or N/A} | {e.g., "Last updated: ..."} |
|
|
31
|
+
| `footer_legend` | {e.g., legend-horizontal-bottom or N/A} | {legend below body} |
|
|
32
|
+
|
|
33
|
+
**Rule**: If the design shows it, document it. If the design doesn't show it, write "N/A". Do NOT leave blank.
|
|
34
|
+
|
|
35
|
+
## Elements Used (body composition)
|
|
36
|
+
|
|
37
|
+
| Slot | Element Contract | Rationale |
|
|
38
|
+
|------------------|-----------------------------------------|------------------------------------|
|
|
39
|
+
| {body element} | {e.g., chart-donut} | {why this element} |
|
|
40
|
+
| {sidebar} | {e.g., legend-vertical-right} | {why this variant} |
|
|
41
|
+
|
|
42
|
+
**Rule**: Each slot references an element contract by name from `design-chart-taxonomy.md`. Widget CANNOT override element visual spec. To customize, create a new element variant.
|
|
43
|
+
|
|
44
|
+
## Layout
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
┌──────────────────────────────────────────────┐
|
|
48
|
+
│ {title} [{filter}] │
|
|
49
|
+
├──────────────────────────────────────────────┤
|
|
50
|
+
│ │ │
|
|
51
|
+
│ {chart} │ {legend} │
|
|
52
|
+
│ │ │
|
|
53
|
+
└──────────────────────────────────────────────┘
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
| Property | Value |
|
|
57
|
+
|--------------------|-----------------------------------------------------|
|
|
58
|
+
| container_width | {100% of parent / fixed 480px} |
|
|
59
|
+
| container_height | {auto / fixed 320px} |
|
|
60
|
+
| padding | {tokens.spacing.6} |
|
|
61
|
+
| gap | {tokens.spacing.4} |
|
|
62
|
+
| background | {tokens.color.surface.card} |
|
|
63
|
+
| border | {1px solid tokens.color.border.subtle} |
|
|
64
|
+
| border_radius | {tokens.radius.lg} |
|
|
65
|
+
| shadow | {tokens.shadow.sm} |
|
|
66
|
+
| chart_area_ratio | {60% of widget width} |
|
|
67
|
+
| legend_area_ratio | {40% of widget width} |
|
|
68
|
+
|
|
69
|
+
## Data Binding
|
|
70
|
+
|
|
71
|
+
**Widget input shape:**
|
|
72
|
+
```typescript
|
|
73
|
+
{
|
|
74
|
+
title: string;
|
|
75
|
+
timeRange: '7d' | '30d' | '90d' | '1y';
|
|
76
|
+
data: { category: string; value: number; color?: string }[];
|
|
77
|
+
onFilterChange?: (range: string) => void;
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Element data mapping:**
|
|
82
|
+
| Element | Receives |
|
|
83
|
+
|------------|------------------------------------------------------------------|
|
|
84
|
+
| chart | `{ categories: data.map(d=>d.category), series: [{name:'Revenue', values: data.map(d=>d.value)}]}` |
|
|
85
|
+
| legend | `data.map(d => ({label: d.category, value: d.value, color: d.color}))` |
|
|
86
|
+
| filter | `{ value: timeRange, options: ['7d','30d','90d','1y'], onChange: onFilterChange }` |
|
|
87
|
+
|
|
88
|
+
## States
|
|
89
|
+
|
|
90
|
+
| State | Widget Behavior |
|
|
91
|
+
|-------------|-------------------------------------------------------------------|
|
|
92
|
+
| loading | Skeleton shimmer replaces chart and legend |
|
|
93
|
+
| empty | Chart shows empty state; legend hidden |
|
|
94
|
+
| error | Error banner replaces chart; filter stays enabled |
|
|
95
|
+
|
|
96
|
+
## Responsive Behavior
|
|
97
|
+
|
|
98
|
+
| Breakpoint | Adaptation |
|
|
99
|
+
|------------|----------------------------------------------------------------|
|
|
100
|
+
| mobile | Legend drops below chart; chart becomes square |
|
|
101
|
+
| tablet | Legend shrinks to 35% width |
|
|
102
|
+
| desktop | Spec as defined above |
|
|
103
|
+
|
|
104
|
+
## Interactions
|
|
105
|
+
|
|
106
|
+
- {Chart segment hover highlights corresponding legend row}
|
|
107
|
+
- {Legend row click toggles segment visibility}
|
|
108
|
+
- {Filter change triggers data refetch via `onFilterChange`}
|
|
109
|
+
|
|
110
|
+
## Accessibility
|
|
111
|
+
|
|
112
|
+
- **Landmark role**: `region` with aria-labelledby pointing to title
|
|
113
|
+
- **Keyboard**: Tab order: filter → chart → legend rows
|
|
114
|
+
- **Announcements**: Data updates announced via `aria-live="polite"`
|
|
115
|
+
|
|
116
|
+
## Implementation Notes
|
|
117
|
+
|
|
118
|
+
- **Component path**: {src/widgets/RevenueBreakdownWidget.vue}
|
|
119
|
+
- **Composes**: {list element components the widget imports}
|
|
120
|
+
- **State management**: {local state / zustand store / props only}
|
|
121
|
+
|
|
122
|
+
## Verification Checklist
|
|
123
|
+
|
|
124
|
+
Widget-level verification runs AFTER all referenced elements pass their own verification. Widget verification only checks composition — element internals are out of scope.
|
|
125
|
+
|
|
126
|
+
- [ ] All referenced elements present and correctly slotted
|
|
127
|
+
- [ ] Layout dimensions (width, height, padding, gap) match design
|
|
128
|
+
- [ ] Responsive breakpoints adapt as specified
|
|
129
|
+
- [ ] Data binding produces correct element inputs (spot-check with sample data)
|
|
130
|
+
- [ ] Inter-element interactions fire (hover sync, click propagation)
|
|
131
|
+
- [ ] Loading/empty/error states render correctly
|
|
132
|
+
- [ ] Accessibility landmark and keyboard order correct
|
|
133
|
+
|
|
134
|
+
## Used By
|
|
135
|
+
|
|
136
|
+
**Pages**: {list page contracts that reference this widget}
|