@radicool/throughline 0.22.0 → 0.24.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 (52) hide show
  1. package/README.md +5 -5
  2. package/adapters/codex/prompts/component-builder.md +12 -4
  3. package/adapters/cursor/.cursor/rules/component-builder.mdc +12 -4
  4. package/adapters/generic/skills/component-builder/SKILL.md +12 -4
  5. package/package.json +1 -1
  6. package/references/figma-checks.md +813 -0
  7. package/references/figma-component-standards.md +16 -38
  8. package/references/figma-scripting.md +6 -6
  9. package/references/proof-bundle.md +1 -0
  10. package/references/state-baseline.md +5 -3
  11. package/scripts/README.md +5 -2
  12. package/scripts/build-figma-checks.mjs +111 -0
  13. package/scripts/build-state-baseline.mjs +5 -3
  14. package/scripts/install.mjs +9 -4
  15. package/scripts/lib/component-states.mjs +4 -1
  16. package/scripts/lib/contrast.mjs +5 -2
  17. package/scripts/lib/figma-checks-read.figma.js +174 -0
  18. package/scripts/lib/figma-checks.mjs +385 -0
  19. package/scripts/lib/fixtures/figma-checks/avatar-not-in-table.json +44 -0
  20. package/scripts/lib/fixtures/figma-checks/button-ios-swift-skipped.json +86 -0
  21. package/scripts/lib/fixtures/figma-checks/button-missing-default.json +72 -0
  22. package/scripts/lib/fixtures/figma-checks/button-mui-ring.json +93 -0
  23. package/scripts/lib/fixtures/figma-checks/button-no-focus-variant.json +72 -0
  24. package/scripts/lib/fixtures/figma-checks/button-plain-frames.json +93 -0
  25. package/scripts/lib/fixtures/figma-checks/button-ring-child-not-absolute.json +95 -0
  26. package/scripts/lib/fixtures/figma-checks/button-ring-hidden.json +93 -0
  27. package/scripts/lib/fixtures/figma-checks/button-ring-unbound-colour.json +99 -0
  28. package/scripts/lib/fixtures/figma-checks/button-shadcn-filled.json +93 -0
  29. package/scripts/lib/fixtures/figma-checks/button-sparse.json +135 -0
  30. package/scripts/lib/fixtures/figma-checks/button-spread-zero.json +93 -0
  31. package/scripts/lib/fixtures/figma-checks/button-transparent-ring-child.json +95 -0
  32. package/scripts/lib/fixtures/figma-checks/button-vanilla-inside.json +88 -0
  33. package/scripts/lib/fixtures/figma-checks/button-vanilla-outside.json +88 -0
  34. package/scripts/lib/fixtures/figma-checks/button-wrong-combination.json +93 -0
  35. package/scripts/lib/fixtures/figma-checks/checkbox-checked-axis.real.json +246 -0
  36. package/scripts/lib/fixtures/figma-checks/checkbox-checked-synonym.json +88 -0
  37. package/scripts/lib/fixtures/figma-checks/checkbox-missing-selected.json +80 -0
  38. package/scripts/lib/fixtures/figma-checks/indicator-failed.json +106 -0
  39. package/scripts/lib/fixtures/figma-checks/input-control-layer-missing.json +67 -0
  40. package/scripts/lib/fixtures/figma-checks/input-control-layer-ring-on-wrapper.json +80 -0
  41. package/scripts/lib/fixtures/figma-checks/input-control-layer.json +80 -0
  42. package/scripts/lib/fixtures/figma-checks/input-mui-weight-unbound.json +67 -0
  43. package/scripts/lib/fixtures/figma-checks/input-mui.json +67 -0
  44. package/scripts/lib/fixtures/figma-checks/ring-single-mode.json +112 -0
  45. package/scripts/lib/fixtures/figma-checks/ring-translucent.json +111 -0
  46. package/scripts/lib/fixtures/figma-checks/sample-button.real.json +1498 -0
  47. package/scripts/lib/fixtures/figma-checks/sample-ring-on-muted-raw.json +113 -0
  48. package/scripts/lib/fixtures/figma-checks/sample-ring-passes.json +169 -0
  49. package/scripts/lib/fixtures/figma-checks/surface-missing.json +108 -0
  50. package/scripts/lib/fixtures/figma-checks/surface-single-mode.json +112 -0
  51. package/scripts/lib/fixtures/figma-checks/surface-translucent.json +112 -0
  52. package/scripts/lib/fixtures/figma-checks/zygarden-ring-light-fails.json +113 -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.22.0 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.24.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.22.0 init --target=cursor # → .cursor/rules + .cursor/mcp.json
