@motion-proto/live-tokens 0.74.0 → 0.76.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 (171) 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 +52 -48
  13. package/.claude/skills/live-tokens-create-theme/references/design-directions.md +1 -1
  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 +47 -38
  17. package/.claude/skills/live-tokens-set-geometry/SKILL.md +58 -35
  18. package/.claude/skills/live-tokens-set-geometry/references/geometry-anchors.md +5 -3
  19. package/.claude/skills/live-tokens-set-type/SKILL.md +30 -30
  20. package/CHANGELOG.md +138 -0
  21. package/README.md +17 -7
  22. package/bin/check-component.mjs +91 -19
  23. package/bin/check-page.mjs +102 -21
  24. package/bin/cli.mjs +87 -113
  25. package/bin/contractRunner.mjs +945 -0
  26. package/bin/create.mjs +1 -1
  27. package/bin/lib/catalogue.mjs +37 -30
  28. package/bin/lib/findings.mjs +46 -15
  29. package/bin/lib/report.mjs +3 -3
  30. package/bin/lib/tokenVocabulary.mjs +4 -4
  31. package/bin/migrate-routes.mjs +5 -5
  32. package/bin/migrate.mjs +4 -4
  33. package/bin/save-theme.mjs +8 -9
  34. package/bin/set-colors.mjs +9 -11
  35. package/bin/set-geometry.mjs +7 -7
  36. package/bin/set-type.mjs +5 -7
  37. package/bin/setup-claude.mjs +110 -0
  38. package/dist-plugin/{chunk-W6Y4BWFB.js → chunk-6WGFOJXO.js} +22 -0
  39. package/dist-plugin/{chunk-7VRTBGJT.js → chunk-PDNL4NC5.js} +9 -2
  40. package/dist-plugin/{chunk-V3YF6CGT.js → chunk-SWXRVZKT.js} +43 -1
  41. package/dist-plugin/{dataPaths-BhWzd5cL.d.cts → dataPaths-BpIK_Obx.d.cts} +1 -0
  42. package/dist-plugin/{dataPaths-BhWzd5cL.d.ts → dataPaths-BpIK_Obx.d.ts} +1 -0
  43. package/dist-plugin/index.cjs +310 -147
  44. package/dist-plugin/index.d.cts +1 -1
  45. package/dist-plugin/index.d.ts +1 -1
  46. package/dist-plugin/index.js +218 -122
  47. package/dist-plugin/migrateData/index.cjs +66 -2
  48. package/dist-plugin/migrateData/index.d.cts +1 -1
  49. package/dist-plugin/migrateData/index.d.ts +1 -1
  50. package/dist-plugin/migrateData/index.js +3 -3
  51. package/dist-plugin/setColors/index.cjs +61 -4
  52. package/dist-plugin/setColors/index.d.cts +1 -1
  53. package/dist-plugin/setColors/index.d.ts +1 -1
  54. package/dist-plugin/setColors/index.js +5 -5
  55. package/dist-plugin/setGeometry/index.cjs +107 -44
  56. package/dist-plugin/setGeometry/index.d.cts +5 -5
  57. package/dist-plugin/setGeometry/index.d.ts +5 -5
  58. package/dist-plugin/setGeometry/index.js +51 -45
  59. package/dist-plugin/setType/index.cjs +15 -0
  60. package/dist-plugin/setType/index.d.cts +1 -1
  61. package/dist-plugin/setType/index.d.ts +1 -1
  62. package/dist-plugin/setType/index.js +1 -1
  63. package/dist-plugin/tokensCssMigrations/index.d.cts +1 -1
  64. package/dist-plugin/tokensCssMigrations/index.d.ts +1 -1
  65. package/dist-plugin/tokensCssMigrations/index.js +1 -1
  66. package/package.json +35 -8
  67. package/src/app/site.css +19 -9
  68. package/src/editor/bootstrap.ts +2 -0
  69. package/src/editor/component-editor/CollapsibleSectionEditor.svelte +4 -4
  70. package/src/editor/component-editor/DialogEditor.svelte +4 -4
  71. package/src/editor/component-editor/MenuSelectEditor.svelte +4 -1
  72. package/src/editor/component-editor/SegmentedControlEditor.svelte +6 -1
  73. package/src/editor/component-editor/TabBarEditor.svelte +1 -1
  74. package/src/editor/component-editor/TableEditor.svelte +2 -2
  75. package/src/editor/component-editor/scaffolding/TokenLayout.svelte +6 -3
  76. package/src/editor/component-editor/scaffolding/VariantGroup.svelte +41 -20
  77. package/src/editor/core/components/adjustAliases.ts +59 -45
  78. package/src/editor/core/components/aliasKinds.ts +9 -5
  79. package/src/editor/core/preview/themePreview.ts +9 -2
  80. package/src/editor/core/sketch/sketchLayer.ts +22 -0
  81. package/src/editor/core/store/editorStore.ts +10 -1
  82. package/src/editor/core/themes/buildColors.ts +3 -3
  83. package/src/editor/core/themes/liveStateStream.ts +26 -0
  84. package/src/editor/core/themes/migrations/2026-09-07-stroke-role-renames.ts +52 -0
  85. package/src/editor/core/themes/migrations/index.ts +2 -0
  86. package/src/editor/core/themes/themeDocumentSync.ts +22 -11
  87. package/src/editor/core/themes/themeService.ts +9 -2
  88. package/src/editor/pages/ComponentEditorPage.svelte +17 -1
  89. package/src/editor/pages/liveTokensEditorHandle.ts +23 -0
  90. package/src/editor/skill-atlas/SkillAtlas.svelte +75 -573
  91. package/src/editor/skill-atlas/TreeCanvas.svelte +263 -0
  92. package/src/editor/skill-atlas/TreeNodeCard.svelte +136 -53
  93. package/src/editor/skill-atlas/edges.ts +31 -0
  94. package/src/editor/skill-atlas/skillSources.generated.ts +20 -19
  95. package/src/editor/skill-atlas/skillTrees.ts +19 -3840
  96. package/src/editor/skill-atlas/trees/check-compliance.ts +183 -0
  97. package/src/editor/skill-atlas/trees/create-component.ts +275 -0
  98. package/src/editor/skill-atlas/trees/create-page.ts +320 -0
  99. package/src/editor/skill-atlas/trees/create-theme.ts +255 -0
  100. package/src/editor/skill-atlas/trees/fix-findings.ts +469 -0
  101. package/src/editor/skill-atlas/trees/pick-component.ts +300 -0
  102. package/src/editor/skill-atlas/trees/set-colors.ts +148 -0
  103. package/src/editor/skill-atlas/trees/set-geometry.ts +136 -0
  104. package/src/editor/skill-atlas/trees/set-type.ts +142 -0
  105. package/src/editor/skill-atlas/types.ts +3 -4
  106. package/src/editor/skill-atlas/wireLayout.ts +287 -0
  107. package/src/live-tokens/data/themes/autumn.json +15 -15
  108. package/src/live-tokens/data/themes/halloween.json +15 -15
  109. package/src/live-tokens/data/themes/midnight-study.json +15 -15
  110. package/src/live-tokens/data/themes/ocean.json +15 -15
  111. package/src/live-tokens/data/themes/royal-velvet.json +15 -15
  112. package/src/live-tokens/data/themes/sketchy.json +15 -15
  113. package/src/live-tokens/data/themes/spring-meadow.json +15 -15
  114. package/src/live-tokens/data/themes/sunset.json +15 -15
  115. package/src/system/components/Badge.svelte +7 -0
  116. package/src/system/components/Button.svelte +7 -0
  117. package/src/system/components/Callout.svelte +10 -6
  118. package/src/system/components/Card.svelte +23 -4
  119. package/src/system/components/CodeSnippet.svelte +4 -3
  120. package/src/system/components/CollapsibleSection.svelte +23 -8
  121. package/src/system/components/CornerBadge.svelte +6 -0
  122. package/src/system/components/Dialog.svelte +13 -6
  123. package/src/system/components/IconButton.svelte +9 -0
  124. package/src/system/components/Image.svelte +8 -0
  125. package/src/system/components/ImageLightbox.svelte +6 -0
  126. package/src/system/components/InlineEditActions.svelte +7 -0
  127. package/src/system/components/Input.svelte +7 -0
  128. package/src/system/components/MenuSelect.svelte +7 -0
  129. package/src/system/components/Notification.svelte +7 -0
  130. package/src/system/components/Panel.svelte +6 -0
  131. package/src/system/components/ProgressBar.svelte +5 -0
  132. package/src/system/components/RadioButton.svelte +11 -5
  133. package/src/system/components/SectionDivider.svelte +8 -0
  134. package/src/system/components/SegmentedControl.svelte +6 -0
  135. package/src/system/components/SideNavigation.svelte +6 -0
  136. package/src/system/components/Slider.svelte +7 -4
  137. package/src/system/components/TabBar.svelte +15 -9
  138. package/src/system/components/Table.svelte +8 -3
  139. package/src/system/components/Toggle.svelte +4 -4
  140. package/src/system/components/Tooltip.svelte +6 -0
  141. package/src/testing-js/chunk-AO7EZHYV.js +776 -0
  142. package/src/testing-js/chunk-AO7EZHYV.js.map +1 -0
  143. package/src/testing-js/chunk-FAFOAWYL.js +39 -0
  144. package/src/testing-js/chunk-FAFOAWYL.js.map +1 -0
  145. package/src/testing-js/chunk-L73N4NSO.js +23 -0
  146. package/src/testing-js/chunk-L73N4NSO.js.map +1 -0
  147. package/src/testing-js/chunk-LXR3MN6N.js +3063 -0
  148. package/src/testing-js/chunk-LXR3MN6N.js.map +1 -0
  149. package/src/testing-js/chunk-ZMSX6CXR.js +53 -0
  150. package/src/testing-js/chunk-ZMSX6CXR.js.map +1 -0
  151. package/src/testing-js/component-alias.contract.js +81 -0
  152. package/src/testing-js/component-alias.contract.js.map +1 -0
  153. package/src/testing-js/component-editor.contract.js +62 -0
  154. package/src/testing-js/component-editor.contract.js.map +1 -0
  155. package/src/testing-js/component-render.contract.js +568 -0
  156. package/src/testing-js/component-render.contract.js.map +1 -0
  157. package/src/testing-js/index.d.ts +293 -0
  158. package/src/testing-js/index.js +222 -0
  159. package/src/testing-js/index.js.map +1 -0
  160. package/src/testing-js/registry.contract.js +39 -0
  161. package/src/testing-js/registry.contract.js.map +1 -0
  162. package/src/testing-js/vitest-BE6uGF31.d.ts +73 -0
  163. package/src/testing-js/vitest.d.ts +3 -0
  164. package/src/testing-js/vitest.js +13 -0
  165. package/src/testing-js/vitest.js.map +1 -0
  166. package/template/README.md +13 -0
  167. package/template/_gitignore +6 -0
  168. package/template/package.json +3 -1
  169. package/template/src/pages/Home.svelte +4 -18
  170. package/.claude/skills/live-tokens-build-page/SKILL.md +0 -103
  171. package/.claude/skills/live-tokens-build-page/references/layout-sources.md +0 -48
