@motion-proto/live-tokens 0.73.0 → 0.75.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 (196) hide show
  1. package/.claude/skills/live-tokens-check-compliance/SKILL.md +33 -38
  2. package/.claude/skills/live-tokens-create-component/SKILL copy.md +196 -0
  3. package/.claude/skills/live-tokens-create-component/SKILL.md +198 -146
  4. package/.claude/skills/live-tokens-create-component/references/contract-tests.md +95 -52
  5. package/.claude/skills/live-tokens-create-component/references/intrinsics.md +2 -2
  6. package/.claude/skills/live-tokens-create-component/references/linked-siblings.md +2 -2
  7. package/.claude/skills/live-tokens-create-component/references/sketch-mode.md +12 -12
  8. package/.claude/skills/live-tokens-create-component/references/token-naming.md +2 -1
  9. package/.claude/skills/live-tokens-create-page/SKILL.md +187 -0
  10. package/.claude/skills/live-tokens-create-page/references/interaction-sources.md +66 -0
  11. package/.claude/skills/live-tokens-create-page/references/layout-sources.md +87 -0
  12. package/.claude/skills/live-tokens-create-theme/SKILL.md +84 -0
  13. package/.claude/skills/live-tokens-create-theme/references/design-directions.md +94 -0
  14. package/.claude/skills/live-tokens-fix-findings/SKILL.md +69 -60
  15. package/.claude/skills/live-tokens-pick-component/SKILL.md +64 -79
  16. package/.claude/skills/live-tokens-set-colors/SKILL.md +149 -0
  17. package/.claude/skills/live-tokens-set-colors/references/color-anchors.md +80 -0
  18. package/.claude/skills/live-tokens-set-geometry/SKILL.md +121 -0
  19. package/.claude/skills/live-tokens-set-geometry/references/geometry-anchors.md +63 -0
  20. package/.claude/skills/live-tokens-set-type/SKILL.md +93 -0
  21. package/.claude/skills/live-tokens-set-type/references/type-anchors.md +60 -0
  22. package/CHANGELOG.md +194 -0
  23. package/README.md +27 -18
  24. package/bin/check-component.mjs +91 -19
  25. package/bin/check-page.mjs +105 -24
  26. package/bin/cli.mjs +154 -97
  27. package/bin/contractRunner.mjs +945 -0
  28. package/bin/create.mjs +1 -1
  29. package/bin/lib/catalogue.mjs +37 -30
  30. package/bin/lib/findings.mjs +46 -15
  31. package/bin/lib/liveState.mjs +110 -0
  32. package/bin/lib/report.mjs +3 -3
  33. package/bin/lib/tokenVocabulary.mjs +4 -4
  34. package/bin/migrate-routes.mjs +5 -5
  35. package/bin/migrate.mjs +4 -4
  36. package/bin/save-theme.mjs +176 -0
  37. package/bin/set-colors.mjs +189 -0
  38. package/bin/{adjust.mjs → set-geometry.mjs} +25 -57
  39. package/bin/{set-fonts.mjs → set-type.mjs} +26 -62
  40. package/dist-plugin/{chunk-W6Y4BWFB.js → chunk-6WGFOJXO.js} +22 -0
  41. package/dist-plugin/{chunk-RIXO2E55.js → chunk-PDNL4NC5.js} +9 -2
  42. package/dist-plugin/{chunk-YLCOIGQC.js → chunk-SWXRVZKT.js} +98 -2
  43. package/dist-plugin/{dataPaths-BhWzd5cL.d.ts → dataPaths-BpIK_Obx.d.cts} +1 -0
  44. package/dist-plugin/{dataPaths-BhWzd5cL.d.cts → dataPaths-BpIK_Obx.d.ts} +1 -0
  45. package/dist-plugin/index.cjs +366 -148
  46. package/dist-plugin/index.d.cts +1 -1
  47. package/dist-plugin/index.d.ts +1 -1
  48. package/dist-plugin/index.js +226 -130
  49. package/dist-plugin/migrateData/index.cjs +121 -2
  50. package/dist-plugin/migrateData/index.d.cts +1 -1
  51. package/dist-plugin/migrateData/index.d.ts +1 -1
  52. package/dist-plugin/migrateData/index.js +3 -3
  53. package/dist-plugin/{generateColorsAndType → setColors}/index.cjs +594 -499
  54. package/dist-plugin/{generateColorsAndType → setColors}/index.d.cts +34 -25
  55. package/dist-plugin/{generateColorsAndType → setColors}/index.d.ts +34 -25
  56. package/dist-plugin/{generateColorsAndType → setColors}/index.js +48 -66
  57. package/dist-plugin/{adjust → setGeometry}/index.cjs +166 -48
  58. package/dist-plugin/{adjust → setGeometry}/index.d.cts +6 -6
  59. package/dist-plugin/{adjust → setGeometry}/index.d.ts +6 -6
  60. package/dist-plugin/{adjust → setGeometry}/index.js +51 -45
  61. package/dist-plugin/{fontPairing → setType}/index.cjs +19 -4
  62. package/dist-plugin/{fontPairing → setType}/index.d.cts +2 -2
  63. package/dist-plugin/{fontPairing → setType}/index.d.ts +2 -2
  64. package/dist-plugin/{fontPairing → setType}/index.js +1 -1
  65. package/dist-plugin/{themeTypes-DSV3Zisf.d.cts → themeTypes-BxRtuN5V.d.cts} +1 -1
  66. package/dist-plugin/{themeTypes-DSV3Zisf.d.ts → themeTypes-BxRtuN5V.d.ts} +1 -1
  67. package/dist-plugin/tokensCssMigrations/index.d.cts +1 -1
  68. package/dist-plugin/tokensCssMigrations/index.d.ts +1 -1
  69. package/dist-plugin/tokensCssMigrations/index.js +1 -1
  70. package/package.json +36 -8
  71. package/src/app/site.css +19 -9
  72. package/src/editor/bootstrap.ts +2 -0
  73. package/src/editor/component-editor/CollapsibleSectionEditor.svelte +4 -4
  74. package/src/editor/component-editor/DialogEditor.svelte +4 -4
  75. package/src/editor/component-editor/MenuSelectEditor.svelte +4 -1
  76. package/src/editor/component-editor/SegmentedControlEditor.svelte +6 -1
  77. package/src/editor/component-editor/TabBarEditor.svelte +1 -1
  78. package/src/editor/component-editor/TableEditor.svelte +2 -2
  79. package/src/editor/component-editor/scaffolding/TokenLayout.svelte +6 -3
  80. package/src/editor/component-editor/scaffolding/VariantGroup.svelte +41 -20
  81. package/src/editor/core/components/adjustAliases.ts +59 -45
  82. package/src/editor/core/components/aliasKinds.ts +9 -5
  83. package/src/editor/core/preview/themePreview.ts +9 -2
  84. package/src/editor/core/sketch/sketchLayer.ts +22 -0
  85. package/src/editor/core/store/editorStore.ts +10 -1
  86. package/src/editor/core/themes/{generateColorsAndType.ts → buildColors.ts} +84 -98
  87. package/src/editor/core/themes/liveStateStream.ts +26 -0
  88. package/src/editor/core/themes/migrations/2026-09-03-drop-legacy-component-keys.ts +62 -0
  89. package/src/editor/core/themes/migrations/2026-09-07-stroke-role-renames.ts +52 -0
  90. package/src/editor/core/themes/migrations/index.ts +4 -0
  91. package/src/editor/core/themes/themeDocumentSync.ts +22 -11
  92. package/src/editor/core/themes/themeService.ts +9 -2
  93. package/src/editor/docs/content/themes-workflow.md +2 -2
  94. package/src/editor/docs/content.generated.ts +1 -1
  95. package/src/editor/overlay/LiveEditorOverlay.svelte +519 -28
  96. package/src/editor/pages/ComponentEditorPage.svelte +17 -1
  97. package/src/editor/pages/liveTokensEditorHandle.ts +23 -0
  98. package/src/editor/skill-atlas/SkillAtlas.svelte +76 -574
  99. package/src/editor/skill-atlas/TreeCanvas.svelte +263 -0
  100. package/src/editor/skill-atlas/TreeNodeCard.svelte +136 -53
  101. package/src/editor/skill-atlas/edges.ts +31 -0
  102. package/src/editor/skill-atlas/skillSources.generated.ts +29 -24
  103. package/src/editor/skill-atlas/skillTrees.ts +19 -3687
  104. package/src/editor/skill-atlas/trees/check-compliance.ts +183 -0
  105. package/src/editor/skill-atlas/trees/create-component.ts +275 -0
  106. package/src/editor/skill-atlas/trees/create-page.ts +320 -0
  107. package/src/editor/skill-atlas/trees/create-theme.ts +255 -0
  108. package/src/editor/skill-atlas/trees/fix-findings.ts +469 -0
  109. package/src/editor/skill-atlas/trees/pick-component.ts +300 -0
  110. package/src/editor/skill-atlas/trees/set-colors.ts +148 -0
  111. package/src/editor/skill-atlas/trees/set-geometry.ts +136 -0
  112. package/src/editor/skill-atlas/trees/set-type.ts +142 -0
  113. package/src/editor/skill-atlas/types.ts +3 -4
  114. package/src/editor/skill-atlas/wireLayout.ts +287 -0
  115. package/src/live-tokens/data/colors-and-type/autumn.json +1 -37
  116. package/src/live-tokens/data/colors-and-type/default.json +1 -37
  117. package/src/live-tokens/data/colors-and-type/halloween.json +1 -37
  118. package/src/live-tokens/data/colors-and-type/midnight-study.json +1 -37
  119. package/src/live-tokens/data/colors-and-type/ocean.json +1 -37
  120. package/src/live-tokens/data/colors-and-type/royal-velvet.json +1 -37
  121. package/src/live-tokens/data/colors-and-type/sketchy.json +1 -37
  122. package/src/live-tokens/data/colors-and-type/spring-meadow.json +1 -37
  123. package/src/live-tokens/data/colors-and-type/sunset.json +1 -37
  124. package/src/live-tokens/data/themes/autumn.json +16 -52
  125. package/src/live-tokens/data/themes/halloween.json +16 -52
  126. package/src/live-tokens/data/themes/midnight-study.json +16 -52
  127. package/src/live-tokens/data/themes/ocean.json +16 -52
  128. package/src/live-tokens/data/themes/royal-velvet.json +16 -52
  129. package/src/live-tokens/data/themes/sketchy.json +16 -52
  130. package/src/live-tokens/data/themes/spring-meadow.json +16 -52
  131. package/src/live-tokens/data/themes/sunset.json +16 -52
  132. package/src/live-tokens/data/tokens.generated.css +0 -36
  133. package/src/system/components/Badge.svelte +7 -0
  134. package/src/system/components/Button.svelte +7 -0
  135. package/src/system/components/Callout.svelte +10 -6
  136. package/src/system/components/Card.svelte +23 -4
  137. package/src/system/components/CodeSnippet.svelte +4 -3
  138. package/src/system/components/CollapsibleSection.svelte +23 -8
  139. package/src/system/components/CornerBadge.svelte +6 -0
  140. package/src/system/components/Dialog.svelte +13 -6
  141. package/src/system/components/IconButton.svelte +9 -0
  142. package/src/system/components/Image.svelte +8 -0
  143. package/src/system/components/ImageLightbox.svelte +6 -0
  144. package/src/system/components/InlineEditActions.svelte +7 -0
  145. package/src/system/components/Input.svelte +7 -0
  146. package/src/system/components/MenuSelect.svelte +7 -0
  147. package/src/system/components/Notification.svelte +7 -0
  148. package/src/system/components/Panel.svelte +6 -0
  149. package/src/system/components/ProgressBar.svelte +5 -0
  150. package/src/system/components/RadioButton.svelte +11 -5
  151. package/src/system/components/SectionDivider.svelte +8 -0
  152. package/src/system/components/SegmentedControl.svelte +6 -0
  153. package/src/system/components/SideNavigation.svelte +6 -0
  154. package/src/system/components/Slider.svelte +7 -4
  155. package/src/system/components/TabBar.svelte +15 -9
  156. package/src/system/components/Table.svelte +8 -3
  157. package/src/system/components/Toggle.svelte +4 -4
  158. package/src/system/components/Tooltip.svelte +6 -0
  159. package/src/testing-js/chunk-AO7EZHYV.js +776 -0
  160. package/src/testing-js/chunk-AO7EZHYV.js.map +1 -0
  161. package/src/testing-js/chunk-FAFOAWYL.js +39 -0
  162. package/src/testing-js/chunk-FAFOAWYL.js.map +1 -0
  163. package/src/testing-js/chunk-L73N4NSO.js +23 -0
  164. package/src/testing-js/chunk-L73N4NSO.js.map +1 -0
  165. package/src/testing-js/chunk-LXR3MN6N.js +3063 -0
  166. package/src/testing-js/chunk-LXR3MN6N.js.map +1 -0
  167. package/src/testing-js/chunk-ZMSX6CXR.js +53 -0
  168. package/src/testing-js/chunk-ZMSX6CXR.js.map +1 -0
  169. package/src/testing-js/component-alias.contract.js +81 -0
  170. package/src/testing-js/component-alias.contract.js.map +1 -0
  171. package/src/testing-js/component-editor.contract.js +62 -0
  172. package/src/testing-js/component-editor.contract.js.map +1 -0
  173. package/src/testing-js/component-render.contract.js +568 -0
  174. package/src/testing-js/component-render.contract.js.map +1 -0
  175. package/src/testing-js/index.d.ts +293 -0
  176. package/src/testing-js/index.js +222 -0
  177. package/src/testing-js/index.js.map +1 -0
  178. package/src/testing-js/registry.contract.js +39 -0
  179. package/src/testing-js/registry.contract.js.map +1 -0
  180. package/src/testing-js/vitest-BE6uGF31.d.ts +73 -0
  181. package/src/testing-js/vitest.d.ts +3 -0
  182. package/src/testing-js/vitest.js +13 -0
  183. package/src/testing-js/vitest.js.map +1 -0
  184. package/template/README.md +13 -0
  185. package/template/_gitignore +2 -0
  186. package/template/package.json +2 -1
  187. package/template/src/pages/Home.svelte +4 -18
  188. package/.claude/skills/live-tokens-adjust-geometry/SKILL.md +0 -93
  189. package/.claude/skills/live-tokens-build-page/SKILL.md +0 -103
  190. package/.claude/skills/live-tokens-build-page/references/layout-sources.md +0 -48
  191. package/.claude/skills/live-tokens-generate-theme/SKILL.md +0 -156
  192. package/.claude/skills/live-tokens-generate-theme/references/mood-vocabulary.md +0 -43
  193. package/.claude/skills/live-tokens-generate-theme/references/named-themes.md +0 -18
  194. package/.claude/skills/live-tokens-generate-theme/references/style-vocabulary.md +0 -35
  195. package/.claude/skills/live-tokens-pair-fonts/SKILL.md +0 -90
  196. package/bin/generate-theme.mjs +0 -260
