@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
@@ -1,6 +1,6 @@
1
1
  # Extension: intrinsics
2
2
 
3
- Some components expose **structural or display choices** that aren't token values: an alignment (start / center), an element's visibility (show / hide), a layout position. These ride a bespoke `<select>` or checkbox you author in an editor snippet, not the generic token grid, so they don't belong in `allTokens`. Toggle and most components have none. SectionDivider is the worked example (alignment, hairline position, eyebrow / description visibility).
3
+ Some components expose **structural or display choices** that are not token values: an alignment (start / center), an element's visibility (show / hide), a layout position. These ride a custom `<select>` or checkbox authored in an editor snippet, outside the generic token grid, so they do not belong in `allTokens`. Toggle and most components have none. SectionDivider is the worked example (alignment, hairline position, eyebrow / description visibility).
4
4
 
5
5
  An intrinsic still cascades through a CSS custom property with a default in the runtime `:global(:root)`. The trap: that default now lives in two places, the runtime `:global(:root)` AND the editor's read-back getter. When they disagree the control displays a state the page never renders, and a native `<select>` won't even fire `onchange` to write the "change" the user thinks they made. `:global(:root)` is the source of truth.
6
6
 
@@ -57,4 +57,4 @@ Declare intrinsics so the editor and the contract test stay honest:
57
57
  });
58
58
  ```
59
59
 
60
- Use `normalize` only when two raw values render identically and the dropdown lists just one (SectionDivider folds `above-description` into `below-label`). Properties that look like intrinsics but aren't: preview-only props with no persistence (a size selector that only changes the demo), `setComponentConfig` editor metadata (Dialog's button variants), and token-valued selects (a control choosing between two tokens). None carry a duplicated runtime default, so none need an `IntrinsicSpec`.
60
+ Use `normalize` only when two raw values render identically and the dropdown lists one (SectionDivider folds `above-description` into `below-label`). Properties that resemble intrinsics but are not: preview-only props with no persistence (a size selector that only changes the demo), `setComponentConfig` editor metadata (Dialog's button variants), and token-valued selects (a control choosing between two tokens). None carry a duplicated runtime default, so none need an `IntrinsicSpec`.
@@ -1,6 +1,6 @@
1
1
  # Extension: linked siblings
2
2
 
3
- Read this when your component has more than one variant and those variants share base properties (surface, radius, padding) that should move together. Toggle and SectionDivider have no linked tokens and skip all of it.
3
+ Read this when the component has more than one variant and those variants share base properties (surface, radius, padding) that should move together. Toggle and SectionDivider have no linked tokens and skip all of it.
4
4
 
5
5
  Toggle's tokens are flat per state. Most multi-variant components (Badge, Card, SegmentedControl) share base properties across variants and surface that equality via a *linked block*: one edit propagates to every variant, while per-variant properties stay independent. Five additions to the Toggle pattern; see `BadgeEditor.svelte` in `node_modules` for the full file.
6
6
 
@@ -67,4 +67,4 @@ Toggle's tokens are flat per state. Most multi-variant components (Badge, Card,
67
67
  </ComponentEditorBase>
68
68
  ```
69
69
 
70
- Single-variant components with multi-state linked tokens still set `canBeLinked` + `linkableContexts`, but skip `buildSiblings` and the `{#each}` loop. Components with no linked tokens (Toggle, SectionDivider) skip all five steps — `ComponentEditorBase` renders fine without a `{linked}` prop.
70
+ Single-variant components with multi-state linked tokens still set `canBeLinked` + `linkableContexts`, but skip `buildSiblings` and the `{#each}` loop. Components with no linked tokens (Toggle, SectionDivider) skip all five steps; `ComponentEditorBase` renders without a `{linked}` prop.
@@ -3,7 +3,7 @@
3
3
  Sketch mode blanks each part's real background and border and repaints them onto
4
4
  `::before`/`::after` through a shared noise field. It draws a fixed set of
5
5
  selectors: the shipped components, plus four classes reserved for everyone else.
6
- Your component is skipped until it opts in, so it stays crisp while the page
6
+ A component is skipped until it opts in, so it stays crisp while the page
7
7
  around it goes hand-drawn.
8
8
 
9
9
  The whole contract is CSS. There is nothing to import and no function to call:
@@ -15,7 +15,7 @@ and naming five custom properties.
15
15
  An opted-in element is no longer painting itself. On every drawn part the layer
16
16
  forces:
17
17
 
18
- | It forces | So you must |
18
+ | It forces | So the component must |
19
19
  |----------------------------------------------|----------------------------------------------------------|
20
20
  | `background: transparent !important` | Name the fill again as `--sketch-fill` |
21
21
  | `border-color: transparent !important` | Name the outline again as `--sketch-stroke` |
@@ -40,8 +40,8 @@ A card and a modal are both containers; a badge and a pill are both chips.
40
40
  | `sketch-chip` | A small box. Finer fill mask, more rotation, less travel. |
41
41
  | `sketch-rule` | A line rather than a box. No rotation, no rounded ends. |
42
42
 
43
- The class opts you in and nothing more. It names no colour, so the layer emits
44
- no rule for it and whatever your component declares survives.
43
+ The class opts the component in and nothing more. It names no colour, so the layer emits
44
+ no rule for it and whatever the component declares survives.
45
45
 
46
46
  ```svelte
47
47
  <div class="mywidget sketch-container {variant}">…</div>
@@ -71,8 +71,8 @@ picks up the card's corners.
71
71
 
72
72
  ## Variants, states and inner parts
73
73
 
74
- Nothing competes with you for these values, so every case is one more
75
- declaration at the specificity you already use.
74
+ Nothing competes for these values, so every case is one more
75
+ declaration at the specificity already in use.
76
76
 
77
77
  ```css
