@motion-proto/live-tokens 0.66.0 → 0.67.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 (38) hide show
  1. package/CHANGELOG.md +132 -0
  2. package/dist-plugin/{chunk-NRONZ3T5.js → chunk-T4PMCFJN.js} +220 -114
  3. package/dist-plugin/index.cjs +253 -129
  4. package/dist-plugin/index.js +27 -9
  5. package/dist-plugin/migrateData/index.cjs +220 -114
  6. package/dist-plugin/migrateData/index.js +1 -1
  7. package/package.json +8 -1
  8. package/src/editor/bootstrap.ts +12 -0
  9. package/src/editor/core/productionPulse.ts +1 -1
  10. package/src/editor/core/sketch/index.ts +23 -27
  11. package/src/editor/core/sketch/maskField.ts +200 -62
  12. package/src/editor/core/sketch/sketchLayer.ts +10 -4
  13. package/src/editor/core/sketch/sketchRegistry.ts +98 -0
  14. package/src/editor/core/sketch/sketchStore.ts +64 -33
  15. package/src/editor/core/sketch/sketchStyleService.ts +3 -0
  16. package/src/editor/core/sketch/sketchStyles.ts +57 -96
  17. package/src/editor/docs/content/sketch-mode.md +56 -14
  18. package/src/editor/docs/content.generated.ts +1 -1
  19. package/src/editor/ui/sketch/SketchTab.svelte +219 -74
  20. package/src/live-tokens/data/sketch-styles/dashed.json +47 -0
  21. package/src/live-tokens/data/sketch-styles/dry.json +47 -0
  22. package/src/live-tokens/data/sketch-styles/hatched.json +47 -0
  23. package/src/live-tokens/data/sketch-styles/marker.json +47 -0
  24. package/src/live-tokens/data/sketch-styles/napkin.json +47 -0
  25. package/src/live-tokens/data/sketch-styles/pencil.json +47 -0
  26. package/src/live-tokens/data/sketch-styles/whiteboard.json +47 -0
  27. package/src/live-tokens/data/themes/autumn.json +4 -4
  28. package/src/live-tokens/data/themes/halloween.json +4 -4
  29. package/src/live-tokens/data/themes/midnight-study.json +4 -4
  30. package/src/live-tokens/data/themes/ocean.json +4 -4
  31. package/src/live-tokens/data/themes/royal-velvet.json +4 -4
  32. package/src/live-tokens/data/themes/sketchy.json +4 -4
  33. package/src/live-tokens/data/themes/spring-meadow.json +4 -4
  34. package/src/live-tokens/data/themes/sunset.json +4 -4
  35. package/src/system/components/Button.svelte +2 -2
  36. package/src/system/components/IconButton.svelte +2 -2
  37. package/src/system/styles/fonts.css +6 -6
  38. package/template/src/main.ts +14 -1
@@ -95,8 +95,8 @@ function formatRadialShape(v) {
95
95
  if (ax === 1 && ay === 1) {
96
96
  return v.radius && v.radius > 0 ? `circle ${v.radius}px` : "circle";
97
97
  }
98
- const base2 = v.radius && v.radius > 0 ? v.radius : RADIAL_BASE_PX;
99
- return `ellipse ${(base2 * ax).toFixed(2)}px ${(base2 * ay).toFixed(2)}px`;
98
+ const base = v.radius && v.radius > 0 ? v.radius : RADIAL_BASE_PX;
99
+ return `ellipse ${(base * ax).toFixed(2)}px ${(base * ay).toFixed(2)}px`;
100
100
  }