package/CHANGELOG.md CHANGED
@@ -1,5 +1,199 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.75.0 — A component passes when the tests pass
4
+
5
+ ### Added
6
+
7
+ - **`check-component` gains `--tests`.** Beyond the static lint, it runs the
8
+ registry contract under vitest and the component contract suites under
9
+ Playwright, for one component or every authored one, and reports coverage
10
+ by rule: listed, persisted and reset, themed, previewed, and drawn in
11
+ Sketch mode. `@playwright/test`, `vitest`, and `happy-dom` are new optional
12
+ peer dependencies; a missing one is a `tests-not-installed` finding naming
13
+ the install command. The suites ship at
14
+ `@motion-proto/live-tokens/testing` and `/testing/vitest`, and run here
15
+ against the library's own demo app and in a consumer against the
16
+ consumer's own app.
17
+
18
+ **live-tokens-create-component now runs `--tests` as its Verification
19
+ step**, in place of the manual pass through `/live-tokens/components`.
20
+ Every line that step asked a reader to confirm by eye is now a contract
21
+ assertion: the component's listing, its controls and preview, persistence
22
+ and reset, theme projection, linked properties, and Sketch mode.
23
+ live-tokens-fix-findings maps the new rule ids to the create-component
24
+ section that fixes each one, and the `create` template's new
25
+ `test:design` script runs the checks once the three peers are installed.
26
+
27
+ ### Changed
28
+
29
+ - **Breaking: `tokens --scale` replaces `tokens --family`, and there is no
30
+ alias.** A token scale is the progression of one token across its range,
31
+ such as `space` or `radius`, and it is the one term for that grouping in the
32
+ CLI, the skills, and the skill atlas. "Family" now means a typeface only.
33
+ The `--json` output names the grouping `scales`, each with a `scale` and its
34
+ `tokens`. `bin/cliStrings.test.ts` bans "token family" and `--family`.
35
+ - **Dividers and accents name their stroke role.** Three stroke roles share
36
+ the `--border-width-*` scale: a border encloses, a divider separates, an
37
+ accent emphasises. `set-geometry` moves each role on its own and reads the
38
+ role off the suffix, so a divider named `-border` moved with the borders.
39
+ TabBar's indicator is `--tabbar-<state>-indicator-width`, CollapsibleSection's
40
+ divider is `--collapsiblesection-divider-<state>-hairline-color` and
41
+ `-hairline-thickness`, Dialog's header and footer rules are
42
+ `--dialog-<part>-divider` and `-divider-width`, and Table's header rule is
43
+ `--table-default-header-divider` and `-divider-width`. Component migration 27
44
+ renames the keys in a saved theme; values are unchanged.
45
+ - **CLI output uses the skills' vocabulary.** Every verb's help and report
46
+ lines say "the buffer" for edits a theme file does not hold yet, "load" for
47
+ making a theme the open one, "design token" and "semantic property" for the
48
+ two token classes, "shipped default", and "scale" and "step". The three set
49
+ verbs close with "The buffer holds this edit. Run save-theme to keep it as a
50
+ theme." Report lines print "old to new" in place of an arrow, and
51
+ `set-geometry` labels a skip "raw value", "off the scale", or "at the end of
52
+ the scale". `bin/cliStrings.test.ts` holds the line. The skills are corrected
53
+ where they described the CLI wrongly; the audit is
54
+ `docs/plans/cli-skill-alignment.md`.
55
+ - **`live-tokens-build-page` is renamed `live-tokens-create-page`.** The verb
56
+ now matches `create-theme` and `create-component`. A project that copied the
57
+ skill keeps the old directory until it deletes it.
58
+ - **The `create` template matches the skill.** `Home.svelte` drops the `h1`
59
+ and `p` rules `site.css` already types, the `0.9em` code size, and a `1.6`
60
+ line-height; its two Buttons take `--space-8`. `site.css` sets all five
61
+ axes from one text style on `p`, list items, `code`, and `pre`, and `ol li`
62
+ reads `--body-md-line-height` in place of `1.6`. A project created before
63
+ this release keeps its copied `site.css`.
64
+
65
+ - **A page's type comes from a text style, and the checker fails a page that
66
+ names a raw axis.** `raw-text-axis` is an error, and it now reads a `var()`
67
+ as well as a literal. A `--font-size-*`, `--line-height-*`,
68
+ `--letter-spacing-*`, or a family stack such as `--font-sans` on a text
69
+ property is a finding. A text style token such as `--body-md-font-size` is
70
+ not. A `--font-weight-*` alone is not either, because a weight cannot move
71
+ the scale or the fonts. Two warnings join it. `control-size` reports a
72
+ `size` prop on a shipped component in a page file. `multiple-primary`
73
+ reports a second `variant="primary"` Button in one page file. A project
74
+ retunes a component's default size once, in the components editor. The
75
+ package's own pages, the template, and the `create` starter are all clean
76
+ under `--strict`. The starter's bulleted lists now take the `--body-md-*`
77
+ bundle.
78
+
79
+ **Every shipped component carries a usage comment.** `npx live-tokens
80
+ components` prints it as the description. `report` checks the shipped
81
+ set as it checks a custom component. The comment
82
+ names what the component is, what it is for, and what to reach for instead.
83
+ It never mentions size.
84
+
85
+ - **Callout owns its box; the page owns the space around it.** `.callout` no
86
+ longer sets `margin: var(--space-24) 0`. A stack of callouts now takes its
87
+ spacing from the page's own gap, and a page that wants the old rhythm sets
88
+ `margin-block` on the container. The four `--callout-*-accent-width` defaults
89
+ point at `--border-width-1`, so the left edge matches the other three sides,
90
+ and the default theme follows. The token stays, so a theme can set the thick
91
+ left rule back, and the seven other presets keep the accents they were
92
+ authored with.
93
+
94
+ - **A CLI run shows up in the open editor, and a Save afterwards keeps it.**
95
+ The dev server now watches the unsaved buffers and the active-theme pointer
96
+ and streams every outside change to the page as one frame over
97
+ `GET /api/live-tokens/events`. The editor hydrates from that frame the way
98
+ it does from an Apply, so `set-colors`, `set-type`, `set-geometry`, and
99
+ `save-theme` land on screen as they finish, and a Save afterwards writes
100
+ what is on screen rather than the tab's stale copy. The four verbs no longer
101
+ ask for a reload, and neither do the skills that run them. The server leaves
102
+ its own writes out of the stream, so an editor Save does not hydrate itself.
103
+ A branch switch that moves a buffer or the pointer reaches the page the same
104
+ way; any other JSON changed from outside still needs a reload.
105
+
106
+ ## 0.74.0 — A theme is three decisions and one document
107
+
108
+ ### Changed
109
+
110
+ - **Breaking: the three theme CLI verbs are renamed, and there is no alias.**
111
+ `generate-theme` is now `set-colors`, `set-fonts` is now `set-type`, and
112
+ `adjust-geometry` is now `set-geometry`. Each verb names the dimension it
113
+ sets, and each matches the skill that runs it. A script or note that types
114
+ an old verb fails with "Unknown command"; there is no deprecation path,
115
+ because nothing is released against these names yet. `set-type` and
116
+ `set-geometry` keep their flags, their file formats, and their behaviour, and
117
+ the geometry ops file is now written to `scratch/geometry-ops.json`.
118
+
119
+ **`set-colors` writes the color buffer, and `save-theme` writes the theme.**
120
+ A theme is three decisions and one document. Each set verb now writes only
121
+ its own dimension into the unsaved buffers the app already renders:
122
+ `set-colors` joins `set-type` and `set-geometry` there, and no longer writes
123
+ or opens a theme. The new `save-theme <name>` composes the live state into
124
+ `themes/<slug>.json` and opens it, and with no unsaved edits it saves a copy
125
+ of the open theme under the new name. `--no-activate` saves without opening,
126
+ which is how a set of themes comes off one starting look. `--carry-from` is
127
+ gone: it existed because `set-colors` activated, and nothing activates now
128
+ until you save. The base color file no longer carries `name`; a name in it
129
+ is ignored with a notice. `live-tokens-create-theme` runs `save-theme` once,
130
+ after its three contributing skills. `init`, an undocumented alias for
131
+ `create` since 0.21.0, is gone: type `create`.
132
+
133
+ **36 dead keys left the override bag.** Themes carried the color, type, and
134
+ border-width siblings of keys an earlier migration dropped (Badge's `trait`
135
+ variant, SectionDivider's title and description slots, Dialog's variant and
136
+ state axes). Nothing read them, and every Adopt baked them into
137
+ `tokens.generated.css`. A colors-and-type migration drops them from your
138
+ themes on the next Save, the nine shipped themes are rewritten, and
139
+ `check:preset-themes` now refuses any shipped theme, `default` included,
140
+ whose override bag names a variable `tokens.css` does not declare.
141
+
142
+ Internal: the engine bundles are `dist-plugin/setColors`, `setType`, and
143
+ `setGeometry`, named for the verbs that load them. They have no `exports`
144
+ entry and no consumer imports them.
145
+
146
+ - **A theme is one design direction routed to three contributing skills.**
147
+ `live-tokens-generate-theme` did two jobs: it read the request and fixed a
148
+ whole look, and it executed the color layer itself. So two of a theme's three
149
+ dimensions were skills and the third was a section. It is now
150
+ **live-tokens-create-theme**, which reads the request once, states one design
151
+ direction, states a color, a type, and a geometry intent, routes each to
152
+ **live-tokens-set-colors**, **live-tokens-set-type**, and
153
+ **live-tokens-set-geometry**, and assembles their three reports. Its one CLI
154
+ is `save-theme`. Every contributing skill still works when invoked directly
155
+ with an intent and no direction behind it. This changes four `description` triggers:
156
+ a whole look reaches create-theme, and a request naming one dimension goes
157
+ straight to that dimension's skill, including a color-only refinement like
158
+ "warmer".
159
+
160
+ - **The anchor tables split by dimension.** A row in the old mood and style
161
+ vocabularies fixed color, type, and geometry at once, which meant the
162
+ coordinator read color mechanics and handed on the other two. create-theme
163
+ now holds `references/design-directions.md`, an index placing each anchor on
164
+ the valence, energy, and dominance axes with its one-line direction; each
165
+ contributing skill holds the column it executes, keyed on the same names.
166
+ `check:skills` gains an anchor-key parity gate, so a name that reaches only
167
+ some of the four files fails at commit.
168
+
169
+ - **The theme skills call the user's own words the request, not the brief.**
170
+ "Brief" named two things at once: the user's words, and the seed JSON at
171
+ `scratch/<slug>-brief.json`. The second sense is fixed in two filenames and
172
+ in the CLI's own `<brief.json>` usage string, so the first sense moves.
173
+ Layer 0 of the pipeline in `docs/terminology.md` is now the request; the
174
+ files stay where they are and the prose calls them the seed file and the
175
+ pairing file. This changes one `description` trigger, in
176
+ `live-tokens-generate-theme`, from "from a natural-language brief" to "from
177
+ a natural-language request". set-fonts loses its one clash with the new
178
+ term: every family is a download rather than a request. The atlas tagline
179
+ named the wrong layer and now credits the design direction, the one sentence
180
+ three skills actually read.
181
+
182
+ - **A palette's base color is called that, not its seed.** The word already
183
+ meant something else in this product: sketch mode displaces its strokes on
184
+ random seeds, and says so in copy a user reads. The theme document has always
185
+ called the value `baseColor`, so the skill and the CLI were the drift. The
186
+ generator's input key is now `baseColors` rather than `seeds`, and the file
187
+ the skill writes is `scratch/<slug>-base-colors.json`; the pairing file
188
+ `set-fonts` reads is `scratch/font-pairing.json`. Both CLI verbs report
189
+ against the new names, so a contrast failure now says "raise the Brand base
190
+ color lightness". Internally `buildColorsAndTypeFromSeeds` becomes
191
+ `buildColorsAndType`, dropping a "from" clause that was never true on the
192
+ type half, and `ColorsAndTypeBrief` becomes `ColorsAndTypeInput`; neither is
193
+ a public export. A kept base color file with
194
+ the old `seeds` key needs that one key renamed, and the skill rewrites the
195
+ file from scratch on every run anyway.
196
+
3
197
  ## 0.73.0 — The skill atlas ships from the package
