@motion-proto/live-tokens 0.65.1 → 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 (39) hide show
  1. package/CHANGELOG.md +184 -0
  2. package/dist-plugin/{chunk-NDJJORKJ.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 +78 -21
  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 +110 -31
  15. package/src/editor/core/sketch/sketchStyleService.ts +3 -0
  16. package/src/editor/core/sketch/sketchStyles.ts +63 -96
  17. package/src/editor/core/themes/themeInit.ts +4 -13
  18. package/src/editor/docs/content/sketch-mode.md +82 -13
  19. package/src/editor/docs/content.generated.ts +1 -1
  20. package/src/editor/ui/sketch/SketchTab.svelte +219 -74
  21. package/src/live-tokens/data/sketch-styles/dashed.json +47 -0
  22. package/src/live-tokens/data/sketch-styles/dry.json +47 -0
  23. package/src/live-tokens/data/sketch-styles/hatched.json +47 -0
  24. package/src/live-tokens/data/sketch-styles/marker.json +47 -0
  25. package/src/live-tokens/data/sketch-styles/napkin.json +47 -0
  26. package/src/live-tokens/data/sketch-styles/pencil.json +47 -0
  27. package/src/live-tokens/data/sketch-styles/whiteboard.json +47 -0
  28. package/src/live-tokens/data/themes/autumn.json +4 -4
  29. package/src/live-tokens/data/themes/halloween.json +4 -4
  30. package/src/live-tokens/data/themes/midnight-study.json +4 -4
  31. package/src/live-tokens/data/themes/ocean.json +4 -4
  32. package/src/live-tokens/data/themes/royal-velvet.json +4 -4
  33. package/src/live-tokens/data/themes/sketchy.json +4 -4
  34. package/src/live-tokens/data/themes/spring-meadow.json +4 -4
  35. package/src/live-tokens/data/themes/sunset.json +4 -4
  36. package/src/system/components/Button.svelte +2 -2
  37. package/src/system/components/IconButton.svelte +2 -2
  38. package/src/system/styles/fonts.css +6 -6
  39. package/template/src/main.ts +14 -1
@@ -13,7 +13,7 @@ import {
13
13
  nextAvailableName,
14
14
  normalizeTheme,
15
15
  versionedFileResourceServer
16
- } from "./chunk-NDJJORKJ.js";
16
+ } from "./chunk-T4PMCFJN.js";
17
17
  import {
18
18
  CURRENT_COMPONENT_SCHEMA_VERSION
19
19
  } from "./chunk-NE6N66EE.js";
@@ -243,12 +243,14 @@ function themeFileApi(opts) {
243
243
  const packageColorsAndTypeDir = path.join(packageDataDir, "colors-and-type");
244
244
  const packageThemesDir = path.join(packageDataDir, "themes");
245
245
  const packageComponentConfigsDir = path.join(packageDataDir, "component-configs");
246
- function shippedColorsAndTypeNames(dataDir) {
246
+ const packageSketchStylesDir = path.join(packageDataDir, "sketch-styles");
247
+ function shippedNames(dataDir, subdir) {
247
248
  try {
248
249
  const pkgRoot = path.resolve(dataDir, "..", "..", "..");
249
250
  const pkg = JSON.parse(fs.readFileSync(path.join(pkgRoot, "package.json"), "utf-8"));
250
251
  const files = Array.isArray(pkg.files) ? pkg.files : [];
251
- return files.filter((f) => /^src\/live-tokens\/data\/colors-and-type\/[^/]+\.json$/.test(f)).map((f) => path.basename(f, ".json"));
252
+ const owned = new RegExp(`^src/live-tokens/data/${subdir}/[^/]+\\.json$`);
253
+ return files.filter((f) => owned.test(f)).map((f) => path.basename(f, ".json"));
252
254
  } catch {
253
255
  return [];
254
256
  }
@@ -260,7 +262,7 @@ function themeFileApi(opts) {
260
262
  const colorsAndTypeResource = versionedFileResourceServer({
261
263
  dir: COLORS_AND_TYPE_DIR,
262
264
  packageDir: packageColorsAndTypeDir,
263
- packageOwnedNames: shippedColorsAndTypeNames(packageDataDir)
265
+ packageOwnedNames: shippedNames(packageDataDir, "colors-and-type")
264
266
  });
265
267
  const componentResourceCache = /* @__PURE__ */ new Map();
266
268
  function componentResource(comp) {
@@ -278,7 +280,11 @@ function themeFileApi(opts) {
278
280
  dir: THEMES_DIR,
279
281
  packageDir: packageThemesDir
280
282
  });
281
- const sketchStylesResource = versionedFileResourceServer({ dir: SKETCH_STYLES_DIR });
283
+ const sketchStylesResource = versionedFileResourceServer({
284
+ dir: SKETCH_STYLES_DIR,
285
+ packageDir: packageSketchStylesDir,
286
+ packageOwnedNames: shippedNames(packageDataDir, "sketch-styles")
287
+ });
282
288
  function ensureColorsAndTypeDir() {
283
289
  colorsAndTypeResource.ensureDir();
284
290
  }
@@ -1090,7 +1096,8 @@ ${lines.join("\n")}
1090
1096
  return {
1091
1097
  name: data?.name || fileName,
1092
1098
  fileName,
1093
- updatedAt: data?.updatedAt || ""
1099
+ updatedAt: data?.updatedAt || "",
1100
+ isPackage: sketchStylesResource.isPackageFile(fileName)
1094
1101
  };
1095
1102
  });
1096
1103
  jsonResponse(res, 200, { component: comp, files });
@@ -1406,7 +1413,8 @@ ${lines.join("\n")}
1406
1413
  return {
1407
1414
  name: data?.name || fileName,
1408
1415
  fileName,
1409
- updatedAt: data?.updatedAt || ""
1416
+ updatedAt: data?.updatedAt || "",
1417
+ isPackage: sketchStylesResource.isPackageFile(fileName)
1410
1418
  };
1411
1419
  });
