@motion-proto/live-tokens 0.73.0 → 0.75.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (196) hide show
  1. package/.claude/skills/live-tokens-check-compliance/SKILL.md +33 -38
  2. package/.claude/skills/live-tokens-create-component/SKILL copy.md +196 -0
  3. package/.claude/skills/live-tokens-create-component/SKILL.md +198 -146
  4. package/.claude/skills/live-tokens-create-component/references/contract-tests.md +95 -52
  5. package/.claude/skills/live-tokens-create-component/references/intrinsics.md +2 -2
  6. package/.claude/skills/live-tokens-create-component/references/linked-siblings.md +2 -2
  7. package/.claude/skills/live-tokens-create-component/references/sketch-mode.md +12 -12
  8. package/.claude/skills/live-tokens-create-component/references/token-naming.md +2 -1
  9. package/.claude/skills/live-tokens-create-page/SKILL.md +187 -0
  10. package/.claude/skills/live-tokens-create-page/references/interaction-sources.md +66 -0
  11. package/.claude/skills/live-tokens-create-page/references/layout-sources.md +87 -0
  12. package/.claude/skills/live-tokens-create-theme/SKILL.md +84 -0
  13. package/.claude/skills/live-tokens-create-theme/references/design-directions.md +94 -0
  14. package/.claude/skills/live-tokens-fix-findings/SKILL.md +69 -60
  15. package/.claude/skills/live-tokens-pick-component/SKILL.md +64 -79
  16. package/.claude/skills/live-tokens-set-colors/SKILL.md +149 -0
  17. package/.claude/skills/live-tokens-set-colors/references/color-anchors.md +80 -0
  18. package/.claude/skills/live-tokens-set-geometry/SKILL.md +121 -0
  19. package/.claude/skills/live-tokens-set-geometry/references/geometry-anchors.md +63 -0
  20. package/.claude/skills/live-tokens-set-type/SKILL.md +93 -0
  21. package/.claude/skills/live-tokens-set-type/references/type-anchors.md +60 -0
  22. package/CHANGELOG.md +194 -0
  23. package/README.md +27 -18
  24. package/bin/check-component.mjs +91 -19
  25. package/bin/check-page.mjs +105 -24
  26. package/bin/cli.mjs +154 -97
  27. package/bin/contractRunner.mjs +945 -0
  28. package/bin/create.mjs +1 -1
  29. package/bin/lib/catalogue.mjs +37 -30
  30. package/bin/lib/findings.mjs +46 -15
  31. package/bin/lib/liveState.mjs +110 -0
  32. package/bin/lib/report.mjs +3 -3
  33. package/bin/lib/tokenVocabulary.mjs +4 -4
  34. package/bin/migrate-routes.mjs +5 -5
  35. package/bin/migrate.mjs +4 -4
  36. package/bin/save-theme.mjs +176 -0
  37. package/bin/set-colors.mjs +189 -0
  38. package/bin/{adjust.mjs → set-geometry.mjs} +25 -57
  39. package/bin/{set-fonts.mjs → set-type.mjs} +26 -62
  40. package/dist-plugin/{chunk-W6Y4BWFB.js → chunk-6WGFOJXO.js} +22 -0
  41. package/dist-plugin/{chunk-RIXO2E55.js → chunk-PDNL4NC5.js} +9 -2
  42. package/dist-plugin/{chunk-YLCOIGQC.js → chunk-SWXRVZKT.js} +98 -2
  43. package/dist-plugin/{dataPaths-BhWzd5cL.d.ts → dataPaths-BpIK_Obx.d.cts} +1 -0
  44. package/dist-plugin/{dataPaths-BhWzd5cL.d.cts → dataPaths-BpIK_Obx.d.ts} +1 -0
  45. package/dist-plugin/index.cjs +366 -148
  46. package/dist-plugin/index.d.cts +1 -1
  47. package/dist-plugin/index.d.ts +1 -1
  48. package/dist-plugin/index.js +226 -130
  49. package/dist-plugin/migrateData/index.cjs +121 -2
  50. package/dist-plugin/migrateData/index.d.cts +1 -1
  51. package/dist-plugin/migrateData/index.d.ts +1 -1
  52. package/dist-plugin/migrateData/index.js +3 -3
  53. package/dist-plugin/{generateColorsAndType → setColors}/index.cjs +594 -499
  54. package/dist-plugin/{generateColorsAndType → setColors}/index.d.cts +34 -25
  55. package/dist-plugin/{generateColorsAndType → setColors}/index.d.ts +34 -25
  56. package/dist-plugin/{generateColorsAndType → setColors}/index.js +48 -66
  57. package/dist-plugin/{adjust → setGeometry}/index.cjs +166 -48
  58. package/dist-plugin/{adjust → setGeometry}/index.d.cts +6 -6
  59. package/dist-plugin/{adjust → setGeometry}/index.d.ts +6 -6
  60. package/dist-plugin/{adjust → setGeometry}/index.js +51 -45
  61. package/dist-plugin/{fontPairing → setType}/index.cjs +19 -4
  62. package/dist-plugin/{fontPairing → setType}/index.d.cts +2 -2
  63. package/dist-plugin/{fontPairing → setType}/index.d.ts +2 -2
  64. package/dist-plugin/{fontPairing → setType}/index.js +1 -1
  65. package/dist-plugin/{themeTypes-DSV3Zisf.d.cts → themeTypes-BxRtuN5V.d.cts} +1 -1
  66. package/dist-plugin/{themeTypes-DSV3Zisf.d.ts → themeTypes-BxRtuN5V.d.ts} +1 -1
  67. package/dist-plugin/tokensCssMigrations/index.d.cts +1 -1
  68. package/dist-plugin/tokensCssMigrations/index.d.ts +1 -1
  69. package/dist-plugin/tokensCssMigrations/index.js +1 -1
  70. package/package.json +36 -8
  71. package/src/app/site.css +19 -9
  72. package/src/editor/bootstrap.ts +2 -0
  73. package/src/editor/component-editor/CollapsibleSectionEditor.svelte +4 -4
  74. package/src/editor/component-editor/DialogEditor.svelte +4 -4
  75. package/src/editor/component-editor/MenuSelectEditor.svelte +4 -1
  76. package/src/editor/component-editor/SegmentedControlEditor.svelte +6 -1
  77. package/src/editor/component-editor/TabBarEditor.svelte +1 -1
  78. package/src/editor/component-editor/TableEditor.svelte +2 -2
  79. package/src/editor/component-editor/scaffolding/TokenLayout.svelte +6 -3
  80. package/src/editor/component-editor/scaffolding/VariantGroup.svelte +41 -20
  81. package/src/editor/core/components/adjustAliases.ts +59 -45
  82. package/src/editor/core/components/aliasKinds.ts +9 -5
  83. package/src/editor/core/preview/themePreview.ts +9 -2
  84. package/src/editor/core/sketch/sketchLayer.ts +22 -0
  85. package/src/editor/core/store/editorStore.ts +10 -1
  86. package/src/editor/core/themes/{generateColorsAndType.ts → buildColors.ts} +84 -98
  87. package/src/editor/core/themes/liveStateStream.ts +26 -0
  88. package/src/editor/core/themes/migrations/2026-09-03-drop-legacy-component-keys.ts +62 -0
  89. package/src/editor/core/themes/migrations/2026-09-07-stroke-role-renames.ts +52 -0
  90. package/src/editor/core/themes/migrations/index.ts +4 -0
  91. package/src/editor/core/themes/themeDocumentSync.ts +22 -11
  92. package/src/editor/core/themes/themeService.ts +9 -2
  93. package/src/editor/docs/content/themes-workflow.md +2 -2
  94. package/src/editor/docs/content.generated.ts +1 -1
  95. package/src/editor/overlay/LiveEditorOverlay.svelte +519 -28
  96. package/src/editor/pages/ComponentEditorPage.svelte +17 -1
  97. package/src/editor/pages/liveTokensEditorHandle.ts +23 -0
  98. package/src/editor/skill-atlas/SkillAtlas.svelte +76 -574
  99. package/src/editor/skill-atlas/TreeCanvas.svelte +263 -0
  100. package/src/editor/skill-atlas/TreeNodeCard.svelte +136 -53
  101. package/src/editor/skill-atlas/edges.ts +31 -0
  102. package/src/editor/skill-atlas/skillSources.generated.ts +29 -24
  103. package/src/editor/skill-atlas/skillTrees.ts +19 -3687
  104. package/src/editor/skill-atlas/trees/check-compliance.ts +183 -0
  105. package/src/editor/skill-atlas/trees/create-component.ts +275 -0
  106. package/src/editor/skill-atlas/trees/create-page.ts +320 -0
  107. package/src/editor/skill-atlas/trees/create-theme.ts +255 -0
  108. package/src/editor/skill-atlas/trees/fix-findings.ts +469 -0
  109. package/src/editor/skill-atlas/trees/pick-component.ts +300 -0
  110. package/src/editor/skill-atlas/trees/set-colors.ts +148 -0
  111. package/src/editor/skill-atlas/trees/set-geometry.ts +136 -0
  112. package/src/editor/skill-atlas/trees/set-type.ts +142 -0
  113. package/src/editor/skill-atlas/types.ts +3 -4
  114. package/src/editor/skill-atlas/wireLayout.ts +287 -0
  115. package/src/live-tokens/data/colors-and-type/autumn.json +1 -37
  116. package/src/live-tokens/data/colors-and-type/default.json +1 -37
  117. package/src/live-tokens/data/colors-and-type/halloween.json +1 -37
  118. package/src/live-tokens/data/colors-and-type/midnight-study.json +1 -37
  119. package/src/live-tokens/data/colors-and-type/ocean.json +1 -37
  120. package/src/live-tokens/data/colors-and-type/royal-velvet.json +1 -37
  121. package/src/live-tokens/data/colors-and-type/sketchy.json +1 -37
  122. package/src/live-tokens/data/colors-and-type/spring-meadow.json +1 -37
  123. package/src/live-tokens/data/colors-and-type/sunset.json +1 -37
  124. package/src/live-tokens/data/themes/autumn.json +16 -52
  125. package/src/live-tokens/data/themes/halloween.json +16 -52
  126. package/src/live-tokens/data/themes/midnight-study.json +16 -52
  127. package/src/live-tokens/data/themes/ocean.json +16 -52
  128. package/src/live-tokens/data/themes/royal-velvet.json +16 -52
  129. package/src/live-tokens/data/themes/sketchy.json +16 -52
  130. package/src/live-tokens/data/themes/spring-meadow.json +16 -52
  131. package/src/live-tokens/data/themes/sunset.json +16 -52
  132. package/src/live-tokens/data/tokens.generated.css +0 -36
  133. package/src/system/components/Badge.svelte +7 -0
  134. package/src/system/components/Button.svelte +7 -0
  135. package/src/system/components/Callout.svelte +10 -6
  136. package/src/system/components/Card.svelte +23 -4
  137. package/src/system/components/CodeSnippet.svelte +4 -3
  138. package/src/system/components/CollapsibleSection.svelte +23 -8
  139. package/src/system/components/CornerBadge.svelte +6 -0
  140. package/src/system/components/Dialog.svelte +13 -6
  141. package/src/system/components/IconButton.svelte +9 -0
  142. package/src/system/components/Image.svelte +8 -0
  143. package/src/system/components/ImageLightbox.svelte +6 -0
  144. package/src/system/components/InlineEditActions.svelte +7 -0
  145. package/src/system/components/Input.svelte +7 -0
  146. package/src/system/components/MenuSelect.svelte +7 -0
  147. package/src/system/components/Notification.svelte +7 -0
  148. package/src/system/components/Panel.svelte +6 -0
  149. package/src/system/components/ProgressBar.svelte +5 -0
  150. package/src/system/components/RadioButton.svelte +11 -5
  151. package/src/system/components/SectionDivider.svelte +8 -0
  152. package/src/system/components/SegmentedControl.svelte +6 -0
  153. package/src/system/components/SideNavigation.svelte +6 -0
  154. package/src/system/components/Slider.svelte +7 -4
  155. package/src/system/components/TabBar.svelte +15 -9
  156. package/src/system/components/Table.svelte +8 -3
  157. package/src/system/components/Toggle.svelte +4 -4
  158. package/src/system/components/Tooltip.svelte +6 -0
  159. package/src/testing-js/chunk-AO7EZHYV.js +776 -0
  160. package/src/testing-js/chunk-AO7EZHYV.js.map +1 -0
  161. package/src/testing-js/chunk-FAFOAWYL.js +39 -0
  162. package/src/testing-js/chunk-FAFOAWYL.js.map +1 -0
  163. package/src/testing-js/chunk-L73N4NSO.js +23 -0
  164. package/src/testing-js/chunk-L73N4NSO.js.map +1 -0
  165. package/src/testing-js/chunk-LXR3MN6N.js +3063 -0
  166. package/src/testing-js/chunk-LXR3MN6N.js.map +1 -0
  167. package/src/testing-js/chunk-ZMSX6CXR.js +53 -0
  168. package/src/testing-js/chunk-ZMSX6CXR.js.map +1 -0
  169. package/src/testing-js/component-alias.contract.js +81 -0
  170. package/src/testing-js/component-alias.contract.js.map +1 -0
  171. package/src/testing-js/component-editor.contract.js +62 -0
  172. package/src/testing-js/component-editor.contract.js.map +1 -0
  173. package/src/testing-js/component-render.contract.js +568 -0
  174. package/src/testing-js/component-render.contract.js.map +1 -0
  175. package/src/testing-js/index.d.ts +293 -0
  176. package/src/testing-js/index.js +222 -0
  177. package/src/testing-js/index.js.map +1 -0
  178. package/src/testing-js/registry.contract.js +39 -0
  179. package/src/testing-js/registry.contract.js.map +1 -0
  180. package/src/testing-js/vitest-BE6uGF31.d.ts +73 -0
  181. package/src/testing-js/vitest.d.ts +3 -0
  182. package/src/testing-js/vitest.js +13 -0
  183. package/src/testing-js/vitest.js.map +1 -0
  184. package/template/README.md +13 -0
  185. package/template/_gitignore +2 -0
  186. package/template/package.json +2 -1
  187. package/template/src/pages/Home.svelte +4 -18
  188. package/.claude/skills/live-tokens-adjust-geometry/SKILL.md +0 -93
  189. package/.claude/skills/live-tokens-build-page/SKILL.md +0 -103
  190. package/.claude/skills/live-tokens-build-page/references/layout-sources.md +0 -48
  191. package/.claude/skills/live-tokens-generate-theme/SKILL.md +0 -156
  192. package/.claude/skills/live-tokens-generate-theme/references/mood-vocabulary.md +0 -43
  193. package/.claude/skills/live-tokens-generate-theme/references/named-themes.md +0 -18
  194. package/.claude/skills/live-tokens-generate-theme/references/style-vocabulary.md +0 -35
  195. package/.claude/skills/live-tokens-pair-fonts/SKILL.md +0 -90
  196. package/bin/generate-theme.mjs +0 -260
