@motion-proto/live-tokens 0.47.0 → 0.48.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 (124) hide show
  1. package/.claude/skills/live-tokens-adjust-shape-space/SKILL.md +68 -0
  2. package/.claude/skills/live-tokens-create-component/SKILL.md +2 -2
  3. package/.claude/skills/live-tokens-generate-theme/SKILL.md +152 -0
  4. package/CHANGELOG.md +292 -0
  5. package/README.md +37 -26
  6. package/bin/adjust.mjs +254 -0
  7. package/bin/cli.mjs +94 -7
  8. package/bin/generate-theme.mjs +251 -0
  9. package/bin/migrate.mjs +95 -6
  10. package/dist-plugin/adjust/index.cjs +259 -0
  11. package/dist-plugin/adjust/index.d.cts +45 -0
  12. package/dist-plugin/adjust/index.d.ts +45 -0
  13. package/dist-plugin/adjust/index.js +176 -0
  14. package/dist-plugin/{chunk-H4TRUINI.js → chunk-44RSTAII.js} +0 -48
  15. package/dist-plugin/chunk-6OZFXIQI.js +316 -0
  16. package/dist-plugin/chunk-76TFDTJO.js +556 -0
  17. package/dist-plugin/chunk-D3ZVKOR4.js +52 -0
  18. package/dist-plugin/dataPaths-DBN0RPuT.d.cts +54 -0
  19. package/dist-plugin/dataPaths-DBN0RPuT.d.ts +54 -0
  20. package/dist-plugin/generateColorsAndType/index.cjs +1781 -0
  21. package/dist-plugin/generateColorsAndType/index.d.cts +81 -0
  22. package/dist-plugin/generateColorsAndType/index.d.ts +81 -0
  23. package/dist-plugin/generateColorsAndType/index.js +1210 -0
  24. package/dist-plugin/index.cjs +901 -533
  25. package/dist-plugin/index.d.cts +3 -2
  26. package/dist-plugin/index.d.ts +3 -2
  27. package/dist-plugin/index.js +658 -1082
  28. package/dist-plugin/migrateData/index.cjs +728 -0
  29. package/dist-plugin/migrateData/index.d.cts +60 -0
  30. package/dist-plugin/migrateData/index.d.ts +60 -0
  31. package/dist-plugin/migrateData/index.js +348 -0
  32. package/dist-plugin/themeTypes-DMHZOnUn.d.cts +211 -0
  33. package/dist-plugin/themeTypes-DMHZOnUn.d.ts +211 -0
  34. package/dist-plugin/tokensCssMigrations/index.cjs +2 -1
  35. package/dist-plugin/tokensCssMigrations/index.d.cts +3 -15
  36. package/dist-plugin/tokensCssMigrations/index.d.ts +3 -15
  37. package/dist-plugin/tokensCssMigrations/index.js +4 -2
  38. package/package.json +18 -4
  39. package/src/editor/component-editor/scaffolding/ComponentFileManager.svelte +183 -158
  40. package/src/editor/component-editor/scaffolding/ComponentFileMenu.svelte +0 -4
  41. package/src/editor/component-editor/scaffolding/SaveAsDialog.svelte +4 -4
  42. package/src/editor/component-editor/scaffolding/TokenLayout.svelte +2 -59
  43. package/src/editor/component-editor/scaffolding/VariantGroup.svelte +1 -1
  44. package/src/editor/core/components/adjustAliases.ts +180 -0
  45. package/src/editor/core/components/aliasKinds.ts +73 -0
  46. package/src/editor/core/components/componentConfigService.ts +26 -38
  47. package/src/editor/core/flashStatus.ts +1 -1
  48. package/src/editor/core/fonts/fontMigration.ts +13 -13
  49. package/src/editor/core/fonts/fontPairing.ts +35 -0
  50. package/src/editor/core/palettes/paletteDerivation.ts +128 -16
  51. package/src/editor/core/preview/lookPreview.ts +141 -0
  52. package/src/editor/core/productionPulse.ts +34 -21
  53. package/src/editor/core/storage/files/versionedFileResourceClient.ts +18 -45
  54. package/src/editor/core/store/editorConfigStore.ts +2 -2
  55. package/src/editor/core/store/editorPersistence.ts +0 -1
  56. package/src/editor/core/store/editorStore.ts +114 -51
  57. package/src/editor/core/store/editorTypes.ts +0 -1
  58. package/src/editor/core/store/gradientSource.ts +2 -2
  59. package/src/editor/core/themes/colorsAndTypeService.ts +95 -0
  60. package/src/editor/core/themes/generateColorsAndType.ts +433 -0
  61. package/src/editor/core/themes/loadRows.ts +64 -0
  62. package/src/editor/core/themes/lookSummary.ts +75 -0
  63. package/src/editor/core/themes/migrations/2026-04-24-legacy-keys-and-bg-to-canvas.ts +3 -3
  64. package/src/editor/core/themes/migrations/2026-05-13-primary-to-brand.ts +2 -2
  65. package/src/editor/core/themes/migrations/2026-05-26-drop-overlay-extra-stops.ts +3 -3
  66. package/src/editor/core/themes/migrations/2026-08-13-drop-legacy-shape-space-keys.ts +38 -0
  67. package/src/editor/core/themes/migrations/2026-08-15-line-height-scale-rename.ts +57 -0
  68. package/src/editor/core/themes/migrations/index.ts +19 -11
  69. package/src/editor/core/themes/slices/components.ts +4 -4
  70. package/src/editor/core/themes/slices/fonts.ts +1 -1
  71. package/src/editor/core/themes/slices/gradients.ts +22 -0
  72. package/src/editor/core/themes/slices/palettes.ts +2 -2
  73. package/src/editor/core/themes/themeInit.ts +21 -29
  74. package/src/editor/core/themes/themeService.ts +218 -78
  75. package/src/editor/core/themes/themeTypes.ts +94 -51
  76. package/src/editor/docs/Docs.svelte +1 -0
  77. package/src/editor/docs/chapters.ts +1 -0
  78. package/src/editor/docs/content/01-overview.md +1 -1
  79. package/src/editor/docs/content/editing-tokens.md +6 -6
  80. package/src/editor/docs/content/getting-started.md +9 -7
  81. package/src/editor/docs/content/themes-workflow.md +74 -34
  82. package/src/editor/docs/content/where-themes-live.md +61 -0
  83. package/src/editor/docs/content.generated.ts +5 -4
  84. package/src/editor/index.ts +27 -27
  85. package/src/editor/pages/ComponentEditorPage.svelte +2 -2
  86. package/src/editor/pages/EditorShell.svelte +4 -30
  87. package/src/editor/ui/BezierCurveEditor.svelte +2 -2
  88. package/src/editor/ui/ColorEditPanel.svelte +1 -1
  89. package/src/editor/ui/FileLoadList.svelte +67 -7
  90. package/src/editor/ui/GradientEditor.svelte +3 -3
  91. package/src/editor/ui/PaletteEditor.svelte +26 -12
  92. package/src/editor/ui/ThemePanel.svelte +1067 -0
  93. package/src/editor/ui/UIDialog.svelte +11 -9
  94. package/src/editor/ui/UIPillButton.svelte +7 -2
  95. package/src/editor/ui/colors/ColorWheel.svelte +34 -1
  96. package/src/editor/ui/curveEngine.ts +48 -0
  97. package/src/editor/ui/index.ts +4 -2
  98. package/src/editor/ui/palette/PaletteBase.svelte +75 -51
  99. package/src/editor/ui/palette/PaletteJumpButton.svelte +3 -8
  100. package/src/live-tokens/data/colors-and-type/autumn.json +2490 -0
  101. package/src/live-tokens/data/{themes → colors-and-type}/default.json +816 -293
  102. package/src/live-tokens/data/colors-and-type/halloween.json +2529 -0
  103. package/src/live-tokens/data/colors-and-type/midnight-study.json +2536 -0
  104. package/src/live-tokens/data/colors-and-type/ocean.json +2489 -0
  105. package/src/live-tokens/data/colors-and-type/royal-velvet.json +2520 -0
  106. package/src/live-tokens/data/colors-and-type/spring-meadow.json +2476 -0
  107. package/src/live-tokens/data/colors-and-type/sunset.json +2528 -0
  108. package/src/live-tokens/data/themes/autumn.json +3918 -0
  109. package/src/live-tokens/data/themes/halloween.json +3992 -0
  110. package/src/live-tokens/data/themes/midnight-study.json +3932 -0
  111. package/src/live-tokens/data/themes/ocean.json +3917 -0
  112. package/src/live-tokens/data/themes/royal-velvet.json +3983 -0
  113. package/src/live-tokens/data/themes/spring-meadow.json +3904 -0
  114. package/src/live-tokens/data/themes/sunset.json +3931 -0
  115. package/src/live-tokens/data/tokens.generated.css +106 -117
  116. package/src/system/styles/CONVENTIONS.md +1 -1
  117. package/src/system/styles/fonts.css +1 -1
  118. package/template/README.md +7 -5
  119. package/template/_gitignore +0 -6
  120. package/src/editor/core/components/componentPersist.ts +0 -62
  121. package/src/editor/core/manifests/manifestService.ts +0 -172
  122. package/src/editor/ui/ManifestFileManager.svelte +0 -446
  123. package/src/editor/ui/ThemeFileManager.svelte +0 -785
  124. package/src/live-tokens/data/manifests/default.json +0 -35