118
- npx @radicool/throughline@0.22.0 init --target=codex # → prompts/ + AGENTS.md index + codex-mcp.toml
119
- npx @radicool/throughline@0.22.0 init --target=generic # → skills/ + AGENTS.md index
117
+ npx @radicool/throughline@0.24.0 init --target=cursor # → .cursor/rules + .cursor/mcp.json
118
+ npx @radicool/throughline@0.24.0 init --target=codex # → prompts/ + AGENTS.md index + codex-mcp.toml
119
+ npx @radicool/throughline@0.24.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.
@@ -212,7 +212,7 @@ Future improvements and planned capabilities. Have a request? **[Open an issue](
212
212
  - **Deeper Code Connect coverage** — richer Figma-to-code mappings as more plans support it.
213
213
  - **Expanded component starters** — a larger foundational kit out of the box.
214
214
  - **Richer status & auditing** — more from `/design-system-status`, including drift detection between Figma and code.
215
- - **Built-in accessibility checks** — the color half is shipped. Eight semantic text-on-surface pairs are checked against WCAG AA's 4.5:1 when tokens are created in Figma, and derived again from the token source when they sync to code — in every mode, so a system that clears in light and fails in dark fails. A failing pair stops the build rather than warning. Components are checked too: on web frameworks, a Figma build stops when a focus state has no visible ring, and in JSX code the adherence gate is built to fail an icon-only button with no accessible name and a status badge that relies on color alone — proven by unit tests. The one real app it has run on had almost nothing for it to check, so it hasn't caught a bug in the wild yet. Still ahead: focus-ring contrast (WCAG's 3:1 for non-text).
215
+ - **Built-in accessibility checks** — the color half is shipped. Eight semantic text-on-surface pairs are checked against WCAG AA's 4.5:1 when tokens are created in Figma, and derived again from the token source when they sync to code — in every mode, so a system that clears in light and fails in dark fails. A failing pair stops the build rather than warning. Components are checked too: on web frameworks, a Figma build stops when a focus state has no visible ring, and in JSX code the adherence gate is built to fail an icon-only button with no accessible name and a status badge that relies on color alone — proven by unit tests. A Figma build also stops when a focus ring falls below WCAG's 3:1 against a surface the architect names for it, in any mode. The one real app it has run on had almost nothing for it to check, so it hasn't caught a bug in the wild yet.
216
216
  - **Token fan-out to more platforms** — the DTCG token source is platform-neutral, and web targets are in daily use. Every target is **validated per build, not assumed**: `tokens:validate-output` checks generated output against its source, native Swift and Kotlin as well as web CSS, because the stock transforms have been measured emitting wrong-but-compiling values. iOS/Swift is a curated adapter whose Style Dictionary configuration ships as tested code, and Android/Kotlin uses the same configuration through the Tier 2 protocol. JavaScript theme output (MUI, a Tailwind v3 config) isn't checked yet.
217
217
  - **Native component code generation** — producing a SwiftUI view or a Compose composable the way Storybook components are produced for React. This does not exist yet; it is a separate, larger effort than token fan-out, and the two were previously described as one roadmap item.
218
218
 
@@ -173,8 +173,16 @@ deterministic naming):
173
173
  re-screenshot) **and its "Post-build audit (REQUIRED before handoff)"
174
174
  read-back checklist** (container type, auto layout, bound variables,
175
175
  deterministic names) before the checkpoint. When you build inline, with no
176
- `figma-executor`, that includes item 9's `focus-indicator` check: a miss stops
177
- 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), and `surfaces` yourself: the colour-variable
181
+ names of the page surfaces the component sits on. A `fail` on the
182
+ `focus-indicator` check stops the build, as it would for the executor. A `fail`
183
+ on `focus-contrast` stops it too, naming its detail. A ring below 3:1 is fixed by
184
+ a token value, so don't change a variable or swap the ring to another one to make
185
+ it pass; a surface the file doesn't have is a wrong name in `surfaces`.
178
186
 
179
187
  Checkpoint after each component: show all variants, confirm before the next.
180
188
 