4
198
 
5
199
  ### Added
package/README.md CHANGED
@@ -324,20 +324,21 @@ npx @motion-proto/live-tokens <command>
324
324
  | `create <dir> [--force]` | Scaffold a new Svelte + Vite app wired up with live-tokens. |
325
325
  | `setup-claude [--force]` | Install the bundled Claude Code skills into `./.claude/skills/`. |
326
326
  | `components [id] [--json]` | List every component the project has, shipped and its own, with the props each takes; with an id, its props, variants, tokens, and defaults. |
327
- | `tokens [--family <name>] [--json]` | List every theme token the project's `tokens.css` declares, by family, with its value. |
327
+ | `tokens [--scale <name>] [--json]` | List every design token the project's `tokens.css` declares, by scale, with its value. |
328
328
  | `report [--json]` | The project as facts: pending migrations, tokens each component reads, which page renders which component, and both checkers' findings by rule. Always exits 0. |
329
329
  | `check-component [id]` | Validate a component's runtime, editor, and registration against the authoring contract; with no id, every component authored under `src/system/components`. |
330
- | `check-page [paths...]` | Validate pages against the build-page contract: catalogue components and their props, theme tokens over literals, route wiring. |
331
- | `generate-theme <brief.json> [--no-activate] [--dry-run] [--carry-from <name>]` | Build a full theme from a 10-seed OKLCH brief, enforce AA contrast, write `themes/<slug>.json`, and open it. |
332
- | `adjust <ops.json> [--dry-run]` | Move radius, padding, gap, and border-width aliases along their token scales. |
333
- | `set-fonts <brief.json> [--dry-run] [--no-verify]` | Bind Google Fonts families to the theme's font stacks, verified against the API. |
330
+ | `check-page [paths...]` | Validate pages against the create-page contract: catalogue components and their props, theme tokens over literals, route wiring. |
331
+ | `set-colors <base-colors.json> [--dry-run]` | Build the theme's whole color identity from 10 OKLCH base colors, enforce AA contrast on the derived text tokens, and write the result to the unsaved colors-and-type buffer. |
332
+ | `set-type <pairing.json> [--dry-run] [--no-verify]` | Bind Google Fonts families to the theme's font stacks, verified against the API. |
333
+ | `set-geometry <ops.json> [--dry-run]` | Move radius, padding, gap, and border-width aliases along their token scales. |
334
+ | `save-theme <name> [--no-activate] [--dry-run]` | Compose the live state into `themes/<slug>.json` and open it, which clears the unsaved buffers. |
334
335
  | `migrate [--check] [--write] [--tokens <path>]` | Reconcile the project with the installed package: additive `tokens.css` migrations, the pre-0.48 data-tree move, and a report on source references to the routes that moved in 0.35.0. |
