@radicool/throughline 0.21.4 → 0.23.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.
Files changed (44) hide show
  1. package/README.md +5 -5
  2. package/adapters/codex/prompts/component-builder.md +12 -7
  3. package/adapters/codex/prompts/token-sync-layer.md +4 -1
  4. package/adapters/cursor/.cursor/rules/component-builder.mdc +12 -7
  5. package/adapters/cursor/.cursor/rules/token-sync-layer.mdc +4 -1
  6. package/adapters/generic/skills/component-builder/SKILL.md +12 -7
  7. package/adapters/generic/skills/token-sync-layer/SKILL.md +4 -1
  8. package/package.json +1 -1
  9. package/references/figma-checks.md +484 -0
  10. package/references/figma-component-standards.md +21 -53
  11. package/references/figma-scripting.md +8 -7
  12. package/references/state-baseline.md +27 -0
  13. package/scripts/README.md +5 -1
  14. package/scripts/build-figma-checks.mjs +98 -0
  15. package/scripts/build-state-baseline.mjs +71 -0
  16. package/scripts/install.mjs +9 -4
  17. package/scripts/lib/component-states.mjs +28 -7
  18. package/scripts/lib/figma-checks-read.figma.js +120 -0
  19. package/scripts/lib/figma-checks.mjs +240 -0
  20. package/scripts/lib/fixtures/figma-checks/avatar-not-in-table.json +43 -0
  21. package/scripts/lib/fixtures/figma-checks/button-ios-swift-skipped.json +85 -0
  22. package/scripts/lib/fixtures/figma-checks/button-missing-default.json +71 -0
  23. package/scripts/lib/fixtures/figma-checks/button-mui-ring.json +92 -0
  24. package/scripts/lib/fixtures/figma-checks/button-no-focus-variant.json +71 -0
  25. package/scripts/lib/fixtures/figma-checks/button-plain-frames.json +92 -0
  26. package/scripts/lib/fixtures/figma-checks/button-ring-child-not-absolute.json +94 -0
  27. package/scripts/lib/fixtures/figma-checks/button-ring-hidden.json +92 -0
  28. package/scripts/lib/fixtures/figma-checks/button-ring-unbound-colour.json +98 -0
  29. package/scripts/lib/fixtures/figma-checks/button-shadcn-filled.json +92 -0
  30. package/scripts/lib/fixtures/figma-checks/button-sparse.json +134 -0
  31. package/scripts/lib/fixtures/figma-checks/button-spread-zero.json +92 -0
  32. package/scripts/lib/fixtures/figma-checks/button-transparent-ring-child.json +94 -0
  33. package/scripts/lib/fixtures/figma-checks/button-vanilla-inside.json +87 -0
  34. package/scripts/lib/fixtures/figma-checks/button-vanilla-outside.json +87 -0
  35. package/scripts/lib/fixtures/figma-checks/button-wrong-combination.json +92 -0
  36. package/scripts/lib/fixtures/figma-checks/checkbox-checked-axis.real.json +245 -0
  37. package/scripts/lib/fixtures/figma-checks/checkbox-checked-synonym.json +87 -0
  38. package/scripts/lib/fixtures/figma-checks/checkbox-missing-selected.json +79 -0
  39. package/scripts/lib/fixtures/figma-checks/input-control-layer-missing.json +66 -0
  40. package/scripts/lib/fixtures/figma-checks/input-control-layer-ring-on-wrapper.json +79 -0
  41. package/scripts/lib/fixtures/figma-checks/input-control-layer.json +79 -0
  42. package/scripts/lib/fixtures/figma-checks/input-mui-weight-unbound.json +66 -0
  43. package/scripts/lib/fixtures/figma-checks/input-mui.json +66 -0
  44. package/scripts/lib/fixtures/figma-checks/sample-button.real.json +1497 -0
package/README.md CHANGED
@@ -73,7 +73,7 @@ Everything above was created during a single working session and synced directly
73
73
 
74
74
  | | |
75
75
  |---|---|