@@ -1,60 +1,100 @@
1
1
  # Themes
2
2
 
3
- Save your work, switch between themes, and ship one to production.
3
+ Save your work, switch between looks, and ship one to production.
4
+
5
+ ## The Theme panel
6
+
7
+ The **Theme** panel at the foot of the editor sidebar holds the whole look:
8
+ colors, type, and a setting for every component you changed, in one file. It
9
+ carries the name the look ships under, whether production is running it, and
10
+ **Adopt**. Two parts sit under it, each a read-out rather than a file to manage.
11
+
12
+ - **Colors & Type** holds the design tokens. Components read those tokens to
13
+ define their appearance. It names the two faces the page is showing.
14
+ - **Components** counts how many components run something the theme does not
15
+ carry, and opens the component editors.
16
+
17
+ A theme holds its own copy of every part, so one theme can never break another.
4
18
 
5
19
  ## How themes work
6
20
 
7
- - **Your live edits** are what the page shows right now. They save to your
8
- browser automatically and survive a reload, but they are not yet a file.
9
- - **A saved theme** is a named JSON file in `src/live-tokens/data/themes/`. You
10
- create one with **Save as**.
11
- - **The active theme** is the saved theme the page loads at startup. Exactly one
12
- at a time.
13
- - **The production theme** is the one that ships. Promoting sets it.
21
+ A theme is a document, and the editor works the way any editor does.
22
+
23
+ - **A theme** is a named JSON file in `src/live-tokens/data/themes/`. It carries
24
+ the whole look: the colors and type plus a setting for every component you
25
+ changed.
26
+ - **The open theme** is the one the editor is working on, named in
27
+ `themes/_active.json`. One at a time.
28
+ - **Your unsaved edits** are what the page shows right now. The editor keeps
29
+ them in your browser as you work and writes them to a buffer, `_working.json`,
30
+ one slot per part of the look. **Save** captures that buffer into the open
31
+ theme.
32
+ - **The production theme** is the one your site ships, named in
33
+ `themes/_production.json`. Only **Adopt** changes it.
34
+
35
+ Absence is the answer for anything untouched: a buffer exists only where the
36
+ look sits off the shipped default, so a new project has none at all.
14
37
 
15
38
  ## Saving
16
39
 
17
- In the editor header:
40
+ In the Theme panel:
18
41
 
19
- - **Save** updates the current theme.
20
- - **Save as** names a new theme. Use it for your first save and for forking.
42
+ - **Save** captures the look on screen into the open theme. Your colors and type
43
+ go in as part of it, so there is nothing to save first.
44
+ - **Save As** names a new theme. Use it for your first save and for forking.
21
45
 
22
- Names are tidied to lowercase with underscores, so "My Brand!" becomes
23
- `my_brand`. There is a built-in `default` theme you can always return to; the
24
- editor never overwrites it.
46
+ Component edits are the exception. Each component editor holds its own unsaved
47
+ state, which this panel cannot write, so save a component in its editor before
48
+ capturing it. The panel says how many are waiting.
49
+
50
+ Names are tidied to lowercase with hyphens, so "My Brand!" becomes `my-brand`,
51
+ and a leading underscore is dropped: those names are reserved for the buffer.
52
+ **Motion Proto** is the built-in theme and is read-only. You can always return
53
+ to it, and the editor never overwrites it, so start your own with **Save As**.
25
54
 
26
55
  ## Switching
27
56
 
28
- The file menu lists every saved theme. Pick one to make it active; the page
29
- reloads with it applied. Your current edits are saved to the previous theme
30
- first, so you don't lose work.
57
+ **Load** lists your saved themes and the seven example looks. Picking one shows
58
+ it on the page as a preview with nothing written to disk, so you can try each
59
+ look and compare. **Save** in that window opens the previewed theme: its copies
60
+ fill the buffers, components it does not carry go back to their defaults, and
61
+ the editor works on it from then on. **Cancel** returns you to where you were.
62
+ Trying a look never changes what your site ships.
63
+
64
+ **Colors and type only. Keep my shapes.** narrows the load to the palette and
65
+ the fonts: your component settings stay as they are and the theme you have open
66
+ stays open. Saved colors and type files are listed there too, marked *colors &
67
+ type*, and picking one is always that narrower load.
31
68
 