@@ -7,7 +7,7 @@ the direction the three intents come from.
7
7
  The mechanics live with the executors. Color anchors are in
8
8
  live-tokens-set-colors, type anchors in live-tokens-set-type, geometry anchors
9
9
  in live-tokens-set-geometry, each keyed on the same names as the tables below.
10
- Name the anchor when you state an intent and the sibling reads its own column.
10
+ Name the anchor in the intent, and the sibling reads its own column.
11
11
 
12
12
  Three axes place any request, including one no entry lists:
13
13
 
@@ -1,89 +1,98 @@
1
1
  ---
2
2
  name: live-tokens-fix-findings
3
- description: Bring an existing @motion-proto/live-tokens project into line with its design system by running check-page and check-component, reading the findings, and fixing each by rule until both exit 0. Use when the user asks to make the build pass, fix the design-system errors or warnings, clean up the literals, replace hex or pixel values with tokens, make a page or component themeable, or apply what a check reported. Not for the check itself (live-tokens-check-compliance reports and edits nothing), not for building a new page (live-tokens-build-page) or a new component (live-tokens-create-component), which run the same gate as their last step, and not for a single token edit (use the editor).
3
+ description: Fix every finding of check-page and check-component in an existing @motion-proto/live-tokens project until both exit 0. Called with the fix list by live-tokens-check-compliance. Use when the user asks to fix the project. Edits the files the checkers name. Updates tokens.css only through the migration command.
4
4
  ---
5
5
 
6
- # Fixing the checkers' findings
6
+ # Fixing the findings of check-page and check-component
7
7
 
8
- Two checkers hold a project to its design system. `check-page` holds pages: every component comes from the catalogue and is passed only the props it declares, and every value in page CSS is a theme token. `check-component` holds authored components: every token names a semantic property and its default is the theme token that property reads. A page or component that passes repaints when the theme changes. One that fails has opted out of the system silently, and its findings say where.
9
-
10
- This skill is the loop for code that already exists. When the user has not seen the state of the project yet, **live-tokens-check-compliance** presents `npx live-tokens report` without editing; this skill edits.
8
+ Fix every finding of `check-page` and `check-component` until both exit 0. `check-page` checks pages. Every component comes from the catalogue, every prop is declared, and every value in page CSS is a design token. `check-component` checks authored components. Every token names a semantic property, and its default is the design token that property reads. Update `tokens.css` only through the migration command. That command also heals the data tree, and with `--write` rewrites the route references it lists. When live-tokens-check-compliance hands over a fix list, the user's choices in it stand.
11
9
 
12
10
  ## Workflow
13
11
 
14
- 1. Run both checkers with `--json`. Each finding carries a stable `rule`, a file, and a line.
12
+ When `check-page` is an unknown command, upgrade `@motion-proto/live-tokens` first.
13
+
14
+ 1. Run `npx live-tokens migrate --check` to see the plan, then `npx live-tokens migrate` to apply it. `--tokens <path>` names a tokens.css in an unusual place.
15
+ 2. Run both checkers with `--json`. Each finding carries a `rule`, a file, and a line.
15
16
  ```sh
16
- npx live-tokens check-page --json # every page under src/
17
- npx live-tokens check-component --json # every component authored under src/system/components
17
+ npx live-tokens check-page --json
18
+ npx live-tokens check-component --json
18
19
  ```
19
- `check-page src/pages/Home.svelte` and `check-component <id>` scope a run when the user names one thing. Unknown command means the installed package predates the checkers: upgrade `@motion-proto/live-tokens`, then run `npx live-tokens migrate --check` and apply what it plans with `--write` (`--tokens <path>` for a tokens.css outside the four default locations).
20
- 2. Group by rule. Take errors before warnings, and the rule with the most findings first, because one recipe clears the whole group.
21
- 3. Apply that rule's recipe to every finding in the group: colour by role, geometry by scale, or the row in the table below. A component outside the catalogue hands off to **live-tokens-pick-component** for the shipped one that fits, or to **live-tokens-create-component**.
22
- 4. Run again. New findings can appear as old ones clear: a token you reached for may not exist, or a moved import may land where a rule now sees it. Stop at exit 0.
23
- 5. Run once with `--strict` and report what it adds, so the user can decide whether warnings are worth clearing now. Then report by rule.
20
+ 3. Group the findings by rule.
21
+ 4. Take the largest error group first, then the remaining errors. Take warnings only when the repair scope includes warnings.
22
+ 5. Fix every finding in the group with its section: Color by role, Geometry by scale, or The remaining rules.
23
+ 6. Run both checkers again. When repairable findings remain in scope, return to step 3. When no token fits a remaining finding, leave it and continue to the reply with its reason.
24
+ 7. When the errors are clear, run both checkers with `--strict`. Report what `--strict` adds. Clear warnings within the existing request. Otherwise ask whether to clear the warnings now.
25
+ 8. When the repair scope includes warnings, return to step 3 with `--strict`. When strict checks pass or the user defers warnings, continue to the reply.
26
+ 9. Reply with:
27
+ - the changes by rule, each with its count and any visible shift
28
+ - the findings left, each with its reason and any config entry the user chose
29
+ - both checker commands with their exit codes
30
+
31
+ `check-page <path>` scopes a run to one page. `check-component <id>` scopes a run to one component: its runtime, its editor, and its registration. The checkers read tokens.css from its default location.
24
32
 