78
78
  .mywidget.danger { --sketch-fill: var(--mywidget-danger-surface); }
@@ -86,7 +86,7 @@ no hover at all once the real background is transparent.
86
86
 
87
87
  An inner part that carries its own surface (a header strip, a footer) takes its
88
88
  own class and its own five values. The class is easy to forget, because the part
89
- already has its own values and looks finished without it — a part carrying only
89
+ already has its own values and looks finished without it. A part carrying only
90
90
  the values is left crisp, and reads as a hard-edged rectangle dropped inside a
91
91
  drawn box. No checker sees it. Where such a part draws no outline, bind the
92
92
  hatch ink to the ink its **parent** is outlined in, so the component reads as one
@@ -124,7 +124,7 @@ colour or an image, so `--sketch-fill` accepts either.
124
124
  - **An element that owns `::before` or `::after`.** The layer claims both. A
125
125
  shimmer, a caret or a decorative arrow on the opted-in element is gone.
126
126
  - **A shipped part's selector** (`.card`, `.panel`). Borrowing one to get drawn
127
- works, but it hands your component that part's colours and its damping, and it
127
+ works, but it hands the component that part's colours and its damping, and it
128
128
  is package-internal. The reserved classes are the contract.
129
129
 
130
130
  ## Rules, which are not boxes
@@ -143,12 +143,12 @@ Make the rule an element, give it `sketch-rule`, and name its ink as the fill.
143
143
  }
144
144
  ```
145
145
 
146
- ## Media inside your component
146
+ ## Media inside the component
147
147
 
148
148
  A drawn part's `overflow` is visible so the fill and outline can travel past the
149
149
  box. A background that bleeds is the effect working. An image that bleeds is
150
150
  not, since it keeps square corners while the part around it turns. Media running
151
- to your component's edge has to carry the corners itself:
151
+ to the component's edge has to carry the corners itself:
152
152
 
153
153
  ```css