32
69
  ## Shipping
33
70
 
34
- **Promote to production** is the "ship it" step. It bakes the theme's variables
35
- into `src/live-tokens/data/tokens.generated.css`, which your build bundles
36
- alongside `tokens.css`. Fonts regenerate to match.
71
+ **Adopt**, in the Theme panel, is the "ship it" step, and it ships the whole
72
+ look. It saves the open theme, then bakes that theme into
73
+ `src/live-tokens/data/tokens.generated.css`, which your build bundles alongside
74
+ `tokens.css`: the colors and type plus every component the theme carries. Fonts
75
+ regenerate to match. The line under the theme name says whether production is
76
+ running this theme.
37
77
 
38
- Production builds (`npm run build`) ship only that plain CSS and your
39
- components. No editor, no JSON loading, no runtime indirection. If you save
40
- while the production theme is active, the generated CSS updates immediately,
41
- with no separate promote step.
78
+ Production is one saved theme, so nothing else publishes. Trying a look, moving
79
+ a token, saving a theme: all of it leaves the generated CSS alone until you
80
+ Adopt. A component editor's Adopt runs the same whole-look step, because a
81
+ component never ships alone. Adopting while Motion Proto is open saves your look
82
+ as a theme of your own first, since the built-in one is read-only.
42
83
 
43
- ## Manifests
44
-
45
- A **manifest** bundles one theme plus a config for each component into a single
46
- named set. Useful when you run several brands and want each to apply its theme
47
- and component tweaks in one move. There is a protected default and an active
48
- manifest; applying one swaps everything at once.
84
+ Production builds (`npm run build`) ship only that plain CSS and your
85
+ components. No editor, no JSON loading, no runtime indirection.
49
86
 
50
87
  ## Keeping your work safe
51
88
 
52
- Everything under `src/live-tokens/data/` is plain JSON, so commit it. Themes
53
- show up as readable diffs you can review per branch. There are no automatic
54
- backups: git is your safety net. To experiment freely, **Save as** a new name
55
- first, then edit.
89
+ Everything under `src/live-tokens/data/` is plain JSON, so commit it. Themes show
90
+ up as readable diffs you can review per branch, and the buffer shows up as the
91
+ work you have not saved into a theme yet. Nothing is backed up anywhere else:
92
+ git is your safety net. To experiment freely, **Save As** a new name first, then
93
+ edit.
56
94
 
57
95
  ## Where to go next
58
96
 
97
+ - **[Where themes live](where-themes-live.md)**: the files behind all of this,
98
+ and what writes each one.
59
99
  - **[Creating components](creating-components.md)**: make your own components
60
100
  editable in the same editor.
@@ -0,0 +1,61 @@
1
+ # Where themes live
2
+
3
+ Everything the editor writes is plain JSON and CSS inside your project. There
4
+ is no database and no hidden state: the files are the storage, and git is the
5
+ history.
6
+
7
+ ## The data tree
8
+
9
+ ```
10
+ src/live-tokens/data/
11
+ themes/
12
+ _active.json names the theme the editor has open
13
+ _production.json names the theme your site ships
14
+ default.json Motion Proto, the built-in look, rewritten at boot
15
+ my-brand.json a saved theme: the whole look in one file
16
+ colors-and-type/
17
+ _working.json unsaved colors and type edits
18
+ component-configs/
19
+ button/
20
+ default.json Button's shipped settings, derived at boot
21
+ _working.json unsaved Button edits
22
+ my-button.json a preset you saved from the Button editor
23
+ tokens.generated.css the baked CSS your production build ships
24
+ src/system/styles/
25
+ tokens.css your token vocabulary, hand-authored, never written
26
+ fonts.css font imports, rewritten when you Adopt
27
+ ```
28
+
29
+ A saved theme carries the whole look by value: the colors and type plus a
30
+ setting for every component you changed. It depends on no other file, so
31
+ deleting anything else never breaks it.
32
+
33
+ ## What writes when
34
+
35
+ - **Editing** changes the page through CSS variables. The editor keeps your
36
+ edits in the browser as you work and writes them to the `_working.json`
37
+ buffers when you save a component or capture the look. A buffer exists only
38
+ where your look sits off the shipped default, so a fresh project has none.
39
+ - **Save** captures the buffers into the open theme's file. That file is the
40
+ durable copy of your look.
41
+ - **Load** fills the buffers from the theme you picked and points
42
+ `themes/_active.json` at it. Nothing else changes, so trying looks is free.
43
+ - **Adopt** points `themes/_production.json` at the open theme, bakes it into
44
+ `tokens.generated.css`, and rewrites `fonts.css` to match. It is the only
45
+ action that changes what your site ships.
46
+
47
+ The `default.json` files are the shipped baseline. The editor derives them at
48
+ boot and refreshes them when the package updates; it never saves your work
49
+ over them.
50
+
51
+ ## What to commit
52
+
53
+ All of it. The data tree is designed to live in git: themes diff readably, the
54
+ two pointers say what is open and what ships, and a `_working.json` in a diff
55
+ is exactly the work you have not yet saved into a theme. Nothing is backed up
56
+ anywhere else.
57
+
58
+ ## Where to go next
59
+
60
+ - **[Themes](themes-workflow.md)**: the workflow built on these files: saving,
61
+ loading, and shipping.
@@ -2,9 +2,10 @@
2
2
  // Source of truth: src/editor/docs/content/*.md · regenerate: npm run sync:docs
3
3
 