@@ -362,8 +370,8 @@ any component built with the toggle + manual-swap fallback is listed in
362
370
  component-builder --subject <Name> --entry <tmp>.json`. Build `<tmp>.json` with
363
371
  `at` (an ISO timestamp you supply), `changed` (what was built), the attested checks `structural-read-back`,
364
372
  `state-baseline` and `figma-name` from what the `figma-executor` returned (or
365
- what your inline read-back found), `focus-indicator` when that check ran and
366
- passed (not when it was skipped),
373
+ what your inline read-back found), `focus-indicator` and `focus-contrast`
374
+ each when that check ran and passed (not when it was skipped),
367
375
  `review` when a reviewer ran, `screenshot` when one was captured, and
368
376
  `advancedBecause`. The entry shape is
369
377
  `.throughline/references/proof-bundle.md` — don't restate it here. Write
@@ -177,8 +177,16 @@ deterministic naming):
177
177
  re-screenshot) **and its "Post-build audit (REQUIRED before handoff)"
178
178
  read-back checklist** (container type, auto layout, bound variables,
179
179
  deterministic names) before the checkpoint. When you build inline, with no
180
- `figma-executor`, that includes item 9's `focus-indicator` check: a miss stops
181
- 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), and `surfaces` yourself: the colour-variable
185
+ names of the page surfaces the component sits on. A `fail` on the
186
+ `focus-indicator` check stops the build, as it would for the executor. A `fail`
187
+ on `focus-contrast` stops it too, naming its detail. A ring below 3:1 is fixed by
188
+ a token value, so don't change a variable or swap the ring to another one to make
189
+ it pass; a surface the file doesn't have is a wrong name in `surfaces`.
182
190
 
183
191
  Checkpoint after each component: show all variants, confirm before the next.
184
192
 
@@ -366,8 +374,8 @@ any component built with the toggle + manual-swap fallback is listed in
366
374
  component-builder --subject <Name> --entry <tmp>.json`. Build `<tmp>.json` with
367
375
  `at` (an ISO timestamp you supply), `changed` (what was built), the attested checks `structural-read-back`,
368
376
  `state-baseline` and `figma-name` from what the `figma-executor` returned (or
369
- what your inline read-back found), `focus-indicator` when that check ran and
370
- passed (not when it was skipped),
377
+ what your inline read-back found), `focus-indicator` and `focus-contrast`
378
+ each when that check ran and passed (not when it was skipped),
371
379
  `review` when a reviewer ran, `screenshot` when one was captured, and
372
380
  `advancedBecause`. The entry shape is
373
381
  `.throughline/references/proof-bundle.md` — don't restate it here. Write
@@ -173,8 +173,16 @@ deterministic naming):
173
173
  re-screenshot) **and its "Post-build audit (REQUIRED before handoff)"
174
174
  read-back checklist** (container type, auto layout, bound variables,
175
175
  deterministic names) before the checkpoint. When you build inline, with no
176
- `figma-executor`, that includes item 9's `focus-indicator` check: a miss stops
177
- 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), and `surfaces` yourself: the colour-variable
181
+ names of the page surfaces the component sits on. A `fail` on the
182
+ `focus-indicator` check stops the build, as it would for the executor. A `fail`
183
+ on `focus-contrast` stops it too, naming its detail. A ring below 3:1 is fixed by
184
+ a token value, so don't change a variable or swap the ring to another one to make
185
+ it pass; a surface the file doesn't have is a wrong name in `surfaces`.
178
186
 
179
187
  Checkpoint after each component: show all variants, confirm before the next.
180
188
 
@@ -362,8 +370,8 @@ any component built with the toggle + manual-swap fallback is listed in
362
370
  component-builder --subject <Name> --entry <tmp>.json`. Build `<tmp>.json` with
363
371
  `at` (an ISO timestamp you supply), `changed` (what was built), the attested checks `structural-read-back`,
364
372
  `state-baseline` and `figma-name` from what the `figma-executor` returned (or
365
- what your inline read-back found), `focus-indicator` when that check ran and
366
- passed (not when it was skipped),
373
+ what your inline read-back found), `focus-indicator` and `focus-contrast`
374
+ each when that check ran and passed (not when it was skipped),
367
375
  `review` when a reviewer ran, `screenshot` when one was captured, and
368
376
  `advancedBecause`. The entry shape is
369
377
  `.throughline/references/proof-bundle.md` — don't restate it here. Write
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@radicool/throughline",
3
- "version": "0.22.0",
3
+ "version": "0.24.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": {