335
336
 
336
337
  Once installed in a project, the same commands are available as `npx live-tokens <command>`.
337
338
 
338
339
  ## Claude Code skills
339
340
 
340
- The package bundles eight Claude Code skills. They encode the conventions this README cannot carry in full: which component fits a need, how a page is wired, what a valid theme looks like in OKLCH, how two typefaces sit together, how geometry moves along the token scales, how a project is checked against all of that, and how an existing page or component is brought back into line. Each triggers from an ordinary request, so there are no slash commands to learn.
341
+ The package bundles nine Claude Code skills. They encode the conventions this README cannot carry in full: which component fits a need, how a page is wired, how one request becomes a whole look, what a valid theme looks like in OKLCH, how two typefaces sit together, how geometry moves along the token scales, how a project is checked against all of that, and how an existing page or component is brought back into line. Each triggers from an ordinary request, so there are no slash commands to learn.
341
342
 
342
343
  ### Install
343
344
 
@@ -357,39 +358,47 @@ Ask "TabBar or SegmentedControl?", "how do I let someone pick one of four option
357
358
 
358
359
  The skill holds the catalogue grouped by job (action, input, selection, containers, messaging, display) and a decision table for each confusable family: `SegmentedControl` vs `TabBar` vs `RadioButton` vs `MenuSelect`, `Card` vs `CollapsibleSection` vs `Dialog`, `Callout` vs `Notification` vs `Tooltip` vs `Badge`, `Button` vs `IconButton`, and the on/off case. It answers the question and writes nothing. Read it before authoring anything new.