4
4
  export const docContent: Record<string, string> = {
5
- "01-overview": "# Overview\n\nLive Tokens is a design system for building Svelte microsites quickly. You\nstyle your site by editing tokens and components in a live editor. When it looks right, you save the manifest and ship it.\n\n## How it works\n\n- The editor runs in your dev server, on top of your real pages. You style in\n context, not in a separate sandbox.\n- Every change updates a CSS variable, so the page repaints instantly. No\n reload, no build step.\n- Saving writes a small JSON file into your project. Shipping bakes your chosen\n theme into a plain CSS file that the build bundles.\n- The editor is dev-only. Production ships plain CSS variables and the\n components you used, nothing else.\n\n## What you can edit\n\n- **Tokens**: the design-system primitives, colour palettes, type, spacing,\n radius, shadow, and gradients, that apply across your whole site.\n- **Components**: the package ships about 25 editable components (Button,\n IconButton, Card, Dialog, Table, and more). You style components by changing\n the tokens assigned to each property.\n\n## Where to go next\n\n- **[Getting started](getting-started.md)**: scaffold a project and make your\n first edit.\n- **[Editing tokens](editing-tokens.md)**: a tour of the editor.\n- **[Themes](themes-workflow.md)**: save, switch, and ship.\n- **[Creating components](creating-components.md)**: make your own components\n editable.\n",
5
+ "01-overview": "# Overview\n\nLive Tokens is a design system for building Svelte microsites quickly. You\nstyle your site by editing tokens and components in a live editor. When it looks right, you save the theme and ship it.\n\n## How it works\n\n- The editor runs in your dev server, on top of your real pages. You style in\n context, not in a separate sandbox.\n- Every change updates a CSS variable, so the page repaints instantly. No\n reload, no build step.\n- Saving writes a small JSON file into your project. Shipping bakes your chosen\n theme into a plain CSS file that the build bundles.\n- The editor is dev-only. Production ships plain CSS variables and the\n components you used, nothing else.\n\n## What you can edit\n\n- **Tokens**: the design-system primitives, colour palettes, type, spacing,\n radius, shadow, and gradients, that apply across your whole site.\n- **Components**: the package ships about 25 editable components (Button,\n IconButton, Card, Dialog, Table, and more). You style components by changing\n the tokens assigned to each property.\n\n## Where to go next\n\n- **[Getting started](getting-started.md)**: scaffold a project and make your\n first edit.\n- **[Editing tokens](editing-tokens.md)**: a tour of the editor.\n- **[Themes](themes-workflow.md)**: save, switch, and ship.\n- **[Creating components](creating-components.md)**: make your own components\n editable.\n",
6
6
  "creating-components": "# Creating components\n\nThe package ships about 25 editable components. When you need one it doesn't\nhave, you can make your own Svelte component editable, so anyone using the\neditor can re-point its colours, type, and spacing without touching code.\n\nThe simplest way is to ask Claude. The package bundles a Claude Code skill that\nknows the conventions, writes the files, and checks the result for you.\n\n## Install the skills\n\n```bash\nnpx @motion-proto/live-tokens setup-claude\n```\n\nThis copies the bundled skills into your project's `.claude/skills/`. Once\nthey're there, Claude Code picks them up automatically.\n\n## Ask for a component\n\nDescribe what you want in plain English. Phrases like these trigger the skill:\n\n- \"Add a Toggle component to live-tokens\"\n- \"Make this Svelte component editable in the live-tokens editor\"\n- \"Create a Stat component with a value and a label\"\n\nClaude asks any clarifying questions it needs (which variants, which states,\nwhich parts), then writes the component, registers it with the editor, and runs\nits verification checklist. When it finishes, open `/live-tokens/components` to see your new\ncomponent in the editor and confirm everything works.\n\n## What you get\n\n- A runtime component whose editable properties default to your theme tokens.\n- An editor entry that appears under **Custom** in the `/live-tokens/components` view.\n- The naming and wiring handled for you, so the component fits the system.\n\nAdvanced authors who want to write a component by hand can read the naming and\nstate-model conventions shipped in the package\n(`src/system/styles/CONVENTIONS.md` and the skill's own `SKILL.md`).\n",
7
- "editing-tokens": "# Editing tokens\n\nA tour of the editor. The page behind it repaints on every change; saving\nwrites a theme file you can reload later.\n\nThe editor has two views:\n\n- **Tokens**: the design-system primitives (colour, type, spacing, and so on).\n They apply everywhere your site uses them.\n- **Components**: per-component editors. Re-Assign what tokens a component uses\n without changing the underlying system.\n\nThis page covers **Tokens**. For components, see\n[Creating components](creating-components.md).\n\n## Palettes\n\nMost colour work happens here. Each palette (Brand, Accent, Neutral, Canvas,\nSuccess, Warning, Info, Danger, and a few more) has:\n\n- **Base colour.** Pick a hex; the palette derives an 11-step ramp (100 to 950)\n from it.\n- **Curves.** Two curves shape how lightness and saturation fall off across the\n ramp. Drag the handles to bias it darker, lighter, or more saturated.\n- **Overrides.** Lock a single step to a hand-picked hex when the curve doesn't\n land where you want.\n\nEditing a palette base ripples through every colour that depends on it, in real\ntime. Colours use OKLCH, so the ramp stays perceptually even across hues\nwithout muddy mid-tones.\n\n## Type\n\n- **Fonts.** Add sources from Google Fonts, Adobe (Typekit), a CSS URL, or an\n inline `@font-face`. The font loads in the page as soon as you add it.\n- **Stacks.** Named font cascades you reference by token, such as a display\n stack and a body stack.\n- **Sizes and weights.** A t-shirt scale (xs, sm, md, lg, xl, 2xl…) for size and\n a numeric scale (100 to 900) for weight.\n\n## Spacing, radius, shadow\n\nNumeric scales with a slider per step.\n\n- **Spacing**: the padding, gap, and margin scale.\n- **Radius**: none through full.\n- **Shadow**: colour, offset, blur, spread, and opacity per step, with stacked\n shadows supported.\n\nChange a step and every element using it repaints.\n\n## Overlays and gradients\n\n- **Overlays** are translucent tints layered over surfaces, like the subtle\n tint a card gets on hover. Set a colour and opacity per state.\n- **Gradients** are reusable gradient tokens with a stop list and direction, for\n hero panels and accent backgrounds.\n\n## Columns\n\nThe page-grid overlay. Set column count, gutter, and outer margin, and toggle\nthe visual guide with `Cmd/Ctrl+G`. Pages built on the column system reflow\nlive.\n\n## Saving\n\nThe editor saves to your browser continuously, so work survives a reload\nmid-edit. **Save** is a separate step: it writes a named theme file under\n`src/live-tokens/data/themes/`.\n\nThe header gives you undo/redo (`Cmd/Ctrl+Z`, `Cmd/Ctrl+Shift+Z`) and a file\nmenu for New, Save, Save as, Switch, and Delete. You can keep many themes side\nby side; one is active at a time. See [Themes](themes-workflow.md) for the full\nlifecycle.\n",
8
- "getting-started": "# Getting started\n\nScaffold a live token site in a moments. You need Node 20 or later, a\npackage manager (npm, pnpm, or yarn), and a browser. Open claude code in your repo and start building.\n\n## Scaffold a new app\n\n```bash\nnpm create @motion-proto/live-tokens@latest my-app\ncd my-app\nnpm install\nnpm run dev\n```\n\nOpen the URL Vite prints (usually `http://localhost:5173`). You get a\none-page Svelte + Vite app that depends on the published package, with the\neditor wired up and the full component set ready to import.\n\n`npx @motion-proto/live-tokens create my-app` runs the same scaffold without\nthe initialiser package.\n\n### What the scaffold gives you\n\nEvery editable file lives under `src/` and is committed, so `npm install` and\nversion upgrades never touch your styles. The package code stays in\n`node_modules`.\n\n| Path | What it is |\n|------|------------|\n| `src/pages/Home.svelte` | The starter page. Replace it with your own content. |\n| `src/App.svelte` | Your routes. `<LiveTokensRouter>` adds dev-only routes under a reserved `/live-tokens/*` namespace: `/live-tokens/editor`, `/live-tokens/components`, and `/live-tokens/docs`. |\n| `src/system/styles/tokens.css` | Your base token vocabulary, hand-authored. |\n| `src/styles/site.css` | Themed page typography, yours to edit. |\n\n## Your first edit\n\n1. Run `npm run dev` and open the home page.\n2. Click **Open Token Editor**, or visit `/live-tokens/editor`. The editor opens beside\n the page.\n3. Open **Palettes**, pick **Brand**, and change the base hex. The page\n repaints as you type.\n4. Open the file menu and choose **Save as**. A theme appears as JSON under\n `src/live-tokens/data/themes/`.\n5. Reload. Your saved theme is the active theme, so the page returns as you\n left it.\n\n## What you just changed\n\nEvery edit sets a CSS custom property on `:root`. Your components read those\nproperties through `var(--...)`. There is no token build step and no\npreprocessor rewriting your code: the page renders against plain CSS variables\nthe editor swaps live.\n\nTo ship, promote a theme to production in the editor. That bakes the theme's\nvariables into `src/live-tokens/data/tokens.generated.css`, which your build\nbundles alongside `tokens.css`. The editor itself never reaches production.\n\nAlready have a Svelte 5 + Vite app? The\n[README](https://github.com/motionproto/live-tokens#readme) covers installing\ninto an existing project.\n\n## Where to go next\n\n- **[Editing tokens](editing-tokens.md)**: a tour of the editor.\n- **[Themes](themes-workflow.md)**: save, switch, and ship.\n- **[Creating components](creating-components.md)**: make your own component\n editable.\n",
9
- "themes-workflow": "# Themes\n\nSave your work, switch between themes, and ship one to production.\n\n## How themes work\n\n- **Your live edits** are what the page shows right now. They save to your\n browser automatically and survive a reload, but they are not yet a file.\n- **A saved theme** is a named JSON file in `src/live-tokens/data/themes/`. You\n create one with **Save as**.\n- **The active theme** is the saved theme the page loads at startup. Exactly one\n at a time.\n- **The production theme** is the one that ships. Promoting sets it.\n\n## Saving\n\nIn the editor header:\n\n- **Save** updates the current theme.\n- **Save as** names a new theme. Use it for your first save and for forking.\n\nNames are tidied to lowercase with underscores, so \"My Brand!\" becomes\n`my_brand`. There is a built-in `default` theme you can always return to; the\neditor never overwrites it.\n\n## Switching\n\nThe file menu lists every saved theme. Pick one to make it active; the page\nreloads with it applied. Your current edits are saved to the previous theme\nfirst, so you don't lose work.\n\n## Shipping\n\n**Promote to production** is the \"ship it\" step. It bakes the theme's variables\ninto `src/live-tokens/data/tokens.generated.css`, which your build bundles\nalongside `tokens.css`. Fonts regenerate to match.\n\nProduction builds (`npm run build`) ship only that plain CSS and your\ncomponents. No editor, no JSON loading, no runtime indirection. If you save\nwhile the production theme is active, the generated CSS updates immediately,\nwith no separate promote step.\n\n## Manifests\n\nA **manifest** bundles one theme plus a config for each component into a single\nnamed set. Useful when you run several brands and want each to apply its theme\nand component tweaks in one move. There is a protected default and an active\nmanifest; applying one swaps everything at once.\n\n## Keeping your work safe\n\nEverything under `src/live-tokens/data/` is plain JSON, so commit it. Themes\nshow up as readable diffs you can review per branch. There are no automatic\nbackups: git is your safety net. To experiment freely, **Save as** a new name\nfirst, then edit.\n\n## Where to go next\n\n- **[Creating components](creating-components.md)**: make your own components\n editable in the same editor.\n",
7
+ "editing-tokens": "# Editing tokens\n\nA tour of the editor. The page behind it repaints on every change; saving\nwrites a theme file you can reload later.\n\nThe editor has two views:\n\n- **Tokens**: the design-system primitives (colour, type, spacing, and so on).\n They apply everywhere your site uses them.\n- **Components**: per-component editors. Re-Assign what tokens a component uses\n without changing the underlying system.\n\nThis page covers **Tokens**. For components, see\n[Creating components](creating-components.md).\n\n## Palettes\n\nMost colour work happens here. Each palette (Brand, Accent, Neutral, Canvas,\nSuccess, Warning, Info, Danger, and a few more) has:\n\n- **Base colour.** Pick a hex; the palette derives an 11-step ramp (100 to 950)\n from it.\n- **Curves.** Two curves shape how lightness and saturation fall off across the\n ramp. Drag the handles to bias it darker, lighter, or more saturated.\n- **Overrides.** Lock a single step to a hand-picked hex when the curve doesn't\n land where you want.\n\nEditing a palette base ripples through every colour that depends on it, in real\ntime. Colours use OKLCH, so the ramp stays perceptually even across hues\nwithout muddy mid-tones.\n\n## Type\n\n- **Fonts.** Add sources from Google Fonts, Adobe (Typekit), a CSS URL, or an\n inline `@font-face`. The font loads in the page as soon as you add it.\n- **Stacks.** Named font cascades you reference by token, such as a display\n stack and a body stack.\n- **Sizes and weights.** A t-shirt scale (xs, sm, md, lg, xl, 2xl…) for size and\n a numeric scale (100 to 900) for weight.\n\n## Spacing, radius, shadow\n\nNumeric scales with a slider per step.\n\n- **Spacing**: the padding, gap, and margin scale.\n- **Radius**: none through full.\n- **Shadow**: colour, offset, blur, spread, and opacity per step, with stacked\n shadows supported.\n\nChange a step and every element using it repaints.\n\n## Overlays and gradients\n\n- **Overlays** are translucent tints layered over surfaces, like the subtle\n tint a card gets on hover. Set a colour and opacity per state.\n- **Gradients** are reusable gradient tokens with a stop list and direction, for\n hero panels and accent backgrounds.\n\n## Columns\n\nThe page-grid overlay. Set column count, gutter, and outer margin, and toggle\nthe visual guide with `Cmd/Ctrl+G`. Pages built on the column system reflow\nlive.\n\n## Saving\n\nThe editor saves to your browser continuously, so work survives a reload\nmid-edit. Writing a file is a separate step: the **Theme** panel at the foot of\nthe sidebar has **Save**, **Save As**, and **Load**, and each theme is one JSON\nfile under `src/live-tokens/data/themes/`.\n\nThe header gives you undo/redo (`Cmd/Ctrl+Z`, `Cmd/Ctrl+Shift+Z`). You can keep\nmany themes side by side; one is open at a time, and only **Adopt** publishes\none. See [Themes](themes-workflow.md) for the full lifecycle.\n",
8
+ "getting-started": "# Getting started\n\nScaffold a live token site in a moments. You need Node 20 or later, a\npackage manager (npm, pnpm, or yarn), and a browser. Open claude code in your repo and start building.\n\n## Scaffold a new app\n\n```bash\nnpm create @motion-proto/live-tokens@latest my-app\ncd my-app\nnpm install\nnpm run dev\n```\n\nOpen the URL Vite prints (usually `http://localhost:5173`). You get a\none-page Svelte + Vite app that depends on the published package, with the\neditor wired up and the full component set ready to import.\n\n`npx @motion-proto/live-tokens create my-app` runs the same scaffold without\nthe initialiser package.\n\n### What the scaffold gives you\n\nEvery editable file lives under `src/` and is committed, so `npm install` and\nversion upgrades never touch your styles. The package code stays in\n`node_modules`.\n\n| Path | What it is |\n|------|------------|\n| `src/pages/Home.svelte` | The starter page. Replace it with your own content. |\n| `src/App.svelte` | Your routes. `<LiveTokensRouter>` adds dev-only routes under a reserved `/live-tokens/*` namespace: `/live-tokens/editor`, `/live-tokens/components`, and `/live-tokens/docs`. |\n| `src/system/styles/tokens.css` | Your base token vocabulary, hand-authored. |\n| `src/styles/site.css` | Themed page typography, yours to edit. |\n\n## Your first edit\n\n1. Run `npm run dev` and open the home page.\n2. Click **Open Token Editor**, or visit `/live-tokens/editor`. The editor opens beside\n the page.\n3. Open **Palettes**, pick **Brand**, and change the base hex. The page\n repaints as you type.\n4. In the **Theme** panel at the foot of the sidebar, choose **Save As**. Your\n theme appears as JSON under `src/live-tokens/data/themes/`.\n5. Reload. The editor reopens on your theme, so the page returns as you left\n it.\n\n## What you just changed\n\nEvery edit sets a CSS custom property on `:root`. Your components read those\nproperties through `var(--...)`. There is no token build step and no\npreprocessor rewriting your code: the page renders against plain CSS variables\nthe editor swaps live.\n\nTo ship, click **Adopt** in the Theme panel. That saves the open theme and bakes\nit into `src/live-tokens/data/tokens.generated.css`, which your build bundles\nalongside `tokens.css`. Adopt is the only action that changes what your site\nships, so try any look you like first. The editor itself never reaches\nproduction.\n\nAlready have a Svelte 5 + Vite app? The\n[README](https://github.com/motionproto/live-tokens#readme) covers installing\ninto an existing project.\n\n## Where to go next\n\n- **[Editing tokens](editing-tokens.md)**: a tour of the editor.\n- **[Themes](themes-workflow.md)**: save, switch, and ship.\n- **[Creating components](creating-components.md)**: make your own component\n editable.\n",
9
+ "themes-workflow": "# Themes\n\nSave your work, switch between looks, and ship one to production.\n\n## The Theme panel\n\nThe **Theme** panel at the foot of the editor sidebar holds the whole look:\ncolors, type, and a setting for every component you changed, in one file. It\ncarries the name the look ships under, whether production is running it, and\n**Adopt**. Two parts sit under it, each a read-out rather than a file to manage.\n\n- **Colors & Type** holds the design tokens. Components read those tokens to\n define their appearance. It names the two faces the page is showing.\n- **Components** counts how many components run something the theme does not\n carry, and opens the component editors.\n\nA theme holds its own copy of every part, so one theme can never break another.\n\n## How themes work\n\nA theme is a document, and the editor works the way any editor does.\n\n- **A theme** is a named JSON file in `src/live-tokens/data/themes/`. It carries\n the whole look: the colors and type plus a setting for every component you\n changed.\n- **The open theme** is the one the editor is working on, named in\n `themes/_active.json`. One at a time.\n- **Your unsaved edits** are what the page shows right now. The editor keeps\n them in your browser as you work and writes them to a buffer, `_working.json`,\n one slot per part of the look. **Save** captures that buffer into the open\n theme.\n- **The production theme** is the one your site ships, named in\n `themes/_production.json`. Only **Adopt** changes it.\n\nAbsence is the answer for anything untouched: a buffer exists only where the\nlook sits off the shipped default, so a new project has none at all.\n\n## Saving\n\nIn the Theme panel:\n\n- **Save** captures the look on screen into the open theme. Your colors and type\n go in as part of it, so there is nothing to save first.\n- **Save As** names a new theme. Use it for your first save and for forking.\n\nComponent edits are the exception. Each component editor holds its own unsaved\nstate, which this panel cannot write, so save a component in its editor before\ncapturing it. The panel says how many are waiting.\n\nNames are tidied to lowercase with hyphens, so \"My Brand!\" becomes `my-brand`,\nand a leading underscore is dropped: those names are reserved for the buffer.\n**Motion Proto** is the built-in theme and is read-only. You can always return\nto it, and the editor never overwrites it, so start your own with **Save As**.\n\n## Switching\n\n**Load** lists your saved themes and the seven example looks. Picking one shows\nit on the page as a preview with nothing written to disk, so you can try each\nlook and compare. **Save** in that window opens the previewed theme: its copies\nfill the buffers, components it does not carry go back to their defaults, and\nthe editor works on it from then on. **Cancel** returns you to where you were.\nTrying a look never changes what your site ships.\n\n**Colors and type only. Keep my shapes.** narrows the load to the palette and\nthe fonts: your component settings stay as they are and the theme you have open\nstays open. Saved colors and type files are listed there too, marked *colors &\ntype*, and picking one is always that narrower load.\n\n## Shipping\n\n**Adopt**, in the Theme panel, is the \"ship it\" step, and it ships the whole\nlook. It saves the open theme, then bakes that theme into\n`src/live-tokens/data/tokens.generated.css`, which your build bundles alongside\n`tokens.css`: the colors and type plus every component the theme carries. Fonts\nregenerate to match. The line under the theme name says whether production is\nrunning this theme.\n\nProduction is one saved theme, so nothing else publishes. Trying a look, moving\na token, saving a theme: all of it leaves the generated CSS alone until you\nAdopt. A component editor's Adopt runs the same whole-look step, because a\ncomponent never ships alone. Adopting while Motion Proto is open saves your look\nas a theme of your own first, since the built-in one is read-only.\n\nProduction builds (`npm run build`) ship only that plain CSS and your\ncomponents. No editor, no JSON loading, no runtime indirection.\n\n## Keeping your work safe\n\nEverything under `src/live-tokens/data/` is plain JSON, so commit it. Themes show\nup as readable diffs you can review per branch, and the buffer shows up as the\nwork you have not saved into a theme yet. Nothing is backed up anywhere else:\ngit is your safety net. To experiment freely, **Save As** a new name first, then\nedit.\n\n## Where to go next\n\n- **[Where themes live](where-themes-live.md)**: the files behind all of this,\n and what writes each one.\n- **[Creating components](creating-components.md)**: make your own components\n editable in the same editor.\n",
10
+ "where-themes-live": "# Where themes live\n\nEverything the editor writes is plain JSON and CSS inside your project. There\nis no database and no hidden state: the files are the storage, and git is the\nhistory.\n\n## The data tree\n\n```\nsrc/live-tokens/data/\n themes/\n _active.json names the theme the editor has open\n _production.json names the theme your site ships\n default.json Motion Proto, the built-in look, rewritten at boot\n my-brand.json a saved theme: the whole look in one file\n colors-and-type/\n _working.json unsaved colors and type edits\n component-configs/\n button/\n default.json Button's shipped settings, derived at boot\n _working.json unsaved Button edits\n my-button.json a preset you saved from the Button editor\n tokens.generated.css the baked CSS your production build ships\nsrc/system/styles/\n tokens.css your token vocabulary, hand-authored, never written\n fonts.css font imports, rewritten when you Adopt\n```\n\nA saved theme carries the whole look by value: the colors and type plus a\nsetting for every component you changed. It depends on no other file, so\ndeleting anything else never breaks it.\n\n## What writes when\n\n- **Editing** changes the page through CSS variables. The editor keeps your\n edits in the browser as you work and writes them to the `_working.json`\n buffers when you save a component or capture the look. A buffer exists only\n where your look sits off the shipped default, so a fresh project has none.\n- **Save** captures the buffers into the open theme's file. That file is the\n durable copy of your look.\n- **Load** fills the buffers from the theme you picked and points\n `themes/_active.json` at it. Nothing else changes, so trying looks is free.\n- **Adopt** points `themes/_production.json` at the open theme, bakes it into\n `tokens.generated.css`, and rewrites `fonts.css` to match. It is the only\n action that changes what your site ships.\n\nThe `default.json` files are the shipped baseline. The editor derives them at\nboot and refreshes them when the package updates; it never saves your work\nover them.\n\n## What to commit\n\nAll of it. The data tree is designed to live in git: themes diff readably, the\ntwo pointers say what is open and what ships, and a `_working.json` in a diff\nis exactly the work you have not yet saved into a theme. Nothing is backed up\nanywhere else.\n\n## Where to go next\n\n- **[Themes](themes-workflow.md)**: the workflow built on these files: saving,\n loading, and shipping.\n",
10
11
  };