25
- A project scaffolded by `create` has a `check:design` script. Give any other project one in `package.json`, `"check:design": "live-tokens check-page && live-tokens check-component"`, and once it passes, gate the build: `"build": "npm run check:design && vite build"`.
33
+ When `package.json` has no `check:design` script, add `"check:design": "live-tokens check-page && live-tokens check-component"`. When both checkers exit 0, prepend `npm run check:design &&` to the existing build command. Preserve its other build steps.
26
34
 
27
- ## Three things the loop never does
35
+ ## Scope
28
36
 
29
- - **Silence a rule to pass.** `--off=<rule>` is for a single run while working. A severity the project wants changed goes in `live-tokens.config.json` under `"checks": { "rules": { "<rule>": "warn" } }`, with the reason in the commit, and only when the user has made that call.
30
- - **Mint a token.** A literal with no token behind it is remapped to the nearest existing token by role. No new `--surface-*`, `--text-*`, or `--space-*` is added to `tokens.css` to match a value the page happened to use. If nothing fits, say so and leave the finding.
31
- - **Change what the page looks like without saying so.** Most remaps land on the same value. When the nearest token differs, `14px` to `--space-16` or a 55% black to `--scrim`, name the shift in the report.
37
+ - Add no token to `tokens.css`. Map a literal with no matching token to the nearest existing token by role. When no token fits, leave the finding and say so.
38
+ - When the user has chosen to lower a rule's severity, record it in `live-tokens.config.json` under `"checks": { "rules": { "<rule>": "warn" } }`. `--off=<rule>` silences a rule for one run only.
39
+ - When the nearest token differs from the literal, use the token and name the shift in the report, such as `14px` to `--space-16`.
32
40
 
33
- ## Colour by role, never by hue
41
+ ## Color by role
34
42
 
35
- `color-literal` is the finding that takes judgement. The replacement is the token for what the colour *does*, not the token nearest in hue, because the theme moves every role together and the page must move with it. `npx live-tokens tokens --family surface` prints a family's names and values (`text`, `border`, `scrim`, `tint` likewise; `--json` for data); the families are fixed.
43
+ `color-literal` is a judgement finding. The replacement is the token for the role the color plays. The theme moves every role together. `npx live-tokens tokens --scale <name>` prints a scale's names and values, with `--json` for data.
36
44
 
37
- | The literal is | Token family | Notes |
45
+ | Literal | Token | Notes |
38
46
  | --- | --- | --- |
39
- | Text on a surface | `--text-primary`, `-secondary`, `-tertiary`, `-muted`, `-disabled` | The neutral scale. Family colour is `--text-accent`, `--text-success`, and so on. |
40
- | Light text on a dark chip over the page | `--text-inverted` | The one flip; no AA guarantee. |
41
- | A box's fill | `--surface-<family>-<level>` | `neutral` for chrome; `brand`, `accent`, `special` for emphasis; `info`, `success`, `warning`, `danger` for status. |
42
- | A stroke | `--border-<family>-<level>` | `faint`, `subtle`, base, `medium`, `strong` in the neutral family. |
43
- | A translucent layer that dims what is behind it | `--scrim-low`, `--scrim`, `--scrim-high` | Behind a modal, under a floating control. |
44
- | A translucent wash on a surface | `--tint-low`, `--tint`, `--tint-high` | Hover, an active tab, a code chip's background. |
45
- | Fully transparent | `--color-transparent` | Never `transparent` inside a component default. |
47
+ | Text on a surface | `--text-primary` through `--text-disabled` | The neutral text scale. `--text-<family>` for a family color. |
48
+ | Light text on a dark chip | `--text-inverted` | No AA guarantee. |
49
+ | A surface fill | `--surface-<family>-<level>` | The role names the family: `neutral` for chrome, `brand` for emphasis, `danger` for status. |
50
+ | A stroke | `--border-<family>-<level>` | Levels run `faint` to `strong`. |
51
+ | A translucent layer that dims what is behind it | `--scrim-low`, `--scrim`, `--scrim-high` | Behind a modal. |
52
+ | A translucent wash on a surface | `--tint-low`, `--tint`, `--tint-high` | A hover state. |
53
+ | Any other translucent color | The role's token at an opacity: `color-mix(in srgb, var(--surface-brand) 80%, transparent)` | The editor reads that form. |
54
+ | Fully transparent | `--color-transparent` | |
46
55
  | A gradient | `--gradient-*` | Or compose one from surface tokens. |
47
56
 
48
- A `var(--x, #fff)` fallback is not a finding. A named colour is: `white` and `rebeccapurple` are literals like any hex.
49
-
50
57
  ## Geometry by scale
51
58
 