359
360
 
360
- ### `live-tokens-build-page`
361
+ ### `live-tokens-create-page`
361
362
 
362
363
  Ask for a page, a route, or a screen: "build a pricing page", "add a /settings route", "put a hero at the top of Home".
363
364
 
364
365
  The skill composes the page from shipped components, styles every value with `var(--token-*)` (no hex, no pixel literals, so editor changes repaint the page), places content on the column grid via `--columns-count`, `--columns-gutter`, and `--columns-max-width`, adds the route as a `lazy` import with a `source` so the overlay's "Page Source" button works, and imports `site.css` from the page rather than `main.ts` so page CSS stays out of the editor routes. It writes your page files and the route entry, and never touches the data tree.
365
366
 
366
- ### `live-tokens-generate-theme`
367
+ ### `live-tokens-create-theme`
367
368
 
368
- Ask for a look: "a dark, moody night theme", "a St Patrick's Day theme in green and gold", "warmer", "more contrast", "calmer".
369
+ Ask for a look: "a dark, moody night theme", "a St Patrick's Day theme in green and gold", "make it feel more serious".
369
370
 
370
- A theme is three decisions made from one brief: color, type, and geometry. The skill owns color and delegates the other two to `live-tokens-pair-fonts` and `live-tokens-adjust-geometry`, so the whole look comes from the same reading of the brief.
371
+ A theme is three decisions: color, type, and geometry. This skill reads the request once, states one design direction that fixes all three, and routes a color, a type, and a geometry intent to `live-tokens-set-colors`, `live-tokens-set-type`, and `live-tokens-set-geometry`. Each of them writes its dimension into the unsaved buffers the app already renders. The skill then runs `npx live-tokens save-theme "<name>"`, which turns those buffers into `themes/<slug>.json` and opens it, and assembles the three reports into one summary.
371
372
 