1412
1420
  jsonResponse(res, 200, { files });
@@ -1446,7 +1454,15 @@ ${lines.join("\n")}
1446
1454
  return;
1447
1455
  }
1448
1456
  if (req.method === "DELETE") {
1449
- if (fs.existsSync(filePath)) fs.unlinkSync(filePath);
1457
+ if (fs.existsSync(filePath)) {
1458
+ fs.unlinkSync(filePath);
1459
+ } else if (sketchStylesResource.existingPath(fileName)) {
1460
+ jsonResponse(res, 403, {
1461
+ error: "Cannot delete a sketchstyle shipped with the package. Saving it creates a local copy; deleting that copy restores the shipped version.",
1462
+ code: "PACKAGE_SKETCH_STYLE"
1463
+ });
1464
+ return;
1465
+ }
1450
1466
  jsonResponse(res, 200, { ok: true });
1451
1467
  return;
1452
1468
  }
@@ -1540,6 +1556,7 @@ ${lines.join("\n")}
1540
1556
  { method: "POST", pattern: PRODUCTION_ROUTE, handler: methodNotAllowed },
1541
1557
  { method: "DELETE", pattern: PRODUCTION_ROUTE, handler: methodNotAllowed }
1542
1558
  ];
1559
+ const isEditorOwnedJson = (file) => file.endsWith(".json") && path.resolve(file).startsWith(dataDirs.dataDir + path.sep);
1543
1560
  return {
1544
1561
  name: "theme-file-api",
1545
1562
  config() {
@@ -1548,7 +1565,8 @@ ${lines.join("\n")}
1548
1565
  __PROJECT_ROOT__: JSON.stringify(process.cwd()),
1549
1566
  __APP_VERSION__: JSON.stringify(PKG_VERSION),
1550
1567
  __LIVE_TOKENS_API_BASE__: JSON.stringify(API_BASE)
1551
- }
1568
+ },
1569
+ server: { watch: { ignored: [isEditorOwnedJson] } }
1552
1570
  };
1553
1571
  },