154
154
  .mywidget-cover {
@@ -166,7 +166,7 @@ high spread the crop is the mean rather than an exact trace of the drawn edge.
166
166
 
167
167
  Icons and inline SVG take the wobble directly, since a glyph has no box to
168
168
  redraw. Body type is left alone deliberately: an icon is a shape and survives a
169
- wobble, a paragraph is not. You opt into none of this; it applies to every
169
+ wobble, a paragraph is not. Nothing opts into this; it applies to every
170
170
  `[class*="fa-"]` and every `svg` under the scope.
171
171
 
172
172
  `--sketch-icon-off` names what a subtree's glyphs are drawn with instead. It
@@ -190,7 +190,7 @@ soft bank before reaching for `none`.
190
190
  A component authored inside the package does not use the reserved classes. Add a
191
191
  `PartSpec` row to `PART_SPECS` in `src/editor/core/sketch/sketchLayer.ts`
192
192
  instead, which is keyed to the component's own token stem and gets the shipped
193
- damping. `sketchPartTokens.test.ts` then holds you to it: every colour the layer
193
+ damping. `sketchPartTokens.test.ts` then holds the component to it: every colour the layer
194
194
  paints must be one the component itself assigns to that same element, checked
195
195
  against the compiled `<style>` block.
196
196
 
@@ -44,6 +44,7 @@ to that list, so the two cannot drift apart.
44
44
  | `-border-width` | Stroke thickness (used even when CSS uses `outline:`) |
45
45
  | `-thickness` | Alternative to `-width` when fallback siblings would collide |
46
46
  | `-accent-width` | An accent bar's thickness |
47
+ | `-indicator-width` | An indicator's thickness, moved with `-accent-width` |
47
48
  | `-hairline-thickness` | A hairline rule's thickness |
48
49
  | `-dot-size` | A dot indicator's diameter |
49
50
  | `-divider-width` | A divider's thickness |
@@ -80,6 +81,6 @@ when one fits; a stroke is `-border-width` even where the CSS says `outline:`.
80
81
  | `-line-height` | Line height |
81
82
  | `-letter-spacing` | Letter spacing |
82
83
 
83
- A suffix you need that is not here is either a rename away from one that is, or
84
+ A suffix that is not here is either a rename away from one that is, or
84
85
  an issue against `@motion-proto/live-tokens`. Inventing one costs the token its
85
86
  picker: the editor falls back to a plain text input.
@@ -0,0 +1,187 @@
1
+ ---
2
+ name: live-tokens-create-page
3
+ description: Create a page in a @motion-proto/live-tokens project from the shipped components at their defaults and the theme's text styles. Use when the user asks for a page or a route. Use when the user asks to change the layout of a page. Edits page files and the route table. For a choice between two components, read live-tokens-pick-component. For a component the catalogue lacks, read live-tokens-create-component. For a theme change, read live-tokens-create-theme.
4
+ ---
5
+
6
+ # Creating a page in a live-tokens project
7
+
8
+ Assemble the page from the shipped components at their defaults and the theme's text styles. A change to a component is made in the components editor at `/live-tokens/components` and reaches every page. A change to the theme is made with **live-tokens-create-theme**.
9
+
10
+ ## Workflow
11
+
12
+ 1. Read the project first: the existing pages and where they live, how `App.svelte` wires routes, `--columns-count` in `tokens.css`, and the catalogue from `npx live-tokens components`.
13
+ 2. Read the page top to bottom and name each section by its purpose. Take each section's column spans from the Page layouts table.
14
+ 3. Build the page grid and place each section on it. Separate the sections with the smallest difference that separates them.
15
+ 4. Give each section its container from the Containers by purpose list.
16
+ 5. Match a shipped component to each need. When two could fit, read **live-tokens-pick-component**. When nothing in the catalogue fits, read **live-tokens-create-component**.
17
+ 6. Write the page CSS in design tokens.
18
+ 7. Set the hierarchy: one text style per element, the shipped size on every control, one primary action, and one space step per position.
19
+ 8. Add the route, with a lazy import and the source path.
20
+ 9. Run **live-tokens-check-compliance**, then check the rendered page.
21
+ 10. Reply with the sections and the layout each took, the components placed, the route, and the compliance result.
22
+
23
+ ## Layout
24
+
25
+ ### Page layouts
26
+
27
+ Decide the sections before the columns. Read the page top to bottom and name each section by its purpose: what the user reads, types into, or presses. Each section is a row of the page grid. Take the column spans from the layout that matches the reader's task.
28
+
29
+ | Layout | Use when | Column spans |
30
+ |---|---|---|
31
+ | Stacked sections | The reader moves top to bottom: an opening, one section per topic, a close; or a stage, its inputs, and a toolbar. | Each section spans all columns. Copy spans half (6 of 12). |
32
+ | Main with a supporting pane | One region is the work and the other adjusts or describes it. | Main two thirds (8), pane one third (4). |
33
+ | List with detail | The reader picks an item from a list and inspects it. | List one third (4), detail two thirds (8). |
34
+ | Grid of equals | The reader compares or scans items of one kind. | Equal spans. Up to seven per section. |
35
+ | Single column | The reader fills a form or reads at length. | Half the columns (6), centered. |
36
+
37
+ The stage is the canvas, player, or strip the work is about. Stretch a section's containers to one height (`align-items: stretch`) so their bottom edges align. Below the scaffold's 768px breakpoint, a section's columns stack in reading order.
38
+
39
+ ### Grid
40
+
41
+ The page is the column grid: `display: grid`, `grid-template-columns: repeat(var(--columns-count), 1fr)`, `column-gap: var(--columns-gutter)`, `max-width: var(--columns-max-width)`, `margin: 0 auto`. Each section spans it with `grid-column: 1 / -1`.
42
+
43
+ To place a section's children at page-column positions:
44
+
45
+ 1. Read `--columns-count` in the project's `tokens.css`.
46
+ 2. Span the parent grid with `grid-column: 1 / -1`.
47
+ 3. Redeclare `repeat(var(--columns-count), 1fr)` with `column-gap: var(--columns-gutter)`.
48
+ 4. Place each child by page-column numbers.
49
+
50
+ A grid that follows the page columns takes `var(--columns-count)` or a `calc()` of it as its count, so it stays in step with `ColumnsOverlay`. A local grid of two or three equal columns writes its own count. A column number in `grid-column` is fixed to the count read in step 1.
51
+
52
+ ### Separation
53
+
54
+ The page shows one thing, and every other element stays out of its way. Each element that is not content costs attention: a hairline, a border, a header bar, a shadow. Keep an element only when it serves a purpose no other element serves.
55
+
56
+ Separate elements with the smallest difference that separates them: space first, then a hairline, then a second surface. Use one separator at a time. Two heavy borders side by side make a third shape between them, and a section of containers with borders and header bars reads as a set of posters.
57
+
58
+ Color each element by its layer.
59
+
60
+ | Layer | Color |
61
+ |---|---|
62
+ | Content | `--text-primary`, or the color `site.css` gives the element |
63
+ | Label | `--text-secondary` |
64
+ | Chrome | `--border-neutral` |
65
+ | Overlay on content, such as a grid or a selection | `--border-brand`, which stays visible on any pixel |
66
+
67
+ Show related items side by side when the width permits. A line of copy runs 45 to 90 characters; the copy span in Page layouts holds that at body size. On a tool page the stage is the content and each control is chrome, so the stage takes the space.
68
+
69
+ `references/layout-sources.md` names the sources for these laws.
70
+
71
+ ## Containers by purpose
72
+
73
+ - `Panel` is a stage: a canvas, a player, a preview. `minHeight` holds its height while what it shows changes.
74
+ - An empty stage shows a heading that names the condition and one `secondary` Button that fills it. An error goes in a `Callout variant="danger"`.
75
+ - `Card` is a titled block of content. Its `title` prop is the title, and the card's own tokens type it.
76
+ - A container in a tool UI labels itself: `Card variant="bare"` with the label in the body as `--body-sm-*` in `--text-secondary`.
77
+ - A form puts the essential fields first and the secondary fields in a `CollapsibleSection`. Its actions sit on the bottom edge.
78
+ - A row of fields is a flex row with `gap: var(--space-20)`. Each field's wrapper takes `flex: 1`.
79
+ - A toolbar is a flex row of Buttons on the section's bottom edge, with no container around it. Group the Buttons left and right with `justify-content: space-between`, the primary last. A `danger` Button sits apart from the group it could be mistaken for.
80
+ - A vertical stack of Buttons sets `fullWidth` on each Button. A row omits it.
81
+ - `MenuSelect` renders its list open. For a picker, toggle it from a Button with a trailing chevron (`icon="fa-solid fa-chevron-down" iconPosition="right"`) and position the list under the Button at `top: 100%` with a `--space-*` margin.
82
+
83
+ ## Components
84
+
85
+ - Use a shipped component when one fits. Import it from `@motion-proto/live-tokens/components/<Name>.svelte`.
86
+ - `npx live-tokens components <id>` prints the declared props, the values each union accepts, and the usage comment. `--json` prints the same as data. The list includes the project's own components.
87
+ - Pass only the props a component declares.
88
+ - A shipped component fills its parent. To size one, size the element the page wraps it in.
89
+ - 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.
90
+ - Text inside a `Card` or a `CollapsibleSection` takes the container's type on nested `p`, `ul`, `ol`, and `li`. When the page owns that type, as full-bleed media does, pass `prose={false}`.
91
+
92
+ ## Tokens
93
+
94
+ - When a design token exists for a value, page CSS takes the token as `var(--token)`. That holds in the `<style>` block, an inline `style=` attribute, and a `style:` directive.
95
+ - A width is a span of page columns. The Layout section gives the grid.
96
+ - A height follows the content. A stage's `minHeight` is the one fixed height, set from what the stage must show.
97
+ - A value that comes from data, such as a sheet's padding in pixels or a chart's scale, is set through a `{}` expression.
98
+
99
+ ## Hierarchy
100
+
101
+ ### Type
102
+
103
+ One text style per element. A text style has five axes: `-font-family`, `-font-size`, `-font-weight`, `-line-height`, and `-letter-spacing`. Set all five from the one style.
104
+
105
+ | Element | Style |
106
+ |---|---|
107
+ | Page title | `h1` in `--heading-xl-*` |
108
+ | Section title | `h2` in `--heading-lg-*`, or `SectionDivider variant="sm"` |
109
+ | Card title | the Card `title` prop |
110
+ | Label above a group | `--body-sm-*` in `--text-secondary` |
111
+ | Body | `p` in `--body-md-*` |
112
+ | Secondary line | `--body-sm-*` in `--text-secondary` |
113
+ | Count, status, read-out | `--body-sm-*` in `--text-primary` |
114
+ | Command or value | `code` in `--code-*` |
115
+
116
+ Use the semantic element for each place: one `h1`, an `h2` for each section, `h3` inside a section, `p` for copy. Heading levels run in order with no skipped level. `site.css` types bare `h1` to `h4`, `p`, `code`, `pre`, and list items from these styles, so the tag carries the style. Type an element only when the table gives its tag a different style. A weight alone, on `strong` or a list marker, is the one axis a page sets by itself. A page shows at most two weights.
117
+
118
+ ### Size
119
+
120
+ Omit `size` on every control and container. The shipped default is the page's size.
121
+
122
+ ### Emphasis
123
+
124
+ One `primary` Button per page: the action that completes the page's main task. An action that supports that task is `secondary`. An action unrelated to the task, or informational, is `outline`. An action that destroys saved work is `danger`.
125
+
126
+ In a row of actions the primary sits last, on the right. Up to four actions are individual Buttons. Five or more collapse into a `MenuSelect` behind one Button.
127
+
128
+ ### Spacing
129
+
130
+ Each position takes one step of the `--space-*` scale. Space inside a group is smaller than space between groups. A shipped component carries its own inner spacing; the table names the space the page draws.
131
+
132
+ | Position | Step |
133
+ |---|---|
134
+ | Between controls in a row | `--space-8` |
135
+ | Inside a wrapper the page draws | `--space-16` |
136
+ | Between fields in a form | `--space-20` |
137
+ | Between containers in a section | `--columns-gutter` across, `--space-24` down |
138
+ | Between sections | `--space-16` above a hairline |
139
+ | Page title to first section | `--space-24`, no hairline |
140
+ | Page margin | `--space-32` |
141
+
142
+ Every section after the first opens with a hairline: `padding-top: var(--space-16)` and `border-top: var(--border-width-1) solid var(--border-neutral)`. The hairline separates, so the gap between sections is smaller than the gap between the containers inside them. A section's edge is the hairline alone.
143
+
144
+ ## Routing
145
+
146
+ Add the route the way `App.svelte` already wires routes.
147
+
148
+ - `<LiveTokensRouter pages={...}>`: add a `pages` entry with `lazy: () => import('./YourPage.svelte')` and `source: 'src/...'`. Add `label` and `icon` to show the page in the nav rail; omit `label` to keep the route reachable by URL alone. For a `/:id`, a path prefix, or a gated page, add `resolve(path) => RouteEntry | null` beside `pages`. The entry fields are the same.
149
+ - Manual `<LiveEditorOverlay>`: dispatch with `$derived.by(() => import(...))` and register the route's source in `pageSources={...}`.
150
+
151
+ Import the page with `lazy`, so page CSS stays off the editor routes. Import `site.css` from each page's `<script>` block for the same reason. `source` is what makes Page Source work. A page route sits outside `/live-tokens/*`, the namespace of the package's own routes, where `Editor` and `ComponentEditorPage` mount.
152
+
153
+ ```svelte
154
+ const pages = {
155
+ '/pricing': {
156
+ lazy: () => import('./pages/Pricing.svelte'),
157
+ source: 'src/pages/Pricing.svelte',
158
+ label: 'Pricing',
159
+ icon: 'fa-tag',
160
+ },
161
+ };
162
+ ```
163
+
164
+ ## Verify
165
+
166
+ Run **live-tokens-check-compliance**. Its report carries both checkers' findings by rule, and **live-tokens-fix-findings** takes the fix list. Repeat until the page is clean.
167
+
168
+ The checkers cannot see a layout. Open the page at the width it is built for and check each line below.
169
+
170
+ - The first section holds what the user came for.
171
+ - One `h1`. Heading levels run in order with no skipped level.
172
+ - No label is larger than the page's body copy.
173
+ - A line of copy runs 45 to 90 characters.
174
+ - The containers in a section align at the bottom.
175
+ - Every control stays inside its wrapper. A `width: 100%` field takes `box-sizing: border-box`.
176
+ - The actions sit where the eye goes last, with the one primary at the end.
177
+ - Every row of actions holds an action that leaves without committing.
178
+ - An action that destroys saved work confirms in a `Dialog`.
179
+ - An action that runs longer than a moment shows progress in a `ProgressBar` or a `Notification`.
180
+ - Every field has a default, and Reset restores it.
181
+ - Secondary settings sit in a `CollapsibleSection`. Every control is in view.
182
+ - Labels use the user's words, such as "Export slices".
183
+ - Every `img` has `alt` text. Focus order follows the reading order.
184
+
185
+ `references/interaction-sources.md` names the sources for these checks.
186
+
187
+ Then read the page from a distance: the sections and their edges are the only shapes that show. Then read it closely. For each border, header bar, and container, ask whether the page loses information when the element is removed. When the answer is no, remove the element. Find the element a reader sees first, second, and third, and confirm that is the reading order the page needs.
@@ -0,0 +1,66 @@
1
+ # Interaction sources
2
+
3
+ Read this when a Verify check or an emphasis rule in SKILL.md needs its reason.
4
+ Each principle below is held by one of three parties. A shipped component
5
+ holds it when the component's own design answers it, so the page's rule is
6
+ the component and pick-component names the test. The page holds it when only
7
+ the page can get it right, so SKILL.md states a read or the checker a rule.
8
+ The product holds it when no page decision touches it, and the row says so
9
+ to keep a later edit from reopening it.
10
+
11
+ ## Jakob Nielsen, ten usability heuristics
12
+
13
+ | Heuristic | Holder | Rule in SKILL.md, or the component |
14
+ |---|---|---|
15
+ | Visibility of system status | Page | Verify: an action that runs longer than a moment shows progress in a `ProgressBar` or a `Notification`. |
16
+ | Match between system and the real world | Page | Verify: labels use the user's words. |
17
+ | User control and freedom | Page | Verify: every row of actions holds an action that leaves without committing. Emphasis: an unrelated or informational action is `outline`. |
18
+ | Consistency and standards | Page | One size, one primary action, one text style per element. The components carry the rest. |
19
+ | Error prevention | Page | Verify: an action that destroys saved work confirms in a `Dialog`; the checker's `danger-without-dialog`. Verify: every field has a default and Reset restores it. |
20
+ | Recognition rather than recall | Component | `MenuSelect` lists the options; `Input` carries its label and hint; `Tooltip` defines in place. |
21
+ | Flexibility and efficiency of use | Product | Shortcuts and customisation are product decisions. |
22
+ | Aesthetic and minimalist design | Page | Layout: each element serves a purpose no other element serves. Verify: secondary settings sit in a `CollapsibleSection`. |
23
+ | Help users recognise, diagnose, and recover from errors | Component | `Input` carries the error line; `Callout variant="danger"` carries a section's. |
24
+ | Help and documentation | Product | Contextual help is a product decision. |
25
+
26
+ The complex-application version of the ten (Kaley, Nielsen Norman Group)
27
+ describes a tool with a stage and controls, which is the tool page SKILL.md
28
+ lays out. Its additions that the page holds: a wait past ten seconds shows
29
+ steps done and steps left, and the stage is the live preview of every
30
+ control. Undo, version history, and autosave are the product's.
31
+
32
+ ## Bruce Tognazzini, first principles of interaction design
33
+
34
+ | Principle | Holder | Rule in SKILL.md, or the component |
35
+ |---|---|---|
36
+ | Anticipation | Page | Layout: show related items side by side. |
37
+ | Colour | Component | `Callout`, `Badge`, and `Notification` carry an icon or text beside the colour. |
38
+ | Consistency | Page | One size, one primary action. |
39
+ | Defaults | Page | Verify: every field has a default and Reset restores it. |
40
+ | Discoverability | Page | Verify: every control is in view. |
41
+ | Explorable interfaces | Page | Verify: every row of actions holds an action that leaves without committing. |
42
+ | Fitts's law | Component | The shipped default is the large target; SKILL.md's one-size rule keeps it. A toolbar sits on the section's bottom edge. |
43
+ | Protect users' work | Page | Verify: an action that destroys saved work confirms in a `Dialog`. |
44
+ | Readability | Component | live-tokens-set-colors gates every text pair at WCAG AA. |
45
+ | Simplicity | Page | Verify: secondary settings sit in a `CollapsibleSection`; no capability is removed for the sake of simplicity. |
46
+ | Visible navigation | Component | `SideNavigation` follows the current path. |
47
+ | Aesthetics, Autonomy, Efficiency of the user, Human-interface objects, Latency reduction, Learnability, Metaphors, State | Product | Measured, engineered, or researched outside a page. |
48
+
49
+ Sources:
50
+
51
+ - Nielsen, 10 Usability Heuristics for User Interface Design (1994, updated 2024). https://www.nngroup.com/articles/ten-usability-heuristics/
52
+ - Kaley, 10 Usability Heuristics Applied to Complex Applications. https://www.nngroup.com/articles/usability-heuristics-complex-applications/
53
+ - Tognazzini, First Principles of Interaction Design (revised 2014). https://asktog.com/atc/principles-of-interaction-design/
54
+
55
+ ## W3C Web Accessibility Initiative
56
+
57
+ | Guidance | Holder | Rule in SKILL.md, or the component |
58
+ |---|---|---|
59
+ | Headings: one `h1`, levels in order, no skipped level | Page | Type: use the semantic element for each place. Verify: one `h1`, levels in order. |
60
+ | Images: text alternatives | Page | Verify: every `img` has `alt` text. |
61
+ | Focus order follows the reading order | Page | Verify: focus order follows the reading order. |
62
+ | Form labels and error messages | Component | `Input` carries its label, hint, and error line. |
63
+
64
+ https://www.w3.org/WAI/tutorials/page-structure/headings/
65
+ https://www.w3.org/WAI/tutorials/images/
66
+ https://www.w3.org/WAI/WCAG22/Understanding/focus-order.html
@@ -0,0 +1,87 @@
1
+ # Layout sources
2
+
3
+ Read this when a layout decision in SKILL.md needs its reason. Each law in the
4
+ Layout section comes from one of these sources. The sources are for layout and
5
+ hierarchy only. Do not take color or type opinions from them: the theme owns
6
+ those.
7
+
8
+ ## Edward Tufte
9
+
10
+ Tufte wrote about information graphics. His laws apply to a page because a page
11
+ is an information display with controls on it.
12
+
13
+ | Law | Statement | Rule in SKILL.md |
14
+ |---|---|---|
15
+ | Smallest effective difference | Make all visual distinctions as subtle as possible, but still clear and effective. | Separate with space first, then a hairline rule, then a second surface. |
16
+ | 1+1=3 | Two heavy marks side by side make a third mark: the space between them. | A section of containers with borders and header bars reads as a set of posters. |
17
+ | Layering and separation | Put data on top, labels next, and scaffolding faintest. | Content, labels, and chrome each take their own token. |
18
+ | Administrative debris | The metaphor for the interface is the information. Remove the chrome that the tool adds for itself. | The stage takes the space. Controls take their shipped default. |
19
+ | Spatial over temporal | Show information adjacent in space. A control that hides it stacks it in time. | Show related items side by side. Frames in a strip are small multiples. |
20
+ | Erase non-data ink | Remove each mark that carries no information. | The Verify question: does the page lose information when this element is removed? |
21
+ | Micro and macro readings | A good display reads at a distance and up close. | Verify from a distance, then closely. |
22
+
23
+ Sources:
24
+
25
+ - Envisioning Information (1990): layering and separation, small multiples, micro and macro. https://www.edwardtufte.com/book/envisioning-information/
26
+ - The Visual Display of Quantitative Information (1983): data-ink, chartjunk.
27
+ - iPhone interface design, edwardtufte.com notebook: administrative debris, spatial over temporal. https://www.edwardtufte.com/notebook/iphone-interface-design/
28
+
29
+ ## Josef Müller-Brockmann
30
+
31
+ Grid Systems in Graphic Design (1981) is the discipline behind the page column
32
+ grid. The grid does the separating, so an element needs no border to show
33
+ where it sits. His stated aim is compact planning, intelligibility, and
34
+ clarity. That is Tufte's aim in a typographer's words.
35
+
36
+ ## Refactoring UI
37
+
38
+ Adam Wathan and Steve Schoger, Refactoring UI (2018), turns both into working
39
+ rules for product screens:
40
+
41
+ - Put more space around a group than within it.
42
+ - Start with too much white space, then remove some.
43
+ - Use fewer borders. Separate with space, a shadow, or a second background.
44
+ - Emphasize by de-emphasizing the secondary content.
45
+ - Labels are a last resort.
46
+ - Keep a spacing scale where no two steps are closer than a quarter. The `--space-*` scale is that scale.
47
+
48
+ https://www.refactoringui.com/
49
+
50
+ ## Material Design 3, canonical layouts
51
+
52
+ The Page layouts table takes its rows from Material's canonical layouts.
53
+
54
+ | Layout | Statement | Row in SKILL.md |
55
+ |---|---|---|
56
+ | Supporting pane | The primary area takes about two thirds of the window; the secondary pane takes the rest. At compact width the pane moves below the main content. | Main with a supporting pane, two thirds and one third; the stacking sentence. |
57
+ | List-detail | The list and the detail of the selected item sit side by side at expanded width. | List with detail. |
58
+ | Feed | Equivalent items in an adaptive grid. | Grid of equals. |
59
+
60
+ https://m3.material.io/foundations/layout/canonical-examples/overview
61
+ https://developer.android.com/develop/adaptive-apps/guides/canonical-layouts
62
+
63
+ ## Cloudscape patterns
64
+
65
+ | Pattern | Statement | Rule in SKILL.md |
66
+ |---|---|---|
67
+ | Dashboard | Three areas top to bottom: overview, data, support. "Consider seven as the limit number for data representation." | Verify: the first section holds what the user came for. Grid of equals: up to seven per section. |
68
+ | Single-page create | One container; the essential fields first and few; secondary inputs in an expandable section; cancel then submit at the bottom. | Containers: a form. Single column. |
69
+ | Details page | The title with its actions, then a summary, then related blocks. | Stacked sections. |
70
+ | Empty state | A heading, an optional line, and one action. "Always provide an action." Errors go elsewhere. | Containers: an empty stage. |
71
+
72
+ https://cloudscape.design/patterns/general/service-dashboard/static-dashboard/
73
+ https://cloudscape.design/patterns/resource-management/create/single-page-create/
74
+ https://cloudscape.design/patterns/resource-management/details/details-page/
75
+ https://cloudscape.design/patterns/general/empty-states/
76
+
77
+ ## Matthew Butterick, line length
78
+
79
+ "45 to 90 characters per line, including spaces." The Separation paragraph and the Verify check carry the measure, and the half-width copy span holds it at body size.
80
+
81
+ https://practicaltypography.com/line-length.html
82
+
83
+ ## Nielsen Norman Group, proximity
84
+
85
+ "Proximity is one of the most important grouping principles and can overpower competing visual cues such as similarity of color or shape." Space inside a group is smaller than space between groups. An unrelated action inside a group is camouflaged, so a `danger` Button sits apart from the toolbar group.
86
+
87
+ https://www.nngroup.com/articles/gestalt-proximity/
@@ -1,55 +1,59 @@
1
1
  ---
2
2
  name: live-tokens-create-theme
3
- description: Create a complete live-tokens theme from a natural-language request by stating one design direction and routing a color intent, a type intent, and a geometry intent to live-tokens-set-colors, live-tokens-set-type, and live-tokens-set-geometry. Use whenever the user asks for a theme, look, vibe, or brand feel by mood, style, era, season, holiday, or hue; when they name only a color and want a theme around it; or when they refine a look across more than one dimension. Not for a single token (use the editor), and not for one dimension alone: color is live-tokens-set-colors, type is live-tokens-set-type, geometry is live-tokens-set-geometry.
3
+ description: Create or modify a complete live-tokens theme from a natural-language request. A theme has three dimensions: color, typography, and geometry. The skill adjusts design token values and their assignment to semantic properties to create a new theme. Derives one design direction and routes a color intent, a type intent, and a geometry intent to live-tokens-set-colors, live-tokens-set-type, and live-tokens-set-geometry. Use when the user asks for a theme, look, vibe, or brand feel by mood, style, era, season, holiday, or hue. Use when the user names only a color and wants a theme around it. Use when the user refines a theme across more than one dimension. For color, type, or geometry named on its own, read that set skill.
4
4
  ---
5
5
 
6
6
  # Creating a theme from a request
7
7
 
8
- A look is three decisions: color, type, and geometry. This skill reads the
9
- **request**, the user's own words, and states one **design direction**, a line
10
- or two that fixes all three. From it come three **intents**, one per dimension,
11
- each naming an outcome and never a value. Each goes to the contributing skill
12
- that owns that dimension, and their three reports come back as one **assembled
13
- report**, so the whole look comes from one reading.
8
+ A theme is built of three dimensions: color, type, and geometry. This skill
9
+ reads the user's prompt, the **request**, and derives the **design direction**,
10
+ a short summary covering three **intents**, one per dimension, each naming an
11
+ outcome rather than a value. Each set skill receives the design direction and
12
+ the intent for its own dimension as a goal, and reports back. The three reports
13
+ combine into one **assembled report** for the whole theme.
14
14
 
15
- Every contributing skill writes its dimension into the unsaved buffers the app
16
- already renders, and those three buffers are the **look**. This skill runs one
17
- CLI of its own, `save-theme`, which turns the look into the **theme**, the
18
- document at `themes/<slug>.json`, and opens it. Never hand-author theme JSON and
19
- never edit the data tree directly.
15
+ One **anchor** carries the direction across all three dimensions. It is a row
16
+ label that `references/design-directions.md` and each set skill list under the
17
+ same names: a feeling, an idiom, or an occasion. Naming it once points every set
18
+ skill at the same row of its own table.
20
19
 
21
- ## Workflow
20
+ Each set skill writes its dimension into the working buffers the app already
21
+ renders. This skill runs one CLI of its own, `save-theme`, which composes those
22
+ buffers into a **theme**, the document at `themes/<slug>.json`, and opens it.
23
+ Never hand-author theme JSON and never edit the data tree directly.
22
24
 
23
- 1. Read the request once and state the design direction to the user: the mood, the hue family, the scheme, and the type and geometry that mood implies. It fixes enough to derive the three intents in step 3, and it names the default where the request leaves a dimension open. Keep it to a line or two. Every step below keys off it.
24
- 2. Read `references/design-directions.md` and name the **anchor** the request matches: a feeling, an idiom, or an occasion that reference lists, each one fixing color, type, and geometry together. An idiom sets constraints and a feeling moves dials inside them, so a request matching both reads the idiom first. A request matching none takes the design direction alone.
25
- 3. State the three intents the design direction and the anchor imply, one line each: the color intent, the type intent, and the geometry intent. Each names an outcome. Pass the anchor's name with each one, because every contributing skill holds its own anchors for its own dimension under the same names. Never reach for an OKLCH triple, a font family, or a token on a contributing skill's behalf.
26
- 4. Invoke **live-tokens-set-colors** with the color intent. This step never skips: a theme request names a color identity, so color is the one dimension every look fixes.
27
- 5. Invoke **live-tokens-set-type** with the type intent. Skip only when the user asked to leave the type alone.
28
- 6. Invoke **live-tokens-set-geometry** with the geometry intent. Skip when the geometry intent is to leave the geometry alone.
29
- 7. Take the theme name from the design direction and run `npx live-tokens save-theme "<name>"`. It composes the three buffers into `themes/<slug>.json` and opens it, so nothing is left unsaved. `--dry-run` prints what it would write.
30
- 8. Assemble the three reports into the assembled report: the design direction, what each contributing skill changed, the theme `save-theme` wrote, and anything one of them flagged. Tell the user to look at the running app. Offer refinements (see Refining a look).
25
+ ## Workflow
31
26
 
32
- A set of themes runs steps 4 to 7 once per theme, with `--no-activate` on every
33
- save but the last, so each theme starts from the same live look.
27
+ 1. Read the request once and generate the design direction based on the prompt: the mood, and the color, typography, and geometry that mood implies. It describes the three intents for each set skill, and it names a default where the request leaves a dimension open. Keep it brief and clear. Every step below keys off it.
28
+ 2. Read `references/design-directions.md` and name the **anchor** the request matches: a feeling, idiom, or occasion the reference lists, each one fixing color, type, and geometry. An idiom sets constraints and a feeling moves dials inside them, so a request matching both reads the idiom first. A request matching none takes the design direction alone.
29
+ 3. Generate the three intents the design direction and the anchor imply, one line each: the color intent, the type intent, and the geometry intent. Each names an outcome. Pass the anchor and the matching intent to each set skill, because every set skill holds its own anchors for its own dimension under the same names. Never specify an OKLCH value, a font family, or a token on a set skill's behalf.
30
+ 4. Invoke **live-tokens-set-colors** with the anchor and the color intent. Skip only when the user asked to leave the color alone.
31
+ 5. Invoke **live-tokens-set-type** with the anchor and the type intent. Skip only when the user asked to leave the type alone.
32
+ 6. Invoke **live-tokens-set-geometry** with the anchor and the geometry intent. Skip when the geometry intent is to leave the geometry alone.
33
+ 7. Take the theme name from the design direction and run `npx live-tokens save-theme "<name>"`. It composes the buffers into `themes/<slug>.json` and loads it. `--dry-run` prints the file path and the layers instead. `--no-activate` writes the theme without loading it. A blank name and the name `default` exit 1. A name whose slug exists overwrites that theme in place. Adopt, in the editor, ships the theme to the site.
34
+ 8. Assemble the three set skill responses into the assembled report: the design direction, what each set skill changed, any dimension left alone, and anything one of them flagged. Review the result in the running app. Offer refinements (see Refining a theme).
34
35
 
35
- ## What each contributing skill owns
36
+ ## Set skill responsibilities
36
37
 
37
- Hand an outcome and the anchor's name. The mechanics stay where they are.
38
+ Invoke set skills with the anchor and the matching intent.
38
39
 
39
- | Dimension | Contributing skill | It decides |
40
+ | Dimension | Set skill | It decides |
40
41
  |---|---|---|
41
- | color | live-tokens-set-colors | ten base colors, the scheme, harmony, the canvas commitment, the contrast pass |
42
- | type | live-tokens-set-type | the two families, the form models behind them, the weights |
43
- | geometry | live-tokens-set-geometry | radius, padding, gap, and border-width moves, global or per component |
42
+ | color | live-tokens-set-colors | ten base colors, the scheme, harmony, the Canvas base color and its gradient, the contrast pass |
43
+ | type | live-tokens-set-type | the families for up to five slots, the form models behind them, the weights |
44
+ | geometry | live-tokens-set-geometry | radius, padding, gap, and border-width |
45
+
46
+ A dimension the request left open still gets an intent, taken from the anchor.
47
+ A dimension the request excludes gets no invocation at all, and the assembled report says which.
44
48
 
45
- A dimension the request leaves open still gets an intent, taken from the anchor.
46
- A dimension the request rules out gets no invocation at all, and the assembled
47
- report says which.
49
+ Component aliases and swatch gradients carry forward from the buffers by value
50
+ into the theme `save-theme` writes. At a set-colors run, gradients tuned in the
51
+ editor survive and stock ones rebuild from the new families.
48
52
 
49
- ## Refining a look
53
+ ## Refining a theme
50
54
 
51
- A refinement arrives against a theme that is already open, and one adjective
52
- usually names one dimension. Route it rather than re-reading the whole look:
55
+ A refinement operates on an existing theme, and one adjective usually names one
56
+ dimension. Route it to the matching set skill:
53
57
 
54
58
  | The user says | Goes to |
55
59
  |---|---|
@@ -57,24 +61,24 @@ usually names one dimension. Route it rather than re-reading the whole look:
57
61
  | more editorial, friendlier, more technical, a serif for headings | live-tokens-set-type |
58
62
  | rounder, sharper, pill buttons, tighter, airier, thicker borders | live-tokens-set-geometry |
59
63
 
64
+ The table gives examples. Route every refinement request, whether or not its
65
+ words appear there.
66
+
67
+ When no refinement is requested, the theme is complete.
68
+
60
69
  Keep this skill for a refinement that spans dimensions ("make it feel more
61
70
  serious"), or one that names no dimension at all. State a new design direction
62
71
  and route all three again.
63
72
 
64
- ## Files each step writes
65
-
66
- Color, type, and geometry each write an unsaved buffer, which the page already
67
- runs. `save-theme` composes the three into `themes/<slug>.json` and opens it,
68
- which clears the buffers; Adopt then ships the theme. Opening a theme never
69
- changes what the site ships. Only Adopt, in the editor, does that. Component
70
- aliases and gradients carry forward from the live look into the theme
71
- `save-theme` writes; user-tuned gradients survive, stock ones rebuild from the
72
- new families.
73
+ Feedback about a page or a component ("make the buttons bigger", "move the
74
+ hero up") is not a theme change: read **live-tokens-create-page** or
75
+ **live-tokens-create-component**. A request for the previous theme is met by
76
+ loading it from the editor's Theme panel; loading clears the buffers.
73
77
 
74
78
  ## Verify
75
79
 
76
- - Each contributing skill reports back, and `set-colors` exits 0 with every check passing (auto-corrected is fine).
80
+ - Each invoked set skill reports its result. When invoked, `set-colors` exits 0 with every check passing (auto-corrected is fine).
77
81
  - `save-theme` exits 0 and names the theme it wrote and opened.
78
- - The app (dev server running) shows the whole look after a reload, and the editor's Theme panel names that theme with no unsaved marker.
79
- - The assembled report names one design direction, and the three intents trace to it.
80
- - To return to the previous look, load the earlier theme from the Theme panel.
82
+ - The app (dev server running) shows the whole theme, and the editor's Theme panel names that theme with no pending changes.
83
+ - The assembled report names one design direction, and the three intents come from it.
84
+ - To return to the previous theme, load it from the Theme panel; loading clears the buffers too.