@@ -0,0 +1,149 @@
1
+ ---
2
+ name: live-tokens-set-colors
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
+ ---
5
+
6
+ # Setting a theme's colors
7
+
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.
11
+
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
+
17
+ ## Workflow
18
+
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
+
25
+ `--dry-run` prints the report without writing.
26
+
27
+ ## The base color file
28
+
29
+ ```json
30
+ {
31
+ "scheme": "light",
32
+ "baseColors": {
33
+ "Brand": { "l": 0.62, "c": 0.17, "h": 145 },
34
+ "Accent": { "l": 0.80, "c": 0.15, "h": 95 },
35
+ "Special": { "l": 0.60, "c": 0.19, "h": 300 },
36
+ "Canvas": { "l": 0.93, "c": 0.04, "h": 120 },
37
+ "Neutral": { "l": 0.55, "c": 0.012, "h": 140 },
38
+ "Alternate": { "l": 0.58, "c": 0.009, "h": 60 },
39
+ "Info": { "l": 0.60, "c": 0.15, "h": 255 },
40
+ "Success": { "l": 0.60, "c": 0.16, "h": 150 },
41
+ "Warning": { "l": 0.75, "c": 0.15, "h": 85 },
42
+ "Danger": { "l": 0.58, "c": 0.20, "h": 25 }
43
+ }
44
+ }
45
+ ```
46
+
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`.
53
+
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.
55
+
56
+ ## Chroma budget
57
+
58
+ The more area a palette covers, the less chroma it gets.
59
+
60
+ | Tier | Palettes | Chroma |
61
+ |---|---|---|
62
+ | Ground (about 60% of every screen) | Neutral, Alternate | C 0.008 to 0.02 |
63
+ | Canvas (the largest single area) | Canvas | C 0.02 to 0.14, by commitment level (see Canvas commitment) |
64
+ | Dominant chromatic (about 30%) | Brand | C 0.10 to 0.20 |
65
+ | Garnish (about 10%) | Accent, Special | may exceed Brand; at most one at the gamut cap for its hue (see Gamut guardrails) |
66
+ | Conditional | Info, Success, Warning, Danger | C 0.12 to 0.19 |
67
+
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.
69
+
70
+ ## Per-role ranges
71
+
72
+ | Base color | Light scheme | Dark scheme | Hue |
73
+ |---|---|---|---|
74
+ | Canvas | L 0.92 to 0.98, C 0.02 to 0.06 | L 0.15 to 0.28, C 0.01 to 0.05 | Brand's hue or its harmony slot |
75
+ | Neutral, Alternate | L about 0.55, C 0.008 to 0.02 | same | per the chroma budget |
76
+ | Brand | L 0.45 to 0.62, C 0.12 to 0.20 | L 0.70 to 0.83, C cut by a third | the request's identity hue |
77
+ | Accent | harmony slot, or at least 0.25 L from Brand when the mode collapses hue distance | lighten and desaturate like Brand | harmony slot |
78
+ | Special | most expressive; default Brand hue +60 at about 65% of Brand's C | same transform | harmony slot |
79
+ | Info | shared status L (0.55 to 0.65 light) | lighten like Brand | H 230 to 260 |
80
+ | Success | shared status L | same | H 140 to 155 |
81
+ | Warning | L 0.75 or higher (vivid yellow must be light) | same | H 70 to 90 |
82
+ | Danger | shared status L, C 0.15 to 0.20 | same | H 20 to 30 |
83
+
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:
91
+
92
+ 1. *Tinted paper* (most UI intents): C 0.02 to 0.06, with L down to 0.92 where the hue needs room.
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.
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.
95
+
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.
97
+
98
+ ## Mood dials
99
+
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.
101
+
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.
103
+
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.
105
+
106
+ ## Gamut guardrails
107
+
108
+ The engine clamps to gamut regardless; these keep the intent achievable.
109
+
110
+ - Dark saturated yellow does not exist: H 90 at L 0.4 caps at C 0.08 and reads olive. Vivid yellow needs L 0.8 or more. Brown is dark low-chroma orange.
111
+ - Vivid light blue does not exist: H 264 at L 0.9 caps at C 0.05. Rich blue lives at L 0.40 to 0.55.
112
+ - Teal and sky cap at C 0.15.
113
+ - Peak chroma anchors: red H20 C 0.25 at L 0.63; orange H60 C 0.18 at L 0.76; yellow H90 C 0.18 at L 0.86; green H140 C 0.28 at L 0.88; blue H264 C 0.28 at L 0.50; magenta H320 C 0.31 at L 0.65.
114
+
115
+ ## Harmony
116
+
117
+ Hue offsets from Brand: complementary +180; split-complementary +150/+210; triadic +120/+240; tetradic +60/+180/+240; square +90 steps; compound +30/+180/+210; analogous plus or minus 30; monochromatic same hue.
118
+
119
+ - A vague or single-adjective intent takes monochromatic or analogous, with Accent separated from Brand by L and C rather than hue. The polished-UI default: Accent at Brand's hue and about 45% of its chroma, Special at +60 and about 65%.
120
+ - An intent naming two colors: measure their hue gap and pick the matching mode (green plus gold is 60 to 90 degrees, so analogous or compound).
121
+ - Drama or maximum contrast: complementary, triadic, or tetradic, and then tone one side down, since max-chroma text on a near-black ground vibrates.
122
+
123
+ ## Canvas sky and shadows
124
+
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.
126
+
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.
128
+
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.
132
+
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.
134
+
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.
136
+
137
+ ## Scope
138
+
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.
142
+
143
+ ## Verify
144
+
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.
148
+ - The canvas is committed: on screen it reads as the theme's color rather than as generic near-white.
149
+ - To revert, re-run with the previous base color file, or load the open theme again to discard the buffer.
@@ -0,0 +1,80 @@
1
+ # Color anchors: feelings, idioms, and occasions
2
+
3
+ Read this when the color intent names one of these. Entries are starting
4
+ points: apply the chroma budget, the per-role bands, and the canvas commitment
5
+ rules from SKILL.md on top of them.
6
+
7
+ An idiom sets constraints and overrides the generic defaults in SKILL.md. The
8
+ polished-UI Accent at 45% of Brand's chroma is right for a vague intent and
9
+ wrong for Bauhaus. A feeling moves dials, and moves them inside an idiom's
10
+ constraints when the intent names both.
11
+
12
+ Energy spent on the ground tier fights the contrast gate, so keep chroma on the
13
+ garnish. A low-valence, low-energy intent taken literally reads as broken
14
+ rather than sad, which is why every dark entry below holds one moment of color.
15
+
16
+ Riso, Memphis, and brutalist break the chroma budget on purpose. Break it in
17
+ the one layer the style is about and hold the rest of the ground tier down.
18
+
19
+ ## Feelings
20
+
21
+ | Anchor | Anchors (L, C, H) |
22
+ |---|---|
23
+ | Joyful, exuberant, energetic | butter canvas (0.95, 0.05, 90), Brand (0.80, 0.17, 75), coral Accent (0.72, 0.18, 20), green Special (0.75, 0.16, 145); analogous warm. Yellow stays yellow only above L 0.80 |
24
+ | Playful, whimsical | tinted canvas (0.93, 0.05, 330), Special at full chroma; tetradic, the rare request that wants four hue families |
25
+ | Optimistic, hopeful | sky canvas (0.94, 0.03, 220), Brand (0.62, 0.14, 200), warm yellow Accent (0.85, 0.14, 90); complementary across the warm/cool line, which reads as sunrise rather than sky |
26
+ | Confident, bold | canvas (0.90, 0.07, 250), Brand C 0.18 at L 0.55, wide L range between surfaces. High dominance is the point |
27
+ | Serene, tranquil | cool canvas (0.95, 0.03, 200), nothing above C 0.08, analogous 160 to 240 |
28
+ | Tender, gentle, romantic | blush canvas (0.95, 0.03, 20), rose Brand (0.70, 0.08, 10), sage Accent (0.68, 0.06, 150); narrow L range |
29
+ | Cozy, comforting | amber-cream canvas (0.92, 0.05, 75), rust Brand (0.55, 0.12, 40), neutrals at H 60; nothing cool on screen |
30
+ | Wistful, nostalgic, vintage, faded | faded canvas (0.92, 0.03, 70), every chromatic base color capped at C 0.10, hues warm and close. The feeling is chroma withheld, not darkness |
31
+ | Earthy, grounded, natural | canvas (0.90, 0.05, 90) at commitment level 2, hues 30 to 140 at C 0.06 to 0.14, neutrals H 60 to 80; no magenta, no cyan, nothing over C 0.16 |
32
+ | Clinical, sterile, precise | near-white canvas at C 0.01, the one request an untinted ground suits; one cool Brand 200 to 260 at C 0.10; statuses carry the only other color |
33
+ | Contemplative, focused | canvas (0.94, 0.015, 250) or its dark twin (0.20, 0.02, 250), one cool Brand at C 0.10, almost no other hue |
34
+ | Urgent, alarming | ground held near-neutral so the alarm lands, red Brand (0.58, 0.22, 27) given real area, Warning and Danger on one shared L |
35
+ | Tense, anxious | an uncomfortable ground, (0.88, 0.04, 105) light or (0.22, 0.03, 280) dark, plus a near-complementary pair that vibrates with one side toned down |
36
+ | Defiant, rebellious, loud | near-black canvas (0.15, 0.01, 0), one acid hue (0.85, 0.20, 120), nothing else chromatic |
37
+ | Melancholy, moody, sad | dark; canvas (0.22, 0.03, 250), chromatic base colors C 0.06 to 0.10 at L 0.72 to 0.80, blue through violet, with Accent held at C 0.14 as the moment of color |
38
+ | Somber, grave, mournful | near-neutral dark canvas (0.18, 0.01, 260), one desaturated Brand, gradient off |
39
+ | Ominous, dramatic, haunted | dark canvas (0.15, 0.04, 300), one hot accent (0.75, 0.16, 30) used sparingly, canvasGradient on |
40
+ | Austere, severe, cold | monochrome; canvas at either L extreme at C 0.01 or below, one low-chroma Brand, muted statuses |
41
+
42
+ ## Idioms, eras, and genres
43
+
44
+ | Anchor | Anchors (L, C, H) |
45
+ |---|---|
46
+ | Swiss, International | near-white canvas (0.97, 0.01, 0), or true black for the poster reading; one red Brand (0.55, 0.22, 27) as the only hue on screen; Neutral at C 0.005, untinted on purpose; monochromatic |
47
+ | Bauhaus | paper canvas (0.95, 0.02, 85) under primaries at full commitment: red (0.58, 0.21, 27), blue (0.48, 0.20, 264), yellow (0.86, 0.17, 90); triadic |
48
+ | Mid-century modern | canvas (0.90, 0.05, 75), mustard (0.75, 0.13, 85), teal (0.55, 0.10, 195), burnt orange (0.60, 0.15, 45), walnut neutrals H 60; nothing over C 0.16; compound |
49
+ | Art deco, opulent, luxurious | near-black canvas (0.20, 0.02, 280), gold (0.78, 0.13, 88), jade (0.60, 0.10, 165); dark, one metallic accent, everything else grey |
50
+ | Terminal, phosphor | canvas (0.16, 0.01, 150), phosphor green Brand (0.80, 0.16, 145), amber Accent (0.80, 0.13, 80); monochromatic, dark, gradient off |
51
+ | Cyberpunk, neon noir, futuristic | canvas (0.18, 0.04, 300), magenta Brand (0.78, 0.18, 330), cyan Accent (0.82, 0.12, 200); complementary, dark, canvasGradient on for the glow |
52
+ | Vaporwave | sunset canvas (0.88, 0.06, 330), pink (0.72, 0.16, 350), cyan (0.80, 0.11, 205), lilac Special; light, gradient on |
53
+ | Y2K, bubble | chrome canvas (0.96, 0.015, 240), electric blue Brand (0.62, 0.18, 255), lime Accent (0.85, 0.17, 130) |
54
+ | Blueprint | canvas (0.35, 0.07, 245), pale rules (0.90, 0.02, 240), one warm accent (0.75, 0.14, 60); dark |
55
+ | Scandinavian, hygge | chalk canvas (0.96, 0.012, 70), sage Brand (0.60, 0.06, 150), clay Accent (0.70, 0.08, 40); nothing above C 0.10; analogous |
56
+ | Japandi, wabi-sabi | unbleached paper canvas (0.93, 0.025, 80), ink Brand (0.35, 0.02, 250), one earth Accent (0.62, 0.09, 45); near-monochrome |
57
+ | Cottagecore, botanical | cream canvas (0.94, 0.04, 85), moss (0.55, 0.10, 135), dusty rose (0.70, 0.09, 15), butter (0.85, 0.11, 95); warm analogous |
58
+ | Editorial, magazine | paper canvas (0.97, 0.015, 85), ink neutrals, one strong Brand (0.50, 0.18, 20) carried by rules and pull quotes |
59
+ | Newsprint, broadsheet | grey-warm canvas (0.91, 0.02, 80), near-black ink, nothing chromatic above C 0.10 |
60
+ | Risograph, zine | paper canvas (0.94, 0.03, 80) with two flat spot inks, fluoro pink (0.68, 0.22, 5) and blue (0.52, 0.18, 260); complementary, no midtones between them |
61
+ | Corporate, professional, trustworthy | canvas (0.97, 0.012, 250), navy Brand (0.48, 0.12, 255), teal Accent (0.60, 0.09, 195), conventional statuses |
62
+ | Brutalist | pure canvas, (0.98, 0, 0) or (0.15, 0, 0), with Neutral at C 0, untinted because that is the point; one alarming Brand (0.58, 0.24, 27) |
63
+ | Memphis, postmodern | pastel canvas (0.95, 0.03, 60) carrying full-chroma primaries and a hot pink Special (0.70, 0.20, 350); tetradic or square, four hue families on purpose |
64
+ | Industrial, workshop, gritty | concrete canvas (0.88, 0.008, 250), or (0.22, 0.01, 250) dark, safety orange Brand (0.68, 0.18, 50), steel neutrals |
65
+
66
+ ## Occasions
67
+
68
+ An occasion is a statement request. Default to canvas commitment level 2 or 3,
69
+ never cream, and put the named color on the ground rather than only on the
70
+ buttons.
71
+
72
+ | Anchor | Anchors (L, C, H) | Strongest form |
73
+ |---|---|---|
74
+ | Christmas | red (0.53, 0.21, 22), green (0.46, 0.11, 155), gold (0.77, 0.14, 91) | red canvas (0.42, 0.14, 25), green Brand, gold Accent, dark scheme. Softer: evergreen canvas (0.35, 0.07, 160) or deep cream (0.95, 0.04, 85). One of red or green owns the ground; never a 50/50 split. |
75
+ | Halloween | pumpkin (0.70, 0.20, 46), purple (0.51, 0.21, 313), poison green (0.73, 0.20, 137) | orange canvas (0.45, 0.13, 55) with violet and poison-green accents, or near-black violet canvas with pumpkin Brand. Dark scheme either way. |
76
+ | St. Patrick's | green (0.51, 0.13, 152) | green Brand, gold Accent, white or beige neutrals. |
77
+ | Ocean | deep blue (0.35, 0.08, 237), aqua (0.78, 0.12, 214) | hues held to 180 to 240. |
78
+ | Sunset | hues 90 to 320 through red | L falls 0.85 to 0.40 across the sweep. |
79
+ | Autumn | parchment canvas (0.87, 0.06, 80), rust Brand (0.55, 0.15, 40), gold Accent (0.75, 0.15, 85), moss Special (0.55, 0.10, 120) | warm brown neutrals H 50 to 70; deep red H 25 welcome. |
80
+ | Spring | pastels L 0.85 to 0.95, C 0.04 to 0.10 | greens 130 to 150, pinks 0 to 20, mint canvas. |
@@ -0,0 +1,121 @@
1
+ ---
2
+ name: live-tokens-set-geometry
3
+ description: Set a live-tokens theme's geometry: corner radius, padding, gap, and border width. Each moves per component along its shipped scale. Called with an anchor and a geometry intent by live-tokens-create-theme, or with the user's request directly. Use when the user asks for pill or capsule buttons. Use when the user asks for rounded, sharp, square, softer, or harder corners. Use when the user asks for thicker or thinner borders. Use when the user asks for density: space it out, tighter, denser, airier. Changes geometry only. For a request that also names color or type, read live-tokens-create-theme.
4
+ ---
5
+
6
+ # Setting a theme's geometry
7
+
8
+ Write the request as an ops file. The CLI moves each matching alias along its scale, writes the result to each component's buffer, and prints a report. Never hand-edit the data tree.
9
+
10
+ The result is on screen as soon as the run finishes. The three set skills write the same buffer, so color, type, and geometry compose in any order. When the user accepts the result, run `save-theme` to keep it as a theme. Loading a theme in the editor discards it.
11
+
12
+ ## Workflow
13
+
14
+ 1. Read the geometry intent and the anchor, when live-tokens-create-theme passed one. When the intent or the anchor names a feeling, an idiom, or a genre, read its entry in `references/geometry-anchors.md`.
15
+ 2. Write the ops file to `scratch/geometry-ops.json`.
16
+ 3. Run `npx live-tokens set-geometry scratch/geometry-ops.json`. It writes `component-configs/<id>/_working.json` for every component the ops change.
17
+ 4. Read the report. It lists every changed alias, old and new, and every skip with its reason.
18
+ 5. When the CLI exits 1, fix the op or the input the message names, then re-run.
19
+ 6. Reply with every alias that moved and any skip worth naming.
20
+
21
+ `--dry-run` prints the report without writing.
22
+
23
+ Each run reads the live config, so "a bit more" and "back one" compound. The live config is the buffer, else the open theme. With no theme loaded, the open theme is the shipped default.
24
+
25
+ ## The ops file
26
+
27
+ Global, relative:
28
+
29
+ ```json
30
+ { "ops": [{ "kind": "radius", "shift": 1 }, { "kind": "padding", "shift": 1 }, { "kind": "gap", "shift": 1 }] }
31
+ ```
32
+
33
+ Targeted, absolute:
34
+
35
+ ```json
36
+ { "ops": [{ "target": "button", "kind": "radius", "set": "--radius-full" }] }
37
+ ```
38
+
39
+ - `target` (optional): a component id, one of the folder names under `src/live-tokens/data/component-configs/`. "Windows" or "modals" is `dialog`, "cards" is `card`, "tabs" is `tabbar`. "The UI", "everything", or no noun means global, so omit `target`.
40
+ - `kind`: `radius | padding | gap | border-width | divider-width | accent-width`. `border-width` moves `-border-width` aliases. `divider-width` moves dividers, hairline rules, and `-thickness` aliases. `accent-width` moves accent bars and indicators.
41
+ - `set` or `shift`, one of the two. `set` takes a token on that kind's scale. `shift` is a whole number of steps and stops at the ends of the scale.
42
+ - `full` (radius shifts only): admits `--radius-full` as the top of the scale. A pill request is `set: "--radius-full"` with no `full` flag.
43
+
44
+ ## Idioms
45
+
46
+ The table covers an intent that names no anchor. An anchor's entry in `references/geometry-anchors.md` overrides the table.
47
+
48
+ | The intent says | Ops |
49
+ |---|---|
50
+ | pill, capsule | radius `set: "--radius-full"`, plus the padding the pill needs (see Compact containers before controls) |
51
+ | sharp, square corners | radius `set: "--radius-none"`, or `--radius-sm` for "mostly sharp" |
52
+ | rounded (a named component) | radius `shift: 2` |
53
+ | softer, rounder (global) | radius `shift: 1` to `2`, no `full` |
54
+ | harder, sharper | radius `shift: -1` to `-2` |
55
+ | increase the radius, less round, more round | radius `shift: 1` or `-1` with `"full": true` |
56
+ | space it out, airier, breathing room | padding and gap `shift: 1` |
57
+ | tighter, denser, more compact | padding and gap `shift: -1` |
58
+ | thicker, thinner borders | border-width `shift: 1` or `-1` |
59
+
60
+ A theme intent names a direction.
61
+
62
+ | The direction is | Geometry |
63
+ |---|---|
64
+ | playful, friendly, soft | rounder and a step airier. Warm adds pill buttons. |
65
+ | luxurious, elegant, editorial | sharper corners, airier padding, thin borders |
66
+ | technical, dense, systematic | tighter spacing, a small radius, square corners on containers |
67
+ | calm, minimal | unchanged |
68
+
69
+ Magnitude follows the qualifier. "Slightly" or "a bit" is 1 step. No qualifier is 1 to 2 steps. "Much", "way", or "really" is 2 to 3 steps. A mood word often means both axes: "softer" is rounder plus airier, "compact" is tighter padding plus smaller gaps.
70
+
71
+ ## Compact containers before controls
72
+
73
+ A global op spends the same number of steps everywhere, but a step costs a control more than a container. `padding shift: -2` takes a card from a 16px inset to 10px and it is still a card. The same op takes a button from 8px to its 6px floor, 12px at each end around an 18px line, and the floor stops it there. Below the floor the button stops reading as a button.
74
+
75
+ So a global compaction is `shift: -1`. When the request wants more, spend the extra steps on the containers by name and leave the controls alone. The containers are:
76
+
77
+ - `card`
78
+ - `dialog`
79
+ - `panel`
80
+ - `collapsiblesection`
81
+ - `sidenavigation`
82
+ - `table`
83
+ - `codesnippet`
84
+
85
+ Airier is safe globally, because nothing breaks by growing.
86
+
87
+ A pill needs the most room. `--radius-full` bends the corner in over the first and last glyph, so a capsule wants more horizontal inset than a square-cornered control. `--space-8` is the floor for a large-text pill. Compact Midnight Study sits there. The roomier pill presets, Ocean, Sunset, and Royal Velvet, run `--space-10` to `--space-12`. Pair the radius op with a padding `set` on the same target. In the ops list, place the padding `set` after any global padding shift. The later op wins:
88
+
89
+ ```json
90
+ { "ops": [
91
+ { "kind": "padding", "shift": -1 },
92
+ { "target": "button", "kind": "radius", "set": "--radius-full" },
93
+ { "target": "button", "kind": "padding", "set": "--space-10" }
94
+ ] }
95
+ ```
96
+
97
+ ## Scales
98
+
99
+ Radius runs `none, sm, md, lg, xl, 2xl, 3xl, 4xl`, with `full` as the gated ninth step. Space (padding and gap) is the editor picker's subset, `0, 2, 4, 6, 8, 10, 12, 16, 20, 24, 32, 48`, so the editor can select every value the CLI writes. Border width is the `--border-width-*` scale from `1` to `24`. A shift never reaches `--border-width-0`, and an alias at 0 is skipped. "No borders" is `set: "--border-width-0"`.
100
+
101
+ An alias off the subset spends its first step reaching the subset, so `--space-2` with `shift: 1` lands on `--space-4`.
102
+
103
+ ## Floors
104
+
105
+ Content insets stop at `--space-4`. Below `--space-4` the text sits against its own edge, so `--space-0` and `--space-2` are values a person picks on purpose, through the editor picker or `set`. An alias below the floor still moves up. A shift that would push one under `--space-4` lands on `--space-4`. An alias already at `--space-4` is skipped, and the report says so.
106
+
107
+ Padding around a line of type stops at `--space-6`. A variant that declares a `-text-font-size` holds text. A component that holds text doubles its padding horizontally, so `--space-4` there is 4px over an 18px line and 8px at each end. No shipped default puts text below `--space-6`.
108
+
109
+ The floor guards `-padding` only. A 2px gap between an icon and its label, or a 2px margin under a bar, is ordinary design. `-margin` belongs to the `padding` kind, so a padding op moves margins too, without the floor.
110
+
111
+ ## Scope
112
+
113
+ Geometry only. Color, type, saved themes, and `tokens.css` are untouched: `set-geometry` writes existing tokens into each component's buffer and creates no new ones. `save-theme` keeps the result; Adopt ships it.
114
+
115
+ ## Verify
116
+
117
+ - The CLI exits 0 and the report lists the expected changes, with no unexpected skips.
118
+ - The app shows the new shape on each changed component.
119
+ - Buttons still read as buttons: the label has room at both ends, and a pill has more than a square-cornered control. A control whose padding sits at `--space-6` is on its floor. A control that also carries `--radius-full` needs a targeted lift.
120
+ - `component-configs/<id>/_working.json` exists for every component the report listed.
121
+ - To revert, run the inverse ops, or load the open theme to discard the buffer.
@@ -0,0 +1,63 @@
1
+ # Geometry anchors: feelings, idioms, and genres
2
+
3
+ Read this when the geometry intent names one of these. An anchor overrides the
4
+ Idioms table in SKILL.md, because it is tuned to the same direction the color
5
+ came from, and a style's geometry is often targeted rather than global.
6
+
7
+ Entries are written in the ops vocabulary. "radius +2" is a radius shift of 2.
8
+ "borders +1" is a border-width shift of 1. "padding +1" is a padding and gap
9
+ shift of 1. "hairline borders" is border-width `set: "--border-width-1"`, and
10
+ "no borders" is `set: "--border-width-0"`. "hairline rules" is divider-width
11
+ `set: "--border-width-1"`. A named component means a targeted op. Controls squeeze before containers,
12
+ so a compaction of more than one step still spends its extra steps on
13
+ containers by name.
14
+
15
+ An occasion (Christmas, Autumn, Ocean) fixes color only. Take its geometry from
16
+ the feeling it implies, or leave geometry alone.
17
+
18
+ ## Feelings
19
+
20
+ | Anchor | Geometry |
21
+ |---|---|
22
+ | Joyful, exuberant, energetic | radius +2, padding +1, pill buttons |
23
+ | Playful, whimsical | pill buttons, rounder cards, wide gaps |
24
+ | Optimistic, hopeful | radius +1 |
25
+ | Confident, bold | radius -1, borders +1, tight gaps |
26
+ | Serene, tranquil | soft radius, padding +1, no borders |
27
+ | Tender, gentle, romantic | rounder, hairline borders |
28
+ | Cozy, comforting | radius +1, padding +1 |
29
+ | Wistful, nostalgic, vintage, faded | unchanged, hairline rules |
30
+ | Earthy, grounded, natural | radius +1, padding +1 |
31
+ | Clinical, sterile, precise | radius sm, tight gaps, hairline borders |
32
+ | Contemplative, focused | padding +1, minimal borders |
33
+ | Urgent, alarming | radius -2, borders +2, tight padding |
34
+ | Tense, anxious | tight gaps, radius sm |
35
+ | Defiant, rebellious, loud | radius none, borders +3 |
36
+ | Melancholy, moody, sad | padding +1, hairline borders |
37
+ | Somber, grave, mournful | sharp, tight gaps, hairline rules |
38
+ | Ominous, dramatic, haunted | sharp, borders +2 |
39
+ | Austere, severe, cold | radius none, tight padding, hairline borders |
40
+
41
+ ## Idioms, eras, and genres
42
+
43
+ | Anchor | Geometry |
44
+ |---|---|
45
+ | Swiss, International | radius none, tight gaps, hairline borders |
46
+ | Bauhaus | radius none on containers, radius full on buttons alone, so the circle reads as a decision |
47
+ | Mid-century modern | radius +1 to +2, padding +1, no borders |
48
+ | Art deco, opulent, luxurious | sharp, padding +1, thin borders |
49
+ | Terminal, phosphor | radius none, tight padding, a 1px border on everything |
50
+ | Cyberpunk, neon noir, futuristic | sharp, tight gaps |
51
+ | Vaporwave | rounder, airier |
52
+ | Y2K, bubble | radius full on buttons with the padding a pill needs, generous spacing |
53
+ | Blueprint | radius none, 1px borders, tight grid |
54
+ | Scandinavian, hygge | soft radius, padding +1, hairline borders |
55
+ | Japandi, wabi-sabi | radius sm, padding +2, no borders |
56
+ | Cottagecore, botanical | rounder, airier |
57
+ | Editorial, magazine | sharp, padding +1, hairline rules |
58
+ | Newsprint, broadsheet | radius none, tight gaps, hairline rules |
59
+ | Risograph, zine | radius none, borders +2 |
60
+ | Corporate, professional, trustworthy | leave it alone |
61
+ | Brutalist | radius none, borders +2 to +3, tight padding |
62
+ | Memphis, postmodern | targeted rather than global: pill buttons against radius-none cards |
63
+ | Industrial, workshop, gritty | radius sm, thick borders, tight padding |
@@ -0,0 +1,93 @@
1
+ ---
2
+ name: live-tokens-set-type
3
+ description: Set a live-tokens theme's type: a Google Fonts pairing for the shipped --font-* stacks. The CLI verifies each family for the weights it ships. Called with an anchor and a type intent by live-tokens-create-theme, or with the user's request directly. Use when the user asks to pair fonts, pick a typeface, or set the fonts. Use when the user describes type by voice: editorial, friendlier, technical, elegant, less generic. Use when the user names a face for a role: a serif for headings, a display font. Changes type only. For a request that also names color or geometry, read live-tokens-create-theme.
4
+ ---
5
+
6
+ # Setting a theme's type
7
+
8
+ Choose the families. The CLI verifies each against Google Fonts, builds the URL from the weights the family has, and writes the result to the buffer. Never hand-author font JSON or edit the data tree. Google Fonts is the pool because it is freely licensable and loads by URL. Other sources go in through the editor's Project fonts section.
9
+
10
+ The result is on screen as soon as the run finishes. The three set skills write the same buffer, so color, type, and geometry compose in any order. When the user accepts the result, run `save-theme` to keep it as a theme. Loading a theme in the editor discards it.
11
+
12
+ ## Workflow
13
+
14
+ 1. Read the type intent and any anchor live-tokens-create-theme passed. When either names an anchor (a feeling, an idiom, or a genre), read its entry in `references/type-anchors.md`; it overrides the Voice table below.
15
+ 2. Choose the pairing and write it to `scratch/font-pairing.json`.
16
+ 3. Run `npx live-tokens set-type scratch/font-pairing.json`. It prints each stack that moved, each family's weights and URL, and, under Weight coverage, the weights the typography tokens ask for that the family lacks.
17
+ 4. Read the report. Name a missing weight and offer an alternative only when it matters: a body face without 400, 700, or italic matters, and a display face without 300 does not. A family not on Google Fonts fails the run. Fix the spelling and re-run. A pairing the stacks already hold prints "Nothing to change" and writes nothing. A pairing equal to the open theme's discards the buffer, and the report says so.
18
+ 5. Reply with the two families, the form model behind each, the matrix verdict, and any missing weight worth naming.
19
+
20
+ Flags: `--dry-run` reports without writing. `--no-verify` skips the network and requires a URL per family; use it only offline.
21
+
22
+ ## The pairing file
23
+
24
+ ```json
25
+ { "display": "Fraunces", "body": "Nunito Sans" }
26
+ ```
27
+
28
+ Every slot is optional; an omitted slot keeps its family. `display` is `--font-display` and `body` is `--font-sans`. `serif`, `mono`, and `editorial` exist when a theme needs them. `editorial` is `--font-editorial`, the long-reading face behind the `--editorial-*` text styles. An omitted `editorial` keeps its family, so set it only when essays and articles need a face of their own. Weight coverage is reported for `display`, `body`, `serif`, and `mono`. A family bound to `editorial` gets no coverage line. A slot may be `{ "name": "...", "url": "..." }` to pin a URL. A pinned URL is not probed, so the report shows no weights for it and coverage skips it. Spell families as Google does; the CLI reports the canonical spelling.
29
+
30
+ ## Choose the body face first
31
+
32
+ The body face is the anchor. It carries most of the words, and text faces survive small sizes where display faces do not. Pick it against the type intent, then pick the display face against it. A body face has regular, bold, and italic; low to moderate stroke contrast; open apertures; and a large x-height. A face missing any of these is a display face, whatever its name says.
33
+
34
+ The shipped text styles ask the display face for 600 and the body face for 400; `strong` and `em` add 700 and italic. Screen candidates against those four weights before running.
35
+
36
+ ## The font matrix
37
+
38
+ Classify each candidate by form model and by stroke contrast and serifs.
39
+
40
+ | Form model | Construction | Reads as |
41
+ |---|---|---|
42
+ | **Dynamic** | diagonal stress, open apertures, written origin | open, warm, humane, timeless |
43
+ | **Rational** | vertical stress, closed apertures, drawn not written | orderly, reserved, elegant, authoritative |
44
+ | **Geometric** | monolinear, circle-and-line | technical, modern, systematic, sober |
45
+
46
+ - One form model with different stroke contrast or serifs pairs reliably. Helvetica and Bodoni are both rational, one a linear sans and one a high-contrast serif.
47
+ - Different form models with the same stroke contrast and serifs fail. The two look alike and fight underneath. Two arbitrary sans serifs clash for this reason.
48
+ - Different on both counts works. An unmistakable difference reads as a decision.
49
+
50
+ Many faces sit between columns. When one straddles, say so and lean on the Voice table and the x-height check.
51
+
52
+ ## Voice
53
+
54
+ | The intent says | Type voice |
55
+ |---|---|
56
+ | editorial, literary, considered | dynamic serif display over a humanist sans body |
57
+ | elegant, luxurious, formal | rational high-contrast serif display; keep the body quiet |
58
+ | friendly, warm, approachable | dynamic sans on both sides, or a soft serif display |
59
+ | technical, systematic, precise | geometric or neo-grotesque sans; a mono for code |
60
+ | playful, informal | an expressive display face over a plain workhorse body |
61
+ | serious, institutional, trustworthy | rational sans body, rational serif display |
62
+ | quiet, minimal, unbranded | one superfamily across both slots |
63
+
64
+ The table covers an intent that names no anchor. An anchor's row in `references/type-anchors.md` wins.
65
+
66
+ Match the type to the design direction the color came from. A warm autumn palette under a cold geometric sans reads as two projects.
67
+
68
+ ## Shortcuts
69
+
70
+ Use these when the request is vague or the type should stay quiet.
71
+
72
+ - **A superfamily.** A Google Fonts family with sans and serif siblings: Alegreya, Ancizar, IBM Plex, Inria, Merriweather, Noto, PT, Roboto, Source. The catalogue moves and this list does not; `set-type` fails on a family that is gone.
73
+ - **One family across weights.**
74
+ - **Same designer or foundry.**
75
+ - **Serif display over sans body** when nothing else decides it.
76
+
77
+ ## Watch for
78
+
79
+ - **x-height parity.** Both faces share one size scale, so a small-x-height display face over a large-x-height body face gives a heading weaker than its own body text. Check it on the rendered page.
80
+ - **Print faces at small sizes.** Delicate serifs and high stroke contrast turn to mud below 16px.
81
+ - **Every family is a download.** Two is the target; three needs a reason.
82
+ - **Sets of themes.** No two share a display face or a body face.
83
+
84
+ ## Scope
85
+
86
+ Type only. Color, component aliases, shape, and the type scale are untouched: `set-type` writes the font entries in the buffer and carries every other value forward. `save-theme` keeps the result; Adopt ships it and rewrites `fonts.css`, which is how a build without the editor loads the family.
87
+
88
+ ## Verify
89
+
90
+ - The CLI exits 0 and names each stack that moved, before and after.
91
+ - Each URL matches the family's weights: a range for a variable family, an enumeration for a static one, a bare URL for a single-weight face. A pinned URL is written as given.
92
+ - The app shows the new type, and the editor's Fonts section lists both families with their fallbacks.
93
+ - To revert, run the previous pairing file, or load the open theme to discard the buffer.
@@ -0,0 +1,60 @@
1
+ # Type anchors: feelings, idioms, and genres
2
+
3
+ Read this when the type intent names one of these. An anchor overrides the
4
+ Voice table in SKILL.md, because it is tuned to the same direction the color
5
+ came from.
6
+
7
+ An entry names a form model and a role, never a family. Take the families from
8
+ the font matrix and the body-face rule in SKILL.md, and screen them against the
9
+ weights the shipped text styles ask for.
10
+
11
+ An occasion (Christmas, Autumn, Ocean) fixes color only. Take its type from the
12
+ feeling it implies: Autumn reads cozy, Halloween reads ominous, Spring reads
13
+ tender.
14
+
15
+ ## Feelings
16
+
17
+ | Anchor | Type voice |
18
+ |---|---|
19
+ | Joyful, exuberant, energetic | dynamic sans in both slots |
20
+ | Playful, whimsical | expressive display over a plain workhorse |
21
+ | Optimistic, hopeful | humanist sans, low contrast |
22
+ | Confident, bold | heavy rational display, plain body |
23
+ | Serene, tranquil | dynamic sans, one family |
24
+ | Tender, gentle, romantic | soft serif display over humanist sans, light weights |
25
+ | Cozy, comforting | dynamic serif over dynamic sans |
26
+ | Wistful, nostalgic, vintage, faded | rational serif display, quiet body |
27
+ | Earthy, grounded, natural | dynamic serif over humanist sans |
28
+ | Clinical, sterile, precise | one neo-grotesque, tightly set |
29
+ | Contemplative, focused | one quiet superfamily |
30
+ | Urgent, alarming | condensed grotesque, heavy |
31
+ | Tense, anxious | neo-grotesque, tightly set |
32
+ | Defiant, rebellious, loud | heavy display; a mono body works |
33
+ | Melancholy, moody, sad | rational serif display over quiet sans |
34
+ | Somber, grave, mournful | rational serif in both slots |
35
+ | Ominous, dramatic, haunted | heavy high-contrast display |
36
+ | Austere, severe, cold | one rational family |
37
+
38
+ ## Idioms, eras, and genres
39
+
40
+ | Anchor | Type voice |
41
+ |---|---|
42
+ | Swiss, International | one rational neo-grotesque across both slots |
43
+ | Bauhaus | geometric sans, heavy display |
44
+ | Mid-century modern | dynamic sans, or a geometric display over a dynamic body |
45
+ | Art deco, opulent, luxurious | rational high-contrast serif display, quiet body |
46
+ | Terminal, phosphor | mono in both slots |
47
+ | Cyberpunk, neon noir, futuristic | wide geometric display, neutral body |
48
+ | Vaporwave | wide retro display, serif welcome |
49
+ | Y2K, bubble | geometric sans, heavy display |
50
+ | Blueprint | mono, or a technical grotesque; a mono body works here and almost nowhere else |
51
+ | Scandinavian, hygge | dynamic sans on both sides |
52
+ | Japandi, wabi-sabi | rational serif display over a quiet humanist body |
53
+ | Cottagecore, botanical | dynamic serif display over humanist sans |
54
+ | Editorial, magazine | high-contrast serif display over a text serif or humanist sans |
55
+ | Newsprint, broadsheet | rational serif in both slots |
56
+ | Risograph, zine | expressive display over a plain workhorse |
57
+ | Corporate, professional, trustworthy | rational sans body with a rational serif or same-family display |
58
+ | Brutalist | neo-grotesque or mono at heavy weight |
59
+ | Memphis, postmodern | geometric display, plain body |
60
+ | Industrial, workshop, gritty | condensed grotesque display over a plain body |