52
- `dimension-literal` fires only on the geometry the theme owns: padding, margin, gap, border and outline widths, inset offsets, radius, and shadow. Sizing (a hero's height, a max content width, a `minmax()` floor) is layout and is never reported, so leave it.
59
+ `dimension-literal` is a mechanical finding. A size, such as a hero's height, is layout. Leave it.
53
60
 
54
- | The literal is | Token | Notes |
61
+ | Literal | Token | Notes |
55
62
  | --- | --- | --- |
56
- | Padding, margin, gap, an offset | `--space-<px>` | `npx live-tokens tokens --family space` prints the steps. Round to the nearest one and name the shift. |
63
+ | Spacing | `--space-<px>` | `npx live-tokens tokens --scale space` prints the steps. Round to the nearest step. |
57
64
  | A stroke width | `--border-width-1`, `-2`, `-4` | Also for `outline`. |
58
- | A corner | `--radius-sm` through `-4xl`, `--radius-full` | |
59
- | A shadow | `--shadow-sm` through `-xl` | Replace the whole value, never one offset. |
65
+ | A corner | `--radius-sm` through `--radius-4xl`, or `--radius-full` | |
66
+ | A shadow | `--shadow-sm` through `--shadow-xl` | Replace the whole value. |
60
67
  | Part of a `calc()` | The token inside the calc | `calc(var(--space-64) * -2 + var(--space-8))` |
68
+ | A duration or easing | `--duration-*`, `--ease-*` | No rule reports it. Fix it while in the file. |
69
+ | A `blur()` | `--blur-*` | No rule reports it. Fix it while in the file. |
61
70
 
62
- While in the file, motion values take `--duration-*` and `--ease-*` even though no rule reports them, and a `blur()` takes `--blur-*`.
63
-
64
- ## Every other rule
71
+ ## The remaining rules
65
72
 
66
73
  | Rule | Fix |
67
74
  | --- | --- |
68
- | `unknown-token` | A typo or a rename. Search `tokens.css` for the stem. A contract-family name (`--surface-…`, `--text-…`) that is gone was renamed: `npx live-tokens migrate --check` names the migration. |
69
- | `raw-text-axis` | Set the whole axis set from one text style: `--heading-xl` through `-sm`, `--body-md`, `--body-sm`, `--editorial-*`, `--eyebrow`, `--code`, each carrying `-font-family`, `-font-size`, `-font-weight`, `-line-height`, `-letter-spacing`. A `font:` shorthand is rewritten the same way. `em`, `%`, and a unitless line-height are relative and fine. |
70
- | `unknown-component` | Not in the catalogue. Read **live-tokens-pick-component** for the shipped one that fits, or author it with **live-tokens-create-component**. |
71
- | `unknown-prop` | The component drops it at runtime. `npx live-tokens components <id>` prints the props it declares and the values each union accepts; map the prop to one of them or delete it. A `class` on a component that declares none does nothing. |
72
- | `unknown-prop-value` | Pick a value from the union the message lists. |
73
- | `hardcoded-columns` | `repeat(var(--columns-count), 1fr)` for the page grid; `calc(var(--columns-count) - 2)` for a sub-grid spanning fewer page columns. A two-up or three-up is a layout and is not reported. |
74
- | `site-css-in-main` | Delete the import from `main.ts` and add it to each page's `<script>`, so page CSS never reaches the editor routes. |
75
- | `missing-source` | Add `source: 'src/...'` to the route entry so Page Source can open it. |
76
- | `reserved-route` | Move the route out of `/live-tokens/*`; the package owns that namespace. |
77
- | `deep-import` | Import from `@motion-proto/live-tokens` or `/component-editor` or `/components/<Name>.svelte`, never from `/src/`. |
78
- | `unknown-suffix`, `state-after-property`, `disabled-is-terminal` | Rename the token. Borrow the name a shipped component uses for the same role; the vocabulary and the state model are in **live-tokens-create-component**. |
79
- | `color-literal`, `unknown-token-ref`, `default-not-token` (component) | The `:global(:root)` default reads a theme token, composed if needed. A structural keyword (`start`, `contain`) is declared in the editor's `intrinsics`. |
80
- | `phantom-editor-token`, `phantom-link` | The editor names a token the runtime never declares, or a bare font helper spans slots. Both are editor fixes; see the same skill. |
81
- | `invalid-id`, `missing-file`, `missing-root-block`, `no-tokens`, `missing-component-const`, `missing-all-tokens`, `missing-registration` | The component is not wired the way the recipe in **live-tokens-create-component** wires it: a lowercase id, a runtime file with a `:global(:root)` block, an editor file exporting `component` and `allTokens`, and a `bootLiveTokens` entry. |
82
-
83
- ## Report
84
-
85
- Say what changed by rule, one line per rule with the count and any visible shift. Say what was left and why, with the config entry if the user chose to lower a severity. End with the two commands and their exit codes.
86
-
87
- ## Verify
88
-
89
- Open `/live-tokens/editor` in dev and change a surface colour and a spacing step. Every file the loop touched should repaint. One that does not still holds a literal the checker cannot see, which is worth reporting as a gap in the checker rather than patching around.
75
+ | `unknown-token` | Search `tokens.css` for the stem. When a contract-family name is gone, `npx live-tokens migrate --check` lists the migration that adds the current name. |
76
+ | `raw-text-axis` | Set every axis from one text style, `-font-family` through `-letter-spacing`. `npx live-tokens tokens --scale heading` prints one text style. The text styles are `heading`, `body`, `editorial`, and `code`. Rewrite a `font:` shorthand the same way. |
77
+ | `unknown-component` | Read **live-tokens-pick-component** for the shipped component that fits. When none fits, author one with **live-tokens-create-component**. |
78
+ | `unknown-prop` | `npx live-tokens components <id>` prints the declared props and their values. Map the prop to one of them, or delete it. |
79
+ | `unknown-prop-value` | Use a value from the union the message lists. |
80
+ | `control-size` | Delete the `size` prop. The shipped default is the page's size. When that default is wrong for the project, retune the component in `/live-tokens/components`. |
81
+ | `multiple-primary` | Keep the action that completes the main task `primary`. A Button with no `variant` counts as `primary`. Use `secondary` for supporting or related actions and `outline` for unrelated or informational actions. |
82
+ | `danger-without-dialog` | Open a `Dialog` from the danger Button or IconButton and run the action from the Dialog's confirm. The rule fires once per page, when the page imports no Dialog. For other actions, assign emphasis by the action's relationship to the main task. |
83
+ | `hardcoded-columns` | `repeat(var(--columns-count), 1fr)` for the page grid. `calc(var(--columns-count) - 2)` for a sub-grid spanning fewer columns. |
84
+ | `site-css-in-main` | Delete the import from `main.ts`. Add it to each page's `<script>`. Page CSS then stays off the editor routes. |
85
+ | `missing-source` | Add `source: 'src/...'` to the route entry. |
86
+ | `reserved-route` | Move the route out of `/live-tokens/*`. |
87
+ | `deep-import` | Import from `@motion-proto/live-tokens`, `/component-editor`, or `/components/<Name>.svelte`. |
88
+ | `fix: property-name` | Rename the token to the name a shipped component uses for the same role. The vocabulary and the state model are in **live-tokens-create-component**. |
89
+ | `fix: property-token` | Make the `:global(:root)` default read a design token, composed when needed. Declare a structural keyword, such as `start`, in the editor's `intrinsics`. |
90
+ | `fix: runtime` | Wire the component as the recipe in **live-tokens-create-component** wires it. |
91
+ | `fix: runtime-defaults` | Make the `:global(:root)` default the value Reset should restore, per the Runtime component section of **live-tokens-create-component**. |
92
+ | `fix: editor` | The editor names a token the runtime never declares, or a property targets the wrong part. Fix the editor's schema, states, or preview props by the Component editor section of **live-tokens-create-component**. |
93
+ | `fix: registration` | Register the component in the shared module the Registration section of **live-tokens-create-component** wires up, importable by the app and by `check-component --tests`. |
94
+ | `fix: sketch` | Add the missing Sketch part or marker, per the Sketch mode and overlays section of **live-tokens-create-component**. |
95
+ | `fix: tooling` | Install the named package (`@playwright/test`, `vitest`, or `happy-dom`) as a devDependency, then `npx playwright install chromium` for a missing browser. A bad path or config is named in the message; fix it and rerun `check-component <id> --tests`. |
96
+ | `fix: coverage` | A contract obligation never ran to a result. Add the missing contract, or find why the suite skipped it, then rerun. |
97
+
98
+ A `tests-*` finding names a problem with the run itself: the tool, the path, or a missing contract. Fix what the message names and rerun `check-component <id> --tests --json` until every applicable rule passes with no rule left `--off`.
@@ -1,111 +1,96 @@
1
1
  ---
2
2
  name: live-tokens-pick-component
3
- description: Recommend which shipped @motion-proto/live-tokens component fits a UX need, with decision trees for the confusable pairs (SegmentedControl / TabBar / RadioButton / MenuSelect, Card / CollapsibleSection / Dialog, Callout / Notification / Tooltip, and others). Use when the user asks which component to use, should I use X or Y, what is the difference between two components, how do I show / let the user / capture some UX outcome, or starts authoring a custom component before checking the catalogue. Read this before live-tokens-create-component. Not for placing the chosen component on a page (see live-tokens-build-page).
3
+ description: Recommend which shipped @motion-proto/live-tokens component fits a UX need, with a decision test for each confusable family. Called by live-tokens-create-page when more than one component could fit, and by live-tokens-create-component before it authors anything. Use when the user asks which component to use, or what the difference between two components is. Use when the user asks how to show or capture a UX outcome. Edits no file. For size, emphasis, or placement, read live-tokens-create-page. When the catalogue lacks a component with chrome, read live-tokens-create-component.
4
4
  ---
5
5
 
6
- # Picking the right live-tokens component
6
+ # Picking a live-tokens component
7
7
 
8
- This skill helps you choose between shipped components when several could plausibly fit. The catalogue is small; the hard part is semantic intent. A `RadioButton` set and a `SegmentedControl` can render identical-looking UIs but communicate different things.
9
-
10
- For composing a page once you've picked components, see **live-tokens-build-page**. For authoring a brand-new component when nothing fits, see **live-tokens-create-component** (but read this skill first to confirm nothing in the catalogue fits).
8
+ When more than one shipped component could fit, find the family below that names the candidates. Apply its test, which asks what the choice means to the reader.
11
9
 
12
10
  ## Catalogue
13
11
 
14
- Action: `Button`, `IconButton`, `InlineEditActions`. Input: `Input`, `Slider`. Selection: `SegmentedControl`, `TabBar`, `RadioButton`, `MenuSelect`, `Toggle`. Containers: `Card`, `CollapsibleSection`, `Dialog`, `Panel`. Messaging: `Callout`, `Notification`, `Tooltip`, `Badge`, `CornerBadge`. Display: `Table`, `Image`, `ImageLightbox`, `ProgressBar`, `SectionDivider`, `SideNavigation`, `CodeSnippet`.
12
+ Before choosing, run `npx live-tokens components`. The list holds every component the project has, shipped and custom, with each one's variants and usage comment. The family tests below name the shipped set only. Weigh a custom component by the same tests.
15
13
 
16
- That line is the shipped set. A project can register components of its own,
17
- and those never appear in this file: run `npx live-tokens components` before
18
- choosing. It lists every component the project has, shipped and custom, with
19
- the variants each takes and the purpose its header comment states, so a custom
20
- component is weighed against the shipped set on the same footing.
21
- `npx live-tokens components <id>` prints one component's props, the values each
22
- union accepts, and its tokens with defaults; `--json` returns the same as data.
14
+ ## Action family
23
15
 
24
- ## Action family: Button vs IconButton
16
+ - The action needs a word to be unambiguous: `Button`.
17
+ - The glyph alone is plain (close, edit, delete) and space is short: `IconButton`.
18
+ - The pair that confirms or cancels an inline edit: `InlineEditActions`.
25
19
 
26
- Both trigger an action and share the same six variants (primary, secondary, outline, success, danger, warning), three states (default, hover, disabled) and two sizes (default, small). They differ only in content.
20
+ ## Single-selection family
27
21
 
28
- - `Button` carries a text label, optionally with a leading or trailing icon. Use it whenever the action needs a word to be unambiguous.
29
- - `IconButton` is icon-only and square. Use it for compact, space-constrained actions whose meaning is obvious from the glyph alone (toolbar controls, close/edit/delete affordances, card overflow menus). It has no text slot, so an `ariaLabel` is required for accessibility.
30
- - **Don't reach for `IconButton` when the icon's meaning isn't self-evident.** A labelled `Button` (or a `Button` with an icon) avoids the guessing game.
31
- - `InlineEditActions` is the confirm-and-cancel pair that follows an inline edit (rename a row, edit a value in place). Use it rather than two loose `IconButton`s so every inline edit on the page resolves the same way.
22
+ Four components pick one option from a set. The test is the option count, whether the selection swaps the content below, and how much the choice asks of the reader.
32
23
 
33
- ## Single-selection family: SegmentedControl vs TabBar vs RadioButton vs MenuSelect
24
+ | Component | Test | Option count |
25
+ |---|---|---|
26
+ | `SegmentedControl` | An inline switch between views of the same data. It sits in a row of controls. | 2 to 4 |
27
+ | `TabBar` | The content area below swaps. | 2 to 7 |
28
+ | `RadioButton` | The reader reads every option as text inside a larger form. | any |
29
+ | `MenuSelect` | The options would overflow a row. | any |
34
30
 
35
- All four pick one option from a set. The right one depends on **option count**, **whether the selection changes what's rendered below**, and **how much visual weight** you want.
31
+ - When a label would wrap in a `SegmentedControl`, use `RadioButton` rows.
32
+ - The URL changes: `SideNavigation`. Sections inside one page: `TabBar`.
36
33
 
37
- | Component | Best for | Visual weight | Option count |
38
- |-------------------|-------------------------------------------------------------------------|------------------|--------------|
39
- | `SegmentedControl`| Inline switch between alternative *views of the same data* | Compact pill | 2–4 |
40
- | `TabBar` | Switching between *tab panels* (content area swaps below) | Page-section | 2–7 |
41
- | `RadioButton` | Form-style selection where the user reviews all options as text | Form-row | Any |
42
- | `MenuSelect` | A list of options, one checked; renders open, so a dropdown toggles it from a `Button` | Open list | Any |
34
+ ## Text entry
43
35
 
44
- - `TabBar` implies "this changes the page"; `SegmentedControl` implies "this is one knob among others."
45
- - Use `RadioButton` when labels deserve room to breathe and the user is committing to a larger form.
46
- - Use `MenuSelect` when options would overflow horizontally or there are too many to display at once.
47
- - **Don't pick `SegmentedControl` when option labels are long enough to wrap.** It loses its compactness; use `RadioButton` rows instead.
36
+ The test is whether the answer comes from a predefined list of options.
48
37
 
49
- ## Text entry: Input vs the selection family
38
+ - A predefined list (a status, a currency, a size, a country): the single-selection family, by its own test. Up to four options sit in a row; more go in a `MenuSelect`, which scrolls.
39
+ - No list (a name, a search string, an amount, a message, a street address): `Input`. Validation keeps a typed answer well-formed.
40
+ - A long list the reader would rather filter by typing (a city): no shipped component filters a list. Use `Input` with validation, or author a filtering select with **live-tokens-create-component**.
41
+ - A number where the position on a track carries the meaning (a volume, a price band, a percentage): `Slider`. A number the reader knows and would rather type: `Input` with `type="number"`.
50
42
 
51
- - `Input` takes an answer the page cannot enumerate: a name, an email, a search string, an amount. It ships the label, the hint line, and the error state as parts (`--input-label-*`, `--input-hint-*`, `--input-error-*`), so style those rather than stacking your own text under a bare field.
52
- - The boundary is whether you can list the answers. A short fixed set is the single-selection family above; a long fixed set is `MenuSelect`; anything you cannot write down is `Input`.
53
- - `Slider` takes a number inside a known range where the position carries the meaning: a volume, a price band, a percentage. Its `range` variant takes a low and a high bound on one track. A number the user knows exactly and would rather type is `Input` with `type="number"`.
54
- - **Don't use it for on/off.** That is `Toggle`, and a one-field form asking for yes or no is the usual way this goes wrong.
55
- - Its four variants are `default`, `focused`, `disabled`, and `error`. A validation message belongs in the `error` variant, not in a `Callout` next to the field.
43
+ ## On and off
56
44
 
57
- ## Container family: Card vs CollapsibleSection vs Dialog
45
+ Three components express a binary choice. The test is whether the two states have names of their own.
58
46
 
59
- | Component | Modality | Use for |
60
- |-----------------------|---------------------|-------------------------------------------------------------|
61
- | `Card` | Inline, always open | Default container for grouped content |
62
- | `CollapsibleSection` | Inline, toggleable | Progressive disclosure inside a longer page |
63
- | `Dialog` | Modal, blocks page | Confirmations, focused tasks the page can't continue around |
64
- | `Panel` | Inline, fixed stage | A demo or preview surface whose height must not reflow |
47
+ | Component | Test |
48
+ |---|---|
49
+ | `Toggle` | A setting that takes effect at once. The label names the setting. The switch position is the state. |
50
+ | `SegmentedControl` | Two named alternatives the reader compares (Light / Dark, List / Grid). Both labels show at once. |
51
+ | `RadioButton` pair | A yes or no the reader answers inside a larger form. |
65
52
 
66
- - Default to `Card`. It's the workhorse. For full-bleed media (cover art, a poster, a chart that reaches its own border) pass `flush` (with `prose={false}`) rather than zeroing its padding tokens from the page.
67
- - Reach for `CollapsibleSection` only when the content is *legitimately secondary* (advanced users open it; most skip). Don't use collapse as a styling choice when the content matters.
68
- - `Panel` is a stage, not a content container. It pins its own height so what it shows can resize without moving the page, which is what a component preview or a live example needs and what article content does not. Content goes in `Card`.
69
- - **Don't use `Dialog` for routine forms.** Reach for it only when the page cannot meaningfully continue until the user decides (destructive confirmations, payment, sign-in). Routine forms go inline in a `Card`.
53
+ When the two states share the feature's one name, use `Toggle`. "Email notifications" has no "off" label.
70
54
 
71
- ## Messaging family: Callout vs Notification vs Tooltip vs Badge
55
+ ## Container family
72
56
 
73
- | Component | Scope | Triggered by | Dismissable | Use for |
74
- |-----------------|----------------|-----------------|-------------|------------------------------------------------------|
75
- | `Callout` | Section-inline | Always present | No | "Heads up about this section" |
76
- | `Notification` | System-level | Event / save | Yes | "Your changes were saved" |
77
- | `Tooltip` | Element-inline | Hover / focus | Auto | Definition or hint anchored to an element |
78
- | `Badge` | Element-inline | Always present | No | Status pill ("Beta", "New", "v2") |
79
- | `CornerBadge` | Element-corner | Always present | No | Position-anchored marker (count, status dot) |
57
+ Four components hold a block of content. The test is what the block is to the reader: one item, a section of the page, secondary content that stays collapsed until opened, or a decision.
80
58
 
81
- - `Callout` is *content*. Part of the section, written into the markup, says something important about what surrounds it. Variants (`info`, `success`, `warning`, `danger`) set the tone.
82
- - `Notification` is *feedback*. Appears in response to an action, then dismisses. **Don't use `Notification` for static content;** persistent messages belong in a `Callout`.
83
- - `Tooltip` is for *what an element means*. **Don't use `Tooltip` as the primary location of important content;** it auto-dismisses and isn't accessible for must-read content.
84
- - `Badge` and `CornerBadge` differ only in positioning. `CornerBadge` lives at a `top-right` / `bottom-left` anchor on a parent (notification counts, "NEW" stickers).
59
+ | Component | Modality | Test |
60
+ |---|---|---|
61
+ | `Card` | Inline, always open | One item, or each item in a set: a product, a record, a plan. It has a title and can react to hover. |
62
+ | `Panel` | Inline, always open | One section of the page's content in a frame: a stage, a list, a form, a block of copy. `minHeight` holds its height while the content changes. |
63
+ | `CollapsibleSection` | Inline, collapsed until the reader opens it | Secondary content most readers skip. |
64
+ | `Dialog` | Modal, blocks the page | A decision the page cannot continue without: a destructive confirmation, payment, sign-in. |
85
65
 
86
- ## Display family: shown, not asked
66
+ A set of items is one `Card` per item. A routine form goes inline in a `Panel`.
87
67
 
88
- - `Image` frames a picture in the flow at one of four sizes, with an optional hover zoom. It is the default for any picture the page simply shows.
89
- - `ImageLightbox` adds click-to-open at full size and takes an array for a gallery. Use it when the detail is the point (screenshots, artwork, charts that need reading), and not for decoration: it puts a modal behind every picture it wraps.
90
- - `Table` themes your own rows and cells without owning the data. Records go here; a set of *things the user acts on* is a stack of `Card`s instead.
91
- - `ProgressBar` reports progress against a labelled track. It is a read-out, never a control.
92
- - `CodeSnippet` is for a single-line command or value the reader is meant to copy back into a terminal (install commands, generated keys, ids), with click-to-copy and a brief "Copied" popover. Use it whenever the page asks the reader to *run* something rather than just *read* it.
93
- - `SectionDivider` separates sections of one page. `SideNavigation` moves between pages, driven by the current path. **Don't use `SideNavigation` to switch panels inside one page;** that is `TabBar`, and the difference is whether the URL changes.
68
+ ## Messaging family
94
69
 
95
- ## Toggle vs SegmentedControl vs RadioButton (for on/off)
70
+ Five components carry a message. The test is what the message is about, what brings it on, and whether the reader dismisses it.
96
71
 
97
- All three can express a binary choice. The right one depends on what the choice *is*.
72
+ | Component | Scope | Trigger | Dismissable | Test |
73
+ |---|---|---|---|---|
74
+ | `Callout` | A section | Always present | No | Something the reader must know about the content around it |
75
+ | `Notification` | The system | An action or event | Yes | Feedback about something that just happened |
76
+ | `Tooltip` | An element | Hover or focus | On leave | A definition or hint the reader can do without |
77
+ | `Badge` | An element | Always present | No | A standing label read at a glance ("Beta", "New", "v2") |
78
+ | `CornerBadge` | A parent's corner | Always present | No | A count or status marker on the thing it describes |
98
79
 
99
- | Component | Best for |
100
- |--------------------|-----------------------------------------------------------------------------------------------------------------------|
101
- | `Toggle` | A *setting* that's either on or off (notifications on/off, dark mode). The label names the setting; the switch shows the state. |
102
- | `SegmentedControl` | A *choice between two named alternatives* (Light / Dark, List / Grid). Both labels are visible at once. |
103
- | `RadioButton` pair | A *form-style choice* where the user reviews both labels before committing (Yes / No questions, opt-in selections). |
80
+ `Badge` and `CornerBadge` differ in position only.
104
81
 
105
- - If the off and on states share a name (the feature itself), it's `Toggle`. "Email notifications" has no "off" label because the switch position is the state.
106
- - If the two states have different names you want users to compare, it's `SegmentedControl`.
107
- - `Toggle` flips immediately; `RadioButton` pair is for forms where the choice is part of a larger submission.
82
+ ## Display family
108
83
 
109
- ---
84
+ Each pair holds a block the reader views and one the reader interacts with. The test is which of the two the page needs.
85
+
86
+ - A picture the page shows: `Image`. A picture whose detail the reader must open, or a gallery: `ImageLightbox`.
87
+ - Records the reader scans and compares: `Table`. A set of items the reader acts on: one `Card` per item.
88
+ - A read-out of progress: `ProgressBar`. A number the reader sets: `Slider`.
89
+ - Text the reader runs or pastes (an install command, a key, an id): `CodeSnippet`. Prose the reader only reads: a paragraph in its `Card` or `Panel`.
90
+ - A titled break between the sections of one page: `SectionDivider`. Movement between pages: `SideNavigation`.
91
+
92
+ ## Nothing fits
93
+
94
+ A native element with no chrome of its own needs no component: an `<input type="file">` behind a Button, a `<canvas>`, an `<img>` inside a stage. When nothing in the catalogue fits a piece with chrome (a `DatePicker`, a `Stepper`), author the component with **live-tokens-create-component**. Size, emphasis, and placement are **live-tokens-create-page**'s.
110
95
 
111
- If nothing in the catalogue fits (a `DatePicker`, a `Stepper`, a custom widget), author it via **live-tokens-create-component**. **Don't reach for a custom component before checking the catalogue;** a custom component is a maintenance commitment.
96
+ `npx live-tokens components <id>` prints one component's usage comment, its declared props, and the values each union accepts. `--json` returns the same as data.
@@ -1,28 +1,28 @@
1
1
  ---
2
2
  name: live-tokens-set-colors
3
- description: Set a live-tokens theme's color from a color intent: ten OKLCH base colors, a light or dark scheme, and an AA-gated contrast pass, written into the unsaved color buffer the app already renders. Use whenever the user asks for a palette, colors, or hues by mood, style, era, season, holiday, or hue; when they name only a color; or when they refine the color of a look: warmer, cooler, calmer, louder, lighter, darker, moodier, more contrast. Also invoked by live-tokens-create-theme, which supplies the color intent for a whole look. Changes color only, never fonts or geometry. Not for a single token (use the editor), and not for a whole look (see live-tokens-create-theme).
3
+ description: Set a live-tokens theme's color: ten OKLCH base colors, a light or dark scheme, and a WCAG AA-gated contrast check. Called with an anchor and a color intent by live-tokens-create-theme, or with the user's request directly. Use when the user asks for a palette, colors, or hues by mood, style, era, season, holiday, or hue. Use when the user names only a color. Use when the user refines a theme's color: warmer, cooler, calmer, louder, lighter, darker, moodier, more contrast. Changes color only. For a request that also names type or geometry, read live-tokens-create-theme.
4
4
  ---
5
5
 
6
6
  # Setting a theme's colors
7
7
 
8
- You choose ten base colors; the CLI builds every ramp from them, enforces AA
9
- contrast on the derived text tokens, writes the result into the unsaved colors
10
- buffer the app already renders, and prints a contrast report. Never hand-author
11
- theme JSON and never edit the data tree directly.
8
+ Choose ten base colors. The CLI builds every ramp from them, checks AA
9
+ contrast, and prints a contrast report. Never write theme JSON by hand and
10
+ never edit the data tree.
12
11
 
13
- The run replaces the color state in that buffer and carries everything else
14
- forward, so it composes with type and geometry in any order. Saving the open
15
- theme in the editor, or running `save-theme`, turns the live look into a theme.
12
+ The result is on screen as soon as the run finishes. The three set skills
13
+ write the same buffer, so color, type, and geometry compose in any order. When
14
+ the user accepts the result, run `save-theme` to keep it as a theme. Loading a
15
+ theme in the editor discards it.
16
16
 
17
17
  ## Workflow
18
18
 
19
- 1. Read the color intent. When it names an anchor (a feeling, an idiom, or an occasion), read `references/color-anchors.md` for that entry; it overrides the generic bands below. Say which anchor you took.
20
- 2. Translate the intent into ten base colors using the framework below and write `scratch/<slug>-base-colors.json`. Nothing else records the base colors, so this file is the only copy; one per slug is what makes the refinement pass cheap.
21
- 3. Run `npx live-tokens set-colors scratch/<slug>-base-colors.json`. It writes the color state into the unsaved buffer the page already runs, and prints a contrast report.
22
- 4. Read the report. Exit 0 passes, and auto-corrected values count as passing. Exit 1 means the base colors are unworkable; each failure line names the base color to change, usually by raising its lightness or cutting its chroma. Fix the base color file and re-run.
23
- 5. Report back in a line: the scheme, the hue families on screen, the canvas commitment level, and anything the report auto-corrected.
19
+ 1. Read the color intent and any anchor live-tokens-create-theme passed. When either names an anchor (a feeling, an idiom, an occasion), read its entry in `references/color-anchors.md`; it overrides the generic ranges below.
20
+ 2. Translate the intent into ten base colors with the framework below and write them to `scratch/<slug>-base-colors.json`. Keep this file for later refinements. The saved theme also records the base colors.
21
+ 3. Run `npx live-tokens set-colors scratch/<slug>-base-colors.json`.
22
+ 4. Read the report. Exit 0 passes, and auto-corrected values count as passing. On a contrast failure, exit 1 names the base color to change and the move: raise its lightness or reduce its chroma. On a bad file, exit 1 names the field. Fix the file and re-run.
23
+ 5. Reply with the anchor if any, the scheme, the hue families, the Canvas base color, and anything the contrast report auto-corrected.
24
24
 
25
- Flags: `--dry-run` prints the contrast report without writing.
25
+ `--dry-run` prints the report without writing.
26
26
 
27
27
  ## The base color file
28
28
 
@@ -44,23 +44,30 @@ Flags: `--dry-run` prints the contrast report without writing.
44
44
  }