372
- For color it translates the brief into ten OKLCH seeds (Brand, Accent, Special, Canvas, Neutral, Alternate, Info, Success, Warning, Danger) plus a light or dark scheme, then runs `npx live-tokens generate-theme <brief.json>`. The CLI assembles the curves, enforces AA contrast on derived text tokens and auto-corrects where it can, writes `themes/<slug>.json`, opens it, and prints a contrast report. Exit 1 means the seeds themselves are unworkable, and each failure line names the seed to change.
373
+ It carries the anchor index: every feeling, idiom, era, genre, holiday, and season the skills know, placed on the valence, energy, and dominance axes with the direction each implies. An idiom sets constraints and a feeling moves dials inside them, so "cozy brutalist" reads the idiom first. Each contributing skill holds the mechanics for its own dimension, keyed on the same anchor names.
373
374
 
374
- Most of the skill is the judgment the generator cannot supply: a chroma budget scaled to how much screen area each palette covers, per-role lightness and hue bands for each scheme, gamut guardrails against impossible seeds, harmony modes, the optional canvas gradient, and a voice-to-shape table for the shape step. OKLCH anchors for named holidays and seasons live in a reference file the skill reads on demand.
375
+ A refinement that names one dimension goes straight to that sibling. This skill takes the ones that span dimensions.
375
376
 
376
- Color lands in the theme file; type and shape land in the unsaved buffers, and one Save keeps all three. `--dry-run` prints the report without writing; `--no-activate` writes without opening. Opening a theme never changes what your site ships; Adopt does. Regenerating replaces that theme's whole color state, including palette edits made in the editor since the last run, and carries the live buffers forward, so re-rolling color after setting fonts and shape keeps both.
377
+ ### `live-tokens-set-colors`
377
378
 
378
- ### `live-tokens-pair-fonts`
379
+ Ask for color: "a cooler palette", "warmer", "more contrast", "calmer", "make the ground darker".
380
+
381
+ The skill translates the color intent into ten OKLCH base colors (Brand, Accent, Special, Canvas, Neutral, Alternate, Info, Success, Warning, Danger) plus a light or dark scheme, then runs `npx live-tokens set-colors <base-colors.json>`. The CLI assembles the curves, enforces AA contrast on derived text tokens and auto-corrects where it can, writes the result to the unsaved colors-and-type buffer, and prints a contrast report. Exit 1 means the base colors themselves are unworkable, and each failure line names the base color to change.
382
+
383
+ Most of the skill is the judgment the generator cannot supply: a chroma budget scaled to how much screen area each palette covers, per-role lightness and hue bands for each scheme, three levels of canvas commitment, gamut guardrails against impossible base colors, harmony modes, and the optional canvas gradient. OKLCH anchors for every named feeling, idiom, and occasion live in a reference file the skill reads on demand.
384
+
385
+ Color is the one dimension every look fixes, so it runs first and never skips. `--dry-run` prints the report without writing. Saving the open theme in the editor, or running `save-theme`, keeps the result; Adopt ships it. A re-run replaces the buffer's whole color state, including palette edits made in the editor since the last run, and carries the type and geometry buffers forward.
386
+
387
+ ### `live-tokens-set-type`
379
388
 
380
389
  Ask for type: "pair some fonts for this theme", "what font should the headings use?", "make the type more editorial", "something friendlier", "a serif for headings".
381
390
 