1554
1572
  configureServer(server) {
@@ -1053,65 +1053,38 @@ var KNOWN_COMPONENT_CONFIG_KEYS = /* @__PURE__ */ new Set([
1053
1053
  "--sectiondivider-sm-color-family"
1054
1054
  ]);
1055
1055
 
1056
- // src/editor/core/sketch/sketchStyles.ts
1057
- var base = {
1058
- label: "",
1059
- blurb: "",
1060
- fillTravel: 1.5,
1061
- strokeTravel: 1.5,
1062
- wobble: 45,
1063
- roughness: 3,
1064
- borderWavelength: 1,
1065
- waveform: 1,
1066
- strokeWidth: 1.5,
1067
- doubleStroke: false,
1068
- retraceOffset: 1.2,
1069
- retracePass: "copy",
1070
- fillStyle: "solid",
1071
- hatchInk: 0.4,
1072
- strokeStyle: "solid",
1073
- pressure: 0.25,
1074
- pressureMod: 0.35,
1075
- pooling: 1.2,
1076
- strokeInk: 1,
1077
- maskOn: true,
1078
- maskBlob: 100,
1079
- maskOutputMin: 0.45,
1080
- maskOutputMax: 1,
1081
- maskOctaves: 2,
1082
- maskGrain: "fractal",
1083
- maskPosterize: 1,
1084
- maskSoftness: 1.5,
1085
- jitterX: 2.5,
1086
- jitterY: 2.5,
1087
- jitterRot: 0.6,
1088
- jitterScale: 0.035,
1089
- cornerSpread: 10,
1090
- cornerTravel: 8,
1091
- iconTravel: 1.25,
1092
- iconWavelength: 0.625,
1093
- iconMaskOn: true,
1094
- iconMaskScale: 1
1095
- };
1096
- var SKETCH_STYLES = {
1097
- pencil: {
1098
- ...base,
1056
+ // src/live-tokens/data/sketch-styles/pencil.json
1057
+ var pencil_default = {
1058
+ name: "Pencil",
1059
+ settings: {
1099
1060
  label: "Pencil",
1100
1061
  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.",
1101
1062
  fillTravel: 0.75,
1102
1063
  strokeTravel: 1.25,
1103
1064
  wobble: 30,
1104
1065
  roughness: 3,
1066
+ borderWavelength: 1,
1105
1067
  waveform: 1,
1106
1068
  strokeWidth: 1.25,
1107
1069
  doubleStroke: true,
1108
- retracePass: "reseeded",
1109
1070
  retraceOffset: 1.5,
1071
+ retracePass: "reseeded",
1072
+ fillStyle: "solid",
1073
+ hatchInk: 0.4,
1074
+ strokeStyle: "solid",
1075
+ pressure: 0.15,
1076
+ pressureMod: 0.3,
1077
+ pooling: 0,
1110
1078
  strokeInk: 0.85,
1111
- maskBlob: 40,
1112
- maskOutputMin: 0.62,
1079
+ maskOn: true,
1080
+ maskBlobX: 525,
1081
+ maskBlobY: 47,
1082
+ maskBlobLinked: false,
1083
+ maskAngle: 67,
1084
+ maskOutputMin: 0.59,
1113
1085
  maskOutputMax: 1,
1114
1086
  maskOctaves: 3,
1087
+ maskGrain: "turbulence",
1115
1088
  maskPosterize: 1,
1116
1089
  maskSoftness: 0,
1117
1090
  jitterX: 1.5,
@@ -1120,147 +1093,243 @@ var SKETCH_STYLES = {
1120
1093
  jitterScale: 0.022,
1121
1094
  cornerSpread: 6,
1122
1095
  cornerTravel: 4.5,
1123
- pressure: 0.15,
1124
- pressureMod: 0.3,
1125
- pooling: 0,
1126
- iconTravel: 0.75
1096
+ iconTravel: 0.75,
1097
+ iconWavelength: 0.625,
1098
+ iconMaskOn: true,
1099
+ iconMaskScale: 1
1127
1100
  },
1128
- marker: {
1129
- ...base,
1101
+ updatedAt: "2026-08-28T14:35:06.291Z",
1102
+ createdAt: "2026-08-28T14:35:06.291Z"
1103
+ };
1104
+
1105
+ // src/live-tokens/data/sketch-styles/marker.json
1106
+ var marker_default = {
1107
+ name: "Marker",
1108
+ settings: {
1130
1109
  label: "Marker",
1131
1110
  blurb: "Broad translucent nib gone round twice on the same line, so the overlap darkens and the ink pools where it slows.",
1132
1111
  fillTravel: 2,
1133
1112
  strokeTravel: 1.5,
1134
1113
  wobble: 56,
1135
- waveform: 1.4,
1114
+ roughness: 3,
1136
1115
  borderWavelength: 1.3,
1116
+ waveform: 1.4,
1137
1117
  strokeWidth: 4,
1138
1118
  doubleStroke: true,
1119
+ retraceOffset: 2.2,
1139
1120
  retracePass: "copy",
1121
+ fillStyle: "solid",
1122
+ hatchInk: 0.4,
1123
+ strokeStyle: "solid",
1124
+ pressure: 0.2,
1125
+ pressureMod: 0.25,
1126
+ pooling: 2,
1140
1127
  strokeInk: 0.52,
1141
- retraceOffset: 2.2,
1142
- maskBlob: 115,
1143
- maskOutputMin: 0.42,
1128
+ maskOn: true,
1129
+ maskBlobX: 230,
1130
+ maskBlobY: 230,
1131
+ maskBlobLinked: true,
1132
+ maskAngle: 0,
1133
+ maskOutputMin: 0.76,
1144
1134
  maskOutputMax: 1,
1145
1135
  maskOctaves: 3,
1136
+ maskGrain: "fractal",
1146
1137
  maskPosterize: 4,
1147
- maskSoftness: 4,
1138
+ maskSoftness: 0,
1148
1139
  jitterX: 3,
1149
1140
  jitterY: 3,
1150
1141
  jitterRot: 0.8,
1151
1142
  jitterScale: 0.045,
1152
1143
  cornerSpread: 10,
1153
1144
  cornerTravel: 8,
1154
- pressure: 0.2,
1155
- pressureMod: 0.25,
1156
- pooling: 2,
1157
1145
  iconTravel: 1.25,
1146
+ iconWavelength: 0.625,
1147
+ iconMaskOn: true,
1158
1148
  iconMaskScale: 4
1159
1149
  },
1160
- whiteboard: {
1161
- ...base,
1150
+ updatedAt: "2026-08-28T14:45:04.324Z",
1151
+ createdAt: "2026-08-28T14:45:04.324Z"
1152
+ };
1153
+
1154
+ // src/live-tokens/data/sketch-styles/whiteboard.json
1155
+ var whiteboard_default = {
1156
+ name: "Whiteboard",
1157
+ settings: {
1162
1158
  label: "Whiteboard",
1163
1159
  blurb: "The fattest nib on glass. One long smooth undulation, and a veined mask that streaks the fill like a half-wiped board.",
1164
1160
  fillTravel: 2.5,
1165
1161
  strokeTravel: 2.5,
1166
1162
  wobble: 90,
1167
1163
  roughness: 1,
1168
- waveform: 1,
1169
1164
  borderWavelength: 1.5,
1165
+ waveform: 1,
1170
1166
  strokeWidth: 5.5,
1171
1167
  doubleStroke: true,
1168
+ retraceOffset: 3,
1172
1169
  retracePass: "copy",
1170
+ fillStyle: "solid",
1171
+ hatchInk: 0.4,
1172
+ strokeStyle: "solid",
1173
+ pressure: 0.15,
1174
+ pressureMod: 0.15,
1175
+ pooling: 3.5,
1173
1176
  strokeInk: 0.66,
1174
- retraceOffset: 3,
1175
- maskGrain: "turbulence",
1176
- maskBlob: 180,
1177
- maskOutputMin: 0.42,
1177
+ maskOn: true,
1178
+ maskBlobX: 180,
1179
+ maskBlobY: 38,
1180
+ maskBlobLinked: false,
1181
+ maskAngle: 0,
1182
+ maskOutputMin: 0.68,
1178
1183
  maskOutputMax: 1,
1179
- maskOctaves: 1,
1184
+ maskOctaves: 3,
1185
+ maskGrain: "turbulence",
1180
1186
  maskPosterize: 3,
1181
- maskSoftness: 8,
1187
+ maskSoftness: 0,
1182
1188
  jitterX: 4.5,
1183
1189
  jitterY: 4.5,
1184
- jitterRot: 1.2,
1190
+ jitterRot: 3,
1185
1191
  jitterScale: 0.07,
1186
1192
  cornerSpread: 14,
1187
1193
  cornerTravel: 11,
1188
- pressure: 0.15,
1189
- pressureMod: 0.15,
1190
- pooling: 3.5,
1191
1194
  iconTravel: 1.75,
1195
+ iconWavelength: 0.625,
1196
+ iconMaskOn: true,
1192
1197
  iconMaskScale: 1.5
1193
1198
  },
1194
- hatched: {
1195
- ...base,
1199
+ updatedAt: "2026-08-28T14:46:58.140Z",
1200
+ createdAt: "2026-08-28T14:46:58.140Z"
1201
+ };
1202
+
1203
+ // src/live-tokens/data/sketch-styles/hatched.json
1204
+ var hatched_default = {
1205
+ name: "Hatched",
1206
+ settings: {
1196
1207
  label: "Hatched",
1197
1208
  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.",
1198
1209
  fillTravel: 1.25,
1199
1210
  strokeTravel: 1.5,
1200
1211
  wobble: 24,
1201
1212
  roughness: 3,
1213
+ borderWavelength: 1,
1202
1214
  waveform: 3,
1203
1215
  strokeWidth: 1.5,
1216
+ doubleStroke: false,
1217
+ retraceOffset: 1.2,
1218
+ retracePass: "copy",
1204
1219
  fillStyle: "hatched",
1205
1220
  hatchInk: 0.5,
1206
- doubleStroke: false,
1221
+ strokeStyle: "solid",
1222
+ pressure: 0.3,
1223
+ pressureMod: 0.45,
1224
+ pooling: 0.8,
1225
+ strokeInk: 1,
1207
1226
  maskOn: false,
1208
- iconMaskOn: false,
1227
+ maskBlobX: 100,
1228
+ maskBlobY: 100,
1229
+ maskBlobLinked: true,
1230
+ maskAngle: 0,
1231
+ maskOutputMin: 0.45,
1232
+ maskOutputMax: 1,
1233
+ maskOctaves: 2,
1234
+ maskGrain: "fractal",
1235
+ maskPosterize: 1,
1236
+ maskSoftness: 1.5,
1209
1237
  jitterX: 1.5,
1210
1238
  jitterY: 1.5,
1211
1239
  jitterRot: 0.4,
1212
1240
  jitterScale: 0.03,
1213
1241
  cornerSpread: 6,
1214
1242
  cornerTravel: 6,
1215
- pressure: 0.3,
1216
- pressureMod: 0.45,
1217
- pooling: 0.8,
1218
1243
  iconTravel: 1.25,
1219
- iconWavelength: 0.5
1244
+ iconWavelength: 0.5,
1245
+ iconMaskOn: false,
1246
+ iconMaskScale: 1
1220
1247
  },
1221
- dashed: {
1222
- ...base,
1248
+ updatedAt: "2026-08-28T15:47:36.934Z",
1249
+ createdAt: "2026-08-28T15:47:36.934Z"
1250
+ };
1251
+
1252
+ // src/live-tokens/data/sketch-styles/dashed.json
1253
+ var dashed_default = {
1254
+ name: "Dashed",
1255
+ settings: {
1223
1256
  label: "Dashed",
1224
1257
  blurb: "A drafting outline. One slow drift along the ruler, broken into strokes, with jitter, mask and pressure all off. The clean pole.",
1225
- strokeStyle: "dashed",
1226
- strokeTravel: 1,
1227
1258
  fillTravel: 0.5,
1259
+ strokeTravel: 1,
1228
1260
  wobble: 120,
1229
1261
  roughness: 1,
1262
+ borderWavelength: 1,
1230
1263
  waveform: 1,
1231
1264
  strokeWidth: 1.5,
1232
1265
  doubleStroke: false,
1266
+ retraceOffset: 1.2,
1267
+ retracePass: "copy",
1268
+ fillStyle: "solid",
1269
+ hatchInk: 0.4,
1270
+ strokeStyle: "dashed",
1271
+ pressure: 0,
1272
+ pressureMod: 0,
1273
+ pooling: 0,
1274
+ strokeInk: 1,
1233
1275
  maskOn: false,
1234
- iconMaskOn: false,
1276
+ maskBlobX: 100,
1277
+ maskBlobY: 100,
1278
+ maskBlobLinked: true,
1279
+ maskAngle: 0,
1280
+ maskOutputMin: 0.45,
1281
+ maskOutputMax: 1,
1282
+ maskOctaves: 2,
1283
+ maskGrain: "fractal",
1284
+ maskPosterize: 1,
1285
+ maskSoftness: 1.5,
1235
1286
  jitterX: 0,
1236
1287
  jitterY: 0,
1237
1288
  jitterRot: 0,
1238
1289
  jitterScale: 0,
1239
1290
  cornerSpread: 4,
1240
1291
  cornerTravel: 3,
1241
- pressure: 0,
1242
- pressureMod: 0,
1243
- pooling: 0,
1244
- iconTravel: 0
1292
+ iconTravel: 0,
1293
+ iconWavelength: 0.625,
1294
+ iconMaskOn: false,
1295
+ iconMaskScale: 1
1245
1296
  },
1246
- napkin: {
1247
- ...base,
1297
+ updatedAt: "2026-08-28T15:47:36.934Z",
1298
+ createdAt: "2026-08-28T15:47:36.934Z"
1299
+ };
1300
+
1301
+ // src/live-tokens/data/sketch-styles/napkin.json
1302
+ var napkin_default = {
1303
+ name: "Napkin",
1304
+ settings: {
1248
1305
  label: "Napkin",
1249
1306
  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.",
1250
1307
  fillTravel: 3,
1251
1308
  strokeTravel: 2.25,
1252
1309
  wobble: 50,
1253
1310
  roughness: 3,
1311
+ borderWavelength: 1,
1254
1312
  waveform: 2.5,
1255
1313
  strokeWidth: 2.25,
1256
1314
  doubleStroke: true,
1257
- retracePass: "reseeded",
1258
1315
  retraceOffset: 4,
1316
+ retracePass: "reseeded",
1317
+ fillStyle: "solid",
1318
+ hatchInk: 0.4,
1319
+ strokeStyle: "solid",
1320
+ pressure: 0.45,
1321
+ pressureMod: 0.6,
1322
+ pooling: 2.5,
1259
1323
  strokeInk: 1,
1260
- maskBlob: 150,
1324
+ maskOn: true,
1325
+ maskBlobX: 150,
1326
+ maskBlobY: 150,
1327
+ maskBlobLinked: true,
1328
+ maskAngle: 0,
1261
1329
  maskOutputMin: 0.43,
1262
1330
  maskOutputMax: 0.95,
1263
1331
  maskOctaves: 2,
1332
+ maskGrain: "fractal",
1264
1333
  maskPosterize: 2,
1265
1334
  maskSoftness: 10,
1266
1335
  jitterX: 6,
@@ -1269,28 +1338,47 @@ var SKETCH_STYLES = {
1269
1338
  jitterScale: 0.1,
1270
1339
  cornerSpread: 20,
1271
1340
  cornerTravel: 17,
1272
- pressure: 0.45,
1273
- pressureMod: 0.6,
1274
- pooling: 2.5,
1275
1341
  iconTravel: 2.25,
1342
+ iconWavelength: 0.625,
1343
+ iconMaskOn: true,
1276
1344
  iconMaskScale: 3.6
1277
1345
  },
1278
- dry: {
1279
- ...base,
1346
+ updatedAt: "2026-08-28T15:47:36.934Z",
1347
+ createdAt: "2026-08-28T15:47:36.934Z"
1348
+ };
1349
+
1350
+ // src/live-tokens/data/sketch-styles/dry.json
1351
+ var dry_default = {
1352
+ name: "Dry marker",
1353
+ settings: {
1280
1354
  label: "Dry marker",
1281
1355
  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.",
1282
1356
  fillTravel: 2.25,
1283
1357
  strokeTravel: 1.75,
1284
1358
  wobble: 50,
1285
- waveform: 2,
1359
+ roughness: 3,
1286
1360
  borderWavelength: 0.5,
1361
+ waveform: 2,
1287
1362
  strokeWidth: 3.5,
1288
1363
  doubleStroke: false,
1364
+ retraceOffset: 1.2,
1365
+ retracePass: "copy",
1366
+ fillStyle: "solid",
1367
+ hatchInk: 0.4,
1368
+ strokeStyle: "solid",
1369
+ pressure: 0.4,
1370
+ pressureMod: 0.8,
1371
+ pooling: 1.5,
1289
1372
  strokeInk: 0.4,
1290
- maskBlob: 150,
1373
+ maskOn: true,
1374
+ maskBlobX: 150,
1375
+ maskBlobY: 150,
1376
+ maskBlobLinked: true,
1377
+ maskAngle: 0,
1291
1378
  maskOutputMin: 0.24,
1292
1379
  maskOutputMax: 0.91,
1293
1380
  maskOctaves: 2,
1381
+ maskGrain: "fractal",
1294
1382
  maskPosterize: 4,
1295
1383
  maskSoftness: 1.75,
1296
1384
  jitterX: 5,
@@ -1299,26 +1387,34 @@ var SKETCH_STYLES = {
1299
1387
  jitterScale: 0.08,
1300
1388
  cornerSpread: 16,
1301
1389
  cornerTravel: 13,
1302
- pressure: 0.4,
1303
- pressureMod: 0.8,
1304
- pooling: 1.5,
1305
1390
  iconTravel: 1.75,
1391
+ iconWavelength: 0.625,
1392
+ iconMaskOn: true,
1306
1393
  iconMaskScale: 3.8
1307
- }
1394
+ },
1395
+ updatedAt: "2026-08-28T15:47:36.934Z",
1396
+ createdAt: "2026-08-28T15:47:36.934Z"
1308
1397
  };
1398
+
1399
+ // src/editor/core/sketch/sketchStyles.ts
1400
+ var SHIPPED_FILES = { pencil: pencil_default, marker: marker_default, whiteboard: whiteboard_default, hatched: hatched_default, dashed: dashed_default, napkin: napkin_default, dry: dry_default };
1401
+ var SKETCH_STYLES = Object.fromEntries(
1402
+ Object.entries(SHIPPED_FILES).map(([id, file]) => [id, file.settings])
1403
+ );
1309
1404
  var DEFAULT_SKETCH_STYLE = "marker";
1310
1405
  function hydrateSketchStyle(raw) {
1311
- const base2 = SKETCH_STYLES[DEFAULT_SKETCH_STYLE];
1406
+ const base = SKETCH_STYLES[DEFAULT_SKETCH_STYLE];
1312
1407
  const stored = raw ?? {};
1313
- const out = { ...base2 };
1314
- for (const key of Object.keys(base2)) {
1408
+ const out = { ...base };
1409
+ for (const key of Object.keys(base)) {
1315
1410
  if (stored[key] !== void 0) out[key] = stored[key];
1316
1411
  }
1317
- if (out.fillStyle === "none") out.fillStyle = base2.fillStyle;
1412
+ if (out.fillStyle === "none") out.fillStyle = base.fillStyle;
1318
1413
  convertTiledMask(stored, out);
1319
1414
  convertCutToLevels(stored, out);
1320
1415
  carryLevelsToOutput(stored, out);
1321
1416
  halveSwingDials(stored, out);
1417
+ splitBlobAxes(stored, out);
1322
1418
  convertCyclesToWavelength(stored, out);
1323
1419
  convertIconTileToScale(stored, out);
1324
1420
  restoreDerivedRetrace(stored, out);
@@ -1350,6 +1446,13 @@ function convertCyclesToWavelength(stored, out) {
1350
1446
  const layers = stored.octaves;
1351
1447
  if (typeof layers === "number") out.roughness = Math.min(3, Math.max(1, layers));
1352
1448
  }
1449
+ function splitBlobAxes(stored, out) {
1450
+ const blob = stored.maskBlob;
1451
+ if (typeof blob !== "number") return;
1452
+ out.maskBlobX = blob;
1453
+ out.maskBlobY = blob;
1454
+ out.maskBlobLinked = true;
1455
+ }
1353
1456
  function convertIconTileToScale(stored, out) {
1354
1457
  const tile = stored.iconMaskTile;
1355
1458
  if (typeof tile !== "number") return;
@@ -1365,7 +1468,10 @@ function convertTiledMask(stored, out) {
1365
1468
  const scale = stored.maskScale;
1366
1469
  if (typeof scale !== "number") return;
1367
1470
  const freq = stored.maskFrequency;
1368
- if (typeof freq === "number") out.maskBlob = Math.round(scale / (freq * LEGACY_TILE));
1471
+ if (typeof freq === "number") {
1472
+ out.maskBlobX = Math.round(scale / (freq * LEGACY_TILE));
1473
+ out.maskBlobY = out.maskBlobX;
1474
+ }
1369
1475
  const soft = stored.maskSoftness;
1370
1476
  if (typeof soft === "number") out.maskSoftness = Number((soft * scale / LEGACY_TILE).toFixed(1));
1371
1477
  }
@@ -1478,12 +1584,12 @@ function normalizeTheme(raw, resolvers) {
1478
1584
  }
1479
1585
  const filled = { components: [], aliases: 0, orphans: 0 };
1480
1586
  for (const comp of resolvers.listComponentNames()) {
1481
- const base2 = asObject(resolvers.readComponentConfig(comp, "default"));
1482
- const baseAliases = base2 ? asObject(base2.aliases) : null;
1483
- if (!base2 || !baseAliases) continue;
1587
+ const base = asObject(resolvers.readComponentConfig(comp, "default"));
1588
+ const baseAliases = base ? asObject(base.aliases) : null;
1589
+ if (!base || !baseAliases) continue;
1484
1590
  const entry = componentConfigs[comp];
1485
1591
  if (!entry) {
1486
- const { schemaVersion: _standaloneStamp, ...rest } = stripFileMarker(base2);
1592
+ const { schemaVersion: _standaloneStamp, ...rest } = stripFileMarker(base);
1487
1593
  componentConfigs[comp] = structuredClone(rest);
1488
1594
  filled.components.push(comp);
1489
1595
  continue;
@@ -7,7 +7,7 @@ import {
7
7
  normalizeTheme,
8
8
  planLegacyRenames,
9
9
  versionedFileResourceServer
10
- } from "../chunk-NDJJORKJ.js";
10
+ } from "../chunk-T4PMCFJN.js";
11
11
  import {
12
12
  CURRENT_COMPONENT_SCHEMA_VERSION
13
13
  } from "../chunk-NE6N66EE.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@motion-proto/live-tokens",
3
- "version": "0.65.1",
3
+ "version": "0.67.0",
4
4
  "type": "module",
5
5
  "description": "Design token editor with live CSS variable editing. Svelte 5 + Vite 8.",
6
6
  "keywords": [
@@ -41,6 +41,13 @@
41
41
  "src/live-tokens/data/themes/sketchy.json",
42
42
  "src/live-tokens/data/themes/spring-meadow.json",
43
43
  "src/live-tokens/data/themes/sunset.json",
44
+ "src/live-tokens/data/sketch-styles/pencil.json",
45
+ "src/live-tokens/data/sketch-styles/marker.json",
46
+ "src/live-tokens/data/sketch-styles/whiteboard.json",
47
+ "src/live-tokens/data/sketch-styles/hatched.json",
48
+ "src/live-tokens/data/sketch-styles/dashed.json",
49
+ "src/live-tokens/data/sketch-styles/napkin.json",
50
+ "src/live-tokens/data/sketch-styles/dry.json",
44
51
  "dist-plugin",
45
52
  ".claude/skills",
46
53
  "bin",
@@ -22,10 +22,16 @@ import * as editorStore from './core/store/editorStore';
22
22
  import * as themeDocumentSync from './core/themes/themeDocumentSync';
23
23
  import { initializeTheme } from './core/themes/themeInit';
24
24
  import { registerComponent, type RegisterComponentEntry } from './component-editor/registry';
25
+ import { registerSketchLook, type RegisterSketchLookInput } from './core/sketch/sketchRegistry';
25
26
 
26
27
  export interface BootLiveTokensOptions {
27
28
  /** Consumer-authored components to register with the editor before mount. Dev-only. */
28
29
  components?: RegisterComponentEntry[];
30
+ /** Sketchstyles this project ships, joining the shipped looks in every
31
+ picker. Registered in a build as well as in dev: carrying a customized
32
+ sketchstyle to a published site is the whole point, so these must not sit
33
+ behind the DEV guard `components` sits behind. */
34
+ sketchLooks?: RegisterSketchLookInput[];
29
35
  }
30
36
 
31
37
  export async function bootLiveTokens(
@@ -38,6 +44,12 @@ export async function bootLiveTokens(
38
44
  columnsOverlay.init();
39
45
  editorStore.init();
40
46
 
47
+ // Before the DEV block: `initializeTheme` recovers the open theme's look by
48
+ // name against the pool, so the pool has to be whole by the time it runs.
49
+ if (opts.sketchLooks) {
50
+ for (const look of opts.sketchLooks) registerSketchLook(look);
51
+ }
52
+
41
53
  if (import.meta.env.DEV) {
42
54
  themeDocumentSync.init();
43
55
  if (opts.components) {
@@ -37,7 +37,7 @@ export function bumpComponentActiveRevision(): void {
37
37
  * Set by the client writes that move the live look (`writeWorkingColorsAndType`,
38
38
  * `writeWorkingComponentConfig`, `saveActiveTheme`, `saveAsTheme`, and every
39
39
  * sketch gesture that changes what the effect paints: `setSketchEnabled`,
40
- * `updateSketchSettings`, `selectSketchStyle`, `selectSavedSketchStyle`);
40
+ * `updateSketchSettings`, `selectSketchStyle`);
41
41
  * cleared by `adoptLook` and by `hydrateAppliedTheme`, on this document and on
42
42
  * every peer an Apply broadcasts to. Module-level, so it survives the
43
43
  * remounts a view switch causes.