@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
package/CHANGELOG.md CHANGED
@@ -1,5 +1,137 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.67.0 — Every sketchstyle is a file
4
+
5
+ ### Added
6
+
7
+ - **A saved sketchstyle ships with your site.** 0.66.0 carried the look a theme
8
+ holds into a build, which covers one look per theme. Everything else a project
9
+ saved in the Sketchstyle view stayed behind: the files live in
10
+ `src/live-tokens/data/sketch-styles/` and only the dev server could read them,
11
+ so a picker on a built site silently listed the shipped seven and nothing
12
+ else. Hand them to `bootLiveTokens` and they are real everywhere:
13
+
14
+ ```ts
15
+ const files = import.meta.glob('./live-tokens/data/sketch-styles/*.json', {
16
+ eager: true,
17
+ import: 'default',
18
+ });
19
+
20
+ await bootLiveTokens(App, '#app', {
21
+ sketchLooks: Object.entries(files).map(([path, file]) => {
22
+ const id = path.split('/').pop().replace('.json', '');
23
+ return { id, label: file.name || id, settings: file.settings };
24
+ }),
25
+ });
26
+ ```
27
+
28
+ Unlike `components`, these register in a build as well as in dev. Reaching a
29
+ published site is the whole point of them.
30
+
31
+ `create` writes this into `src/main.ts`, so a new project publishes what it
32
+ saves without wiring anything.
33
+
34
+ - **A Save pill in the Sketchstyle view**, which writes the dials back over the
35
+ sketchstyle you have selected. Updating a saved sketchstyle used to run
36
+ through the naming form: open it, accept the pre-filled label, submit, and
37
+ nothing on screen said a file had been replaced rather than created. Save
38
+ lights as soon as the dials leave the sketchstyle they name. On one of your
39
+ own it writes that file; on a shipped one it writes your project's own copy
40
+ under the same name, which takes its place in the list, and deleting that file
41
+ brings the shipped look back. **Save As** always creates, and starts its form
42
+ empty to say so.
43
+
44
+ ### Changed
45
+
46
+ - **Every sketchstyle ships as a file.** The seven looks were a constant in
47
+ `sketchStyles.ts`. The Sketchstyle view could save over one, but the thing it
48
+ saved over had no file to read, copy or compare against, so "restore the
49
+ shipped Pencil" meant trusting that a deleted file fell back to something
50
+ nobody could open. They now ship as JSON under
51
+ `src/live-tokens/data/sketch-styles/`, one per look, and the module reads
52
+ them: the file is the look.
53
+
54
+ A shipped sketchstyle behaves like a shipped colors-and-type. Save over one
55
+ and your project gets its own copy that shadows it; delete that copy and the
56
+ packaged file comes back. The listing marks which is which (`isPackage`), and
57
+ deleting a look that only the package ships answers 403 rather than reporting
58
+ success and leaving it on screen.
59
+
60
+ Pencil, Marker and Whiteboard ship with reworked ink coverage. Pencil's grain
61
+ is now stretched and turned rather than square (`maskBlobX` 40 to 525 at 67
62
+ degrees, on turbulence), Marker's blobs are twice the size over a much higher
63
+ floor with the softness off, and Whiteboard's streak is finer and harder with
64
+ more rotation on the jitter. The other four are unchanged.
65
+
66
+ - **Primary and secondary buttons rest one rung lower.**
67
+ `--button-primary-surface` moves from `--surface-brand-high` to
68
+ `--surface-brand` and `--button-secondary-surface` from
69
+ `--surface-neutral-high` to `--surface-neutral`, with `--iconbutton-*`
70
+ following. The border scale runs at the same lightness as the `-high` surface
71
+ rung, so a filled button was outlined in its own fill colour: the sketch
72
+ effect's hatch, which inks itself from the part's stroke, came out invisible
73
+ on exactly these two variants while Danger, Success, and Warning shaded
74
+ normally. Those three already rest on `-low`. This puts Primary and Secondary
75
+ on the rung Badge and CornerBadge already use, and lifts white text off the
76
+ surface by a further step. The eight preset themes carry the new value.
77
+
78
+ - **Ink coverage scales on two axes, and the px it states are the px it
79
+ paints.** The Scale dial fitted a whole number of blobs to a fixed 600px tile,
80
+ so it could only reach the sizes that divide 600: it read 250px at the top of
81
+ its travel and painted 300px, there was nothing above that at all, and every
82
+ reading in between was the nearest fit rather than the number on the dial. The
83
+ tile is now painted at whatever the dial says, which makes the px exact and
84
+ opens the travel to 8px speckle and 600px patches.
85
+
86
+ The dial is a pair, **Scale across** and **Scale down**, held together by a
87
+ chain. Click it and the two part company: blobs wider than they are tall read
88
+ as ink dragged sideways, taller than wide as a vertical grain, and the fill
89
+ keeps the same field underneath either way. Sketchstyles stored before the
90
+ split come back square and linked, which is the look they had.
91
+
92
+ Unlinked, a **Rotation** dial appears with them and points the stretch
93
+ wherever you like. It is offered only there because a field the same in every
94
+ direction is the same field turned. The tile still meets itself at every
95
+ setting: a turned pattern repeats seamlessly only at the angles that land the
96
+ page's own axes back on whole noise cells, so the dial takes the nearest of
97
+ those and reads back the turn it landed on, usually within a degree or two of
98
+ the one you asked for.
99
+
100
+ - **Shipped and saved sketchstyles are one list, in one id namespace.** A
101
+ sketchstyle named after a shipped one replaces it and keeps its place, so a
102
+ project that wants its own Pencil saves one. The Sketchstyle view shows a
103
+ single grid; the ✕ marks the rows your project owns.
104
+
105
+ ### Fixed
106
+
107
+ - **Saving no longer reloads the page.** A project registers its saved
108
+ sketchstyles with `import.meta.glob`, which is what `create` writes into
109
+ `main.ts`, so writing one invalidated the entry module and Vite answered with
110
+ a full reload. The Sketchstyle view the save came from was torn down and
111
+ rebuilt mid-edit, which read as the editor closing itself every time you
112
+ pressed Save. The dev server now keeps every JSON under the data directory off
113
+ its watcher: the editor reads that directory over its own API and re-lists
114
+ after each write, so the page already holds what the reload would fetch.
115
+ `tokens.generated.css` and `fonts.css` stay watched, since the page really
116
+ does import them and CSS updates without a reload. A data file changed from
117
+ outside the editor, by a CLI run or a branch switch, now needs the page
118
+ reloaded by hand.
119
+
120
+ ### Breaking
121
+
122
+ Pre-1.0, and the sketch API is days old. Every consumer we know of is in this
123
+ repo or in a site we own.
124
+
125
+ - `SKETCH_LOOKS` is now the `sketchLooks` store, since looks register after the
126
+ module is imported and a constant array would be stale. A picker reads
127
+ `$sketchLooks` the way it already reads `$themeSketchLook`.
128
+ - `USER_STYLE_PREFIX` and `selectSavedSketchStyle` are gone. A saved
129
+ sketchstyle's id is its file slug, so `setSketch(id)` and
130
+ `selectSketchStyle(id)` take it like any other.
131
+ - A `user:` id already in a browser's storage is stripped on read, so no
132
+ migration is needed and nobody loses their selection. Themes need nothing at
133
+ all: a theme has always stored its `sketchStyle` by value, never by id.
134
+
3
135
  ## 0.66.0 — A theme's sketchstyle reaches the built site