382
- The skill chooses the families and runs `npx live-tokens set-fonts <brief.json>`, which binds each one to `--font-display`, `--font-sans`, `--font-serif`, or `--font-mono`. Every family is checked against the Google Fonts API before it is written, and the URL is built from the weights that family actually has: a range for a variable font, an enumeration for a static one, a bare URL for a single-weight display face. The report names the weights your typography tokens ask for and the family does not carry.
391
+ The skill chooses the families and runs `npx live-tokens set-type <pairing.json>`, which binds each one to `--font-display`, `--font-sans`, `--font-serif`, or `--font-mono`. Every family is checked against the Google Fonts API before it is written, and the URL is built from the weights that family actually has: a range for a variable font, an enumeration for a static one, a bare URL for a single-weight display face. The report names the weights your typography tokens ask for and the family does not carry.
383
392
 
384
- The judgment is the skill's half. It anchors on the body face, because that is most of the words on the page and text faces survive small sizes where display faces do not. It classifies both candidates by form model (dynamic, rational, geometric) and applies the font matrix: two faces sharing a skeleton under different surfaces pair reliably, two faces sharing a surface over different skeletons fight, and two faces far apart on both read as a decision. It also carries the screen test a body face has to pass, a voice table from brief to type, and the Google Fonts superfamilies for when the type should stay quiet.
393
+ The judgment is the skill's half. It anchors on the body face, because that is most of the words on the page and text faces survive small sizes where display faces do not. It classifies both candidates by form model (dynamic, rational, geometric) and applies the font matrix: two faces sharing a skeleton under different surfaces pair reliably, two faces sharing a surface over different skeletons fight, and two faces far apart on both read as a decision. It also carries the screen test a body face has to pass, a voice table from intent to type, a type anchor per named feeling and idiom, and the Google Fonts superfamilies for when the type should stay quiet.
385
394
 
386
395
  Scope: type only, and never color. Edits land in the colors-and-type `_working.json` buffer, so save the open theme to keep them. `--dry-run` reports without writing.
387
396
 
388
- ### `live-tokens-adjust-geometry`
397
+ ### `live-tokens-set-geometry`
389
398
 
390
399
  Ask for shape or space: "make the buttons pill shaped", "sharper corners on the cards", "space it out", "tighter", "thinner borders".
391
400
 
392
- The skill turns the phrase into ops (`kind` of `radius`, `padding`, `gap`, or `border-width`, with `shift: N` or `set: <token>`, optionally scoped to one component id), then runs `npx live-tokens adjust <ops.json>`. The CLI moves each matching alias along its ladder, reads the live config first so "a bit more" compounds, and prints every change and every skip.
401
+ The skill turns the phrase into ops (`kind` of `radius`, `padding`, `gap`, or `border-width`, with `shift: N` or `set: <token>`, optionally scoped to one component id), then runs `npx live-tokens set-geometry <ops.json>`. The CLI moves each matching alias along its ladder, reads the live config first so "a bit more" compounds, and prints every change and every skip.
393
402
 
394
403
  It also knows where these edits go wrong: controls run out of room long before containers do, so a global compaction is one step and anything deeper is aimed at named containers; a pill needs more horizontal padding than a square-cornered control, not less; and content insets stop at `--space-4`, below which a relative "tighter" reports as clamped instead of writing.
395
404
 
@@ -43,6 +43,60 @@ export const COMPONENT_RULES = {
43
43
  'default-not-token': 'error',
44
44
  'phantom-link': 'warn',
45
45
  'dimension-literal': 'warn',
46
+ // `--tests` (bin/contractRunner.mjs). Fixed by design decision 8 so
47
+ // `fix-findings` can map them; every one is an error, including the setup
48
+ // rules, which `--tests` treats as never-silenceable (see cli.mjs).
49
+ 'contract-registry': 'error',
50
+ 'contract-render': 'error',
51
+ 'contract-alias': 'error',
52
+ 'contract-persist': 'error',
53
+ 'contract-theme': 'error',
54
+ 'contract-states': 'error',
55
+ 'contract-interaction': 'error',
56
+ 'contract-listed': 'error',
57
+ 'contract-sketch': 'error',
58
+ 'tests-not-installed': 'error',
59
+ 'tests-setup': 'error',
60
+ 'tests-incomplete': 'error',
61
+ };
62
+
63
+ /**
64
+ * Where a rule is fixed, as a stable slug carried on the finding. The skills
65
+ * resolve the slug to one of their own headings, so adding a rule here costs
66
+ * no skill edit as long as it reuses a slug. Two skills used to enumerate every
67
+ * rule id in their own tables, with nothing holding the two in agreement or
68
+ * checking either against this list.
69
+ */
70
+ export const COMPONENT_RULE_FIX = {
71
+ 'unknown-suffix': 'property-name',
72
+ 'state-after-property': 'property-name',
73
+ 'disabled-is-terminal': 'property-name',
74
+ 'default-not-token': 'property-token',
75
+ 'color-literal': 'property-token',
76
+ 'dimension-literal': 'property-token',
77
+ 'unknown-token-ref': 'property-token',
78
+ 'contract-theme': 'property-token',
79
+ 'invalid-id': 'runtime',
80
+ 'missing-file': 'runtime',
81
+ 'missing-root-block': 'runtime',
82
+ 'no-tokens': 'runtime',
83
+ 'contract-persist': 'runtime-defaults',
84
+ 'missing-component-const': 'editor',
85
+ 'missing-all-tokens': 'editor',
86
+ 'phantom-editor-token': 'editor',
87
+ 'phantom-link': 'editor',
88
+ 'deep-import': 'editor',
89
+ 'contract-render': 'editor',
90
+ 'contract-alias': 'editor',
91
+ 'contract-states': 'editor',
92
+ 'contract-interaction': 'editor',
93
+ 'missing-registration': 'registration',
94
+ 'contract-registry': 'registration',
95
+ 'contract-listed': 'registration',
96
+ 'contract-sketch': 'sketch',
97
+ 'tests-not-installed': 'tooling',
98
+ 'tests-setup': 'tooling',
99
+ 'tests-incomplete': 'coverage',
46
100
  };
47
101
 
48
102
  // Shipped components keep their editor beside the other editors; a
@@ -97,6 +151,35 @@ function capitalize(id) {
97
151
  return id.charAt(0).toUpperCase() + id.slice(1);
98
152
  }
99
153
 