45
45
  ```
46
46
 
47
- A base color is the one color a palette's whole ramp derives from. All 10 are required, and each may be given as a `"#rrggbb"` string instead. OKLCH: `l` is 0 to 1 lightness, `c` is chroma (0 grey, about 0.37 max), `h` is hue in degrees. The file names no theme: the slug in its own path is the theme name live-tokens-create-theme intends, or any label when this skill runs alone. `canvasGradient` is an optional boolean, see below.
47
+ A base color is the one color a palette's whole ramp derives from.
48
+
49
+ - `baseColors`: all ten required. Each is an OKLCH triple or a `"#rrggbb"` string in its place. `l` is lightness, above 0 and below 1. `c` is chroma, 0 for grey and at most 0.4. `h` is hue in degrees.
50
+ - `scheme`: `"light"` or `"dark"`.
51
+ - `canvasGradient` (optional): a boolean, default off. See Canvas sky and shadows.
52
+ - `harmony` (optional): `{ "mode": "<mode>" }`, a record of the harmony the base colors follow. The CLI validates the mode and derives nothing from it. The modes are the ones the Harmony section names, plus `custom`.
48
53
 
49
54
  Roles: **Brand** is the dominant chromatic identity; **Accent** the supporting color; **Special** the rare expressive tertiary; **Canvas** is the page background verbatim; **Neutral** drives neutral surfaces and body text; **Alternate** is the second near-grey family; the four statuses are conventional signals.
50
55
 
51
- ## Chroma budget: color is inversely proportional to area
56
+ ## Chroma budget
57
+
58
+ The more area a palette covers, the less chroma it gets.
52
59
 
53
60
  | Tier | Palettes | Chroma |
54
61
  |---|---|---|
55
62
  | Ground (about 60% of every screen) | Neutral, Alternate | C 0.008 to 0.02 |
56
- | Canvas (the largest single area) | Canvas | Per the commitment levels below, C 0.02 to 0.14 |
63
+ | Canvas (the largest single area) | Canvas | C 0.02 to 0.14, by commitment level (see Canvas commitment) |
57
64
  | Dominant chromatic (about 30%) | Brand | C 0.10 to 0.20 |
58
65
  | Garnish (about 10%) | Accent, Special | may exceed Brand; at most one at the gamut cap for its hue (see Gamut guardrails) |
59
66
  | Conditional | Info, Success, Warning, Danger | C 0.12 to 0.19 |
60
67
 
61
- A good theme reads as 3 or 4 hue families on screen, never 10. Neutral and Alternate stay near-grey but tinted toward the theme (Neutral near Brand's hue; Alternate offset 15 to 60 degrees, or a warm/cool counterpoint), never pure C = 0 unless an anchor calls for it.
68
+ A good theme reads as 3 or 4 hue families on screen, never 10. Neutral and Alternate stay near-grey, tinted toward the theme: Neutral near Brand's hue, Alternate offset 15 to 60 degrees or a warm/cool counterpoint. Pure C = 0 only when an anchor calls for it.
62
69
 
63
- ## Per-role bands
70
+ ## Per-role ranges
64
71
 
65
72
  | Base color | Light scheme | Dark scheme | Hue |
66
73
  |---|---|---|---|
@@ -74,25 +81,25 @@ A good theme reads as 3 or 4 hue families on screen, never 10. Neutral and Alter
74
81
  | Warning | L 0.75 or higher (vivid yellow must be light) | same | H 70 to 90 |
75
82
  | Danger | shared status L, C 0.15 to 0.20 | same | H 20 to 30 |
76
83
 
77
- **The canvas carries the theme's identity, so commit to it.** The page background is the largest area on screen and the strongest difference between themes; a timid canvas makes every theme look the same. Below C 0.015 at L 0.95 a tint is imperceptible, which makes near-white a deliberate choice for clean or minimal intents and never the default. Three levels of commitment:
84
+ Three rules cross every role:
85
+
86
+ - A dark scheme transforms every base color: each chromatic one lightens to L 0.75 to 0.85 and drops about a third of its chroma, because saturated color vibrates on dark grounds.
87
+ - Equal lightness reads as equal weight: give the four statuses one shared L, and do the same for Brand and Accent when they should balance.
88
+ - Status hues never rotate with the harmony; only their L and C adapt to the mood.
89
+
90
+ **The canvas carries the theme's identity, so commit to it.** The page background is the largest area on screen and the strongest difference between themes; a timid canvas makes every theme look the same. Below C 0.015 at L 0.95 a tint is imperceptible, so near-white is a choice for a clean or minimal intent, never a default. The canvas sits in one of three ranges:
78
91
 
79
92
  1. *Tinted paper* (most UI intents): C 0.02 to 0.06, with L down to 0.92 where the hue needs room.
80
93
  2. *Colored ground* (expressive intents): L 0.85 to 0.92 at C 0.05 to 0.10. The page is unmistakably mint, parchment, sky.
81
94
  3. *Full-color ground* (holiday and statement intents): the canvas is the theme color, like a red Christmas page with green and gold on it. Keep canvas L at or below 0.48 or at or above 0.85 so text has somewhere to go; the contrast gate enforces legibility either way.
82
95
 
83
- Also:
84
-
85
- - Blue tints cap very low at high L (H 264 at L 0.95 barely reaches C 0.03): lower L for a blue canvas rather than fighting the ceiling. Yellow, green, and cream tint generously at high L.
86
- - When generating a set of themes, make the canvases pairwise distinct in hue or in L. Two light themes both near (0.97, 0.01) read as one theme with different buttons.
87
- - A dark scheme transforms every base color: each chromatic one lightens to L 0.75 to 0.85 and drops about a third of its chroma, because saturated color vibrates on dark grounds.
88
- - Equal lightness reads as equal weight: give the four statuses one shared L, and do the same for Brand and Accent when they should balance.
89
- - Status hues never rotate with the harmony; only their L and C adapt to the mood.
96
+ Blue tints cap very low at high L (H 264 at L 0.95 barely reaches C 0.03), so lower L for a blue canvas rather than fighting the ceiling; yellow, green, and cream tint generously at high L. Across a set of themes, make the canvases pairwise distinct in hue or in L. Two light themes both near (0.97, 0.01) read as one theme with different buttons.
90
97
 
91
98
  ## Mood dials
92
99
 
93
- Pleasantness rises with lightness (strongly) and saturation (weakly); energy rises with saturation; drama rises with dark plus saturated. Dominance, the third axis, is carried by surface contrast, type weight, and tightness rather than by color at all.
100
+ Pleasantness rises with lightness (strongly) and saturation (weakly); energy rises with saturation; drama rises with dark plus saturated. Dominance, the third axis, is carried by surface contrast, type weight, and tightness rather than by color.
94
101
 
95
- That is the whole mechanism, and one dial moves without a reference: warm is hues 20 to 110 plus pink 290 to 360, cool is 140 to 290. For an intent that names a feeling, read `references/color-anchors.md` instead of guessing the dial settings.
102
+ Warm is hues 20 to 110 plus pink 290 to 360; cool is 140 to 290. For an intent that names a feeling, read `references/color-anchors.md` rather than guessing the dial settings.
96
103
 
97
104
  Avoid mid-lightness yellow-green (H 100 to 120 at L 0.5 to 0.7, C about 0.1) unless the intent asks for olive or toxic.
98
105
 
@@ -115,26 +122,28 @@ Hue offsets from Brand: complementary +180; split-complementary +150/+210; triad
115
122
 
116
123
  ## Canvas sky and shadows
117
124
 
118
- `"canvasGradient": true` renders the page background as a vertical gradient from the Canvas ramp. Default off. Turn it on only when the intent evokes atmosphere (sky, night, dusk, glow, underwater) or asks for a gradient outright; keep it off for crisp, flat, minimal, or corporate intents and whenever in doubt, because a sky on every theme stops meaning anything. It needs a committed canvas (level 2 or 3); at the ramp edge the engine skips it and says so. Say why it is on, in one line.
125
+ `"canvasGradient": true` renders the page background as a vertical gradient from the Canvas ramp. Default off. Turn it on only when the intent evokes atmosphere (sky, night, dusk, glow, underwater) or asks for a gradient outright; keep it off for crisp, flat, minimal, or corporate intents and whenever in doubt, because a sky on every theme stops meaning anything. It needs a Canvas base color with L above 0.10 and below 0.90. Outside that range the engine skips it and says so. Say why it is on, in one line.
119
126
 
120
127
  Shadow opacity derives from Canvas lightness and re-derives on every run, so there is nothing to choose. When shadows read heavy or muddy, raise the Canvas base color's L.
121
128
 
122
- ## Refining the color of a theme that exists
129
+ ## Refining a theme's color
130
+
131
+ "Warmer", "calmer", "more contrast" arrive against a theme that is already open, and the answer is a new base color file. Edit `scratch/<slug>-base-colors.json` when it is still there. When it is not, recover the ten base colors from `src/live-tokens/data/themes/<slug>.json`: each one sits at `colorsAndType.editorConfigs.<Palette>.baseColor` as an OKLCH triple, and the Canvas base color's lightness gives the scheme. Rebuild the base color file from those values, move the dial the user named, and re-run.
123
132
 
124
- "Warmer", "calmer", "more contrast" arrive against a theme that is already open, and the answer is a new base color file. Edit `scratch/<slug>-base-colors.json` when it is still there. When it is not, recover the base colors: `src/live-tokens/data/themes/<slug>.json` holds each one verbatim at `colorsAndType.editorConfigs.<Palette>.baseColor` as `{l, c, h}`, and the Canvas base color's lightness gives the scheme. Rebuild the base color file from those ten values, move the dial the user named, and re-run. A re-run replaces the buffer's whole color state, including palette edits made in the editor since the last run, so say so once when iterating; a Save or a `save-theme` run keeps the result.
133
+ A re-run replaces the buffer's palette state, including palette edits made in the editor since the last run. Swatch gradients tuned in the editor carry through, and the report says which. Say so once when iterating.
125
134
 
126
135
  One adjective moves one dial. Warmer and cooler rotate hue; calmer and louder move chroma; lighter, darker, and moodier move Canvas L and the scheme; more contrast widens the L gap between Canvas and Brand and takes chroma out of the ground rather than adding it to the garnish. Leave every base color the user did not name alone, because a refinement that re-rolls the whole palette reads as a different theme and loses the thing they liked.
127
136
 
128
137
  ## Scope
129
138
 
130
- Color only. Type and geometry are untouched: `set-colors` replaces the color
131
- state in the unsaved buffer and carries every other value in it forward. Save
132
- the open theme in the editor, or run `save-theme`, to keep the result; Adopt
133
- ships it.
139
+ Color only. Fonts, geometry, saved themes, `tokens.css`, and `fonts.css` are
140
+ untouched: `set-colors` replaces the color state in the buffer and carries
141
+ every other value in it forward. `save-theme` keeps the result; Adopt ships it.
134
142
 
135
143
  ## Verify
136
144
 
137
- - The CLI exits 0 with every check passing (auto-corrected is fine), and the report names the layer it carried the rest of the look forward from.
138
- - The app (dev server running) shows the new palette after a reload. The editor's Theme panel marks the open theme unsaved, unless the run was a dry one or the report says the layer under the buffer, the open theme or the package default, already holds these colors.
145
+ - The CLI exits 0 with every check passing (auto-corrected is fine), and the report names which layer the non-color values came from.
146
+ - The app (dev server running) shows the new palette.
147
+ - The editor's Theme panel marks the open theme as edited. A dry run marks nothing, and neither does a run whose report says the open theme or the shipped default already holds these colors.
139
148
  - The canvas is committed: on screen it reads as the theme's color rather than as generic near-white.
140
149
  - To revert, re-run with the previous base color file, or load the open theme again to discard the buffer.