76
- | **A supported agent** | Required — [Claude Code](https://docs.claude.com/en/docs/claude-code) (native plugin), or **Cursor**, **Codex**, or any **AGENTS.md**-aware agent via `npx @radicool/throughline@0.21.4 init`. |
76
+ | **A supported agent** | Required — [Claude Code](https://docs.claude.com/en/docs/claude-code) (native plugin), or **Cursor**, **Codex**, or any **AGENTS.md**-aware agent via `npx @radicool/throughline@0.23.0 init`. |
77
77
  | **Figma** | Required, **desktop app** (the browser version causes connection errors). **Professional plan or higher recommended** — multi-mode variables (Light/Dark, brand themes) need it. |
78
78
  | **Figma access token** | Optional — only for the few Figma calls the Desktop Bridge can't make, like reading a published library. Without it, you work through the bridge alone. The setup skill walks you through it; your token stays yours and is never shared in chat. |
79
79
  | **GitHub** (or similar) | Optional — only when you're ready to graduate to a real remote repo with PRs and CI. |
@@ -114,9 +114,9 @@ Update anytime with `/plugin marketplace update throughline-marketplace`.
114
114
  Run the installer in your project — it stamps in the skills, the reference docs, the scripts, and the Figma MCP config for your tool:
115
115
 
116
116
  ```
117
- npx @radicool/throughline@0.21.4 init --target=cursor # → .cursor/rules + .cursor/mcp.json
118
- npx @radicool/throughline@0.21.4 init --target=codex # → prompts/ + AGENTS.md index + codex-mcp.toml
119
- npx @radicool/throughline@0.21.4 init --target=generic # → skills/ + AGENTS.md index
117
+ npx @radicool/throughline@0.23.0 init --target=cursor # → .cursor/rules + .cursor/mcp.json
118
+ npx @radicool/throughline@0.23.0 init --target=codex # → prompts/ + AGENTS.md index + codex-mcp.toml
119
+ npx @radicool/throughline@0.23.0 init --target=generic # → skills/ + AGENTS.md index
120
120
  ```
121
121
 
122
122
  It's safe to re-run (it merges `AGENTS.md` and `.cursor/mcp.json` non-destructively) and stages everything the skills read into `.throughline/`. Then open the `figma-environment-setup` skill/rule/prompt for your tool to begin. For Codex, add the printed `codex-mcp.toml` block to your Codex config to enable Figma access.
@@ -162,7 +162,7 @@ For the technically curious — how the machine actually runs.
162
162
 
163
163
  **Modes, within Figma's limits.** Light/Dark lives on the semantic collections; brand variants live on the primitive palette. Splitting the two axes across two collections keeps each one under Figma's 4-modes-per-collection cap on the Professional plan while still resolving correctly (`bg/default` → `{gray/50}` → the active brand's gray).
164
164
 
165
- **Model routing.** ThroughLine routes work by *cognition, not guesswork* — the expensive thinking on the best model, the mechanical doing on a cheap one. Setup pins **Haiku** to keep first-run costs low. Inside a skill, the deciding — a token architecture, a variant matrix, a slot contract — is planned once on the strongest tier, while the long mechanical part — placing Figma nodes, transcribing component code, running SVGR — runs on a cheap tier and self-verifies. You get the best model where it matters and a cheap one where it doesn't, without micromanaging it. The recommended mapping is **Haiku → Sonnet → Opus** for the `fast < balanced < deep` tiers, but apart from setup's Haiku pin, nothing is hardcoded — the ladder resolves against whatever models your install actually has, and on hosts without subagents skills degrade cleanly to a single model. You can still steer the session yourself (`/model opus` for the heaviest authoring, back to `/model sonnet` after); nothing forces an expensive model on you.
165
+ **Model routing.** ThroughLine routes work by *cognition, not guesswork* — the expensive thinking on the best model, the mechanical doing on a cheap one. Inside a skill, the deciding — a token architecture, a variant matrix, a slot contract — is planned once on the strongest tier, while the long mechanical part — placing Figma nodes, transcribing component code, running SVGR — runs on a cheap tier and self-verifies. You get the best model where it matters and a cheap one where it doesn't, without micromanaging it. The recommended mapping is **Haiku → Sonnet → Opus** for the `fast < balanced < deep` tiers, but nothing is hardcoded — the ladder resolves against whatever models your install actually has, and on hosts without subagents skills degrade cleanly to a single model. You can still steer the session yourself (`/model opus` for the heaviest authoring, back to `/model sonnet` after); nothing forces an expensive model on you.
166
166
 
167
167
  ## Who it's for
168
168
 
@@ -67,8 +67,9 @@ inconsistent output:
67
67
  - **Sizes** (sm, md, lg). Each size is its **own variant row**, not a state — see
68
68
  the layout law below.
69
69
  - **States** — **include the full relevant set, don't trim it.** The baseline is
70
- default, hover, focus, active (pressed), disabled; add the conditional states
71
- wherever they apply (loading, selected, success/error). Decide which conditional
70
+ the set `.throughline/references/state-baseline.md` owes that component
71
+ (default included); add the conditional states wherever they apply (loading,
72
+ success/error). Decide which conditional
72
73
  states a given component can reach, but never drop a state it genuinely has. See
73
74
  "State handling" in `.throughline/references/figma-component-standards.md`
74
75
  for the per-component checklist.
@@ -172,8 +173,12 @@ deterministic naming):
172
173
  re-screenshot) **and its "Post-build audit (REQUIRED before handoff)"
173
174
  read-back checklist** (container type, auto layout, bound variables,
174
175
  deterministic names) before the checkpoint. When you build inline, with no
175
- `figma-executor`, that includes item 9's `focus-indicator` check: a miss stops
176
- the build, as it would for the executor.
176
+ `figma-executor`, run `.throughline/references/figma-checks.md` the
177
+ way the executor does: `'spec'` mode before the first write and `'built'` mode
178
+ in the self-verify loop, with `EXPECT` built from your own matrix. You are the
179
+ architect here, so you name `controlLayer` yourself for a wrapped control (an
180
+ Input with a label or helper text). A `fail` on the `focus-indicator` check
181
+ stops the build, as it would for the executor.
177
182
 
178
183
  Checkpoint after each component: show all variants, confirm before the next.
179
184
 
@@ -400,9 +405,9 @@ Offer next steps: build the code counterparts and stories
400
405
  auto-layout grid where **variants are rows and states are columns**: one row per
401
406
  variant (each `type`, and each `size`, since size is a variant) stepping through
402
407
  states across the columns, size groups stacked vertically (see the standards doc).
403
- - Never ship a component with only its `default` state — include the full relevant
404
- state set (default/hover/focus/active/disabled plus applicable
405
- loading/selected/success/error).
408
+ - Never ship a component with only its `default` state — include every state
409
+ `.throughline/references/state-baseline.md` owes that component, plus
410
+ `default`, plus any applicable loading/success/error.
406
411
  - Never run the component header and the component area together with no division —
407
412
  every doc card segments the header from the component area with a divider line or
408
413
  a distinct header surface.
@@ -140,7 +140,10 @@ fit in the adapter output.
140
140
 
141
141
  ## Step 3 — Set up Style Dictionary + adapters
142
142
 
143
- Install and configure Style Dictionary v4 in `packages/tokens/`. For each chosen
143
+ Install Style Dictionary pinned to an exact version with
144
+ `pnpm add -D style-dictionary@4.4.0` (or the project's package manager) in
145
+ `packages/tokens/`; the generated config is verified against 4.4.0, and a newer
146
+ release can rename or add stock transforms. Then configure it. For each chosen
144
147
  platform, apply its adapter preset (per `.throughline/references/sync-adapters.md`):
145
148
  register the platform, transform group, format, and `outputReferences`
146
149
  (true for web → preserves the semantic→primitive cascade; false for native →
@@ -71,8 +71,9 @@ inconsistent output:
71
71
  - **Sizes** (sm, md, lg). Each size is its **own variant row**, not a state — see
72
72
  the layout law below.
73
73
  - **States** — **include the full relevant set, don't trim it.** The baseline is
74
- default, hover, focus, active (pressed), disabled; add the conditional states
75
- wherever they apply (loading, selected, success/error). Decide which conditional
74
+ the set `.throughline/references/state-baseline.md` owes that component
75
+ (default included); add the conditional states wherever they apply (loading,
76
+ success/error). Decide which conditional
76
77
  states a given component can reach, but never drop a state it genuinely has. See
77
78
  "State handling" in `.throughline/references/figma-component-standards.md`
78
79
  for the per-component checklist.
@@ -176,8 +177,12 @@ deterministic naming):
176
177
  re-screenshot) **and its "Post-build audit (REQUIRED before handoff)"
177
178
  read-back checklist** (container type, auto layout, bound variables,
178
179
  deterministic names) before the checkpoint. When you build inline, with no
179
- `figma-executor`, that includes item 9's `focus-indicator` check: a miss stops
180
- the build, as it would for the executor.
180
+ `figma-executor`, run `.throughline/references/figma-checks.md` the
181
+ way the executor does: `'spec'` mode before the first write and `'built'` mode
182
+ in the self-verify loop, with `EXPECT` built from your own matrix. You are the
183
+ architect here, so you name `controlLayer` yourself for a wrapped control (an
184
+ Input with a label or helper text). A `fail` on the `focus-indicator` check
185
+ stops the build, as it would for the executor.
181
186
 
182
187
  Checkpoint after each component: show all variants, confirm before the next.
183
188
 
@@ -404,9 +409,9 @@ Offer next steps: build the code counterparts and stories
404
409
  auto-layout grid where **variants are rows and states are columns**: one row per
405
410
  variant (each `type`, and each `size`, since size is a variant) stepping through
406
411
  states across the columns, size groups stacked vertically (see the standards doc).
407
- - Never ship a component with only its `default` state — include the full relevant
408
- state set (default/hover/focus/active/disabled plus applicable
409
- loading/selected/success/error).
412
+ - Never ship a component with only its `default` state — include every state
413
+ `.throughline/references/state-baseline.md` owes that component, plus
414
+ `default`, plus any applicable loading/success/error.
410
415
  - Never run the component header and the component area together with no division —
411
416
  every doc card segments the header from the component area with a divider line or
412
417
  a distinct header surface.
@@ -144,7 +144,10 @@ fit in the adapter output.
144
144
 
145
145
  ## Step 3 — Set up Style Dictionary + adapters
146
146
 
147
- Install and configure Style Dictionary v4 in `packages/tokens/`. For each chosen
147
+ Install Style Dictionary pinned to an exact version with
148
+ `pnpm add -D style-dictionary@4.4.0` (or the project's package manager) in
149
+ `packages/tokens/`; the generated config is verified against 4.4.0, and a newer
150
+ release can rename or add stock transforms. Then configure it. For each chosen
148
151
  platform, apply its adapter preset (per `.throughline/references/sync-adapters.md`):
149
152
  register the platform, transform group, format, and `outputReferences`
150
153
  (true for web → preserves the semantic→primitive cascade; false for native →
@@ -67,8 +67,9 @@ inconsistent output:
67
67
  - **Sizes** (sm, md, lg). Each size is its **own variant row**, not a state — see
68
68
  the layout law below.
69
69
  - **States** — **include the full relevant set, don't trim it.** The baseline is
70
- default, hover, focus, active (pressed), disabled; add the conditional states
71
- wherever they apply (loading, selected, success/error). Decide which conditional
70
+ the set `.throughline/references/state-baseline.md` owes that component
71
+ (default included); add the conditional states wherever they apply (loading,
72
+ success/error). Decide which conditional
72
73
  states a given component can reach, but never drop a state it genuinely has. See
73
74
  "State handling" in `.throughline/references/figma-component-standards.md`
74
75
  for the per-component checklist.
@@ -172,8 +173,12 @@ deterministic naming):
172
173
  re-screenshot) **and its "Post-build audit (REQUIRED before handoff)"
173
174
  read-back checklist** (container type, auto layout, bound variables,
174
175
  deterministic names) before the checkpoint. When you build inline, with no
175
- `figma-executor`, that includes item 9's `focus-indicator` check: a miss stops
176
- the build, as it would for the executor.
176
+ `figma-executor`, run `.throughline/references/figma-checks.md` the
177
+ way the executor does: `'spec'` mode before the first write and `'built'` mode
178
+ in the self-verify loop, with `EXPECT` built from your own matrix. You are the
179
+ architect here, so you name `controlLayer` yourself for a wrapped control (an
180
+ Input with a label or helper text). A `fail` on the `focus-indicator` check
181
+ stops the build, as it would for the executor.
177
182
 
178
183
  Checkpoint after each component: show all variants, confirm before the next.
179
184
 
@@ -400,9 +405,9 @@ Offer next steps: build the code counterparts and stories
400
405
  auto-layout grid where **variants are rows and states are columns**: one row per
401
406
  variant (each `type`, and each `size`, since size is a variant) stepping through
402
407
  states across the columns, size groups stacked vertically (see the standards doc).
403
- - Never ship a component with only its `default` state — include the full relevant
404
- state set (default/hover/focus/active/disabled plus applicable
405
- loading/selected/success/error).
408
+ - Never ship a component with only its `default` state — include every state
409
+ `.throughline/references/state-baseline.md` owes that component, plus
410
+ `default`, plus any applicable loading/success/error.
406
411
  - Never run the component header and the component area together with no division —
407
412
  every doc card segments the header from the component area with a divider line or
408
413
  a distinct header surface.
@@ -140,7 +140,10 @@ fit in the adapter output.
140
140
 
141
141
  ## Step 3 — Set up Style Dictionary + adapters
142
142
 
143
- Install and configure Style Dictionary v4 in `packages/tokens/`. For each chosen
143
+ Install Style Dictionary pinned to an exact version with
144
+ `pnpm add -D style-dictionary@4.4.0` (or the project's package manager) in
145
+ `packages/tokens/`; the generated config is verified against 4.4.0, and a newer
146
+ release can rename or add stock transforms. Then configure it. For each chosen
144
147
  platform, apply its adapter preset (per `.throughline/references/sync-adapters.md`):
145
148
  register the platform, transform group, format, and `outputReferences`
146
149
  (true for web → preserves the semantic→primitive cascade; false for native →
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@radicool/throughline",
3
- "version": "0.21.4",
3
+ "version": "0.23.0",
4
4
  "description": "Build a complete design system end to end — author in Figma, sync tokens to code, generate Storybook. Usable from Claude Code, Cursor, Codex, or any AGENTS.md agent.",
5
5
  "type": "module",
6
6
  "bin": {