154
+ /**
155
+ * Where `id`'s runtime and editor files live, resolved the same way
156
+ * `checkComponent` does: the real on-disk filename rather than a capitalised
157
+ * guess, since `cornerbadge` ships as `CornerBadge.svelte`. Exported so a
158
+ * caller outside the lint (the `--tests` runner, attributing a contract
159
+ * finding to a consumer artifact) doesn't re-derive it differently.
160
+ */
161
+ export function resolveComponentPaths(id, root = process.cwd()) {
162
+ // A consumer names a shipped id and owns no copy of its files. Falling back
163
+ // to the package keeps the lint reading the same source the contract run
164
+ // resolves, instead of reporting the component's own files missing. In this
165
+ // repo the consumer paths always exist, so the fallback never fires here.
166
+ const roots = builtInIds(root).has(id) ? [root, PKG_ROOT] : [root];
167
+ for (const base of roots) {
168
+ const dir = join(base, 'src/system/components');
169
+ const Id =
170
+ (existsSync(dir) ? readdirSync(dir) : [])
171
+ .find((f) => f.toLowerCase() === `${id}.svelte`)
172
+ ?.replace('.svelte', '') ?? capitalize(id);
173
+ const runtimePath = join(dir, `${Id}.svelte`);
174
+ const editorPath =
175
+ EDITOR_DIRS.map((d) => join(base, d, `${Id}Editor.svelte`)).find(existsSync) ??
176
+ join(base, EDITOR_DIRS[0], `${Id}Editor.svelte`);
177
+ if (base === roots.at(-1) || (existsSync(runtimePath) && existsSync(editorPath))) {
178
+ return { Id, runtimePath, editorPath };
179
+ }
180
+ }
181
+ }
182
+
100
183
  function extractImports(source) {
101
184
  const out = [];
102
185
  const re = /import\s+(?:[^'"]*\s+from\s+)?['"]([^'"]+)['"]/g;
@@ -267,10 +350,10 @@ function checkDefaultsAreSemantic({ blocks, runtime, editor, root, runtimePath,
267
350
  record(
268
351
  'unknown-token-ref',
269
352
  STATE_TOKENS.includes(ref.replace(/^--/, '').split('-')[0])
270
- ? `${rel}: ${name} reads ${ref}, but a state is a segment of a property name, not a token of its own; read the token the state should paint`
353
+ ? `${rel}: ${name} reads ${ref}, but a state is a segment of a property name. Read the token the state should paint`
271
354
  : isContractToken(ref)
272
- ? `${rel}: ${name} reads ${ref}, which looks like a theme token but no longer exists; check tokens.css for a rename`
273
- : `${rel}: ${name} reads ${ref}, which is not a theme token or a component token`,
355
+ ? `${rel}: ${name} reads ${ref}, which has the shape of a design token but no longer exists. Check tokens.css for a rename`
356
+ : `${rel}: ${name} reads ${ref}, which is not a design token or a semantic property`,
274
357
  at,
275
358
  );
276
359
  }
@@ -278,7 +361,7 @@ function checkDefaultsAreSemantic({ blocks, runtime, editor, root, runtimePath,
278
361
  if (hasColorLiteral(painted)) {
279
362
  record(
280
363
  'color-literal',
281
- `${rel}: ${name}: ${value} is a colour literal; defaults must reference theme tokens (e.g. var(--surface-primary))`,
364
+ `${rel}: ${name}: ${value} is a colour literal; defaults must reference design tokens (e.g. var(--surface-primary))`,
282
365
  at,
283
366
  );
284
367
  continue;
@@ -287,7 +370,7 @@ function checkDefaultsAreSemantic({ blocks, runtime, editor, root, runtimePath,
287
370
  if (refs.length === 0 && !matchers.some((re) => re.test(name))) {
288
371
  record(
289
372
  'default-not-token',
290
- `${rel}: ${name}: ${value} has no theme token behind it; back it with a token, or declare it in the editor's \`intrinsics\` if it is a structural keyword`,
373
+ `${rel}: ${name}: ${value} has no design token behind it. Back it with a token, or declare it in the editor's \`intrinsics\` when it is a structural keyword`,
291
374
  at,
292
375
  );
293
376
  }
@@ -326,18 +409,7 @@ export function checkComponent(id, root = process.cwd(), { vocabulary } = {}) {
326
409
  return done();
327
410
  }
328
411
 
329
- // Resolve the real filename rather than capitalising the id: `cornerbadge`
330
- // ships as `CornerBadge.svelte`, and the casing is what gives the kebab form
331
- // of its token prefix.
332
- const dir = join(root, 'src/system/components');
333
- const Id =
334
- (existsSync(dir) ? readdirSync(dir) : [])
335
- .find((f) => f.toLowerCase() === `${id}.svelte`)
336
- ?.replace('.svelte', '') ?? capitalize(id);
337
- const runtimePath = join(dir, `${Id}.svelte`);
338
- const editorPath =
339
- EDITOR_DIRS.map((d) => join(root, d, `${Id}Editor.svelte`)).find(existsSync) ??
340
- join(root, EDITOR_DIRS[0], `${Id}Editor.svelte`);
412
+ const { Id, runtimePath, editorPath } = resolveComponentPaths(id, root);
341
413
 
342
414
  file = relative(root, runtimePath);
343
415
  if (!existsSync(runtimePath)) {
@@ -381,7 +453,7 @@ export function checkComponent(id, root = process.cwd(), { vocabulary } = {}) {
381
453
  record(
382
454
  'state-after-property',
383
455
  `${relative(root, runtimePath)}: ${token} has '${trailingState}' after the property; ` +
384
- `state must come before property (e.g. -${trailingState}-surface, not -surface-${trailingState})`,
456
+ `state must come before property (e.g. -${trailingState}-surface)`,
385
457
  runtime.indexOf(token),
386
458
  );
387
459
  }
@@ -512,7 +584,7 @@ export function checkComponent(id, root = process.cwd(), { vocabulary } = {}) {
512
584
  if (!registrationFile) {
513
585
  record(
514
586
  'missing-registration',
515
- `no registration for '${id}' under src/ — expected registerComponent({ id: '${id}', ... }) or bootLiveTokens({ components: [{ id: '${id}', ... }] })`,
587
+ `no registration for '${id}' under src/. Expected registerComponent({ id: '${id}', ... }) or bootLiveTokens({ components: [{ id: '${id}', ... }] })`,
516
588
  );
517
589
  } else {
518
590
  // Check the registration file's imports too.