4
136
 
5
137
  ### Added
@@ -268,65 +268,38 @@ var KNOWN_COMPONENT_CONFIG_KEYS = /* @__PURE__ */ new Set([
268
268
  "--sectiondivider-sm-color-family"
269
269
  ]);
270
270
 
271
- // src/editor/core/sketch/sketchStyles.ts
272
- var base = {
273
- label: "",
274
- blurb: "",
275
- fillTravel: 1.5,
276
- strokeTravel: 1.5,
277
- wobble: 45,
278
- roughness: 3,
279
- borderWavelength: 1,
280
- waveform: 1,
281
- strokeWidth: 1.5,
282
- doubleStroke: false,
283
- retraceOffset: 1.2,
284
- retracePass: "copy",
285
- fillStyle: "solid",
286
- hatchInk: 0.4,
287
- strokeStyle: "solid",
288
- pressure: 0.25,
289
- pressureMod: 0.35,
290
- pooling: 1.2,
291
- strokeInk: 1,
292
- maskOn: true,
293
- maskBlob: 100,
294
- maskOutputMin: 0.45,
295
- maskOutputMax: 1,
296
- maskOctaves: 2,
297
- maskGrain: "fractal",
298
- maskPosterize: 1,
299
- maskSoftness: 1.5,
300
- jitterX: 2.5,
301
- jitterY: 2.5,
302
- jitterRot: 0.6,
303
- jitterScale: 0.035,
304
- cornerSpread: 10,
305
- cornerTravel: 8,
306
- iconTravel: 1.25,
307
- iconWavelength: 0.625,
308
- iconMaskOn: true,
309
- iconMaskScale: 1
310
- };
311
- var SKETCH_STYLES = {
312
- pencil: {
313
- ...base,
271
+ // src/live-tokens/data/sketch-styles/pencil.json
272
+ var pencil_default = {
273
+ name: "Pencil",
274
+ settings: {
314
275
  label: "Pencil",
315
276
  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.",
316
277
  fillTravel: 0.75,
317
278
  strokeTravel: 1.25,
318
279
  wobble: 30,
319
280
  roughness: 3,
281
+ borderWavelength: 1,
320
282
  waveform: 1,
321
283
  strokeWidth: 1.25,
322
284
  doubleStroke: true,
323
- retracePass: "reseeded",
324
285
  retraceOffset: 1.5,
286
+ retracePass: "reseeded",
287
+ fillStyle: "solid",
288
+ hatchInk: 0.4,
289
+ strokeStyle: "solid",
290
+ pressure: 0.15,
291
+ pressureMod: 0.3,
292
+ pooling: 0,
325
293
  strokeInk: 0.85,
326
- maskBlob: 40,
327
- maskOutputMin: 0.62,
294
+ maskOn: true,
295
+ maskBlobX: 525,
296
+ maskBlobY: 47,
297
+ maskBlobLinked: false,
298
+ maskAngle: 67,
299
+ maskOutputMin: 0.59,
328
300
  maskOutputMax: 1,
329
301
  maskOctaves: 3,
302
+ maskGrain: "turbulence",
330
303
  maskPosterize: 1,
331
304
  maskSoftness: 0,
332
305
  jitterX: 1.5,
@@ -335,147 +308,243 @@ var SKETCH_STYLES = {
335
308
  jitterScale: 0.022,
336
309
  cornerSpread: 6,
337
310
  cornerTravel: 4.5,
338
- pressure: 0.15,
339
- pressureMod: 0.3,
340
- pooling: 0,
341
- iconTravel: 0.75
311
+ iconTravel: 0.75,
312
+ iconWavelength: 0.625,
313
+ iconMaskOn: true,
314
+ iconMaskScale: 1
342
315
  },
343
- marker: {
344
- ...base,
316
+ updatedAt: "2026-08-28T14:35:06.291Z",
317
+ createdAt: "2026-08-28T14:35:06.291Z"
318
+ };
319
+
320
+ // src/live-tokens/data/sketch-styles/marker.json
321
+ var marker_default = {
322
+ name: "Marker",
323
+ settings: {
345
324
  label: "Marker",
346
325
  blurb: "Broad translucent nib gone round twice on the same line, so the overlap darkens and the ink pools where it slows.",
347
326
  fillTravel: 2,
348
327
  strokeTravel: 1.5,
349
328
  wobble: 56,
350
- waveform: 1.4,
329
+ roughness: 3,
351
330
  borderWavelength: 1.3,
331
+ waveform: 1.4,
352
332
  strokeWidth: 4,
353
333
  doubleStroke: true,
334
+ retraceOffset: 2.2,
354
335
  retracePass: "copy",
336
+ fillStyle: "solid",
337
+ hatchInk: 0.4,
338
+ strokeStyle: "solid",
339
+ pressure: 0.2,
340
+ pressureMod: 0.25,
341
+ pooling: 2,
355
342
  strokeInk: 0.52,
356
- retraceOffset: 2.2,
357
- maskBlob: 115,
358
- maskOutputMin: 0.42,
343
+ maskOn: true,
344
+ maskBlobX: 230,
345
+ maskBlobY: 230,
346
+ maskBlobLinked: true,
347
+ maskAngle: 0,
348
+ maskOutputMin: 0.76,
359
349
  maskOutputMax: 1,
360
350
  maskOctaves: 3,
351
+ maskGrain: "fractal",
361
352
  maskPosterize: 4,
362
- maskSoftness: 4,
353
+ maskSoftness: 0,
363
354
  jitterX: 3,
364
355
  jitterY: 3,
365
356
  jitterRot: 0.8,
366
357
  jitterScale: 0.045,
367
358
  cornerSpread: 10,
368
359
  cornerTravel: 8,
369
- pressure: 0.2,
370
- pressureMod: 0.25,
371
- pooling: 2,
372
360
  iconTravel: 1.25,
361
+ iconWavelength: 0.625,
362
+ iconMaskOn: true,
373
363
  iconMaskScale: 4
374
364
  },
375
- whiteboard: {
376
- ...base,
365
+ updatedAt: "2026-08-28T14:45:04.324Z",
366
+ createdAt: "2026-08-28T14:45:04.324Z"
367
+ };
368
+
369
+ // src/live-tokens/data/sketch-styles/whiteboard.json
370
+ var whiteboard_default = {
371
+ name: "Whiteboard",
372
+ settings: {
377
373
  label: "Whiteboard",
378
374
  blurb: "The fattest nib on glass. One long smooth undulation, and a veined mask that streaks the fill like a half-wiped board.",
379
375
  fillTravel: 2.5,
380
376
  strokeTravel: 2.5,
381
377
  wobble: 90,
382
378
  roughness: 1,
383
- waveform: 1,
384
379
  borderWavelength: 1.5,
380
+ waveform: 1,
385
381
  strokeWidth: 5.5,
386
382
  doubleStroke: true,
383
+ retraceOffset: 3,
387
384
  retracePass: "copy",
385
+ fillStyle: "solid",
386
+ hatchInk: 0.4,
387
+ strokeStyle: "solid",
388
+ pressure: 0.15,
389
+ pressureMod: 0.15,
390
+ pooling: 3.5,
388
391
  strokeInk: 0.66,
389
- retraceOffset: 3,
390
- maskGrain: "turbulence",
391
- maskBlob: 180,
392
- maskOutputMin: 0.42,
392
+ maskOn: true,
393
+ maskBlobX: 180,
394
+ maskBlobY: 38,
395
+ maskBlobLinked: false,
396
+ maskAngle: 0,
397
+ maskOutputMin: 0.68,
393
398
  maskOutputMax: 1,
394
- maskOctaves: 1,
399
+ maskOctaves: 3,
400
+ maskGrain: "turbulence",
395
401
  maskPosterize: 3,
396
- maskSoftness: 8,
402
+ maskSoftness: 0,
397
403
  jitterX: 4.5,
398
404
  jitterY: 4.5,
399
- jitterRot: 1.2,
405
+ jitterRot: 3,
400
406
  jitterScale: 0.07,
401
407
  cornerSpread: 14,
402
408
  cornerTravel: 11,
403
- pressure: 0.15,
404
- pressureMod: 0.15,
405
- pooling: 3.5,
406
409
  iconTravel: 1.75,
410
+ iconWavelength: 0.625,
411
+ iconMaskOn: true,
407
412
  iconMaskScale: 1.5
408
413
  },
409
- hatched: {
410
- ...base,
414
+ updatedAt: "2026-08-28T14:46:58.140Z",
415
+ createdAt: "2026-08-28T14:46:58.140Z"
416
+ };
417
+
418
+ // src/live-tokens/data/sketch-styles/hatched.json
419
+ var hatched_default = {
420
+ name: "Hatched",
421
+ settings: {
411
422
  label: "Hatched",
412
423
  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.",
413
424
  fillTravel: 1.25,
414
425
  strokeTravel: 1.5,
415
426
  wobble: 24,
416
427
  roughness: 3,
428
+ borderWavelength: 1,
417
429
  waveform: 3,
418
430
  strokeWidth: 1.5,
431
+ doubleStroke: false,
432
+ retraceOffset: 1.2,
433
+ retracePass: "copy",
419
434
  fillStyle: "hatched",
420
435
  hatchInk: 0.5,
421
- doubleStroke: false,
436
+ strokeStyle: "solid",
437
+ pressure: 0.3,
438
+ pressureMod: 0.45,
439
+ pooling: 0.8,
440
+ strokeInk: 1,
422
441
  maskOn: false,
423
- iconMaskOn: false,
442
+ maskBlobX: 100,
443
+ maskBlobY: 100,
444
+ maskBlobLinked: true,
445
+ maskAngle: 0,
446
+ maskOutputMin: 0.45,
447
+ maskOutputMax: 1,
448
+ maskOctaves: 2,
449
+ maskGrain: "fractal",
450
+ maskPosterize: 1,
451
+ maskSoftness: 1.5,
424
452
  jitterX: 1.5,
425
453
  jitterY: 1.5,
426
454
  jitterRot: 0.4,
427
455
  jitterScale: 0.03,
428
456
  cornerSpread: 6,
429
457
  cornerTravel: 6,
430
- pressure: 0.3,
431
- pressureMod: 0.45,
432
- pooling: 0.8,
433
458
  iconTravel: 1.25,
434
- iconWavelength: 0.5
459
+ iconWavelength: 0.5,
460
+ iconMaskOn: false,
461
+ iconMaskScale: 1
435
462
  },
436
- dashed: {
437
- ...base,
463
+ updatedAt: "2026-08-28T15:47:36.934Z",
464
+ createdAt: "2026-08-28T15:47:36.934Z"
465
+ };
466
+
467
+ // src/live-tokens/data/sketch-styles/dashed.json
468
+ var dashed_default = {
469
+ name: "Dashed",
470
+ settings: {
438
471
  label: "Dashed",
439
472
  blurb: "A drafting outline. One slow drift along the ruler, broken into strokes, with jitter, mask and pressure all off. The clean pole.",
440
- strokeStyle: "dashed",
441
- strokeTravel: 1,
442
473
  fillTravel: 0.5,
474
+ strokeTravel: 1,
443
475
  wobble: 120,
444
476
  roughness: 1,
477
+ borderWavelength: 1,
445
478
  waveform: 1,
446
479
  strokeWidth: 1.5,
447
480
  doubleStroke: false,
481
+ retraceOffset: 1.2,
482
+ retracePass: "copy",
483
+ fillStyle: "solid",
484
+ hatchInk: 0.4,
485
+ strokeStyle: "dashed",
486
+ pressure: 0,
487
+ pressureMod: 0,
488
+ pooling: 0,
489
+ strokeInk: 1,
448
490
  maskOn: false,
449
- iconMaskOn: false,
491
+ maskBlobX: 100,
492
+ maskBlobY: 100,
493
+ maskBlobLinked: true,
494
+ maskAngle: 0,
495
+ maskOutputMin: 0.45,
496
+ maskOutputMax: 1,
497
+ maskOctaves: 2,
498
+ maskGrain: "fractal",
499
+ maskPosterize: 1,
500
+ maskSoftness: 1.5,
450
501
  jitterX: 0,
451
502
  jitterY: 0,
452
503
  jitterRot: 0,
453
504
  jitterScale: 0,
454
505
  cornerSpread: 4,
455
506
  cornerTravel: 3,
456
- pressure: 0,
457
- pressureMod: 0,
458
- pooling: 0,
459
- iconTravel: 0
507
+ iconTravel: 0,
508
+ iconWavelength: 0.625,
509
+ iconMaskOn: false,
510
+ iconMaskScale: 1
460
511
  },
461
- napkin: {
462
- ...base,
512
+ updatedAt: "2026-08-28T15:47:36.934Z",
513
+ createdAt: "2026-08-28T15:47:36.934Z"
514
+ };
515
+
516
+ // src/live-tokens/data/sketch-styles/napkin.json
517
+ var napkin_default = {
518
+ name: "Napkin",
519
+ settings: {
463
520
  label: "Napkin",
464
521
  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.",
465
522
  fillTravel: 3,
466
523
  strokeTravel: 2.25,
467
524
  wobble: 50,
468
525
  roughness: 3,
526
+ borderWavelength: 1,
469
527
  waveform: 2.5,
470
528
  strokeWidth: 2.25,
471
529
  doubleStroke: true,
472
- retracePass: "reseeded",
473
530
  retraceOffset: 4,
531
+ retracePass: "reseeded",
532
+ fillStyle: "solid",
533
+ hatchInk: 0.4,
534
+ strokeStyle: "solid",
535
+ pressure: 0.45,
536
+ pressureMod: 0.6,
537
+ pooling: 2.5,
474
538
  strokeInk: 1,
475
- maskBlob: 150,
539
+ maskOn: true,
540
+ maskBlobX: 150,
541
+ maskBlobY: 150,
542
+ maskBlobLinked: true,
543
+ maskAngle: 0,
476
544
  maskOutputMin: 0.43,
477
545
  maskOutputMax: 0.95,
478
546
  maskOctaves: 2,
547
+ maskGrain: "fractal",
479
548
  maskPosterize: 2,
480
549
  maskSoftness: 10,
481
550
  jitterX: 6,
@@ -484,28 +553,47 @@ var SKETCH_STYLES = {
484
553
  jitterScale: 0.1,
485
554
  cornerSpread: 20,
486
555
  cornerTravel: 17,
487
- pressure: 0.45,
488
- pressureMod: 0.6,
489
- pooling: 2.5,
490
556
  iconTravel: 2.25,
557
+ iconWavelength: 0.625,
558
+ iconMaskOn: true,
491
559
  iconMaskScale: 3.6
492
560
  },
493
- dry: {
494
- ...base,
561
+ updatedAt: "2026-08-28T15:47:36.934Z",
562
+ createdAt: "2026-08-28T15:47:36.934Z"
563
+ };
564
+
565
+ // src/live-tokens/data/sketch-styles/dry.json
566
+ var dry_default = {
567
+ name: "Dry marker",
568
+ settings: {
495
569
  label: "Dry marker",
496
570
  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.",
497
571
  fillTravel: 2.25,
498
572
  strokeTravel: 1.75,
499
573
  wobble: 50,
500
- waveform: 2,
574
+ roughness: 3,
501
575
  borderWavelength: 0.5,
576
+ waveform: 2,
502
577
  strokeWidth: 3.5,
503
578
  doubleStroke: false,
579
+ retraceOffset: 1.2,
580
+ retracePass: "copy",
581
+ fillStyle: "solid",
582
+ hatchInk: 0.4,
583
+ strokeStyle: "solid",
584
+ pressure: 0.4,
585
+ pressureMod: 0.8,
586
+ pooling: 1.5,
504
587
  strokeInk: 0.4,
505
- maskBlob: 150,
588
+ maskOn: true,
589
+ maskBlobX: 150,
590
+ maskBlobY: 150,
591
+ maskBlobLinked: true,
592
+ maskAngle: 0,
506
593
  maskOutputMin: 0.24,
507
594
  maskOutputMax: 0.91,
508
595
  maskOctaves: 2,
596
+ maskGrain: "fractal",
509
597
  maskPosterize: 4,
510
598
  maskSoftness: 1.75,
511
599
  jitterX: 5,
@@ -514,26 +602,34 @@ var SKETCH_STYLES = {
514
602
  jitterScale: 0.08,
515
603
  cornerSpread: 16,
516
604
  cornerTravel: 13,
517
- pressure: 0.4,
518
- pressureMod: 0.8,
519
- pooling: 1.5,
520
605
  iconTravel: 1.75,
606
+ iconWavelength: 0.625,
607
+ iconMaskOn: true,
521
608
  iconMaskScale: 3.8
522
- }
609
+ },
610
+ updatedAt: "2026-08-28T15:47:36.934Z",
611
+ createdAt: "2026-08-28T15:47:36.934Z"
523
612
  };
613
+
614
+ // src/editor/core/sketch/sketchStyles.ts
615
+ var SHIPPED_FILES = { pencil: pencil_default, marker: marker_default, whiteboard: whiteboard_default, hatched: hatched_default, dashed: dashed_default, napkin: napkin_default, dry: dry_default };
616
+ var SKETCH_STYLES = Object.fromEntries(
617
+ Object.entries(SHIPPED_FILES).map(([id, file]) => [id, file.settings])
618
+ );
524
619
  var DEFAULT_SKETCH_STYLE = "marker";
525
620
  function hydrateSketchStyle(raw) {
526
- const base2 = SKETCH_STYLES[DEFAULT_SKETCH_STYLE];
621
+ const base = SKETCH_STYLES[DEFAULT_SKETCH_STYLE];
527
622
  const stored = raw ?? {};
528
- const out = { ...base2 };
529
- for (const key of Object.keys(base2)) {
623
+ const out = { ...base };
624
+ for (const key of Object.keys(base)) {
530
625
  if (stored[key] !== void 0) out[key] = stored[key];
531
626
  }
532
- if (out.fillStyle === "none") out.fillStyle = base2.fillStyle;
627
+ if (out.fillStyle === "none") out.fillStyle = base.fillStyle;
533
628
  convertTiledMask(stored, out);
534
629
  convertCutToLevels(stored, out);
535
630
  carryLevelsToOutput(stored, out);
536
631
  halveSwingDials(stored, out);
632
+ splitBlobAxes(stored, out);
537
633
  convertCyclesToWavelength(stored, out);
538
634
  convertIconTileToScale(stored, out);
539
635
  restoreDerivedRetrace(stored, out);
@@ -565,6 +661,13 @@ function convertCyclesToWavelength(stored, out) {
565
661
  const layers = stored.octaves;
566
662
  if (typeof layers === "number") out.roughness = Math.min(3, Math.max(1, layers));
567
663
  }
664
+ function splitBlobAxes(stored, out) {
665
+ const blob = stored.maskBlob;
666
+ if (typeof blob !== "number") return;
667
+ out.maskBlobX = blob;
668
+ out.maskBlobY = blob;
669
+ out.maskBlobLinked = true;
670
+ }
568
671
  function convertIconTileToScale(stored, out) {
569
672
  const tile = stored.iconMaskTile;
570
673
  if (typeof tile !== "number") return;
@@ -580,7 +683,10 @@ function convertTiledMask(stored, out) {
580
683
  const scale = stored.maskScale;
581
684
  if (typeof scale !== "number") return;
582
685
  const freq = stored.maskFrequency;
583
- if (typeof freq === "number") out.maskBlob = Math.round(scale / (freq * LEGACY_TILE));
686
+ if (typeof freq === "number") {
687
+ out.maskBlobX = Math.round(scale / (freq * LEGACY_TILE));
688
+ out.maskBlobY = out.maskBlobX;
689
+ }
584
690
  const soft = stored.maskSoftness;
585
691
  if (typeof soft === "number") out.maskSoftness = Number((soft * scale / LEGACY_TILE).toFixed(1));
586
692
  }
@@ -693,12 +799,12 @@ function normalizeTheme(raw, resolvers) {
693
799
  }
694
800
  const filled = { components: [], aliases: 0, orphans: 0 };
695
801
  for (const comp of resolvers.listComponentNames()) {
696
- const base2 = asObject(resolvers.readComponentConfig(comp, "default"));
697
- const baseAliases = base2 ? asObject(base2.aliases) : null;
698
- if (!base2 || !baseAliases) continue;
802
+ const base = asObject(resolvers.readComponentConfig(comp, "default"));
803
+ const baseAliases = base ? asObject(base.aliases) : null;
804
+ if (!base || !baseAliases) continue;
699
805
  const entry = componentConfigs[comp];
700
806
  if (!entry) {
701
- const { schemaVersion: _standaloneStamp, ...rest } = stripFileMarker(base2);
807
+ const { schemaVersion: _standaloneStamp, ...rest } = stripFileMarker(base);
702
808
  componentConfigs[comp] = structuredClone(rest);
703
809
  filled.components.push(comp);
704
810
  continue;