@@ -8,7 +8,7 @@ export type { BootLiveTokensOptions } from './bootstrap';
8
8
 
9
9
  export { columnsVisible, toggleColumns, init as initColumnsOverlay } from './overlay/columnsOverlay';
10
10
  export { configureEditor, storageKey } from './core/store/editorConfig';
11
- export { activeFileName } from './core/store/editorConfigStore';
11
+ export { openThemeSlug } from './core/store/editorConfigStore';
12
12
  export { init as initRouter, route, navigate, setScrollReset } from './core/routing/router';
13
13
  export { init as initCssVarSync } from './core/cssVarSync';
14
14
  export {
@@ -22,22 +22,20 @@ export {
22
22
  export { setCssVar, removeCssVar } from './core/cssVarSync';
23
23
 
24
24
  export {
25
- listThemes,
26
- loadTheme,
27
- saveTheme,
28
- deleteTheme,
29
- getActiveTheme,
30
- setActiveFile,
31
- getProductionInfo,
32
- setProductionFile,
25
+ listColorsAndType,
26
+ loadColorsAndType,
27
+ saveColorsAndType,
28
+ deleteColorsAndType,
29
+ getActiveColorsAndType,
30
+ writeWorkingColorsAndType,
33
31
  sanitizeFileName,
34
- } from './core/themes/themeService';
35
- export type { ProductionInfo } from './core/themes/themeService';
32
+ } from './core/themes/colorsAndTypeService';
36
33
 
37
34
  export type {
38
35
  PaletteConfig,
39
- Theme,
40
- ThemeMeta,
36
+ ColorsAndType,
37
+ ColorsAndTypeMeta,
38
+ LiveSource,
41
39
  GradientStyle,
42
40
  GradientStop,
43
41
  FontSource,
@@ -48,22 +46,24 @@ export type {
48
46
  FontStackVariable,
49
47
  SystemCascadePreset,
50
48
  GenericFamily,
51
- Manifest,
52
- ManifestMeta,
49
+ Theme,
50
+ ThemeMeta,
53
51
  } from './core/themes/themeTypes';
54
52
 
55
53
  export {
56
- listManifests,
57
- loadManifest,
58
- saveManifest,
59
- deleteManifest,
60
- getActiveManifest,
61
- setActiveManifest,
62
- applyManifest,
63
- saveAsManifest,
64
- saveActiveManifest,
65
- } from './core/manifests/manifestService';
66
- export type { ApplyManifestResult } from './core/manifests/manifestService';
54
+ listThemes,
55
+ loadTheme,
56
+ saveTheme,
57
+ deleteTheme,
58
+ getActiveTheme,
59
+ setActiveTheme,
60
+ getProductionTheme,
61
+ applyTheme,
62
+ adoptLook,
63
+ saveAsTheme,
64
+ saveActiveTheme,
65
+ } from './core/themes/themeService';
66
+ export type { AdoptLookResult, ApplyThemeResult } from './core/themes/themeService';
67
67
 
68
68
  export {
69
69
  applyFontSources,
@@ -71,7 +71,7 @@ export {
71
71
  resolveFontStackValues,
72
72
  SYSTEM_CASCADES,
73
73
  } from './core/fonts/fontLoader';
74
- export { migrateThemeFonts, defaultFontSources, defaultFontStacks } from './core/fonts/fontMigration';
74
+ export { migrateColorsAndTypeFonts, defaultFontSources, defaultFontStacks } from './core/fonts/fontMigration';
75
75
 
76
76
  export { hexToOklch, oklchToHex, gamutClamp } from './core/palettes/oklch';
77
77
  export type { Oklch } from './core/palettes/oklch';
@@ -3,7 +3,7 @@
3
3
 
4
4
  import { onMount, onDestroy } from 'svelte';
5
5
  import ComponentsTab from '../component-editor/scaffolding/ComponentsTab.svelte';
6
- import ManifestFileManager from '../ui/ManifestFileManager.svelte';
6
+ import ThemePanel from '../ui/ThemePanel.svelte';
7
7
  import { navigate } from '../core/routing/router';
8
8
  import { getComponentRegistryEntries, validateRegistryAgainstServerScan } from '../component-editor/registry';
9
9
  import { listComponents } from '../core/components/componentConfigService';
@@ -177,7 +177,7 @@
177
177
  </div>
178
178
  {#if drawerOpen}
179
179
  <div class="sidebar-footer">
180
- <ManifestFileManager />
180
+ <ThemePanel showComponentsLink={false} />
181
181
  </div>
182
182
  {/if}
183
183
  </nav>
@@ -2,16 +2,12 @@
2
2
  import { run } from 'svelte/legacy';
3
3
 
4
4
  import { onMount } from 'svelte';
5
- import { get } from 'svelte/store';
6
5
  import VariablesTab from '../ui/VariablesTab.svelte';
7
6
  import ColorsTab from '../ui/colors/ColorsTab.svelte';
8
- import ThemeFileManager from '../ui/ThemeFileManager.svelte';
9
7
  import EditorViewSwitcher from '../ui/EditorViewSwitcher.svelte';
10
8
  import ComponentsTab from '../component-editor/scaffolding/ComponentsTab.svelte';
11
- import ManifestFileManager from '../ui/ManifestFileManager.svelte';
12
- import { persistTheme, hydrateTheme } from '../core/themes/themeService';
9
+ import ThemePanel from '../ui/ThemePanel.svelte';
13
10
  import { scrollSectionIntoView } from '../ui/scrollSection';
14
- import { editorState } from '../core/store/editorStore';
15
11
  import { editorView, sidebarCondensed, selectedComponent } from '../core/store/editorViewStore';
16
12
  import { componentDirty } from '../core/store/editorStore';
17
13
  import { getComponentRegistryEntries, validateRegistryAgainstServerScan } from '../component-editor/registry';
@@ -40,7 +36,6 @@
40
36
  const customNavItems = allComponentNavItems.filter((i) => i.origin === 'custom');
41
37
 
42
38
  let selectedTokenSection: string | null = $state(null);
43
- let saveStatus: 'idle' | 'saving' | 'saved' | 'error' = $state('idle');
44
39
 
45
40
  // 'auto' = open by default. Auto-condensing on shellWidth caused a bounce
46
41
  // as the overlay panel grew past the threshold mid-animation.
@@ -88,27 +83,6 @@
88
83
  sidebarCondensed.update((v) => !(v === true));
89
84
  }
90
85
 
91
- async function handleSave(detail: { fileName: string; displayName: string }) {
92
- const { fileName, displayName } = detail;
93
- saveStatus = 'saving';
94
- try {
95
- await persistTheme(get(editorState), fileName, displayName);
96
- saveStatus = 'saved';
97
- setTimeout(() => { saveStatus = 'idle'; }, 2000);
98
- } catch {
99
- saveStatus = 'error';
100
- setTimeout(() => { saveStatus = 'idle'; }, 3000);
101
- }
102
- }
103
-
104
- async function handleLoad(detail: { fileName: string }) {
105
- try {
106
- await hydrateTheme(detail.fileName);
107
- } catch {
108
- // silent
109
- }
110
- }
111
-
112
86
  onMount(async () => {
113
87
  try {
114
88
  const summaries = await listComponents();
@@ -152,7 +126,7 @@
152
126
  </div>
153
127
  {#if !condensed}
154
128
  <div class="sidebar-footer">
155
- <ThemeFileManager {saveStatus} onsave={handleSave} onload={handleLoad} />
129
+ <ThemePanel />
156
130
  </div>
157
131
  {/if}
158
132
  {:else if $editorView === 'colors'}
@@ -172,7 +146,7 @@
172
146
  </div>
173
147
  {#if !condensed}
174
148
  <div class="sidebar-footer">
175
- <ThemeFileManager {saveStatus} onsave={handleSave} onload={handleLoad} />
149
+ <ThemePanel />
176
150
  </div>
177
151
  {/if}
178
152
  {:else}
@@ -217,7 +191,7 @@
217
191
  </div>
218
192
  {#if !condensed}
219
193
  <div class="sidebar-footer">
220
- <ManifestFileManager />
194
+ <ThemePanel />
221
195
  </div>
222
196
  {/if}
223
197
  {/if}
@@ -4,7 +4,7 @@
4
4
  import {
5
5
  type CurveAnchor, type CurveConfig,
6
6
  CURVE_H, CURVE_PAD_Y, CURVE_Y_PAD,
7
- isCornerAnchor, curveXToSvg, curveYToSvg, svgToX, svgToY,
7
+ isCornerAnchor, tangentAnchor, curveXToSvg, curveYToSvg, svgToX, svgToY,
8
8
  evalBezier, buildCurvePath, curveTemplates,
9
9
  serializeCurve, deserializeCurve,
10
10
  } from './curveEngine';
@@ -191,7 +191,7 @@
191
191
  const a = anchors[index];
192
192
  const updated = [...anchors];
193
193
  if (isCornerAnchor(a)) {
194
- updated[index] = { ...a, inDx: -15, inDy: 0, outDx: 15, outDy: 0 };
194
+ updated[index] = tangentAnchor(a.x, a.y, anchors[index - 1] ?? null, anchors[index + 1] ?? null);
195
195
  } else {
196
196
  updated[index] = { ...a, inDx: 0, inDy: 0, outDx: 0, outDy: 0 };
197
197
  }
@@ -340,7 +340,7 @@
340
340
  regardless of row content; the row wrappers dissolve into the grid. */
341
341
  .hsl-sliders {
342
342
  display: grid;
343
- grid-template-columns: 2.5rem minmax(6rem, 1fr) 3.5rem 0.75rem;
343
+ grid-template-columns: 1.25rem minmax(6rem, 1fr) 3.5rem 0.75rem;
344
344
  gap: var(--ui-space-6) var(--ui-space-8);
345
345
  align-items: center;
346
346
  }