101
101
  function formatGradientValue(v) {
102
102
  if (v.type === "none") return "transparent";
@@ -486,14 +486,14 @@ function scaleStepToX(step, scale) {
486
486
  function serializeDerivedValue(value) {
487
487
  return value.kind === "raw" ? value.css : oklchToCss(value.l, value.c, value.h);
488
488
  }
489
- function computePaletteOklch(index, base2, lightnessCurve, saturationCurve, curveOffset, hueCurve) {
490
- const { c: baseC } = base2;
489
+ function computePaletteOklch(index, base, lightnessCurve, saturationCurve, curveOffset, hueCurve) {
490
+ const { c: baseC } = base;
491
491
  const xPos = stepIndexToX(index);
492
492
  const targetL = Math.max(0, Math.min(100, sampleCurve(lightnessCurve, xPos) + (curveOffset.lightness ?? 0))) / 100;
493
493
  const satMul = Math.max(0, Math.min(2, (sampleCurve(saturationCurve, xPos) + (curveOffset.saturation ?? 0)) / 100));
494
494
  const targetC = baseC * satMul;
495
495
  const hueDelta = (hueCurve ? sampleCurve(hueCurve, xPos) : 0) + (curveOffset.hue ?? 0);
496
- const h = hueDelta === 0 ? base2.h : wrapHue(base2.h + hueDelta);
496
+ const h = hueDelta === 0 ? base.h : wrapHue(base.h + hueDelta);
497
497
  return gamutClamp(targetL, targetC, h);
498
498
  }
499
499
  function nearestPaletteStep(lightnessCurve, baseL) {
@@ -617,7 +617,7 @@ function syncBaseAnchor(cfg) {
617
617
  priorHueEndpoints: h ? prev?.priorHueEndpoints ?? h.priorEndpoints : void 0
618
618
  };
619
619
  }
620
- function computeDerivedOklch(step, base2, scaleTitle, scaleCurves, curveOffset) {
620
+ function computeDerivedOklch(step, base, scaleTitle, scaleCurves, curveOffset) {
621
621
  const scale = SCALES.find((s) => s.title === scaleTitle);
622
622
  const xPos = scaleStepToX(step, scale);
623
623
  const defs = defaultScaleCurves[scaleTitle];
@@ -627,7 +627,7 @@ function computeDerivedOklch(step, base2, scaleTitle, scaleCurves, curveOffset)
627
627
  const lOff = curveOffset[`${scaleTitle}-lightness`] ?? 0;
628
628
  const sOff = curveOffset[`${scaleTitle}-saturation`] ?? 0;
629
629
  const hOff = curveOffset[`${scaleTitle}-hue`] ?? 0;
630
- const { l: baseL, c: baseC, h: baseH } = base2;
630
+ const { l: baseL, c: baseC, h: baseH } = base;
631
631
  let targetL;
632
632
  if (scale.isText) {
633
633
  const lMul = Math.max(0, Math.min(2, (sampleCurve(lCurve, xPos) + lOff) / 100));
@@ -1904,65 +1904,38 @@ var KNOWN_COMPONENT_CONFIG_KEYS = /* @__PURE__ */ new Set([
1904
1904
  "--sectiondivider-sm-color-family"
1905
1905
  ]);
1906
1906
 
1907
- // src/editor/core/sketch/sketchStyles.ts
1908
- var base = {
1909
- label: "",
1910
- blurb: "",
1911
- fillTravel: 1.5,
1912
- strokeTravel: 1.5,
1913
- wobble: 45,
1914
- roughness: 3,
1915
- borderWavelength: 1,
1916
- waveform: 1,
1917
- strokeWidth: 1.5,
1918
- doubleStroke: false,
1919
- retraceOffset: 1.2,
1920
- retracePass: "copy",
1921
- fillStyle: "solid",
1922
- hatchInk: 0.4,
1923
- strokeStyle: "solid",
1924
- pressure: 0.25,
1925
- pressureMod: 0.35,
1926
- pooling: 1.2,
1927
- strokeInk: 1,
1928
- maskOn: true,
1929
- maskBlob: 100,
1930
- maskOutputMin: 0.45,
1931
- maskOutputMax: 1,
1932
- maskOctaves: 2,
1933
- maskGrain: "fractal",
1934
- maskPosterize: 1,
1935
- maskSoftness: 1.5,
1936
- jitterX: 2.5,
1937
- jitterY: 2.5,
1938
- jitterRot: 0.6,
1939
- jitterScale: 0.035,
1940
- cornerSpread: 10,
1941
- cornerTravel: 8,
1942
- iconTravel: 1.25,
1943
- iconWavelength: 0.625,
1944
- iconMaskOn: true,
1945
- iconMaskScale: 1
1946
- };
1947
- var SKETCH_STYLES = {
1948
- pencil: {
1949
- ...base,
1907
+ // src/live-tokens/data/sketch-styles/pencil.json
1908
+ var pencil_default = {
1909
+ name: "Pencil",
1910
+ settings: {
1950
1911
  label: "Pencil",
1951
1912
  blurb: "Two graphite passes on their own seeds, so the outline disagrees with itself the way a hand coming back round does. Tight grain, little else.",
1952
1913
  fillTravel: 0.75,
1953
1914
  strokeTravel: 1.25,
1954
1915
  wobble: 30,
1955
1916
  roughness: 3,
1917
+ borderWavelength: 1,
1956
1918
  waveform: 1,
1957
1919
  strokeWidth: 1.25,
1958
1920
  doubleStroke: true,
1959
- retracePass: "reseeded",
1960
1921
  retraceOffset: 1.5,
1922
+ retracePass: "reseeded",
1923
+ fillStyle: "solid",
1924
+ hatchInk: 0.4,
1925
+ strokeStyle: "solid",
1926
+ pressure: 0.15,
1927
+ pressureMod: 0.3,
1928
+ pooling: 0,
1961
1929
  strokeInk: 0.85,
1962
- maskBlob: 40,
1963
- maskOutputMin: 0.62,
1930
+ maskOn: true,
1931
+ maskBlobX: 525,
1932
+ maskBlobY: 47,
1933
+ maskBlobLinked: false,
1934
+ maskAngle: 67,
1935
+ maskOutputMin: 0.59,
1964
1936
  maskOutputMax: 1,
1965
1937
  maskOctaves: 3,
1938
+ maskGrain: "turbulence",
1966
1939
  maskPosterize: 1,
1967
1940
  maskSoftness: 0,
1968
1941
  jitterX: 1.5,
@@ -1971,147 +1944,243 @@ var SKETCH_STYLES = {
1971
1944
  jitterScale: 0.022,
1972
1945
  cornerSpread: 6,
1973
1946
  cornerTravel: 4.5,
1974
- pressure: 0.15,
1975
- pressureMod: 0.3,
1976
- pooling: 0,
1977
- iconTravel: 0.75
1947
+ iconTravel: 0.75,
1948
+ iconWavelength: 0.625,
1949
+ iconMaskOn: true,
1950
+ iconMaskScale: 1
1978
1951
  },
1979
- marker: {
1980
- ...base,
1952
+ updatedAt: "2026-08-28T14:35:06.291Z",
1953
+ createdAt: "2026-08-28T14:35:06.291Z"
1954
+ };
1955
+
1956
+ // src/live-tokens/data/sketch-styles/marker.json
1957
+ var marker_default = {
1958
+ name: "Marker",
1959
+ settings: {
1981
1960
  label: "Marker",
1982
1961
  blurb: "Broad translucent nib gone round twice on the same line, so the overlap darkens and the ink pools where it slows.",
1983
1962
  fillTravel: 2,
1984
1963
  strokeTravel: 1.5,
1985
1964
  wobble: 56,
1986
- waveform: 1.4,
1965
+ roughness: 3,
1987
1966
  borderWavelength: 1.3,
1967
+ waveform: 1.4,
1988
1968
  strokeWidth: 4,
1989
1969
  doubleStroke: true,
1970
+ retraceOffset: 2.2,
1990
1971
  retracePass: "copy",
1972
+ fillStyle: "solid",
1973
+ hatchInk: 0.4,
1974
+ strokeStyle: "solid",
1975
+ pressure: 0.2,
1976
+ pressureMod: 0.25,
1977
+ pooling: 2,
1991
1978
  strokeInk: 0.52,
1992
- retraceOffset: 2.2,
1993
- maskBlob: 115,
1994
- maskOutputMin: 0.42,
1979
+ maskOn: true,
1980
+ maskBlobX: 230,
1981
+ maskBlobY: 230,
1982
+ maskBlobLinked: true,
1983
+ maskAngle: 0,
1984
+ maskOutputMin: 0.76,
1995
1985
  maskOutputMax: 1,
1996
1986
  maskOctaves: 3,
1987
+ maskGrain: "fractal",
1997
1988
  maskPosterize: 4,
1998
- maskSoftness: 4,
1989
+ maskSoftness: 0,
1999
1990
  jitterX: 3,
2000
1991
  jitterY: 3,
2001
1992
  jitterRot: 0.8,
2002
1993
  jitterScale: 0.045,
2003
1994
  cornerSpread: 10,
2004
1995
  cornerTravel: 8,
2005
- pressure: 0.2,
2006
- pressureMod: 0.25,
2007
- pooling: 2,
2008
1996
  iconTravel: 1.25,
1997
+ iconWavelength: 0.625,
1998
+ iconMaskOn: true,
2009
1999
  iconMaskScale: 4
2010
2000
  },
2011
- whiteboard: {
2012
- ...base,
2001
+ updatedAt: "2026-08-28T14:45:04.324Z",
2002
+ createdAt: "2026-08-28T14:45:04.324Z"
2003
+ };
2004
+
2005
+ // src/live-tokens/data/sketch-styles/whiteboard.json
2006
+ var whiteboard_default = {
2007
+ name: "Whiteboard",
2008
+ settings: {
2013
2009
  label: "Whiteboard",
2014
2010
  blurb: "The fattest nib on glass. One long smooth undulation, and a veined mask that streaks the fill like a half-wiped board.",
2015
2011
  fillTravel: 2.5,
2016
2012
  strokeTravel: 2.5,
2017
2013
  wobble: 90,
2018
2014
  roughness: 1,
2019
- waveform: 1,
2020
2015
  borderWavelength: 1.5,
2016
+ waveform: 1,
2021
2017
  strokeWidth: 5.5,
2022
2018
  doubleStroke: true,
2019
+ retraceOffset: 3,
2023
2020
  retracePass: "copy",
2021
+ fillStyle: "solid",
2022
+ hatchInk: 0.4,
2023
+ strokeStyle: "solid",
2024
+ pressure: 0.15,
2025
+ pressureMod: 0.15,
2026
+ pooling: 3.5,
2024
2027
  strokeInk: 0.66,
2025
- retraceOffset: 3,
2026
- maskGrain: "turbulence",
2027
- maskBlob: 180,
2028
- maskOutputMin: 0.42,
2028
+ maskOn: true,
2029
+ maskBlobX: 180,
2030
+ maskBlobY: 38,
2031
+ maskBlobLinked: false,
2032
+ maskAngle: 0,
2033
+ maskOutputMin: 0.68,
2029
2034
  maskOutputMax: 1,
2030
- maskOctaves: 1,
2035
+ maskOctaves: 3,
2036
+ maskGrain: "turbulence",
2031
2037
  maskPosterize: 3,
2032
- maskSoftness: 8,
2038
+ maskSoftness: 0,
2033
2039
  jitterX: 4.5,
2034
2040
  jitterY: 4.5,
2035
- jitterRot: 1.2,
2041
+ jitterRot: 3,
2036
2042
  jitterScale: 0.07,
2037
2043
  cornerSpread: 14,
2038
2044
  cornerTravel: 11,
2039
- pressure: 0.15,
2040
- pressureMod: 0.15,
2041
- pooling: 3.5,
2042
2045
  iconTravel: 1.75,
2046
+ iconWavelength: 0.625,
2047
+ iconMaskOn: true,
2043
2048
  iconMaskScale: 1.5
2044
2049
  },
2045
- hatched: {
2046
- ...base,
2050
+ updatedAt: "2026-08-28T14:46:58.140Z",
2051
+ createdAt: "2026-08-28T14:46:58.140Z"
2052
+ };
2053
+
2054
+ // src/live-tokens/data/sketch-styles/hatched.json
2055
+ var hatched_default = {
2056
+ name: "Hatched",
2057
+ settings: {
2047
2058
  label: "Hatched",
2048
2059
  blurb: "An etching. The fill is angled shading, the outline a single hard-edged scratch that chatters along its length. No mask: the hatch is the texture.",
2049
2060
  fillTravel: 1.25,
2050
2061
  strokeTravel: 1.5,
2051
2062
  wobble: 24,
2052
2063
  roughness: 3,
2064
+ borderWavelength: 1,
2053
2065
  waveform: 3,
2054
2066
  strokeWidth: 1.5,
2067
+ doubleStroke: false,
2068
+ retraceOffset: 1.2,
2069
+ retracePass: "copy",
2055
2070
  fillStyle: "hatched",
2056
2071
  hatchInk: 0.5,
2057
- doubleStroke: false,
2072
+ strokeStyle: "solid",
2073
+ pressure: 0.3,
2074
+ pressureMod: 0.45,
2075
+ pooling: 0.8,
2076
+ strokeInk: 1,
2058
2077
  maskOn: false,
2059
- iconMaskOn: false,
2078
+ maskBlobX: 100,
2079
+ maskBlobY: 100,
2080
+ maskBlobLinked: true,
2081
+ maskAngle: 0,
2082
+ maskOutputMin: 0.45,
2083
+ maskOutputMax: 1,
2084
+ maskOctaves: 2,
2085
+ maskGrain: "fractal",
2086
+ maskPosterize: 1,
2087
+ maskSoftness: 1.5,
2060
2088
  jitterX: 1.5,
2061
2089
  jitterY: 1.5,
2062
2090
  jitterRot: 0.4,
2063
2091
  jitterScale: 0.03,
2064
2092
  cornerSpread: 6,
2065
2093
  cornerTravel: 6,
2066
- pressure: 0.3,
2067
- pressureMod: 0.45,
2068
- pooling: 0.8,
2069
2094
  iconTravel: 1.25,
2070
- iconWavelength: 0.5
2095
+ iconWavelength: 0.5,
2096
+ iconMaskOn: false,
2097
+ iconMaskScale: 1
2071
2098
  },
2072
- dashed: {
2073
- ...base,
2099
+ updatedAt: "2026-08-28T15:47:36.934Z",
2100
+ createdAt: "2026-08-28T15:47:36.934Z"
2101
+ };
2102
+
2103
+ // src/live-tokens/data/sketch-styles/dashed.json
2104
+ var dashed_default = {
2105
+ name: "Dashed",
2106
+ settings: {
2074
2107
  label: "Dashed",
2075
2108
  blurb: "A drafting outline. One slow drift along the ruler, broken into strokes, with jitter, mask and pressure all off. The clean pole.",
2076
- strokeStyle: "dashed",
2077
- strokeTravel: 1,
2078
2109
  fillTravel: 0.5,
2110
+ strokeTravel: 1,
2079
2111
  wobble: 120,
2080
2112
  roughness: 1,
2113
+ borderWavelength: 1,
2081
2114
  waveform: 1,
2082
2115
  strokeWidth: 1.5,
2083
2116
  doubleStroke: false,
2117
+ retraceOffset: 1.2,
2118
+ retracePass: "copy",
2119
+ fillStyle: "solid",
2120
+ hatchInk: 0.4,
2121
+ strokeStyle: "dashed",
2122
+ pressure: 0,
2123
+ pressureMod: 0,
2124
+ pooling: 0,
2125
+ strokeInk: 1,
2084
2126
  maskOn: false,
2085
- iconMaskOn: false,
2127
+ maskBlobX: 100,
2128
+ maskBlobY: 100,
2129
+ maskBlobLinked: true,
2130
+ maskAngle: 0,
2131
+ maskOutputMin: 0.45,
2132
+ maskOutputMax: 1,
2133
+ maskOctaves: 2,
2134
+ maskGrain: "fractal",
2135
+ maskPosterize: 1,
2136
+ maskSoftness: 1.5,
2086
2137
  jitterX: 0,
2087
2138
  jitterY: 0,
2088
2139
  jitterRot: 0,
2089
2140
  jitterScale: 0,
2090
2141
  cornerSpread: 4,
2091
2142
  cornerTravel: 3,
2092
- pressure: 0,
2093
- pressureMod: 0,
2094
- pooling: 0,
2095
- iconTravel: 0
2143
+ iconTravel: 0,
2144
+ iconWavelength: 0.625,
2145
+ iconMaskOn: false,
2146
+ iconMaskScale: 1
2096
2147
  },
2097
- napkin: {
2098
- ...base,
2148
+ updatedAt: "2026-08-28T15:47:36.934Z",
2149
+ createdAt: "2026-08-28T15:47:36.934Z"
2150
+ };
2151
+
2152
+ // src/live-tokens/data/sketch-styles/napkin.json
2153
+ var napkin_default = {
2154
+ name: "Napkin",
2155
+ settings: {
2099
2156
  label: "Napkin",
2100
2157
  blurb: "Ballpoint in a hurry. Everything loose at once: a square wave sends every edge to full travel, and the second pass lands wherever it lands.",
2101
2158
  fillTravel: 3,
2102
2159
  strokeTravel: 2.25,
2103
2160
  wobble: 50,
2104
2161
  roughness: 3,
2162
+ borderWavelength: 1,
2105
2163
  waveform: 2.5,
2106
2164
  strokeWidth: 2.25,
2107
2165
  doubleStroke: true,
2108
- retracePass: "reseeded",
2109
2166
  retraceOffset: 4,
2167
+ retracePass: "reseeded",
2168
+ fillStyle: "solid",
2169
+ hatchInk: 0.4,
2170
+ strokeStyle: "solid",
2171
+ pressure: 0.45,
2172
+ pressureMod: 0.6,
2173
+ pooling: 2.5,
2110
2174
  strokeInk: 1,
2111
- maskBlob: 150,
2175
+ maskOn: true,
2176
+ maskBlobX: 150,
2177
+ maskBlobY: 150,
2178
+ maskBlobLinked: true,
2179
+ maskAngle: 0,
2112
2180
  maskOutputMin: 0.43,
2113
2181
  maskOutputMax: 0.95,
2114
2182
  maskOctaves: 2,
2183
+ maskGrain: "fractal",
2115
2184
  maskPosterize: 2,
2116
2185
  maskSoftness: 10,
2117
2186
  jitterX: 6,
@@ -2120,28 +2189,47 @@ var SKETCH_STYLES = {
2120
2189
  jitterScale: 0.1,
2121
2190
  cornerSpread: 20,
2122
2191
  cornerTravel: 17,
2123
- pressure: 0.45,
2124
- pressureMod: 0.6,
2125
- pooling: 2.5,
2126
2192
  iconTravel: 2.25,
2193
+ iconWavelength: 0.625,
2194
+ iconMaskOn: true,
2127
2195
  iconMaskScale: 3.6
2128
2196
  },
2129
- dry: {
2130
- ...base,
2197
+ updatedAt: "2026-08-28T15:47:36.934Z",
2198
+ createdAt: "2026-08-28T15:47:36.934Z"
2199
+ };
2200
+
2201
+ // src/live-tokens/data/sketch-styles/dry.json
2202
+ var dry_default = {
2203
+ name: "Dry marker",
2204
+ settings: {
2131
2205
  label: "Dry marker",
2132
2206
  blurb: "Ink that ran out. One scratchy pass that breaks up along its length, over a fill the mask has worn nearly through in patches.",
2133
2207
  fillTravel: 2.25,
2134
2208
  strokeTravel: 1.75,
2135
2209
  wobble: 50,
2136
- waveform: 2,
2210
+ roughness: 3,
2137
2211
  borderWavelength: 0.5,
2212
+ waveform: 2,
2138
2213
  strokeWidth: 3.5,
2139
2214
  doubleStroke: false,
2215
+ retraceOffset: 1.2,
2216
+ retracePass: "copy",
2217
+ fillStyle: "solid",
2218
+ hatchInk: 0.4,
2219
+ strokeStyle: "solid",
2220
+ pressure: 0.4,
2221
+ pressureMod: 0.8,
2222
+ pooling: 1.5,
2140
2223
  strokeInk: 0.4,
2141
- maskBlob: 150,
2224
+ maskOn: true,
2225
+ maskBlobX: 150,
2226
+ maskBlobY: 150,
2227
+ maskBlobLinked: true,
2228
+ maskAngle: 0,
2142
2229
  maskOutputMin: 0.24,
2143
2230
  maskOutputMax: 0.91,
2144
2231
  maskOctaves: 2,
2232
+ maskGrain: "fractal",
2145
2233
  maskPosterize: 4,
2146
2234
  maskSoftness: 1.75,
2147
2235
  jitterX: 5,
@@ -2150,26 +2238,34 @@ var SKETCH_STYLES = {
2150
2238
  jitterScale: 0.08,
2151
2239
  cornerSpread: 16,
2152
2240
  cornerTravel: 13,
2153
- pressure: 0.4,
2154
- pressureMod: 0.8,
2155
- pooling: 1.5,
2156
2241
  iconTravel: 1.75,
2242
+ iconWavelength: 0.625,
2243
+ iconMaskOn: true,
2157
2244
  iconMaskScale: 3.8
2158
- }
2245
+ },
2246
+ updatedAt: "2026-08-28T15:47:36.934Z",
2247
+ createdAt: "2026-08-28T15:47:36.934Z"
2159
2248
  };
2249
+
2250
+ // src/editor/core/sketch/sketchStyles.ts
2251
+ var SHIPPED_FILES = { pencil: pencil_default, marker: marker_default, whiteboard: whiteboard_default, hatched: hatched_default, dashed: dashed_default, napkin: napkin_default, dry: dry_default };
2252
+ var SKETCH_STYLES = Object.fromEntries(
2253
+ Object.entries(SHIPPED_FILES).map(([id, file]) => [id, file.settings])
2254
+ );
2160
2255
  var DEFAULT_SKETCH_STYLE = "marker";
2161
2256
  function hydrateSketchStyle(raw) {
2162
- const base2 = SKETCH_STYLES[DEFAULT_SKETCH_STYLE];
2257
+ const base = SKETCH_STYLES[DEFAULT_SKETCH_STYLE];
2163
2258
  const stored = raw ?? {};
2164
- const out = { ...base2 };
2165
- for (const key of Object.keys(base2)) {
2259
+ const out = { ...base };
2260
+ for (const key of Object.keys(base)) {
2166
2261
  if (stored[key] !== void 0) out[key] = stored[key];
2167
2262
  }
2168
- if (out.fillStyle === "none") out.fillStyle = base2.fillStyle;
2263
+ if (out.fillStyle === "none") out.fillStyle = base.fillStyle;
2169
2264
  convertTiledMask(stored, out);
2170
2265
  convertCutToLevels(stored, out);
2171
2266
  carryLevelsToOutput(stored, out);
2172
2267
  halveSwingDials(stored, out);
2268
+ splitBlobAxes(stored, out);
2173
2269
  convertCyclesToWavelength(stored, out);
2174
2270
  convertIconTileToScale(stored, out);
2175
2271
  restoreDerivedRetrace(stored, out);
@@ -2201,6 +2297,13 @@ function convertCyclesToWavelength(stored, out) {
2201
2297
  const layers = stored.octaves;
2202
2298
  if (typeof layers === "number") out.roughness = Math.min(3, Math.max(1, layers));
2203
2299
  }
2300
+ function splitBlobAxes(stored, out) {
2301
+ const blob = stored.maskBlob;
2302
+ if (typeof blob !== "number") return;
2303
+ out.maskBlobX = blob;
2304
+ out.maskBlobY = blob;
2305
+ out.maskBlobLinked = true;
2306
+ }
2204
2307
  function convertIconTileToScale(stored, out) {
2205
2308
  const tile = stored.iconMaskTile;
2206
2309
  if (typeof tile !== "number") return;
@@ -2216,7 +2319,10 @@ function convertTiledMask(stored, out) {
2216
2319
  const scale = stored.maskScale;
2217
2320
  if (typeof scale !== "number") return;
2218
2321
  const freq = stored.maskFrequency;
2219
- if (typeof freq === "number") out.maskBlob = Math.round(scale / (freq * LEGACY_TILE));
2322
+ if (typeof freq === "number") {
2323
+ out.maskBlobX = Math.round(scale / (freq * LEGACY_TILE));
2324
+ out.maskBlobY = out.maskBlobX;
2325
+ }
2220
2326
  const soft = stored.maskSoftness;
2221
2327
  if (typeof soft === "number") out.maskSoftness = Number((soft * scale / LEGACY_TILE).toFixed(1));
2222
2328
  }
@@ -2329,12 +2435,12 @@ function normalizeTheme(raw, resolvers) {
2329
2435
  }
2330
2436
  const filled = { components: [], aliases: 0, orphans: 0 };
2331
2437
  for (const comp of resolvers.listComponentNames()) {
2332
- const base2 = asObject(resolvers.readComponentConfig(comp, "default"));
2333
- const baseAliases = base2 ? asObject(base2.aliases) : null;
2334
- if (!base2 || !baseAliases) continue;
2438
+ const base = asObject(resolvers.readComponentConfig(comp, "default"));
2439
+ const baseAliases = base ? asObject(base.aliases) : null;
2440
+ if (!base || !baseAliases) continue;
2335
2441
  const entry = componentConfigs[comp];
2336
2442
  if (!entry) {
2337
- const { schemaVersion: _standaloneStamp, ...rest } = stripFileMarker(base2);
2443
+ const { schemaVersion: _standaloneStamp, ...rest } = stripFileMarker(base);
2338
2444
  componentConfigs[comp] = structuredClone(rest);
2339
2445
  filled.components.push(comp);
2340
2446
  continue;
@@ -3124,12 +3230,14 @@ function themeFileApi(opts) {
3124
3230
  const packageColorsAndTypeDir = import_path4.default.join(packageDataDir, "colors-and-type");
3125
3231
  const packageThemesDir = import_path4.default.join(packageDataDir, "themes");
3126
3232
  const packageComponentConfigsDir = import_path4.default.join(packageDataDir, "component-configs");
3127
- function shippedColorsAndTypeNames(dataDir) {
3233
+ const packageSketchStylesDir = import_path4.default.join(packageDataDir, "sketch-styles");
3234
+ function shippedNames(dataDir, subdir) {
3128
3235
  try {
3129
3236
  const pkgRoot = import_path4.default.resolve(dataDir, "..", "..", "..");
3130
3237
  const pkg = JSON.parse(import_fs4.default.readFileSync(import_path4.default.join(pkgRoot, "package.json"), "utf-8"));
3131
3238
  const files = Array.isArray(pkg.files) ? pkg.files : [];
3132
- return files.filter((f) => /^src\/live-tokens\/data\/colors-and-type\/[^/]+\.json$/.test(f)).map((f) => import_path4.default.basename(f, ".json"));
3239
+ const owned = new RegExp(`^src/live-tokens/data/${subdir}/[^/]+\\.json$`);
3240
+ return files.filter((f) => owned.test(f)).map((f) => import_path4.default.basename(f, ".json"));
3133
3241
  } catch {
3134
3242
  return [];
3135
3243
  }
@@ -3141,7 +3249,7 @@ function themeFileApi(opts) {
3141
3249
  const colorsAndTypeResource = versionedFileResourceServer({
3142
3250
  dir: COLORS_AND_TYPE_DIR,
3143
3251
  packageDir: packageColorsAndTypeDir,
3144
- packageOwnedNames: shippedColorsAndTypeNames(packageDataDir)
3252
+ packageOwnedNames: shippedNames(packageDataDir, "colors-and-type")
3145
3253
  });
3146
3254
  const componentResourceCache = /* @__PURE__ */ new Map();
3147
3255
  function componentResource(comp) {
@@ -3159,7 +3267,11 @@ function themeFileApi(opts) {
3159
3267
  dir: THEMES_DIR,
3160
3268
  packageDir: packageThemesDir
3161
3269
  });
3162
- const sketchStylesResource = versionedFileResourceServer({ dir: SKETCH_STYLES_DIR });
3270
+ const sketchStylesResource = versionedFileResourceServer({
3271
+ dir: SKETCH_STYLES_DIR,
3272
+ packageDir: packageSketchStylesDir,
3273
+ packageOwnedNames: shippedNames(packageDataDir, "sketch-styles")
3274
+ });
3163
3275
  function ensureColorsAndTypeDir() {
3164
3276
  colorsAndTypeResource.ensureDir();
3165
3277
  }
@@ -3971,7 +4083,8 @@ ${lines.join("\n")}
3971
4083
  return {
3972
4084
  name: data?.name || fileName,
3973
4085
  fileName,
3974
- updatedAt: data?.updatedAt || ""
4086
+ updatedAt: data?.updatedAt || "",
4087
+ isPackage: sketchStylesResource.isPackageFile(fileName)
3975
4088
  };
3976
4089
  });
3977
4090
  jsonResponse(res, 200, { component: comp, files });
@@ -4287,7 +4400,8 @@ ${lines.join("\n")}
4287
4400
  return {
4288
4401
  name: data?.name || fileName,
4289
4402
  fileName,
4290
- updatedAt: data?.updatedAt || ""
4403
+ updatedAt: data?.updatedAt || "",
4404
+ isPackage: sketchStylesResource.isPackageFile(fileName)
4291
4405
  };
4292
4406
  });
4293
4407
  jsonResponse(res, 200, { files });
@@ -4327,7 +4441,15 @@ ${lines.join("\n")}
4327
4441
  return;
4328
4442
  }
4329
4443
  if (req.method === "DELETE") {
4330
- if (import_fs4.default.existsSync(filePath)) import_fs4.default.unlinkSync(filePath);
4444
+ if (import_fs4.default.existsSync(filePath)) {
4445
+ import_fs4.default.unlinkSync(filePath);
4446
+ } else if (sketchStylesResource.existingPath(fileName)) {
4447
+ jsonResponse(res, 403, {
4448
+ error: "Cannot delete a sketchstyle shipped with the package. Saving it creates a local copy; deleting that copy restores the shipped version.",
4449
+ code: "PACKAGE_SKETCH_STYLE"
4450
+ });
4451
+ return;
4452
+ }
4331
4453
  jsonResponse(res, 200, { ok: true });
4332
4454
  return;
4333
4455
  }
@@ -4421,6 +4543,7 @@ ${lines.join("\n")}
4421
4543
  { method: "POST", pattern: PRODUCTION_ROUTE, handler: methodNotAllowed },
4422
4544
  { method: "DELETE", pattern: PRODUCTION_ROUTE, handler: methodNotAllowed }
4423
4545
  ];
4546
+ const isEditorOwnedJson = (file) => file.endsWith(".json") && import_path4.default.resolve(file).startsWith(dataDirs.dataDir + import_path4.default.sep);
4424
4547
  return {
4425
4548
  name: "theme-file-api",
4426
4549
  config() {
@@ -4429,7 +4552,8 @@ ${lines.join("\n")}
4429
4552
  __PROJECT_ROOT__: JSON.stringify(process.cwd()),
4430
4553
  __APP_VERSION__: JSON.stringify(PKG_VERSION),
4431
4554
  __LIVE_TOKENS_API_BASE__: JSON.stringify(API_BASE)
4432
- }
4555
+ },
4556
+ server: { watch: { ignored: [isEditorOwnedJson] } }
4433
4557
  };
4434
4558
  },
4435
4559
  configureServer(server) {