@pixerate/editor 0.270.0 → 0.272.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 (77) hide show
  1. package/dist/animation-editor/index.cjs +62 -62
  2. package/dist/animation-editor/index.js +5 -5
  3. package/dist/brushes/index.cjs +69 -66
  4. package/dist/brushes/index.js +6 -3
  5. package/dist/brushes/patch.d.cts +1 -1
  6. package/dist/brushes/patch.d.ts +1 -1
  7. package/dist/brushes/schema.d.cts +1 -0
  8. package/dist/brushes/schema.d.ts +1 -0
  9. package/dist/brushes/types.d.cts +8 -0
  10. package/dist/brushes/types.d.ts +8 -0
  11. package/dist/{brushstrokeRender-WR2N5HHY.cjs → brushstrokeRender-5YBCLFDQ.cjs} +15 -15
  12. package/dist/{brushstrokeRender-A727TTNQ.js → brushstrokeRender-DZGFU3J4.js} +3 -3
  13. package/dist/canvas/index.cjs +15 -15
  14. package/dist/canvas/index.js +2 -2
  15. package/dist/{chunk-THBJHPUL.js → chunk-2F3YDXCN.js} +1 -1
  16. package/dist/{chunk-4CPOKP27.js → chunk-2XDNF73E.js} +1 -1
  17. package/dist/{chunk-3KNQ2W6X.cjs → chunk-3JKCREEU.cjs} +59 -53
  18. package/dist/{chunk-4YSPQGZW.js → chunk-5HP2VSAS.js} +1 -1
  19. package/dist/{chunk-BPJSI4NT.cjs → chunk-7W2EQQBP.cjs} +2 -2
  20. package/dist/{chunk-LETF75CA.js → chunk-CLB2I2FU.js} +1 -1
  21. package/dist/{chunk-BAZMCFVL.js → chunk-DZVRH63Y.js} +1 -1
  22. package/dist/{chunk-PY4GWSE2.cjs → chunk-EBFPMSJO.cjs} +27 -5
  23. package/dist/{chunk-VBRHE4AM.cjs → chunk-FXVCB6YG.cjs} +35 -35
  24. package/dist/{chunk-EU2ZZA6L.cjs → chunk-GHGBIAWQ.cjs} +126 -39
  25. package/dist/{chunk-CBVNCWJM.cjs → chunk-LBDC5434.cjs} +2 -2
  26. package/dist/{chunk-2WOGXEDX.cjs → chunk-M3RZOF3G.cjs} +1 -1
  27. package/dist/{chunk-GSTSZPSR.js → chunk-N3SKPQEH.js} +225 -18
  28. package/dist/{chunk-J5VQYK7T.cjs → chunk-N5IMDAHM.cjs} +251 -44
  29. package/dist/{chunk-ININNHLM.js → chunk-NAHJV3O6.js} +11 -5
  30. package/dist/{chunk-MWUZCEFT.js → chunk-S2XPXA47.js} +1 -1
  31. package/dist/{chunk-56RHCIJV.cjs → chunk-SNAFFCAX.cjs} +296 -203
  32. package/dist/{chunk-EHLOCVWB.js → chunk-T2URHAJX.js} +27 -5
  33. package/dist/{chunk-BENSE3VX.cjs → chunk-TNLKFW7D.cjs} +23 -23
  34. package/dist/{chunk-KZI3YWKW.js → chunk-UXYCY3HP.js} +93 -6
  35. package/dist/{chunk-4NMPUJUK.cjs → chunk-YJANF2BL.cjs} +86 -86
  36. package/dist/{chunk-FUDP5QBB.js → chunk-ZEI7ZEA4.js} +101 -8
  37. package/dist/effects/index.cjs +5 -2
  38. package/dist/effects/index.js +4 -1
  39. package/dist/effects/pool.d.cts +9 -0
  40. package/dist/effects/pool.d.ts +9 -0
  41. package/dist/effects/types.d.cts +2 -0
  42. package/dist/effects/types.d.ts +2 -0
  43. package/dist/image-editor/index.cjs +791 -791
  44. package/dist/image-editor/index.js +6 -6
  45. package/dist/paint/index.cjs +2 -2
  46. package/dist/paint/index.js +1 -1
  47. package/dist/paint/wet/world.d.cts +37 -1
  48. package/dist/paint/wet/world.d.ts +37 -1
  49. package/dist/paint-editor/brush-controls.d.cts +2 -0
  50. package/dist/paint-editor/brush-controls.d.ts +2 -0
  51. package/dist/paint-editor/brush-model.d.cts +14 -1
  52. package/dist/paint-editor/brush-model.d.ts +14 -1
  53. package/dist/paint-editor/controller.d.cts +75 -4
  54. package/dist/paint-editor/controller.d.ts +75 -4
  55. package/dist/paint-editor/effect-paint.d.cts +33 -8
  56. package/dist/paint-editor/effect-paint.d.ts +33 -8
  57. package/dist/paint-editor/effects.d.cts +4 -0
  58. package/dist/paint-editor/effects.d.ts +4 -0
  59. package/dist/paint-editor/index.cjs +814 -483
  60. package/dist/paint-editor/index.js +408 -77
  61. package/dist/paint-editor/stroke.d.cts +13 -5
  62. package/dist/paint-editor/stroke.d.ts +13 -5
  63. package/dist/paint-editor/ui.d.cts +1 -1
  64. package/dist/paint-editor/ui.d.ts +1 -1
  65. package/dist/paint-editor/wet.d.cts +8 -1
  66. package/dist/paint-editor/wet.d.ts +8 -1
  67. package/dist/vector/index.cjs +999 -999
  68. package/dist/vector/index.js +5 -5
  69. package/dist/video-editor/index.cjs +317 -317
  70. package/dist/video-editor/index.js +2 -2
  71. package/package.json +1 -1
  72. package/skills/pixerate-brushes/SKILL.md +1 -0
  73. package/skills/pixerate-paint-editor/SKILL.md +6 -13
  74. package/skills/pixerate-paint-editor/references/brush-facets.md +1 -0
  75. package/skills/pixerate-paint-editor/references/effect-paint.md +28 -6
  76. package/skills/pixerate-paint-editor/references/ghost.md +47 -0
  77. package/skills/pixerate-paint-watercolour/SKILL.md +1 -0
@@ -11,7 +11,8 @@ var _chunk3VHH6V67cjs = require('../chunk-3VHH6V67.cjs');
11
11
 
12
12
 
13
13
 
14
- var _chunk3KNQ2W6Xcjs = require('../chunk-3KNQ2W6X.cjs');
14
+
15
+ var _chunk3JKCREEUcjs = require('../chunk-3JKCREEU.cjs');
15
16
 
16
17
 
17
18
 
@@ -19,10 +20,10 @@ var _chunkPFHJS4HEcjs = require('../chunk-PFHJS4HE.cjs');
19
20
 
20
21
 
21
22
 
22
- var _chunkBPJSI4NTcjs = require('../chunk-BPJSI4NT.cjs');
23
+ var _chunk7W2EQQBPcjs = require('../chunk-7W2EQQBP.cjs');
23
24
 
24
25
 
25
- var _chunkCBVNCWJMcjs = require('../chunk-CBVNCWJM.cjs');
26
+ var _chunkLBDC5434cjs = require('../chunk-LBDC5434.cjs');
26
27
 
27
28
 
28
29
  var _chunk7TD63DZPcjs = require('../chunk-7TD63DZP.cjs');
@@ -34,7 +35,7 @@ var _chunk7TD63DZPcjs = require('../chunk-7TD63DZP.cjs');
34
35
 
35
36
 
36
37
 
37
- var _chunk4NMPUJUKcjs = require('../chunk-4NMPUJUK.cjs');
38
+ var _chunkYJANF2BLcjs = require('../chunk-YJANF2BL.cjs');
38
39
  require('../chunk-YZWM6ZIP.cjs');
39
40
  require('../chunk-3ZRNK3RO.cjs');
40
41
 
@@ -113,7 +114,11 @@ var _chunkK7ENM55Pcjs = require('../chunk-K7ENM55P.cjs');
113
114
 
114
115
 
115
116
 
116
- var _chunk56RHCIJVcjs = require('../chunk-56RHCIJV.cjs');
117
+
118
+
119
+
120
+
121
+ var _chunkSNAFFCAXcjs = require('../chunk-SNAFFCAX.cjs');
117
122
 
118
123
 
119
124
 
@@ -176,7 +181,9 @@ var _chunk56RHCIJVcjs = require('../chunk-56RHCIJV.cjs');
176
181
 
177
182
 
178
183
 
179
- var _chunkEU2ZZA6Lcjs = require('../chunk-EU2ZZA6L.cjs');
184
+
185
+
186
+ var _chunkGHGBIAWQcjs = require('../chunk-GHGBIAWQ.cjs');
180
187
 
181
188
 
182
189
 
@@ -201,7 +208,8 @@ var _chunkJBZRVLXVcjs = require('../chunk-JBZRVLXV.cjs');
201
208
  var _chunkU67EN7GGcjs = require('../chunk-U67EN7GG.cjs');
202
209
 
203
210
 
204
- var _chunkPY4GWSE2cjs = require('../chunk-PY4GWSE2.cjs');
211
+ var _chunkEBFPMSJOcjs = require('../chunk-EBFPMSJO.cjs');
212
+
205
213
 
206
214
 
207
215
 
@@ -223,7 +231,7 @@ require('../chunk-WOFXZ3XU.cjs');
223
231
 
224
232
 
225
233
 
226
- var _chunkJ5VQYK7Tcjs = require('../chunk-J5VQYK7T.cjs');
234
+ var _chunkN5IMDAHMcjs = require('../chunk-N5IMDAHM.cjs');
227
235
  require('../chunk-STLTOISW.cjs');
228
236
 
229
237
 
@@ -380,7 +388,7 @@ function normalizeCanvas(raw) {
380
388
  function createPaintDocument(options = {}) {
381
389
  const canvas = normalizeCanvas({ width: _nullishCoalesce(options.width, () => ( 2048)), height: _nullishCoalesce(options.height, () => ( 1536)), dpi: options.dpi });
382
390
  const layer = createPaintLayer("Layer 1");
383
- return { canvas, paper: _chunk56RHCIJVcjs.normalizePaper.call(void 0, _nullishCoalesce(options.paper, () => ( {}))), layers: [layer], activeLayerId: layer.id, strokes: [] };
391
+ return { canvas, paper: _chunkSNAFFCAXcjs.normalizePaper.call(void 0, _nullishCoalesce(options.paper, () => ( {}))), layers: [layer], activeLayerId: layer.id, strokes: [] };
384
392
  }
385
393
 
386
394
  // src/paint-editor/thick.ts
@@ -448,10 +456,10 @@ function lightTile(color, height, heightAround, material, light) {
448
456
  const nh = Math.max(0, nx * hx + ny * hy + nz * hz);
449
457
  const spec = Math.max(0, Math.pow(nh, shininess) - Math.pow(hz, shininess)) * (0.25 + 0.75 * gloss) * light.relief;
450
458
  for (let c = 0; c < 3; c++) {
451
- const a = _chunkJ5VQYK7Tcjs.SRGB_TO_LINEAR[color[i + c]];
459
+ const a = _chunkN5IMDAHMcjs.SRGB_TO_LINEAR[color[i + c]];
452
460
  const tint = metal * a + (1 - metal);
453
461
  const v = a * shade * (1 - 0.35 * metal) + spec * tint * (1 + metal);
454
- out[i + c] = _chunkJ5VQYK7Tcjs.linearToSrgb8.call(void 0, v);
462
+ out[i + c] = _chunkN5IMDAHMcjs.linearToSrgb8.call(void 0, v);
455
463
  }
456
464
  }
457
465
  }
@@ -511,12 +519,12 @@ var ThickStrokeDriver = (_class2 = class {
511
519
  constructor(init) {;_class2.prototype.__init2.call(this);_class2.prototype.__init3.call(this);_class2.prototype.__init4.call(this);_class2.prototype.__init5.call(this);_class2.prototype.__init6.call(this);_class2.prototype.__init7.call(this);_class2.prototype.__init8.call(this);_class2.prototype.__init9.call(this);_class2.prototype.__init10.call(this);_class2.prototype.__init11.call(this);
512
520
  this.init = init;
513
521
  const b = init.brush;
514
- this.smoother = new (0, _chunk56RHCIJVcjs.PenSmoother)(b.tip.smoothing, b.pressureSmoothing);
515
- const copies = init.copies.length ? init.copies : [_chunk56RHCIJVcjs.IDENTITY_COPY];
522
+ this.smoother = new (0, _chunkSNAFFCAXcjs.PenSmoother)(b.tip.smoothing, b.pressureSmoothing);
523
+ const copies = init.copies.length ? init.copies : [_chunkSNAFFCAXcjs.IDENTITY_COPY];
516
524
  this.copies = copies;
517
525
  const rates = _chunkNIBFKXMDcjs.exchangeRates.call(void 0, b.behavior.pickup, b.behavior.mix, 1, b.behavior.mixing);
518
526
  this.states = copies.map((c, i) => ({
519
- walker: new (0, _chunk56RHCIJVcjs.PenDabWalker)(b, init.seed + i * 7919 | 0, c.linear),
527
+ walker: new (0, _chunkSNAFFCAXcjs.PenDabWalker)(b, init.seed + i * 7919 | 0, c.linear),
520
528
  exchange: new (0, _chunkNIBFKXMDcjs.PaintExchange)(rates, init.load),
521
529
  smudge: b.impasto.tool === "knife" ? new (0, _chunkNIBFKXMDcjs.SmudgeTip)({ strength: 0.85, length: 0.6 + 0.38 * b.impasto.drag, mixing: b.behavior.mixing }, b.tip.size * 1.2) : null,
522
530
  carried: null,
@@ -662,7 +670,7 @@ var ThickStrokeDriver = (_class2 = class {
662
670
  let flow = 1;
663
671
  const effect = this.init.effect;
664
672
  if (effect) {
665
- _chunk56RHCIJVcjs.sampleEffectAt.call(void 0, effect, d.x, d.y, this.centre, d);
673
+ _chunkSNAFFCAXcjs.sampleEffectAt.call(void 0, effect, d.x, d.y, this.centre, d);
666
674
  ex.setReservoirColor(this.centre[0], this.centre[1], this.centre[2]);
667
675
  } else if (this.sampler) {
668
676
  const g = this.sampler.dab(d, this.sample);
@@ -679,7 +687,7 @@ var ThickStrokeDriver = (_class2 = class {
679
687
  let field = null;
680
688
  if (effect) {
681
689
  field = new Float32Array(n * 3);
682
- _chunk56RHCIJVcjs.effectDabField.call(void 0, effect, rect, cov, this.centre, this.paint, field, 0, d);
690
+ _chunkSNAFFCAXcjs.effectDabField.call(void 0, effect, rect, cov, this.centre, this.paint, field, 0, d);
683
691
  }
684
692
  this.medium.deposit(rect, cov, dep, this.paint, ex.paintPigment, field);
685
693
  }
@@ -856,7 +864,7 @@ function shadowToLight(shadow) {
856
864
  return new (0, _chunk474IQG74cjs.TiledSurface)(1, tiles, 0);
857
865
  }
858
866
  function lightTwinBrush(brush) {
859
- return _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0,
867
+ return _chunkGHGBIAWQcjs.normalizePaintBrush.call(void 0,
860
868
  {
861
869
  tip: { ...brush.tip, blend: "normal", pressureOpacity: brush.tip.pressureOpacity || brush.light.pressure },
862
870
  behavior: { ...brush.behavior, mixing: "rgb" },
@@ -1068,11 +1076,11 @@ var MarkStroke = (_class4 = class {
1068
1076
  this.options = options;
1069
1077
  this.sampler = options.paint ? new (0, _chunkNIBFKXMDcjs.PaintGradientSampler)(options.paint, _nullishCoalesce(options.seed, () => ( 0))) : null;
1070
1078
  this.tipTable = _optionalChain([this, 'access', _29 => _29.sampler, 'optionalAccess', _30 => _30.acrossTip]) ? this.sampler.tipTable(_chunkNIBFKXMDcjs.TIP_GRADIENT_STEPS) : null;
1071
- this.smoother = new (0, _chunk56RHCIJVcjs.PenSmoother)(brush.tip.smoothing, brush.pressureSmoothing);
1072
- this.copies = _optionalChain([options, 'access', _31 => _31.copies, 'optionalAccess', _32 => _32.length]) ? options.copies : [_chunk56RHCIJVcjs.IDENTITY_COPY];
1079
+ this.smoother = new (0, _chunkSNAFFCAXcjs.PenSmoother)(brush.tip.smoothing, brush.pressureSmoothing);
1080
+ this.copies = _optionalChain([options, 'access', _31 => _31.copies, 'optionalAccess', _32 => _32.length]) ? options.copies : [_chunkSNAFFCAXcjs.IDENTITY_COPY];
1073
1081
  this.seed = _nullishCoalesce(options.seed, () => ( 0));
1074
1082
  const fine = { ...brush, tip: { ...brush.tip, spacing: Math.max(0.01, Math.min(0.25, STEP_PX / Math.max(1, brush.tip.size))) } };
1075
- this.walkers = this.copies.map((c, i) => new (0, _chunk56RHCIJVcjs.PenDabWalker)(fine, (_nullishCoalesce(options.seed, () => ( 0))) + i * 7919 | 0, c.linear));
1083
+ this.walkers = this.copies.map((c, i) => new (0, _chunkSNAFFCAXcjs.PenDabWalker)(fine, (_nullishCoalesce(options.seed, () => ( 0))) + i * 7919 | 0, c.linear));
1076
1084
  this.depth = options.grain && !options.grain.flat ? Math.min(1, Math.max(0, options.paperDepth * brush.grain)) : 0;
1077
1085
  }
1078
1086
 
@@ -1151,7 +1159,7 @@ var MarkStroke = (_class4 = class {
1151
1159
  */
1152
1160
  stamp(x, y, r, kind, rotation, seed, alpha, opacity, pressure, rects) {
1153
1161
  if (!(r > 0.05) || !(alpha > 0)) return;
1154
- const sample = _chunk56RHCIJVcjs.stampSampler.call(void 0, kind, this.options.stampArt);
1162
+ const sample = _chunkSNAFFCAXcjs.stampSampler.call(void 0, kind, this.options.stampArt);
1155
1163
  if (!sample) return this.mark(x, y, r, alpha, opacity, pressure, rects);
1156
1164
  const reach = Math.max(0.5, r) * Math.SQRT2 + 1;
1157
1165
  const rect = { x: Math.floor(x - reach), y: Math.floor(y - reach), width: 0, height: 0 };
@@ -1201,7 +1209,7 @@ var MarkStroke = (_class4 = class {
1201
1209
  if (this.options.effect) {
1202
1210
  if (this.field.length < n * 3) this.field = new Float32Array(n * 3);
1203
1211
  const field = this.field.subarray(0, n * 3);
1204
- _chunk56RHCIJVcjs.sampleEffectField.call(void 0, this.options.effect, rect, vals, field, this.pen);
1212
+ _chunkSNAFFCAXcjs.sampleEffectField.call(void 0, this.options.effect, rect, vals, field, this.pen);
1205
1213
  this.coverage.accumulate(rect, vals, opacity, null, field);
1206
1214
  } else {
1207
1215
  const color = this.markColor(x, y);
@@ -1880,11 +1888,11 @@ var StickerSpray = (_class7 = class {
1880
1888
  constructor(init) {;_class7.prototype.__init29.call(this);_class7.prototype.__init30.call(this);_class7.prototype.__init31.call(this);_class7.prototype.__init32.call(this);_class7.prototype.__init33.call(this);
1881
1889
  this.init = init;
1882
1890
  const b = init.brush;
1883
- this.smoother = new (0, _chunk56RHCIJVcjs.PenSmoother)(b.tip.smoothing, b.pressureSmoothing);
1884
- this.copies = init.copies.length ? init.copies : [_chunk56RHCIJVcjs.IDENTITY_COPY];
1891
+ this.smoother = new (0, _chunkSNAFFCAXcjs.PenSmoother)(b.tip.smoothing, b.pressureSmoothing);
1892
+ this.copies = init.copies.length ? init.copies : [_chunkSNAFFCAXcjs.IDENTITY_COPY];
1885
1893
  const spacing = Math.max(0.05, 1 / Math.max(0.05, b.sticker.density * 4));
1886
1894
  const walk = { ...b, tip: { ...b.tip, spacing }, dynamics: { ...b.dynamics, scatter: 0, sizeJitter: 0, angleJitter: 0 } };
1887
- this.walkers = this.copies.map((c, i) => new (0, _chunk56RHCIJVcjs.PenDabWalker)(walk, init.seed + i * 7919 | 0, c.linear));
1895
+ this.walkers = this.copies.map((c, i) => new (0, _chunkSNAFFCAXcjs.PenDabWalker)(walk, init.seed + i * 7919 | 0, c.linear));
1888
1896
  this.medium = new (0, _chunkNIBFKXMDcjs.TileMedium)(init.target, {});
1889
1897
  this.next = init.nextId;
1890
1898
  }
@@ -1970,7 +1978,7 @@ var StickerSpray = (_class7 = class {
1970
1978
  const effect = this.init.effect;
1971
1979
  if (effect) {
1972
1980
  const rgb = [0, 0, 0];
1973
- const alpha = _chunk56RHCIJVcjs.sampleEffectAt.call(void 0, effect, d.x + dx, d.y + dy, rgb, d);
1981
+ const alpha = _chunkSNAFFCAXcjs.sampleEffectAt.call(void 0, effect, d.x + dx, d.y + dy, rgb, d);
1974
1982
  return { color: "#" + rgb.map((c) => Math.round(c * 255).toString(16).padStart(2, "0")).join(""), alpha };
1975
1983
  }
1976
1984
  const g = this.init.paint;
@@ -2099,11 +2107,10 @@ var PaintStrokeSession = (_class8 = class _PaintStrokeSession {
2099
2107
  this.layerId = init.layerId;
2100
2108
  this.base = init.surface;
2101
2109
  this.live = new Map(this.base.tiles);
2102
- this.copies = init.copies.length ? init.copies : [_chunk56RHCIJVcjs.IDENTITY_COPY];
2110
+ this.copies = init.copies.length ? init.copies : [_chunkSNAFFCAXcjs.IDENTITY_COPY];
2103
2111
  const brush = init.brush;
2104
2112
  if (init.wet) this.wetDriver = init.wet.driver;
2105
2113
  if (init.light && !init.wet && !init.sticker) this.lightTwin = this.makeLightTwin(init.light.surface);
2106
- const effect = _nullishCoalesce(_optionalChain([init, 'access', _50 => _50.effect, 'optionalAccess', _51 => _51.pixels]), () => ( null));
2107
2114
  this.apply = {
2108
2115
  mode: brush.engine === "eraser" ? "erase" : "paint",
2109
2116
  color: init.color,
@@ -2114,31 +2121,7 @@ var PaintStrokeSession = (_class8 = class _PaintStrokeSession {
2114
2121
  selection: _nullishCoalesce(init.selection, () => ( null)),
2115
2122
  offset: init.offset
2116
2123
  };
2117
- if (this.wetDriver) {
2118
- } else if (init.sticker) {
2119
- this.stickerSpray = new StickerSpray({ brush, target: this.tileTarget(), color: init.colorHex, seed: init.seed, copies: this.copies, nextId: init.sticker.nextId, paint: _nullishCoalesce(init.paint, () => ( null)), effect, art: init.sticker.art, variant: init.sticker.variant });
2120
- } else if (init.thick) {
2121
- const rgb = (c) => [c[0] / 255, c[1] / 255, c[2] / 255];
2122
- this.thickDriver = new ThickStrokeDriver({ brush, target: this.tileTarget(), channels: init.thick.channels, color: rgb(init.color), load: init.mixerLoad, seed: init.seed, copies: this.copies, paint: _nullishCoalesce(init.paint, () => ( null)), effect });
2123
- } else if (brush.engine === "mixer" || brush.engine === "blender" || brush.engine === "smudge" || _chunkEU2ZZA6Lcjs.usesPaintExchange.call(void 0, brush, Boolean(init.paint))) {
2124
- const rgb = (c) => [c[0] / 255, c[1] / 255, c[2] / 255];
2125
- this.wet = new (0, _chunk56RHCIJVcjs.PaintDabStroke)(brush, {
2126
- target: this.tileTarget(),
2127
- color: rgb(init.color),
2128
- secondary: rgb(_nullishCoalesce(init.secondary, () => ( init.background))),
2129
- load: init.mixerLoad,
2130
- grain: init.grain,
2131
- paperDepth: init.paperDepth,
2132
- seed: init.seed,
2133
- copies: this.copies,
2134
- paint: _nullishCoalesce(init.paint, () => ( null)),
2135
- effect,
2136
- stampArt: init.stampArt
2137
- });
2138
- } else {
2139
- const opts = { grain: init.grain, paperDepth: init.paperDepth, seed: init.seed, copies: this.copies, paint: _nullishCoalesce(init.paint, () => ( null)), effect, stampArt: init.stampArt };
2140
- this.dry = brush.engine === "particle" ? new ParticleStroke(brush, opts) : brush.engine === "bristle" ? new BristleStroke(brush, opts) : new (0, _chunk56RHCIJVcjs.DryStroke)(brush, opts);
2141
- }
2124
+ if (!this.wetDriver) this.build(_nullishCoalesce(_optionalChain([init, 'access', _50 => _50.effect, 'optionalAccess', _51 => _51.pixels]), () => ( null)));
2142
2125
  }
2143
2126
 
2144
2127
 
@@ -2167,6 +2150,52 @@ var PaintStrokeSession = (_class8 = class _PaintStrokeSession {
2167
2150
  __init48() {this.result = null}
2168
2151
  /** The mask stencils this stroke was painted with when they are not the editor's (replays). */
2169
2152
  __init49() {this.maskStencils = null}
2153
+ /** Sets up the marks' engine (every kind but wet, which the wet layer paints), sampling `effect` for effect paint. */
2154
+ build(effect) {
2155
+ const init = this.init;
2156
+ const brush = init.brush;
2157
+ this.dry = this.wet = this.thickDriver = this.stickerSpray = null;
2158
+ if (init.sticker) {
2159
+ this.stickerSpray = new StickerSpray({ brush, target: this.tileTarget(), color: init.colorHex, seed: init.seed, copies: this.copies, nextId: init.sticker.nextId, paint: _nullishCoalesce(init.paint, () => ( null)), effect, art: init.sticker.art, variant: init.sticker.variant });
2160
+ } else if (init.thick) {
2161
+ const rgb = (c) => [c[0] / 255, c[1] / 255, c[2] / 255];
2162
+ this.thickDriver = new ThickStrokeDriver({ brush, target: this.tileTarget(), channels: init.thick.channels, color: rgb(init.color), load: init.mixerLoad, seed: init.seed, copies: this.copies, paint: _nullishCoalesce(init.paint, () => ( null)), effect });
2163
+ } else if (brush.engine === "mixer" || brush.engine === "blender" || brush.engine === "smudge" || _chunkGHGBIAWQcjs.usesPaintExchange.call(void 0, brush, Boolean(init.paint))) {
2164
+ const rgb = (c) => [c[0] / 255, c[1] / 255, c[2] / 255];
2165
+ this.wet = new (0, _chunkSNAFFCAXcjs.PaintDabStroke)(brush, {
2166
+ target: this.tileTarget(),
2167
+ color: rgb(init.color),
2168
+ secondary: rgb(_nullishCoalesce(init.secondary, () => ( init.background))),
2169
+ load: init.mixerLoad,
2170
+ grain: init.grain,
2171
+ paperDepth: init.paperDepth,
2172
+ seed: init.seed,
2173
+ copies: this.copies,
2174
+ paint: _nullishCoalesce(init.paint, () => ( null)),
2175
+ effect,
2176
+ stampArt: init.stampArt
2177
+ });
2178
+ } else {
2179
+ const opts = { grain: init.grain, paperDepth: init.paperDepth, seed: init.seed, copies: this.copies, paint: _nullishCoalesce(init.paint, () => ( null)), effect, stampArt: init.stampArt };
2180
+ this.dry = brush.engine === "particle" ? new ParticleStroke(brush, opts) : brush.engine === "bristle" ? new BristleStroke(brush, opts) : new (0, _chunkSNAFFCAXcjs.DryStroke)(brush, opts);
2181
+ }
2182
+ }
2183
+ /**
2184
+ * Paints the stroke so far again, sampling new effect pixels: a path-mapped effect rendered
2185
+ * along the path drawn so far (`map: { by: 'path' }`). Only the live preview changes; the stroke
2186
+ * keeps recording its own paint. Nothing for wet strokes or once the stroke has ended.
2187
+ */
2188
+ repaintEffect(pixels) {
2189
+ if (this.closed || this.wetDriver || !this.init.effect) return;
2190
+ const was = this.bounds;
2191
+ this.live = new Map(this.base.tiles);
2192
+ this.touched.clear();
2193
+ this.fresh.clear();
2194
+ this.bounds = null;
2195
+ this.build(pixels);
2196
+ const rects = this.points.length ? this.dry ? this.dry.push(this.points) : this.thickDriver ? this.thickDriver.push(this.points) : this.stickerSpray ? this.stickerSpray.push(this.points) : this.wet.push(this.points) : [];
2197
+ this.update(was ? [...rects, was] : rects);
2198
+ }
2170
2199
  /** The stroke's twin over the light channel: the same marks in grey at the brush's light amount (see `light.ts`). */
2171
2200
  makeLightTwin(light) {
2172
2201
  const init = this.init;
@@ -2360,7 +2389,7 @@ function brushLoadForStroke(brush, current, color) {
2360
2389
  if (brush.engine === "mixer") return mixerLoadForStroke(brush, current, color);
2361
2390
  if (brush.engine === "impasto") return { reservoir: [color[0], color[1], color[2]], amount: 1, pickup: brush.behavior.dirty ? current.pickup : null };
2362
2391
  if (brush.engine === "wet") return brush.wet.tool === "paint" ? { reservoir: [color[0], color[1], color[2]], amount: 1, pickup: brush.behavior.dirty ? current.pickup : null } : _chunkNIBFKXMDcjs.EMPTY_MIXER_LOAD;
2363
- if (_chunkEU2ZZA6Lcjs.usesPaintExchange.call(void 0, brush)) return { reservoir: [color[0], color[1], color[2]], amount: 1, pickup: brush.behavior.dirty ? current.pickup : null };
2392
+ if (_chunkGHGBIAWQcjs.usesPaintExchange.call(void 0, brush)) return { reservoir: [color[0], color[1], color[2]], amount: 1, pickup: brush.behavior.dirty ? current.pickup : null };
2364
2393
  return _chunkNIBFKXMDcjs.EMPTY_MIXER_LOAD;
2365
2394
  }
2366
2395
 
@@ -2622,15 +2651,15 @@ function readLoad(raw) {
2622
2651
  function readStrokeBrush(raw) {
2623
2652
  if (raw && typeof raw === "object" && "kind" in raw && !("engine" in raw)) {
2624
2653
  try {
2625
- return _chunkEU2ZZA6Lcjs.resolveBrush.call(void 0, _chunkEU2ZZA6Lcjs.normalizeBrushSpec.call(void 0, raw));
2654
+ return _chunkGHGBIAWQcjs.resolveBrush.call(void 0, _chunkGHGBIAWQcjs.normalizeBrushSpec.call(void 0, raw));
2626
2655
  } catch (e3) {
2627
2656
  }
2628
2657
  }
2629
- return _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, _nullishCoalesce(raw, () => ( {})));
2658
+ return _chunkGHGBIAWQcjs.normalizePaintBrush.call(void 0, _nullishCoalesce(raw, () => ( {})));
2630
2659
  }
2631
2660
  function strokeToJSON(stroke) {
2632
2661
  const { brush, ...rest } = stroke;
2633
- return { ...JSON.parse(JSON.stringify(rest)), brush: _chunkEU2ZZA6Lcjs.migrateBrushV1.call(void 0, brush) };
2662
+ return { ...JSON.parse(JSON.stringify(rest)), brush: _chunkGHGBIAWQcjs.migrateBrushV1.call(void 0, brush) };
2634
2663
  }
2635
2664
  function normalizeBrushStroke(raw) {
2636
2665
  if (!raw || typeof raw !== "object") return null;
@@ -2660,7 +2689,7 @@ function normalizeBrushStroke(raw) {
2660
2689
  }
2661
2690
  if (st.length) out.stencils = st;
2662
2691
  }
2663
- const effect = _chunk56RHCIJVcjs.readPaintEffectPaint.call(void 0, r.paint);
2692
+ const effect = _chunkSNAFFCAXcjs.readPaintEffectPaint.call(void 0, r.paint);
2664
2693
  const paint = effect ? null : _chunkNIBFKXMDcjs.readPaintSource.call(void 0, r.paint);
2665
2694
  if (effect) out.paint = effect;
2666
2695
  else if (paint && paint.type === "gradient") out.paint = paint;
@@ -2700,11 +2729,12 @@ function varyStroke(stroke, m, v) {
2700
2729
  if (ps !== 1) q.pressure = Math.min(1, Math.max(0, (_nullishCoalesce(p.pressure, () => ( 1))) * ps));
2701
2730
  return q;
2702
2731
  });
2703
- const brush = s !== 1 ? _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, { ...stroke.brush, tip: { ...stroke.brush.tip, size: stroke.brush.tip.size * s } }) : stroke.brush;
2732
+ const brush = s !== 1 ? _chunkGHGBIAWQcjs.normalizePaintBrush.call(void 0, { ...stroke.brush, tip: { ...stroke.brush.tip, size: stroke.brush.tip.size * s } }) : stroke.brush;
2704
2733
  const out = { ...stroke, brush, points };
2705
2734
  if (_optionalChain([stroke, 'access', _107 => _107.paint, 'optionalAccess', _108 => _108.type]) === "gradient" && s !== 1) out.paint = _chunkNIBFKXMDcjs.scalePaintGradient.call(void 0, stroke.paint, s);
2706
- if (_optionalChain([stroke, 'access', _109 => _109.paint, 'optionalAccess', _110 => _110.type]) === "effect" && stroke.paint.map && s !== 1) out.paint = { ...stroke.paint, map: { ...stroke.paint.map, length: Math.min(4096, Math.max(16, Math.round(stroke.paint.map.length * s))) } };
2707
- if (_optionalChain([stroke, 'access', _111 => _111.copies, 'optionalAccess', _112 => _112.length])) {
2735
+ if (_optionalChain([stroke, 'access', _109 => _109.paint, 'optionalAccess', _110 => _110.type]) === "effect" && _optionalChain([stroke, 'access', _111 => _111.paint, 'access', _112 => _112.map, 'optionalAccess', _113 => _113.by]) === "stroke" && s !== 1) out.paint = { ...stroke.paint, map: { ...stroke.paint.map, length: Math.min(4096, Math.max(16, Math.round(stroke.paint.map.length * s))) } };
2736
+ if (_optionalChain([stroke, 'access', _114 => _114.paint, 'optionalAccess', _115 => _115.type]) === "effect" && _optionalChain([stroke, 'access', _116 => _116.paint, 'access', _117 => _117.map, 'optionalAccess', _118 => _118.by]) === "path") out.paint = _chunkSNAFFCAXcjs.withStrokePath.call(void 0, stroke.paint, points);
2737
+ if (_optionalChain([stroke, 'access', _119 => _119.copies, 'optionalAccess', _120 => _120.length])) {
2708
2738
  const inv = invertAffine(m);
2709
2739
  out.copies = stroke.copies.map((c) => composeAffine(m, composeAffine(c, inv)));
2710
2740
  }
@@ -2723,7 +2753,7 @@ var paperNodes = /* @__PURE__ */ new WeakMap();
2723
2753
  function paperNode(paper, light) {
2724
2754
  let n = paperNodes.get(paper);
2725
2755
  const metal = (_nullishCoalesce(paper.metallic, () => ( 0))) > 0;
2726
- if (!n || metal && (_optionalChain([n, 'access', _113 => _113.light, 'optionalAccess', _114 => _114.azimuth]) !== _optionalChain([light, 'optionalAccess', _115 => _115.azimuth]) || _optionalChain([n, 'access', _116 => _116.light, 'optionalAccess', _117 => _117.elevation]) !== _optionalChain([light, 'optionalAccess', _118 => _118.elevation]))) {
2756
+ if (!n || metal && (_optionalChain([n, 'access', _121 => _121.light, 'optionalAccess', _122 => _122.azimuth]) !== _optionalChain([light, 'optionalAccess', _123 => _123.azimuth]) || _optionalChain([n, 'access', _124 => _124.light, 'optionalAccess', _125 => _125.elevation]) !== _optionalChain([light, 'optionalAccess', _126 => _126.elevation]))) {
2727
2757
  n = { type: "paper", id: PAPER_NODE_ID, name: "Paper", visible: true, opacity: 1, blend: "normal", paper, ...metal && light ? { light: { azimuth: light.azimuth, elevation: light.elevation } } : {} };
2728
2758
  paperNodes.set(paper, n);
2729
2759
  }
@@ -2745,7 +2775,7 @@ function paperTile(paper, r, light) {
2745
2775
  const key = `${paperKey(paper, light)}|${r.x},${r.y},${r.width},${r.height}`;
2746
2776
  let t = tileCache.get(key);
2747
2777
  if (!t) {
2748
- t = _chunk56RHCIJVcjs.renderPaper.call(void 0, paper, r, paperGrain(paper), light);
2778
+ t = _chunkSNAFFCAXcjs.renderPaper.call(void 0, paper, r, paperGrain(paper), light);
2749
2779
  if (tileCache.size > 512) tileCache.delete(tileCache.keys().next().value);
2750
2780
  tileCache.set(key, t);
2751
2781
  }
@@ -2844,17 +2874,17 @@ function header(state, options) {
2844
2874
  if (options.swatches !== void 0) out.swatches = JSON.parse(JSON.stringify(options.swatches));
2845
2875
  if (options.mixingPad !== void 0) out.mixingPad = JSON.parse(JSON.stringify(options.mixingPad));
2846
2876
  if (options.wet !== void 0) out.wet = JSON.parse(JSON.stringify(options.wet));
2847
- if (_optionalChain([state, 'access', _119 => _119.wetEvents, 'optionalAccess', _120 => _120.length])) out.wetEvents = JSON.parse(JSON.stringify(state.wetEvents));
2848
- if (_optionalChain([state, 'access', _121 => _121.paintEvents, 'optionalAccess', _122 => _122.length])) out.paintEvents = JSON.parse(JSON.stringify(state.paintEvents));
2877
+ if (_optionalChain([state, 'access', _127 => _127.wetEvents, 'optionalAccess', _128 => _128.length])) out.wetEvents = JSON.parse(JSON.stringify(state.wetEvents));
2878
+ if (_optionalChain([state, 'access', _129 => _129.paintEvents, 'optionalAccess', _130 => _130.length])) out.paintEvents = JSON.parse(JSON.stringify(state.paintEvents));
2849
2879
  if (state.origin && (state.origin.x || state.origin.y)) out.origin = { ...state.origin };
2850
2880
  return out;
2851
2881
  }
2852
2882
  function serializePaintDocument(state, options = {}) {
2853
- const { layers, assets } = _chunk4NMPUJUKcjs.serializeLayers.call(void 0, state.layers);
2883
+ const { layers, assets } = _chunkYJANF2BLcjs.serializeLayers.call(void 0, state.layers);
2854
2884
  return { ...header(state, options), layers, assets };
2855
2885
  }
2856
2886
  async function serializePaintDocumentExternal(state, store, options = {}) {
2857
- const { layers, assets } = await _chunk4NMPUJUKcjs.serializeLayersExternal.call(void 0, state.layers, store);
2887
+ const { layers, assets } = await _chunkYJANF2BLcjs.serializeLayersExternal.call(void 0, state.layers, store);
2858
2888
  return { ...header(state, options), layers, assets };
2859
2889
  }
2860
2890
  function paintLayersOnly(layers, problems) {
@@ -2862,7 +2892,7 @@ function paintLayersOnly(layers, problems) {
2862
2892
  for (const l of layers) {
2863
2893
  if (l.type === "pixel") {
2864
2894
  const { filters, source, ...rest } = l;
2865
- if (_optionalChain([filters, 'optionalAccess', _123 => _123.length])) problems.push(`Layer "${l.name}": its filters are an image editor feature and were dropped.`);
2895
+ if (_optionalChain([filters, 'optionalAccess', _131 => _131.length])) problems.push(`Layer "${l.name}": its filters are an image editor feature and were dropped.`);
2866
2896
  if (source) problems.push(`Layer "${l.name}" refers to an image editor source image; it loads empty.`);
2867
2897
  out.push(rest);
2868
2898
  } else if (l.type === "group") out.push({ ...l, children: paintLayersOnly(l.children, problems) });
@@ -2889,11 +2919,11 @@ function deserializePaintDocument(raw) {
2889
2919
  }
2890
2920
  const problems = [];
2891
2921
  const canvas = normalizeCanvas({ width: r.width, height: r.height, dpi: _nullishCoalesce(r.dpi, () => ( void 0)) });
2892
- const paper = _chunk56RHCIJVcjs.normalizePaper.call(void 0, _nullishCoalesce(r.paper, () => ( {})));
2922
+ const paper = _chunkSNAFFCAXcjs.normalizePaper.call(void 0, _nullishCoalesce(r.paper, () => ( {})));
2893
2923
  const assets = r.assets && typeof r.assets === "object" ? r.assets : {};
2894
- const layers = paintLayersOnly(_chunk4NMPUJUKcjs.deserializeLayers.call(void 0, r.layers, { assets, problems }), problems);
2924
+ const layers = paintLayersOnly(_chunkYJANF2BLcjs.deserializeLayers.call(void 0, r.layers, { assets, problems }), problems);
2895
2925
  const wanted = typeof r.activeLayerId === "string" ? r.activeLayerId : null;
2896
- const activeLayerId = wanted && _chunkPVJMTLPJcjs.findLayer.call(void 0, layers, wanted) ? wanted : _nullishCoalesce(_optionalChain([_chunkPVJMTLPJcjs.flattenLayers.call(void 0, layers), 'access', _124 => _124.filter, 'call', _125 => _125((l) => l.type === "pixel"), 'access', _126 => _126.pop, 'call', _127 => _127(), 'optionalAccess', _128 => _128.id]), () => ( null));
2926
+ const activeLayerId = wanted && _chunkPVJMTLPJcjs.findLayer.call(void 0, layers, wanted) ? wanted : _nullishCoalesce(_optionalChain([_chunkPVJMTLPJcjs.flattenLayers.call(void 0, layers), 'access', _132 => _132.filter, 'call', _133 => _133((l) => l.type === "pixel"), 'access', _134 => _134.pop, 'call', _135 => _135(), 'optionalAccess', _136 => _136.id]), () => ( null));
2897
2927
  const wetEvents = Array.isArray(r.wetEvents) ? r.wetEvents.filter((e) => e && typeof e === "object" && Number.isInteger(e.clock) && typeof e.kind === "string") : [];
2898
2928
  const state = { canvas, paper, layers, activeLayerId, strokes: readStrokes(r.strokes, problems) };
2899
2929
  if (wetEvents.length) state.wetEvents = wetEvents;
@@ -2907,7 +2937,7 @@ async function deserializePaintDocumentAsync(raw, store) {
2907
2937
  if (!raw || typeof raw !== "object") throw new Error("Not a paint document: expected a JSON object.");
2908
2938
  const r = raw;
2909
2939
  const problems = [];
2910
- const assets = await _chunk4NMPUJUKcjs.resolveExternalAssets.call(void 0, _nullishCoalesce(r.assets, () => ( {})), store, problems);
2940
+ const assets = await _chunkYJANF2BLcjs.resolveExternalAssets.call(void 0, _nullishCoalesce(r.assets, () => ( {})), store, problems);
2911
2941
  const loaded = deserializePaintDocument({ ...r, assets });
2912
2942
  return { ...loaded, problems: [...problems, ...loaded.problems] };
2913
2943
  }
@@ -2990,7 +3020,7 @@ function pointerToPenPoint(e, x, y, view) {
2990
3020
  const p = { x, y, pressure: samplePressure(e) };
2991
3021
  if (typeof e.timeStamp === "number" && Number.isFinite(e.timeStamp)) p.t = e.timeStamp;
2992
3022
  if (e.pointerType !== "pen") return p;
2993
- const o = _chunk56RHCIJVcjs.penOrientation.call(void 0, {
3023
+ const o = _chunkSNAFFCAXcjs.penOrientation.call(void 0, {
2994
3024
  x,
2995
3025
  y,
2996
3026
  altitude: typeof e.altitudeAngle === "number" ? e.altitudeAngle : void 0,
@@ -3038,7 +3068,7 @@ async function decodeImageBlob(blob) {
3038
3068
  if (!ctx) throw new Error("No 2D context to decode with.");
3039
3069
  ctx.drawImage(bitmap, 0, 0);
3040
3070
  const data = new Uint8ClampedArray(ctx.getImageData(0, 0, bitmap.width, bitmap.height).data);
3041
- _optionalChain([bitmap, 'access', _129 => _129.close, 'optionalCall', _130 => _130()]);
3071
+ _optionalChain([bitmap, 'access', _137 => _137.close, 'optionalCall', _138 => _138()]);
3042
3072
  return { width: bitmap.width, height: bitmap.height, data };
3043
3073
  }
3044
3074
  function downloadBytes(bytes, fileName, mimeType) {
@@ -3056,19 +3086,19 @@ function downloadBytes(bytes, fileName, mimeType) {
3056
3086
  var thumbWorld = null;
3057
3087
  function paintWetTestStroke(brush, paper, color, width, height) {
3058
3088
  if (!thumbWorld || thumbWorld.width !== width || thumbWorld.height !== height) {
3059
- _optionalChain([thumbWorld, 'optionalAccess', _131 => _131.destroy, 'call', _132 => _132()]);
3060
- thumbWorld = new (0, _chunkJ5VQYK7Tcjs.WetWorld)(width, height, _chunk56RHCIJVcjs.wetPaperInput.call(void 0, paper), { kernel: "typescript", threads: 0 });
3061
- } else thumbWorld.setPaper(_chunk56RHCIJVcjs.wetPaperInput.call(void 0, paper));
3089
+ _optionalChain([thumbWorld, 'optionalAccess', _139 => _139.destroy, 'call', _140 => _140()]);
3090
+ thumbWorld = new (0, _chunkN5IMDAHMcjs.WetWorld)(width, height, _chunkSNAFFCAXcjs.wetPaperInput.call(void 0, paper), { kernel: "typescript", threads: 0 });
3091
+ } else thumbWorld.setPaper(_chunkSNAFFCAXcjs.wetPaperInput.call(void 0, paper));
3062
3092
  const w = thumbWorld;
3063
3093
  if (w.hasLane("thumb")) w.removeLane("thumb");
3064
3094
  w.ensureLane("thumb");
3065
- const [r, g, b] = _chunk56RHCIJVcjs.hexToRgb8.call(void 0, color);
3095
+ const [r, g, b] = _chunkSNAFFCAXcjs.hexToRgb8.call(void 0, color);
3066
3096
  if (brush.wet.tool !== "paint" && brush.wet.tool !== "water") {
3067
3097
  const half = Math.ceil(height / 2);
3068
- w.paint("thumb", { x: 0, y: 0, width, height: half }, null, 0.4, Array.from(_chunkJ5VQYK7Tcjs.pigmentOf.call(void 0, [r / 255, g / 255, b / 255], 0), (v) => v * 0.05));
3069
- w.paint("thumb", { x: 0, y: half, width, height: height - half }, null, 0.4, Array.from(_chunkJ5VQYK7Tcjs.pigmentOf.call(void 0, [232 / 255, 196 / 255, 64 / 255], 0), (v) => v * 0.05));
3098
+ w.paint("thumb", { x: 0, y: 0, width, height: half }, null, 0.4, Array.from(_chunkN5IMDAHMcjs.pigmentOf.call(void 0, [r / 255, g / 255, b / 255], 0), (v) => v * 0.05));
3099
+ w.paint("thumb", { x: 0, y: half, width, height: height - half }, null, 0.4, Array.from(_chunkN5IMDAHMcjs.pigmentOf.call(void 0, [232 / 255, 196 / 255, 64 / 255], 0), (v) => v * 0.05));
3070
3100
  }
3071
- const driver = new (0, _chunk56RHCIJVcjs.WetStrokeDriver)({
3101
+ const driver = new (0, _chunkSNAFFCAXcjs.WetStrokeDriver)({
3072
3102
  world: w,
3073
3103
  laneId: "thumb",
3074
3104
  brush,
@@ -3076,9 +3106,9 @@ function paintWetTestStroke(brush, paper, color, width, height) {
3076
3106
  load: brushLoadForStroke(brush, _chunkNIBFKXMDcjs.EMPTY_MIXER_LOAD, [r / 255, g / 255, b / 255]),
3077
3107
  grain: paperGrain(paper),
3078
3108
  paperDepth: paper.depth,
3079
- paperColor: _chunk56RHCIJVcjs.hexToRgb8.call(void 0, paper.color),
3109
+ paperColor: _chunkSNAFFCAXcjs.hexToRgb8.call(void 0, paper.color),
3080
3110
  seed: 7,
3081
- copies: [_chunk56RHCIJVcjs.IDENTITY_COPY]
3111
+ copies: [_chunkSNAFFCAXcjs.IDENTITY_COPY]
3082
3112
  });
3083
3113
  driver.push(thumbnailStroke(width, height));
3084
3114
  driver.finish();
@@ -3098,7 +3128,7 @@ function thumbnailStroke(width, height) {
3098
3128
  return pts;
3099
3129
  }
3100
3130
  function paintTestStroke(surface, brush, paper, color, width, height, stampArt) {
3101
- const [r, g, b] = _chunk56RHCIJVcjs.hexToRgb8.call(void 0, color);
3131
+ const [r, g, b] = _chunkSNAFFCAXcjs.hexToRgb8.call(void 0, color);
3102
3132
  let result = surface;
3103
3133
  let thick = null;
3104
3134
  let light = null;
@@ -3119,13 +3149,13 @@ function paintTestStroke(surface, brush, paper, color, width, height, stampArt)
3119
3149
  lockTransparency: false,
3120
3150
  brush,
3121
3151
  color: [r, g, b, 255],
3122
- background: [..._chunk56RHCIJVcjs.hexToRgb8.call(void 0, paper.color), 255],
3152
+ background: [..._chunkSNAFFCAXcjs.hexToRgb8.call(void 0, paper.color), 255],
3123
3153
  grain: paperGrain(paper),
3124
3154
  paperDepth: paper.depth,
3125
3155
  seed: 7,
3126
3156
  colorHex: color,
3127
3157
  affineCopies: [],
3128
- copies: [_chunk56RHCIJVcjs.IDENTITY_COPY],
3158
+ copies: [_chunkSNAFFCAXcjs.IDENTITY_COPY],
3129
3159
  mixerLoad: brushLoadForStroke(brush, _chunkNIBFKXMDcjs.EMPTY_MIXER_LOAD, [r / 255, g / 255, b / 255]),
3130
3160
  thick: brush.engine === "impasto" ? { channels: emptyThickChannels() } : void 0,
3131
3161
  sticker: brush.engine === "sticker" ? { nextId: 1 } : void 0,
@@ -3142,8 +3172,8 @@ function renderBrushThumbnail(brush, options) {
3142
3172
  const width = Math.max(16, Math.min(512, Math.round(_nullishCoalesce(options.width, () => ( 160)))));
3143
3173
  const height = Math.max(16, Math.min(512, Math.round(_nullishCoalesce(options.height, () => ( 48)))));
3144
3174
  const maxSize = height * 0.42;
3145
- const b = brush.tip.size > maxSize ? _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, { tip: { ...brush.tip, size: maxSize } }, brush) : brush;
3146
- const rgba = [..._chunk56RHCIJVcjs.hexToRgb8.call(void 0, options.color), 255];
3175
+ const b = brush.tip.size > maxSize ? _chunkGHGBIAWQcjs.normalizePaintBrush.call(void 0, { tip: { ...brush.tip, size: maxSize } }, brush) : brush;
3176
+ const rgba = [..._chunkSNAFFCAXcjs.hexToRgb8.call(void 0, options.color), 255];
3147
3177
  let surface = _chunk474IQG74cjs.emptySurface.call(void 0, 4);
3148
3178
  if (b.engine === "eraser") {
3149
3179
  surface = _chunk474IQG74cjs.fillRect.call(void 0, surface, { x: 0, y: 0, width, height }, rgba);
@@ -3157,7 +3187,7 @@ function renderBrushThumbnail(brush, options) {
3157
3187
  if (b.engine === "wet") surface = paintWetTestStroke(b, options.paper, options.color, width, height);
3158
3188
  else ({ surface, light } = paintTestStroke(surface, b, options.paper, options.color, width, height, options.stampArt));
3159
3189
  const layer = { type: "pixel", id: "thumbnail", name: "thumbnail", visible: true, opacity: 1, blend: "normal", surface, offset: { x: 0, y: 0 } };
3160
- const paper = light && _chunkBPJSI4NTcjs.brushPreviewsOnDark.call(void 0, b) ? { ...options.paper, color: _chunkBPJSI4NTcjs.BRUSH_PREVIEW_DARK_PAPER } : options.paper;
3190
+ const paper = light && _chunk7W2EQQBPcjs.brushPreviewsOnDark.call(void 0, b) ? { ...options.paper, color: _chunk7W2EQQBPcjs.BRUSH_PREVIEW_DARK_PAPER } : options.paper;
3161
3191
  const spill = light ? computeSpill(surface, light, { radius: Math.max(4, height / 6), strength: 1 }) : null;
3162
3192
  const layers = [paperNode(paper), layer];
3163
3193
  if (spill) layers.push({ type: "pixel", id: "thumbnail-light", name: "light", visible: true, opacity: 1, blend: "linear-dodge", surface: spill, offset: { x: 0, y: 0 } });
@@ -3402,11 +3432,11 @@ function readSwatch(raw) {
3402
3432
  if (!raw || typeof raw !== "object") return null;
3403
3433
  const r = raw;
3404
3434
  const g = _chunkNIBFKXMDcjs.readPaintSource.call(void 0, r.paint);
3405
- const color = typeof r.color === "string" && /^#[0-9a-f]{6}$/i.test(r.color) ? r.color.toLowerCase() : _optionalChain([g, 'optionalAccess', _133 => _133.type]) === "gradient" ? _chunkNIBFKXMDcjs.paintSourceColor.call(void 0, g) : null;
3435
+ const color = typeof r.color === "string" && /^#[0-9a-f]{6}$/i.test(r.color) ? r.color.toLowerCase() : _optionalChain([g, 'optionalAccess', _141 => _141.type]) === "gradient" ? _chunkNIBFKXMDcjs.paintSourceColor.call(void 0, g) : null;
3406
3436
  if (!color) return null;
3407
3437
  const out = { color };
3408
3438
  if (typeof r.name === "string" && r.name.trim()) out.name = r.name.trim().slice(0, 80);
3409
- if (_optionalChain([g, 'optionalAccess', _134 => _134.type]) === "gradient") out.paint = g;
3439
+ if (_optionalChain([g, 'optionalAccess', _142 => _142.type]) === "gradient") out.paint = g;
3410
3440
  return out;
3411
3441
  }
3412
3442
  var DEFAULT_SWATCHES = [
@@ -3425,7 +3455,7 @@ var DEFAULT_SWATCHES = [
3425
3455
  // src/paint-editor/mixing-pad.ts
3426
3456
  var MIXING_PAD_WIDTH = 360;
3427
3457
  var MIXING_PAD_HEIGHT = 220;
3428
- var PAD_PAINT = _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, {
3458
+ var PAD_PAINT = _chunkGHGBIAWQcjs.normalizePaintBrush.call(void 0, {
3429
3459
  id: "pad-paint",
3430
3460
  name: "Pad paint",
3431
3461
  category: "mixer",
@@ -3433,7 +3463,7 @@ var PAD_PAINT = _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, {
3433
3463
  tip: { size: 28, hardness: 0.75, spacing: 0.1, opacity: 1, flow: 0.7, pressureSize: false, pressureOpacity: false },
3434
3464
  mixer: { wet: 0.45, load: 1, mix: 0.4, loadEachStroke: true, cleanEachStroke: true, mixing: "pigment" }
3435
3465
  });
3436
- var PAD_KNIFE = _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, {
3466
+ var PAD_KNIFE = _chunkGHGBIAWQcjs.normalizePaintBrush.call(void 0, {
3437
3467
  id: "pad-knife",
3438
3468
  name: "Palette knife",
3439
3469
  category: "smudge",
@@ -3443,7 +3473,7 @@ var PAD_KNIFE = _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, {
3443
3473
  // A knife drags streaks of paint and folds them into each other, mixing them as pigment.
3444
3474
  smudge: { strength: 0.6, length: 0.8, mixing: "pigment" }
3445
3475
  });
3446
- var PAD_BLOB = _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, {
3476
+ var PAD_BLOB = _chunkGHGBIAWQcjs.normalizePaintBrush.call(void 0, {
3447
3477
  id: "pad-blob",
3448
3478
  name: "Pad blob",
3449
3479
  category: "custom",
@@ -3465,12 +3495,12 @@ var MixingPad = (_class10 = class {constructor() { _class10.prototype.__init52.c
3465
3495
  }
3466
3496
  }
3467
3497
  let brush = options.tool === "knife" ? PAD_KNIFE : PAD_PAINT;
3468
- if (options.size !== void 0) brush = _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, { tip: { ...brush.tip, size: options.size } }, brush);
3498
+ if (options.size !== void 0) brush = _chunkGHGBIAWQcjs.normalizePaintBrush.call(void 0, { tip: { ...brush.tip, size: options.size } }, brush);
3469
3499
  return this.run(brush, points, options.color);
3470
3500
  }
3471
3501
  /** Paints `points` with `brush` in `color` on the pad. */
3472
3502
  run(brush, points, color) {
3473
- const [r, g, b] = _chunk56RHCIJVcjs.hexToRgb8.call(void 0, color);
3503
+ const [r, g, b] = _chunkSNAFFCAXcjs.hexToRgb8.call(void 0, color);
3474
3504
  let result = null;
3475
3505
  const session = new PaintStrokeSession(
3476
3506
  { update: () => {
@@ -3488,7 +3518,7 @@ var MixingPad = (_class10 = class {constructor() { _class10.prototype.__init52.c
3488
3518
  seed: 1,
3489
3519
  colorHex: color,
3490
3520
  affineCopies: [],
3491
- copies: [_chunk56RHCIJVcjs.IDENTITY_COPY],
3521
+ copies: [_chunkSNAFFCAXcjs.IDENTITY_COPY],
3492
3522
  mixerLoad: brushLoadForStroke(brush, _chunkNIBFKXMDcjs.EMPTY_MIXER_LOAD, [r / 255, g / 255, b / 255])
3493
3523
  }
3494
3524
  );
@@ -3564,10 +3594,10 @@ var MixingPad = (_class10 = class {constructor() { _class10.prototype.__init52.c
3564
3594
  const off = used.length === 1 ? 0 : 0.45 * R;
3565
3595
  const x = Math.min(cx + R - r, Math.max(cx - R + r, cx + Math.cos(a) * off));
3566
3596
  const y = Math.min(cy + R - r, Math.max(cy - R + r, cy + Math.sin(a) * off));
3567
- const blob = _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, { tip: { ...PAD_BLOB.tip, size: Math.max(2, 2 * r) } }, PAD_BLOB);
3597
+ const blob = _chunkGHGBIAWQcjs.normalizePaintBrush.call(void 0, { tip: { ...PAD_BLOB.tip, size: Math.max(2, 2 * r) } }, PAD_BLOB);
3568
3598
  this.run(blob, [{ x, y }], p.color.toLowerCase());
3569
3599
  });
3570
- const knife = _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, { tip: { ...PAD_KNIFE.tip, size: Math.max(12, R * 0.5) } }, PAD_KNIFE);
3600
+ const knife = _chunkGHGBIAWQcjs.normalizePaintBrush.call(void 0, { tip: { ...PAD_KNIFE.tip, size: Math.max(12, R * 0.5) } }, PAD_KNIFE);
3571
3601
  for (let k = 0; k < passes; k++) {
3572
3602
  const stir = [];
3573
3603
  const turns = 1.6;
@@ -3579,10 +3609,10 @@ var MixingPad = (_class10 = class {constructor() { _class10.prototype.__init52.c
3579
3609
  this.run(knife, stir, "#000000");
3580
3610
  }
3581
3611
  const mixed = _chunk2VX55NFMcjs.mixPigments.call(void 0,
3582
- paints2.map((p) => _chunk56RHCIJVcjs.hexToRgb8.call(void 0, p.color).map((v) => v / 255)),
3612
+ paints2.map((p) => _chunkSNAFFCAXcjs.hexToRgb8.call(void 0, p.color).map((v) => v / 255)),
3583
3613
  paints2.map((p) => p.parts)
3584
3614
  );
3585
- const core = _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, { tip: { ...PAD_BLOB.tip, size: R * 1.1, hardness: 0.55 } }, PAD_BLOB);
3615
+ const core = _chunkGHGBIAWQcjs.normalizePaintBrush.call(void 0, { tip: { ...PAD_BLOB.tip, size: R * 1.1, hardness: 0.55 } }, PAD_BLOB);
3586
3616
  const hex2 = "#" + mixed.map((v) => Math.round(v * 255).toString(16).padStart(2, "0")).join("");
3587
3617
  this.run(core, [{ x: cx, y: cy }], hex2);
3588
3618
  return { color: this.pick(cx, cy, 2), bounds };
@@ -3593,7 +3623,7 @@ var MixingPad = (_class10 = class {constructor() { _class10.prototype.__init52.c
3593
3623
  }
3594
3624
  /** Replaces the pad with a PNG (data URL or base64) of the pad's size, as `toPng` writes. */
3595
3625
  fromPng(png) {
3596
- const bytes = png.startsWith("data:") ? _optionalChain([_chunkW5M3J7PVcjs.parseDataUrl.call(void 0, png), 'optionalAccess', _135 => _135.bytes]) : _chunkW5M3J7PVcjs.base64ToBytes.call(void 0, png);
3626
+ const bytes = png.startsWith("data:") ? _optionalChain([_chunkW5M3J7PVcjs.parseDataUrl.call(void 0, png), 'optionalAccess', _143 => _143.bytes]) : _chunkW5M3J7PVcjs.base64ToBytes.call(void 0, png);
3597
3627
  if (!bytes || !_chunkW5M3J7PVcjs.isPng.call(void 0, bytes)) throw new Error("The pad image is not a PNG data URL or base64 PNG.");
3598
3628
  const img = _chunkW5M3J7PVcjs.decodePng.call(void 0, bytes);
3599
3629
  if (img.width !== this.width || img.height !== this.height) throw new Error(`The pad image is ${img.width}\xD7${img.height}; a mixing pad is ${this.width}\xD7${this.height}.`);
@@ -3622,21 +3652,21 @@ var MixingPad = (_class10 = class {constructor() { _class10.prototype.__init52.c
3622
3652
  var copyJSON = (v) => JSON.parse(JSON.stringify(v));
3623
3653
  var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
3624
3654
  function libraryBrush(spec, builtin, resolved) {
3625
- const brush = resolved ? _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, resolved, resolved) : _chunkEU2ZZA6Lcjs.resolveBrush.call(void 0, spec);
3655
+ const brush = resolved ? _chunkGHGBIAWQcjs.normalizePaintBrush.call(void 0, resolved, resolved) : _chunkGHGBIAWQcjs.resolveBrush.call(void 0, spec);
3626
3656
  if (builtin) brush.builtin = true;
3627
3657
  else delete brush.builtin;
3628
3658
  return { spec, brush, builtin };
3629
3659
  }
3630
3660
  var builtins = null;
3631
3661
  function builtinLibraryBrushes() {
3632
- return builtins ??= _chunkEU2ZZA6Lcjs.BRUSH_PRESETS.map((spec) => {
3633
- const resolved = _chunkEU2ZZA6Lcjs.BUILTIN_BRUSHES.find((b) => b.id === spec.id);
3662
+ return builtins ??= _chunkGHGBIAWQcjs.BRUSH_PRESETS.map((spec) => {
3663
+ const resolved = _chunkGHGBIAWQcjs.BUILTIN_BRUSHES.find((b) => b.id === spec.id);
3634
3664
  return libraryBrush(spec, true, resolved);
3635
3665
  });
3636
3666
  }
3637
3667
  function seededStorage(brushes) {
3638
3668
  if (!brushes.length) return void 0;
3639
- let stored = JSON.stringify({ format: "pixerate-brushes", version: 1, brushes: brushes.map(_chunkEU2ZZA6Lcjs.brushToJSON) });
3669
+ let stored = JSON.stringify({ format: "pixerate-brushes", version: 1, brushes: brushes.map(_chunkGHGBIAWQcjs.brushToJSON) });
3640
3670
  return {
3641
3671
  get: async () => stored,
3642
3672
  set: async (_key, value) => {
@@ -3649,28 +3679,28 @@ var paints = (b) => {
3649
3679
  return JSON.stringify(rest);
3650
3680
  };
3651
3681
  function brushSpecOf(next, from) {
3652
- const plain = _chunkEU2ZZA6Lcjs.migrateBrushV1.call(void 0, next);
3682
+ const plain = _chunkGHGBIAWQcjs.migrateBrushV1.call(void 0, next);
3653
3683
  const out = copyJSON(plain);
3654
3684
  if (from.description) out.description = from.description;
3655
- if (_optionalChain([from, 'access', _136 => _136.tags, 'optionalAccess', _137 => _137.length])) out.tags = [...from.tags];
3685
+ if (_optionalChain([from, 'access', _144 => _144.tags, 'optionalAccess', _145 => _145.length])) out.tags = [...from.tags];
3656
3686
  if (out.kind === "mark" && from.kind === "mark") {
3657
3687
  if (from.medium) out.medium = from.medium;
3658
3688
  if (from.variety) out.variety = from.variety;
3659
3689
  }
3660
3690
  const colour = { ..._nullishCoalesce(from.colour, () => ( {})) };
3661
- if (_optionalChain([plain, 'access', _138 => _138.colour, 'optionalAccess', _139 => _139.default]) !== void 0) colour.default = plain.colour.default;
3691
+ if (_optionalChain([plain, 'access', _146 => _146.colour, 'optionalAccess', _147 => _147.default]) !== void 0) colour.default = plain.colour.default;
3662
3692
  else if (isObject(colour.default) && colour.default.type === "gradient") delete colour.default;
3663
3693
  if (Object.keys(colour).length) out.colour = copyJSON(colour);
3664
3694
  else delete out.colour;
3665
- if ((_nullishCoalesce(_optionalChain([out, 'access', _140 => _140.light, 'optionalAccess', _141 => _141.amount]), () => ( 0))) > 0 && (_optionalChain([from, 'access', _142 => _142.light, 'optionalAccess', _143 => _143.spill]) || _optionalChain([from, 'access', _144 => _144.light, 'optionalAccess', _145 => _145.glow]) !== void 0)) {
3695
+ if ((_nullishCoalesce(_optionalChain([out, 'access', _148 => _148.light, 'optionalAccess', _149 => _149.amount]), () => ( 0))) > 0 && (_optionalChain([from, 'access', _150 => _150.light, 'optionalAccess', _151 => _151.spill]) || _optionalChain([from, 'access', _152 => _152.light, 'optionalAccess', _153 => _153.glow]) !== void 0)) {
3666
3696
  out.light = { ...out.light, ...from.light.spill ? { spill: { ...from.light.spill } } : {}, ...from.light.glow !== void 0 ? { glow: from.light.glow } : {} };
3667
3697
  }
3668
- if (_optionalChain([from, 'access', _146 => _146.motion, 'optionalAccess', _147 => _147.live]) !== void 0 || _optionalChain([from, 'access', _148 => _148.motion, 'optionalAccess', _149 => _149.fps]) !== void 0) {
3698
+ if (_optionalChain([from, 'access', _154 => _154.motion, 'optionalAccess', _155 => _155.live]) !== void 0 || _optionalChain([from, 'access', _156 => _156.motion, 'optionalAccess', _157 => _157.fps]) !== void 0) {
3669
3699
  out.motion = { ..._nullishCoalesce(out.motion, () => ( {})), ...from.motion.live !== void 0 ? { live: from.motion.live } : {}, ...from.motion.fps !== void 0 ? { fps: from.motion.fps } : {} };
3670
3700
  }
3671
3701
  try {
3672
- const hinted = _chunkEU2ZZA6Lcjs.normalizeBrushSpec.call(void 0, out, []);
3673
- if (paints(_chunkEU2ZZA6Lcjs.resolveBrush.call(void 0, hinted)) === paints(_chunkEU2ZZA6Lcjs.resolveBrush.call(void 0, plain))) return hinted;
3702
+ const hinted = _chunkGHGBIAWQcjs.normalizeBrushSpec.call(void 0, out, []);
3703
+ if (paints(_chunkGHGBIAWQcjs.resolveBrush.call(void 0, hinted)) === paints(_chunkGHGBIAWQcjs.resolveBrush.call(void 0, plain))) return hinted;
3674
3704
  } catch (e5) {
3675
3705
  }
3676
3706
  return plain;
@@ -3768,14 +3798,14 @@ var BrushSourceArtCache = (_class11 = class {constructor() { _class11.prototype.
3768
3798
  }
3769
3799
  /** The art of a `source:<id>` ref (alpha = the mask), or `undefined` when the source is unknown or its image can't be read. */
3770
3800
  __init58() {this.get = (ref2) => {
3771
- const id = _chunkEU2ZZA6Lcjs.brushSourceIdOf.call(void 0, ref2);
3801
+ const id = _chunkGHGBIAWQcjs.brushSourceIdOf.call(void 0, ref2);
3772
3802
  if (id === null) return void 0;
3773
3803
  if (this.art.has(id)) return _nullishCoalesce(this.art.get(id), () => ( void 0));
3774
3804
  const source = this.sources.get(id);
3775
3805
  if (!source) return void 0;
3776
3806
  let art = null;
3777
3807
  try {
3778
- const { width, height, mask } = _chunkEU2ZZA6Lcjs.decodeBrushSource.call(void 0, source);
3808
+ const { width, height, mask } = _chunkGHGBIAWQcjs.decodeBrushSource.call(void 0, source);
3779
3809
  const data = new Uint8ClampedArray(width * height * 4);
3780
3810
  for (let i = 0; i < mask.length; i++) {
3781
3811
  data[i * 4] = data[i * 4 + 1] = data[i * 4 + 2] = 255;
@@ -3790,12 +3820,12 @@ var BrushSourceArtCache = (_class11 = class {constructor() { _class11.prototype.
3790
3820
  }}
3791
3821
  /** A lookup that reads sources from here and every other ref from `stickers`. */
3792
3822
  with(stickers) {
3793
- return (ref2, variant) => _chunkEU2ZZA6Lcjs.isBrushSourceRef.call(void 0, ref2) ? this.get(ref2) : stickers(ref2, variant);
3823
+ return (ref2, variant) => _chunkGHGBIAWQcjs.isBrushSourceRef.call(void 0, ref2) ? this.get(ref2) : stickers(ref2, variant);
3794
3824
  }
3795
3825
  }, _class11);
3796
3826
  function engineBrushSourceIds(brush) {
3797
- const refs = [brush.stamp, _optionalChain([brush, 'access', _150 => _150.tipGrain, 'optionalAccess', _151 => _151.source]), ..._nullishCoalesce(_optionalChain([brush, 'access', _152 => _152.particle, 'optionalAccess', _153 => _153.dotTextures]), () => ( []))];
3798
- return [...new Set(refs.filter((r) => !!r && _chunkEU2ZZA6Lcjs.isBrushSourceRef.call(void 0, r)).map((r) => _chunkEU2ZZA6Lcjs.brushSourceIdOf.call(void 0, r)))];
3827
+ const refs = [brush.stamp, _optionalChain([brush, 'access', _158 => _158.tipGrain, 'optionalAccess', _159 => _159.source]), ..._nullishCoalesce(_optionalChain([brush, 'access', _160 => _160.particle, 'optionalAccess', _161 => _161.dotTextures]), () => ( []))];
3828
+ return [...new Set(refs.filter((r) => !!r && _chunkGHGBIAWQcjs.isBrushSourceRef.call(void 0, r)).map((r) => _chunkGHGBIAWQcjs.brushSourceIdOf.call(void 0, r)))];
3799
3829
  }
3800
3830
 
3801
3831
  // src/paint-editor/live-strokes.ts
@@ -3895,8 +3925,8 @@ var BacklightCache = (_class12 = class {constructor() { _class12.prototype.__ini
3895
3925
  refs.length = 0;
3896
3926
  for (const l of layers) {
3897
3927
  tilesUnder(l.surface, rect, l.offset, refs);
3898
- tilesUnder(_optionalChain([l, 'access', _154 => _154.thick, 'optionalAccess', _155 => _155.height]), rect, l.offset, refs);
3899
- tilesUnder(_optionalChain([l, 'access', _156 => _156.thick, 'optionalAccess', _157 => _157.material]), rect, l.offset, refs);
3928
+ tilesUnder(_optionalChain([l, 'access', _162 => _162.thick, 'optionalAccess', _163 => _163.height]), rect, l.offset, refs);
3929
+ tilesUnder(_optionalChain([l, 'access', _164 => _164.thick, 'optionalAccess', _165 => _165.material]), rect, l.offset, refs);
3900
3930
  }
3901
3931
  const k = _chunk474IQG74cjs.tileKey.call(void 0, tx, ty);
3902
3932
  let r = this.tiles.get(k);
@@ -3968,10 +3998,10 @@ function addTiles(a, b) {
3968
3998
  }
3969
3999
  function computeTile(paper, grain, amount, rect, layers) {
3970
4000
  const n = rect.width * rect.height;
3971
- const [p0, p1, p2] = _chunk56RHCIJVcjs.hexToRgb8.call(void 0, paper.color);
4001
+ const [p0, p1, p2] = _chunkSNAFFCAXcjs.hexToRgb8.call(void 0, paper.color);
3972
4002
  const pb = [p0, p1, p2];
3973
4003
  const pl = [Math.max(1e-4, LIN[p0]), Math.max(1e-4, LIN[p1]), Math.max(1e-4, LIN[p2])];
3974
- const [c0, c1, c2] = _chunk56RHCIJVcjs.hexToRgb8.call(void 0, _nullishCoalesce(paper.backlightColor, () => ( DEFAULT_BACKLIGHT_COLOR)));
4004
+ const [c0, c1, c2] = _chunkSNAFFCAXcjs.hexToRgb8.call(void 0, _nullishCoalesce(paper.backlightColor, () => ( DEFAULT_BACKLIGHT_COLOR)));
3975
4005
  const t0 = new Float32Array(n).fill(amount * LIN[c0]);
3976
4006
  const t1 = new Float32Array(n).fill(amount * LIN[c1]);
3977
4007
  const t2 = new Float32Array(n).fill(amount * LIN[c2]);
@@ -3990,8 +4020,8 @@ function computeTile(paper, grain, amount, rect, layers) {
3990
4020
  const lr = { x: rect.x - l.offset.x, y: rect.y - l.offset.y, width: rect.width, height: rect.height };
3991
4021
  if (!l.surface.tiles.size) continue;
3992
4022
  const px = _chunk474IQG74cjs.readRegion.call(void 0, l.surface, lr);
3993
- const h = _optionalChain([l, 'access', _158 => _158.thick, 'optionalAccess', _159 => _159.height, 'access', _160 => _160.tiles, 'access', _161 => _161.size]) ? _chunk474IQG74cjs.readRegion.call(void 0, l.thick.height, lr) : null;
3994
- const m = h && _optionalChain([l, 'access', _162 => _162.thick, 'optionalAccess', _163 => _163.material, 'access', _164 => _164.tiles, 'access', _165 => _165.size]) ? _chunk474IQG74cjs.readRegion.call(void 0, l.thick.material, lr) : null;
4023
+ const h = _optionalChain([l, 'access', _166 => _166.thick, 'optionalAccess', _167 => _167.height, 'access', _168 => _168.tiles, 'access', _169 => _169.size]) ? _chunk474IQG74cjs.readRegion.call(void 0, l.thick.height, lr) : null;
4024
+ const m = h && _optionalChain([l, 'access', _170 => _170.thick, 'optionalAccess', _171 => _171.material, 'access', _172 => _172.tiles, 'access', _173 => _173.size]) ? _chunk474IQG74cjs.readRegion.call(void 0, l.thick.material, lr) : null;
3995
4025
  const op = l.opacity;
3996
4026
  for (let i = 0; i < n; i++) {
3997
4027
  const a8 = px[i * 4 + 3];
@@ -4067,7 +4097,7 @@ async function replayPainting(source, target, options = {}) {
4067
4097
  const chunk = Math.max(1, _nullishCoalesce(options.wetChunk, () => ( 0))) || Infinity;
4068
4098
  let strokes = 0;
4069
4099
  const scaled = source.strokes.slice(0, maxStrokes).map((st) => s === 1 ? st : varyStroke(st, scaleM, { scale: s }));
4070
- await target.prepareEffectPaints(scaled.flatMap((st) => _optionalChain([st, 'access', _166 => _166.paint, 'optionalAccess', _167 => _167.type]) === "effect" ? [st.paint] : []));
4100
+ await target.prepareEffectPaints(scaled.flatMap((st) => _optionalChain([st, 'access', _174 => _174.paint, 'optionalAccess', _175 => _175.type]) === "effect" && _optionalChain([st, 'access', _176 => _176.paint, 'access', _177 => _177.map, 'optionalAccess', _178 => _178.by]) !== "path" ? [st.paint] : []));
4071
4101
  const advanceTo = async (clock) => {
4072
4102
  const now = target.getState().wet.clock;
4073
4103
  let left = clock - now;
@@ -4075,7 +4105,7 @@ async function replayPainting(source, target, options = {}) {
4075
4105
  const n = Math.min(left, chunk);
4076
4106
  await target.advanceWet({ steps: n });
4077
4107
  left -= n;
4078
- if (Number.isFinite(chunk)) await _optionalChain([options, 'access', _168 => _168.onWetSteps, 'optionalCall', _169 => _169(target.getState().wet.clock)]);
4108
+ if (Number.isFinite(chunk)) await _optionalChain([options, 'access', _179 => _179.onWetSteps, 'optionalCall', _180 => _180(target.getState().wet.clock)]);
4079
4109
  }
4080
4110
  };
4081
4111
  const sr = (r) => ({ x: r.x * s, y: r.y * s, width: r.width * s, height: r.height * s });
@@ -4088,14 +4118,14 @@ async function replayPainting(source, target, options = {}) {
4088
4118
  else if (e.kind === "clear") target.clearLayer(e.layerId);
4089
4119
  else if (e.kind === "live-strokes") {
4090
4120
  const d = e.data;
4091
- if (_optionalChain([d, 'optionalAccess', _170 => _170.rasterized])) target.replaceLiveStrokes(e.layerId, null);
4121
+ if (_optionalChain([d, 'optionalAccess', _181 => _181.rasterized])) target.replaceLiveStrokes(e.layerId, null);
4092
4122
  else {
4093
- const list = (_nullishCoalesce(_optionalChain([d, 'optionalAccess', _171 => _171.strokes]), () => ( []))).map((st2) => s === 1 ? st2 : { ...varyStroke(st2, scaleM, { scale: s }), ...st2.stencils ? { stencils: st2.stencils.map((x) => scaleStencil(x, s)) } : {} });
4094
- await target.prepareEffectPaints(list.flatMap((st2) => _optionalChain([st2, 'access', _172 => _172.paint, 'optionalAccess', _173 => _173.type]) === "effect" ? [st2.paint] : []));
4123
+ const list = (_nullishCoalesce(_optionalChain([d, 'optionalAccess', _182 => _182.strokes]), () => ( []))).map((st2) => s === 1 ? st2 : { ...varyStroke(st2, scaleM, { scale: s }), ...st2.stencils ? { stencils: st2.stencils.map((x) => scaleStencil(x, s)) } : {} });
4124
+ await target.prepareEffectPaints(list.flatMap((st2) => _optionalChain([st2, 'access', _183 => _183.paint, 'optionalAccess', _184 => _184.type]) === "effect" ? [st2.paint] : []));
4095
4125
  target.replaceLiveStrokes(e.layerId, list);
4096
4126
  }
4097
4127
  } else if (e.kind === "stickers") {
4098
- const list = (_nullishCoalesce(_optionalChain([e, 'access', _174 => _174.data, 'optionalAccess', _175 => _175.stickers]), () => ( []))).map((x) => s === 1 ? x : { ...x, x: x.x * s, y: x.y * s, size: x.size * s });
4128
+ const list = (_nullishCoalesce(_optionalChain([e, 'access', _185 => _185.data, 'optionalAccess', _186 => _186.stickers]), () => ( []))).map((x) => s === 1 ? x : { ...x, x: x.x * s, y: x.y * s, size: x.size * s });
4099
4129
  target.replaceStickers(e.layerId, list);
4100
4130
  } else target.flattenRelief(e.layerId);
4101
4131
  continue;
@@ -4108,8 +4138,8 @@ async function replayPainting(source, target, options = {}) {
4108
4138
  switch (e.kind) {
4109
4139
  case "dry": {
4110
4140
  const rect = e.data;
4111
- const ids = _optionalChain([e, 'access', _176 => _176.layerId, 'optionalAccess', _177 => _177.split, 'call', _178 => _178(","), 'access', _179 => _179.filter, 'call', _180 => _180(Boolean)]);
4112
- if (_optionalChain([ids, 'optionalAccess', _181 => _181.length])) for (const id of ids) target.dryPaint({ layerId: id, rect: rect ? sr(rect) : void 0 });
4141
+ const ids = _optionalChain([e, 'access', _187 => _187.layerId, 'optionalAccess', _188 => _188.split, 'call', _189 => _189(","), 'access', _190 => _190.filter, 'call', _191 => _191(Boolean)]);
4142
+ if (_optionalChain([ids, 'optionalAccess', _192 => _192.length])) for (const id of ids) target.dryPaint({ layerId: id, rect: rect ? sr(rect) : void 0 });
4113
4143
  else target.dryPaint({ rect: rect ? sr(rect) : void 0 });
4114
4144
  break;
4115
4145
  }
@@ -4139,8 +4169,9 @@ async function replayPainting(source, target, options = {}) {
4139
4169
  const st = s === 1 ? item.stroke : varyStroke(item.stroke, scaleM, { scale: s });
4140
4170
  strokes++;
4141
4171
  if (!target.getLayer(st.layerId)) continue;
4172
+ if (_optionalChain([st, 'access', _193 => _193.paint, 'optionalAccess', _194 => _194.type]) === "effect" && _optionalChain([st, 'access', _195 => _195.paint, 'access', _196 => _196.map, 'optionalAccess', _197 => _197.by]) === "path") await target.prepareEffectPaints([st.paint]);
4142
4173
  const init = { layerId: st.layerId, color: st.color, brush: st.brush, seed: st.seed, copies: _nullishCoalesce(st.copies, () => ( [])), ...st.load ? { load: st.load } : {}, ...st.paint ? { paint: st.paint } : {}, snapToPerspective: false, stencils: false, maskStencils: (_nullishCoalesce(st.stencils, () => ( []))).map((x) => s === 1 ? x : scaleStencil(x, s)) };
4143
- if (st.brush.engine === "wet" && _optionalChain([st, 'access', _182 => _182.steps, 'optionalAccess', _183 => _183.length]) === st.points.length) {
4174
+ if (st.brush.engine === "wet" && _optionalChain([st, 'access', _198 => _198.steps, 'optionalAccess', _199 => _199.length]) === st.points.length) {
4144
4175
  await target.wetIdle();
4145
4176
  await advanceTo(st.steps[0]);
4146
4177
  const session = target.beginStroke({ ...init, start: st.points[0] });
@@ -4160,7 +4191,7 @@ async function replayPainting(source, target, options = {}) {
4160
4191
  await target.wetIdle();
4161
4192
  target.paintStroke({ ...init, points: st.points });
4162
4193
  }
4163
- await _optionalChain([options, 'access', _184 => _184.onStroke, 'optionalCall', _185 => _185(strokes)]);
4194
+ await _optionalChain([options, 'access', _200 => _200.onStroke, 'optionalCall', _201 => _201(strokes)]);
4164
4195
  }
4165
4196
  void IDENTITY_AFFINE;
4166
4197
  }
@@ -4183,7 +4214,7 @@ function timeLapseVideo(frameCount, width, height, fps, holdMs, name = "Time-lap
4183
4214
  }
4184
4215
  const video = { version: 1, name, width: w, height: h, fps, background: "#000000", assets, tracks: [{ id: "v1", kind: "video", clips }] };
4185
4216
  const durationMs = frameCount ? clips[clips.length - 1].start + clips[clips.length - 1].duration : 0;
4186
- return { video, ffmpeg: _chunkCBVNCWJMcjs.toVideoFfmpeg.call(void 0, video, { output: "timelapse.mp4" }), durationMs };
4217
+ return { video, ffmpeg: _chunkLBDC5434cjs.toVideoFfmpeg.call(void 0, video, { output: "timelapse.mp4" }), durationMs };
4187
4218
  }
4188
4219
  async function buildTimeLapse(source, target, options = {}) {
4189
4220
  const maxSide = Math.max(32, Math.min(4096, Math.round(_nullishCoalesce(options.maxSide, () => ( 720)))));
@@ -4205,7 +4236,7 @@ async function buildTimeLapse(source, target, options = {}) {
4205
4236
  wetChunk: wetEvery > 0 ? wetEvery : 0,
4206
4237
  onStroke: (i) => {
4207
4238
  if (i % perFrame === 0 || i === total) shoot(i);
4208
- _optionalChain([options, 'access', _186 => _186.onProgress, 'optionalCall', _187 => _187(total ? i / total : 1)]);
4239
+ _optionalChain([options, 'access', _202 => _202.onProgress, 'optionalCall', _203 => _203(total ? i / total : 1)]);
4209
4240
  },
4210
4241
  onWetSteps: wetEvery > 0 ? () => shoot(-1) : void 0
4211
4242
  });
@@ -4293,7 +4324,7 @@ function mixPixels(before, after, amount) {
4293
4324
  return out;
4294
4325
  }
4295
4326
  var PaintEffectsRenderer = (_class13 = class {constructor() { _class13.prototype.__init63.call(this);_class13.prototype.__init64.call(this);_class13.prototype.__init65.call(this); }
4296
- __init63() {this.pool = new (0, _chunkPY4GWSE2cjs.EffectRendererPool)({ maxRenderers: 3 })}
4327
+ __init63() {this.pool = new (0, _chunkEBFPMSJOcjs.EffectRendererPool)({ maxRenderers: 3 })}
4297
4328
  __init64() {this.descriptions = /* @__PURE__ */ new Map()}
4298
4329
  __init65() {this.provider = null}
4299
4330
  /** Forgets cached descriptions and renderers when the provider changes. */
@@ -4321,6 +4352,12 @@ var PaintEffectsRenderer = (_class13 = class {constructor() { _class13.prototype
4321
4352
  }
4322
4353
  return out;
4323
4354
  }
4355
+ renderSync(provider, id, size, request) {
4356
+ this.follow(provider);
4357
+ const out = this.pool.renderSync(provider, id, { ...size, depth: 8 }, request);
4358
+ if (!out || out.width !== size.width || out.height !== size.height || out.data.length !== size.width * size.height * 4) return null;
4359
+ return out;
4360
+ }
4324
4361
  dispose() {
4325
4362
  this.pool.clear();
4326
4363
  this.descriptions.clear();
@@ -4385,7 +4422,7 @@ async function libraryCall(call) {
4385
4422
  try {
4386
4423
  return await call();
4387
4424
  } catch (e) {
4388
- throw e instanceof _chunkEU2ZZA6Lcjs.BrushLibraryError ? new PaintEditorError(e.message) : e;
4425
+ throw e instanceof _chunkGHGBIAWQcjs.BrushLibraryError ? new PaintEditorError(e.message) : e;
4389
4426
  }
4390
4427
  }
4391
4428
  var HEX2 = /^#[0-9a-f]{6}$/i;
@@ -4395,7 +4432,7 @@ function parseColor(value, what = "color") {
4395
4432
  return value.trim().toLowerCase();
4396
4433
  }
4397
4434
  function rgbaOf(hex2) {
4398
- const [r, g, b] = _chunk56RHCIJVcjs.hexToRgb8.call(void 0, hex2);
4435
+ const [r, g, b] = _chunkSNAFFCAXcjs.hexToRgb8.call(void 0, hex2);
4399
4436
  return [r, g, b, 255];
4400
4437
  }
4401
4438
  function rgbToHex(r, g, b) {
@@ -4408,7 +4445,7 @@ function unionRect(a, b) {
4408
4445
  const y = Math.min(a.y, b.y);
4409
4446
  return { x, y, width: Math.max(a.x + a.width, b.x + b.width) - x, height: Math.max(a.y + a.height, b.y + b.height) - y };
4410
4447
  }
4411
- var isPixelLayer = (l) => _optionalChain([l, 'optionalAccess', _188 => _188.type]) === "pixel";
4448
+ var isPixelLayer = (l) => _optionalChain([l, 'optionalAccess', _204 => _204.type]) === "pixel";
4412
4449
  var PaintEditorController = (_class14 = class _PaintEditorController {
4413
4450
 
4414
4451
  __init66() {this.extensions = {}}
@@ -4439,95 +4476,106 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
4439
4476
  __init76() {this.paintEpoch = 0}
4440
4477
  /** Rendered effect paints by `effectPaintKey` (most recently used last). */
4441
4478
  __init77() {this.effectPaintPixels = /* @__PURE__ */ new Map()}
4442
- __init78() {this.mixerLoad = _chunkNIBFKXMDcjs.EMPTY_MIXER_LOAD}
4443
- __init79() {this.view = { ...DEFAULT_VIEW, pan: { ...DEFAULT_VIEW.pan } }}
4479
+ /** Primary path control name (`format: 'svg-path'`) per effect id, learned from `describeEffect`. */
4480
+ __init78() {this.effectPathControls = /* @__PURE__ */ new Map()}
4481
+ /** How many renders the running batch needs together (`prepareEffectPaints`; a synchronous replay reads them all). */
4482
+ __init79() {this.effectPaintBatch = 0}
4483
+ /** The hand-painted stroke waiting for its path render (`finishPathStroke`), or `null`. */
4484
+ __init80() {this.pathStroke = null}
4485
+ /**
4486
+ * The hand-painted path stroke's live preview: the effect rendered along the path drawn so far
4487
+ * (one render at a time; the newest path when it lands), repainted into the stroke as it lands.
4488
+ */
4489
+ __init81() {this.pathPreview = null}
4490
+ __init82() {this.mixerLoad = _chunkNIBFKXMDcjs.EMPTY_MIXER_LOAD}
4491
+ __init83() {this.view = { ...DEFAULT_VIEW, pan: { ...DEFAULT_VIEW.pan } }}
4444
4492
 
4445
- __init80() {this.selectedStroke = null}
4446
- __init81() {this.selectedSticker = null}
4493
+ __init84() {this.selectedStroke = null}
4494
+ __init85() {this.selectedSticker = null}
4447
4495
  /** A sticker drag in progress (`previewSticker`): the document before it, so the drop undoes in one step, and the one it showed last. */
4448
- __init82() {this.stickerPreview = null}
4496
+ __init86() {this.stickerPreview = null}
4449
4497
 
4450
- __init83() {this.listeners = /* @__PURE__ */ new Set()}
4451
- __init84() {this.commitListeners = /* @__PURE__ */ new Set()}
4452
- __init85() {this.sampleListeners = /* @__PURE__ */ new Set()}
4498
+ __init87() {this.listeners = /* @__PURE__ */ new Set()}
4499
+ __init88() {this.commitListeners = /* @__PURE__ */ new Set()}
4500
+ __init89() {this.sampleListeners = /* @__PURE__ */ new Set()}
4453
4501
  /** Origins set by `withOrigin`, innermost last. */
4454
- __init86() {this.origins = []}
4502
+ __init90() {this.origins = []}
4455
4503
  /** `group` in progress: commits fold into one step, recorded when it ends. */
4456
- __init87() {this.grouping = null}
4504
+ __init91() {this.grouping = null}
4457
4505
  /** `previewPaint` in progress: nothing is emitted or recorded. */
4458
- __init88() {this.previewing = false}
4459
- __init89() {this.version = 0}
4460
- __init90() {this.cached = null}
4461
- __init91() {this.session = null}
4462
- __init92() {this.live = null}
4463
- __init93() {this.liveLayers = null}
4464
- __init94() {this.dirty = "all"}
4465
- __init95() {this.seedCounter = 1}
4466
- __init96() {this.strokeCounter = 1}
4506
+ __init92() {this.previewing = false}
4507
+ __init93() {this.version = 0}
4508
+ __init94() {this.cached = null}
4509
+ __init95() {this.session = null}
4510
+ __init96() {this.live = null}
4511
+ __init97() {this.liveLayers = null}
4512
+ __init98() {this.dirty = "all"}
4513
+ __init99() {this.seedCounter = 1}
4514
+ __init100() {this.strokeCounter = 1}
4467
4515
  /** Light paint: each layer's spill settings (saved with the document, not undo steps; missing = the defaults). */
4468
- __init97() {this.lightSpills = {}}
4469
- __init98() {this.lightCaches = /* @__PURE__ */ new Map()}
4516
+ __init101() {this.lightSpills = {}}
4517
+ __init102() {this.lightCaches = /* @__PURE__ */ new Map()}
4470
4518
  /** Backlit paper: the light through the paint as drawn (live strokes too), and as committed (its spill). */
4471
- __init99() {this.backlightView = new BacklightCache()}
4472
- __init100() {this.backlightCommitted = new BacklightCache()}
4519
+ __init103() {this.backlightView = new BacklightCache()}
4520
+ __init104() {this.backlightCommitted = new BacklightCache()}
4473
4521
  /** Live effect paint: playing and the frame rate cap (editor state), and the time the view shows. */
4474
- __init101() {this.effectPlaybackState = { playing: true, fps: 30 }}
4475
- __init102() {this.effectTime = 0}
4522
+ __init105() {this.effectPlaybackState = { playing: true, fps: 30 }}
4523
+ __init106() {this.effectTime = 0}
4476
4524
  /** While a frame is drawn: the time live effect strokes are drawn at (else their own time). */
4477
- __init103() {this.liveEffectAt = null}
4525
+ __init107() {this.liveEffectAt = null}
4478
4526
  /** The view's stroke layers at `effectTime`, each with the document surface it was drawn from (stale once that changes). */
4479
- __init104() {this.animatedLayers = /* @__PURE__ */ new Map()}
4527
+ __init108() {this.animatedLayers = /* @__PURE__ */ new Map()}
4480
4528
  /** `renderAnimationFrame` / `withEffectTime`: layer surfaces at another time, for one render. */
4481
- __init105() {this.frameOverride = null}
4529
+ __init109() {this.frameOverride = null}
4482
4530
  /** The area each stroke painted (document pixels; `null`: nothing), learnt as it is painted or drawn, so a stroke layer edit redraws only where it changes (see `drawLiveStrokes`). */
4483
- __init106() {this.paintedBounds = /* @__PURE__ */ new WeakMap()}
4531
+ __init110() {this.paintedBounds = /* @__PURE__ */ new WeakMap()}
4484
4532
 
4485
- __init107() {this.swatches = DEFAULT_SWATCHES.map((s) => ({ ...s }))}
4486
- __init108() {this.pad = new MixingPad()}
4487
- __init109() {this.savedPads = []}
4488
- __init110() {this.nextPadId = 1}
4489
- __init111() {this.tracingVersion = 1}
4490
- __init112() {this.tracingCache = null}
4491
- __init113() {this.imagePixels = /* @__PURE__ */ new Map()}
4492
- __init114() {this.nextReferenceId = 1}
4493
- __init115() {this.viewCompositor = createPaintCompositor()}
4494
- __init116() {this.exportCompositor = createPaintCompositor()}
4533
+ __init111() {this.swatches = DEFAULT_SWATCHES.map((s) => ({ ...s }))}
4534
+ __init112() {this.pad = new MixingPad()}
4535
+ __init113() {this.savedPads = []}
4536
+ __init114() {this.nextPadId = 1}
4537
+ __init115() {this.tracingVersion = 1}
4538
+ __init116() {this.tracingCache = null}
4539
+ __init117() {this.imagePixels = /* @__PURE__ */ new Map()}
4540
+ __init118() {this.nextReferenceId = 1}
4541
+ __init119() {this.viewCompositor = createPaintCompositor()}
4542
+ __init120() {this.exportCompositor = createPaintCompositor()}
4495
4543
  /** Wet media: the simulation, its settings and time. */
4496
4544
 
4497
4545
 
4498
4546
  /** Where the light comes from for thick paint (saved with the document, not undo steps). */
4499
- __init117() {this.lighting = { ...DEFAULT_LIGHTING }}
4500
- __init118() {this.litCaches = /* @__PURE__ */ new Map()}
4547
+ __init121() {this.lighting = { ...DEFAULT_LIGHTING }}
4548
+ __init122() {this.litCaches = /* @__PURE__ */ new Map()}
4501
4549
  /** The live impasto stroke's channels. */
4502
- __init119() {this.liveThick = null}
4550
+ __init123() {this.liveThick = null}
4503
4551
  /** Set while an operation that changes wet paint runs: the simulation before it (for undo). */
4504
- __init120() {this.wetOp = null}
4552
+ __init124() {this.wetOp = null}
4505
4553
  /** The effects provider slot (see `setEffectsProvider`). */
4506
- __init121() {this.effects = new (0, _chunkL2JTLW6Bcjs.EffectsSlot)()}
4554
+ __init125() {this.effects = new (0, _chunkL2JTLW6Bcjs.EffectsSlot)()}
4507
4555
  /** The sticker library slot (see `setStickersProvider`). */
4508
- __init122() {this.stickers = new (0, _chunkRDFHWAHLcjs.StickersSlot)(_chunk3VHH6V67cjs.editorStickers.call(void 0, ))}
4509
- __init123() {this.stickerArt = new StickerArtCache()}
4556
+ __init126() {this.stickers = new (0, _chunkRDFHWAHLcjs.StickersSlot)(_chunk3VHH6V67cjs.editorStickers.call(void 0, ))}
4557
+ __init127() {this.stickerArt = new StickerArtCache()}
4510
4558
  /** Image sources strokes draw with: the brush library's and the open painting's (saved with it). */
4511
- __init124() {this.brushSources = new BrushSourceArtCache()}
4559
+ __init128() {this.brushSources = new BrushSourceArtCache()}
4512
4560
  /** Art for stamp tips and tip grain: image sources from `brushSources`, stickers from the sticker library. */
4513
- __init125() {this.stampArt = (ref2, variant) => _chunkEU2ZZA6Lcjs.isBrushSourceRef.call(void 0, ref2) ? this.brushSources.get(ref2) : this.stickerArt.get(ref2, variant)}
4561
+ __init129() {this.stampArt = (ref2, variant) => _chunkGHGBIAWQcjs.isBrushSourceRef.call(void 0, ref2) ? this.brushSources.get(ref2) : this.stickerArt.get(ref2, variant)}
4514
4562
 
4515
- __init126() {this.effectsRenderer = new PaintEffectsRenderer()}
4516
- __init127() {this.paperEffectNodeCache = null}
4517
- constructor(options = {}) {;_class14.prototype.__init66.call(this);_class14.prototype.__init67.call(this);_class14.prototype.__init68.call(this);_class14.prototype.__init69.call(this);_class14.prototype.__init70.call(this);_class14.prototype.__init71.call(this);_class14.prototype.__init72.call(this);_class14.prototype.__init73.call(this);_class14.prototype.__init74.call(this);_class14.prototype.__init75.call(this);_class14.prototype.__init76.call(this);_class14.prototype.__init77.call(this);_class14.prototype.__init78.call(this);_class14.prototype.__init79.call(this);_class14.prototype.__init80.call(this);_class14.prototype.__init81.call(this);_class14.prototype.__init82.call(this);_class14.prototype.__init83.call(this);_class14.prototype.__init84.call(this);_class14.prototype.__init85.call(this);_class14.prototype.__init86.call(this);_class14.prototype.__init87.call(this);_class14.prototype.__init88.call(this);_class14.prototype.__init89.call(this);_class14.prototype.__init90.call(this);_class14.prototype.__init91.call(this);_class14.prototype.__init92.call(this);_class14.prototype.__init93.call(this);_class14.prototype.__init94.call(this);_class14.prototype.__init95.call(this);_class14.prototype.__init96.call(this);_class14.prototype.__init97.call(this);_class14.prototype.__init98.call(this);_class14.prototype.__init99.call(this);_class14.prototype.__init100.call(this);_class14.prototype.__init101.call(this);_class14.prototype.__init102.call(this);_class14.prototype.__init103.call(this);_class14.prototype.__init104.call(this);_class14.prototype.__init105.call(this);_class14.prototype.__init106.call(this);_class14.prototype.__init107.call(this);_class14.prototype.__init108.call(this);_class14.prototype.__init109.call(this);_class14.prototype.__init110.call(this);_class14.prototype.__init111.call(this);_class14.prototype.__init112.call(this);_class14.prototype.__init113.call(this);_class14.prototype.__init114.call(this);_class14.prototype.__init115.call(this);_class14.prototype.__init116.call(this);_class14.prototype.__init117.call(this);_class14.prototype.__init118.call(this);_class14.prototype.__init119.call(this);_class14.prototype.__init120.call(this);_class14.prototype.__init121.call(this);_class14.prototype.__init122.call(this);_class14.prototype.__init123.call(this);_class14.prototype.__init124.call(this);_class14.prototype.__init125.call(this);_class14.prototype.__init126.call(this);_class14.prototype.__init127.call(this);_class14.prototype.__init128.call(this);_class14.prototype.__init129.call(this);_class14.prototype.__init130.call(this);_class14.prototype.__init131.call(this);_class14.prototype.__init132.call(this);_class14.prototype.__init133.call(this);
4563
+ __init130() {this.effectsRenderer = new PaintEffectsRenderer()}
4564
+ __init131() {this.paperEffectNodeCache = null}
4565
+ constructor(options = {}) {;_class14.prototype.__init66.call(this);_class14.prototype.__init67.call(this);_class14.prototype.__init68.call(this);_class14.prototype.__init69.call(this);_class14.prototype.__init70.call(this);_class14.prototype.__init71.call(this);_class14.prototype.__init72.call(this);_class14.prototype.__init73.call(this);_class14.prototype.__init74.call(this);_class14.prototype.__init75.call(this);_class14.prototype.__init76.call(this);_class14.prototype.__init77.call(this);_class14.prototype.__init78.call(this);_class14.prototype.__init79.call(this);_class14.prototype.__init80.call(this);_class14.prototype.__init81.call(this);_class14.prototype.__init82.call(this);_class14.prototype.__init83.call(this);_class14.prototype.__init84.call(this);_class14.prototype.__init85.call(this);_class14.prototype.__init86.call(this);_class14.prototype.__init87.call(this);_class14.prototype.__init88.call(this);_class14.prototype.__init89.call(this);_class14.prototype.__init90.call(this);_class14.prototype.__init91.call(this);_class14.prototype.__init92.call(this);_class14.prototype.__init93.call(this);_class14.prototype.__init94.call(this);_class14.prototype.__init95.call(this);_class14.prototype.__init96.call(this);_class14.prototype.__init97.call(this);_class14.prototype.__init98.call(this);_class14.prototype.__init99.call(this);_class14.prototype.__init100.call(this);_class14.prototype.__init101.call(this);_class14.prototype.__init102.call(this);_class14.prototype.__init103.call(this);_class14.prototype.__init104.call(this);_class14.prototype.__init105.call(this);_class14.prototype.__init106.call(this);_class14.prototype.__init107.call(this);_class14.prototype.__init108.call(this);_class14.prototype.__init109.call(this);_class14.prototype.__init110.call(this);_class14.prototype.__init111.call(this);_class14.prototype.__init112.call(this);_class14.prototype.__init113.call(this);_class14.prototype.__init114.call(this);_class14.prototype.__init115.call(this);_class14.prototype.__init116.call(this);_class14.prototype.__init117.call(this);_class14.prototype.__init118.call(this);_class14.prototype.__init119.call(this);_class14.prototype.__init120.call(this);_class14.prototype.__init121.call(this);_class14.prototype.__init122.call(this);_class14.prototype.__init123.call(this);_class14.prototype.__init124.call(this);_class14.prototype.__init125.call(this);_class14.prototype.__init126.call(this);_class14.prototype.__init127.call(this);_class14.prototype.__init128.call(this);_class14.prototype.__init129.call(this);_class14.prototype.__init130.call(this);_class14.prototype.__init131.call(this);_class14.prototype.__init132.call(this);_class14.prototype.__init133.call(this);_class14.prototype.__init134.call(this);_class14.prototype.__init135.call(this);_class14.prototype.__init136.call(this);_class14.prototype.__init137.call(this);
4518
4566
  this.historyLimit = Math.max(1, _nullishCoalesce(options.historyLimit, () => ( 200)));
4519
4567
  this.rasterizeSticker = _nullishCoalesce(options.rasterizeSticker, () => ( defaultStickerRasterizer));
4520
4568
  if (options.stickers) this.stickers.set(options.stickers);
4521
4569
  this.doc = createPaintDocument({ width: options.width, height: options.height, dpi: options.dpi, paper: this.resolvePaper(options.paper) });
4522
- const seed = (_nullishCoalesce(options.brushes, () => ( []))).map((b) => _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, { ...b, builtin: false }));
4523
- this.brushLibrary = _nullishCoalesce(options.brushLibrary, () => ( _chunkEU2ZZA6Lcjs.createBrushLibrary.call(void 0, { storage: seededStorage(seed) })));
4524
- this.brushEntries = [...builtinLibraryBrushes(), ...seed.map((b) => libraryBrush(_chunkEU2ZZA6Lcjs.migrateBrushV1.call(void 0, b), false, b))];
4525
- const wanted = _nullishCoalesce(options.brushId, () => ( _chunkEU2ZZA6Lcjs.DEFAULT_BRUSH_ID));
4526
- const start = _nullishCoalesce(this.findEntry(wanted), () => ( this.findEntry(_chunkEU2ZZA6Lcjs.DEFAULT_BRUSH_ID)));
4527
- this.brush = _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, start.brush);
4570
+ const seed = (_nullishCoalesce(options.brushes, () => ( []))).map((b) => _chunkGHGBIAWQcjs.normalizePaintBrush.call(void 0, { ...b, builtin: false }));
4571
+ this.brushLibrary = _nullishCoalesce(options.brushLibrary, () => ( _chunkGHGBIAWQcjs.createBrushLibrary.call(void 0, { storage: seededStorage(seed) })));
4572
+ this.brushEntries = [...builtinLibraryBrushes(), ...seed.map((b) => libraryBrush(_chunkGHGBIAWQcjs.migrateBrushV1.call(void 0, b), false, b))];
4573
+ const wanted = _nullishCoalesce(options.brushId, () => ( _chunkGHGBIAWQcjs.DEFAULT_BRUSH_ID));
4574
+ const start = _nullishCoalesce(this.findEntry(wanted), () => ( this.findEntry(_chunkGHGBIAWQcjs.DEFAULT_BRUSH_ID)));
4575
+ this.brush = _chunkGHGBIAWQcjs.normalizePaintBrush.call(void 0, start.brush);
4528
4576
  this.brushSpec = copyJSON(start.spec);
4529
4577
  this.unsubscribeLibrary = this.brushLibrary.subscribe(() => void this.refreshBrushes().catch(() => void 0));
4530
- if (options.brushLibrary && seed.length) void this.brushLibrary.importFile(seed.map(_chunkEU2ZZA6Lcjs.brushToJSON)).catch(() => void 0);
4578
+ if (options.brushLibrary && seed.length) void this.brushLibrary.importFile(seed.map(_chunkGHGBIAWQcjs.brushToJSON)).catch(() => void 0);
4531
4579
  void this.refreshBrushes().catch(() => void 0);
4532
4580
  this.pendingBrushId = start.brush.id === wanted ? null : wanted;
4533
4581
  this.color = options.color ? parseColor(options.color) : "#1f2937";
@@ -4536,12 +4584,12 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
4536
4584
  this.encodeImage = options.encodeImage;
4537
4585
  this.guides = defaultGuides(this.doc.canvas);
4538
4586
  this.wetOptions = options.wet;
4539
- this.wet = new (0, _chunk56RHCIJVcjs.PaintWetLayers)(
4587
+ this.wet = new (0, _chunkSNAFFCAXcjs.PaintWetLayers)(
4540
4588
  {
4541
4589
  canvas: () => this.doc.canvas,
4542
4590
  paper: () => this.doc.paper,
4543
4591
  layerSurface: (id) => {
4544
- const l = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _189 => _189.layer]);
4592
+ const l = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _205 => _205.layer]);
4545
4593
  return isPixelLayer(l) ? l.surface : null;
4546
4594
  },
4547
4595
  updateSurfaces: (surfaces, rects) => {
@@ -4550,7 +4598,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
4550
4598
  this.doc = { ...this.doc, layers };
4551
4599
  this.emit(rects.length ? rects : "all");
4552
4600
  },
4553
- layerLight: (id) => _nullishCoalesce(_optionalChain([this, 'access', _190 => _190.doc, 'access', _191 => _191.light, 'optionalAccess', _192 => _192[id]]), () => ( null)),
4601
+ layerLight: (id) => _nullishCoalesce(_optionalChain([this, 'access', _206 => _206.doc, 'access', _207 => _207.light, 'optionalAccess', _208 => _208[id]]), () => ( null)),
4554
4602
  updateLights: (lights) => {
4555
4603
  let light = this.doc.light;
4556
4604
  for (const [id, surface] of lights) if (_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, id)) light = withLayerLight(light, id, surface);
@@ -4561,7 +4609,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
4561
4609
  },
4562
4610
  options.wet
4563
4611
  );
4564
- this.wet.onDriverDone = () => _optionalChain([this, 'access', _193 => _193.session, 'optionalAccess', _194 => _194.completeWetEnd, 'call', _195 => _195()]);
4612
+ this.wet.onDriverDone = () => _optionalChain([this, 'access', _209 => _209.session, 'optionalAccess', _210 => _210.completeWetEnd, 'call', _211 => _211()]);
4565
4613
  }
4566
4614
  // --- State and events ----------------------------------------------------------
4567
4615
  subscribe(listener) {
@@ -4731,7 +4779,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
4731
4779
  if (placement.bottom) this.moveLayer(layer.id, 0, null);
4732
4780
  fn(layer.id);
4733
4781
  if (this.wetOp || this.pendingWetEvents.length) throw new PaintEditorError("Wet paint can't be previewed; suggest it with a dry brush.");
4734
- const found = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, layer.id), 'optionalAccess', _196 => _196.layer]);
4782
+ const found = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, layer.id), 'optionalAccess', _212 => _212.layer]);
4735
4783
  const surface = found && isPixelLayer(found) ? found.surface : null;
4736
4784
  const bounds = surface ? _chunk474IQG74cjs.contentBounds.call(void 0, surface) : null;
4737
4785
  const box = bounds ? clipToCanvas(bounds, this.doc.canvas) : null;
@@ -4775,7 +4823,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
4775
4823
  secondaryColor: this.secondaryColor,
4776
4824
  paint: _nullishCoalesce(this.gradient, () => ( { type: "color", color: this.color })),
4777
4825
  effectPaint: _nullishCoalesce(this.effectPaintPending, () => ( this.effectPaint)),
4778
- effectPaintRendering: Boolean(this.effectPaintPending),
4826
+ effectPaintRendering: Boolean(this.effectPaintPending || this.pathStroke),
4779
4827
  mixerLoad: this.mixerLoad,
4780
4828
  view: this.view,
4781
4829
  hand: this.hand,
@@ -4784,8 +4832,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
4784
4832
  selectedSticker: this.selectedSticker,
4785
4833
  canUndo: this.undoStack.length > 0 && !this.session,
4786
4834
  canRedo: this.redoStack.length > 0 && !this.session,
4787
- undoLabel: _nullishCoalesce(_optionalChain([last, 'optionalAccess', _197 => _197.label]), () => ( null)),
4788
- redoLabel: _nullishCoalesce(_optionalChain([next, 'optionalAccess', _198 => _198.label]), () => ( null)),
4835
+ undoLabel: _nullishCoalesce(_optionalChain([last, 'optionalAccess', _213 => _213.label]), () => ( null)),
4836
+ redoLabel: _nullishCoalesce(_optionalChain([next, 'optionalAccess', _214 => _214.label]), () => ( null)),
4789
4837
  guides: this.guides,
4790
4838
  swatches: this.swatches,
4791
4839
  mixingPadVersion: this.pad.version,
@@ -4798,10 +4846,10 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
4798
4846
  overlay: this.wet.overlay,
4799
4847
  instantDry: this.wet.instantDry,
4800
4848
  speed: this.wet.speed,
4801
- clock: _nullishCoalesce(_optionalChain([this, 'access', _199 => _199.wet, 'access', _200 => _200.world, 'optionalAccess', _201 => _201.clock]), () => ( 0)),
4849
+ clock: _nullishCoalesce(_optionalChain([this, 'access', _215 => _215.wet, 'access', _216 => _216.world, 'optionalAccess', _217 => _217.clock]), () => ( 0)),
4802
4850
  tilt: { ...this.wet.tilt },
4803
4851
  gpu: this.wet.gpuMode,
4804
- gpuActive: Boolean(_optionalChain([this, 'access', _202 => _202.wet, 'access', _203 => _203.world, 'optionalAccess', _204 => _204.gpuActive]))
4852
+ gpuActive: Boolean(_optionalChain([this, 'access', _218 => _218.wet, 'access', _219 => _219.world, 'optionalAccess', _220 => _220.gpuActive]))
4805
4853
  },
4806
4854
  version: this.version
4807
4855
  };
@@ -4820,7 +4868,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
4820
4868
  return d;
4821
4869
  }
4822
4870
  // --- History -------------------------------------------------------------------
4823
- __init128() {this.docRevision = 0}
4871
+ __init132() {this.docRevision = 0}
4824
4872
  /**
4825
4873
  * Bumped on every change to the painting (a committed or amended step, undo, redo, opening a
4826
4874
  * document), not on wet-paint frames or view changes. `createPaintEditorDocument` uses it.
@@ -4831,13 +4879,14 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
4831
4879
  /** Why the document cannot be replaced or stepped through right now, or `null`. */
4832
4880
  busyReason() {
4833
4881
  if (this.session) return "A stroke is in progress; end or cancel it first.";
4834
- if (_optionalChain([this, 'access', _205 => _205.grouping, 'optionalAccess', _206 => _206.pending]) && !this.grouping.inside) return `"${this.grouping.label}" is still being painted; wait for it to finish first.`;
4882
+ if (_optionalChain([this, 'access', _221 => _221.grouping, 'optionalAccess', _222 => _222.pending]) && !this.grouping.inside) return `"${this.grouping.label}" is still being painted; wait for it to finish first.`;
4835
4883
  if (this.wet.busy) return "Wet paint is mid-step; wait a moment (wetIdle()) first.";
4836
4884
  return null;
4837
4885
  }
4838
4886
  requireIdle(what) {
4839
4887
  if (this.session) throw new PaintEditorError(`A stroke is in progress; end or cancel it before ${what}.`);
4840
- if (_optionalChain([this, 'access', _207 => _207.grouping, 'optionalAccess', _208 => _208.pending]) && !this.grouping.inside) throw new PaintEditorError(`"${this.grouping.label}" is still being painted (one undo step); wait for it to finish before ${what}.`);
4888
+ if (this.pathStroke) throw new PaintEditorError(`The last stroke is still rendering the effect "${this.pathStroke.effect}" along its path; wait for it (strokeRendering) before ${what}.`);
4889
+ if (_optionalChain([this, 'access', _223 => _223.grouping, 'optionalAccess', _224 => _224.pending]) && !this.grouping.inside) throw new PaintEditorError(`"${this.grouping.label}" is still being painted (one undo step); wait for it to finish before ${what}.`);
4841
4890
  }
4842
4891
  commit(label, next, before = this.doc) {
4843
4892
  if (this.grouping) {
@@ -4913,9 +4962,9 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
4913
4962
  return wetIds;
4914
4963
  }
4915
4964
  /** Records a wet event (for replays) in the document being built. */
4916
- __init129() {this.pendingWetEvents = []}
4965
+ __init133() {this.pendingWetEvents = []}
4917
4966
  logWet(e) {
4918
- this.pendingWetEvents.push({ clock: _nullishCoalesce(_optionalChain([this, 'access', _209 => _209.wet, 'access', _210 => _210.world, 'optionalAccess', _211 => _211.clock]), () => ( 0)), at: this.doc.strokes.length, ...e });
4967
+ this.pendingWetEvents.push({ clock: _nullishCoalesce(_optionalChain([this, 'access', _225 => _225.wet, 'access', _226 => _226.world, 'optionalAccess', _227 => _227.clock]), () => ( 0)), at: this.doc.strokes.length, ...e });
4919
4968
  }
4920
4969
  /** The document with a paint event appended (for replays). */
4921
4970
  withPaintEvent(doc, e) {
@@ -4978,7 +5027,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
4978
5027
  // --- Canvas and paper ----------------------------------------------------------
4979
5028
  resolvePaper(paper) {
4980
5029
  if (typeof paper === "string") {
4981
- const p = _chunk56RHCIJVcjs.paperPreset.call(void 0, paper);
5030
+ const p = _chunkSNAFFCAXcjs.paperPreset.call(void 0, paper);
4982
5031
  if (!p) throw new PaintEditorError(`Unknown paper "${paper}". Call list_papers for the ids.`);
4983
5032
  return p;
4984
5033
  }
@@ -5061,7 +5110,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5061
5110
  }
5062
5111
  let next = { ...shiftDocument(this.withWetEvents(this.doc), left, top), canvas: { ...was, width, height } };
5063
5112
  for (const id of keptWet) {
5064
- const l = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, next.layers, id), 'optionalAccess', _212 => _212.layer]);
5113
+ const l = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, next.layers, id), 'optionalAccess', _228 => _228.layer]);
5065
5114
  if (isPixelLayer(l)) next = { ...next, layers: _chunkPVJMTLPJcjs.mapLayer.call(void 0, next.layers, id, () => ({ ...l, surface: _chunk474IQG74cjs.translateSurface.call(void 0, l.surface, l.offset.x, l.offset.y), offset: { x: 0, y: 0 } })) };
5066
5115
  }
5067
5116
  if (this.wet.world) {
@@ -5089,23 +5138,23 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5089
5138
  this.requireIdle("changing the paper");
5090
5139
  let base = this.doc.paper;
5091
5140
  if (update.preset !== void 0 && update.preset !== this.doc.paper.preset) {
5092
- const p = _chunk56RHCIJVcjs.paperPreset.call(void 0, update.preset);
5141
+ const p = _chunkSNAFFCAXcjs.paperPreset.call(void 0, update.preset);
5093
5142
  if (!p) throw new PaintEditorError(`Unknown paper "${update.preset}". Call list_papers for the ids.`);
5094
5143
  base = p;
5095
5144
  }
5096
5145
  const { preset: _p, ...rest } = update;
5097
5146
  if (rest.color !== void 0) parseColor(rest.color, "paper color");
5098
- const paper = _chunk56RHCIJVcjs.normalizePaper.call(void 0, { ...rest, preset: base.preset, offset: _nullishCoalesce(rest.offset, () => ( this.doc.paper.offset)) }, base);
5147
+ const paper = _chunkSNAFFCAXcjs.normalizePaper.call(void 0, { ...rest, preset: base.preset, offset: _nullishCoalesce(rest.offset, () => ( this.doc.paper.offset)) }, base);
5099
5148
  const changedKeys = Object.keys(rest).filter((k) => k !== "name");
5100
5149
  if (changedKeys.length && update.preset === void 0) paper.preset = base.preset;
5101
5150
  if (this.wet.world) this.beginWetOp();
5102
5151
  this.commit("Paper", { ...this.doc, paper });
5103
5152
  this.wet.paperChanged();
5104
- return _chunk56RHCIJVcjs.clonePaper.call(void 0, paper);
5153
+ return _chunkSNAFFCAXcjs.clonePaper.call(void 0, paper);
5105
5154
  }
5106
5155
  // --- Layers --------------------------------------------------------------------
5107
5156
  getLayer(id) {
5108
- return _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _213 => _213.layer]);
5157
+ return _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _229 => _229.layer]);
5109
5158
  }
5110
5159
  /** The active pixel layer (or `undefined`). */
5111
5160
  getActiveLayer() {
@@ -5124,7 +5173,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5124
5173
  walk(this.doc.layers, null, 0);
5125
5174
  return out;
5126
5175
  }
5127
- describeLayer(l, parentId = _nullishCoalesce(_optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, l.id), 'optionalAccess', _214 => _214.parent, 'optionalAccess', _215 => _215.id]), () => ( null)), depth = _nullishCoalesce(_optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, l.id), 'optionalAccess', _216 => _216.path, 'access', _217 => _217.length]), () => ( 0))) {
5176
+ describeLayer(l, parentId = _nullishCoalesce(_optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, l.id), 'optionalAccess', _230 => _230.parent, 'optionalAccess', _231 => _231.id]), () => ( null)), depth = _nullishCoalesce(_optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, l.id), 'optionalAccess', _232 => _232.path, 'access', _233 => _233.length]), () => ( 0))) {
5128
5177
  let bounds = null;
5129
5178
  if (l.type === "pixel") {
5130
5179
  const b = _chunk474IQG74cjs.contentBounds.call(void 0, l.surface);
@@ -5141,8 +5190,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5141
5190
  locks: { ..._nullishCoalesce(l.locks, () => ( {})) },
5142
5191
  active: l.id === this.doc.activeLayerId,
5143
5192
  bounds,
5144
- ..._optionalChain([this, 'access', _218 => _218.doc, 'access', _219 => _219.liveStrokes, 'optionalAccess', _220 => _220[l.id]]) ? { liveStrokes: this.doc.liveStrokes[l.id].length } : {},
5145
- ..._optionalChain([l, 'access', _221 => _221.effects, 'optionalAccess', _222 => _222.items, 'access', _223 => _223.length]) ? { effects: l.effects.items.length } : {},
5193
+ ..._optionalChain([this, 'access', _234 => _234.doc, 'access', _235 => _235.liveStrokes, 'optionalAccess', _236 => _236[l.id]]) ? { liveStrokes: this.doc.liveStrokes[l.id].length } : {},
5194
+ ..._optionalChain([l, 'access', _237 => _237.effects, 'optionalAccess', _238 => _238.items, 'access', _239 => _239.length]) ? { effects: l.effects.items.length } : {},
5146
5195
  parentId,
5147
5196
  depth
5148
5197
  };
@@ -5174,7 +5223,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5174
5223
  this.requireIdle("adding a layer");
5175
5224
  const count = _chunkPVJMTLPJcjs.flattenLayers.call(void 0, this.doc.layers).length;
5176
5225
  const type = _nullishCoalesce(options.type, () => ( "pixel"));
5177
- const name = _optionalChain([options, 'access', _224 => _224.name, 'optionalAccess', _225 => _225.trim, 'call', _226 => _226()]) || (type === "group" ? `Group ${count + 1}` : type === "strokes" ? `Strokes ${count + 1}` : `Layer ${count + 1}`);
5226
+ const name = _optionalChain([options, 'access', _240 => _240.name, 'optionalAccess', _241 => _241.trim, 'call', _242 => _242()]) || (type === "group" ? `Group ${count + 1}` : type === "strokes" ? `Strokes ${count + 1}` : `Layer ${count + 1}`);
5178
5227
  const layer = type === "group" ? { type: "group", id: newPaintLayerId(), name, visible: true, opacity: 1, blend: "pass-through", children: [] } : createPaintLayer(name);
5179
5228
  let parentId = null;
5180
5229
  let index;
@@ -5186,7 +5235,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5186
5235
  } else if (above) {
5187
5236
  const loc = _chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, above);
5188
5237
  if (!loc) throw new PaintEditorError(`Unknown layer "${above}". Call list_layers for the ids.`);
5189
- parentId = _nullishCoalesce(_optionalChain([loc, 'access', _227 => _227.parent, 'optionalAccess', _228 => _228.id]), () => ( null));
5238
+ parentId = _nullishCoalesce(_optionalChain([loc, 'access', _243 => _243.parent, 'optionalAccess', _244 => _244.id]), () => ( null));
5190
5239
  index = loc.index + 1;
5191
5240
  }
5192
5241
  const layers = _chunkPVJMTLPJcjs.insertLayer.call(void 0, this.doc.layers, layer, parentId, index);
@@ -5292,7 +5341,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5292
5341
  }
5293
5342
  requireEffect(id, effectId) {
5294
5343
  const l = this.requireLayer(id);
5295
- const items = _nullishCoalesce(_optionalChain([l, 'access', _229 => _229.effects, 'optionalAccess', _230 => _230.items]), () => ( []));
5344
+ const items = _nullishCoalesce(_optionalChain([l, 'access', _245 => _245.effects, 'optionalAccess', _246 => _246.items]), () => ( []));
5296
5345
  const i = items.findIndex((e) => e.id === effectId);
5297
5346
  if (i === -1) throw new PaintEditorError(`Layer "${l.name}" has no effect "${effectId}". Effects: ${items.map((e) => `${e.id} (${e.kind})`).join(", ") || "none"}; call list_layer_effects.`);
5298
5347
  return i;
@@ -5315,7 +5364,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5315
5364
  }
5316
5365
  const layers = _chunkPVJMTLPJcjs.mapLayer.call(void 0, this.doc.layers, id, () => null);
5317
5366
  let active = this.doc.activeLayerId;
5318
- if (active && !_chunkPVJMTLPJcjs.findLayer.call(void 0, layers, active)) active = _nullishCoalesce(_optionalChain([_chunkPVJMTLPJcjs.flattenLayers.call(void 0, layers), 'access', _231 => _231.filter, 'call', _232 => _232((x) => x.type === "pixel"), 'access', _233 => _233.pop, 'call', _234 => _234(), 'optionalAccess', _235 => _235.id]), () => ( null));
5367
+ if (active && !_chunkPVJMTLPJcjs.findLayer.call(void 0, layers, active)) active = _nullishCoalesce(_optionalChain([_chunkPVJMTLPJcjs.flattenLayers.call(void 0, layers), 'access', _247 => _247.filter, 'call', _248 => _248((x) => x.type === "pixel"), 'access', _249 => _249.pop, 'call', _250 => _250(), 'optionalAccess', _251 => _251.id]), () => ( null));
5319
5368
  this.commit("Remove layer", { ...this.doc, layers, activeLayerId: active, ...this.thickWithout(_chunkPVJMTLPJcjs.flattenLayers.call(void 0, [l]).map((x) => x.id)), ...this.stickersWithout(_chunkPVJMTLPJcjs.flattenLayers.call(void 0, [l]).map((x) => x.id)), ...this.liveStrokesWithout(_chunkPVJMTLPJcjs.flattenLayers.call(void 0, [l]).map((x) => x.id)), ...this.lightWithout(_chunkPVJMTLPJcjs.flattenLayers.call(void 0, [l]).map((x) => x.id)) });
5320
5369
  return { removed: id, activeLayerId: active };
5321
5370
  }
@@ -5341,7 +5390,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5341
5390
  return l.type === "group" ? { ...l, id: id2, children: l.children.map(copy) } : { ...l, id: id2 };
5342
5391
  };
5343
5392
  const dup = { ...copy(loc.layer), name: `${loc.layer.name} copy` };
5344
- const layers = _chunkPVJMTLPJcjs.insertLayer.call(void 0, this.doc.layers, dup, _nullishCoalesce(_optionalChain([loc, 'access', _236 => _236.parent, 'optionalAccess', _237 => _237.id]), () => ( null)), loc.index + 1);
5393
+ const layers = _chunkPVJMTLPJcjs.insertLayer.call(void 0, this.doc.layers, dup, _nullishCoalesce(_optionalChain([loc, 'access', _252 => _252.parent, 'optionalAccess', _253 => _253.id]), () => ( null)), loc.index + 1);
5345
5394
  this.commit("Duplicate layer", this.withWetEvents({ ...this.doc, layers, activeLayerId: dup.id, ...this.doc.thick ? { thick } : {}, ...this.doc.stickers ? { stickers } : {}, ...this.doc.liveStrokes ? { liveStrokes } : {}, ...this.doc.light ? { light } : {} }));
5346
5395
  return this.describeLayer(dup);
5347
5396
  }
@@ -5350,7 +5399,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5350
5399
  this.requireIdle("moving a layer");
5351
5400
  const loc = _chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, id);
5352
5401
  if (!loc) throw new PaintEditorError(`Unknown layer "${id}". Call list_layers for the ids.`);
5353
- const target = parentId === void 0 ? _nullishCoalesce(_optionalChain([loc, 'access', _238 => _238.parent, 'optionalAccess', _239 => _239.id]), () => ( null)) : parentId;
5402
+ const target = parentId === void 0 ? _nullishCoalesce(_optionalChain([loc, 'access', _254 => _254.parent, 'optionalAccess', _255 => _255.id]), () => ( null)) : parentId;
5354
5403
  if (target) {
5355
5404
  const g = this.requireLayer(target);
5356
5405
  if (g.type !== "group") throw new PaintEditorError(`Layer "${g.name}" is not a group; pass a group id as parentId.`);
@@ -5369,7 +5418,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5369
5418
  const pre = _chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, id);
5370
5419
  if (pre) {
5371
5420
  const sib = pre.parent ? pre.parent.children : this.doc.layers;
5372
- this.dryLayersFirst([id, _optionalChain([sib, 'access', _240 => _240[pre.index - 1], 'optionalAccess', _241 => _241.id])].filter((x) => Boolean(x)));
5421
+ this.dryLayersFirst([id, _optionalChain([sib, 'access', _256 => _256[pre.index - 1], 'optionalAccess', _257 => _257.id])].filter((x) => Boolean(x)));
5373
5422
  }
5374
5423
  const loc = _chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, id);
5375
5424
  if (!loc) throw new PaintEditorError(`Unknown layer "${id}". Call list_layers for the ids.`);
@@ -5389,7 +5438,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5389
5438
  const merged = { ...below, surface, offset: { x: 0, y: 0 } };
5390
5439
  const layers = _chunkPVJMTLPJcjs.mapLayer.call(void 0, _chunkPVJMTLPJcjs.mapLayer.call(void 0, this.doc.layers, upper.id, () => null), below.id, () => merged);
5391
5440
  const toDoc = (t, l) => t ? _chunk474IQG74cjs.translateSurface.call(void 0, t, l.offset.x, l.offset.y) : void 0;
5392
- const mergedLight = _optionalChain([this, 'access', _242 => _242.doc, 'access', _243 => _243.light, 'optionalAccess', _244 => _244[upper.id]]) || _optionalChain([this, 'access', _245 => _245.doc, 'access', _246 => _246.light, 'optionalAccess', _247 => _247[below.id]]) ? mergeLight(toDoc(_optionalChain([this, 'access', _248 => _248.doc, 'access', _249 => _249.light, 'optionalAccess', _250 => _250[below.id]]), below), upper.visible ? toDoc(_optionalChain([this, 'access', _251 => _251.doc, 'access', _252 => _252.light, 'optionalAccess', _253 => _253[upper.id]]), upper) : void 0, _chunk474IQG74cjs.translateSurface.call(void 0, upper.surface, upper.offset.x, upper.offset.y)) : void 0;
5441
+ const mergedLight = _optionalChain([this, 'access', _258 => _258.doc, 'access', _259 => _259.light, 'optionalAccess', _260 => _260[upper.id]]) || _optionalChain([this, 'access', _261 => _261.doc, 'access', _262 => _262.light, 'optionalAccess', _263 => _263[below.id]]) ? mergeLight(toDoc(_optionalChain([this, 'access', _264 => _264.doc, 'access', _265 => _265.light, 'optionalAccess', _266 => _266[below.id]]), below), upper.visible ? toDoc(_optionalChain([this, 'access', _267 => _267.doc, 'access', _268 => _268.light, 'optionalAccess', _269 => _269[upper.id]]), upper) : void 0, _chunk474IQG74cjs.translateSurface.call(void 0, upper.surface, upper.offset.x, upper.offset.y)) : void 0;
5393
5442
  const lightAfter = _nullishCoalesce(this.lightWithout([upper.id, below.id]).light, () => ( (this.doc.light ? { ...this.doc.light } : void 0)));
5394
5443
  const light = mergedLight ? { ..._nullishCoalesce(lightAfter, () => ( {})), [below.id]: mergedLight } : lightAfter;
5395
5444
  this.commit("Merge down", this.withWetEvents({ ...this.doc, layers, activeLayerId: below.id, ...this.thickWithout([upper.id]), ...this.stickersWithout([upper.id, below.id]), ...this.liveStrokesWithout([upper.id, below.id]), ...light ? { light } : {} }));
@@ -5404,7 +5453,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5404
5453
  this.wet.world.removeLane(l.id);
5405
5454
  }
5406
5455
  const bounds = this.describeLayer(l).bounds;
5407
- this.commit("Clear layer", this.withPaintEvent({ ...this.doc, layers: _chunkPVJMTLPJcjs.mapLayer.call(void 0, this.doc.layers, l.id, () => ({ ...l, surface: _chunk474IQG74cjs.emptySurface.call(void 0, 4) })), ...this.thickWithout([l.id]), ...this.stickersWithout([l.id]), ..._optionalChain([this, 'access', _254 => _254.doc, 'access', _255 => _255.liveStrokes, 'optionalAccess', _256 => _256[l.id]]) ? { liveStrokes: { ...this.doc.liveStrokes, [l.id]: [] } } : {}, ...this.lightWithout([l.id]) }, { kind: "clear", layerId: l.id }));
5456
+ this.commit("Clear layer", this.withPaintEvent({ ...this.doc, layers: _chunkPVJMTLPJcjs.mapLayer.call(void 0, this.doc.layers, l.id, () => ({ ...l, surface: _chunk474IQG74cjs.emptySurface.call(void 0, 4) })), ...this.thickWithout([l.id]), ...this.stickersWithout([l.id]), ..._optionalChain([this, 'access', _270 => _270.doc, 'access', _271 => _271.liveStrokes, 'optionalAccess', _272 => _272[l.id]]) ? { liveStrokes: { ...this.doc.liveStrokes, [l.id]: [] } } : {}, ...this.lightWithout([l.id]) }, { kind: "clear", layerId: l.id }));
5408
5457
  return { layerId: l.id, bounds };
5409
5458
  }
5410
5459
  /**
@@ -5414,8 +5463,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5414
5463
  fillLayer(options = {}) {
5415
5464
  this.requireIdle("filling");
5416
5465
  const fillTarget = this.paintTarget(options.layerId, "fill");
5417
- if (_optionalChain([this, 'access', _257 => _257.doc, 'access', _258 => _258.stickers, 'optionalAccess', _259 => _259[fillTarget.id], 'optionalAccess', _260 => _260.length])) throw new PaintEditorError(`Layer "${fillTarget.name}" is a sticker layer; fill another layer (add_layer).`);
5418
- if (_optionalChain([this, 'access', _261 => _261.doc, 'access', _262 => _262.liveStrokes, 'optionalAccess', _263 => _263[fillTarget.id]])) throw new PaintEditorError(`Layer "${fillTarget.name}" is a stroke layer (its pixels are drawn from its strokes); fill another layer (add_layer), or rasterize it first (rasterize_stroke_layer).`);
5466
+ if (_optionalChain([this, 'access', _273 => _273.doc, 'access', _274 => _274.stickers, 'optionalAccess', _275 => _275[fillTarget.id], 'optionalAccess', _276 => _276.length])) throw new PaintEditorError(`Layer "${fillTarget.name}" is a sticker layer; fill another layer (add_layer).`);
5467
+ if (_optionalChain([this, 'access', _277 => _277.doc, 'access', _278 => _278.liveStrokes, 'optionalAccess', _279 => _279[fillTarget.id]])) throw new PaintEditorError(`Layer "${fillTarget.name}" is a stroke layer (its pixels are drawn from its strokes); fill another layer (add_layer), or rasterize it first (rasterize_stroke_layer).`);
5419
5468
  this.dryLayersFirst([_nullishCoalesce(_nullishCoalesce(options.layerId, () => ( this.doc.activeLayerId)), () => ( ""))]);
5420
5469
  const l = this.paintTarget(options.layerId, "fill");
5421
5470
  const color = options.color === void 0 ? this.color : parseColor(options.color);
@@ -5448,7 +5497,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5448
5497
  offset: l.offset
5449
5498
  };
5450
5499
  const surface = this.applyCoverage(l, coverage, rect, apply);
5451
- const lit = _optionalChain([this, 'access', _264 => _264.doc, 'access', _265 => _265.light, 'optionalAccess', _266 => _266[l.id]]);
5500
+ const lit = _optionalChain([this, 'access', _280 => _280.doc, 'access', _281 => _281.light, 'optionalAccess', _282 => _282[l.id]]);
5452
5501
  const light = lit ? withLayerLight(this.doc.light, l.id, scaleLight(lit, 1 - opacity)) : void 0;
5453
5502
  this.commit("Fill layer", this.withPaintEvent(this.withWetEvents({ ...this.doc, layers: _chunkPVJMTLPJcjs.mapLayer.call(void 0, this.doc.layers, l.id, () => ({ ...l, surface })), ...light ? { light } : {} }), { kind: "fill", layerId: l.id, data: { color, opacity, grain: grainAmount, pressure, blend } }));
5454
5503
  return { layerId: l.id, bounds: rect };
@@ -5458,7 +5507,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5458
5507
  const tiles = new Map(base.tiles);
5459
5508
  for (const { tx, ty } of _chunk474IQG74cjs.tilesInRect.call(void 0, { x: rect.x - l.offset.x, y: rect.y - l.offset.y, width: rect.width, height: rect.height })) {
5460
5509
  const key = _chunk474IQG74cjs.tileKey.call(void 0, tx, ty);
5461
- const src = _nullishCoalesce(_optionalChain([base, 'access', _267 => _267.tiles, 'access', _268 => _268.get, 'call', _269 => _269(key), 'optionalAccess', _270 => _270.data]), () => ( new Uint8ClampedArray(_chunk474IQG74cjs.TILE * _chunk474IQG74cjs.TILE * 4)));
5510
+ const src = _nullishCoalesce(_optionalChain([base, 'access', _283 => _283.tiles, 'access', _284 => _284.get, 'call', _285 => _285(key), 'optionalAccess', _286 => _286.data]), () => ( new Uint8ClampedArray(_chunk474IQG74cjs.TILE * _chunk474IQG74cjs.TILE * 4)));
5462
5511
  const tile = _chunk474IQG74cjs.finishTile.call(void 0, _chunkNIBFKXMDcjs.applyStrokeToTile.call(void 0, coverage, src, 4, tx, ty, apply), 4, 0);
5463
5512
  if (tile) tiles.set(key, tile);
5464
5513
  else tiles.delete(key);
@@ -5481,6 +5530,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5481
5530
  /** The provider's description of an effect, checked for `place` (rejects without a provider or for an unknown id). */
5482
5531
  async describeEffect(effect, place) {
5483
5532
  const d = await this.effectsRenderer.describe(this.effects.require(), effect);
5533
+ const pcs = _chunkL2JTLW6Bcjs.pathControlsOf.call(void 0, d);
5534
+ if (pcs.length) this.effectPathControls.set(d.id, pcs[0]);
5484
5535
  if (place) checkPaintEffectPlace(d, place);
5485
5536
  return d;
5486
5537
  }
@@ -5491,7 +5542,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5491
5542
  }
5492
5543
  /** The effect a layer is drawn from, or `undefined` for other layers. */
5493
5544
  getEffectLayer(layerId) {
5494
- return _chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, layerId) ? _optionalChain([this, 'access', _271 => _271.doc, 'access', _272 => _272.effectLayers, 'optionalAccess', _273 => _273[layerId]]) : void 0;
5545
+ return _chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, layerId) ? _optionalChain([this, 'access', _287 => _287.doc, 'access', _288 => _288.effectLayers, 'optionalAccess', _289 => _289[layerId]]) : void 0;
5495
5546
  }
5496
5547
  /** The effect paper (without its pixels), or `null`. */
5497
5548
  getPaperEffect() {
@@ -5528,8 +5579,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5528
5579
  /** A pixel layer that takes effect pixels: unlocked, visible, no sticker layer, no wet paint. */
5529
5580
  effectTarget(layerId, what) {
5530
5581
  const l = this.paintTarget(layerId, what);
5531
- if (_optionalChain([this, 'access', _274 => _274.doc, 'access', _275 => _275.stickers, 'optionalAccess', _276 => _276[l.id], 'optionalAccess', _277 => _277.length])) throw new PaintEditorError(`Layer "${l.name}" is a sticker layer; ${what} another layer (add_layer).`);
5532
- if (_optionalChain([this, 'access', _278 => _278.doc, 'access', _279 => _279.liveStrokes, 'optionalAccess', _280 => _280[l.id]])) throw new PaintEditorError(`Layer "${l.name}" is a stroke layer (its pixels are drawn from its strokes); ${what} another layer (add_layer), or rasterize it first (rasterize_stroke_layer).`);
5582
+ if (_optionalChain([this, 'access', _290 => _290.doc, 'access', _291 => _291.stickers, 'optionalAccess', _292 => _292[l.id], 'optionalAccess', _293 => _293.length])) throw new PaintEditorError(`Layer "${l.name}" is a sticker layer; ${what} another layer (add_layer).`);
5583
+ if (_optionalChain([this, 'access', _294 => _294.doc, 'access', _295 => _295.liveStrokes, 'optionalAccess', _296 => _296[l.id]])) throw new PaintEditorError(`Layer "${l.name}" is a stroke layer (its pixels are drawn from its strokes); ${what} another layer (add_layer), or rasterize it first (rasterize_stroke_layer).`);
5533
5584
  if (this.wet.wetLayerIds().includes(l.id)) throw new PaintEditorError(`Layer "${l.name}" holds wet paint; effects go on dried paint, so dry it first (dry_paint) and try again.`);
5534
5585
  return l;
5535
5586
  }
@@ -5568,8 +5619,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5568
5619
  const was = this.doc.paperEffect;
5569
5620
  const paperEffect = {
5570
5621
  ...this.sourceOf(d, values, options.time),
5571
- opacity: _nullishCoalesce(_nullishCoalesce(options.opacity, () => ( _optionalChain([was, 'optionalAccess', _281 => _281.opacity]))), () => ( 1)),
5572
- blend: _nullishCoalesce(_nullishCoalesce(options.blend, () => ( _optionalChain([was, 'optionalAccess', _282 => _282.blend]))), () => ( "multiply")),
5622
+ opacity: _nullishCoalesce(_nullishCoalesce(options.opacity, () => ( _optionalChain([was, 'optionalAccess', _297 => _297.opacity]))), () => ( 1)),
5623
+ blend: _nullishCoalesce(_nullishCoalesce(options.blend, () => ( _optionalChain([was, 'optionalAccess', _298 => _298.blend]))), () => ( "multiply")),
5573
5624
  image: { width: pixels.width, height: pixels.height, data: new Uint8ClampedArray(pixels.data) },
5574
5625
  version: nextPaperEffectVersion()
5575
5626
  };
@@ -5622,8 +5673,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5622
5673
  const above = _nullishCoalesce(options.aboveId, () => ( this.doc.activeLayerId));
5623
5674
  const loc = above ? _chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, above) : null;
5624
5675
  if (options.aboveId !== void 0 && !loc) throw new PaintEditorError(`Layer "${options.aboveId}" was removed while the effect rendered.`);
5625
- const layer = { ...createPaintLayer(_optionalChain([options, 'access', _283 => _283.name, 'optionalAccess', _284 => _284.trim, 'call', _285 => _285()]) || d.name), surface: _chunk474IQG74cjs.surfaceFromPixels.call(void 0, pixels, 4), opacity: _nullishCoalesce(options.opacity, () => ( 1)), blend: _nullishCoalesce(options.blend, () => ( "normal")) };
5626
- const layers = _chunkPVJMTLPJcjs.insertLayer.call(void 0, this.doc.layers, layer, _nullishCoalesce(_optionalChain([loc, 'optionalAccess', _286 => _286.parent, 'optionalAccess', _287 => _287.id]), () => ( null)), loc ? loc.index + 1 : void 0);
5676
+ const layer = { ...createPaintLayer(_optionalChain([options, 'access', _299 => _299.name, 'optionalAccess', _300 => _300.trim, 'call', _301 => _301()]) || d.name), surface: _chunk474IQG74cjs.surfaceFromPixels.call(void 0, pixels, 4), opacity: _nullishCoalesce(options.opacity, () => ( 1)), blend: _nullishCoalesce(options.blend, () => ( "normal")) };
5677
+ const layers = _chunkPVJMTLPJcjs.insertLayer.call(void 0, this.doc.layers, layer, _nullishCoalesce(_optionalChain([loc, 'optionalAccess', _302 => _302.parent, 'optionalAccess', _303 => _303.id]), () => ( null)), loc ? loc.index + 1 : void 0);
5627
5678
  const source = this.sourceOf(d, values, options.time);
5628
5679
  this.commit("Add effect layer", { ...this.doc, layers, activeLayerId: layer.id, effectLayers: { ..._nullishCoalesce(this.doc.effectLayers, () => ( {})), [layer.id]: source } });
5629
5680
  return { layer: this.describeLayer(layer), source };
@@ -5681,7 +5732,11 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5681
5732
  return { layerId: now.id, source: this.sourceOf(d, values, options.time) };
5682
5733
  }
5683
5734
  // --- Effect paint ----------------------------------------------------------------
5684
- /** At most this many rendered effect paints are kept (each is canvas-sized). */
5735
+ /**
5736
+ * At most this many rendered effect paints are kept (each is canvas-sized), more only while
5737
+ * something needs them all: a replay's batch, and the path-mapped strokes on stroke layers,
5738
+ * which each have a render of their own and are redrawn synchronously.
5739
+ */
5685
5740
  static __initStatic() {this.EFFECT_PAINT_CACHE = 6}
5686
5741
  /** The effect paint strokes use (or the one rendering), or `null`. */
5687
5742
  getEffectPaint() {
@@ -5693,15 +5748,17 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5693
5748
  * size, and brushes then take each pixel's colour (and alpha) from it, fixed to the canvas, as if
5694
5749
  * painting a hidden picture into view. `setColor` and `setPaint` go back to colour. Editor state,
5695
5750
  * not an undo step. Strokes that would paint with it throw while it renders. Returns the paint.
5696
- * With `map: { by: 'stroke' }` the effect lies along each stroke instead of the canvas; with
5697
- * `live`, strokes on a stroke layer keep playing it (see `setEffectPlayback`).
5751
+ * With `map: { by: 'stroke' }` the effect lies along each stroke as a strip; with
5752
+ * `map: { by: 'path' }` an effect with a path control (`format: 'svg-path'`) draws itself along
5753
+ * each stroke's centreline in canvas pixels; with `live`, strokes on a stroke layer keep playing
5754
+ * it (see `setEffectPlayback`).
5698
5755
  */
5699
5756
  async setEffectPaint(source) {
5700
5757
  if (!source || typeof source.effect !== "string" || !source.effect) throw new PaintEditorError("effect is missing; pass an effect id from search_effects (use generator, overlay or title).");
5701
5758
  this.checkTime(source.time);
5702
5759
  let map;
5703
5760
  try {
5704
- map = _chunk56RHCIJVcjs.readEffectStrokeMap.call(void 0, source.map);
5761
+ map = _chunkSNAFFCAXcjs.readEffectStrokeMap.call(void 0, source.map);
5705
5762
  } catch (e) {
5706
5763
  throw new PaintEditorError(e.message);
5707
5764
  }
@@ -5709,6 +5766,9 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5709
5766
  const epoch = ++this.paintEpoch;
5710
5767
  const changed = (name) => new PaintEditorError(`The paint changed while "${name}" rendered (set_color, set_paint or another set_effect_paint); call set_effect_paint again to paint with it.`);
5711
5768
  const d = await this.describeEffect(source.effect, "paint");
5769
+ if (_optionalChain([map, 'optionalAccess', _304 => _304.by]) === "path" && !_chunkL2JTLW6Bcjs.pathControlsOf.call(void 0, d).length) {
5770
+ throw new PaintEditorError(`Effect "${d.id}" has no path control (format "svg-path"); use by: "stroke" (bent along each stroke) or by: "canvas" (fixed to the canvas).`);
5771
+ }
5712
5772
  const values = this.effectValues(d, { ...d.defaults }, source.values);
5713
5773
  if (epoch !== this.paintEpoch) throw changed(d.name);
5714
5774
  const paint = { type: "effect", effect: d.id, provider: this.effects.require().id, values, time: _nullishCoalesce(source.time, () => ( 0)), ...map ? { map } : {}, ...source.live ? { live: true } : {} };
@@ -5732,51 +5792,158 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5732
5792
  }
5733
5793
  /** The rendered pixels of an effect paint at the current canvas size, or `null` when it has not been rendered. */
5734
5794
  effectPaintImage(p) {
5735
- const key = _chunk56RHCIJVcjs.effectPaintKey.call(void 0, p);
5795
+ const key = _chunkSNAFFCAXcjs.effectPaintKey.call(void 0, p);
5736
5796
  const img = this.effectPaintPixels.get(key);
5737
- const size = _chunk56RHCIJVcjs.effectPaintSize.call(void 0, p, this.doc.canvas);
5797
+ const size = _chunkSNAFFCAXcjs.effectPaintSize.call(void 0, p, this.doc.canvas);
5738
5798
  if (!img || img.width !== size.width || img.height !== size.height) return null;
5739
5799
  this.effectPaintPixels.delete(key);
5740
5800
  this.effectPaintPixels.set(key, img);
5741
5801
  return img;
5742
5802
  }
5803
+ cacheEffectPaintPixels(p, pixels) {
5804
+ return this.cacheEffectPaintImage(p, toEffectPaintPixels(p, pixels));
5805
+ }
5806
+ cacheEffectPaintImage(p, img) {
5807
+ this.effectPaintPixels.set(_chunkSNAFFCAXcjs.effectPaintKey.call(void 0, p), img);
5808
+ this.trimEffectPaints();
5809
+ return img;
5810
+ }
5811
+ trimEffectPaints() {
5812
+ let live = 0;
5813
+ for (const list of Object.values(_nullishCoalesce(this.doc.liveStrokes, () => ( {})))) for (const s of list) if (_optionalChain([s, 'access', _305 => _305.paint, 'optionalAccess', _306 => _306.type]) === "effect" && _optionalChain([s, 'access', _307 => _307.paint, 'access', _308 => _308.map, 'optionalAccess', _309 => _309.by]) === "path") live++;
5814
+ const limit = Math.max(_PaintEditorController.EFFECT_PAINT_CACHE, this.effectPaintBatch, live + 1);
5815
+ while (this.effectPaintPixels.size > limit) this.effectPaintPixels.delete(this.effectPaintPixels.keys().next().value);
5816
+ }
5817
+ /** Renders an effect paint on the caller's stack when its renderer is warm and has `renderSync`; otherwise `null`. */
5818
+ renderEffectPaintSync(p) {
5819
+ const have = this.effectPaintImage(p);
5820
+ if (have) return have;
5821
+ const provider = this.effects.provider;
5822
+ if (!provider || p.provider && provider.id !== p.provider) return null;
5823
+ const size = _chunkSNAFFCAXcjs.effectPaintSize.call(void 0, p, this.doc.canvas);
5824
+ const pixels = this.effectsRenderer.renderSync(provider, p.effect, size, { time: p.time, values: p.values });
5825
+ return pixels ? this.cacheEffectPaintPixels(p, pixels) : null;
5826
+ }
5743
5827
  /** Renders an effect paint at the canvas size into the cache (nothing when it is there already). */
5744
5828
  async renderEffectPaint(p) {
5745
5829
  const have = this.effectPaintImage(p);
5746
5830
  if (have) return have;
5831
+ return this.cacheEffectPaintImage(p, await this.renderEffectPaintPixels(p));
5832
+ }
5833
+ /** Renders an effect paint at the canvas size without keeping it. */
5834
+ async renderEffectPaintPixels(p) {
5747
5835
  const provider = this.effects.provider;
5748
5836
  const what = `the effect "${p.effect}"${p.provider ? ` from provider "${p.provider}"` : ""}`;
5749
5837
  if (!provider) throw new PaintEditorError(`Effect paint needs ${what}, but no effects provider is registered; register it (setEffectsProvider) and try again.`);
5750
5838
  if (p.provider && provider.id !== p.provider) throw new PaintEditorError(`Effect paint needs ${what}, but the registered provider is "${provider.id}"; register "${p.provider}" (setEffectsProvider) and try again.`);
5751
- const { width, height } = _chunk56RHCIJVcjs.effectPaintSize.call(void 0, p, this.doc.canvas);
5839
+ const { width, height } = _chunkSNAFFCAXcjs.effectPaintSize.call(void 0, p, this.doc.canvas);
5752
5840
  let pixels;
5753
5841
  try {
5754
5842
  pixels = await this.effectsRenderer.render(provider, p.effect, { width, height }, { time: p.time, values: p.values });
5755
5843
  } catch (e) {
5756
5844
  throw new PaintEditorError(`Effect paint could not render ${what}: ${e instanceof Error ? e.message : String(e)}`);
5757
5845
  }
5758
- const img = { width, height, data: new Uint8ClampedArray(pixels.data), ...p.map ? { map: p.map } : {} };
5759
- this.effectPaintPixels.set(_chunk56RHCIJVcjs.effectPaintKey.call(void 0, p), img);
5760
- while (this.effectPaintPixels.size > _PaintEditorController.EFFECT_PAINT_CACHE) this.effectPaintPixels.delete(this.effectPaintPixels.keys().next().value);
5761
- return img;
5846
+ return toEffectPaintPixels(p, pixels);
5762
5847
  }
5763
5848
  /**
5764
5849
  * Renders effect paints that are not rendered yet (strokes and replays need them rendered
5765
5850
  * first, since strokes are synchronous). Throws naming the effect and provider when one cannot be.
5766
5851
  */
5767
5852
  async prepareEffectPaints(paints2) {
5853
+ const list = [...paints2];
5854
+ this.effectPaintBatch = new Set(list.map(_chunkSNAFFCAXcjs.effectPaintKey)).size;
5768
5855
  const seen = /* @__PURE__ */ new Set();
5769
- for (const p of paints2) {
5770
- const key = _chunk56RHCIJVcjs.effectPaintKey.call(void 0, p);
5856
+ for (const p of list) {
5857
+ const key = _chunkSNAFFCAXcjs.effectPaintKey.call(void 0, p);
5771
5858
  if (seen.has(key)) continue;
5772
5859
  seen.add(key);
5773
5860
  await this.renderEffectPaint(p);
5774
5861
  }
5775
5862
  }
5863
+ /**
5864
+ * Renders the path-mapped effect paint for one or more strokes' points before a synchronous
5865
+ * stroke call runs (`paint_stroke` and `stroke_path` do; `paintStroke` throws without it on a
5866
+ * provider that can't render synchronously). For a stroke layer edit, see `prepareStrokeEdit`.
5867
+ */
5868
+ async prepareStrokePathEffect(init, pointsList) {
5869
+ const brush = this.strokeBrush(init);
5870
+ if (!_chunkGHGBIAWQcjs.brushTakesPaint.call(void 0, brush)) return;
5871
+ let source = null;
5872
+ if (init.paint !== void 0) {
5873
+ if (!_chunkSNAFFCAXcjs.isPaintEffectPaint.call(void 0, init.paint)) return;
5874
+ source = _chunkSNAFFCAXcjs.readPaintEffectPaint.call(void 0, init.paint);
5875
+ } else if (init.color === void 0 && !brush.paint && !this.effectPaintPending) {
5876
+ source = this.effectPaint;
5877
+ }
5878
+ if (!source || _optionalChain([source, 'access', _310 => _310.map, 'optionalAccess', _311 => _311.by]) !== "path") return;
5879
+ if (!this.effectPathControls.has(source.effect)) await this.describeEffect(source.effect);
5880
+ const control = this.effectPathControls.get(source.effect);
5881
+ const paints2 = pointsList.filter((pts) => pts.length > 0).map((pts) => _chunkSNAFFCAXcjs.withStrokePath.call(void 0, source, pts, control));
5882
+ if (paints2.length) await this.prepareEffectPaints(paints2);
5883
+ }
5884
+ /**
5885
+ * Renders what an edit of a stroke layer's stroke paints with (`updateStroke`, `editStrokePoints`):
5886
+ * a new effect paint, or a path-mapped stroke's new path. Those calls are synchronous, and throw
5887
+ * without it on a provider that can't render synchronously. Bad edits are left for them to refuse.
5888
+ */
5889
+ async prepareStrokeEdit(id, edit) {
5890
+ const p = this.strokeEditPaint(id, edit);
5891
+ if (!p) return;
5892
+ if (_optionalChain([p, 'access', _312 => _312.map, 'optionalAccess', _313 => _313.by]) === "path" && !this.effectPathControls.has(p.effect)) await this.describeEffect(p.effect);
5893
+ await this.prepareEffectPaints([_nullishCoalesce(this.strokeEditPaint(id, edit), () => ( p))]);
5894
+ }
5895
+ /** Whether `prepareStrokeEdit` has to be awaited before this edit can run. */
5896
+ strokeEditNeedsRender(id, edit) {
5897
+ const p = this.strokeEditPaint(id, edit);
5898
+ return Boolean(p && !this.effectPaintImage(p) && !this.renderEffectPaintSync(p));
5899
+ }
5900
+ strokeEditPaint(id, edit) {
5901
+ const was = Object.values(_nullishCoalesce(this.doc.liveStrokes, () => ( {}))).flat().find((s) => s.id === id);
5902
+ if (!was) return null;
5903
+ try {
5904
+ if (edit.paint !== void 0) {
5905
+ if (!_chunkSNAFFCAXcjs.isPaintEffectPaint.call(void 0, edit.paint)) return null;
5906
+ const p = _chunkSNAFFCAXcjs.readPaintEffectPaint.call(void 0, edit.paint);
5907
+ return p && _chunkSNAFFCAXcjs.withStrokePath.call(void 0, p, was.points, this.effectPathControls.get(p.effect));
5908
+ }
5909
+ if (_optionalChain([was, 'access', _314 => _314.paint, 'optionalAccess', _315 => _315.type]) !== "effect" || _optionalChain([was, 'access', _316 => _316.paint, 'access', _317 => _317.map, 'optionalAccess', _318 => _318.by]) !== "path") return null;
5910
+ if (edit.points !== void 0) return _chunkSNAFFCAXcjs.withStrokePath.call(void 0, was.paint, this.checkPoints(edit.points), this.effectPathControls.get(was.paint.effect));
5911
+ if (!edit.transform) return null;
5912
+ const varied = varyStroke(was, this.strokeTransform(was, edit.transform), {}).paint;
5913
+ return _optionalChain([varied, 'optionalAccess', _319 => _319.type]) === "effect" ? varied : null;
5914
+ } catch (e9) {
5915
+ return null;
5916
+ }
5917
+ }
5918
+ /** A stroke edit's transform as an affine map, checked. */
5919
+ strokeTransform(stroke, t) {
5920
+ if (t.scale !== void 0 && !(t.scale > 0 && t.scale <= 20)) throw new PaintEditorError(`scale ${t.scale} is out of range; use above 0 up to 20.`);
5921
+ for (const k of ["dx", "dy", "rotate"]) if (t[k] !== void 0 && !Number.isFinite(t[k])) throw new PaintEditorError(`${k} must be a number.`);
5922
+ const b = strokeBounds(stroke.points);
5923
+ return variationAffine(t, _nullishCoalesce(t.origin, () => ( { x: b.x + b.width / 2, y: b.y + b.height / 2 })));
5924
+ }
5776
5925
  /** Renders the effect paints of recorded strokes (default all of them) before a replay. */
5777
- async prepareStrokeEffects(strokeIds) {
5926
+ async prepareStrokeEffects(strokeIds, variation) {
5778
5927
  const ids = strokeIds ? new Set(strokeIds) : null;
5779
- const paints2 = this.doc.strokes.filter((s) => (!ids || ids.has(s.id)) && _optionalChain([s, 'access', _288 => _288.paint, 'optionalAccess', _289 => _289.type]) === "effect").map((s) => s.paint);
5928
+ const strokes = this.doc.strokes.filter((s) => (!ids || ids.has(s.id)) && _optionalChain([s, 'access', _320 => _320.paint, 'optionalAccess', _321 => _321.type]) === "effect");
5929
+ const paints2 = strokes.map((s) => s.paint);
5930
+ if (variation && strokes.length) {
5931
+ const repeat = Math.max(1, Math.min(100, _nullishCoalesce(variation.repeat, () => ( 1))));
5932
+ let origin = variation.origin;
5933
+ if (!origin) {
5934
+ const b = strokeBounds(strokes.flatMap((s) => s.points));
5935
+ origin = { x: b.x + b.width / 2, y: b.y + b.height / 2 };
5936
+ }
5937
+ const step = variationAffine(variation, origin);
5938
+ let m = IDENTITY_AFFINE;
5939
+ for (let k = 0; k < repeat; k++) {
5940
+ m = [step[0] * m[0] + step[1] * m[2], step[0] * m[1] + step[1] * m[3], step[2] * m[0] + step[3] * m[2], step[2] * m[1] + step[3] * m[3], step[0] * m[4] + step[1] * m[5] + step[4], step[2] * m[4] + step[3] * m[5] + step[5]];
5941
+ for (const s of strokes) {
5942
+ const v = varyStroke(s, m, variation);
5943
+ if (_optionalChain([v, 'access', _322 => _322.paint, 'optionalAccess', _323 => _323.type]) === "effect") paints2.push(v.paint);
5944
+ }
5945
+ }
5946
+ }
5780
5947
  await this.prepareEffectPaints(paints2);
5781
5948
  }
5782
5949
  /** A small preview of the effect paint (a PNG data URL `size` px wide), or `null` without a rendered one. */
@@ -5804,20 +5971,22 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5804
5971
  * Throws while the editor's is still rendering, for an engine that cannot paint with it, or when
5805
5972
  * its pixels are not rendered.
5806
5973
  */
5807
- strokeEffect(init, brush) {
5808
- if (!_chunkEU2ZZA6Lcjs.brushTakesPaint.call(void 0, brush)) return null;
5974
+ strokeEffect(init, brush, points) {
5975
+ if (!_chunkGHGBIAWQcjs.brushTakesPaint.call(void 0, brush)) return null;
5809
5976
  let source = null;
5810
5977
  if (init.paint !== void 0) {
5811
- if (!_chunk56RHCIJVcjs.isPaintEffectPaint.call(void 0, init.paint)) return null;
5812
- source = _chunk56RHCIJVcjs.readPaintEffectPaint.call(void 0, init.paint);
5978
+ if (!_chunkSNAFFCAXcjs.isPaintEffectPaint.call(void 0, init.paint)) return null;
5979
+ source = _chunkSNAFFCAXcjs.readPaintEffectPaint.call(void 0, init.paint);
5813
5980
  if (!source) throw new PaintEditorError("The stroke's effect paint needs an effect id and values (getEffectPaint returns one).");
5814
5981
  } else if (init.color === void 0 && !brush.paint) {
5815
5982
  if (this.effectPaintPending) throw new PaintEditorError(`The effect paint "${this.effectPaintPending.effect}" is still rendering; wait for set_effect_paint to finish, then paint.`);
5816
5983
  source = this.effectPaint;
5817
5984
  }
5818
5985
  if (!source) return null;
5819
- const pixels = this.effectPaintImage(source);
5820
- if (!pixels) throw new PaintEditorError(`The effect paint "${source.effect}"${source.provider ? ` from provider "${source.provider}"` : ""} is not rendered at this canvas size; call set_effect_paint (or prepareEffectPaints) first.`);
5986
+ const path = _optionalChain([source, 'access', _324 => _324.map, 'optionalAccess', _325 => _325.by]) === "path";
5987
+ if (path && _optionalChain([points, 'optionalAccess', _326 => _326.length])) source = _chunkSNAFFCAXcjs.withStrokePath.call(void 0, source, points, this.effectPathControls.get(source.effect));
5988
+ const pixels = _nullishCoalesce(this.effectPaintImage(source), () => ( (path ? this.renderEffectPaintSync(source) : null)));
5989
+ if (!pixels) throw new PaintEditorError(`The effect paint "${source.effect}"${source.provider ? ` from provider "${source.provider}"` : ""} is not rendered at this canvas size; call ${path ? "prepareStrokePathEffect (the paint_stroke tool does this) or prepareStrokeEdit" : "set_effect_paint (or prepareEffectPaints)"} first.`);
5821
5990
  return { source, pixels };
5822
5991
  }
5823
5992
  /**
@@ -5839,14 +6008,14 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5839
6008
  const before = _chunk474IQG74cjs.readRegion.call(void 0, l.surface, rect);
5840
6009
  const inputs = { source: { width: rect.width, height: rect.height, data: before } };
5841
6010
  const heightInput = d.inputs.find((i) => i.kind === "image" && /^(height|depth|relief)$/i.test(i.name));
5842
- const relief = _optionalChain([this, 'access', _290 => _290.doc, 'access', _291 => _291.thick, 'optionalAccess', _292 => _292[l.id]]);
6011
+ const relief = _optionalChain([this, 'access', _327 => _327.doc, 'access', _328 => _328.thick, 'optionalAccess', _329 => _329[l.id]]);
5843
6012
  if (heightInput && relief) {
5844
6013
  const h = _chunk474IQG74cjs.readRegion.call(void 0, relief.height, rect);
5845
6014
  const rgba = new Uint8ClampedArray(rect.width * rect.height * 4);
5846
6015
  for (let i = 0; i < h.length; i++) rgba.set([h[i], h[i], h[i], 255], i * 4);
5847
6016
  inputs[heightInput.name] = { width: rect.width, height: rect.height, data: rgba };
5848
6017
  }
5849
- const sourceInput = _nullishCoalesce(_optionalChain([d, 'access', _293 => _293.inputs, 'access', _294 => _294.find, 'call', _295 => _295((i) => i.kind === "image" && i.name !== _optionalChain([heightInput, 'optionalAccess', _296 => _296.name])), 'optionalAccess', _297 => _297.name]), () => ( "source"));
6018
+ const sourceInput = _nullishCoalesce(_optionalChain([d, 'access', _330 => _330.inputs, 'access', _331 => _331.find, 'call', _332 => _332((i) => i.kind === "image" && i.name !== _optionalChain([heightInput, 'optionalAccess', _333 => _333.name])), 'optionalAccess', _334 => _334.name]), () => ( "source"));
5850
6019
  if (sourceInput !== "source") {
5851
6020
  inputs[sourceInput] = inputs.source;
5852
6021
  delete inputs.source;
@@ -5862,11 +6031,11 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5862
6031
  return this.brushEntries.find((e) => e.brush.id === id);
5863
6032
  }
5864
6033
  findBrush(id) {
5865
- return _optionalChain([this, 'access', _298 => _298.findEntry, 'call', _299 => _299(id), 'optionalAccess', _300 => _300.brush]);
6034
+ return _optionalChain([this, 'access', _335 => _335.findEntry, 'call', _336 => _336(id), 'optionalAccess', _337 => _337.brush]);
5866
6035
  }
5867
6036
  requireEntry(id) {
5868
6037
  const e = this.findEntry(id);
5869
- if (!e) throw new PaintEditorError(`Unknown brush "${id}". ${_chunkEU2ZZA6Lcjs.closest.call(void 0, id, this.brushEntries.map((x) => x.brush.id))}Call list_brush_presets for the ids.`);
6038
+ if (!e) throw new PaintEditorError(`Unknown brush "${id}". ${_chunkGHGBIAWQcjs.closest.call(void 0, id, this.brushEntries.map((x) => x.brush.id))}Call list_brush_presets for the ids.`);
5870
6039
  return e;
5871
6040
  }
5872
6041
  requireBrush(id) {
@@ -5895,11 +6064,11 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5895
6064
  /** A library brush by id, as the engine paints it (`undefined` when unknown). */
5896
6065
  getBrush(id) {
5897
6066
  const b = this.findBrush(id);
5898
- return b ? _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, b, b) : void 0;
6067
+ return b ? _chunkGHGBIAWQcjs.normalizePaintBrush.call(void 0, b, b) : void 0;
5899
6068
  }
5900
6069
  /** A library brush by id as stored (its facets), or without an id the active brush as edited. */
5901
6070
  getBrushSpec(id) {
5902
- const spec = id === void 0 ? this.brushSpec : _optionalChain([this, 'access', _301 => _301.findEntry, 'call', _302 => _302(id), 'optionalAccess', _303 => _303.spec]);
6071
+ const spec = id === void 0 ? this.brushSpec : _optionalChain([this, 'access', _338 => _338.findEntry, 'call', _339 => _339(id), 'optionalAccess', _340 => _340.spec]);
5903
6072
  return spec ? copyJSON(spec) : void 0;
5904
6073
  }
5905
6074
  /**
@@ -5913,7 +6082,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5913
6082
  const baseSpec = entry ? entry.spec : this.brushSpec;
5914
6083
  if (changes.paint !== void 0 && changes.paint !== null) this.readStrokePaint(changes.paint);
5915
6084
  const unchanged = !Object.keys(changes).length;
5916
- const next = _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, { ...changes, id: base.id }, base);
6085
+ const next = _chunkGHGBIAWQcjs.normalizePaintBrush.call(void 0, { ...changes, id: base.id }, base);
5917
6086
  if (entry) this.takeBrushColour(entry.spec);
5918
6087
  this.useBrush(next, unchanged ? baseSpec : brushSpecOf(next, baseSpec), unchanged && base.builtin === true);
5919
6088
  return this.brush;
@@ -5931,8 +6100,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5931
6100
  const base = copyJSON(entry ? entry.spec : this.brushSpec);
5932
6101
  for (const k of unset) delete base[k];
5933
6102
  const spec = this.readBrushPatch(base, patch, problems);
5934
- if (entry || _optionalChain([patch, 'access', _304 => _304.colour, 'optionalAccess', _305 => _305.default]) !== void 0) this.takeBrushColour(spec);
5935
- this.useBrush(unchanged && entry ? entry.brush : _chunkEU2ZZA6Lcjs.resolveBrush.call(void 0, spec), spec, unchanged && _optionalChain([entry, 'optionalAccess', _306 => _306.builtin]) === true);
6103
+ if (entry || _optionalChain([patch, 'access', _341 => _341.colour, 'optionalAccess', _342 => _342.default]) !== void 0) this.takeBrushColour(spec);
6104
+ this.useBrush(unchanged && entry ? entry.brush : _chunkGHGBIAWQcjs.resolveBrush.call(void 0, spec), spec, unchanged && _optionalChain([entry, 'optionalAccess', _343 => _343.builtin]) === true);
5936
6105
  return { brush: this.brush, spec: copyJSON(this.brushSpec), problems };
5937
6106
  }
5938
6107
  /**
@@ -5942,15 +6111,15 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5942
6111
  */
5943
6112
  setBrushSpec(spec) {
5944
6113
  const problems = [];
5945
- const paint = _optionalChain([spec, 'access', _307 => _307.colour, 'optionalAccess', _308 => _308.default]);
6114
+ const paint = _optionalChain([spec, 'access', _344 => _344.colour, 'optionalAccess', _345 => _345.default]);
5946
6115
  if (paint && typeof paint === "object" && "type" in paint && paint.type === "gradient") this.readStrokePaint(paint);
5947
6116
  let next;
5948
6117
  try {
5949
- next = _chunkEU2ZZA6Lcjs.normalizeBrushSpec.call(void 0, { ...spec, id: this.brush.id }, problems);
6118
+ next = _chunkGHGBIAWQcjs.normalizeBrushSpec.call(void 0, { ...spec, id: this.brush.id }, problems);
5950
6119
  } catch (e) {
5951
6120
  throw new PaintEditorError(e.message);
5952
6121
  }
5953
- this.useBrush(_chunkEU2ZZA6Lcjs.resolveBrush.call(void 0, next), next, false);
6122
+ this.useBrush(_chunkGHGBIAWQcjs.resolveBrush.call(void 0, next), next, false);
5954
6123
  return { brush: this.brush, spec: copyJSON(this.brushSpec), problems };
5955
6124
  }
5956
6125
  /**
@@ -5959,29 +6128,29 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5959
6128
  */
5960
6129
  brushChanges(patch, from) {
5961
6130
  const entry = typeof from === "string" ? this.requireEntry(from) : null;
5962
- const base = entry ? entry.brush : typeof from === "object" ? _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, from, from) : this.brush;
5963
- const spec = entry ? entry.spec : typeof from === "object" ? _chunkEU2ZZA6Lcjs.migrateBrushV1.call(void 0, base) : this.brushSpec;
5964
- return engineChanges(base, _chunkEU2ZZA6Lcjs.resolveBrush.call(void 0, this.readBrushPatch(spec, patch, [])));
6131
+ const base = entry ? entry.brush : typeof from === "object" ? _chunkGHGBIAWQcjs.normalizePaintBrush.call(void 0, from, from) : this.brush;
6132
+ const spec = entry ? entry.spec : typeof from === "object" ? _chunkGHGBIAWQcjs.migrateBrushV1.call(void 0, base) : this.brushSpec;
6133
+ return engineChanges(base, _chunkGHGBIAWQcjs.resolveBrush.call(void 0, this.readBrushPatch(spec, patch, [])));
5965
6134
  }
5966
6135
  readBrushPatch(base, patch, problems) {
5967
6136
  const { id: _id, name, ...rest } = patch;
5968
- const paint = _optionalChain([rest, 'access', _309 => _309.colour, 'optionalAccess', _310 => _310.default]);
6137
+ const paint = _optionalChain([rest, 'access', _346 => _346.colour, 'optionalAccess', _347 => _347.default]);
5969
6138
  if (paint && typeof paint === "object" && "type" in paint && paint.type === "gradient") this.readStrokePaint(paint);
5970
6139
  try {
5971
- return _chunkEU2ZZA6Lcjs.normalizeBrushSpec.call(void 0, _chunk3KNQ2W6Xcjs.mergeBrushPatch.call(void 0, base, { ...rest, ...name !== void 0 ? { name } : {} }), problems);
6140
+ return _chunkGHGBIAWQcjs.normalizeBrushSpec.call(void 0, _chunk3JKCREEUcjs.mergeBrushPatch.call(void 0, base, { ...rest, ...name !== void 0 ? { name } : {} }), problems);
5972
6141
  } catch (e) {
5973
6142
  throw new PaintEditorError(e.message);
5974
6143
  }
5975
6144
  }
5976
6145
  useBrush(next, spec, builtin) {
5977
- next = _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, next, next);
6146
+ next = _chunkGHGBIAWQcjs.normalizePaintBrush.call(void 0, next, next);
5978
6147
  if (builtin) next.builtin = true;
5979
6148
  else delete next.builtin;
5980
6149
  this.brush = next;
5981
6150
  this.brushSpec = { ...copyJSON(spec), id: next.id, name: next.name };
5982
6151
  this.pendingBrushId = null;
5983
6152
  this.emit([]);
5984
- const refs = _chunk56RHCIJVcjs.brushStickerRefs.call(void 0, next);
6153
+ const refs = _chunkSNAFFCAXcjs.brushStickerRefs.call(void 0, next);
5985
6154
  if (refs.length) void this.prepareStickers(refs).catch(() => this.emit([]));
5986
6155
  }
5987
6156
  /**
@@ -5990,9 +6159,9 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5990
6159
  * saved brush.
5991
6160
  */
5992
6161
  async saveBrush(options) {
5993
- if (!_chunkEU2ZZA6Lcjs.BRUSH_ID.test(options.id)) throw new PaintEditorError(`Brush id "${options.id}" is invalid; use lowercase letters, digits and dashes (e.g. "my-pencil").`);
6162
+ if (!_chunkGHGBIAWQcjs.BRUSH_ID.test(options.id)) throw new PaintEditorError(`Brush id "${options.id}" is invalid; use lowercase letters, digits and dashes (e.g. "my-pencil").`);
5994
6163
  if (this.brushLibrary.isBuiltin(options.id)) throw new PaintEditorError(`"${options.id}" is a built-in brush; save under another id.`);
5995
- const spec = options.brush ? brushSpecOf(_chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, options.brush, this.brush), this.brushSpec) : this.brushSpec;
6164
+ const spec = options.brush ? brushSpecOf(_chunkGHGBIAWQcjs.normalizePaintBrush.call(void 0, options.brush, this.brush), this.brushSpec) : this.brushSpec;
5996
6165
  const { brush } = await libraryCall(() => this.brushLibrary.save({ ...spec, id: options.id, name: _nullishCoalesce(options.name, () => ( spec.name)) }, { overwrite: true }));
5997
6166
  await this.refreshBrushes();
5998
6167
  return this.requireBrush(brush.id);
@@ -6005,7 +6174,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6005
6174
  }
6006
6175
  /** The user's saved brushes, as the engine paints them. */
6007
6176
  getUserBrushes() {
6008
- return this.brushEntries.filter((e) => !e.builtin).map((e) => _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, e.brush, e.brush));
6177
+ return this.brushEntries.filter((e) => !e.builtin).map((e) => _chunkGHGBIAWQcjs.normalizePaintBrush.call(void 0, e.brush, e.brush));
6009
6178
  }
6010
6179
  /** A brush library file (version 2) of the given brushes (default: the user's brushes). */
6011
6180
  exportBrushes(ids) {
@@ -6028,9 +6197,9 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6028
6197
  }
6029
6198
  // --- Colour --------------------------------------------------------------------
6030
6199
 
6031
- __init130() {this.colorLocked = false}
6200
+ __init134() {this.colorLocked = false}
6032
6201
  /** The brush default colour the paint colour came from (resolved again when the scheme changes), or `null`. */
6033
- __init131() {this.brushColour = null}
6202
+ __init135() {this.brushColour = null}
6034
6203
  /**
6035
6204
  * The host's colour scheme: a paint colour that came from a brush's light / dark default
6036
6205
  * resolves to the new side. Editor state, not an undo step.
@@ -6041,7 +6210,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6041
6210
  this.colorScheme = next;
6042
6211
  const hex2 = this.brushColour ? _chunkJBZRVLXVcjs.brushColourHex.call(void 0, this.brushColour, next) : null;
6043
6212
  if (hex2) this.color = hex2;
6044
- const refs = _chunk56RHCIJVcjs.brushStickerRefs.call(void 0, this.brush);
6213
+ const refs = _chunkSNAFFCAXcjs.brushStickerRefs.call(void 0, this.brush);
6045
6214
  if (refs.some((r) => !_chunkRDFHWAHLcjs.editorStampOf.call(void 0, r))) void this.prepareStickers(refs).catch(() => this.emit([]));
6046
6215
  this.emit([]);
6047
6216
  }
@@ -6058,7 +6227,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6058
6227
  */
6059
6228
  takeBrushColour(spec) {
6060
6229
  if (this.colorLocked) return;
6061
- const d = _optionalChain([spec, 'access', _311 => _311.colour, 'optionalAccess', _312 => _312.default]);
6230
+ const d = _optionalChain([spec, 'access', _348 => _348.colour, 'optionalAccess', _349 => _349.default]);
6062
6231
  const hex2 = d !== void 0 ? _chunkJBZRVLXVcjs.brushColourHex.call(void 0, d, this.colorScheme) : null;
6063
6232
  if (!hex2) return;
6064
6233
  this.color = hex2;
@@ -6069,8 +6238,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6069
6238
  }
6070
6239
  /** A brush that always paints its own colour (`colour.own`): that colour, resolved for the scheme now; else `null`. */
6071
6240
  ownColour(brushId) {
6072
- const spec = brushId !== void 0 ? _optionalChain([this, 'access', _313 => _313.findEntry, 'call', _314 => _314(brushId), 'optionalAccess', _315 => _315.spec]) : this.brushSpec;
6073
- const d = _optionalChain([spec, 'optionalAccess', _316 => _316.colour, 'optionalAccess', _317 => _317.own]) ? spec.colour.default : void 0;
6241
+ const spec = brushId !== void 0 ? _optionalChain([this, 'access', _350 => _350.findEntry, 'call', _351 => _351(brushId), 'optionalAccess', _352 => _352.spec]) : this.brushSpec;
6242
+ const d = _optionalChain([spec, 'optionalAccess', _353 => _353.colour, 'optionalAccess', _354 => _354.own]) ? spec.colour.default : void 0;
6074
6243
  return d !== void 0 ? _chunkJBZRVLXVcjs.brushColourHex.call(void 0, d, this.colorScheme) : null;
6075
6244
  }
6076
6245
  /** Sets the paint colour (and goes back to one colour from gradient paint). */
@@ -6113,10 +6282,10 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6113
6282
  * brush's gradient, else the editor's gradient paint. Erasers, blenders and smudges take none.
6114
6283
  */
6115
6284
  strokeGradient(init, brush, color) {
6116
- if (!_chunkEU2ZZA6Lcjs.brushTakesPaint.call(void 0, brush)) return null;
6285
+ if (!_chunkGHGBIAWQcjs.brushTakesPaint.call(void 0, brush)) return null;
6117
6286
  let g = null;
6118
6287
  if (init.paint !== void 0) {
6119
- if (_chunk56RHCIJVcjs.isPaintEffectPaint.call(void 0, init.paint)) return null;
6288
+ if (_chunkSNAFFCAXcjs.isPaintEffectPaint.call(void 0, init.paint)) return null;
6120
6289
  const p = this.readStrokePaint(init.paint);
6121
6290
  g = p.type === "gradient" ? p : null;
6122
6291
  } else g = _nullishCoalesce(brush.paint, () => ( (init.color === void 0 ? this.gradient : null)));
@@ -6160,7 +6329,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6160
6329
  // --- Mixer Brush ---------------------------------------------------------------
6161
6330
  /** Fills the Mixer Brush reservoir with a colour (default the editor colour). */
6162
6331
  loadMixerBrush(color) {
6163
- const [r, g, b] = _chunk56RHCIJVcjs.hexToRgb8.call(void 0, color === void 0 ? this.color : parseColor(color));
6332
+ const [r, g, b] = _chunkSNAFFCAXcjs.hexToRgb8.call(void 0, color === void 0 ? this.color : parseColor(color));
6164
6333
  this.mixerLoad = _chunkNIBFKXMDcjs.loadMixer.call(void 0, this.mixerLoad, [r / 255, g / 255, b / 255]);
6165
6334
  this.emit([]);
6166
6335
  return this.mixerLoad;
@@ -6190,7 +6359,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6190
6359
  // --- Strokes -------------------------------------------------------------------
6191
6360
  strokeBrush(init) {
6192
6361
  let brush = init.brushId !== void 0 ? this.requireBrush(init.brushId) : this.brush;
6193
- if (init.brush) brush = _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, { ...init.brush, id: brush.id }, brush);
6362
+ if (init.brush) brush = _chunkGHGBIAWQcjs.normalizePaintBrush.call(void 0, { ...init.brush, id: brush.id }, brush);
6194
6363
  return brush;
6195
6364
  }
6196
6365
  /**
@@ -6205,8 +6374,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6205
6374
  strokeCopies() {
6206
6375
  return symmetryCopies(this.guides.symmetry);
6207
6376
  }
6208
- sessionFor(doc, init, host) {
6209
- if (init.paint !== void 0 && !_chunk56RHCIJVcjs.isPaintEffectPaint.call(void 0, init.paint)) {
6377
+ sessionFor(doc, init, host, points) {
6378
+ if (init.paint !== void 0 && !_chunkSNAFFCAXcjs.isPaintEffectPaint.call(void 0, init.paint)) {
6210
6379
  const p = this.readStrokePaint(init.paint);
6211
6380
  if (p.type === "color") init = { ...init, color: p.color, paint: void 0 };
6212
6381
  else init = { ...init, paint: p };
@@ -6223,30 +6392,48 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6223
6392
  return l;
6224
6393
  })();
6225
6394
  const brush = this.strokeBrush(init);
6226
- if (this.previewing && _chunkEU2ZZA6Lcjs.isWetBrush.call(void 0, brush)) throw new PaintEditorError(`Wet paint can't be previewed; the ${brush.name} brush paints wet media. Suggest it with a dry brush.`);
6227
- const effect = this.strokeEffect(init, brush);
6395
+ if (this.previewing && _chunkGHGBIAWQcjs.isWetBrush.call(void 0, brush)) throw new PaintEditorError(`Wet paint can't be previewed; the ${brush.name} brush paints wet media. Suggest it with a dry brush.`);
6396
+ if (brush.ghost) {
6397
+ if (brush.light.amount > 0) throw new PaintEditorError(`Ghost paint (${brush.name}) shares the wet light channel and can't emit light; set light.amount to 0 or ghost to null (set_brush).`);
6398
+ if (_chunkSNAFFCAXcjs.isPaintEffectPaint.call(void 0, init.paint) || init.paint === void 0 && init.color === void 0 && Boolean(this.effectPaint)) {
6399
+ throw new PaintEditorError(`Ghost paint (${brush.name}) needs a single colour to subtract as it fades, so it can't paint with an effect; set a solid colour (set_color) or pass color to paint_stroke.`);
6400
+ }
6401
+ if (brush.behavior.multicolor.mode !== "off") throw new PaintEditorError(`Ghost paint (${brush.name}) needs a single colour to subtract as it fades, so it can't use multi-colour paint; set behavior.multicolor.mode to "off" (set_brush).`);
6402
+ const gCol = init.color === void 0 ? _nullishCoalesce(this.ownColour(init.brushId), () => ( this.color)) : parseColor(init.color);
6403
+ if (this.strokeGradient(init, brush, gCol)) throw new PaintEditorError(`Ghost paint (${brush.name}) needs a single colour to subtract as it fades, so it can't paint a gradient; set a solid colour (set_color) or pass color to paint_stroke.`);
6404
+ if (Boolean(_optionalChain([doc, 'access', _355 => _355.light, 'optionalAccess', _356 => _356[layer.id], 'optionalAccess', _357 => _357.tiles, 'access', _358 => _358.size])) || Boolean(_optionalChain([this, 'access', _359 => _359.wet, 'access', _360 => _360.world, 'optionalAccess', _361 => _361.hasLane, 'call', _362 => _362(layer.id)]) && this.wet.world.isLit(layer.id))) {
6405
+ throw new PaintEditorError(`Layer "${layer.name}" holds light paint, and ghost paint shares the wet light channel; paint on another layer (add_layer) or clear the light first (clear_light).`);
6406
+ }
6407
+ }
6408
+ const effect = this.strokeEffect(init, brush, points);
6409
+ if (!points && init.paint === void 0 && _optionalChain([effect, 'optionalAccess', _363 => _363.source, 'access', _364 => _364.map, 'optionalAccess', _365 => _365.by]) === "path" && _chunkGHGBIAWQcjs.isWetBrush.call(void 0, brush)) {
6410
+ throw new PaintEditorError(`The ${brush.name} brush paints wet media, which can't follow a path that isn't known until the stroke ends; paint with a dry brush, set_effect_paint with by: "stroke", or give the points to paint_stroke.`);
6411
+ }
6228
6412
  if (brush.light.amount > 0) {
6229
6413
  if (brush.engine === "sticker") throw new PaintEditorError(`The ${brush.name} brush sprays stickers, which don't take light yet; paint light with a dab or particle light brush (glow-gel, neon-marker; list_brush_presets lists them), or set light.amount to 0 (set_brush).`);
6414
+ if (Boolean(_optionalChain([this, 'access', _366 => _366.wet, 'access', _367 => _367.world, 'optionalAccess', _368 => _368.hasLane, 'call', _369 => _369(layer.id)]) && this.wet.world.getGhost(layer.id)) || Boolean(_optionalChain([this, 'access', _370 => _370.wet, 'access', _371 => _371.settings, 'access', _372 => _372.get, 'call', _373 => _373(layer.id), 'optionalAccess', _374 => _374.ghost]))) {
6415
+ throw new PaintEditorError(`Layer "${layer.name}" has ghost paint fading on it, which uses the wet light channel; paint light on another layer (add_layer), or finish the ghost first (dry_paint).`);
6416
+ }
6230
6417
  }
6231
- if (_optionalChain([doc, 'access', _318 => _318.liveStrokes, 'optionalAccess', _319 => _319[layer.id]])) {
6418
+ if (_optionalChain([doc, 'access', _375 => _375.liveStrokes, 'optionalAccess', _376 => _376[layer.id]])) {
6232
6419
  const why = liveStrokeRefusal(brush);
6233
6420
  if (why) throw new PaintEditorError(`Layer "${layer.name}" is a stroke layer. ${why}`);
6234
6421
  }
6235
- if (_optionalChain([doc, 'access', _320 => _320.liveStrokes, 'optionalAccess', _321 => _321[layer.id]]) && _optionalChain([effect, 'optionalAccess', _322 => _322.source, 'access', _323 => _323.live])) {
6236
- const key = _chunk56RHCIJVcjs.effectPaintKey.call(void 0, effect.source);
6422
+ if (_optionalChain([doc, 'access', _377 => _377.liveStrokes, 'optionalAccess', _378 => _378[layer.id]]) && _optionalChain([effect, 'optionalAccess', _379 => _379.source, 'access', _380 => _380.live])) {
6423
+ const key = _chunkSNAFFCAXcjs.effectPaintKey.call(void 0, effect.source);
6237
6424
  const { sources } = this.liveEffects(doc);
6238
- if (!sources.some((p) => _chunk56RHCIJVcjs.effectPaintKey.call(void 0, p) === key) && sources.length >= MAX_LIVE_EFFECT_SOURCES) {
6425
+ if (!sources.some((p) => _chunkSNAFFCAXcjs.effectPaintKey.call(void 0, p) === key) && sources.length >= MAX_LIVE_EFFECT_SOURCES) {
6239
6426
  throw new PaintEditorError(`The painting already plays ${MAX_LIVE_EFFECT_SOURCES} live effects, the most it can; paint with one of them, or set_effect_paint with live false to bake this one.`);
6240
6427
  }
6241
6428
  }
6242
- const stickerLayer = Boolean(_optionalChain([doc, 'access', _324 => _324.stickers, 'optionalAccess', _325 => _325[layer.id], 'optionalAccess', _326 => _326.length]));
6429
+ const stickerLayer = Boolean(_optionalChain([doc, 'access', _381 => _381.stickers, 'optionalAccess', _382 => _382[layer.id], 'optionalAccess', _383 => _383.length]));
6243
6430
  if (brush.engine === "sticker") {
6244
6431
  if (!stickerLayer && _chunk474IQG74cjs.contentBounds.call(void 0, layer.surface)) throw new PaintEditorError(`Layer "${layer.name}" already has paint; spray stickers onto an empty layer (add_layer) so they stay editable.`);
6245
6432
  } else if (stickerLayer) {
6246
6433
  throw new PaintEditorError(`Layer "${layer.name}" is a sticker layer (its pixels are drawn from its stickers); paint on another layer (add_layer).`);
6247
6434
  }
6248
6435
  let wet;
6249
- if (_chunkEU2ZZA6Lcjs.isWetBrush.call(void 0, brush)) {
6436
+ if (_chunkGHGBIAWQcjs.isWetBrush.call(void 0, brush)) {
6250
6437
  this.requireWetIdle("painting");
6251
6438
  if (layer.offset.x || layer.offset.y) {
6252
6439
  const moved = { ...layer, surface: _chunk474IQG74cjs.translateSurface.call(void 0, layer.surface, layer.offset.x, layer.offset.y), offset: { x: 0, y: 0 } };
@@ -6254,19 +6441,19 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6254
6441
  if (doc !== this.doc) doc = { ...doc, layers: _chunkPVJMTLPJcjs.mapLayer.call(void 0, doc.layers, layer.id, () => moved) };
6255
6442
  layer = moved;
6256
6443
  }
6257
- if (!this.wet.wetLayerIds().includes(layer.id) && this.wet.wetLayerIds().length >= _chunkJ5VQYK7Tcjs.MAX_WET_LANES) {
6258
- throw new PaintEditorError(`At most ${_chunkJ5VQYK7Tcjs.MAX_WET_LANES} layers can hold wet paint at once; dry one first (dry_paint).`);
6444
+ if (!this.wet.wetLayerIds().includes(layer.id) && this.wet.wetLayerIds().length >= _chunkN5IMDAHMcjs.MAX_WET_LANES) {
6445
+ throw new PaintEditorError(`At most ${_chunkN5IMDAHMcjs.MAX_WET_LANES} layers can hold wet paint at once; dry one first (dry_paint).`);
6259
6446
  }
6260
6447
  this.beginWetOp();
6261
6448
  const world = this.wet.ensureLane(layer.id, brush.wet.medium);
6262
6449
  const id = layer.id;
6263
6450
  const wetColor = init.color === void 0 ? _nullishCoalesce(this.ownColour(init.brushId), () => ( this.color)) : parseColor(init.color);
6264
- const [r, g, b] = _chunk56RHCIJVcjs.hexToRgb8.call(void 0, wetColor);
6451
+ const [r, g, b] = _chunkSNAFFCAXcjs.hexToRgb8.call(void 0, wetColor);
6265
6452
  const wetGradient = this.strokeGradient(init, brush, wetColor);
6266
6453
  const load = _nullishCoalesce(init.load, () => ( brushLoadForStroke(brush, this.mixerLoad, [r / 255, g / 255, b / 255])));
6267
6454
  const seedW = _nullishCoalesce(init.seed, () => ( _chunk3K6HWEXZcjs.mix32.call(void 0, this.seedCounter * 2654435761 >>> 0) & 2147483647));
6268
6455
  const copiesW = (_nullishCoalesce(init.copies, () => ( this.strokeCopies()))).filter((m) => m.some((v, i) => v !== IDENTITY_AFFINE[i]));
6269
- const driver = new (0, _chunk56RHCIJVcjs.WetStrokeDriver)({
6456
+ const driver = new (0, _chunkSNAFFCAXcjs.WetStrokeDriver)({
6270
6457
  world,
6271
6458
  laneId: id,
6272
6459
  brush,
@@ -6274,12 +6461,13 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6274
6461
  load,
6275
6462
  grain: paperGrain(doc.paper),
6276
6463
  paperDepth: doc.paper.depth,
6277
- paperColor: _chunk56RHCIJVcjs.hexToRgb8.call(void 0, doc.paper.color),
6464
+ paperColor: _chunkSNAFFCAXcjs.hexToRgb8.call(void 0, doc.paper.color),
6278
6465
  seed: seedW,
6279
6466
  copies: [IDENTITY_AFFINE, ...copiesW].map(affineCopy),
6280
6467
  mask: init.maskStencils ? this.stencilSelection(init.maskStencils) : init.stencils !== false ? this.stencilSelection() : null,
6281
6468
  paint: effect ? null : wetGradient,
6282
- effect: _nullishCoalesce(_optionalChain([effect, 'optionalAccess', _327 => _327.pixels]), () => ( null))
6469
+ effect: _nullishCoalesce(_optionalChain([effect, 'optionalAccess', _384 => _384.pixels]), () => ( null)),
6470
+ speed: this.wet.speed
6283
6471
  });
6284
6472
  init = { ...init, seed: seedW, load };
6285
6473
  wet = { driver, surface: () => world.display(id).surface };
@@ -6290,7 +6478,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6290
6478
  }
6291
6479
  let color = init.color === void 0 ? _nullishCoalesce(this.ownColour(init.brushId), () => ( this.color)) : parseColor(init.color);
6292
6480
  const tracing = this.guides.tracing;
6293
- if (init.color === void 0 && init.start && _optionalChain([tracing, 'optionalAccess', _328 => _328.visible]) && tracing.sampleColors) color = _nullishCoalesce(this.sampleTracingColor(init.start.x, init.start.y), () => ( color));
6481
+ if (init.color === void 0 && init.start && _optionalChain([tracing, 'optionalAccess', _385 => _385.visible]) && tracing.sampleColors) color = _nullishCoalesce(this.sampleTracingColor(init.start.x, init.start.y), () => ( color));
6294
6482
  const perspective = this.guides.perspective;
6295
6483
  const snapper = init.snapToPerspective && perspective.enabled && perspective.snap ? new PerspectiveSnapper(perspective) : null;
6296
6484
  const useStencils = init.stencils !== false;
@@ -6323,9 +6511,9 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6323
6511
  mixerLoad: _nullishCoalesce(init.load, () => ( brushLoadForStroke(brush, this.mixerLoad, [rgba[0] / 255, rgba[1] / 255, rgba[2] / 255]))),
6324
6512
  secondary: rgbaOf(this.secondaryColor),
6325
6513
  wet,
6326
- thick: brush.engine === "impasto" ? { channels: _nullishCoalesce(_optionalChain([doc, 'access', _329 => _329.thick, 'optionalAccess', _330 => _330[layer.id]]), () => ( emptyThickChannels())) } : void 0,
6514
+ thick: brush.engine === "impasto" ? { channels: _nullishCoalesce(_optionalChain([doc, 'access', _386 => _386.thick, 'optionalAccess', _387 => _387[layer.id]]), () => ( emptyThickChannels())) } : void 0,
6327
6515
  // Light paint: a twin of the stroke paints the light channel (laying, dimming, moving light).
6328
- light: !wet && brush.engine !== "sticker" && (brush.light.amount > 0 || _optionalChain([doc, 'access', _331 => _331.light, 'optionalAccess', _332 => _332[layer.id]])) ? { surface: _nullishCoalesce(_optionalChain([doc, 'access', _333 => _333.light, 'optionalAccess', _334 => _334[layer.id]]), () => ( emptyLight())) } : null,
6516
+ light: !wet && brush.engine !== "sticker" && (brush.light.amount > 0 || _optionalChain([doc, 'access', _388 => _388.light, 'optionalAccess', _389 => _389[layer.id]])) ? { surface: _nullishCoalesce(_optionalChain([doc, 'access', _390 => _390.light, 'optionalAccess', _391 => _391[layer.id]]), () => ( emptyLight())) } : null,
6329
6517
  sticker: brush.engine === "sticker" ? { nextId: this.nextStickerNumber(doc), art: this.stickerArt.get, variant: (ref2) => this.stickerArt.variantFor(ref2, this.colorScheme === "dark") } : void 0,
6330
6518
  stampArt: this.stampArt,
6331
6519
  paint: effect ? null : this.strokeGradient(init, brush, color),
@@ -6340,7 +6528,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6340
6528
  const stroke = {
6341
6529
  id: `s${this.strokeCounter++}`,
6342
6530
  layerId: session.layerId,
6343
- brush: _chunkEU2ZZA6Lcjs.brushToJSON.call(void 0, init.brush),
6531
+ brush: _chunkGHGBIAWQcjs.brushToJSON.call(void 0, init.brush),
6344
6532
  color: init.colorHex,
6345
6533
  points: session.points.map((p) => ({ ...p })),
6346
6534
  seed: init.seed
@@ -6365,25 +6553,35 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6365
6553
  const before = this.doc;
6366
6554
  const host = {
6367
6555
  update: (layerId, surface, rects) => {
6368
- if (_optionalChain([this, 'access', _335 => _335.session, 'optionalAccess', _336 => _336.init, 'access', _337 => _337.wet])) {
6556
+ if (_optionalChain([this, 'access', _392 => _392.session, 'optionalAccess', _393 => _393.init, 'access', _394 => _394.wet])) {
6369
6557
  this.wet.syncDisplays();
6370
6558
  return;
6371
6559
  }
6372
6560
  this.live = { layerId, surface };
6373
- const ch = _optionalChain([this, 'access', _338 => _338.session, 'optionalAccess', _339 => _339.thickChannels, 'call', _340 => _340()]);
6561
+ const ch = _optionalChain([this, 'access', _395 => _395.session, 'optionalAccess', _396 => _396.thickChannels, 'call', _397 => _397()]);
6374
6562
  this.liveThick = ch ? { layerId, channels: ch } : null;
6375
6563
  this.emit(rects);
6376
6564
  },
6377
- sampled: (s, points) => this.notifySample("points", s, points),
6565
+ sampled: (s, points) => {
6566
+ this.notifySample("points", s, points);
6567
+ this.previewPathStroke(s);
6568
+ },
6378
6569
  commit: (s, surface, cancelled) => {
6379
6570
  this.session = null;
6571
+ const preview = _optionalChain([this, 'access', _398 => _398.pathPreview, 'optionalAccess', _399 => _399.session]) === s ? this.pathPreview : null;
6572
+ this.pathPreview = null;
6573
+ const pathPaint = cancelled ? null : this.pathStrokePaint(s);
6574
+ if (pathPaint) {
6575
+ this.finishPathStroke(s, pathPaint, preview);
6576
+ return;
6577
+ }
6380
6578
  this.live = null;
6381
6579
  this.liveLayers = null;
6382
6580
  this.liveThick = null;
6383
6581
  const wetStroke = Boolean(s.init.wet);
6384
6582
  if (wetStroke) this.wet.driver = null;
6385
6583
  const brush = s.init.brush;
6386
- if (!cancelled && _optionalChain([s, 'access', _341 => _341.result, 'optionalAccess', _342 => _342.mixerLoad])) this.keepLoad(brush, s.result.mixerLoad);
6584
+ if (!cancelled && _optionalChain([s, 'access', _400 => _400.result, 'optionalAccess', _401 => _401.mixerLoad])) this.keepLoad(brush, s.result.mixerLoad);
6387
6585
  if (cancelled || !surface) {
6388
6586
  if (this.wetOp) {
6389
6587
  const snap = this.wetOp.before;
@@ -6399,7 +6597,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6399
6597
  }
6400
6598
  const stroke = this.record(s);
6401
6599
  s.result.strokeId = stroke.id;
6402
- this.paintedBounds.set(stroke, _nullishCoalesce(_optionalChain([s, 'access', _343 => _343.result, 'optionalAccess', _344 => _344.bounds]), () => ( null)));
6600
+ this.paintedBounds.set(stroke, _nullishCoalesce(_optionalChain([s, 'access', _402 => _402.result, 'optionalAccess', _403 => _403.bounds]), () => ( null)));
6403
6601
  if (wetStroke && this.wet.instantDry) {
6404
6602
  this.wet.dry(s.layerId);
6405
6603
  this.logWet({ kind: "dry", layerId: s.layerId, at: this.doc.strokes.length + 1 });
@@ -6410,8 +6608,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6410
6608
  const ch = s.thickChannels();
6411
6609
  const thick = ch ? { ..._nullishCoalesce(this.doc.thick, () => ( {})), [l.id]: ch } : this.doc.thick;
6412
6610
  const sprayed = s.stickers();
6413
- const stickers = sprayed ? { ..._nullishCoalesce(this.doc.stickers, () => ( {})), [l.id]: [..._nullishCoalesce(_optionalChain([this, 'access', _345 => _345.doc, 'access', _346 => _346.stickers, 'optionalAccess', _347 => _347[l.id]]), () => ( [])), ...sprayed] } : this.doc.stickers;
6414
- const wetLight = wetStroke && _optionalChain([this, 'access', _348 => _348.wet, 'access', _349 => _349.world, 'optionalAccess', _350 => _350.hasLane, 'call', _351 => _351(l.id)]) ? this.wet.world.lightDisplay(l.id) : null;
6611
+ const stickers = sprayed ? { ..._nullishCoalesce(this.doc.stickers, () => ( {})), [l.id]: [..._nullishCoalesce(_optionalChain([this, 'access', _404 => _404.doc, 'access', _405 => _405.stickers, 'optionalAccess', _406 => _406[l.id]]), () => ( [])), ...sprayed] } : this.doc.stickers;
6612
+ const wetLight = wetStroke && _optionalChain([this, 'access', _407 => _407.wet, 'access', _408 => _408.world, 'optionalAccess', _409 => _409.hasLane, 'call', _410 => _410(l.id)]) ? this.wet.world.lightDisplay(l.id) : null;
6415
6613
  const light = withLayerLight(this.doc.light, l.id, _nullishCoalesce(s.lightChannel(), () => ( wetLight)));
6416
6614
  this.commit(`${brush.name} stroke`, this.withWetEvents(withLiveStroke({ ...this.doc, layers: _chunkPVJMTLPJcjs.mapLayer.call(void 0, this.doc.layers, l.id, () => ({ ...l, surface })), strokes: [...this.doc.strokes, stroke], ...thick ? { thick } : {}, ...stickers ? { stickers } : {}, ...light ? { light } : {} }, stroke)), wetStroke ? before : this.doc);
6417
6615
  this.notifySample("end", s, [], stroke.id);
@@ -6425,14 +6623,99 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6425
6623
  throw e;
6426
6624
  }
6427
6625
  this.session = session;
6626
+ if (_optionalChain([session, 'access', _411 => _411.init, 'access', _412 => _412.effect, 'optionalAccess', _413 => _413.source, 'access', _414 => _414.map, 'optionalAccess', _415 => _415.by]) === "path" && !session.init.wet) this.pathPreview = { session, key: "", pending: null, landed: null };
6428
6627
  this.emit([]);
6429
6628
  this.notifySample("begin", session);
6430
6629
  return session;
6431
6630
  }
6631
+ /**
6632
+ * Renders a hand-painted path stroke's effect along the path drawn so far and paints the stroke
6633
+ * again with it when it lands, so the effect follows the pen while it draws. One render at a
6634
+ * time: when one lands, the next takes the newest path. A failed render leaves the preview as it
6635
+ * was; the render on release reports it.
6636
+ */
6637
+ previewPathStroke(s) {
6638
+ const pv = this.pathPreview;
6639
+ if (!pv || pv.session !== s || pv.pending || !s.open) return;
6640
+ const paint = this.pathStrokePaint(s);
6641
+ if (!paint) return;
6642
+ const key = _chunkSNAFFCAXcjs.effectPaintKey.call(void 0, paint);
6643
+ if (key === pv.key) return;
6644
+ pv.key = key;
6645
+ const cached = this.effectPaintImage(paint);
6646
+ const pending = cached ? Promise.resolve(cached) : this.renderEffectPaintPixels(paint);
6647
+ pv.pending = pending;
6648
+ pending.then(
6649
+ (pixels) => {
6650
+ pv.pending = null;
6651
+ pv.landed = { key, pixels };
6652
+ if (this.pathPreview !== pv || !s.open) return;
6653
+ s.repaintEffect(pixels);
6654
+ this.previewPathStroke(s);
6655
+ },
6656
+ () => {
6657
+ pv.pending = null;
6658
+ }
6659
+ );
6660
+ }
6432
6661
  /** The current live stroke, if any. */
6433
6662
  get activeStroke() {
6434
6663
  return this.session;
6435
6664
  }
6665
+ /**
6666
+ * While a hand-painted stroke waits for its path render (`map: { by: 'path' }`), settles when it
6667
+ * has landed and rejects if it could not (the stroke is dropped); `null` otherwise. Until then
6668
+ * the editor is busy, as during a stroke, and shows the stroke as it was painted.
6669
+ */
6670
+ get strokeRendering() {
6671
+ return _nullishCoalesce(_optionalChain([this, 'access', _416 => _416.pathStroke, 'optionalAccess', _417 => _417.done]), () => ( null));
6672
+ }
6673
+ /** The paint a finished hand-painted stroke must be painted again with, or `null` when it already painted with it. */
6674
+ pathStrokePaint(s) {
6675
+ const source = _optionalChain([s, 'access', _418 => _418.init, 'access', _419 => _419.effect, 'optionalAccess', _420 => _420.source]);
6676
+ if (_optionalChain([source, 'optionalAccess', _421 => _421.map, 'optionalAccess', _422 => _422.by]) !== "path" || !s.points.length) return null;
6677
+ const paint = _chunkSNAFFCAXcjs.withStrokePath.call(void 0, source, s.points, this.effectPathControls.get(source.effect));
6678
+ return _chunkSNAFFCAXcjs.effectPaintKey.call(void 0, paint) === _chunkSNAFFCAXcjs.effectPaintKey.call(void 0, source) ? null : paint;
6679
+ }
6680
+ /**
6681
+ * Ends a hand-painted stroke with a path-mapped effect. Its whole path isn't known until now, so
6682
+ * the live stroke was only a preview from renders along the path so far (`previewPathStroke`):
6683
+ * nothing of it was committed. Paints it again with the path's own render, as one stroke and one undo step, at
6684
+ * once if that can render synchronously and when the render lands if not.
6685
+ */
6686
+ finishPathStroke(s, paint, preview) {
6687
+ const finish = () => {
6688
+ this.pathStroke = null;
6689
+ this.live = null;
6690
+ this.liveLayers = null;
6691
+ this.liveThick = null;
6692
+ const masks = s.init.selection ? (_nullishCoalesce(s.maskStencils, () => ( this.guides.stencils))).filter((x) => x.enabled && x.mode === "mask") : [];
6693
+ const load = s.init.mixerLoad;
6694
+ const result = this.paintStroke({ layerId: s.layerId, points: s.points, color: s.init.colorHex, brush: _chunkGHGBIAWQcjs.brushToJSON.call(void 0, s.init.brush), seed: s.init.seed, copies: s.init.affineCopies, ...load.reservoir || load.pickup ? { load } : {}, paint, snapToPerspective: false, stencils: false, maskStencils: masks });
6695
+ Object.assign(s.result, result);
6696
+ this.notifySample("end", s, [], result.strokeId);
6697
+ };
6698
+ const key = _chunkSNAFFCAXcjs.effectPaintKey.call(void 0, paint);
6699
+ if (_optionalChain([preview, 'optionalAccess', _423 => _423.landed, 'optionalAccess', _424 => _424.key]) === key) this.cacheEffectPaintImage(paint, preview.landed.pixels);
6700
+ if (this.effectPaintImage(paint) || this.renderEffectPaintSync(paint)) {
6701
+ finish();
6702
+ return;
6703
+ }
6704
+ const render = _optionalChain([preview, 'optionalAccess', _425 => _425.pending]) && preview.key === key ? preview.pending.then((img) => this.cacheEffectPaintImage(paint, img)) : this.renderEffectPaint(paint);
6705
+ const done = render.then(finish, (e) => {
6706
+ this.pathStroke = null;
6707
+ this.live = null;
6708
+ this.liveLayers = null;
6709
+ this.liveThick = null;
6710
+ this.emit();
6711
+ this.notifySample("cancel", s, []);
6712
+ throw e;
6713
+ });
6714
+ done.catch(() => {
6715
+ });
6716
+ this.pathStroke = { effect: paint.effect, done };
6717
+ this.emit([]);
6718
+ }
6436
6719
  /** Runs a whole stroke against `doc` without touching the editor; returns the new document. */
6437
6720
  runStroke(doc, init, points) {
6438
6721
  let out = doc;
@@ -6443,23 +6726,23 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6443
6726
  if (cancelled || !surface) return;
6444
6727
  const stroke = this.record(s);
6445
6728
  s.result.strokeId = stroke.id;
6446
- this.paintedBounds.set(stroke, _nullishCoalesce(_optionalChain([s, 'access', _352 => _352.result, 'optionalAccess', _353 => _353.bounds]), () => ( null)));
6729
+ this.paintedBounds.set(stroke, _nullishCoalesce(_optionalChain([s, 'access', _426 => _426.result, 'optionalAccess', _427 => _427.bounds]), () => ( null)));
6447
6730
  const l = _chunkPVJMTLPJcjs.findLayer.call(void 0, out.layers, s.layerId).layer;
6448
6731
  const offset = s.init.wet ? { x: 0, y: 0 } : l.offset;
6449
6732
  const ch = s.thickChannels();
6450
6733
  const sprayed = s.stickers();
6451
- const lit = _nullishCoalesce(s.lightChannel(), () => ( (s.init.wet && _optionalChain([this, 'access', _354 => _354.wet, 'access', _355 => _355.world, 'optionalAccess', _356 => _356.hasLane, 'call', _357 => _357(l.id)]) ? this.wet.world.lightDisplay(l.id) : null)));
6734
+ const lit = _nullishCoalesce(s.lightChannel(), () => ( (s.init.wet && _optionalChain([this, 'access', _428 => _428.wet, 'access', _429 => _429.world, 'optionalAccess', _430 => _430.hasLane, 'call', _431 => _431(l.id)]) ? this.wet.world.lightDisplay(l.id) : null)));
6452
6735
  out = withLiveStroke({
6453
6736
  ...out,
6454
6737
  layers: _chunkPVJMTLPJcjs.mapLayer.call(void 0, out.layers, l.id, () => ({ ...l, surface, offset })),
6455
6738
  strokes: [...out.strokes, stroke],
6456
6739
  ...ch ? { thick: { ..._nullishCoalesce(out.thick, () => ( {})), [l.id]: ch } } : {},
6457
- ...sprayed ? { stickers: { ..._nullishCoalesce(out.stickers, () => ( {})), [l.id]: [..._nullishCoalesce(_optionalChain([out, 'access', _358 => _358.stickers, 'optionalAccess', _359 => _359[l.id]]), () => ( [])), ...sprayed] } } : {},
6740
+ ...sprayed ? { stickers: { ..._nullishCoalesce(out.stickers, () => ( {})), [l.id]: [..._nullishCoalesce(_optionalChain([out, 'access', _432 => _432.stickers, 'optionalAccess', _433 => _433[l.id]]), () => ( [])), ...sprayed] } } : {},
6458
6741
  ...lit ? { light: withLayerLight(out.light, l.id, lit) } : {}
6459
6742
  }, stroke);
6460
6743
  }
6461
6744
  };
6462
- const session = this.sessionFor(doc, init, host);
6745
+ const session = this.sessionFor(doc, init, host, points);
6463
6746
  session.push(points);
6464
6747
  const result = session.end();
6465
6748
  if (session.init.wet) {
@@ -6527,11 +6810,11 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6527
6810
  throw e;
6528
6811
  }
6529
6812
  const run = last;
6530
- if (_optionalChain([run, 'optionalAccess', _360 => _360.result, 'access', _361 => _361.mixerLoad])) this.keepLoad(run.brush, run.result.mixerLoad);
6531
- if (doc !== before || this.wetOp) this.commit(`${_nullishCoalesce(_optionalChain([run, 'optionalAccess', _362 => _362.brush, 'access', _363 => _363.name]), () => ( "Brush"))} path stroke`, this.withWetEvents(doc), before);
6813
+ if (_optionalChain([run, 'optionalAccess', _434 => _434.result, 'access', _435 => _435.mixerLoad])) this.keepLoad(run.brush, run.result.mixerLoad);
6814
+ if (doc !== before || this.wetOp) this.commit(`${_nullishCoalesce(_optionalChain([run, 'optionalAccess', _436 => _436.brush, 'access', _437 => _437.name]), () => ( "Brush"))} path stroke`, this.withWetEvents(doc), before);
6532
6815
  else this.emit([]);
6533
- const layerId = _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(_optionalChain([run, 'optionalAccess', _364 => _364.result, 'access', _365 => _365.layerId]), () => ( stroke.layerId)), () => ( this.doc.activeLayerId)), () => ( ""));
6534
- return { layerId, bounds, dabs, strokeIds, ..._optionalChain([run, 'optionalAccess', _366 => _366.result, 'access', _367 => _367.mixerLoad]) ? { mixerLoad: run.result.mixerLoad } : {}, ..._optionalChain([run, 'optionalAccess', _368 => _368.result, 'access', _369 => _369.wet]) !== void 0 ? { wet: run.result.wet } : {} };
6816
+ const layerId = _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(_optionalChain([run, 'optionalAccess', _438 => _438.result, 'access', _439 => _439.layerId]), () => ( stroke.layerId)), () => ( this.doc.activeLayerId)), () => ( ""));
6817
+ return { layerId, bounds, dabs, strokeIds, ..._optionalChain([run, 'optionalAccess', _440 => _440.result, 'access', _441 => _441.mixerLoad]) ? { mixerLoad: run.result.mixerLoad } : {}, ..._optionalChain([run, 'optionalAccess', _442 => _442.result, 'access', _443 => _443.wet]) !== void 0 ? { wet: run.result.wet } : {} };
6535
6818
  }
6536
6819
  /** Checks stroke samples (finite x and y, pressure 0..1) and returns them; throws a sentence naming the bad point. */
6537
6820
  checkPoints(points) {
@@ -6554,7 +6837,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6554
6837
  */
6555
6838
  replayStrokes(options) {
6556
6839
  this.requireIdle("replaying");
6557
- if (!_optionalChain([options, 'access', _370 => _370.strokeIds, 'optionalAccess', _371 => _371.length])) throw new PaintEditorError("strokeIds is empty; pass ids from list_strokes.");
6840
+ if (!_optionalChain([options, 'access', _444 => _444.strokeIds, 'optionalAccess', _445 => _445.length])) throw new PaintEditorError("strokeIds is empty; pass ids from list_strokes.");
6558
6841
  const strokes = options.strokeIds.map((id) => {
6559
6842
  const s = this.doc.strokes.find((x) => x.id === id);
6560
6843
  if (!s) throw new PaintEditorError(`Unknown stroke "${id}". Call list_strokes for the ids.`);
@@ -6568,7 +6851,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6568
6851
  if (options.layerId !== void 0) this.paintTarget(options.layerId, "replay onto");
6569
6852
  if (options.color === void 0) {
6570
6853
  for (const s of strokes) {
6571
- if (_optionalChain([s, 'access', _372 => _372.paint, 'optionalAccess', _373 => _373.type]) === "effect" && !this.effectPaintImage(s.paint)) {
6854
+ if (_optionalChain([s, 'access', _446 => _446.paint, 'optionalAccess', _447 => _447.type]) === "effect" && !this.effectPaintImage(s.paint)) {
6572
6855
  throw new PaintEditorError(`Stroke "${s.id}" paints with the effect "${s.paint.effect}"${s.paint.provider ? ` from provider "${s.paint.provider}"` : ""}, which is not rendered in this editor; render it first (prepareStrokeEffects; the replay_strokes tool does this) or recolour the replay with color.`);
6573
6856
  }
6574
6857
  }
@@ -6591,13 +6874,13 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6591
6874
  let brush = v.brush;
6592
6875
  if (options.brushId !== void 0) {
6593
6876
  const b = this.requireBrush(options.brushId);
6594
- brush = _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, { tip: { ...b.tip, size: b.tip.size * (v.brush.tip.size / s.brush.tip.size) } }, b);
6877
+ brush = _chunkGHGBIAWQcjs.normalizePaintBrush.call(void 0, { tip: { ...b.tip, size: b.tip.size * (v.brush.tip.size / s.brush.tip.size) } }, b);
6595
6878
  }
6596
6879
  const layerId = _nullishCoalesce(options.layerId, () => ( s.layerId));
6597
6880
  if (!_chunkPVJMTLPJcjs.findLayer.call(void 0, doc.layers, layerId)) throw new PaintEditorError(`Stroke "${s.id}" was painted on layer "${layerId}", which no longer exists; pass layerId to replay it elsewhere.`);
6598
6881
  let load = s.load;
6599
6882
  if (load && options.color !== void 0 && load.reservoir) {
6600
- const [r, g, b] = _chunk56RHCIJVcjs.hexToRgb8.call(void 0, options.color);
6883
+ const [r, g, b] = _chunkSNAFFCAXcjs.hexToRgb8.call(void 0, options.color);
6601
6884
  load = { ...load, reservoir: [r / 255, g / 255, b / 255] };
6602
6885
  }
6603
6886
  const paint = v.paint && options.color === void 0 ? { paint: v.paint } : {};
@@ -6609,6 +6892,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6609
6892
  }
6610
6893
  }
6611
6894
  if (doc !== this.doc) this.commit(strokes.length === 1 && repeat === 1 ? "Replay stroke" : "Replay strokes", doc);
6895
+ this.effectPaintBatch = 0;
6896
+ this.trimEffectPaints();
6612
6897
  return { strokeIds: ids, bounds, layerIds: [...layerIds] };
6613
6898
  }
6614
6899
  // --- Light paint --------------------------------------------------------------------
@@ -6626,7 +6911,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6626
6911
  /** A layer's light paint: whether it has any, where (document pixels), its brightest value 0..255, and its spill. */
6627
6912
  lightOf(layerId) {
6628
6913
  const l = this.wetLayer(layerId, "read the light of");
6629
- const info = lightInfo(_optionalChain([this, 'access', _374 => _374.doc, 'access', _375 => _375.light, 'optionalAccess', _376 => _376[l.id]]));
6914
+ const info = lightInfo(_optionalChain([this, 'access', _448 => _448.doc, 'access', _449 => _449.light, 'optionalAccess', _450 => _450[l.id]]));
6630
6915
  const bounds = info.bounds ? { ...info.bounds, x: info.bounds.x + l.offset.x, y: info.bounds.y + l.offset.y } : null;
6631
6916
  return { layerId: l.id, hasLight: info.peak > 0, bounds, peak: info.peak, spill: { ...this.lightSpillOf(l.id) } };
6632
6917
  }
@@ -6677,7 +6962,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6677
6962
  const id = _nullishCoalesce(layerId, () => ( this.doc.activeLayerId));
6678
6963
  if (!id) return null;
6679
6964
  this.requireLayer(id);
6680
- const ch = _optionalChain([this, 'access', _377 => _377.doc, 'access', _378 => _378.thick, 'optionalAccess', _379 => _379[id]]);
6965
+ const ch = _optionalChain([this, 'access', _451 => _451.doc, 'access', _452 => _452.thick, 'optionalAccess', _453 => _453[id]]);
6681
6966
  if (!ch) return null;
6682
6967
  const r = reliefInfo(ch);
6683
6968
  return { layerId: id, bounds: r.bounds, maxHeight: r.maxHeight };
@@ -6788,7 +7073,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6788
7073
  wetState() {
6789
7074
  const st = this.getState().wet;
6790
7075
  const backend = this.wet.backend();
6791
- return { ...st, layers: this.wet.wetLayerIds().map((id) => this.wet.info(id)), backend, message: _nullishCoalesce(_optionalChain([backend, 'optionalAccess', _380 => _380.message]), () => ( _chunkJ5VQYK7Tcjs.wetSupport.call(void 0, ).message)), engine: this.wet.engineInfo() };
7076
+ return { ...st, layers: this.wet.wetLayerIds().map((id) => this.wet.info(id)), backend, message: _nullishCoalesce(_optionalChain([backend, 'optionalAccess', _454 => _454.message]), () => ( _chunkN5IMDAHMcjs.wetSupport.call(void 0, ).message)), engine: this.wet.engineInfo() };
6792
7077
  }
6793
7078
  /**
6794
7079
  * Engine B, the WebGPU accelerator for large wet areas: whether it may run, its state (`off`,
@@ -6806,7 +7091,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6806
7091
  */
6807
7092
  async setWetEngine(options) {
6808
7093
  const gpu = _nullishCoalesce(options.gpu, () => ( this.wet.gpuMode));
6809
- if (!_chunk56RHCIJVcjs.WET_GPU_MODES.includes(gpu)) throw new PaintEditorError(`gpu must be ${_chunk56RHCIJVcjs.WET_GPU_MODES.join(" or ")}, not ${JSON.stringify(gpu)}.`);
7094
+ if (!_chunkSNAFFCAXcjs.WET_GPU_MODES.includes(gpu)) throw new PaintEditorError(`gpu must be ${_chunkSNAFFCAXcjs.WET_GPU_MODES.join(" or ")}, not ${JSON.stringify(gpu)}.`);
6810
7095
  if (options.minTiles !== void 0 && !(Number.isInteger(options.minTiles) && options.minTiles >= 1 && options.minTiles <= 1024)) throw new PaintEditorError(`minTiles ${options.minTiles} is out of range; use 1..1024 tiles of 256 px.`);
6811
7096
  this.wet.setGpu(gpu, options.minTiles);
6812
7097
  this.emit();
@@ -6861,7 +7146,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6861
7146
  const amount = _nullishCoalesce(options.amount, () => ( 1));
6862
7147
  if (!(amount > 0 && amount <= 1)) throw new PaintEditorError(`amount ${amount} is out of range; use above 0 up to 1.`);
6863
7148
  const rect = _nullishCoalesce(this.checkRect(options.rect), () => ( { x: 0, y: 0, width: this.doc.canvas.width, height: this.doc.canvas.height }));
6864
- if (!this.wet.wetLayerIds().includes(l.id) && this.wet.wetLayerIds().length >= _chunkJ5VQYK7Tcjs.MAX_WET_LANES) throw new PaintEditorError(`At most ${_chunkJ5VQYK7Tcjs.MAX_WET_LANES} layers can hold wet paint at once; dry one first (dry_paint).`);
7149
+ if (!this.wet.wetLayerIds().includes(l.id) && this.wet.wetLayerIds().length >= _chunkN5IMDAHMcjs.MAX_WET_LANES) throw new PaintEditorError(`At most ${_chunkN5IMDAHMcjs.MAX_WET_LANES} layers can hold wet paint at once; dry one first (dry_paint).`);
6865
7150
  const before = this.doc;
6866
7151
  this.beginWetOp();
6867
7152
  const world = this.wet.ensureLane(l.id);
@@ -6873,7 +7158,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6873
7158
  }
6874
7159
  /** Records a settings change as a wet event (not an undo step). */
6875
7160
  recordWetSetting(e) {
6876
- this.doc = { ...this.doc, wetEvents: [..._nullishCoalesce(this.doc.wetEvents, () => ( [])), { clock: _nullishCoalesce(_optionalChain([this, 'access', _381 => _381.wet, 'access', _382 => _382.world, 'optionalAccess', _383 => _383.clock]), () => ( 0)), at: this.doc.strokes.length, ...e }] };
7161
+ this.doc = { ...this.doc, wetEvents: [..._nullishCoalesce(this.doc.wetEvents, () => ( [])), { clock: _nullishCoalesce(_optionalChain([this, 'access', _455 => _455.wet, 'access', _456 => _456.world, 'optionalAccess', _457 => _457.clock]), () => ( 0)), at: this.doc.strokes.length, ...e }] };
6877
7162
  }
6878
7163
  /** Changes a layer's wet settings (viscosity, evaporation, granulation…). Editor settings saved with the document, not an undo step. */
6879
7164
  setWetParams(layerId, update) {
@@ -6942,7 +7227,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6942
7227
  if (override) return Array.from(override).reduce((ls, [id, surface]) => _chunkPVJMTLPJcjs.mapLayer.call(void 0, ls, id, (l) => ({ ...l, surface })), this.doc.layers);
6943
7228
  const live = this.live;
6944
7229
  if (!live) return this.animatedView();
6945
- if (_optionalChain([this, 'access', _384 => _384.liveLayers, 'optionalAccess', _385 => _385.key]) === live.surface) return this.liveLayers.layers;
7230
+ if (_optionalChain([this, 'access', _458 => _458.liveLayers, 'optionalAccess', _459 => _459.key]) === live.surface) return this.liveLayers.layers;
6946
7231
  const layers = _chunkPVJMTLPJcjs.mapLayer.call(void 0, this.doc.layers, live.layerId, (l) => ({ ...l, surface: live.surface }));
6947
7232
  this.liveLayers = { key: live.surface, layers };
6948
7233
  return layers;
@@ -6965,7 +7250,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6965
7250
  tracingNode(t) {
6966
7251
  const { width, height } = this.doc.canvas;
6967
7252
  const key = this.tracingVersion * 100003 + width * 7 + height;
6968
- if (_optionalChain([this, 'access', _386 => _386.tracingCache, 'optionalAccess', _387 => _387.key]) === key && this.tracingCache.node.opacity === t.opacity) return this.tracingCache.node;
7253
+ if (_optionalChain([this, 'access', _460 => _460.tracingCache, 'optionalAccess', _461 => _461.key]) === key && this.tracingCache.node.opacity === t.opacity) return this.tracingCache.node;
6969
7254
  const src = _nullishCoalesce(this.imagePixels.get(t.src), () => ( this.decodeImage(t.src)));
6970
7255
  const image = resampleInto(src, t.rect, width, height);
6971
7256
  const node = { type: "image", id: TRACING_NODE_ID, name: "Tracing", visible: true, opacity: t.opacity, blend: "normal", image, version: key + Math.round(t.opacity * 1e3) / 1e4 };
@@ -6992,8 +7277,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6992
7277
  let out = layers;
6993
7278
  const ids = /* @__PURE__ */ new Set([...Object.keys(_nullishCoalesce(thick, () => ( {}))), ...live ? [live.layerId] : []]);
6994
7279
  for (const id of ids) {
6995
- const ch = _optionalChain([live, 'optionalAccess', _388 => _388.layerId]) === id ? live.channels : _optionalChain([thick, 'optionalAccess', _389 => _389[id]]);
6996
- const l = ch && _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, out, id), 'optionalAccess', _390 => _390.layer]);
7280
+ const ch = _optionalChain([live, 'optionalAccess', _462 => _462.layerId]) === id ? live.channels : _optionalChain([thick, 'optionalAccess', _463 => _463[id]]);
7281
+ const l = ch && _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, out, id), 'optionalAccess', _464 => _464.layer]);
6997
7282
  if (!ch || !isPixelLayer(l)) continue;
6998
7283
  let cache = this.litCaches.get(id);
6999
7284
  if (!cache) this.litCaches.set(id, cache = new LitCache());
@@ -7013,13 +7298,13 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7013
7298
  if (!ids.size) return layers;
7014
7299
  let out = layers;
7015
7300
  for (const id of ids) {
7016
- const l = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, out, id), 'optionalAccess', _391 => _391.layer]);
7301
+ const l = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, out, id), 'optionalAccess', _465 => _465.layer]);
7017
7302
  if (!isPixelLayer(l)) continue;
7018
7303
  let cache = this.lightCaches.get(id);
7019
7304
  if (!cache) this.lightCaches.set(id, cache = new LightCache());
7020
- const glowed = cache.glow(l.surface, light[id], _optionalChain([this, 'access', _392 => _392.liveThick, 'optionalAccess', _393 => _393.layerId]) === id ? this.liveThick.channels : _optionalChain([this, 'access', _394 => _394.doc, 'access', _395 => _395.thick, 'optionalAccess', _396 => _396[id]]));
7305
+ const glowed = cache.glow(l.surface, light[id], _optionalChain([this, 'access', _466 => _466.liveThick, 'optionalAccess', _467 => _467.layerId]) === id ? this.liveThick.channels : _optionalChain([this, 'access', _468 => _468.doc, 'access', _469 => _469.thick, 'optionalAccess', _470 => _470[id]]));
7021
7306
  if (glowed !== l.surface) out = _chunkPVJMTLPJcjs.mapLayer.call(void 0, out, id, () => ({ ...l, surface: glowed }));
7022
- const committed = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _397 => _397.layer]);
7307
+ const committed = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _471 => _471.layer]);
7023
7308
  const spill = light[id] && isPixelLayer(committed) ? cache.spill(committed.surface, light[id], this.lightSpillOf(id)) : null;
7024
7309
  if (spill) out = insertAfter(out, id, { type: "pixel", id: `${id}${SPILL_SUFFIX}`, name: `${l.name} light`, visible: l.visible, opacity: l.opacity, blend: "linear-dodge", surface: spill, offset: { ...l.offset } });
7025
7310
  }
@@ -7031,7 +7316,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7031
7316
  if (!l.visible) continue;
7032
7317
  if (l.type === "group") this.backlitLayers(l.children, committed, opacity * l.opacity, out);
7033
7318
  else if (isPixelLayer(l)) {
7034
- const thick = !committed && _optionalChain([this, 'access', _398 => _398.liveThick, 'optionalAccess', _399 => _399.layerId]) === l.id ? this.liveThick.channels : _optionalChain([this, 'access', _400 => _400.doc, 'access', _401 => _401.thick, 'optionalAccess', _402 => _402[l.id]]);
7319
+ const thick = !committed && _optionalChain([this, 'access', _472 => _472.liveThick, 'optionalAccess', _473 => _473.layerId]) === l.id ? this.liveThick.channels : _optionalChain([this, 'access', _474 => _474.doc, 'access', _475 => _475.thick, 'optionalAccess', _476 => _476[l.id]]);
7035
7320
  out.push({ surface: l.surface, offset: l.offset, opacity: opacity * l.opacity, ...thick ? { thick } : {} });
7036
7321
  }
7037
7322
  }
@@ -7060,7 +7345,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7060
7345
  if (backlight) layers = [...layers, backlight];
7061
7346
  if (options.layerIds) {
7062
7347
  const picked = [];
7063
- for (const id of options.layerIds) picked.push(_nullishCoalesce(_optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, layers, id), 'optionalAccess', _403 => _403.layer]), () => ( this.requireLayer(id))));
7348
+ for (const id of options.layerIds) picked.push(_nullishCoalesce(_optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, layers, id), 'optionalAccess', _477 => _477.layer]), () => ( this.requireLayer(id))));
7064
7349
  layers = picked.map((l) => ({ ...l, visible: true }));
7065
7350
  }
7066
7351
  const under = options.paper === false ? [] : [paperNode(this.doc.paper, this.lighting)];
@@ -7076,7 +7361,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7076
7361
  */
7077
7362
  compositeTiles(rect, onTile, options = {}) {
7078
7363
  const dirty = options.dirty === "all" ? void 0 : options.dirty;
7079
- this.viewCompositor.compositeTiles(this.renderLayers({ paper: options.paper }, true), rect, this.sources(), onTile, { dirty, checkpointLayerId: _nullishCoalesce(_optionalChain([this, 'access', _404 => _404.live, 'optionalAccess', _405 => _405.layerId]), () => ( this.doc.activeLayerId)) });
7364
+ this.viewCompositor.compositeTiles(this.renderLayers({ paper: options.paper }, true), rect, this.sources(), onTile, { dirty, checkpointLayerId: _nullishCoalesce(_optionalChain([this, 'access', _478 => _478.live, 'optionalAccess', _479 => _479.layerId]), () => ( this.doc.activeLayerId)) });
7080
7365
  }
7081
7366
  /** The canvas as canvas-sized RGBA (paper included by default). */
7082
7367
  compositePixels(options = {}) {
@@ -7104,7 +7389,11 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7104
7389
  /** Wet settings saved with the document (`null` when they are all defaults). */
7105
7390
  wetJSON() {
7106
7391
  const layers = {};
7107
- for (const [id, set] of this.wet.settings) if (_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, id)) layers[id] = { params: { ...set.params }, flow: { ...set.flow } };
7392
+ for (const [id, set] of this.wet.settings) {
7393
+ if (!_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, id)) continue;
7394
+ const ghost = _optionalChain([this, 'access', _480 => _480.wet, 'access', _481 => _481.world, 'optionalAccess', _482 => _482.hasLane, 'call', _483 => _483(id)]) ? this.wet.world.getGhost(id) : _nullishCoalesce(set.ghost, () => ( null));
7395
+ layers[id] = { params: { ...set.params }, flow: { ...set.flow }, ...ghost ? { ghost } : {} };
7396
+ }
7108
7397
  const flat = this.wet.tilt.angle === 0;
7109
7398
  if (!Object.keys(layers).length && flat) return void 0;
7110
7399
  return { tilt: { ...this.wet.tilt }, layers };
@@ -7113,7 +7402,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7113
7402
  this.wet.reset();
7114
7403
  if (!raw || typeof raw !== "object") return;
7115
7404
  const r = raw;
7116
- this.wet.setTilt(_chunkJ5VQYK7Tcjs.normalizeTilt.call(void 0, _nullishCoalesce(r.tilt, () => ( {}))));
7405
+ this.wet.setTilt(_chunkN5IMDAHMcjs.normalizeTilt.call(void 0, _nullishCoalesce(r.tilt, () => ( {}))));
7117
7406
  if (r.layers && typeof r.layers === "object") {
7118
7407
  for (const [id, v] of Object.entries(r.layers)) {
7119
7408
  if (!v || typeof v !== "object") {
@@ -7121,7 +7410,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7121
7410
  continue;
7122
7411
  }
7123
7412
  const x = v;
7124
- this.wet.settings.set(id, { params: _chunkJ5VQYK7Tcjs.normalizeWetParams.call(void 0, _nullishCoalesce(x.params, () => ( {}))), flow: _chunkJ5VQYK7Tcjs.normalizeFlow.call(void 0, _nullishCoalesce(x.flow, () => ( {}))) });
7413
+ const ghost = readWetGhost(x.ghost);
7414
+ this.wet.settings.set(id, { params: _chunkN5IMDAHMcjs.normalizeWetParams.call(void 0, _nullishCoalesce(x.params, () => ( {}))), flow: _chunkN5IMDAHMcjs.normalizeFlow.call(void 0, _nullishCoalesce(x.flow, () => ( {}))), ...ghost ? { ghost } : {} });
7125
7415
  }
7126
7416
  }
7127
7417
  }
@@ -7160,7 +7450,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7160
7450
  const spills = Object.fromEntries(Object.entries(this.lightSpills).filter(([id]) => _chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, id)));
7161
7451
  if (Object.keys(spills).length) ext.lightSpill = spills;
7162
7452
  else delete ext.lightSpill;
7163
- const effectLayers = effectLayersToJSON(_nullishCoalesce(this.doc.effectLayers, () => ( {})), (id) => isPixelLayer(_optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _406 => _406.layer])));
7453
+ const effectLayers = effectLayersToJSON(_nullishCoalesce(this.doc.effectLayers, () => ( {})), (id) => isPixelLayer(_optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _484 => _484.layer])));
7164
7454
  if (effectLayers) ext.effectLayers = effectLayers;
7165
7455
  else delete ext.effectLayers;
7166
7456
  if (this.doc.paperEffect) ext.paperEffect = paperEffectToJSON(this.doc.paperEffect);
@@ -7171,7 +7461,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7171
7461
  }
7172
7462
  /** Reads `layerChannels` and `lighting` from loaded extensions into the document. */
7173
7463
  readThick(state, ext, problems) {
7174
- if (Array.isArray(ext.brushSources)) this.brushSources.set(ext.brushSources.map((x, i) => _chunkEU2ZZA6Lcjs.readBrushSource.call(void 0, x, `brushSources[${i}]`, problems)).filter((x) => x !== null));
7464
+ if (Array.isArray(ext.brushSources)) this.brushSources.set(ext.brushSources.map((x, i) => _chunkGHGBIAWQcjs.readBrushSource.call(void 0, x, `brushSources[${i}]`, problems)).filter((x) => x !== null));
7175
7465
  this.lighting = normalizeLighting(_nullishCoalesce(ext.lighting, () => ( {})), DEFAULT_LIGHTING);
7176
7466
  this.litCaches.clear();
7177
7467
  if (ext.stickers && typeof ext.stickers === "object") {
@@ -7185,7 +7475,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7185
7475
  const stamp = _chunkRDFHWAHLcjs.editorStampOf.call(void 0, ref2);
7186
7476
  const { stamp: _old, variant, ...rest } = x;
7187
7477
  return [{ ...rest, ref: ref2, ...stamp ? { stamp } : {}, ...variant === "dark" && !stamp ? { variant } : {} }];
7188
- } catch (e9) {
7478
+ } catch (e10) {
7189
7479
  return [];
7190
7480
  }
7191
7481
  });
@@ -7197,7 +7487,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7197
7487
  if (ext.liveStrokes && typeof ext.liveStrokes === "object") {
7198
7488
  const liveStrokes = {};
7199
7489
  for (const [id, list] of Object.entries(ext.liveStrokes)) {
7200
- if (!isPixelLayer(_optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, state.layers, id), 'optionalAccess', _407 => _407.layer])) || !Array.isArray(list)) continue;
7490
+ if (!isPixelLayer(_optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, state.layers, id), 'optionalAccess', _485 => _485.layer])) || !Array.isArray(list)) continue;
7201
7491
  const ok = list.map(normalizeBrushStroke).filter((x) => x !== null).map((x) => ({ ...x, layerId: id }));
7202
7492
  if (ok.length !== list.length) problems.push(`Some strokes of stroke layer "${id}" could not be read; they were dropped (the layer's pixels are kept until a stroke is edited).`);
7203
7493
  liveStrokes[id] = ok;
@@ -7207,7 +7497,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7207
7497
  if (ext.effectLayers && typeof ext.effectLayers === "object") {
7208
7498
  const effectLayers = {};
7209
7499
  for (const [id, v] of Object.entries(ext.effectLayers)) {
7210
- if (!isPixelLayer(_optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, state.layers, id), 'optionalAccess', _408 => _408.layer]))) continue;
7500
+ if (!isPixelLayer(_optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, state.layers, id), 'optionalAccess', _486 => _486.layer]))) continue;
7211
7501
  const source = readPaintEffectSource(v);
7212
7502
  if (source) effectLayers[id] = source;
7213
7503
  else problems.push(`The effect of layer "${id}" could not be read; it loads as a plain layer.`);
@@ -7227,7 +7517,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7227
7517
  for (const [id, v] of Object.entries(ext.lightSpill)) {
7228
7518
  try {
7229
7519
  if (_chunkPVJMTLPJcjs.findLayer.call(void 0, state.layers, id)) this.lightSpills[id] = normalizeLightSpill(_nullishCoalesce(v, () => ( {})));
7230
- } catch (e10) {
7520
+ } catch (e11) {
7231
7521
  problems.push(`The light spill of layer "${id}" could not be read; it takes the defaults.`);
7232
7522
  }
7233
7523
  }
@@ -7235,7 +7525,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7235
7525
  if (ext.light && typeof ext.light === "object") {
7236
7526
  const light = {};
7237
7527
  for (const [id, v] of Object.entries(ext.light)) {
7238
- if (!isPixelLayer(_optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, state.layers, id), 'optionalAccess', _409 => _409.layer]))) continue;
7528
+ if (!isPixelLayer(_optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, state.layers, id), 'optionalAccess', _487 => _487.layer]))) continue;
7239
7529
  try {
7240
7530
  light[id] = lightFromJSON(v);
7241
7531
  } catch (e) {
@@ -7271,7 +7561,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7271
7561
  this.readGuides(loaded.guides, loaded.state, loaded.problems);
7272
7562
  if (Array.isArray(loaded.swatches)) this.swatches = loaded.swatches.map(readSwatch).filter((x) => x !== null);
7273
7563
  for (const s of loaded.state.strokes) {
7274
- const n = Number(_nullishCoalesce(_optionalChain([/^s(\d+)$/, 'access', _410 => _410.exec, 'call', _411 => _411(s.id), 'optionalAccess', _412 => _412[1]]), () => ( 0)));
7564
+ const n = Number(_nullishCoalesce(_optionalChain([/^s(\d+)$/, 'access', _488 => _488.exec, 'call', _489 => _489(s.id), 'optionalAccess', _490 => _490[1]]), () => ( 0)));
7275
7565
  if (n >= this.strokeCounter) this.strokeCounter = n + 1;
7276
7566
  }
7277
7567
  this.undoStack = [];
@@ -7279,7 +7569,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7279
7569
  this.doc = this.readThick(loaded.state, loaded.extensions, loaded.problems);
7280
7570
  for (const list of Object.values(_nullishCoalesce(this.doc.liveStrokes, () => ( {})))) {
7281
7571
  for (const s of list) {
7282
- const n = Number(_nullishCoalesce(_optionalChain([/^s(\d+)$/, 'access', _413 => _413.exec, 'call', _414 => _414(s.id), 'optionalAccess', _415 => _415[1]]), () => ( 0)));
7572
+ const n = Number(_nullishCoalesce(_optionalChain([/^s(\d+)$/, 'access', _491 => _491.exec, 'call', _492 => _492(s.id), 'optionalAccess', _493 => _493[1]]), () => ( 0)));
7283
7573
  if (n >= this.strokeCounter) this.strokeCounter = n + 1;
7284
7574
  }
7285
7575
  }
@@ -7377,10 +7667,10 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7377
7667
  return next.type === "group" ? { ...next, children: toStandard(next.children) } : next;
7378
7668
  });
7379
7669
  const layers = toStandard(dried);
7380
- const result = _chunk4NMPUJUKcjs.exportPsd.call(void 0, { width, height, layers: [paperLayer, ...layers], merged, resolution: dpi });
7670
+ const result = _chunkYJANF2BLcjs.exportPsd.call(void 0, { width, height, layers: [paperLayer, ...layers], merged, resolution: dpi });
7381
7671
  for (const [mode, names] of changed) {
7382
- const label = _nullishCoalesce(_optionalChain([_chunk2VX55NFMcjs.BLEND_MODES, 'access', _416 => _416.find, 'call', _417 => _417((m) => m.id === mode), 'optionalAccess', _418 => _418.label]), () => ( mode));
7383
- const std = _nullishCoalesce(_optionalChain([_chunk2VX55NFMcjs.BLEND_MODES, 'access', _419 => _419.find, 'call', _420 => _420((m) => m.id === _chunk2VX55NFMcjs.standardBlendMode.call(void 0, mode)), 'optionalAccess', _421 => _421.label]), () => ( _chunk2VX55NFMcjs.standardBlendMode.call(void 0, mode)));
7672
+ const label = _nullishCoalesce(_optionalChain([_chunk2VX55NFMcjs.BLEND_MODES, 'access', _494 => _494.find, 'call', _495 => _495((m) => m.id === mode), 'optionalAccess', _496 => _496.label]), () => ( mode));
7673
+ const std = _nullishCoalesce(_optionalChain([_chunk2VX55NFMcjs.BLEND_MODES, 'access', _497 => _497.find, 'call', _498 => _498((m) => m.id === _chunk2VX55NFMcjs.standardBlendMode.call(void 0, mode)), 'optionalAccess', _499 => _499.label]), () => ( _chunk2VX55NFMcjs.standardBlendMode.call(void 0, mode)));
7384
7674
  const list = names.map((n) => `"${n}"`).join(", ");
7385
7675
  const one = names.length === 1;
7386
7676
  result.warnings.push(`${label} blending has no PSD equivalent; ${list} ${one ? "was" : "were"} written as ${std}, the nearest Photoshop mode, so ${one ? "it looks" : "they look"} different in Photoshop (the merged image is exact).`);
@@ -7502,7 +7792,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7502
7792
  const { src, pixels } = this.importImage(options, "The reference image");
7503
7793
  const ref2 = {
7504
7794
  id: `ref${this.nextReferenceId++}`,
7505
- name: _optionalChain([options, 'access', _422 => _422.name, 'optionalAccess', _423 => _423.trim, 'call', _424 => _424()]) || `Reference ${this.guides.references.length + 1}`,
7795
+ name: _optionalChain([options, 'access', _500 => _500.name, 'optionalAccess', _501 => _501.trim, 'call', _502 => _502()]) || `Reference ${this.guides.references.length + 1}`,
7506
7796
  src,
7507
7797
  width: pixels.width,
7508
7798
  height: pixels.height,
@@ -7581,7 +7871,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7581
7871
  try {
7582
7872
  const px = this.decodeImage(ref2.src, `Reference "${ref2.name}"`);
7583
7873
  guides.references.push({ id: ref2.id, name: String(_nullishCoalesce(ref2.name, () => ( ref2.id))), src: ref2.src, width: px.width, height: px.height, x: Number(ref2.x) || 0, y: Number(ref2.y) || 0, displayWidth: Number(ref2.displayWidth) || 240, visible: ref2.visible !== false });
7584
- const n = Number(_nullishCoalesce(_optionalChain([/^ref(\d+)$/, 'access', _425 => _425.exec, 'call', _426 => _426(ref2.id), 'optionalAccess', _427 => _427[1]]), () => ( 0)));
7874
+ const n = Number(_nullishCoalesce(_optionalChain([/^ref(\d+)$/, 'access', _503 => _503.exec, 'call', _504 => _504(ref2.id), 'optionalAccess', _505 => _505[1]]), () => ( 0)));
7585
7875
  if (n >= this.nextReferenceId) this.nextReferenceId = n + 1;
7586
7876
  } catch (e) {
7587
7877
  problems.push(e.message);
@@ -7592,7 +7882,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7592
7882
  guides.stencils = [];
7593
7883
  r.stencils.forEach((raw2, i) => {
7594
7884
  try {
7595
- const id = typeof _optionalChain([raw2, 'optionalAccess', _428 => _428.id]) === "string" && /^stencil\d+$/.test(raw2.id) ? raw2.id : `stencil${this.nextStencilId}`;
7885
+ const id = typeof _optionalChain([raw2, 'optionalAccess', _506 => _506.id]) === "string" && /^stencil\d+$/.test(raw2.id) ? raw2.id : `stencil${this.nextStencilId}`;
7596
7886
  guides.stencils.push(normalizeStencil(raw2, id));
7597
7887
  const n = Number(id.slice(7));
7598
7888
  if (n >= this.nextStencilId) this.nextStencilId = n + 1;
@@ -7615,12 +7905,12 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7615
7905
  /** The next free sticker number (ids `st<n>` are unique across the document). */
7616
7906
  nextStickerNumber(doc = this.doc) {
7617
7907
  let n = 0;
7618
- for (const list of Object.values(_nullishCoalesce(doc.stickers, () => ( {})))) for (const st of list) n = Math.max(n, Number(_nullishCoalesce(_optionalChain([/^st(\d+)$/, 'access', _429 => _429.exec, 'call', _430 => _430(st.id), 'optionalAccess', _431 => _431[1]]), () => ( 0))));
7908
+ for (const list of Object.values(_nullishCoalesce(doc.stickers, () => ( {})))) for (const st of list) n = Math.max(n, Number(_nullishCoalesce(_optionalChain([/^st(\d+)$/, 'access', _507 => _507.exec, 'call', _508 => _508(st.id), 'optionalAccess', _509 => _509[1]]), () => ( 0))));
7619
7909
  return n + 1;
7620
7910
  }
7621
7911
  stickerLayer(layerId) {
7622
7912
  const l = this.wetLayer(layerId, "edit the stickers of");
7623
- const stickers = _optionalChain([this, 'access', _432 => _432.doc, 'access', _433 => _433.stickers, 'optionalAccess', _434 => _434[l.id]]);
7913
+ const stickers = _optionalChain([this, 'access', _510 => _510.doc, 'access', _511 => _511.stickers, 'optionalAccess', _512 => _512[l.id]]);
7624
7914
  if (!stickers) throw new PaintEditorError(`Layer "${l.name}" has no stickers; spray some with a sticker brush (sticker-stars; list_brush_presets lists them).`);
7625
7915
  return { layer: l, stickers };
7626
7916
  }
@@ -7696,7 +7986,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7696
7986
  const id = _nullishCoalesce(layerId, () => ( this.doc.activeLayerId));
7697
7987
  if (!id) return [];
7698
7988
  this.requireLayer(id);
7699
- return (_nullishCoalesce(_optionalChain([this, 'access', _435 => _435.doc, 'access', _436 => _436.stickers, 'optionalAccess', _437 => _437[id]]), () => ( []))).map((s) => ({ ...s }));
7989
+ return (_nullishCoalesce(_optionalChain([this, 'access', _513 => _513.doc, 'access', _514 => _514.stickers, 'optionalAccess', _515 => _515[id]]), () => ( []))).map((s) => ({ ...s }));
7700
7990
  }
7701
7991
  /**
7702
7992
  * Replaces a layer's stickers and redraws its pixels from them (one undo step). With `dirty`,
@@ -7717,7 +8007,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7717
8007
  }
7718
8008
  /** The document from before the sticker preview on screen, or `null` when none is (anything else changed the document since). */
7719
8009
  previewBase() {
7720
- return _optionalChain([this, 'access', _438 => _438.stickerPreview, 'optionalAccess', _439 => _439.shown]) === this.doc ? this.stickerPreview.base : null;
8010
+ return _optionalChain([this, 'access', _516 => _516.stickerPreview, 'optionalAccess', _517 => _517.shown]) === this.doc ? this.stickerPreview.base : null;
7721
8011
  }
7722
8012
  readStickerUpdate(update) {
7723
8013
  try {
@@ -7732,7 +8022,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7732
8022
  const id = _nullishCoalesce(layerId, () => ( this.doc.activeLayerId));
7733
8023
  if (!id) return null;
7734
8024
  this.requireLayer(id);
7735
- const hit = stickerAt(_nullishCoalesce(_optionalChain([this, 'access', _440 => _440.doc, 'access', _441 => _441.stickers, 'optionalAccess', _442 => _442[id]]), () => ( [])), x, y, this.stickerArt.get);
8025
+ const hit = stickerAt(_nullishCoalesce(_optionalChain([this, 'access', _518 => _518.doc, 'access', _519 => _519.stickers, 'optionalAccess', _520 => _520[id]]), () => ( [])), x, y, this.stickerArt.get);
7736
8026
  return hit ? { ...hit } : null;
7737
8027
  }
7738
8028
  /** Picks a sticker for the panel and canvas (`null` for none). Editor state, not an undo step. */
@@ -7789,8 +8079,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7789
8079
  const layer = this.wetLayer(layerId, "add stickers to");
7790
8080
  if (!input.length) throw new PaintEditorError("Pass at least one sticker (ref, x, y).");
7791
8081
  if (input.length > MAX_ADD_STICKERS) throw new PaintEditorError(`At most ${MAX_ADD_STICKERS} stickers per call; split them over several calls.`);
7792
- const existing = _optionalChain([this, 'access', _443 => _443.doc, 'access', _444 => _444.stickers, 'optionalAccess', _445 => _445[layer.id]]);
7793
- if (!_optionalChain([existing, 'optionalAccess', _446 => _446.length])) {
8082
+ const existing = _optionalChain([this, 'access', _521 => _521.doc, 'access', _522 => _522.stickers, 'optionalAccess', _523 => _523[layer.id]]);
8083
+ if (!_optionalChain([existing, 'optionalAccess', _524 => _524.length])) {
7794
8084
  if (this.wet.wetLayerIds().includes(layer.id) || _chunk474IQG74cjs.contentBounds.call(void 0, layer.surface)) throw new PaintEditorError(`Layer "${layer.name}" already has paint; add stickers to an empty layer (add_layer) or a sticker layer so they stay editable.`);
7795
8085
  }
7796
8086
  let n = this.nextStickerNumber();
@@ -7807,7 +8097,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7807
8097
  const id = n++;
7808
8098
  return this.withStickerVariant({ id: `st${id}`, size: 48, rotation: 0, color: this.color, opacity: 1, seed: _nullishCoalesce(raw.seed, () => ( _chunk3K6HWEXZcjs.mix32.call(void 0, id * 2654435761 >>> 0) & 2147483647)), ...u });
7809
8099
  });
7810
- this.commitStickers("Add stickers", layer, [..._nullishCoalesce(existing, () => ( [])), ...added], _optionalChain([existing, 'optionalAccess', _447 => _447.length]) ? added.map(stickerRect) : void 0);
8100
+ this.commitStickers("Add stickers", layer, [..._nullishCoalesce(existing, () => ( [])), ...added], _optionalChain([existing, 'optionalAccess', _525 => _525.length]) ? added.map(stickerRect) : void 0);
7811
8101
  return added.map((s) => ({ ...s }));
7812
8102
  }
7813
8103
  /** Brings stickers to the top (`front`) or bottom of their layer (one undo step). */
@@ -7846,20 +8136,20 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7846
8136
  }
7847
8137
  liveStrokeLayer(layerId, what) {
7848
8138
  const l = this.wetLayer(layerId, what);
7849
- const strokes = _optionalChain([this, 'access', _448 => _448.doc, 'access', _449 => _449.liveStrokes, 'optionalAccess', _450 => _450[l.id]]);
8139
+ const strokes = _optionalChain([this, 'access', _526 => _526.doc, 'access', _527 => _527.liveStrokes, 'optionalAccess', _528 => _528[l.id]]);
7850
8140
  if (!strokes) throw new PaintEditorError(`Layer "${l.name}" is not a stroke layer; add one with add_layer {type: "strokes"} (or convert_to_stroke_layer on an empty layer), then paint on it.`);
7851
8141
  return { layer: l, strokes };
7852
8142
  }
7853
8143
  /** Whether a layer is a live stroke layer. */
7854
8144
  isLiveStrokeLayer(layerId) {
7855
- return Boolean(_optionalChain([this, 'access', _451 => _451.doc, 'access', _452 => _452.liveStrokes, 'optionalAccess', _453 => _453[layerId]]));
8145
+ return Boolean(_optionalChain([this, 'access', _529 => _529.doc, 'access', _530 => _530.liveStrokes, 'optionalAccess', _531 => _531[layerId]]));
7856
8146
  }
7857
8147
  /** Makes an empty pixel layer a live stroke layer (one undo step). */
7858
8148
  convertToLiveStrokes(layerId) {
7859
8149
  this.requireIdle("converting a layer");
7860
8150
  const l = this.paintTarget(layerId, "convert");
7861
- if (_optionalChain([this, 'access', _454 => _454.doc, 'access', _455 => _455.liveStrokes, 'optionalAccess', _456 => _456[l.id]])) return this.describeLayer(l);
7862
- if (_optionalChain([this, 'access', _457 => _457.doc, 'access', _458 => _458.stickers, 'optionalAccess', _459 => _459[l.id], 'optionalAccess', _460 => _460.length])) throw new PaintEditorError(`Layer "${l.name}" is a sticker layer; add a stroke layer instead (add_layer {type: "strokes"}).`);
8151
+ if (_optionalChain([this, 'access', _532 => _532.doc, 'access', _533 => _533.liveStrokes, 'optionalAccess', _534 => _534[l.id]])) return this.describeLayer(l);
8152
+ if (_optionalChain([this, 'access', _535 => _535.doc, 'access', _536 => _536.stickers, 'optionalAccess', _537 => _537[l.id], 'optionalAccess', _538 => _538.length])) throw new PaintEditorError(`Layer "${l.name}" is a sticker layer; add a stroke layer instead (add_layer {type: "strokes"}).`);
7863
8153
  if (_chunk474IQG74cjs.contentBounds.call(void 0, l.surface) || this.wet.wetLayerIds().includes(l.id)) throw new PaintEditorError(`Layer "${l.name}" already has paint, which isn't kept as strokes; convert an empty layer or add a stroke layer (add_layer {type: "strokes"}).`);
7864
8154
  this.commit("Convert to stroke layer", { ...this.doc, liveStrokes: { ..._nullishCoalesce(this.doc.liveStrokes, () => ( {})), [l.id]: [] } });
7865
8155
  return this.describeLayer(this.getLayer(l.id));
@@ -7872,7 +8162,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7872
8162
  findLiveStroke(id) {
7873
8163
  for (const [layerId, strokes] of Object.entries(_nullishCoalesce(this.doc.liveStrokes, () => ( {})))) {
7874
8164
  const index = strokes.findIndex((x) => x.id === id);
7875
- const layer = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, layerId), 'optionalAccess', _461 => _461.layer]);
8165
+ const layer = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, layerId), 'optionalAccess', _539 => _539.layer]);
7876
8166
  if (index >= 0 && isPixelLayer(layer)) return { layer, strokes, index };
7877
8167
  }
7878
8168
  const baked = this.doc.strokes.some((x) => x.id === id);
@@ -7892,15 +8182,15 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7892
8182
  let brush = was.brush;
7893
8183
  if (update.brushId !== void 0) {
7894
8184
  const b = this.requireBrush(update.brushId);
7895
- brush = _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, { tip: { ...b.tip, size: was.brush.tip.size } }, b);
8185
+ brush = _chunkGHGBIAWQcjs.normalizePaintBrush.call(void 0, { tip: { ...b.tip, size: was.brush.tip.size } }, b);
7896
8186
  }
7897
8187
  if (update.brush !== void 0) {
7898
8188
  if (!update.brush || typeof update.brush !== "object") throw new PaintEditorError("brush must be an object of brush settings (as set_brush takes).");
7899
- brush = _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, { ...update.brush, id: brush.id }, brush);
8189
+ brush = _chunkGHGBIAWQcjs.normalizePaintBrush.call(void 0, { ...update.brush, id: brush.id }, brush);
7900
8190
  }
7901
8191
  const why = liveStrokeRefusal(brush);
7902
8192
  if (why) throw new PaintEditorError(why);
7903
- const next = { ...was, brush: _chunkEU2ZZA6Lcjs.brushToJSON.call(void 0, brush) };
8193
+ const next = { ...was, brush: _chunkGHGBIAWQcjs.brushToJSON.call(void 0, brush) };
7904
8194
  if (update.seed !== void 0) {
7905
8195
  if (!Number.isInteger(update.seed) || update.seed < 0) throw new PaintEditorError(`seed ${update.seed} must be a whole number of 0 or more.`);
7906
8196
  next.seed = update.seed;
@@ -7911,9 +8201,10 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7911
8201
  }
7912
8202
  if (update.paint !== void 0) {
7913
8203
  if (update.paint === null) delete next.paint;
7914
- else if (_chunk56RHCIJVcjs.isPaintEffectPaint.call(void 0, update.paint)) {
7915
- if (!this.effectPaintImage(update.paint)) throw new PaintEditorError(`The effect "${update.paint.effect}" is not rendered yet; render it first (prepareEffectPaints; the update_stroke tool does this).`);
7916
- next.paint = JSON.parse(JSON.stringify(update.paint));
8204
+ else if (_chunkSNAFFCAXcjs.isPaintEffectPaint.call(void 0, update.paint)) {
8205
+ const ep = _optionalChain([update, 'access', _540 => _540.paint, 'access', _541 => _541.map, 'optionalAccess', _542 => _542.by]) === "path" ? _chunkSNAFFCAXcjs.withStrokePath.call(void 0, update.paint, next.points, this.effectPathControls.get(update.paint.effect)) : update.paint;
8206
+ if (!this.effectPaintImage(ep) && !this.renderEffectPaintSync(ep)) throw new PaintEditorError(`The effect "${update.paint.effect}" is not rendered yet; render it first (prepareEffectPaints; the update_stroke tool does this).`);
8207
+ next.paint = JSON.parse(JSON.stringify(ep));
7917
8208
  } else {
7918
8209
  const p = this.readStrokePaint(update.paint);
7919
8210
  if (p.type === "color") {
@@ -7922,7 +8213,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7922
8213
  } else next.paint = JSON.parse(JSON.stringify(p));
7923
8214
  }
7924
8215
  }
7925
- const rgb = _chunk56RHCIJVcjs.hexToRgb8.call(void 0, next.color).map((v) => v / 255);
8216
+ const rgb = _chunkSNAFFCAXcjs.hexToRgb8.call(void 0, next.color).map((v) => v / 255);
7926
8217
  const load = brushLoadForStroke(brush, _chunkNIBFKXMDcjs.EMPTY_MIXER_LOAD, rgb);
7927
8218
  if (load.reservoir || load.pickup) next.load = load;
7928
8219
  else delete next.load;
@@ -7944,13 +8235,11 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7944
8235
  if (edit.points !== void 0) {
7945
8236
  const points = this.checkPoints(edit.points);
7946
8237
  next = { ...was, points: points.map((p) => ({ ...p })) };
8238
+ if (_optionalChain([next, 'access', _543 => _543.paint, 'optionalAccess', _544 => _544.type]) === "effect" && _optionalChain([next, 'access', _545 => _545.paint, 'access', _546 => _546.map, 'optionalAccess', _547 => _547.by]) === "path") {
8239
+ next.paint = _chunkSNAFFCAXcjs.withStrokePath.call(void 0, next.paint, next.points, this.effectPathControls.get(next.paint.effect));
8240
+ }
7947
8241
  } else {
7948
- const t = edit.transform;
7949
- if (t.scale !== void 0 && !(t.scale > 0 && t.scale <= 20)) throw new PaintEditorError(`scale ${t.scale} is out of range; use above 0 up to 20.`);
7950
- for (const k of ["dx", "dy", "rotate"]) if (t[k] !== void 0 && !Number.isFinite(t[k])) throw new PaintEditorError(`${k} must be a number.`);
7951
- const b = strokeBounds(was.points);
7952
- const m = variationAffine(t, _nullishCoalesce(t.origin, () => ( { x: b.x + b.width / 2, y: b.y + b.height / 2 })));
7953
- next = varyStroke(was, m, {});
8242
+ next = varyStroke(was, this.strokeTransform(was, edit.transform), {});
7954
8243
  if (was.stencils) next.stencils = was.stencils;
7955
8244
  }
7956
8245
  const list = strokes.map((x, i) => i === index ? next : x);
@@ -7967,9 +8256,9 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7967
8256
  const layers = /* @__PURE__ */ new Map();
7968
8257
  for (const f of found) layers.set(f.layer.id, f.layer);
7969
8258
  for (const [layerId, layer] of layers) {
7970
- const gone = (_nullishCoalesce(_optionalChain([doc, 'access', _462 => _462.liveStrokes, 'optionalAccess', _463 => _463[layerId]]), () => ( []))).filter((x) => ids.includes(x.id));
8259
+ const gone = (_nullishCoalesce(_optionalChain([doc, 'access', _548 => _548.liveStrokes, 'optionalAccess', _549 => _549[layerId]]), () => ( []))).filter((x) => ids.includes(x.id));
7971
8260
  for (const x of gone) bounds = unionRect(bounds, this.strokeArea(x));
7972
- doc = this.withLiveStrokes(doc, layer, (_nullishCoalesce(_optionalChain([doc, 'access', _464 => _464.liveStrokes, 'optionalAccess', _465 => _465[layerId]]), () => ( []))).filter((x) => !ids.includes(x.id)), this.strokeAreas(gone));
8261
+ doc = this.withLiveStrokes(doc, layer, (_nullishCoalesce(_optionalChain([doc, 'access', _550 => _550.liveStrokes, 'optionalAccess', _551 => _551[layerId]]), () => ( []))).filter((x) => !ids.includes(x.id)), this.strokeAreas(gone));
7973
8262
  }
7974
8263
  this.commit(ids.length === 1 ? "Remove stroke" : "Remove strokes", doc);
7975
8264
  return { removed: [...ids], bounds };
@@ -8037,7 +8326,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
8037
8326
  }
8038
8327
  withLiveStrokes(doc, layer, list, dirty) {
8039
8328
  if (_chunkPVJMTLPJcjs.isLayerLocked.call(void 0, layer, "pixels")) throw new PaintEditorError(`Layer "${layer.name}" has its pixels locked; unlock it (update_layer locks) first.`);
8040
- const current = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, doc.layers, layer.id), 'optionalAccess', _466 => _466.layer]);
8329
+ const current = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, doc.layers, layer.id), 'optionalAccess', _552 => _552.layer]);
8041
8330
  const surface = this.drawLiveStrokes(_nullishCoalesce(current, () => ( layer)), list, dirty);
8042
8331
  const next = { ...doc, layers: _chunkPVJMTLPJcjs.mapLayer.call(void 0, doc.layers, layer.id, (l) => ({ ...l, surface, offset: { x: 0, y: 0 } })), liveStrokes: { ..._nullishCoalesce(doc.liveStrokes, () => ( {})), [layer.id]: [...list] } };
8043
8332
  return this.withPaintEvent(next, { kind: "live-strokes", layerId: layer.id, data: { strokes: list.map((x) => JSON.parse(JSON.stringify(x))) } });
@@ -8115,7 +8404,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
8115
8404
  if (!this.animatedLayers.size) return this.doc.layers;
8116
8405
  let layers = this.doc.layers;
8117
8406
  for (const [id, a] of this.animatedLayers) {
8118
- const l = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, layers, id), 'optionalAccess', _467 => _467.layer]);
8407
+ const l = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, layers, id), 'optionalAccess', _553 => _553.layer]);
8119
8408
  if (isPixelLayer(l) && l.surface === a.base) layers = _chunkPVJMTLPJcjs.mapLayer.call(void 0, layers, id, () => ({ ...l, surface: a.surface }));
8120
8409
  }
8121
8410
  return layers;
@@ -8125,11 +8414,11 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
8125
8414
  const layers = [];
8126
8415
  const sources = /* @__PURE__ */ new Map();
8127
8416
  for (const [id, strokes] of Object.entries(_nullishCoalesce(doc.liveStrokes, () => ( {})))) {
8128
- const layer = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, doc.layers, id), 'optionalAccess', _468 => _468.layer]);
8417
+ const layer = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, doc.layers, id), 'optionalAccess', _554 => _554.layer]);
8129
8418
  const live = strokes.filter(isLiveEffect);
8130
8419
  if (!isPixelLayer(layer) || !live.length) continue;
8131
8420
  layers.push({ layer, strokes });
8132
- for (const st of live) sources.set(_chunk56RHCIJVcjs.effectPaintKey.call(void 0, st.paint), st.paint);
8421
+ for (const st of live) sources.set(_chunkSNAFFCAXcjs.effectPaintKey.call(void 0, st.paint), st.paint);
8133
8422
  }
8134
8423
  return { layers, sources: [...sources.values()] };
8135
8424
  }
@@ -8250,13 +8539,13 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
8250
8539
  return this.withEffectTime(time, () => this.compositePixels(options));
8251
8540
  }
8252
8541
  // --- Stencils --------------------------------------------------------------------
8253
- __init132() {this.stencilCache = null}
8254
- __init133() {this.nextStencilId = 1}
8542
+ __init136() {this.stencilCache = null}
8543
+ __init137() {this.nextStencilId = 1}
8255
8544
  /** The mask stencils' coverage over the canvas (cached), or `null` when none masks. */
8256
8545
  stencilSelection(stencils = this.guides.stencils) {
8257
8546
  const { width, height } = this.doc.canvas;
8258
8547
  const size = `${width}x${height}`;
8259
- if (_optionalChain([this, 'access', _469 => _469.stencilCache, 'optionalAccess', _470 => _470.key]) === stencils && this.stencilCache.size === size) return this.stencilCache.mask;
8548
+ if (_optionalChain([this, 'access', _555 => _555.stencilCache, 'optionalAccess', _556 => _556.key]) === stencils && this.stencilCache.size === size) return this.stencilCache.mask;
8260
8549
  const mask = stencilMask(stencils, width, height);
8261
8550
  this.stencilCache = { key: stencils, size, mask };
8262
8551
  return mask;
@@ -8318,7 +8607,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
8318
8607
  makeSwatch(color, name) {
8319
8608
  const p = typeof color === "string" ? { type: "color", color: parseColor(color) } : this.readStrokePaint(color);
8320
8609
  const out = { color: _chunkNIBFKXMDcjs.paintSourceColor.call(void 0, p, { paint: this.color, secondary: this.secondaryColor }) };
8321
- if (_optionalChain([name, 'optionalAccess', _471 => _471.trim, 'call', _472 => _472()])) out.name = name.trim();
8610
+ if (_optionalChain([name, 'optionalAccess', _557 => _557.trim, 'call', _558 => _558()])) out.name = name.trim();
8322
8611
  if (p.type === "gradient") out.paint = p;
8323
8612
  return out;
8324
8613
  }
@@ -8370,7 +8659,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
8370
8659
  * mix becomes the paint colour. Returns the mixed colour and the pile's bounds.
8371
8660
  */
8372
8661
  mixOnPad(paints2, options = {}) {
8373
- const parsed = (_nullishCoalesce(paints2, () => ( []))).map((p, i) => ({ color: parseColor(_optionalChain([p, 'optionalAccess', _473 => _473.color]), `paints[${i}].color`), parts: _optionalChain([p, 'optionalAccess', _474 => _474.parts]) }));
8662
+ const parsed = (_nullishCoalesce(paints2, () => ( []))).map((p, i) => ({ color: parseColor(_optionalChain([p, 'optionalAccess', _559 => _559.color]), `paints[${i}].color`), parts: _optionalChain([p, 'optionalAccess', _560 => _560.parts]) }));
8374
8663
  let r;
8375
8664
  try {
8376
8665
  r = this.pad.mix(parsed, options);
@@ -8459,7 +8748,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
8459
8748
  }
8460
8749
  /** A layer's tile surface (live while stroking), for thumbnails. */
8461
8750
  layerSurface(id) {
8462
- const l = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.currentLayers(), id), 'optionalAccess', _475 => _475.layer]);
8751
+ const l = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.currentLayers(), id), 'optionalAccess', _561 => _561.layer]);
8463
8752
  return isPixelLayer(l) ? l.surface : null;
8464
8753
  }
8465
8754
  }, _class14.__initStatic(), _class14);
@@ -8481,7 +8770,7 @@ function insertAfter(layers, id, node) {
8481
8770
  return layers.map((l) => l.type === "group" ? { ...l, children: insertAfter(l.children, id, node) } : l);
8482
8771
  }
8483
8772
  function isLiveEffect(s) {
8484
- return _optionalChain([s, 'access', _476 => _476.paint, 'optionalAccess', _477 => _477.type]) === "effect" && s.paint.live === true;
8773
+ return _optionalChain([s, 'access', _562 => _562.paint, 'optionalAccess', _563 => _563.type]) === "effect" && s.paint.live === true;
8485
8774
  }
8486
8775
  function framePaint(p, t) {
8487
8776
  return { ...p, time: p.time + t };
@@ -8506,7 +8795,7 @@ function clipRect(r, width, height) {
8506
8795
  return x1 > x0 && y1 > y0 ? { x: x0, y: y0, width: x1 - x0, height: y1 - y0 } : null;
8507
8796
  }
8508
8797
  function withLiveStroke(doc, stroke) {
8509
- const list = _optionalChain([doc, 'access', _478 => _478.liveStrokes, 'optionalAccess', _479 => _479[stroke.layerId]]);
8798
+ const list = _optionalChain([doc, 'access', _564 => _564.liveStrokes, 'optionalAccess', _565 => _565[stroke.layerId]]);
8510
8799
  return list ? { ...doc, liveStrokes: { ...doc.liveStrokes, [stroke.layerId]: [...list, stroke] } } : doc;
8511
8800
  }
8512
8801
  function shiftDocument(doc, dx, dy) {
@@ -8533,9 +8822,9 @@ function shiftDocument(doc, dx, dy) {
8533
8822
  if (doc.liveStrokes) out.liveStrokes = Object.fromEntries(Object.entries(doc.liveStrokes).map(([id, list]) => [id, list.map(moveStroke)]));
8534
8823
  if (doc.paintEvents) {
8535
8824
  out.paintEvents = doc.paintEvents.map((e) => {
8536
- const list = e.kind === "stickers" ? _optionalChain([e, 'access', _480 => _480.data, 'optionalAccess', _481 => _481.stickers]) : void 0;
8825
+ const list = e.kind === "stickers" ? _optionalChain([e, 'access', _566 => _566.data, 'optionalAccess', _567 => _567.stickers]) : void 0;
8537
8826
  if (list) return { ...e, data: { ...e.data, stickers: moveStickers(list) } };
8538
- const strokes = e.kind === "live-strokes" ? _optionalChain([e, 'access', _482 => _482.data, 'optionalAccess', _483 => _483.strokes]) : void 0;
8827
+ const strokes = e.kind === "live-strokes" ? _optionalChain([e, 'access', _568 => _568.data, 'optionalAccess', _569 => _569.strokes]) : void 0;
8539
8828
  return strokes ? { ...e, data: { ...e.data, strokes: strokes.map(moveStroke) } } : e;
8540
8829
  });
8541
8830
  }
@@ -8606,6 +8895,19 @@ function clipToCanvas(rect, canvas) {
8606
8895
  const y1 = Math.min(canvas.height, rect.y + rect.height);
8607
8896
  return x1 > x0 && y1 > y0 ? { x: x0, y: y0, width: x1 - x0, height: y1 - y0 } : null;
8608
8897
  }
8898
+ function toEffectPaintPixels(p, pixels) {
8899
+ return { width: pixels.width, height: pixels.height, data: new Uint8ClampedArray(pixels.data), ..._optionalChain([p, 'access', _570 => _570.map, 'optionalAccess', _571 => _571.by]) === "stroke" ? { map: p.map } : {} };
8900
+ }
8901
+ function readWetGhost(raw) {
8902
+ if (!raw || typeof raw !== "object") return null;
8903
+ const g = raw;
8904
+ if (!Array.isArray(g.pigment) || g.pigment.length !== 4 || !g.pigment.every((x) => typeof x === "number" && Number.isFinite(x))) return null;
8905
+ const remaining = typeof g.remaining === "number" && Number.isFinite(g.remaining) ? Math.max(0, Math.round(g.remaining)) : 0;
8906
+ if (remaining <= 0) return null;
8907
+ const total = typeof g.total === "number" && Number.isFinite(g.total) ? Math.max(1, Math.round(g.total)) : remaining;
8908
+ const linger = typeof g.linger === "number" && Number.isFinite(g.linger) ? Math.max(0.5, Math.min(60, g.linger)) : 4;
8909
+ return { pigment: [g.pigment[0], g.pigment[1], g.pigment[2], g.pigment[3]], remaining, total, linger };
8910
+ }
8609
8911
 
8610
8912
  // src/paint-editor/presence.ts
8611
8913
  var PaintPresence = class extends _chunkK7ENM55Pcjs.PresenceStore {
@@ -8624,8 +8926,8 @@ function strokeSchedule(points) {
8624
8926
  return total > 0 ? acc.map((d) => d / total) : points.map(() => 1);
8625
8927
  }
8626
8928
  function strokeDuration(points, max = 1800) {
8627
- const t0 = _optionalChain([points, 'access', _484 => _484[0], 'optionalAccess', _485 => _485.t]);
8628
- const t1 = _optionalChain([points, 'access', _486 => _486[points.length - 1], 'optionalAccess', _487 => _487.t]);
8929
+ const t0 = _optionalChain([points, 'access', _572 => _572[0], 'optionalAccess', _573 => _573.t]);
8930
+ const t1 = _optionalChain([points, 'access', _574 => _574[points.length - 1], 'optionalAccess', _575 => _575.t]);
8629
8931
  let ms;
8630
8932
  if (points.every((p) => Number.isFinite(p.t)) && t1 > t0) ms = t1 - t0;
8631
8933
  else {
@@ -8679,7 +8981,7 @@ var PaintDirector = class {
8679
8981
  }
8680
8982
  where(id) {
8681
8983
  const a = this.presence.get(id);
8682
- return { x: _nullishCoalesce(_optionalChain([a, 'optionalAccess', _488 => _488.x]), () => ( 0)), y: _nullishCoalesce(_optionalChain([a, 'optionalAccess', _489 => _489.y]), () => ( 0)) };
8984
+ return { x: _nullishCoalesce(_optionalChain([a, 'optionalAccess', _576 => _576.x]), () => ( 0)), y: _nullishCoalesce(_optionalChain([a, 'optionalAccess', _577 => _577.y]), () => ( 0)) };
8683
8985
  }
8684
8986
  /** Glides to `to`; an actor that just appeared starts there instead of the corner. */
8685
8987
  async glide(id, to, ms = 380) {
@@ -8729,8 +9031,8 @@ var PaintDirector = class {
8729
9031
  }
8730
9032
  case "replay": {
8731
9033
  await this.say(id, command.note, 500);
8732
- const source = c.getStrokes().filter((s) => _optionalChain([command, 'access', _490 => _490.replay, 'access', _491 => _491.strokeIds, 'optionalAccess', _492 => _492.includes, 'call', _493 => _493(s.id)]));
8733
- const first = _optionalChain([source, 'access', _494 => _494[0], 'optionalAccess', _495 => _495.points, 'access', _496 => _496[0]]);
9034
+ const source = c.getStrokes().filter((s) => _optionalChain([command, 'access', _578 => _578.replay, 'access', _579 => _579.strokeIds, 'optionalAccess', _580 => _580.includes, 'call', _581 => _581(s.id)]));
9035
+ const first = _optionalChain([source, 'access', _582 => _582[0], 'optionalAccess', _583 => _583.points, 'access', _584 => _584[0]]);
8734
9036
  if (first) await this.glide(id, first);
8735
9037
  const result = c.replayStrokes(command.replay);
8736
9038
  if (result.bounds) await this.glide(id, centre(result.bounds), 520);
@@ -8778,7 +9080,7 @@ var PaintDirector = class {
8778
9080
  const checked = inits.map((s) => ({ ...s, points: c.checkPoints(s.points) }));
8779
9081
  const first = checked[0];
8780
9082
  const base = first.brushId ? c.getBrush(first.brushId) : c.getState().brush;
8781
- const stepLabel = _nullishCoalesce(label, () => ( `${_nullishCoalesce(_optionalChain([base, 'optionalAccess', _497 => _497.name]), () => ( "Brush"))} path stroke`));
9083
+ const stepLabel = _nullishCoalesce(label, () => ( `${_nullishCoalesce(_optionalChain([base, 'optionalAccess', _585 => _585.name]), () => ( "Brush"))} path stroke`));
8782
9084
  return c.group(stepLabel, async (within) => {
8783
9085
  let layerId = _nullishCoalesce(_nullishCoalesce(first.layerId, () => ( c.document.activeLayerId)), () => ( ""));
8784
9086
  let bounds = null;
@@ -8798,8 +9100,8 @@ var PaintDirector = class {
8798
9100
  bounds,
8799
9101
  dabs,
8800
9102
  strokeIds,
8801
- ..._optionalChain([last, 'optionalAccess', _498 => _498.mixerLoad]) ? { mixerLoad: last.mixerLoad } : {},
8802
- ..._optionalChain([last, 'optionalAccess', _499 => _499.wet]) !== void 0 ? { wet: last.wet } : {}
9103
+ ..._optionalChain([last, 'optionalAccess', _586 => _586.mixerLoad]) ? { mixerLoad: last.mixerLoad } : {},
9104
+ ..._optionalChain([last, 'optionalAccess', _587 => _587.wet]) !== void 0 ? { wet: last.wet } : {}
8803
9105
  };
8804
9106
  });
8805
9107
  }
@@ -9528,7 +9830,7 @@ function createPaintWetTools(c) {
9528
9830
  {
9529
9831
  name: "get_wet_paint",
9530
9832
  title: "Get the wet paint",
9531
- description: "Reads the wet media: whether any paint is still wet, the simulation clock (steps), whether time is paused, its speed (steps per second), the canvas tilt, the kernel running it (typescript, wasm, wasm-threads with the thread count, and a message when it runs slower than it could, e.g. without cross-origin isolation), and each wet layer: wet cells, where the water is (wetBounds), live tiles, its settings and flow map. Also engine: Engine B, the GPU accelerator: WebGPU in browsers, Metal in the Swift editors (mode auto/off, state, reason, adapter, minTiles, activeTiles). Call it after wet strokes to see what is still wet.",
9833
+ description: "Reads the wet media: whether any paint is still wet, the simulation clock (steps), whether time is paused, its speed (steps per second), the canvas tilt, the kernel running it (typescript, wasm, wasm-threads with the thread count, and a message when it runs slower than it could, e.g. without cross-origin isolation), and each wet layer: wet cells, where the water is (wetBounds), live tiles, its settings, flow map, and ghost: { remaining } (seconds of simulated time left when ghost paint is fading on the layer). Also engine: Engine B, the GPU accelerator: WebGPU in browsers, Metal in the Swift editors (mode auto/off, state, reason, adapter, minTiles, activeTiles). Call it after wet strokes to see what is still wet.",
9532
9834
  inputSchema: EMPTY2,
9533
9835
  annotations: { title: "Get the wet paint", ...READ3 },
9534
9836
  coordinates: { out: ["layers[].wetBounds", "layers[].flow.center"] },
@@ -9599,7 +9901,7 @@ function createPaintWetTools(c) {
9599
9901
  type: "object",
9600
9902
  properties: {
9601
9903
  layerId: LAYER_ID2,
9602
- kind: { type: "string", enum: [..._chunkJ5VQYK7Tcjs.WET_FLOW_KINDS], description: "none, linear, swirl, radial or turbulent." },
9904
+ kind: { type: "string", enum: [..._chunkN5IMDAHMcjs.WET_FLOW_KINDS], description: "none, linear, swirl, radial or turbulent." },
9603
9905
  strength: UNIT("How hard it pushes, 0..1 (1 is about a 25\xB0 tilt; default 0.5)."),
9604
9906
  angle: { type: "number", minimum: -360, maximum: 360, description: "linear: direction in degrees clockwise from canvas down (default 0)." },
9605
9907
  center: {
@@ -9971,8 +10273,8 @@ function createPaintEditorToolProvider(controller, options = {}) {
9971
10273
  inputSchema: EMPTY3,
9972
10274
  annotations: { title: "List papers", ...READ6 },
9973
10275
  handler: () => ({
9974
- papers: _chunk56RHCIJVcjs.PAPER_LIBRARY.map((p) => ({ id: p.preset, name: p.name, family: p.family, pattern: p.pattern, color: p.color, depth: p.depth, absorption: p.absorption, permeability: p.permeability, roughness: p.roughness })),
9975
- families: [..._chunk56RHCIJVcjs.PAPER_FAMILIES],
10276
+ papers: _chunkSNAFFCAXcjs.PAPER_LIBRARY.map((p) => ({ id: p.preset, name: p.name, family: p.family, pattern: p.pattern, color: p.color, depth: p.depth, absorption: p.absorption, permeability: p.permeability, roughness: p.roughness })),
10277
+ families: [..._chunkSNAFFCAXcjs.PAPER_FAMILIES],
9976
10278
  patterns: [..._chunkNIBFKXMDcjs.GRAIN_PATTERNS]
9977
10279
  })
9978
10280
  });
@@ -10204,10 +10506,10 @@ function createPaintEditorToolProvider(controller, options = {}) {
10204
10506
  name: "set_brush",
10205
10507
  title: "Set the brush",
10206
10508
  description: "Chooses the active brush (id, from list_brush_presets) and / or changes it with facets laid over it (objects merge, lists and values replace, marks of another kind replace the marks; the brush library's create_brush fields); unset removes whole facets first (unset colour drops a brush's own gradient). Strokes without a brush use it. Editor state, not an undo step: the changes stay on the active brush until the library's create_brush or update_brush stores a brush. Returns the active brush as facets, the engine it paints with, and problems (values clamped or dropped).",
10207
- inputSchema: { type: "object", properties: { id: { type: "string", description: "Brush id from list_brush_presets to start from (default the active brush)." }, name: { type: "string", minLength: 1, maxLength: 80, description: "Display name." }, ..._chunk3KNQ2W6Xcjs.BRUSH_PATCH_PROPERTIES, unset: _chunk3KNQ2W6Xcjs.BRUSH_UNSET_PROPERTY }, additionalProperties: false },
10509
+ inputSchema: { type: "object", properties: { id: { type: "string", description: "Brush id from list_brush_presets to start from (default the active brush)." }, name: { type: "string", minLength: 1, maxLength: 80, description: "Display name." }, ..._chunk3JKCREEUcjs.BRUSH_PATCH_PROPERTIES, unset: _chunk3JKCREEUcjs.BRUSH_UNSET_PROPERTY }, additionalProperties: false },
10208
10510
  annotations: { title: "Set the brush", ...SET4 },
10209
10511
  handler: async ({ id, unset, ...patch }) => {
10210
- const stamps = _optionalChain([patch, 'access', _500 => _500.tip, 'optionalAccess', _501 => _501.stamps]);
10512
+ const stamps = _optionalChain([patch, 'access', _588 => _588.tip, 'optionalAccess', _589 => _589.stamps]);
10211
10513
  if (stamps) await c.prepareStickers(stamps);
10212
10514
  const r = c.setBrushFacets(patch, id, unset);
10213
10515
  return { brush: r.spec, engine: r.brush.engine, problems: r.problems };
@@ -10300,7 +10602,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
10300
10602
  points: POINTS,
10301
10603
  layerId: LAYER_ID4,
10302
10604
  brushId: { type: "string", description: "Brush id from list_brush_presets (default the active brush)." },
10303
- brush: { type: "object", description: "Facets to change for this stroke only, laid over brushId or the active brush (as set_brush takes them).", properties: _chunk3KNQ2W6Xcjs.BRUSH_PATCH_PROPERTIES, additionalProperties: false },
10605
+ brush: { type: "object", description: "Facets to change for this stroke only, laid over brushId or the active brush (as set_brush takes them).", properties: _chunk3JKCREEUcjs.BRUSH_PATCH_PROPERTIES, additionalProperties: false },
10304
10606
  color: { ...COLOR3, description: "Paint colour #rrggbb (default the paint colour)." },
10305
10607
  paint: { ..._chunkNIBFKXMDcjs.PAINT_SOURCE_JSON_SCHEMA, description: "What this stroke paints with instead of the editor's paint: a colour, or gradient paint that changes colour as the stroke goes (by distance, pressure, tilt, speed, direction, time, across the tip or at random). Wins over the brush's own gradient." },
10306
10608
  seed: { type: "integer", minimum: 0, description: "Jitter seed (default a new one); the same seed and points give the same marks." },
@@ -10316,10 +10618,11 @@ function createPaintEditorToolProvider(controller, options = {}) {
10316
10618
  const base = a.brushId ? c.getBrush(a.brushId) : c.getState().brush;
10317
10619
  const brush = a.brush ? c.brushChanges(a.brush, a.brushId) : void 0;
10318
10620
  if (base) {
10319
- const refs = _chunk56RHCIJVcjs.brushStickerRefs.call(void 0, _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, { ..._nullishCoalesce(brush, () => ( {})), id: base.id }, base));
10621
+ const refs = _chunkSNAFFCAXcjs.brushStickerRefs.call(void 0, _chunkGHGBIAWQcjs.normalizePaintBrush.call(void 0, { ..._nullishCoalesce(brush, () => ( {})), id: base.id }, base));
10320
10622
  if (refs.length) await c.prepareStickers(refs);
10321
10623
  }
10322
10624
  const stroke = { points: a.points, layerId: a.layerId, brushId: a.brushId, brush, color: a.color, paint: a.paint, seed: a.seed, snapToPerspective: a.snapToPerspective };
10625
+ await c.prepareStrokePathEffect(stroke, [stroke.points]);
10323
10626
  const r = await act({ kind: "stroke", stroke }, () => c.paintStroke(stroke));
10324
10627
  return r.mixerLoad ? { ...r, mixerLoad: loadResult(r.mixerLoad) } : r;
10325
10628
  }
@@ -10337,7 +10640,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
10337
10640
  speed: { type: "number", minimum: 0.01, maximum: 100, description: "Drawing speed in document pixels per millisecond (optional; gives each sample a time t so playback has a pace and speed-sensitive brushes respond)." },
10338
10641
  layerId: LAYER_ID4,
10339
10642
  brushId: { type: "string", description: "Brush id from list_brush_presets (default the active brush)." },
10340
- brush: { type: "object", description: "Facets to change for this stroke only, laid over brushId or the active brush (as set_brush takes them).", properties: _chunk3KNQ2W6Xcjs.BRUSH_PATCH_PROPERTIES, additionalProperties: false },
10643
+ brush: { type: "object", description: "Facets to change for this stroke only, laid over brushId or the active brush (as set_brush takes them).", properties: _chunk3JKCREEUcjs.BRUSH_PATCH_PROPERTIES, additionalProperties: false },
10341
10644
  color: { ...COLOR3, description: "Paint colour #rrggbb (default the paint colour)." },
10342
10645
  paint: { ..._chunkNIBFKXMDcjs.PAINT_SOURCE_JSON_SCHEMA, description: "What the strokes paint with instead of the editor's paint: a colour, or gradient paint that changes colour as each stroke goes." },
10343
10646
  seed: { type: "integer", minimum: 0, description: "Jitter seed of the first subpath, the next ones take the following seeds (default new ones); the same seed and path give the same marks." }
@@ -10352,11 +10655,18 @@ function createPaintEditorToolProvider(controller, options = {}) {
10352
10655
  const base = a.brushId ? c.getBrush(a.brushId) : c.getState().brush;
10353
10656
  const brush = a.brush ? c.brushChanges(a.brush, a.brushId) : void 0;
10354
10657
  if (base) {
10355
- const refs = _chunk56RHCIJVcjs.brushStickerRefs.call(void 0, _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, { ..._nullishCoalesce(brush, () => ( {})), id: base.id }, base));
10658
+ const refs = _chunkSNAFFCAXcjs.brushStickerRefs.call(void 0, _chunkGHGBIAWQcjs.normalizePaintBrush.call(void 0, { ..._nullishCoalesce(brush, () => ( {})), id: base.id }, base));
10356
10659
  if (refs.length) await c.prepareStickers(refs);
10357
10660
  }
10358
10661
  const path = options.origin && typeof a.path === "string" && a.path.trim() ? _chunkGF2RBSDMcjs.bezierPathToSvg.call(void 0, a.path, { offset: { x: -options.origin.x, y: -options.origin.y } }) : a.path;
10359
10662
  const init = { path, spacing: a.spacing, pressure: a.pressure, speed: a.speed, layerId: a.layerId, brushId: a.brushId, brush, color: a.color, paint: a.paint, seed: a.seed };
10663
+ if (typeof path === "string" && path.trim()) {
10664
+ try {
10665
+ const sampled = samplePath(path, init);
10666
+ await c.prepareStrokePathEffect(init, sampled);
10667
+ } catch (e12) {
10668
+ }
10669
+ }
10360
10670
  const r = await act(
10361
10671
  () => {
10362
10672
  if (typeof path !== "string" || !path.trim()) throw new PaintEditorError('path is empty; give SVG path data in document pixels, e.g. "M 10 10 C 40 0 80 60 120 30".');
@@ -10369,7 +10679,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
10369
10679
  const { path: _path, spacing: _spacing, pressure: _pressure, speed: _speed, ...stroke } = init;
10370
10680
  return {
10371
10681
  kind: "strokes",
10372
- label: `${_nullishCoalesce(_optionalChain([base, 'optionalAccess', _502 => _502.name]), () => ( "Brush"))} path stroke`,
10682
+ label: `${_nullishCoalesce(_optionalChain([base, 'optionalAccess', _590 => _590.name]), () => ( "Brush"))} path stroke`,
10373
10683
  strokes: subpaths.map((points, i) => ({
10374
10684
  ...stroke,
10375
10685
  ...stroke.seed !== void 0 ? { seed: stroke.seed + i } : {},
@@ -10426,7 +10736,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
10426
10736
  if (ids) {
10427
10737
  for (const id of ids) if (!all.some((s) => s.id === id)) throw new Error(`Unknown stroke "${id}". Call list_strokes without ids for the ids.`);
10428
10738
  }
10429
- return { total: all.length, strokes: picked.map((s) => strokeSummary(s, Boolean(ids), live ? true : liveIds.has(s.id) && _optionalChain([c, 'access', _503 => _503.document, 'access', _504 => _504.liveStrokes, 'optionalAccess', _505 => _505[s.layerId], 'optionalAccess', _506 => _506.includes, 'call', _507 => _507(s)]) === true)) };
10739
+ return { total: all.length, strokes: picked.map((s) => strokeSummary(s, Boolean(ids), live ? true : liveIds.has(s.id) && _optionalChain([c, 'access', _591 => _591.document, 'access', _592 => _592.liveStrokes, 'optionalAccess', _593 => _593[s.layerId], 'optionalAccess', _594 => _594.includes, 'call', _595 => _595(s)]) === true)) };
10430
10740
  }
10431
10741
  });
10432
10742
  add({
@@ -10459,7 +10769,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
10459
10769
  properties: {
10460
10770
  id: { type: "string", description: "Stroke id from list_strokes {live: true}." },
10461
10771
  brushId: { type: "string", description: "Brush id from list_brush_presets; the stroke keeps its size." },
10462
- brush: { type: "object", properties: _chunk3KNQ2W6Xcjs.BRUSH_PATCH_PROPERTIES, additionalProperties: false, description: "Facets to change on top of brushId or the stroke\u2019s brush (as set_brush takes them); missing fields keep their values." },
10772
+ brush: { type: "object", properties: _chunk3JKCREEUcjs.BRUSH_PATCH_PROPERTIES, additionalProperties: false, description: "Facets to change on top of brushId or the stroke\u2019s brush (as set_brush takes them); missing fields keep their values." },
10463
10773
  color: { type: "string", pattern: "^#[0-9a-fA-F]{6}$", description: "New colour #rrggbb (replaces gradient paint)." },
10464
10774
  paint: { anyOf: [_chunkNIBFKXMDcjs.PAINT_SOURCE_JSON_SCHEMA, { type: "null", description: "Back to the stroke\u2019s plain colour." }], description: "A colour or gradient paint for the stroke; null drops its gradient." },
10465
10775
  seed: { type: "integer", minimum: 0, description: "Another jitter seed: particles, scatter and texture fall differently." }
@@ -10508,7 +10818,8 @@ function createPaintEditorToolProvider(controller, options = {}) {
10508
10818
  },
10509
10819
  annotations: { title: "Move or reshape a stroke", ...WRITE5 },
10510
10820
  coordinates: { in: ["points[]", "transform.origin"], out: ["bounds", "stroke.bounds", "stroke.points[]"] },
10511
- handler: ({ id, points, transform }) => {
10821
+ handler: async ({ id, points, transform }) => {
10822
+ await c.prepareStrokeEdit(id, { points, transform });
10512
10823
  const r = c.editStrokePoints(id, { points, transform });
10513
10824
  return { stroke: strokeSummary(r.stroke, true, true), bounds: r.bounds };
10514
10825
  }
@@ -10591,7 +10902,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
10591
10902
  coordinates: { in: ["origin"], out: ["bounds"] },
10592
10903
  handler: async (a) => {
10593
10904
  const replay = a;
10594
- if (replay.color === void 0) await c.prepareStrokeEffects(replay.strokeIds);
10905
+ if (replay.color === void 0) await c.prepareStrokeEffects(replay.strokeIds, replay);
10595
10906
  return act({ kind: "replay", replay }, () => c.replayStrokes(replay));
10596
10907
  }
10597
10908
  });
@@ -10710,7 +11021,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
10710
11021
  tools.push(..._chunk62MFUHSIcjs.createPigmentTools.call(void 0, ));
10711
11022
  tools.push(..._chunkPFHJS4HEcjs.createStickerTools.call(void 0, { provider: () => c.stickersProvider }));
10712
11023
  tools.push(
10713
- ..._chunk4NMPUJUKcjs.createLayerEffectTools.call(void 0,
11024
+ ..._chunkYJANF2BLcjs.createLayerEffectTools.call(void 0,
10714
11025
  {
10715
11026
  requireLayer: (id) => void c.getLayerEffects(id),
10716
11027
  getLayerEffects: (id) => c.getLayerEffects(id),
@@ -10735,16 +11046,16 @@ function createPaintEditorToolProvider(controller, options = {}) {
10735
11046
  }
10736
11047
  function hostTool({ coordinates, ...tool }, { origin, onChange }) {
10737
11048
  if (!origin && !onChange) return tool;
10738
- const write = !_optionalChain([tool, 'access', _508 => _508.annotations, 'optionalAccess', _509 => _509.readOnlyHint]);
11049
+ const write = !_optionalChain([tool, 'access', _596 => _596.annotations, 'optionalAccess', _597 => _597.readOnlyHint]);
10739
11050
  const done = (result) => {
10740
- if (write) _optionalChain([onChange, 'optionalCall', _510 => _510({ tool: tool.name })]);
10741
- return origin && _optionalChain([coordinates, 'optionalAccess', _511 => _511.out]) ? fromDocument(result, coordinates.out, origin) : result;
11051
+ if (write) _optionalChain([onChange, 'optionalCall', _598 => _598({ tool: tool.name })]);
11052
+ return origin && _optionalChain([coordinates, 'optionalAccess', _599 => _599.out]) ? fromDocument(result, coordinates.out, origin) : result;
10742
11053
  };
10743
11054
  return {
10744
11055
  ...tool,
10745
11056
  ...origin ? { description: hostedText(_nullishCoalesce(tool.description, () => ( ""))), inputSchema: hostedSchema(tool.inputSchema) } : {},
10746
11057
  handler: (args, context) => {
10747
- const r = tool.handler(origin && _optionalChain([coordinates, 'optionalAccess', _512 => _512.in]) ? toDocument(args, coordinates.in, origin) : args, context);
11058
+ const r = tool.handler(origin && _optionalChain([coordinates, 'optionalAccess', _600 => _600.in]) ? toDocument(args, coordinates.in, origin) : args, context);
10748
11059
  return r instanceof Promise ? r.then(done) : done(r);
10749
11060
  }
10750
11061
  };
@@ -10761,23 +11072,23 @@ function strokeSummary(s, withPoints, live) {
10761
11072
  color: s.color,
10762
11073
  points: withPoints ? s.points : s.points.length,
10763
11074
  seed: s.seed,
10764
- copies: _nullishCoalesce(_optionalChain([s, 'access', _513 => _513.copies, 'optionalAccess', _514 => _514.length]), () => ( 0)),
11075
+ copies: _nullishCoalesce(_optionalChain([s, 'access', _601 => _601.copies, 'optionalAccess', _602 => _602.length]), () => ( 0)),
10765
11076
  live,
10766
11077
  bounds: { x: Math.floor(Math.min(...xs) - pad), y: Math.floor(Math.min(...ys) - pad), width: Math.ceil(Math.max(...xs) - Math.min(...xs) + 2 * pad), height: Math.ceil(Math.max(...ys) - Math.min(...ys) + 2 * pad) }
10767
11078
  };
10768
11079
  }
10769
11080
 
10770
11081
  // src/paint-editor/brush-library-tools.ts
10771
- function paintBrushPreviewRenderer(paper = () => _chunk56RHCIJVcjs.DEFAULT_PAPER, options = {}) {
11082
+ function paintBrushPreviewRenderer(paper = () => _chunkSNAFFCAXcjs.DEFAULT_PAPER, options = {}) {
10772
11083
  const sources = new BrushSourceArtCache();
10773
11084
  const draw = (brush, { width, height, color }) => {
10774
- const stickers = _optionalChain([options, 'access', _515 => _515.stampArt, 'optionalCall', _516 => _516()]);
11085
+ const stickers = _optionalChain([options, 'access', _603 => _603.stampArt, 'optionalCall', _604 => _604()]);
10775
11086
  const stampArt = sources.with(_nullishCoalesce(stickers, () => ( (() => void 0))));
10776
- const t = renderBrushThumbnail(_chunkEU2ZZA6Lcjs.resolveBrush.call(void 0, brush), { paper: paper(), width, height, color: color.toLowerCase(), stampArt });
11087
+ const t = renderBrushThumbnail(_chunkGHGBIAWQcjs.resolveBrush.call(void 0, brush), { paper: paper(), width, height, color: color.toLowerCase(), stampArt });
10777
11088
  return { data: _chunkW5M3J7PVcjs.bytesToBase64.call(void 0, _chunkW5M3J7PVcjs.encodePng.call(void 0, t.width, t.height, t.data)), mimeType: "image/png" };
10778
11089
  };
10779
11090
  const render = (brush, size) => {
10780
- const ids = _chunkEU2ZZA6Lcjs.brushSourceIds.call(void 0, brush);
11091
+ const ids = _chunkGHGBIAWQcjs.brushSourceIds.call(void 0, brush);
10781
11092
  if (!ids.length || !options.library) return draw(brush, size);
10782
11093
  const library = options.library;
10783
11094
  return Promise.all(ids.map((id) => library.getSource(id))).then((found) => {
@@ -10788,8 +11099,8 @@ function paintBrushPreviewRenderer(paper = () => _chunk56RHCIJVcjs.DEFAULT_PAPER
10788
11099
  return Object.defineProperty(render, "paper", { get: () => paper().color, enumerable: true });
10789
11100
  }
10790
11101
  function createPaintBrushLibraryToolProvider(controller, options = {}) {
10791
- return _chunk3KNQ2W6Xcjs.createBrushLibraryToolProvider.call(void 0, controller.brushLibrary, {
10792
- profile: _chunkEU2ZZA6Lcjs.PAINT_PROFILE,
11102
+ return _chunk3JKCREEUcjs.createBrushLibraryToolProvider.call(void 0, controller.brushLibrary, {
11103
+ profile: _chunkGHGBIAWQcjs.PAINT_PROFILE,
10793
11104
  stickers: () => controller.stickers.provider,
10794
11105
  ...options,
10795
11106
  renderPreview: paintBrushPreviewRenderer(() => controller.getState().document.paper, { library: controller.brushLibrary, stampArt: () => controller.stampArt })
@@ -10806,20 +11117,20 @@ var PAINT_TOOLS = [
10806
11117
  { id: "rotate", label: "Rotate view", key: "r" }
10807
11118
  ];
10808
11119
  var PaintGesture = (_class15 = class {
10809
- constructor(controller, box) {;_class15.prototype.__init134.call(this);_class15.prototype.__init135.call(this);_class15.prototype.__init136.call(this);_class15.prototype.__init137.call(this);_class15.prototype.__init138.call(this);_class15.prototype.__init139.call(this);
11120
+ constructor(controller, box) {;_class15.prototype.__init138.call(this);_class15.prototype.__init139.call(this);_class15.prototype.__init140.call(this);_class15.prototype.__init141.call(this);_class15.prototype.__init142.call(this);_class15.prototype.__init143.call(this);
10810
11121
  this.controller = controller;
10811
11122
  this.box = box;
10812
11123
  }
10813
11124
 
10814
11125
 
10815
- __init134() {this.tool = "brush"}
11126
+ __init138() {this.tool = "brush"}
10816
11127
  /** The last refusal (a hidden or locked layer), for the editor to show. */
10817
- __init135() {this.error = null}
11128
+ __init139() {this.error = null}
10818
11129
  /** The predicted tail of the current stroke in document pixels (draw it as a thin preview). */
10819
- __init136() {this.predicted = []}
10820
- __init137() {this.mode = null}
10821
- __init138() {this.penAt = null}
10822
- __init139() {this.penDown = false}
11130
+ __init140() {this.predicted = []}
11131
+ __init141() {this.mode = null}
11132
+ __init142() {this.penAt = null}
11133
+ __init143() {this.penDown = false}
10823
11134
  doc(e) {
10824
11135
  const b = this.box();
10825
11136
  const s = this.controller.getState();
@@ -10875,13 +11186,13 @@ var PaintGesture = (_class15 = class {
10875
11186
  const p = this.doc(e);
10876
11187
  const s = this.controller.getState();
10877
11188
  const layerId = s.document.activeLayerId;
10878
- if (!layerId || !_optionalChain([s, 'access', _517 => _517.document, 'access', _518 => _518.liveStrokes, 'optionalAccess', _519 => _519[layerId]])) {
11189
+ if (!layerId || !_optionalChain([s, 'access', _605 => _605.document, 'access', _606 => _606.liveStrokes, 'optionalAccess', _607 => _607[layerId]])) {
10879
11190
  this.error = "Pick a stroke layer in the Layers panel (or add one) to select its strokes.";
10880
11191
  return false;
10881
11192
  }
10882
11193
  try {
10883
11194
  const hit = this.controller.liveStrokeAt(layerId, p.x, p.y);
10884
- this.controller.selectStroke(_nullishCoalesce(_optionalChain([hit, 'optionalAccess', _520 => _520.id]), () => ( null)));
11195
+ this.controller.selectStroke(_nullishCoalesce(_optionalChain([hit, 'optionalAccess', _608 => _608.id]), () => ( null)));
10885
11196
  if (!hit) return false;
10886
11197
  this.mode = { kind: "move-stroke", pointerId: e.pointerId, id: hit.id, from: p, to: p };
10887
11198
  return true;
@@ -10893,7 +11204,7 @@ var PaintGesture = (_class15 = class {
10893
11204
  /** While a stroke is dragged: how far it has moved (document pixels), to draw its outline there. */
10894
11205
  get strokeDrag() {
10895
11206
  const m = this.mode;
10896
- return _optionalChain([m, 'optionalAccess', _521 => _521.kind]) === "move-stroke" ? { id: m.id, dx: m.to.x - m.from.x, dy: m.to.y - m.from.y } : null;
11207
+ return _optionalChain([m, 'optionalAccess', _609 => _609.kind]) === "move-stroke" ? { id: m.id, dx: m.to.x - m.from.x, dy: m.to.y - m.from.y } : null;
10897
11208
  }
10898
11209
  /**
10899
11210
  * The Stickers tool: pressing a sticker picks it and dragging moves it (one undo step at the
@@ -10967,15 +11278,28 @@ var PaintGesture = (_class15 = class {
10967
11278
  if (!m || m.pointerId !== e.pointerId) return;
10968
11279
  this.mode = null;
10969
11280
  this.predicted = [];
10970
- if (m.kind === "stroke") _optionalChain([this, 'access', _522 => _522.controller, 'access', _523 => _523.activeStroke, 'optionalAccess', _524 => _524.end, 'call', _525 => _525()]);
11281
+ if (m.kind === "stroke") {
11282
+ _optionalChain([this, 'access', _610 => _610.controller, 'access', _611 => _611.activeStroke, 'optionalAccess', _612 => _612.end, 'call', _613 => _613()]);
11283
+ _optionalChain([this, 'access', _614 => _614.controller, 'access', _615 => _615.strokeRendering, 'optionalAccess', _616 => _616.catch, 'call', _617 => _617((err) => {
11284
+ this.error = err instanceof Error ? err.message : String(err);
11285
+ })]);
11286
+ }
10971
11287
  if (m.kind === "move-stroke") {
10972
11288
  const dx = Math.round((this.doc(e).x - m.from.x) * 100) / 100;
10973
11289
  const dy = Math.round((this.doc(e).y - m.from.y) * 100) / 100;
10974
11290
  if (dx || dy) {
10975
- try {
10976
- this.controller.editStrokePoints(m.id, { transform: { dx, dy } });
10977
- } catch (err) {
11291
+ const edit = { transform: { dx, dy } };
11292
+ const failed = (err) => {
10978
11293
  this.error = err instanceof Error ? err.message : String(err);
11294
+ };
11295
+ if (this.controller.strokeEditNeedsRender(m.id, edit)) {
11296
+ this.controller.prepareStrokeEdit(m.id, edit).then(() => this.controller.editStrokePoints(m.id, edit)).catch(failed);
11297
+ } else {
11298
+ try {
11299
+ this.controller.editStrokePoints(m.id, edit);
11300
+ } catch (err) {
11301
+ failed(err);
11302
+ }
10979
11303
  }
10980
11304
  }
10981
11305
  }
@@ -10991,8 +11315,8 @@ var PaintGesture = (_class15 = class {
10991
11315
  cancel() {
10992
11316
  this.penDown = false;
10993
11317
  this.predicted = [];
10994
- if (_optionalChain([this, 'access', _526 => _526.mode, 'optionalAccess', _527 => _527.kind]) === "stroke") _optionalChain([this, 'access', _528 => _528.controller, 'access', _529 => _529.activeStroke, 'optionalAccess', _530 => _530.cancel, 'call', _531 => _531()]);
10995
- if (_optionalChain([this, 'access', _532 => _532.mode, 'optionalAccess', _533 => _533.kind]) === "sticker") this.controller.cancelStickerPreview();
11318
+ if (_optionalChain([this, 'access', _618 => _618.mode, 'optionalAccess', _619 => _619.kind]) === "stroke") _optionalChain([this, 'access', _620 => _620.controller, 'access', _621 => _621.activeStroke, 'optionalAccess', _622 => _622.cancel, 'call', _623 => _623()]);
11319
+ if (_optionalChain([this, 'access', _624 => _624.mode, 'optionalAccess', _625 => _625.kind]) === "sticker") this.controller.cancelStickerPreview();
10996
11320
  this.mode = null;
10997
11321
  }
10998
11322
  get active() {
@@ -11057,13 +11381,13 @@ function handlePaintShortcut(controller, gesture, e) {
11057
11381
  return true;
11058
11382
  }
11059
11383
  var PaintCanvasPresenter = (_class16 = class {
11060
- constructor(controller) {;_class16.prototype.__init140.call(this);_class16.prototype.__init141.call(this);_class16.prototype.__init142.call(this);
11384
+ constructor(controller) {;_class16.prototype.__init144.call(this);_class16.prototype.__init145.call(this);_class16.prototype.__init146.call(this);
11061
11385
  this.controller = controller;
11062
11386
  }
11063
11387
 
11064
- __init140() {this.uploaded = /* @__PURE__ */ new Map()}
11065
- __init141() {this.scratch = null}
11066
- __init142() {this.size = ""}
11388
+ __init144() {this.uploaded = /* @__PURE__ */ new Map()}
11389
+ __init145() {this.scratch = null}
11390
+ __init146() {this.size = ""}
11067
11391
  /** Draws what changed into `ctx` (a canvas the size of the document); returns the tiles drawn. */
11068
11392
  render(ctx) {
11069
11393
  const { width, height } = this.controller.document.canvas;
@@ -11095,7 +11419,7 @@ function guideOverlay(controller, drag) {
11095
11419
  const size = s.document.canvas;
11096
11420
  const out = [];
11097
11421
  const layerId = s.document.activeLayerId;
11098
- const strokePicked = layerId && s.selectedStroke ? _optionalChain([s, 'access', _534 => _534.document, 'access', _535 => _535.liveStrokes, 'optionalAccess', _536 => _536[layerId], 'optionalAccess', _537 => _537.some, 'call', _538 => _538((x) => x.id === s.selectedStroke)]) : false;
11422
+ const strokePicked = layerId && s.selectedStroke ? _optionalChain([s, 'access', _626 => _626.document, 'access', _627 => _627.liveStrokes, 'optionalAccess', _628 => _628[layerId], 'optionalAccess', _629 => _629.some, 'call', _630 => _630((x) => x.id === s.selectedStroke)]) : false;
11099
11423
  const area = strokePicked ? controller.liveStrokeArea(s.selectedStroke) : null;
11100
11424
  if (area) {
11101
11425
  const dx = drag && drag.id === s.selectedStroke ? drag.dx : 0;
@@ -11108,7 +11432,7 @@ function guideOverlay(controller, drag) {
11108
11432
  ];
11109
11433
  for (let i = 0; i < 4; i++) out.push({ from: box[i], to: box[(i + 1) % 4], kind: "stroke" });
11110
11434
  }
11111
- const picked = layerId && s.selectedSticker ? _optionalChain([s, 'access', _539 => _539.document, 'access', _540 => _540.stickers, 'optionalAccess', _541 => _541[layerId], 'optionalAccess', _542 => _542.find, 'call', _543 => _543((x) => x.id === s.selectedSticker)]) : void 0;
11435
+ const picked = layerId && s.selectedSticker ? _optionalChain([s, 'access', _631 => _631.document, 'access', _632 => _632.stickers, 'optionalAccess', _633 => _633[layerId], 'optionalAccess', _634 => _634.find, 'call', _635 => _635((x) => x.id === s.selectedSticker)]) : void 0;
11112
11436
  if (picked) {
11113
11437
  const r = picked.size / 2 + 2;
11114
11438
  const a = picked.rotation * Math.PI / 180;
@@ -11138,7 +11462,7 @@ var PAPER_SLIDERS = [
11138
11462
  ];
11139
11463
  function readPath(obj, path) {
11140
11464
  let v = obj;
11141
- for (const k of path.split(".")) v = _optionalChain([v, 'optionalAccess', _544 => _544[k]]);
11465
+ for (const k of path.split(".")) v = _optionalChain([v, 'optionalAccess', _636 => _636[k]]);
11142
11466
  return typeof v === "number" ? v : 0;
11143
11467
  }
11144
11468
  function patchPath(obj, path, value) {
@@ -11254,7 +11578,7 @@ function startWetClock(controller, frame, cancel) {
11254
11578
  id = raf(loop);
11255
11579
  return () => {
11256
11580
  stopped = true;
11257
- _optionalChain([caf, 'optionalCall', _545 => _545(id)]);
11581
+ _optionalChain([caf, 'optionalCall', _637 => _637(id)]);
11258
11582
  };
11259
11583
  }
11260
11584
  function drawWaterOverlay(controller, ctx) {
@@ -11285,7 +11609,7 @@ var DOT_ROTATION_LABELS = { follow: "Follow motion", random: "Random", fixed: "T
11285
11609
  var STAMP_LABELS = { dot: "Dot", star: "Star", heart: "Heart", leaf: "Leaf", flower: "Flower", confetti: "Confetti", splat: "Splat", sparkle: "Sparkle", ring: "Ring" };
11286
11610
  function toggleStickerRef(refs, ref2) {
11287
11611
  if (refs.includes(ref2)) return refs.length > 1 ? refs.filter((r) => r !== ref2) : [...refs];
11288
- return refs.length < _chunkEU2ZZA6Lcjs.MAX_STICKER_STAMPS ? [...refs, ref2] : [...refs];
11612
+ return refs.length < _chunkGHGBIAWQcjs.MAX_STICKER_STAMPS ? [...refs, ref2] : [...refs];
11289
11613
  }
11290
11614
  function stickerRefLabel(ref2) {
11291
11615
  const stamp = ref2.startsWith("editor:") ? ref2.slice(7) : null;
@@ -11298,7 +11622,7 @@ function toggleStamp(stamps, stamp) {
11298
11622
  }
11299
11623
  function toggleDotTexture(textures, stamp) {
11300
11624
  if (textures.includes(stamp)) return textures.filter((s) => s !== stamp);
11301
- return textures.length < _chunkEU2ZZA6Lcjs.MAX_DOT_TEXTURES ? [...textures, stamp] : [...textures];
11625
+ return textures.length < _chunkGHGBIAWQcjs.MAX_DOT_TEXTURES ? [...textures, stamp] : [...textures];
11302
11626
  }
11303
11627
  var PATH_STROKE_TAPERS = [
11304
11628
  { id: "even", label: "Even" },
@@ -11482,9 +11806,9 @@ function createPaintEffectsToolProvider(controller, options = {}) {
11482
11806
  time: { type: "number", minimum: 0, description: "Which moment of an animated effect to paint with, in ms (default 0)." },
11483
11807
  map: {
11484
11808
  type: "object",
11485
- description: "How the effect lies on the paint: by canvas (default: fixed to the canvas, painting reveals a hidden picture) or by stroke (along each stroke: the effect is rendered as a strip length px long, and each pixel takes the colour at its distance along the stroke and its place across the tip).",
11809
+ description: `How the effect lies on the paint: by canvas (default: fixed to the canvas, painting reveals a hidden picture), by stroke (along each stroke: the effect is rendered as a strip length px long, and each pixel takes the colour at its distance along the stroke and its place across the tip), or by path (for effects with a path control format svg-path, e.g. search_effects accepts ["path"]: passes each stroke's centreline [x0, y0, x1, y1, \u2026] in canvas pixels to that control so the effect draws itself along the stroke; strokes longer than 256 points are simplified rather than refused).`,
11486
11810
  properties: {
11487
- by: { type: "string", enum: ["canvas", "stroke"], description: "canvas (default) or stroke." },
11811
+ by: { type: "string", enum: ["canvas", "stroke", "path"], description: "canvas (default), stroke (bent strip along each stroke) or path (native path control for effects with format svg-path)." },
11488
11812
  length: { type: "number", minimum: 16, maximum: 4096, description: "by stroke: px of stroke per repeat of the effect (default 300)." },
11489
11813
  repeat: { type: "string", enum: ["repeat", "mirror", "clamp"], description: "by stroke: past the strip end start again (default), run back, or hold the last colour." }
11490
11814
  },
@@ -11612,7 +11936,7 @@ function createPaintChangeFeed(controller, options = {}) {
11612
11936
  const doc = state.document;
11613
11937
  const layers = /* @__PURE__ */ new Map();
11614
11938
  for (const l of controller.listLayers()) layers.set(l.id, { name: l.name, visible: l.visible, opacity: l.opacity, blend: l.blend });
11615
- return { doc, strokes: new Map(doc.strokes.map((s) => [s.id, s])), events: _nullishCoalesce(_optionalChain([doc, 'access', _546 => _546.paintEvents, 'optionalAccess', _547 => _547.length]), () => ( 0)), layers, stroking: state.stroking };
11939
+ return { doc, strokes: new Map(doc.strokes.map((s) => [s.id, s])), events: _nullishCoalesce(_optionalChain([doc, 'access', _638 => _638.paintEvents, 'optionalAccess', _639 => _639.length]), () => ( 0)), layers, stroking: state.stroking };
11616
11940
  };
11617
11941
  let last = take();
11618
11942
  const check = () => {
@@ -11643,7 +11967,7 @@ function createPaintChangeFeed(controller, options = {}) {
11643
11967
  if (edited) pending = void 0;
11644
11968
  const change = {
11645
11969
  seq: ++seq,
11646
- origin: _nullishCoalesce(_optionalChain([commit, 'optionalAccess', _548 => _548.origin]), () => ( "user")),
11970
+ origin: _nullishCoalesce(_optionalChain([commit, 'optionalAccess', _640 => _640.origin]), () => ( "user")),
11647
11971
  ...commit ? { commit } : {},
11648
11972
  addedStrokes,
11649
11973
  removedStrokes,
@@ -11710,7 +12034,7 @@ function createPaintProposals(options) {
11710
12034
  };
11711
12035
  const strokeIds = () => new Set(controller.getStrokes().map((s) => s.id));
11712
12036
  const validate = (input) => {
11713
- if (!_optionalChain([input, 'access', _549 => _549.title, 'optionalAccess', _550 => _550.trim, 'call', _551 => _551()])) throw new PaintEditorError("A proposal needs a title: what it adds, in a few words.");
12037
+ if (!_optionalChain([input, 'access', _641 => _641.title, 'optionalAccess', _642 => _642.trim, 'call', _643 => _643()])) throw new PaintEditorError("A proposal needs a title: what it adds, in a few words.");
11714
12038
  if (!Array.isArray(input.ops) || !input.ops.length) throw new PaintEditorError("A proposal needs at least one op (stroke, wash or echo).");
11715
12039
  const place = _nullishCoalesce(input.place, () => ( "top"));
11716
12040
  if (place === "above") {
@@ -11722,7 +12046,7 @@ function createPaintProposals(options) {
11722
12046
  input.ops.forEach((op, i) => {
11723
12047
  const at = `ops[${i}]`;
11724
12048
  if (op.kind === "stroke") {
11725
- if (!_optionalChain([op, 'access', _552 => _552.points, 'optionalAccess', _553 => _553.length])) throw new PaintEditorError(`${at}: a stroke needs points in document pixels.`);
12049
+ if (!_optionalChain([op, 'access', _644 => _644.points, 'optionalAccess', _645 => _645.length])) throw new PaintEditorError(`${at}: a stroke needs points in document pixels.`);
11726
12050
  points += op.points.length;
11727
12051
  if (op.color !== void 0 && !HEX3.test(op.color)) throw new PaintEditorError(`${at}: color "${op.color}" is not #rrggbb.`);
11728
12052
  const brush = op.brushId ? controller.getBrush(op.brushId) : controller.getState().brush;
@@ -11734,7 +12058,7 @@ function createPaintProposals(options) {
11734
12058
  if (!HEX3.test(_nullishCoalesce(op.color, () => ( "")))) throw new PaintEditorError(`${at}: a wash needs color as #rrggbb.`);
11735
12059
  if (op.opacity !== void 0 && !(op.opacity > 0 && op.opacity <= 1)) throw new PaintEditorError(`${at}: opacity must be in (0, 1].`);
11736
12060
  } else if (op.kind === "echo") {
11737
- if (!_optionalChain([op, 'access', _554 => _554.strokeIds, 'optionalAccess', _555 => _555.length])) throw new PaintEditorError(`${at}: an echo needs strokeIds (list_strokes).`);
12061
+ if (!_optionalChain([op, 'access', _646 => _646.strokeIds, 'optionalAccess', _647 => _647.length])) throw new PaintEditorError(`${at}: an echo needs strokeIds (list_strokes).`);
11738
12062
  const unknown = op.strokeIds.filter((id) => !known.has(id));
11739
12063
  if (unknown.length) throw new PaintEditorError(`${at}: unknown stroke ${unknown.map((u) => `"${u}"`).join(", ")}. Call list_strokes for the ids.`);
11740
12064
  if (op.color !== void 0 && !HEX3.test(op.color)) throw new PaintEditorError(`${at}: color "${op.color}" is not #rrggbb.`);
@@ -11783,7 +12107,7 @@ function createPaintProposals(options) {
11783
12107
  ...input.layerId ? { layerId: input.layerId } : {},
11784
12108
  ...input.layerName ? { layerName: input.layerName } : {}
11785
12109
  });
11786
- const topLayerId = () => _optionalChain([controller, 'access', _556 => _556.listLayers, 'call', _557 => _557(), 'access', _558 => _558.find, 'call', _559 => _559((l) => l.parentId === null), 'optionalAccess', _560 => _560.id]);
12110
+ const topLayerId = () => _optionalChain([controller, 'access', _648 => _648.listLayers, 'call', _649 => _649(), 'access', _650 => _650.find, 'call', _651 => _651((l) => l.parentId === null), 'optionalAccess', _652 => _652.id]);
11787
12111
  return {
11788
12112
  getState: () => state,
11789
12113
  subscribe(listener) {
@@ -11970,7 +12294,7 @@ function createPaintProposalToolProvider(proposals, options = {}) {
11970
12294
  },
11971
12295
  annotations: { title: "Propose paint", ...WRITE6 },
11972
12296
  handler: (args, context) => {
11973
- const origin = _optionalChain([context, 'access', _561 => _561.actor, 'optionalAccess', _562 => _562.id]) ? `agent:${context.actor.id}` : options.fallbackOrigin;
12297
+ const origin = _optionalChain([context, 'access', _653 => _653.actor, 'optionalAccess', _654 => _654.id]) ? `agent:${context.actor.id}` : options.fallbackOrigin;
11974
12298
  const proposal = proposals.propose({ ...args, ...origin ? { origin } : {} });
11975
12299
  const { id: _id, missing: _missing, createdAt: _createdAt, ...rest } = describe(proposal);
11976
12300
  return { proposalId: proposal.id, ...rest };
@@ -12092,10 +12416,10 @@ function toolList(provider) {
12092
12416
  function uiTables() {
12093
12417
  return {
12094
12418
  tools: PAINT_TOOLS,
12095
- brushOptions: _chunk4NMPUJUKcjs.BRUSH_OPTION_CONTROLS,
12419
+ brushOptions: _chunkYJANF2BLcjs.BRUSH_OPTION_CONTROLS,
12096
12420
  blendMenu: BLEND_MENU_GROUPS,
12097
12421
  layerEffects: _chunkPVJMTLPJcjs.LAYER_EFFECT_MENU.map(({ kind, label }) => ({ kind, label, controls: _chunkPVJMTLPJcjs.layerEffectControls.call(void 0, _chunkPVJMTLPJcjs.defaultLayerEffect.call(void 0, kind, kind)) })),
12098
- sliders: { paper: PAPER_SLIDERS, wet: WET_PARAM_SLIDERS, wetTilt: WET_TILT_SLIDERS, wetSpeed: WET_SPEED_SLIDER, light: LIGHT_SLIDERS, stroke: STROKE_SLIDERS, sticker: STICKER_SLIDERS },
12422
+ sliders: { paper: PAPER_SLIDERS, wet: WET_PARAM_SLIDERS, wetTilt: WET_TILT_SLIDERS, wetSpeed: WET_SPEED_SLIDER, light: LIGHT_SLIDERS, ghost: _chunk3JKCREEUcjs.GHOST_SLIDERS, stroke: STROKE_SLIDERS, sticker: STICKER_SLIDERS },
12099
12423
  pathStrokeTapers: PATH_STROKE_TAPERS,
12100
12424
  padSampleSizes: PAD_SAMPLE_SIZES,
12101
12425
  wetGpu: WET_GPU_OPTIONS,
@@ -12525,4 +12849,11 @@ function createPaintConformanceHost(setup, options) {
12525
12849
 
12526
12850
 
12527
12851
 
12528
- exports.BACKLIGHT_SPILL = BACKLIGHT_SPILL; exports.BLEND_MENU_GROUPS = BLEND_MENU_GROUPS; exports.BLEND_MODES = _chunk2VX55NFMcjs.BLEND_MODES; exports.BRUSH_ID = _chunkEU2ZZA6Lcjs.BRUSH_ID; exports.BRUSH_ROTATIONS = _chunkEU2ZZA6Lcjs.BRUSH_ROTATIONS; exports.BRUSH_SLIDERS = _chunk3KNQ2W6Xcjs.BRUSH_SLIDERS; exports.BUILTIN_BRUSHES = _chunkEU2ZZA6Lcjs.BUILTIN_BRUSHES; exports.BristleStroke = BristleStroke; exports.BrushSourceArtCache = BrushSourceArtCache; exports.DAB_FLIPS = _chunkEU2ZZA6Lcjs.DAB_FLIPS; exports.DEFAULT_BACKLIGHT_COLOR = DEFAULT_BACKLIGHT_COLOR; exports.DEFAULT_BEHAVIOR = _chunkEU2ZZA6Lcjs.DEFAULT_BEHAVIOR; exports.DEFAULT_BRISTLE = _chunkEU2ZZA6Lcjs.DEFAULT_BRISTLE; exports.DEFAULT_BRUSH_ID = _chunkEU2ZZA6Lcjs.DEFAULT_BRUSH_ID; exports.DEFAULT_DPI = DEFAULT_DPI; exports.DEFAULT_DYNAMICS = _chunkEU2ZZA6Lcjs.DEFAULT_DYNAMICS; exports.DEFAULT_FLOW = _chunkJ5VQYK7Tcjs.DEFAULT_FLOW; exports.DEFAULT_IMPASTO = _chunkEU2ZZA6Lcjs.DEFAULT_IMPASTO; exports.DEFAULT_LIGHT = _chunkEU2ZZA6Lcjs.DEFAULT_LIGHT; exports.DEFAULT_LIGHTING = DEFAULT_LIGHTING; exports.DEFAULT_MULTI_COLOR = _chunkEU2ZZA6Lcjs.DEFAULT_MULTI_COLOR; exports.DEFAULT_PAINT_GRADIENT = _chunkNIBFKXMDcjs.DEFAULT_PAINT_GRADIENT; exports.DEFAULT_PAINT_GRADIENT_MAPPING = _chunkNIBFKXMDcjs.DEFAULT_PAINT_GRADIENT_MAPPING; exports.DEFAULT_PAPER = _chunk56RHCIJVcjs.DEFAULT_PAPER; exports.DEFAULT_PARTICLE = _chunkEU2ZZA6Lcjs.DEFAULT_PARTICLE; exports.DEFAULT_SPRAY = _chunkEU2ZZA6Lcjs.DEFAULT_SPRAY; exports.DEFAULT_STICKER = _chunkEU2ZZA6Lcjs.DEFAULT_STICKER; exports.DEFAULT_SWATCHES = DEFAULT_SWATCHES; exports.DEFAULT_TIP_GRAIN = _chunkEU2ZZA6Lcjs.DEFAULT_TIP_GRAIN; exports.DEFAULT_VIEW = DEFAULT_VIEW; exports.DEFAULT_WET_BRUSH = _chunkEU2ZZA6Lcjs.DEFAULT_WET_BRUSH; exports.DEFAULT_WET_PARAMS = _chunkJ5VQYK7Tcjs.DEFAULT_WET_PARAMS; exports.DOT_ROTATIONS = _chunkEU2ZZA6Lcjs.DOT_ROTATIONS; exports.DOT_ROTATION_LABELS = DOT_ROTATION_LABELS; exports.DOT_TEXTURE_ORDERS = _chunkEU2ZZA6Lcjs.DOT_TEXTURE_ORDERS; exports.DOT_TEXTURE_ORDER_LABELS = DOT_TEXTURE_ORDER_LABELS; exports.DryStroke = _chunk56RHCIJVcjs.DryStroke; exports.EFFECT_MAP_REPEATS = _chunk56RHCIJVcjs.EFFECT_MAP_REPEATS; exports.EFFECT_STRIP_HEIGHT = _chunk56RHCIJVcjs.EFFECT_STRIP_HEIGHT; exports.GPU_LEAD = _chunk56RHCIJVcjs.GPU_LEAD; exports.GRAIN_PATTERNS = _chunkNIBFKXMDcjs.GRAIN_PATTERNS; exports.GRAIN_TILE = _chunkNIBFKXMDcjs.GRAIN_TILE; exports.HARMONY_KINDS = _chunkI3Y2Q3PMcjs.HARMONY_KINDS; exports.IDENTITY_AFFINE = IDENTITY_AFFINE; exports.IDENTITY_COPY = _chunk56RHCIJVcjs.IDENTITY_COPY; exports.IMPASTO_TOOLS = _chunkEU2ZZA6Lcjs.IMPASTO_TOOLS; exports.IMPASTO_TOOL_LABELS = IMPASTO_TOOL_LABELS; exports.LIGHT_SLIDERS = LIGHT_SLIDERS; exports.LIVE_STROKE_ENGINES = LIVE_STROKE_ENGINES; exports.LitCache = LitCache; exports.MAX_BRUSH_SIZE = _chunkNIBFKXMDcjs.MAX_BRUSH_SIZE; exports.MAX_CANVAS_SIDE = MAX_CANVAS_SIDE; exports.MAX_COORDINATE = MAX_COORDINATE; exports.MAX_DOT_TEXTURES = _chunkEU2ZZA6Lcjs.MAX_DOT_TEXTURES; exports.MAX_IMAGE_SIDE = MAX_IMAGE_SIDE; exports.MAX_LIVE_EFFECT_SOURCES = MAX_LIVE_EFFECT_SOURCES; exports.MAX_PATH_SAMPLES = MAX_PATH_SAMPLES; exports.MAX_STICKER_STAMPS = _chunkEU2ZZA6Lcjs.MAX_STICKER_STAMPS; exports.MAX_ZOOM = MAX_ZOOM; exports.MIN_CANVAS_SIDE = MIN_CANVAS_SIDE; exports.MIN_ZOOM = MIN_ZOOM; exports.MIXING_PAD_HEIGHT = MIXING_PAD_HEIGHT; exports.MIXING_PAD_WIDTH = MIXING_PAD_WIDTH; exports.MULTI_COLOR_MODES = _chunkEU2ZZA6Lcjs.MULTI_COLOR_MODES; exports.MixingPad = MixingPad; exports.PAD_SAMPLE_SIZES = PAD_SAMPLE_SIZES; exports.PAINTERLY_BLEND_MODES = _chunk2VX55NFMcjs.PAINTERLY_BLEND_MODES; exports.PAINT_BRUSH_CATEGORIES = _chunkEU2ZZA6Lcjs.PAINT_BRUSH_CATEGORIES; exports.PAINT_BRUSH_ENGINES = _chunkEU2ZZA6Lcjs.PAINT_BRUSH_ENGINES; exports.PAINT_COLOR_JSON_SCHEMA = _chunkNIBFKXMDcjs.PAINT_COLOR_JSON_SCHEMA; exports.PAINT_CONTRACT_FORMAT_VERSION = PAINT_CONTRACT_FORMAT_VERSION; exports.PAINT_DOCUMENT_JSON_SCHEMA = PAINT_DOCUMENT_JSON_SCHEMA; exports.PAINT_EFFECT_PLACES = PAINT_EFFECT_PLACES; exports.PAINT_FORMAT = PAINT_FORMAT; exports.PAINT_GRADIENT_FULL_SPEED = _chunkNIBFKXMDcjs.PAINT_GRADIENT_FULL_SPEED; exports.PAINT_GRADIENT_JSON_SCHEMA = _chunkNIBFKXMDcjs.PAINT_GRADIENT_JSON_SCHEMA; exports.PAINT_GRADIENT_KIT = _chunkNIBFKXMDcjs.PAINT_GRADIENT_KIT; exports.PAINT_GRADIENT_MAPPINGS = _chunkNIBFKXMDcjs.PAINT_GRADIENT_MAPPINGS; exports.PAINT_GRADIENT_MAPPING_LABELS = _chunkNIBFKXMDcjs.PAINT_GRADIENT_MAPPING_LABELS; exports.PAINT_GRADIENT_PRESETS = _chunkNIBFKXMDcjs.PAINT_GRADIENT_PRESETS; exports.PAINT_GRADIENT_REPEATS = _chunkNIBFKXMDcjs.PAINT_GRADIENT_REPEATS; exports.PAINT_GRADIENT_REPEAT_LABELS = _chunkNIBFKXMDcjs.PAINT_GRADIENT_REPEAT_LABELS; exports.PAINT_GRADIENT_SPACES = _chunkNIBFKXMDcjs.PAINT_GRADIENT_SPACES; exports.PAINT_GRADIENT_SPACE_LABELS = _chunkNIBFKXMDcjs.PAINT_GRADIENT_SPACE_LABELS; exports.PAINT_SCHEMA_VERSION = PAINT_SCHEMA_VERSION; exports.PAINT_SHORTCUTS = PAINT_SHORTCUTS; exports.PAINT_SOURCE_JSON_SCHEMA = _chunkNIBFKXMDcjs.PAINT_SOURCE_JSON_SCHEMA; exports.PAINT_TARGET = PAINT_TARGET; exports.PAINT_TOOLS = PAINT_TOOLS; exports.PAPER_EFFECT_BLENDS = PAPER_EFFECT_BLENDS; exports.PAPER_EFFECT_NODE_ID = PAPER_EFFECT_NODE_ID; exports.PAPER_FAMILIES = _chunk56RHCIJVcjs.PAPER_FAMILIES; exports.PAPER_LIBRARY = _chunk56RHCIJVcjs.PAPER_LIBRARY; exports.PAPER_NODE_ID = PAPER_NODE_ID; exports.PAPER_SLIDERS = PAPER_SLIDERS; exports.PAPER_TARGET = PAPER_TARGET; exports.PARTICLE_KINDS = _chunkEU2ZZA6Lcjs.PARTICLE_KINDS; exports.PARTICLE_KIND_LABELS = PARTICLE_KIND_LABELS; exports.PARTICLE_RENDERS = _chunkEU2ZZA6Lcjs.PARTICLE_RENDERS; exports.PARTICLE_RENDER_LABELS = PARTICLE_RENDER_LABELS; exports.PATH_STROKE_TAPERS = PATH_STROKE_TAPERS; exports.PaintCanvasPresenter = PaintCanvasPresenter; exports.PaintDabStroke = _chunk56RHCIJVcjs.PaintDabStroke; exports.PaintDirector = PaintDirector; exports.PaintDocumentError = PaintDocumentError; exports.PaintEditorController = PaintEditorController; exports.PaintEditorError = PaintEditorError; exports.PaintEffectsRenderer = PaintEffectsRenderer; exports.PaintGesture = PaintGesture; exports.PaintGradientSampler = _chunkNIBFKXMDcjs.PaintGradientSampler; exports.PaintPresence = PaintPresence; exports.PaintSourceError = _chunkNIBFKXMDcjs.PaintSourceError; exports.PaintStrokeSession = PaintStrokeSession; exports.PaintWetLayers = _chunk56RHCIJVcjs.PaintWetLayers; exports.PaperGrain = _chunkNIBFKXMDcjs.PaperGrain; exports.ParticleStroke = ParticleStroke; exports.PenDabWalker = _chunk56RHCIJVcjs.PenDabWalker; exports.PenSmoother = _chunk56RHCIJVcjs.PenSmoother; exports.PerspectiveSnapper = PerspectiveSnapper; exports.RIBBON_PAIRS = _chunkEU2ZZA6Lcjs.RIBBON_PAIRS; exports.RIBBON_PAIR_LABELS = RIBBON_PAIR_LABELS; exports.SNAP_DECIDE_DISTANCE = SNAP_DECIDE_DISTANCE; exports.STAMP_KINDS = _chunkRDFHWAHLcjs.STAMP_KINDS; exports.STAMP_LABELS = STAMP_LABELS; exports.STENCIL_KINDS = STENCIL_KINDS; exports.STENCIL_SHAPES = STENCIL_SHAPES; exports.STICKER_ART_SIZE = STICKER_ART_SIZE; exports.STICKER_SLIDERS = STICKER_SLIDERS; exports.STROKE_SLIDERS = STROKE_SLIDERS; exports.SYMMETRY_MODES = SYMMETRY_MODES; exports.StencilSnapper = StencilSnapper; exports.StickerArtCache = StickerArtCache; exports.StickerBrowser = _chunk3VHH6V67cjs.StickerBrowser; exports.StickerSpray = StickerSpray; exports.TIP_GRAIN_MODES = _chunkEU2ZZA6Lcjs.TIP_GRAIN_MODES; exports.TRACING_NODE_ID = TRACING_NODE_ID; exports.ThickStrokeDriver = ThickStrokeDriver; exports.TileableNoise = _chunk3K6HWEXZcjs.TileableNoise; exports.TipGrain = _chunk56RHCIJVcjs.TipGrain; exports.WET_FLOW_KINDS = _chunkJ5VQYK7Tcjs.WET_FLOW_KINDS; exports.WET_GPU_MODES = _chunk56RHCIJVcjs.WET_GPU_MODES; exports.WET_GPU_OPTIONS = WET_GPU_OPTIONS; exports.WET_MEDIA = _chunkEU2ZZA6Lcjs.WET_MEDIA; exports.WET_MEDIUM_LABELS = WET_MEDIUM_LABELS; exports.WET_MEDIUM_PARAMS = _chunk56RHCIJVcjs.WET_MEDIUM_PARAMS; exports.WET_PARAM_KEYS = _chunkJ5VQYK7Tcjs.WET_PARAM_KEYS; exports.WET_PARAM_SCHEMA = WET_PARAM_SCHEMA; exports.WET_PARAM_SLIDERS = WET_PARAM_SLIDERS; exports.WET_SPEED_SLIDER = WET_SPEED_SLIDER; exports.WET_TILT_SLIDERS = WET_TILT_SLIDERS; exports.WET_TOOLS = _chunkEU2ZZA6Lcjs.WET_TOOLS; exports.WET_TOOL_LABELS = WET_TOOL_LABELS; exports.WetStrokeDriver = _chunk56RHCIJVcjs.WetStrokeDriver; exports.addPaintGradientStop = _chunkNIBFKXMDcjs.addPaintGradientStop; exports.addPolygonArea = addPolygonArea; exports.affineCopy = affineCopy; exports.applyAffine = applyAffine; exports.backlightOf = backlightOf; exports.brushEngineControls = _chunk3KNQ2W6Xcjs.brushEngineControls; exports.brushLoadColor = brushLoadColor; exports.brushLoadForStroke = brushLoadForStroke; exports.brushTakesPaint = _chunkEU2ZZA6Lcjs.brushTakesPaint; exports.brushToJSON = _chunkEU2ZZA6Lcjs.brushToJSON; exports.buildTimeLapse = buildTimeLapse; exports.checkPaintEffectPlace = checkPaintEffectPlace; exports.clonePaper = _chunk56RHCIJVcjs.clonePaper; exports.colorHarmony = colorHarmony2; exports.composeAffine = composeAffine; exports.contactSheet = contactSheet; exports.createPaintAgentStrokes = createPaintAgentStrokes; exports.createPaintBrushLibraryToolProvider = createPaintBrushLibraryToolProvider; exports.createPaintChangeFeed = createPaintChangeFeed; exports.createPaintCompositor = createPaintCompositor; exports.createPaintConformanceHost = createPaintConformanceHost; exports.createPaintDocument = createPaintDocument; exports.createPaintEditorDocument = createPaintEditorDocument; exports.createPaintEditorToolProvider = createPaintEditorToolProvider; exports.createPaintEffectsToolProvider = createPaintEffectsToolProvider; exports.createPaintLayer = createPaintLayer; exports.createPaintProposalToolProvider = createPaintProposalToolProvider; exports.createPaintProposals = createPaintProposals; exports.createPaintReplayTools = createPaintReplayTools; exports.createPaintStickerTools = createPaintStickerTools; exports.createPaintThickTools = createPaintThickTools; exports.createPaintWetTools = createPaintWetTools; exports.decodeImageBlob = decodeImageBlob; exports.defaultGuides = defaultGuides; exports.defaultImageEncoder = defaultImageEncoder; exports.defaultStickerRasterizer = defaultStickerRasterizer; exports.deserializePaintDocument = deserializePaintDocument; exports.deserializePaintDocumentAsync = deserializePaintDocumentAsync; exports.documentExtensions = documentExtensions; exports.documentToScreen = documentToScreen; exports.downloadBytes = downloadBytes; exports.downsampleRgba = downsampleRgba; exports.drawSticker = drawSticker; exports.drawWaterOverlay = drawWaterOverlay; exports.effectDabField = _chunk56RHCIJVcjs.effectDabField; exports.effectLayersToJSON = effectLayersToJSON; exports.effectPaintKey = _chunk56RHCIJVcjs.effectPaintKey; exports.effectPaintSize = _chunk56RHCIJVcjs.effectPaintSize; exports.emptiedLayers = emptiedLayers; exports.emptyThickChannels = emptyThickChannels; exports.engineBrushSourceIds = engineBrushSourceIds; exports.fitZoom = fitZoom; exports.grainCatch = _chunkNIBFKXMDcjs.grainCatch; exports.grainHeights = _chunkNIBFKXMDcjs.grainHeights; exports.guideOverlay = guideOverlay; exports.handlePaintShortcut = handlePaintShortcut; exports.hash2 = _chunk3K6HWEXZcjs.hash2; exports.hexToPaintRgb = _chunkNIBFKXMDcjs.hexToPaintRgb; exports.hexToRgb8 = _chunk56RHCIJVcjs.hexToRgb8; exports.hslToRgb = hslToRgb; exports.hsvToRgb = hsvToRgb; exports.hueToWheel = _chunkI3Y2Q3PMcjs.hueToWheel; exports.invertAffine = invertAffine; exports.isBlendMode = _chunk2VX55NFMcjs.isBlendMode; exports.isGradientPaint = _chunkNIBFKXMDcjs.isGradientPaint; exports.isPaintEffectPaint = _chunk56RHCIJVcjs.isPaintEffectPaint; exports.isPainterlyBlendMode = _chunk2VX55NFMcjs.isPainterlyBlendMode; exports.isPalmTouch = isPalmTouch; exports.isWetBrush = _chunkEU2ZZA6Lcjs.isWetBrush; exports.isWetCapable = _chunkEU2ZZA6Lcjs.isWetCapable; exports.lightTile = lightTile; exports.lightingKey = lightingKey; exports.liveStrokeBounds = liveStrokeBounds; exports.liveStrokeRefusal = liveStrokeRefusal; exports.mapPenPoint = mapPenPoint; exports.mix32 = _chunk3K6HWEXZcjs.mix32; exports.mixPixels = mixPixels; exports.mixerLoadForStroke = mixerLoadForStroke; exports.mixerTip = _chunk56RHCIJVcjs.mixerTip; exports.multiColorForDab = _chunk56RHCIJVcjs.multiColorForDab; exports.multiColorGradient = _chunk56RHCIJVcjs.multiColorGradient; exports.multiColorPalette = _chunk56RHCIJVcjs.multiColorPalette; exports.multiColorSliders = _chunk3KNQ2W6Xcjs.multiColorSliders; exports.multiColorToPaint = _chunkEU2ZZA6Lcjs.multiColorToPaint; exports.newPaintLayerId = newPaintLayerId; exports.nextPaperEffectVersion = nextPaperEffectVersion; exports.normalizeBehavior = _chunkEU2ZZA6Lcjs.normalizeBehavior; exports.normalizeBristle = _chunkEU2ZZA6Lcjs.normalizeBristle; exports.normalizeBrushStroke = normalizeBrushStroke; exports.normalizeCanvas = normalizeCanvas; exports.normalizeDynamics = _chunkEU2ZZA6Lcjs.normalizeDynamics; exports.normalizeFlow = _chunkJ5VQYK7Tcjs.normalizeFlow; exports.normalizeHexColor = _chunkNIBFKXMDcjs.normalizeHexColor; exports.normalizeImpasto = _chunkEU2ZZA6Lcjs.normalizeImpasto; exports.normalizeLight = _chunkEU2ZZA6Lcjs.normalizeLight; exports.normalizeLighting = normalizeLighting; exports.normalizeMultiColor = _chunkEU2ZZA6Lcjs.normalizeMultiColor; exports.normalizePaintBrush = _chunkEU2ZZA6Lcjs.normalizePaintBrush; exports.normalizePaper = _chunk56RHCIJVcjs.normalizePaper; exports.normalizeParticle = _chunkEU2ZZA6Lcjs.normalizeParticle; exports.normalizePerspective = normalizePerspective; exports.normalizeRotation = normalizeRotation; exports.normalizeStencil = normalizeStencil; exports.normalizeStickerSettings = _chunkEU2ZZA6Lcjs.normalizeStickerSettings; exports.normalizeStickerUpdate = normalizeStickerUpdate; exports.normalizeSymmetry = normalizeSymmetry; exports.normalizeView = normalizeView; exports.normalizeWetBrush = _chunkEU2ZZA6Lcjs.normalizeWetBrush; exports.normalizeWetParams = _chunkJ5VQYK7Tcjs.normalizeWetParams; exports.overPixels = overPixels; exports.padSampleRadius = padSampleRadius; exports.paintAgentStrokePoints = paintAgentStrokePoints; exports.paintBrushPreviewRenderer = paintBrushPreviewRenderer; exports.paintContracts = paintContracts; exports.paintGradientMappingFor = _chunkNIBFKXMDcjs.paintGradientMappingFor; exports.paintPlaybackPanel = paintPlaybackPanel; exports.paintProposalGhost = paintProposalGhost; exports.paintShortcutFor = paintShortcutFor; exports.paintSourceColor = _chunkNIBFKXMDcjs.paintSourceColor; exports.paintSourceCss = _chunkNIBFKXMDcjs.paintSourceCss; exports.paintToMultiColor = _chunkEU2ZZA6Lcjs.paintToMultiColor; exports.paperEffectFromJSON = paperEffectFromJSON; exports.paperEffectToJSON = paperEffectToJSON; exports.paperGrain = paperGrain; exports.paperKey = paperKey; exports.paperNode = paperNode; exports.paperPreset = _chunk56RHCIJVcjs.paperPreset; exports.parseBrushLibrary = _chunkEU2ZZA6Lcjs.parseBrushLibrary; exports.parseHexColor = parseHexColor; exports.parsePaintSource = _chunkNIBFKXMDcjs.parsePaintSource; exports.patchBrushValue = _chunk3KNQ2W6Xcjs.patchBrushValue; exports.patchPath = patchPath; exports.penOrientation = _chunk56RHCIJVcjs.penOrientation; exports.perspectiveDirections = perspectiveDirections; exports.perspectiveGuideLines = perspectiveGuideLines; exports.planPaintToolPlayback = planPaintToolPlayback; exports.pointerToPenPoint = pointerToPenPoint; exports.quickStencil = quickStencil; exports.rand01 = _chunk3K6HWEXZcjs.rand01; exports.randSigned = _chunk3K6HWEXZcjs.randSigned; exports.readEffectStrokeMap = _chunk56RHCIJVcjs.readEffectStrokeMap; exports.readPaintEffectPaint = _chunk56RHCIJVcjs.readPaintEffectPaint; exports.readPaintEffectSource = readPaintEffectSource; exports.readPaintSource = _chunkNIBFKXMDcjs.readPaintSource; exports.readPath = readPath; exports.readSwatch = readSwatch; exports.reliefInfo = reliefInfo; exports.removePaintGradientStop = _chunkNIBFKXMDcjs.removePaintGradientStop; exports.renderBrushThumbnail = renderBrushThumbnail; exports.renderColorWheel = renderColorWheel; exports.renderPaper = _chunk56RHCIJVcjs.renderPaper; exports.renderStickers = renderStickers; exports.replayFrame = replayFrame; exports.replayItems = replayItems; exports.replayPainting = replayPainting; exports.resolvePaintGradient = _chunkNIBFKXMDcjs.resolvePaintGradient; exports.reversePaintGradient = _chunkNIBFKXMDcjs.reversePaintGradient; exports.rgbToHexColor = rgbToHexColor; exports.rgbToHsl = rgbToHsl; exports.rgbToHsv = rgbToHsv; exports.sampleArt = sampleArt; exports.sampleEffectAt = _chunk56RHCIJVcjs.sampleEffectAt; exports.sampleEffectField = _chunk56RHCIJVcjs.sampleEffectField; exports.samplePath = samplePath; exports.samplePressure = samplePressure; exports.scalePaintGradient = _chunkNIBFKXMDcjs.scalePaintGradient; exports.scaleStencil = scaleStencil; exports.screenToDocument = screenToDocument; exports.seedFromString = _chunk3K6HWEXZcjs.seedFromString; exports.serializePaintDocument = serializePaintDocument; exports.serializePaintDocumentExternal = serializePaintDocumentExternal; exports.solidPaint = _chunkNIBFKXMDcjs.solidPaint; exports.stampCoverage = _chunkRDFHWAHLcjs.stampCoverage; exports.standardBlendMode = _chunk2VX55NFMcjs.standardBlendMode; exports.startWetClock = startWetClock; exports.stencilMask = stencilMask; exports.stencilOutline = stencilOutline; exports.stickerAt = stickerAt; exports.stickerRect = stickerRect; exports.stickerRefLabel = stickerRefLabel; exports.stickerStamp = stickerStamp; exports.stickerSurface = stickerSurface; exports.strokeBounds = strokeBounds; exports.strokeDuration = strokeDuration; exports.strokeSchedule = strokeSchedule; exports.strokeToJSON = strokeToJSON; exports.sweepPath = sweepPath; exports.symmetryAxisAngles = symmetryAxisAngles; exports.symmetryAxisSegments = symmetryAxisSegments; exports.symmetryCopies = symmetryCopies; exports.thickFromJSON = thickFromJSON; exports.thickToJSON = thickToJSON; exports.thumbnailStroke = thumbnailStroke; exports.tiltToOrientation = _chunk56RHCIJVcjs.tiltToOrientation; exports.timeLapseVideo = timeLapseVideo; exports.timeLapseZip = timeLapseZip; exports.toStrokePoint = _chunk56RHCIJVcjs.toStrokePoint; exports.toggleDotTexture = toggleDotTexture; exports.toggleStamp = toggleStamp; exports.toggleStickerRef = toggleStickerRef; exports.translateStencil = translateStencil; exports.updatePaintGradientStop = _chunkNIBFKXMDcjs.updatePaintGradientStop; exports.usesPaintExchange = _chunkEU2ZZA6Lcjs.usesPaintExchange; exports.variationAffine = variationAffine; exports.varyStroke = varyStroke; exports.viewCssTransform = viewCssTransform; exports.viewMatrix = viewMatrix; exports.viewPenToDocument = viewPenToDocument; exports.wetEngineSummary = wetEngineSummary; exports.wetPaperInput = _chunk56RHCIJVcjs.wetPaperInput; exports.wetPigmentOf = _chunk56RHCIJVcjs.wetPigmentOf; exports.wetSupport = _chunkJ5VQYK7Tcjs.wetSupport; exports.wheelAngle = wheelAngle; exports.wheelPick = wheelPick; exports.wheelPoint = wheelPoint; exports.wheelToHue = _chunkI3Y2Q3PMcjs.wheelToHue; exports.withPaintPlayback = withPaintPlayback;
12852
+
12853
+
12854
+
12855
+
12856
+
12857
+
12858
+
12859
+ exports.BACKLIGHT_SPILL = BACKLIGHT_SPILL; exports.BLEND_MENU_GROUPS = BLEND_MENU_GROUPS; exports.BLEND_MODES = _chunk2VX55NFMcjs.BLEND_MODES; exports.BRUSH_ID = _chunkGHGBIAWQcjs.BRUSH_ID; exports.BRUSH_ROTATIONS = _chunkGHGBIAWQcjs.BRUSH_ROTATIONS; exports.BRUSH_SLIDERS = _chunk3JKCREEUcjs.BRUSH_SLIDERS; exports.BUILTIN_BRUSHES = _chunkGHGBIAWQcjs.BUILTIN_BRUSHES; exports.BristleStroke = BristleStroke; exports.BrushSourceArtCache = BrushSourceArtCache; exports.DAB_FLIPS = _chunkGHGBIAWQcjs.DAB_FLIPS; exports.DEFAULT_BACKLIGHT_COLOR = DEFAULT_BACKLIGHT_COLOR; exports.DEFAULT_BEHAVIOR = _chunkGHGBIAWQcjs.DEFAULT_BEHAVIOR; exports.DEFAULT_BRISTLE = _chunkGHGBIAWQcjs.DEFAULT_BRISTLE; exports.DEFAULT_BRUSH_ID = _chunkGHGBIAWQcjs.DEFAULT_BRUSH_ID; exports.DEFAULT_DPI = DEFAULT_DPI; exports.DEFAULT_DYNAMICS = _chunkGHGBIAWQcjs.DEFAULT_DYNAMICS; exports.DEFAULT_FLOW = _chunkN5IMDAHMcjs.DEFAULT_FLOW; exports.DEFAULT_GHOST = _chunkGHGBIAWQcjs.DEFAULT_GHOST; exports.DEFAULT_IMPASTO = _chunkGHGBIAWQcjs.DEFAULT_IMPASTO; exports.DEFAULT_LIGHT = _chunkGHGBIAWQcjs.DEFAULT_LIGHT; exports.DEFAULT_LIGHTING = DEFAULT_LIGHTING; exports.DEFAULT_MULTI_COLOR = _chunkGHGBIAWQcjs.DEFAULT_MULTI_COLOR; exports.DEFAULT_PAINT_GRADIENT = _chunkNIBFKXMDcjs.DEFAULT_PAINT_GRADIENT; exports.DEFAULT_PAINT_GRADIENT_MAPPING = _chunkNIBFKXMDcjs.DEFAULT_PAINT_GRADIENT_MAPPING; exports.DEFAULT_PAPER = _chunkSNAFFCAXcjs.DEFAULT_PAPER; exports.DEFAULT_PARTICLE = _chunkGHGBIAWQcjs.DEFAULT_PARTICLE; exports.DEFAULT_SPRAY = _chunkGHGBIAWQcjs.DEFAULT_SPRAY; exports.DEFAULT_STICKER = _chunkGHGBIAWQcjs.DEFAULT_STICKER; exports.DEFAULT_SWATCHES = DEFAULT_SWATCHES; exports.DEFAULT_TIP_GRAIN = _chunkGHGBIAWQcjs.DEFAULT_TIP_GRAIN; exports.DEFAULT_VIEW = DEFAULT_VIEW; exports.DEFAULT_WET_BRUSH = _chunkGHGBIAWQcjs.DEFAULT_WET_BRUSH; exports.DEFAULT_WET_PARAMS = _chunkN5IMDAHMcjs.DEFAULT_WET_PARAMS; exports.DOT_ROTATIONS = _chunkGHGBIAWQcjs.DOT_ROTATIONS; exports.DOT_ROTATION_LABELS = DOT_ROTATION_LABELS; exports.DOT_TEXTURE_ORDERS = _chunkGHGBIAWQcjs.DOT_TEXTURE_ORDERS; exports.DOT_TEXTURE_ORDER_LABELS = DOT_TEXTURE_ORDER_LABELS; exports.DryStroke = _chunkSNAFFCAXcjs.DryStroke; exports.EFFECT_MAP_REPEATS = _chunkSNAFFCAXcjs.EFFECT_MAP_REPEATS; exports.EFFECT_STRIP_HEIGHT = _chunkSNAFFCAXcjs.EFFECT_STRIP_HEIGHT; exports.GHOST_SLIDERS = _chunk3JKCREEUcjs.GHOST_SLIDERS; exports.GPU_LEAD = _chunkSNAFFCAXcjs.GPU_LEAD; exports.GRAIN_PATTERNS = _chunkNIBFKXMDcjs.GRAIN_PATTERNS; exports.GRAIN_TILE = _chunkNIBFKXMDcjs.GRAIN_TILE; exports.HARMONY_KINDS = _chunkI3Y2Q3PMcjs.HARMONY_KINDS; exports.IDENTITY_AFFINE = IDENTITY_AFFINE; exports.IDENTITY_COPY = _chunkSNAFFCAXcjs.IDENTITY_COPY; exports.IMPASTO_TOOLS = _chunkGHGBIAWQcjs.IMPASTO_TOOLS; exports.IMPASTO_TOOL_LABELS = IMPASTO_TOOL_LABELS; exports.LIGHT_SLIDERS = LIGHT_SLIDERS; exports.LIVE_STROKE_ENGINES = LIVE_STROKE_ENGINES; exports.LitCache = LitCache; exports.MAX_BRUSH_SIZE = _chunkNIBFKXMDcjs.MAX_BRUSH_SIZE; exports.MAX_CANVAS_SIDE = MAX_CANVAS_SIDE; exports.MAX_COORDINATE = MAX_COORDINATE; exports.MAX_DOT_TEXTURES = _chunkGHGBIAWQcjs.MAX_DOT_TEXTURES; exports.MAX_EFFECT_PATH_POINTS = _chunkSNAFFCAXcjs.MAX_EFFECT_PATH_POINTS; exports.MAX_IMAGE_SIDE = MAX_IMAGE_SIDE; exports.MAX_LIVE_EFFECT_SOURCES = MAX_LIVE_EFFECT_SOURCES; exports.MAX_PATH_SAMPLES = MAX_PATH_SAMPLES; exports.MAX_STICKER_STAMPS = _chunkGHGBIAWQcjs.MAX_STICKER_STAMPS; exports.MAX_ZOOM = MAX_ZOOM; exports.MIN_CANVAS_SIDE = MIN_CANVAS_SIDE; exports.MIN_ZOOM = MIN_ZOOM; exports.MIXING_PAD_HEIGHT = MIXING_PAD_HEIGHT; exports.MIXING_PAD_WIDTH = MIXING_PAD_WIDTH; exports.MULTI_COLOR_MODES = _chunkGHGBIAWQcjs.MULTI_COLOR_MODES; exports.MixingPad = MixingPad; exports.PAD_SAMPLE_SIZES = PAD_SAMPLE_SIZES; exports.PAINTERLY_BLEND_MODES = _chunk2VX55NFMcjs.PAINTERLY_BLEND_MODES; exports.PAINT_BRUSH_CATEGORIES = _chunkGHGBIAWQcjs.PAINT_BRUSH_CATEGORIES; exports.PAINT_BRUSH_ENGINES = _chunkGHGBIAWQcjs.PAINT_BRUSH_ENGINES; exports.PAINT_COLOR_JSON_SCHEMA = _chunkNIBFKXMDcjs.PAINT_COLOR_JSON_SCHEMA; exports.PAINT_CONTRACT_FORMAT_VERSION = PAINT_CONTRACT_FORMAT_VERSION; exports.PAINT_DOCUMENT_JSON_SCHEMA = PAINT_DOCUMENT_JSON_SCHEMA; exports.PAINT_EFFECT_PLACES = PAINT_EFFECT_PLACES; exports.PAINT_FORMAT = PAINT_FORMAT; exports.PAINT_GRADIENT_FULL_SPEED = _chunkNIBFKXMDcjs.PAINT_GRADIENT_FULL_SPEED; exports.PAINT_GRADIENT_JSON_SCHEMA = _chunkNIBFKXMDcjs.PAINT_GRADIENT_JSON_SCHEMA; exports.PAINT_GRADIENT_KIT = _chunkNIBFKXMDcjs.PAINT_GRADIENT_KIT; exports.PAINT_GRADIENT_MAPPINGS = _chunkNIBFKXMDcjs.PAINT_GRADIENT_MAPPINGS; exports.PAINT_GRADIENT_MAPPING_LABELS = _chunkNIBFKXMDcjs.PAINT_GRADIENT_MAPPING_LABELS; exports.PAINT_GRADIENT_PRESETS = _chunkNIBFKXMDcjs.PAINT_GRADIENT_PRESETS; exports.PAINT_GRADIENT_REPEATS = _chunkNIBFKXMDcjs.PAINT_GRADIENT_REPEATS; exports.PAINT_GRADIENT_REPEAT_LABELS = _chunkNIBFKXMDcjs.PAINT_GRADIENT_REPEAT_LABELS; exports.PAINT_GRADIENT_SPACES = _chunkNIBFKXMDcjs.PAINT_GRADIENT_SPACES; exports.PAINT_GRADIENT_SPACE_LABELS = _chunkNIBFKXMDcjs.PAINT_GRADIENT_SPACE_LABELS; exports.PAINT_SCHEMA_VERSION = PAINT_SCHEMA_VERSION; exports.PAINT_SHORTCUTS = PAINT_SHORTCUTS; exports.PAINT_SOURCE_JSON_SCHEMA = _chunkNIBFKXMDcjs.PAINT_SOURCE_JSON_SCHEMA; exports.PAINT_TARGET = PAINT_TARGET; exports.PAINT_TOOLS = PAINT_TOOLS; exports.PAPER_EFFECT_BLENDS = PAPER_EFFECT_BLENDS; exports.PAPER_EFFECT_NODE_ID = PAPER_EFFECT_NODE_ID; exports.PAPER_FAMILIES = _chunkSNAFFCAXcjs.PAPER_FAMILIES; exports.PAPER_LIBRARY = _chunkSNAFFCAXcjs.PAPER_LIBRARY; exports.PAPER_NODE_ID = PAPER_NODE_ID; exports.PAPER_SLIDERS = PAPER_SLIDERS; exports.PAPER_TARGET = PAPER_TARGET; exports.PARTICLE_KINDS = _chunkGHGBIAWQcjs.PARTICLE_KINDS; exports.PARTICLE_KIND_LABELS = PARTICLE_KIND_LABELS; exports.PARTICLE_RENDERS = _chunkGHGBIAWQcjs.PARTICLE_RENDERS; exports.PARTICLE_RENDER_LABELS = PARTICLE_RENDER_LABELS; exports.PATH_STROKE_TAPERS = PATH_STROKE_TAPERS; exports.PaintCanvasPresenter = PaintCanvasPresenter; exports.PaintDabStroke = _chunkSNAFFCAXcjs.PaintDabStroke; exports.PaintDirector = PaintDirector; exports.PaintDocumentError = PaintDocumentError; exports.PaintEditorController = PaintEditorController; exports.PaintEditorError = PaintEditorError; exports.PaintEffectsRenderer = PaintEffectsRenderer; exports.PaintGesture = PaintGesture; exports.PaintGradientSampler = _chunkNIBFKXMDcjs.PaintGradientSampler; exports.PaintPresence = PaintPresence; exports.PaintSourceError = _chunkNIBFKXMDcjs.PaintSourceError; exports.PaintStrokeSession = PaintStrokeSession; exports.PaintWetLayers = _chunkSNAFFCAXcjs.PaintWetLayers; exports.PaperGrain = _chunkNIBFKXMDcjs.PaperGrain; exports.ParticleStroke = ParticleStroke; exports.PenDabWalker = _chunkSNAFFCAXcjs.PenDabWalker; exports.PenSmoother = _chunkSNAFFCAXcjs.PenSmoother; exports.PerspectiveSnapper = PerspectiveSnapper; exports.RIBBON_PAIRS = _chunkGHGBIAWQcjs.RIBBON_PAIRS; exports.RIBBON_PAIR_LABELS = RIBBON_PAIR_LABELS; exports.SNAP_DECIDE_DISTANCE = SNAP_DECIDE_DISTANCE; exports.STAMP_KINDS = _chunkRDFHWAHLcjs.STAMP_KINDS; exports.STAMP_LABELS = STAMP_LABELS; exports.STENCIL_KINDS = STENCIL_KINDS; exports.STENCIL_SHAPES = STENCIL_SHAPES; exports.STICKER_ART_SIZE = STICKER_ART_SIZE; exports.STICKER_SLIDERS = STICKER_SLIDERS; exports.STROKE_SLIDERS = STROKE_SLIDERS; exports.SYMMETRY_MODES = SYMMETRY_MODES; exports.StencilSnapper = StencilSnapper; exports.StickerArtCache = StickerArtCache; exports.StickerBrowser = _chunk3VHH6V67cjs.StickerBrowser; exports.StickerSpray = StickerSpray; exports.TIP_GRAIN_MODES = _chunkGHGBIAWQcjs.TIP_GRAIN_MODES; exports.TRACING_NODE_ID = TRACING_NODE_ID; exports.ThickStrokeDriver = ThickStrokeDriver; exports.TileableNoise = _chunk3K6HWEXZcjs.TileableNoise; exports.TipGrain = _chunkSNAFFCAXcjs.TipGrain; exports.WET_FLOW_KINDS = _chunkN5IMDAHMcjs.WET_FLOW_KINDS; exports.WET_GPU_MODES = _chunkSNAFFCAXcjs.WET_GPU_MODES; exports.WET_GPU_OPTIONS = WET_GPU_OPTIONS; exports.WET_MEDIA = _chunkGHGBIAWQcjs.WET_MEDIA; exports.WET_MEDIUM_LABELS = WET_MEDIUM_LABELS; exports.WET_MEDIUM_PARAMS = _chunkSNAFFCAXcjs.WET_MEDIUM_PARAMS; exports.WET_PARAM_KEYS = _chunkN5IMDAHMcjs.WET_PARAM_KEYS; exports.WET_PARAM_SCHEMA = WET_PARAM_SCHEMA; exports.WET_PARAM_SLIDERS = WET_PARAM_SLIDERS; exports.WET_SPEED_SLIDER = WET_SPEED_SLIDER; exports.WET_TILT_SLIDERS = WET_TILT_SLIDERS; exports.WET_TOOLS = _chunkGHGBIAWQcjs.WET_TOOLS; exports.WET_TOOL_LABELS = WET_TOOL_LABELS; exports.WetStrokeDriver = _chunkSNAFFCAXcjs.WetStrokeDriver; exports.addPaintGradientStop = _chunkNIBFKXMDcjs.addPaintGradientStop; exports.addPolygonArea = addPolygonArea; exports.affineCopy = affineCopy; exports.applyAffine = applyAffine; exports.backlightOf = backlightOf; exports.brushEngineControls = _chunk3JKCREEUcjs.brushEngineControls; exports.brushLoadColor = brushLoadColor; exports.brushLoadForStroke = brushLoadForStroke; exports.brushTakesPaint = _chunkGHGBIAWQcjs.brushTakesPaint; exports.brushToJSON = _chunkGHGBIAWQcjs.brushToJSON; exports.buildTimeLapse = buildTimeLapse; exports.checkPaintEffectPlace = checkPaintEffectPlace; exports.clonePaper = _chunkSNAFFCAXcjs.clonePaper; exports.colorHarmony = colorHarmony2; exports.composeAffine = composeAffine; exports.contactSheet = contactSheet; exports.createPaintAgentStrokes = createPaintAgentStrokes; exports.createPaintBrushLibraryToolProvider = createPaintBrushLibraryToolProvider; exports.createPaintChangeFeed = createPaintChangeFeed; exports.createPaintCompositor = createPaintCompositor; exports.createPaintConformanceHost = createPaintConformanceHost; exports.createPaintDocument = createPaintDocument; exports.createPaintEditorDocument = createPaintEditorDocument; exports.createPaintEditorToolProvider = createPaintEditorToolProvider; exports.createPaintEffectsToolProvider = createPaintEffectsToolProvider; exports.createPaintLayer = createPaintLayer; exports.createPaintProposalToolProvider = createPaintProposalToolProvider; exports.createPaintProposals = createPaintProposals; exports.createPaintReplayTools = createPaintReplayTools; exports.createPaintStickerTools = createPaintStickerTools; exports.createPaintThickTools = createPaintThickTools; exports.createPaintWetTools = createPaintWetTools; exports.decodeImageBlob = decodeImageBlob; exports.defaultGuides = defaultGuides; exports.defaultImageEncoder = defaultImageEncoder; exports.defaultStickerRasterizer = defaultStickerRasterizer; exports.deserializePaintDocument = deserializePaintDocument; exports.deserializePaintDocumentAsync = deserializePaintDocumentAsync; exports.documentExtensions = documentExtensions; exports.documentToScreen = documentToScreen; exports.downloadBytes = downloadBytes; exports.downsampleRgba = downsampleRgba; exports.drawSticker = drawSticker; exports.drawWaterOverlay = drawWaterOverlay; exports.effectDabField = _chunkSNAFFCAXcjs.effectDabField; exports.effectLayersToJSON = effectLayersToJSON; exports.effectPaintKey = _chunkSNAFFCAXcjs.effectPaintKey; exports.effectPaintSize = _chunkSNAFFCAXcjs.effectPaintSize; exports.emptiedLayers = emptiedLayers; exports.emptyThickChannels = emptyThickChannels; exports.engineBrushSourceIds = engineBrushSourceIds; exports.fitZoom = fitZoom; exports.grainCatch = _chunkNIBFKXMDcjs.grainCatch; exports.grainHeights = _chunkNIBFKXMDcjs.grainHeights; exports.guideOverlay = guideOverlay; exports.handlePaintShortcut = handlePaintShortcut; exports.hash2 = _chunk3K6HWEXZcjs.hash2; exports.hexToPaintRgb = _chunkNIBFKXMDcjs.hexToPaintRgb; exports.hexToRgb8 = _chunkSNAFFCAXcjs.hexToRgb8; exports.hslToRgb = hslToRgb; exports.hsvToRgb = hsvToRgb; exports.hueToWheel = _chunkI3Y2Q3PMcjs.hueToWheel; exports.inferEffectPathControl = _chunkSNAFFCAXcjs.inferEffectPathControl; exports.invertAffine = invertAffine; exports.isBlendMode = _chunk2VX55NFMcjs.isBlendMode; exports.isGradientPaint = _chunkNIBFKXMDcjs.isGradientPaint; exports.isPaintEffectPaint = _chunkSNAFFCAXcjs.isPaintEffectPaint; exports.isPainterlyBlendMode = _chunk2VX55NFMcjs.isPainterlyBlendMode; exports.isPalmTouch = isPalmTouch; exports.isWetBrush = _chunkGHGBIAWQcjs.isWetBrush; exports.isWetCapable = _chunkGHGBIAWQcjs.isWetCapable; exports.lightTile = lightTile; exports.lightingKey = lightingKey; exports.liveStrokeBounds = liveStrokeBounds; exports.liveStrokeRefusal = liveStrokeRefusal; exports.mapPenPoint = mapPenPoint; exports.mix32 = _chunk3K6HWEXZcjs.mix32; exports.mixPixels = mixPixels; exports.mixerLoadForStroke = mixerLoadForStroke; exports.mixerTip = _chunkSNAFFCAXcjs.mixerTip; exports.multiColorForDab = _chunkSNAFFCAXcjs.multiColorForDab; exports.multiColorGradient = _chunkSNAFFCAXcjs.multiColorGradient; exports.multiColorPalette = _chunkSNAFFCAXcjs.multiColorPalette; exports.multiColorSliders = _chunk3JKCREEUcjs.multiColorSliders; exports.multiColorToPaint = _chunkGHGBIAWQcjs.multiColorToPaint; exports.newPaintLayerId = newPaintLayerId; exports.nextPaperEffectVersion = nextPaperEffectVersion; exports.normalizeBehavior = _chunkGHGBIAWQcjs.normalizeBehavior; exports.normalizeBristle = _chunkGHGBIAWQcjs.normalizeBristle; exports.normalizeBrushStroke = normalizeBrushStroke; exports.normalizeCanvas = normalizeCanvas; exports.normalizeDynamics = _chunkGHGBIAWQcjs.normalizeDynamics; exports.normalizeFlow = _chunkN5IMDAHMcjs.normalizeFlow; exports.normalizeGhost = _chunkGHGBIAWQcjs.normalizeGhost; exports.normalizeHexColor = _chunkNIBFKXMDcjs.normalizeHexColor; exports.normalizeImpasto = _chunkGHGBIAWQcjs.normalizeImpasto; exports.normalizeLight = _chunkGHGBIAWQcjs.normalizeLight; exports.normalizeLighting = normalizeLighting; exports.normalizeMultiColor = _chunkGHGBIAWQcjs.normalizeMultiColor; exports.normalizePaintBrush = _chunkGHGBIAWQcjs.normalizePaintBrush; exports.normalizePaper = _chunkSNAFFCAXcjs.normalizePaper; exports.normalizeParticle = _chunkGHGBIAWQcjs.normalizeParticle; exports.normalizePerspective = normalizePerspective; exports.normalizeRotation = normalizeRotation; exports.normalizeStencil = normalizeStencil; exports.normalizeStickerSettings = _chunkGHGBIAWQcjs.normalizeStickerSettings; exports.normalizeStickerUpdate = normalizeStickerUpdate; exports.normalizeSymmetry = normalizeSymmetry; exports.normalizeView = normalizeView; exports.normalizeWetBrush = _chunkGHGBIAWQcjs.normalizeWetBrush; exports.normalizeWetParams = _chunkN5IMDAHMcjs.normalizeWetParams; exports.overPixels = overPixels; exports.padSampleRadius = padSampleRadius; exports.paintAgentStrokePoints = paintAgentStrokePoints; exports.paintBrushPreviewRenderer = paintBrushPreviewRenderer; exports.paintContracts = paintContracts; exports.paintGradientMappingFor = _chunkNIBFKXMDcjs.paintGradientMappingFor; exports.paintPlaybackPanel = paintPlaybackPanel; exports.paintProposalGhost = paintProposalGhost; exports.paintShortcutFor = paintShortcutFor; exports.paintSourceColor = _chunkNIBFKXMDcjs.paintSourceColor; exports.paintSourceCss = _chunkNIBFKXMDcjs.paintSourceCss; exports.paintToMultiColor = _chunkGHGBIAWQcjs.paintToMultiColor; exports.paperEffectFromJSON = paperEffectFromJSON; exports.paperEffectToJSON = paperEffectToJSON; exports.paperGrain = paperGrain; exports.paperKey = paperKey; exports.paperNode = paperNode; exports.paperPreset = _chunkSNAFFCAXcjs.paperPreset; exports.parseBrushLibrary = _chunkGHGBIAWQcjs.parseBrushLibrary; exports.parseHexColor = parseHexColor; exports.parsePaintSource = _chunkNIBFKXMDcjs.parsePaintSource; exports.patchBrushValue = _chunk3JKCREEUcjs.patchBrushValue; exports.patchPath = patchPath; exports.penOrientation = _chunkSNAFFCAXcjs.penOrientation; exports.perspectiveDirections = perspectiveDirections; exports.perspectiveGuideLines = perspectiveGuideLines; exports.planPaintToolPlayback = planPaintToolPlayback; exports.pointerToPenPoint = pointerToPenPoint; exports.quickStencil = quickStencil; exports.rand01 = _chunk3K6HWEXZcjs.rand01; exports.randSigned = _chunk3K6HWEXZcjs.randSigned; exports.readEffectStrokeMap = _chunkSNAFFCAXcjs.readEffectStrokeMap; exports.readPaintEffectPaint = _chunkSNAFFCAXcjs.readPaintEffectPaint; exports.readPaintEffectSource = readPaintEffectSource; exports.readPaintSource = _chunkNIBFKXMDcjs.readPaintSource; exports.readPath = readPath; exports.readSwatch = readSwatch; exports.reliefInfo = reliefInfo; exports.removePaintGradientStop = _chunkNIBFKXMDcjs.removePaintGradientStop; exports.renderBrushThumbnail = renderBrushThumbnail; exports.renderColorWheel = renderColorWheel; exports.renderPaper = _chunkSNAFFCAXcjs.renderPaper; exports.renderStickers = renderStickers; exports.replayFrame = replayFrame; exports.replayItems = replayItems; exports.replayPainting = replayPainting; exports.resolvePaintGradient = _chunkNIBFKXMDcjs.resolvePaintGradient; exports.reversePaintGradient = _chunkNIBFKXMDcjs.reversePaintGradient; exports.rgbToHexColor = rgbToHexColor; exports.rgbToHsl = rgbToHsl; exports.rgbToHsv = rgbToHsv; exports.sampleArt = sampleArt; exports.sampleEffectAt = _chunkSNAFFCAXcjs.sampleEffectAt; exports.sampleEffectField = _chunkSNAFFCAXcjs.sampleEffectField; exports.samplePath = samplePath; exports.samplePressure = samplePressure; exports.scalePaintGradient = _chunkNIBFKXMDcjs.scalePaintGradient; exports.scaleStencil = scaleStencil; exports.screenToDocument = screenToDocument; exports.seedFromString = _chunk3K6HWEXZcjs.seedFromString; exports.serializePaintDocument = serializePaintDocument; exports.serializePaintDocumentExternal = serializePaintDocumentExternal; exports.solidPaint = _chunkNIBFKXMDcjs.solidPaint; exports.stampCoverage = _chunkRDFHWAHLcjs.stampCoverage; exports.standardBlendMode = _chunk2VX55NFMcjs.standardBlendMode; exports.startWetClock = startWetClock; exports.stencilMask = stencilMask; exports.stencilOutline = stencilOutline; exports.stickerAt = stickerAt; exports.stickerRect = stickerRect; exports.stickerRefLabel = stickerRefLabel; exports.stickerStamp = stickerStamp; exports.stickerSurface = stickerSurface; exports.strokeBounds = strokeBounds; exports.strokeDuration = strokeDuration; exports.strokePathPoints = _chunkSNAFFCAXcjs.strokePathPoints; exports.strokeSchedule = strokeSchedule; exports.strokeToJSON = strokeToJSON; exports.sweepPath = sweepPath; exports.symmetryAxisAngles = symmetryAxisAngles; exports.symmetryAxisSegments = symmetryAxisSegments; exports.symmetryCopies = symmetryCopies; exports.thickFromJSON = thickFromJSON; exports.thickToJSON = thickToJSON; exports.thumbnailStroke = thumbnailStroke; exports.tiltToOrientation = _chunkSNAFFCAXcjs.tiltToOrientation; exports.timeLapseVideo = timeLapseVideo; exports.timeLapseZip = timeLapseZip; exports.toStrokePoint = _chunkSNAFFCAXcjs.toStrokePoint; exports.toggleDotTexture = toggleDotTexture; exports.toggleStamp = toggleStamp; exports.toggleStickerRef = toggleStickerRef; exports.translateStencil = translateStencil; exports.updatePaintGradientStop = _chunkNIBFKXMDcjs.updatePaintGradientStop; exports.usesPaintExchange = _chunkGHGBIAWQcjs.usesPaintExchange; exports.variationAffine = variationAffine; exports.varyStroke = varyStroke; exports.viewCssTransform = viewCssTransform; exports.viewMatrix = viewMatrix; exports.viewPenToDocument = viewPenToDocument; exports.wetEngineSummary = wetEngineSummary; exports.wetPaperInput = _chunkSNAFFCAXcjs.wetPaperInput; exports.wetPigmentOf = _chunkSNAFFCAXcjs.wetPigmentOf; exports.wetSupport = _chunkN5IMDAHMcjs.wetSupport; exports.wheelAngle = wheelAngle; exports.wheelPick = wheelPick; exports.wheelPoint = wheelPoint; exports.wheelToHue = _chunkI3Y2Q3PMcjs.wheelToHue; exports.withPaintPlayback = withPaintPlayback; exports.withStrokePath = _chunkSNAFFCAXcjs.withStrokePath;