@pixerate/editor 0.269.2 → 0.271.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 (74) hide show
  1. package/README.md +5 -2
  2. package/dist/agent/index.cjs +30 -30
  3. package/dist/agent/index.js +3 -3
  4. package/dist/animation-editor/index.cjs +62 -62
  5. package/dist/animation-editor/index.js +4 -4
  6. package/dist/canvas/editorDocument.d.cts +3 -1
  7. package/dist/canvas/editorDocument.d.ts +3 -1
  8. package/dist/canvas/index.cjs +53 -27
  9. package/dist/canvas/index.js +34 -8
  10. package/dist/chart/index.cjs +21 -21
  11. package/dist/chart/index.js +2 -2
  12. package/dist/{chunk-GBEF2D4P.js → chunk-23YL2EAB.js} +1 -1
  13. package/dist/{chunk-QGVTOCNB.js → chunk-6ZSFRRJI.js} +1 -1
  14. package/dist/{chunk-4YSPQGZW.js → chunk-B5W677L7.js} +1 -1
  15. package/dist/{chunk-4NMPUJUK.cjs → chunk-DDL3ZBHK.cjs} +86 -86
  16. package/dist/{chunk-T4JPGBW3.cjs → chunk-DGITFN73.cjs} +8 -8
  17. package/dist/{chunk-PY4GWSE2.cjs → chunk-EBFPMSJO.cjs} +27 -5
  18. package/dist/{chunk-NS62CQ2B.js → chunk-GAZPHCTV.js} +23 -2
  19. package/dist/{chunk-YYBW6DF2.cjs → chunk-GSLOH2IN.cjs} +2 -2
  20. package/dist/{chunk-56RHCIJV.cjs → chunk-JJ2H25JG.cjs} +237 -170
  21. package/dist/{chunk-CBVNCWJM.cjs → chunk-LBDC5434.cjs} +2 -2
  22. package/dist/{chunk-BENSE3VX.cjs → chunk-M2ZVPU7L.cjs} +23 -23
  23. package/dist/{chunk-MQ6MGIQM.js → chunk-NMZQMPFZ.js} +1 -1
  24. package/dist/{chunk-AI4F33IV.cjs → chunk-NQUKTRKN.cjs} +45 -45
  25. package/dist/{chunk-4CPOKP27.js → chunk-QYXUE37Q.js} +1 -1
  26. package/dist/{chunk-MWUZCEFT.js → chunk-S2XPXA47.js} +1 -1
  27. package/dist/{chunk-EHLOCVWB.js → chunk-T2URHAJX.js} +27 -5
  28. package/dist/{chunk-FUDP5QBB.js → chunk-TNHDCP4R.js} +70 -3
  29. package/dist/{chunk-VBRHE4AM.cjs → chunk-U2ASNGO6.cjs} +35 -35
  30. package/dist/{chunk-WKPXOGZZ.cjs → chunk-WPLGZBNE.cjs} +23 -2
  31. package/dist/{chunk-N3UMQVKX.js → chunk-X4FTNFIA.js} +1 -1
  32. package/dist/{chunk-2OQGPEHH.cjs → chunk-XUDMRMXQ.cjs} +2 -2
  33. package/dist/{chunk-THBJHPUL.js → chunk-YNFSH72F.js} +1 -1
  34. package/dist/diagram/index.cjs +2 -2
  35. package/dist/diagram/index.js +1 -1
  36. package/dist/effects/index.cjs +8 -5
  37. package/dist/effects/index.js +6 -3
  38. package/dist/effects/pool.d.cts +9 -0
  39. package/dist/effects/pool.d.ts +9 -0
  40. package/dist/effects/types.d.cts +2 -0
  41. package/dist/effects/types.d.ts +2 -0
  42. package/dist/extensions/index.cjs +5 -5
  43. package/dist/extensions/index.js +4 -4
  44. package/dist/gradient/index.cjs +2 -2
  45. package/dist/gradient/index.js +1 -1
  46. package/dist/history/HistoryManager.d.cts +9 -0
  47. package/dist/history/HistoryManager.d.ts +9 -0
  48. package/dist/history/index.cjs +2 -2
  49. package/dist/history/index.js +1 -1
  50. package/dist/history/types.d.cts +5 -2
  51. package/dist/history/types.d.ts +5 -2
  52. package/dist/image-editor/index.cjs +784 -784
  53. package/dist/image-editor/index.js +4 -4
  54. package/dist/index.cjs +10 -10
  55. package/dist/index.js +4 -4
  56. package/dist/paint-editor/controller.d.cts +75 -4
  57. package/dist/paint-editor/controller.d.ts +75 -4
  58. package/dist/paint-editor/effect-paint.d.cts +33 -8
  59. package/dist/paint-editor/effect-paint.d.ts +33 -8
  60. package/dist/paint-editor/effects.d.cts +4 -0
  61. package/dist/paint-editor/effects.d.ts +4 -0
  62. package/dist/paint-editor/index.cjs +692 -398
  63. package/dist/paint-editor/index.js +362 -68
  64. package/dist/paint-editor/stroke.d.cts +13 -5
  65. package/dist/paint-editor/stroke.d.ts +13 -5
  66. package/dist/parameters/index.cjs +2 -2
  67. package/dist/parameters/index.js +1 -1
  68. package/dist/vector/index.cjs +998 -998
  69. package/dist/vector/index.js +4 -4
  70. package/dist/video-editor/index.cjs +321 -321
  71. package/dist/video-editor/index.js +4 -4
  72. package/package.json +1 -1
  73. package/skills/pixerate-paint-editor/SKILL.md +2 -2
  74. package/skills/pixerate-paint-editor/references/effect-paint.md +28 -6
@@ -22,7 +22,7 @@ var _chunkPFHJS4HEcjs = require('../chunk-PFHJS4HE.cjs');
22
22
  var _chunkBPJSI4NTcjs = require('../chunk-BPJSI4NT.cjs');
23
23
 
24
24
 
25
- var _chunkCBVNCWJMcjs = require('../chunk-CBVNCWJM.cjs');
25
+ var _chunkLBDC5434cjs = require('../chunk-LBDC5434.cjs');
26
26
 
27
27
 
28
28
  var _chunk7TD63DZPcjs = require('../chunk-7TD63DZP.cjs');
@@ -34,7 +34,7 @@ var _chunk7TD63DZPcjs = require('../chunk-7TD63DZP.cjs');
34
34
 
35
35
 
36
36
 
37
- var _chunk4NMPUJUKcjs = require('../chunk-4NMPUJUK.cjs');
37
+ var _chunkDDL3ZBHKcjs = require('../chunk-DDL3ZBHK.cjs');
38
38
  require('../chunk-YZWM6ZIP.cjs');
39
39
  require('../chunk-3ZRNK3RO.cjs');
40
40
 
@@ -113,7 +113,11 @@ var _chunkK7ENM55Pcjs = require('../chunk-K7ENM55P.cjs');
113
113
 
114
114
 
115
115
 
116
- var _chunk56RHCIJVcjs = require('../chunk-56RHCIJV.cjs');
116
+
117
+
118
+
119
+
120
+ var _chunkJJ2H25JGcjs = require('../chunk-JJ2H25JG.cjs');
117
121
 
118
122
 
119
123
 
@@ -201,7 +205,8 @@ var _chunkJBZRVLXVcjs = require('../chunk-JBZRVLXV.cjs');
201
205
  var _chunkU67EN7GGcjs = require('../chunk-U67EN7GG.cjs');
202
206
 
203
207
 
204
- var _chunkPY4GWSE2cjs = require('../chunk-PY4GWSE2.cjs');
208
+ var _chunkEBFPMSJOcjs = require('../chunk-EBFPMSJO.cjs');
209
+
205
210
 
206
211
 
207
212
 
@@ -380,7 +385,7 @@ function normalizeCanvas(raw) {
380
385
  function createPaintDocument(options = {}) {
381
386
  const canvas = normalizeCanvas({ width: _nullishCoalesce(options.width, () => ( 2048)), height: _nullishCoalesce(options.height, () => ( 1536)), dpi: options.dpi });
382
387
  const layer = createPaintLayer("Layer 1");
383
- return { canvas, paper: _chunk56RHCIJVcjs.normalizePaper.call(void 0, _nullishCoalesce(options.paper, () => ( {}))), layers: [layer], activeLayerId: layer.id, strokes: [] };
388
+ return { canvas, paper: _chunkJJ2H25JGcjs.normalizePaper.call(void 0, _nullishCoalesce(options.paper, () => ( {}))), layers: [layer], activeLayerId: layer.id, strokes: [] };
384
389
  }
385
390
 
386
391
  // src/paint-editor/thick.ts
@@ -511,12 +516,12 @@ var ThickStrokeDriver = (_class2 = class {
511
516
  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
517
  this.init = init;
513
518
  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];
519
+ this.smoother = new (0, _chunkJJ2H25JGcjs.PenSmoother)(b.tip.smoothing, b.pressureSmoothing);
520
+ const copies = init.copies.length ? init.copies : [_chunkJJ2H25JGcjs.IDENTITY_COPY];
516
521
  this.copies = copies;
517
522
  const rates = _chunkNIBFKXMDcjs.exchangeRates.call(void 0, b.behavior.pickup, b.behavior.mix, 1, b.behavior.mixing);
518
523
  this.states = copies.map((c, i) => ({
519
- walker: new (0, _chunk56RHCIJVcjs.PenDabWalker)(b, init.seed + i * 7919 | 0, c.linear),
524
+ walker: new (0, _chunkJJ2H25JGcjs.PenDabWalker)(b, init.seed + i * 7919 | 0, c.linear),
520
525
  exchange: new (0, _chunkNIBFKXMDcjs.PaintExchange)(rates, init.load),
521
526
  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
527
  carried: null,
@@ -662,7 +667,7 @@ var ThickStrokeDriver = (_class2 = class {
662
667
  let flow = 1;
663
668
  const effect = this.init.effect;
664
669
  if (effect) {
665
- _chunk56RHCIJVcjs.sampleEffectAt.call(void 0, effect, d.x, d.y, this.centre, d);
670
+ _chunkJJ2H25JGcjs.sampleEffectAt.call(void 0, effect, d.x, d.y, this.centre, d);
666
671
  ex.setReservoirColor(this.centre[0], this.centre[1], this.centre[2]);
667
672
  } else if (this.sampler) {
668
673
  const g = this.sampler.dab(d, this.sample);
@@ -679,7 +684,7 @@ var ThickStrokeDriver = (_class2 = class {
679
684
  let field = null;
680
685
  if (effect) {
681
686
  field = new Float32Array(n * 3);
682
- _chunk56RHCIJVcjs.effectDabField.call(void 0, effect, rect, cov, this.centre, this.paint, field, 0, d);
687
+ _chunkJJ2H25JGcjs.effectDabField.call(void 0, effect, rect, cov, this.centre, this.paint, field, 0, d);
683
688
  }
684
689
  this.medium.deposit(rect, cov, dep, this.paint, ex.paintPigment, field);
685
690
  }
@@ -1068,11 +1073,11 @@ var MarkStroke = (_class4 = class {
1068
1073
  this.options = options;
1069
1074
  this.sampler = options.paint ? new (0, _chunkNIBFKXMDcjs.PaintGradientSampler)(options.paint, _nullishCoalesce(options.seed, () => ( 0))) : null;
1070
1075
  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];
1076
+ this.smoother = new (0, _chunkJJ2H25JGcjs.PenSmoother)(brush.tip.smoothing, brush.pressureSmoothing);
1077
+ this.copies = _optionalChain([options, 'access', _31 => _31.copies, 'optionalAccess', _32 => _32.length]) ? options.copies : [_chunkJJ2H25JGcjs.IDENTITY_COPY];
1073
1078
  this.seed = _nullishCoalesce(options.seed, () => ( 0));
1074
1079
  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));
1080
+ this.walkers = this.copies.map((c, i) => new (0, _chunkJJ2H25JGcjs.PenDabWalker)(fine, (_nullishCoalesce(options.seed, () => ( 0))) + i * 7919 | 0, c.linear));
1076
1081
  this.depth = options.grain && !options.grain.flat ? Math.min(1, Math.max(0, options.paperDepth * brush.grain)) : 0;
1077
1082
  }
1078
1083
 
@@ -1151,7 +1156,7 @@ var MarkStroke = (_class4 = class {
1151
1156
  */
1152
1157
  stamp(x, y, r, kind, rotation, seed, alpha, opacity, pressure, rects) {
1153
1158
  if (!(r > 0.05) || !(alpha > 0)) return;
1154
- const sample = _chunk56RHCIJVcjs.stampSampler.call(void 0, kind, this.options.stampArt);
1159
+ const sample = _chunkJJ2H25JGcjs.stampSampler.call(void 0, kind, this.options.stampArt);
1155
1160
  if (!sample) return this.mark(x, y, r, alpha, opacity, pressure, rects);
1156
1161
  const reach = Math.max(0.5, r) * Math.SQRT2 + 1;
1157
1162
  const rect = { x: Math.floor(x - reach), y: Math.floor(y - reach), width: 0, height: 0 };
@@ -1201,7 +1206,7 @@ var MarkStroke = (_class4 = class {
1201
1206
  if (this.options.effect) {
1202
1207
  if (this.field.length < n * 3) this.field = new Float32Array(n * 3);
1203
1208
  const field = this.field.subarray(0, n * 3);
1204
- _chunk56RHCIJVcjs.sampleEffectField.call(void 0, this.options.effect, rect, vals, field, this.pen);
1209
+ _chunkJJ2H25JGcjs.sampleEffectField.call(void 0, this.options.effect, rect, vals, field, this.pen);
1205
1210
  this.coverage.accumulate(rect, vals, opacity, null, field);
1206
1211
  } else {
1207
1212
  const color = this.markColor(x, y);
@@ -1880,11 +1885,11 @@ var StickerSpray = (_class7 = class {
1880
1885
  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
1886
  this.init = init;
1882
1887
  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];
1888
+ this.smoother = new (0, _chunkJJ2H25JGcjs.PenSmoother)(b.tip.smoothing, b.pressureSmoothing);
1889
+ this.copies = init.copies.length ? init.copies : [_chunkJJ2H25JGcjs.IDENTITY_COPY];
1885
1890
  const spacing = Math.max(0.05, 1 / Math.max(0.05, b.sticker.density * 4));
1886
1891
  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));
1892
+ this.walkers = this.copies.map((c, i) => new (0, _chunkJJ2H25JGcjs.PenDabWalker)(walk, init.seed + i * 7919 | 0, c.linear));
1888
1893
  this.medium = new (0, _chunkNIBFKXMDcjs.TileMedium)(init.target, {});
1889
1894
  this.next = init.nextId;
1890
1895
  }
@@ -1970,7 +1975,7 @@ var StickerSpray = (_class7 = class {
1970
1975
  const effect = this.init.effect;
1971
1976
  if (effect) {
1972
1977
  const rgb = [0, 0, 0];
1973
- const alpha = _chunk56RHCIJVcjs.sampleEffectAt.call(void 0, effect, d.x + dx, d.y + dy, rgb, d);
1978
+ const alpha = _chunkJJ2H25JGcjs.sampleEffectAt.call(void 0, effect, d.x + dx, d.y + dy, rgb, d);
1974
1979
  return { color: "#" + rgb.map((c) => Math.round(c * 255).toString(16).padStart(2, "0")).join(""), alpha };
1975
1980
  }
1976
1981
  const g = this.init.paint;
@@ -2099,11 +2104,10 @@ var PaintStrokeSession = (_class8 = class _PaintStrokeSession {
2099
2104
  this.layerId = init.layerId;
2100
2105
  this.base = init.surface;
2101
2106
  this.live = new Map(this.base.tiles);
2102
- this.copies = init.copies.length ? init.copies : [_chunk56RHCIJVcjs.IDENTITY_COPY];
2107
+ this.copies = init.copies.length ? init.copies : [_chunkJJ2H25JGcjs.IDENTITY_COPY];
2103
2108
  const brush = init.brush;
2104
2109
  if (init.wet) this.wetDriver = init.wet.driver;
2105
2110
  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
2111
  this.apply = {
2108
2112
  mode: brush.engine === "eraser" ? "erase" : "paint",
2109
2113
  color: init.color,
@@ -2114,31 +2118,7 @@ var PaintStrokeSession = (_class8 = class _PaintStrokeSession {
2114
2118
  selection: _nullishCoalesce(init.selection, () => ( null)),
2115
2119
  offset: init.offset
2116
2120
  };
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
- }
2121
+ if (!this.wetDriver) this.build(_nullishCoalesce(_optionalChain([init, 'access', _50 => _50.effect, 'optionalAccess', _51 => _51.pixels]), () => ( null)));
2142
2122
  }
2143
2123
 
2144
2124
 
@@ -2167,6 +2147,52 @@ var PaintStrokeSession = (_class8 = class _PaintStrokeSession {
2167
2147
  __init48() {this.result = null}
2168
2148
  /** The mask stencils this stroke was painted with when they are not the editor's (replays). */
2169
2149
  __init49() {this.maskStencils = null}
2150
+ /** Sets up the marks' engine (every kind but wet, which the wet layer paints), sampling `effect` for effect paint. */
2151
+ build(effect) {
2152
+ const init = this.init;
2153
+ const brush = init.brush;
2154
+ this.dry = this.wet = this.thickDriver = this.stickerSpray = null;
2155
+ if (init.sticker) {
2156
+ 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 });
2157
+ } else if (init.thick) {
2158
+ const rgb = (c) => [c[0] / 255, c[1] / 255, c[2] / 255];
2159
+ 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 });
2160
+ } else if (brush.engine === "mixer" || brush.engine === "blender" || brush.engine === "smudge" || _chunkEU2ZZA6Lcjs.usesPaintExchange.call(void 0, brush, Boolean(init.paint))) {
2161
+ const rgb = (c) => [c[0] / 255, c[1] / 255, c[2] / 255];
2162
+ this.wet = new (0, _chunkJJ2H25JGcjs.PaintDabStroke)(brush, {
2163
+ target: this.tileTarget(),
2164
+ color: rgb(init.color),
2165
+ secondary: rgb(_nullishCoalesce(init.secondary, () => ( init.background))),
2166
+ load: init.mixerLoad,
2167
+ grain: init.grain,
2168
+ paperDepth: init.paperDepth,
2169
+ seed: init.seed,
2170
+ copies: this.copies,
2171
+ paint: _nullishCoalesce(init.paint, () => ( null)),
2172
+ effect,
2173
+ stampArt: init.stampArt
2174
+ });
2175
+ } else {
2176
+ const opts = { grain: init.grain, paperDepth: init.paperDepth, seed: init.seed, copies: this.copies, paint: _nullishCoalesce(init.paint, () => ( null)), effect, stampArt: init.stampArt };
2177
+ this.dry = brush.engine === "particle" ? new ParticleStroke(brush, opts) : brush.engine === "bristle" ? new BristleStroke(brush, opts) : new (0, _chunkJJ2H25JGcjs.DryStroke)(brush, opts);
2178
+ }
2179
+ }
2180
+ /**
2181
+ * Paints the stroke so far again, sampling new effect pixels: a path-mapped effect rendered
2182
+ * along the path drawn so far (`map: { by: 'path' }`). Only the live preview changes; the stroke
2183
+ * keeps recording its own paint. Nothing for wet strokes or once the stroke has ended.
2184
+ */
2185
+ repaintEffect(pixels) {
2186
+ if (this.closed || this.wetDriver || !this.init.effect) return;
2187
+ const was = this.bounds;
2188
+ this.live = new Map(this.base.tiles);
2189
+ this.touched.clear();
2190
+ this.fresh.clear();
2191
+ this.bounds = null;
2192
+ this.build(pixels);
2193
+ 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) : [];
2194
+ this.update(was ? [...rects, was] : rects);
2195
+ }
2170
2196
  /** The stroke's twin over the light channel: the same marks in grey at the brush's light amount (see `light.ts`). */
2171
2197
  makeLightTwin(light) {
2172
2198
  const init = this.init;
@@ -2660,7 +2686,7 @@ function normalizeBrushStroke(raw) {
2660
2686
  }
2661
2687
  if (st.length) out.stencils = st;
2662
2688
  }
2663
- const effect = _chunk56RHCIJVcjs.readPaintEffectPaint.call(void 0, r.paint);
2689
+ const effect = _chunkJJ2H25JGcjs.readPaintEffectPaint.call(void 0, r.paint);
2664
2690
  const paint = effect ? null : _chunkNIBFKXMDcjs.readPaintSource.call(void 0, r.paint);
2665
2691
  if (effect) out.paint = effect;
2666
2692
  else if (paint && paint.type === "gradient") out.paint = paint;
@@ -2703,8 +2729,9 @@ function varyStroke(stroke, m, v) {
2703
2729
  const brush = s !== 1 ? _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, { ...stroke.brush, tip: { ...stroke.brush.tip, size: stroke.brush.tip.size * s } }) : stroke.brush;
2704
2730
  const out = { ...stroke, brush, points };
2705
2731
  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])) {
2732
+ 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))) } };
2733
+ 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 = _chunkJJ2H25JGcjs.withStrokePath.call(void 0, stroke.paint, points);
2734
+ if (_optionalChain([stroke, 'access', _119 => _119.copies, 'optionalAccess', _120 => _120.length])) {
2708
2735
  const inv = invertAffine(m);
2709
2736
  out.copies = stroke.copies.map((c) => composeAffine(m, composeAffine(c, inv)));
2710
2737
  }
@@ -2723,7 +2750,7 @@ var paperNodes = /* @__PURE__ */ new WeakMap();
2723
2750
  function paperNode(paper, light) {
2724
2751
  let n = paperNodes.get(paper);
2725
2752
  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]))) {
2753
+ 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
2754
  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
2755
  paperNodes.set(paper, n);
2729
2756
  }
@@ -2745,7 +2772,7 @@ function paperTile(paper, r, light) {
2745
2772
  const key = `${paperKey(paper, light)}|${r.x},${r.y},${r.width},${r.height}`;
2746
2773
  let t = tileCache.get(key);
2747
2774
  if (!t) {
2748
- t = _chunk56RHCIJVcjs.renderPaper.call(void 0, paper, r, paperGrain(paper), light);
2775
+ t = _chunkJJ2H25JGcjs.renderPaper.call(void 0, paper, r, paperGrain(paper), light);
2749
2776
  if (tileCache.size > 512) tileCache.delete(tileCache.keys().next().value);
2750
2777
  tileCache.set(key, t);
2751
2778
  }
@@ -2844,17 +2871,17 @@ function header(state, options) {
2844
2871
  if (options.swatches !== void 0) out.swatches = JSON.parse(JSON.stringify(options.swatches));
2845
2872
  if (options.mixingPad !== void 0) out.mixingPad = JSON.parse(JSON.stringify(options.mixingPad));
2846
2873
  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));
2874
+ if (_optionalChain([state, 'access', _127 => _127.wetEvents, 'optionalAccess', _128 => _128.length])) out.wetEvents = JSON.parse(JSON.stringify(state.wetEvents));
2875
+ if (_optionalChain([state, 'access', _129 => _129.paintEvents, 'optionalAccess', _130 => _130.length])) out.paintEvents = JSON.parse(JSON.stringify(state.paintEvents));
2849
2876
  if (state.origin && (state.origin.x || state.origin.y)) out.origin = { ...state.origin };
2850
2877
  return out;
2851
2878
  }
2852
2879
  function serializePaintDocument(state, options = {}) {
2853
- const { layers, assets } = _chunk4NMPUJUKcjs.serializeLayers.call(void 0, state.layers);
2880
+ const { layers, assets } = _chunkDDL3ZBHKcjs.serializeLayers.call(void 0, state.layers);
2854
2881
  return { ...header(state, options), layers, assets };
2855
2882
  }
2856
2883
  async function serializePaintDocumentExternal(state, store, options = {}) {
2857
- const { layers, assets } = await _chunk4NMPUJUKcjs.serializeLayersExternal.call(void 0, state.layers, store);
2884
+ const { layers, assets } = await _chunkDDL3ZBHKcjs.serializeLayersExternal.call(void 0, state.layers, store);
2858
2885
  return { ...header(state, options), layers, assets };
2859
2886
  }
2860
2887
  function paintLayersOnly(layers, problems) {
@@ -2862,7 +2889,7 @@ function paintLayersOnly(layers, problems) {
2862
2889
  for (const l of layers) {
2863
2890
  if (l.type === "pixel") {
2864
2891
  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.`);
2892
+ if (_optionalChain([filters, 'optionalAccess', _131 => _131.length])) problems.push(`Layer "${l.name}": its filters are an image editor feature and were dropped.`);
2866
2893
  if (source) problems.push(`Layer "${l.name}" refers to an image editor source image; it loads empty.`);
2867
2894
  out.push(rest);
2868
2895
  } else if (l.type === "group") out.push({ ...l, children: paintLayersOnly(l.children, problems) });
@@ -2889,11 +2916,11 @@ function deserializePaintDocument(raw) {
2889
2916
  }
2890
2917
  const problems = [];
2891
2918
  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, () => ( {})));
2919
+ const paper = _chunkJJ2H25JGcjs.normalizePaper.call(void 0, _nullishCoalesce(r.paper, () => ( {})));
2893
2920
  const assets = r.assets && typeof r.assets === "object" ? r.assets : {};
2894
- const layers = paintLayersOnly(_chunk4NMPUJUKcjs.deserializeLayers.call(void 0, r.layers, { assets, problems }), problems);
2921
+ const layers = paintLayersOnly(_chunkDDL3ZBHKcjs.deserializeLayers.call(void 0, r.layers, { assets, problems }), problems);
2895
2922
  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));
2923
+ 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
2924
  const wetEvents = Array.isArray(r.wetEvents) ? r.wetEvents.filter((e) => e && typeof e === "object" && Number.isInteger(e.clock) && typeof e.kind === "string") : [];
2898
2925
  const state = { canvas, paper, layers, activeLayerId, strokes: readStrokes(r.strokes, problems) };
2899
2926
  if (wetEvents.length) state.wetEvents = wetEvents;
@@ -2907,7 +2934,7 @@ async function deserializePaintDocumentAsync(raw, store) {
2907
2934
  if (!raw || typeof raw !== "object") throw new Error("Not a paint document: expected a JSON object.");
2908
2935
  const r = raw;
2909
2936
  const problems = [];
2910
- const assets = await _chunk4NMPUJUKcjs.resolveExternalAssets.call(void 0, _nullishCoalesce(r.assets, () => ( {})), store, problems);
2937
+ const assets = await _chunkDDL3ZBHKcjs.resolveExternalAssets.call(void 0, _nullishCoalesce(r.assets, () => ( {})), store, problems);
2911
2938
  const loaded = deserializePaintDocument({ ...r, assets });
2912
2939
  return { ...loaded, problems: [...problems, ...loaded.problems] };
2913
2940
  }
@@ -2990,7 +3017,7 @@ function pointerToPenPoint(e, x, y, view) {
2990
3017
  const p = { x, y, pressure: samplePressure(e) };
2991
3018
  if (typeof e.timeStamp === "number" && Number.isFinite(e.timeStamp)) p.t = e.timeStamp;
2992
3019
  if (e.pointerType !== "pen") return p;
2993
- const o = _chunk56RHCIJVcjs.penOrientation.call(void 0, {
3020
+ const o = _chunkJJ2H25JGcjs.penOrientation.call(void 0, {
2994
3021
  x,
2995
3022
  y,
2996
3023
  altitude: typeof e.altitudeAngle === "number" ? e.altitudeAngle : void 0,
@@ -3038,7 +3065,7 @@ async function decodeImageBlob(blob) {
3038
3065
  if (!ctx) throw new Error("No 2D context to decode with.");
3039
3066
  ctx.drawImage(bitmap, 0, 0);
3040
3067
  const data = new Uint8ClampedArray(ctx.getImageData(0, 0, bitmap.width, bitmap.height).data);
3041
- _optionalChain([bitmap, 'access', _129 => _129.close, 'optionalCall', _130 => _130()]);
3068
+ _optionalChain([bitmap, 'access', _137 => _137.close, 'optionalCall', _138 => _138()]);
3042
3069
  return { width: bitmap.width, height: bitmap.height, data };
3043
3070
  }
3044
3071
  function downloadBytes(bytes, fileName, mimeType) {
@@ -3056,19 +3083,19 @@ function downloadBytes(bytes, fileName, mimeType) {
3056
3083
  var thumbWorld = null;
3057
3084
  function paintWetTestStroke(brush, paper, color, width, height) {
3058
3085
  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));
3086
+ _optionalChain([thumbWorld, 'optionalAccess', _139 => _139.destroy, 'call', _140 => _140()]);
3087
+ thumbWorld = new (0, _chunkJ5VQYK7Tcjs.WetWorld)(width, height, _chunkJJ2H25JGcjs.wetPaperInput.call(void 0, paper), { kernel: "typescript", threads: 0 });
3088
+ } else thumbWorld.setPaper(_chunkJJ2H25JGcjs.wetPaperInput.call(void 0, paper));
3062
3089
  const w = thumbWorld;
3063
3090
  if (w.hasLane("thumb")) w.removeLane("thumb");
3064
3091
  w.ensureLane("thumb");
3065
- const [r, g, b] = _chunk56RHCIJVcjs.hexToRgb8.call(void 0, color);
3092
+ const [r, g, b] = _chunkJJ2H25JGcjs.hexToRgb8.call(void 0, color);
3066
3093
  if (brush.wet.tool !== "paint" && brush.wet.tool !== "water") {
3067
3094
  const half = Math.ceil(height / 2);
3068
3095
  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
3096
  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));
3070
3097
  }
3071
- const driver = new (0, _chunk56RHCIJVcjs.WetStrokeDriver)({
3098
+ const driver = new (0, _chunkJJ2H25JGcjs.WetStrokeDriver)({
3072
3099
  world: w,
3073
3100
  laneId: "thumb",
3074
3101
  brush,
@@ -3076,9 +3103,9 @@ function paintWetTestStroke(brush, paper, color, width, height) {
3076
3103
  load: brushLoadForStroke(brush, _chunkNIBFKXMDcjs.EMPTY_MIXER_LOAD, [r / 255, g / 255, b / 255]),
3077
3104
  grain: paperGrain(paper),
3078
3105
  paperDepth: paper.depth,
3079
- paperColor: _chunk56RHCIJVcjs.hexToRgb8.call(void 0, paper.color),
3106
+ paperColor: _chunkJJ2H25JGcjs.hexToRgb8.call(void 0, paper.color),
3080
3107
  seed: 7,
3081
- copies: [_chunk56RHCIJVcjs.IDENTITY_COPY]
3108
+ copies: [_chunkJJ2H25JGcjs.IDENTITY_COPY]
3082
3109
  });
3083
3110
  driver.push(thumbnailStroke(width, height));
3084
3111
  driver.finish();
@@ -3098,7 +3125,7 @@ function thumbnailStroke(width, height) {
3098
3125
  return pts;
3099
3126
  }
3100
3127
  function paintTestStroke(surface, brush, paper, color, width, height, stampArt) {
3101
- const [r, g, b] = _chunk56RHCIJVcjs.hexToRgb8.call(void 0, color);
3128
+ const [r, g, b] = _chunkJJ2H25JGcjs.hexToRgb8.call(void 0, color);
3102
3129
  let result = surface;
3103
3130
  let thick = null;
3104
3131
  let light = null;
@@ -3119,13 +3146,13 @@ function paintTestStroke(surface, brush, paper, color, width, height, stampArt)
3119
3146
  lockTransparency: false,
3120
3147
  brush,
3121
3148
  color: [r, g, b, 255],
3122
- background: [..._chunk56RHCIJVcjs.hexToRgb8.call(void 0, paper.color), 255],
3149
+ background: [..._chunkJJ2H25JGcjs.hexToRgb8.call(void 0, paper.color), 255],
3123
3150
  grain: paperGrain(paper),
3124
3151
  paperDepth: paper.depth,
3125
3152
  seed: 7,
3126
3153
  colorHex: color,
3127
3154
  affineCopies: [],
3128
- copies: [_chunk56RHCIJVcjs.IDENTITY_COPY],
3155
+ copies: [_chunkJJ2H25JGcjs.IDENTITY_COPY],
3129
3156
  mixerLoad: brushLoadForStroke(brush, _chunkNIBFKXMDcjs.EMPTY_MIXER_LOAD, [r / 255, g / 255, b / 255]),
3130
3157
  thick: brush.engine === "impasto" ? { channels: emptyThickChannels() } : void 0,
3131
3158
  sticker: brush.engine === "sticker" ? { nextId: 1 } : void 0,
@@ -3143,7 +3170,7 @@ function renderBrushThumbnail(brush, options) {
3143
3170
  const height = Math.max(16, Math.min(512, Math.round(_nullishCoalesce(options.height, () => ( 48)))));
3144
3171
  const maxSize = height * 0.42;
3145
3172
  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];
3173
+ const rgba = [..._chunkJJ2H25JGcjs.hexToRgb8.call(void 0, options.color), 255];
3147
3174
  let surface = _chunk474IQG74cjs.emptySurface.call(void 0, 4);
3148
3175
  if (b.engine === "eraser") {
3149
3176
  surface = _chunk474IQG74cjs.fillRect.call(void 0, surface, { x: 0, y: 0, width, height }, rgba);
@@ -3402,11 +3429,11 @@ function readSwatch(raw) {
3402
3429
  if (!raw || typeof raw !== "object") return null;
3403
3430
  const r = raw;
3404
3431
  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;
3432
+ 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
3433
  if (!color) return null;
3407
3434
  const out = { color };
3408
3435
  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;
3436
+ if (_optionalChain([g, 'optionalAccess', _142 => _142.type]) === "gradient") out.paint = g;
3410
3437
  return out;
3411
3438
  }
3412
3439
  var DEFAULT_SWATCHES = [
@@ -3470,7 +3497,7 @@ var MixingPad = (_class10 = class {constructor() { _class10.prototype.__init52.c
3470
3497
  }
3471
3498
  /** Paints `points` with `brush` in `color` on the pad. */
3472
3499
  run(brush, points, color) {
3473
- const [r, g, b] = _chunk56RHCIJVcjs.hexToRgb8.call(void 0, color);
3500
+ const [r, g, b] = _chunkJJ2H25JGcjs.hexToRgb8.call(void 0, color);
3474
3501
  let result = null;
3475
3502
  const session = new PaintStrokeSession(
3476
3503
  { update: () => {
@@ -3488,7 +3515,7 @@ var MixingPad = (_class10 = class {constructor() { _class10.prototype.__init52.c
3488
3515
  seed: 1,
3489
3516
  colorHex: color,
3490
3517
  affineCopies: [],
3491
- copies: [_chunk56RHCIJVcjs.IDENTITY_COPY],
3518
+ copies: [_chunkJJ2H25JGcjs.IDENTITY_COPY],
3492
3519
  mixerLoad: brushLoadForStroke(brush, _chunkNIBFKXMDcjs.EMPTY_MIXER_LOAD, [r / 255, g / 255, b / 255])
3493
3520
  }
3494
3521
  );
@@ -3579,7 +3606,7 @@ var MixingPad = (_class10 = class {constructor() { _class10.prototype.__init52.c
3579
3606
  this.run(knife, stir, "#000000");
3580
3607
  }
3581
3608
  const mixed = _chunk2VX55NFMcjs.mixPigments.call(void 0,
3582
- paints2.map((p) => _chunk56RHCIJVcjs.hexToRgb8.call(void 0, p.color).map((v) => v / 255)),
3609
+ paints2.map((p) => _chunkJJ2H25JGcjs.hexToRgb8.call(void 0, p.color).map((v) => v / 255)),
3583
3610
  paints2.map((p) => p.parts)
3584
3611
  );
3585
3612
  const core = _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, { tip: { ...PAD_BLOB.tip, size: R * 1.1, hardness: 0.55 } }, PAD_BLOB);
@@ -3593,7 +3620,7 @@ var MixingPad = (_class10 = class {constructor() { _class10.prototype.__init52.c
3593
3620
  }
3594
3621
  /** Replaces the pad with a PNG (data URL or base64) of the pad's size, as `toPng` writes. */
3595
3622
  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);
3623
+ const bytes = png.startsWith("data:") ? _optionalChain([_chunkW5M3J7PVcjs.parseDataUrl.call(void 0, png), 'optionalAccess', _143 => _143.bytes]) : _chunkW5M3J7PVcjs.base64ToBytes.call(void 0, png);
3597
3624
  if (!bytes || !_chunkW5M3J7PVcjs.isPng.call(void 0, bytes)) throw new Error("The pad image is not a PNG data URL or base64 PNG.");
3598
3625
  const img = _chunkW5M3J7PVcjs.decodePng.call(void 0, bytes);
3599
3626
  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}.`);
@@ -3652,20 +3679,20 @@ function brushSpecOf(next, from) {
3652
3679
  const plain = _chunkEU2ZZA6Lcjs.migrateBrushV1.call(void 0, next);
3653
3680
  const out = copyJSON(plain);
3654
3681
  if (from.description) out.description = from.description;
3655
- if (_optionalChain([from, 'access', _136 => _136.tags, 'optionalAccess', _137 => _137.length])) out.tags = [...from.tags];
3682
+ if (_optionalChain([from, 'access', _144 => _144.tags, 'optionalAccess', _145 => _145.length])) out.tags = [...from.tags];
3656
3683
  if (out.kind === "mark" && from.kind === "mark") {
3657
3684
  if (from.medium) out.medium = from.medium;
3658
3685
  if (from.variety) out.variety = from.variety;
3659
3686
  }
3660
3687
  const colour = { ..._nullishCoalesce(from.colour, () => ( {})) };
3661
- if (_optionalChain([plain, 'access', _138 => _138.colour, 'optionalAccess', _139 => _139.default]) !== void 0) colour.default = plain.colour.default;
3688
+ if (_optionalChain([plain, 'access', _146 => _146.colour, 'optionalAccess', _147 => _147.default]) !== void 0) colour.default = plain.colour.default;
3662
3689
  else if (isObject(colour.default) && colour.default.type === "gradient") delete colour.default;
3663
3690
  if (Object.keys(colour).length) out.colour = copyJSON(colour);
3664
3691
  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)) {
3692
+ 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
3693
  out.light = { ...out.light, ...from.light.spill ? { spill: { ...from.light.spill } } : {}, ...from.light.glow !== void 0 ? { glow: from.light.glow } : {} };
3667
3694
  }
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) {
3695
+ 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
3696
  out.motion = { ..._nullishCoalesce(out.motion, () => ( {})), ...from.motion.live !== void 0 ? { live: from.motion.live } : {}, ...from.motion.fps !== void 0 ? { fps: from.motion.fps } : {} };
3670
3697
  }
3671
3698
  try {
@@ -3794,7 +3821,7 @@ var BrushSourceArtCache = (_class11 = class {constructor() { _class11.prototype.
3794
3821
  }
3795
3822
  }, _class11);
3796
3823
  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]), () => ( []))];
3824
+ 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]), () => ( []))];
3798
3825
  return [...new Set(refs.filter((r) => !!r && _chunkEU2ZZA6Lcjs.isBrushSourceRef.call(void 0, r)).map((r) => _chunkEU2ZZA6Lcjs.brushSourceIdOf.call(void 0, r)))];
3799
3826
  }
3800
3827
 
@@ -3895,8 +3922,8 @@ var BacklightCache = (_class12 = class {constructor() { _class12.prototype.__ini
3895
3922
  refs.length = 0;
3896
3923
  for (const l of layers) {
3897
3924
  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);
3925
+ tilesUnder(_optionalChain([l, 'access', _162 => _162.thick, 'optionalAccess', _163 => _163.height]), rect, l.offset, refs);
3926
+ tilesUnder(_optionalChain([l, 'access', _164 => _164.thick, 'optionalAccess', _165 => _165.material]), rect, l.offset, refs);
3900
3927
  }
3901
3928
  const k = _chunk474IQG74cjs.tileKey.call(void 0, tx, ty);
3902
3929
  let r = this.tiles.get(k);
@@ -3968,10 +3995,10 @@ function addTiles(a, b) {
3968
3995
  }
3969
3996
  function computeTile(paper, grain, amount, rect, layers) {
3970
3997
  const n = rect.width * rect.height;
3971
- const [p0, p1, p2] = _chunk56RHCIJVcjs.hexToRgb8.call(void 0, paper.color);
3998
+ const [p0, p1, p2] = _chunkJJ2H25JGcjs.hexToRgb8.call(void 0, paper.color);
3972
3999
  const pb = [p0, p1, p2];
3973
4000
  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)));
4001
+ const [c0, c1, c2] = _chunkJJ2H25JGcjs.hexToRgb8.call(void 0, _nullishCoalesce(paper.backlightColor, () => ( DEFAULT_BACKLIGHT_COLOR)));
3975
4002
  const t0 = new Float32Array(n).fill(amount * LIN[c0]);
3976
4003
  const t1 = new Float32Array(n).fill(amount * LIN[c1]);
3977
4004
  const t2 = new Float32Array(n).fill(amount * LIN[c2]);
@@ -3990,8 +4017,8 @@ function computeTile(paper, grain, amount, rect, layers) {
3990
4017
  const lr = { x: rect.x - l.offset.x, y: rect.y - l.offset.y, width: rect.width, height: rect.height };
3991
4018
  if (!l.surface.tiles.size) continue;
3992
4019
  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;
4020
+ 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;
4021
+ 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
4022
  const op = l.opacity;
3996
4023
  for (let i = 0; i < n; i++) {
3997
4024
  const a8 = px[i * 4 + 3];
@@ -4067,7 +4094,7 @@ async function replayPainting(source, target, options = {}) {
4067
4094
  const chunk = Math.max(1, _nullishCoalesce(options.wetChunk, () => ( 0))) || Infinity;
4068
4095
  let strokes = 0;
4069
4096
  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] : []));
4097
+ 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
4098
  const advanceTo = async (clock) => {
4072
4099
  const now = target.getState().wet.clock;
4073
4100
  let left = clock - now;
@@ -4075,7 +4102,7 @@ async function replayPainting(source, target, options = {}) {
4075
4102
  const n = Math.min(left, chunk);
4076
4103
  await target.advanceWet({ steps: n });
4077
4104
  left -= n;
4078
- if (Number.isFinite(chunk)) await _optionalChain([options, 'access', _168 => _168.onWetSteps, 'optionalCall', _169 => _169(target.getState().wet.clock)]);
4105
+ if (Number.isFinite(chunk)) await _optionalChain([options, 'access', _179 => _179.onWetSteps, 'optionalCall', _180 => _180(target.getState().wet.clock)]);
4079
4106
  }
4080
4107
  };
4081
4108
  const sr = (r) => ({ x: r.x * s, y: r.y * s, width: r.width * s, height: r.height * s });
@@ -4088,14 +4115,14 @@ async function replayPainting(source, target, options = {}) {
4088
4115
  else if (e.kind === "clear") target.clearLayer(e.layerId);
4089
4116
  else if (e.kind === "live-strokes") {
4090
4117
  const d = e.data;
4091
- if (_optionalChain([d, 'optionalAccess', _170 => _170.rasterized])) target.replaceLiveStrokes(e.layerId, null);
4118
+ if (_optionalChain([d, 'optionalAccess', _181 => _181.rasterized])) target.replaceLiveStrokes(e.layerId, null);
4092
4119
  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] : []));
4120
+ 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)) } : {} });
4121
+ await target.prepareEffectPaints(list.flatMap((st2) => _optionalChain([st2, 'access', _183 => _183.paint, 'optionalAccess', _184 => _184.type]) === "effect" ? [st2.paint] : []));
4095
4122
  target.replaceLiveStrokes(e.layerId, list);
4096
4123
  }
4097
4124
  } 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 });
4125
+ 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
4126
  target.replaceStickers(e.layerId, list);
4100
4127
  } else target.flattenRelief(e.layerId);
4101
4128
  continue;
@@ -4108,8 +4135,8 @@ async function replayPainting(source, target, options = {}) {
4108
4135
  switch (e.kind) {
4109
4136
  case "dry": {
4110
4137
  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 });
4138
+ const ids = _optionalChain([e, 'access', _187 => _187.layerId, 'optionalAccess', _188 => _188.split, 'call', _189 => _189(","), 'access', _190 => _190.filter, 'call', _191 => _191(Boolean)]);
4139
+ if (_optionalChain([ids, 'optionalAccess', _192 => _192.length])) for (const id of ids) target.dryPaint({ layerId: id, rect: rect ? sr(rect) : void 0 });
4113
4140
  else target.dryPaint({ rect: rect ? sr(rect) : void 0 });
4114
4141
  break;
4115
4142
  }
@@ -4139,8 +4166,9 @@ async function replayPainting(source, target, options = {}) {
4139
4166
  const st = s === 1 ? item.stroke : varyStroke(item.stroke, scaleM, { scale: s });
4140
4167
  strokes++;
4141
4168
  if (!target.getLayer(st.layerId)) continue;
4169
+ 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
4170
  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) {
4171
+ if (st.brush.engine === "wet" && _optionalChain([st, 'access', _198 => _198.steps, 'optionalAccess', _199 => _199.length]) === st.points.length) {
4144
4172
  await target.wetIdle();
4145
4173
  await advanceTo(st.steps[0]);
4146
4174
  const session = target.beginStroke({ ...init, start: st.points[0] });
@@ -4160,7 +4188,7 @@ async function replayPainting(source, target, options = {}) {
4160
4188
  await target.wetIdle();
4161
4189
  target.paintStroke({ ...init, points: st.points });
4162
4190
  }
4163
- await _optionalChain([options, 'access', _184 => _184.onStroke, 'optionalCall', _185 => _185(strokes)]);
4191
+ await _optionalChain([options, 'access', _200 => _200.onStroke, 'optionalCall', _201 => _201(strokes)]);
4164
4192
  }
4165
4193
  void IDENTITY_AFFINE;
4166
4194
  }
@@ -4183,7 +4211,7 @@ function timeLapseVideo(frameCount, width, height, fps, holdMs, name = "Time-lap
4183
4211
  }
4184
4212
  const video = { version: 1, name, width: w, height: h, fps, background: "#000000", assets, tracks: [{ id: "v1", kind: "video", clips }] };
4185
4213
  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 };
4214
+ return { video, ffmpeg: _chunkLBDC5434cjs.toVideoFfmpeg.call(void 0, video, { output: "timelapse.mp4" }), durationMs };
4187
4215
  }
4188
4216
  async function buildTimeLapse(source, target, options = {}) {
4189
4217
  const maxSide = Math.max(32, Math.min(4096, Math.round(_nullishCoalesce(options.maxSide, () => ( 720)))));
@@ -4205,7 +4233,7 @@ async function buildTimeLapse(source, target, options = {}) {
4205
4233
  wetChunk: wetEvery > 0 ? wetEvery : 0,
4206
4234
  onStroke: (i) => {
4207
4235
  if (i % perFrame === 0 || i === total) shoot(i);
4208
- _optionalChain([options, 'access', _186 => _186.onProgress, 'optionalCall', _187 => _187(total ? i / total : 1)]);
4236
+ _optionalChain([options, 'access', _202 => _202.onProgress, 'optionalCall', _203 => _203(total ? i / total : 1)]);
4209
4237
  },
4210
4238
  onWetSteps: wetEvery > 0 ? () => shoot(-1) : void 0
4211
4239
  });
@@ -4293,7 +4321,7 @@ function mixPixels(before, after, amount) {
4293
4321
  return out;
4294
4322
  }
4295
4323
  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 })}
4324
+ __init63() {this.pool = new (0, _chunkEBFPMSJOcjs.EffectRendererPool)({ maxRenderers: 3 })}
4297
4325
  __init64() {this.descriptions = /* @__PURE__ */ new Map()}
4298
4326
  __init65() {this.provider = null}
4299
4327
  /** Forgets cached descriptions and renderers when the provider changes. */
@@ -4321,6 +4349,12 @@ var PaintEffectsRenderer = (_class13 = class {constructor() { _class13.prototype
4321
4349
  }
4322
4350
  return out;
4323
4351
  }
4352
+ renderSync(provider, id, size, request) {
4353
+ this.follow(provider);
4354
+ const out = this.pool.renderSync(provider, id, { ...size, depth: 8 }, request);
4355
+ if (!out || out.width !== size.width || out.height !== size.height || out.data.length !== size.width * size.height * 4) return null;
4356
+ return out;
4357
+ }
4324
4358
  dispose() {
4325
4359
  this.pool.clear();
4326
4360
  this.descriptions.clear();
@@ -4395,7 +4429,7 @@ function parseColor(value, what = "color") {
4395
4429
  return value.trim().toLowerCase();
4396
4430
  }
4397
4431
  function rgbaOf(hex2) {
4398
- const [r, g, b] = _chunk56RHCIJVcjs.hexToRgb8.call(void 0, hex2);
4432
+ const [r, g, b] = _chunkJJ2H25JGcjs.hexToRgb8.call(void 0, hex2);
4399
4433
  return [r, g, b, 255];
4400
4434
  }
4401
4435
  function rgbToHex(r, g, b) {
@@ -4408,7 +4442,7 @@ function unionRect(a, b) {
4408
4442
  const y = Math.min(a.y, b.y);
4409
4443
  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
4444
  }
4411
- var isPixelLayer = (l) => _optionalChain([l, 'optionalAccess', _188 => _188.type]) === "pixel";
4445
+ var isPixelLayer = (l) => _optionalChain([l, 'optionalAccess', _204 => _204.type]) === "pixel";
4412
4446
  var PaintEditorController = (_class14 = class _PaintEditorController {
4413
4447
 
4414
4448
  __init66() {this.extensions = {}}
@@ -4439,82 +4473,93 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
4439
4473
  __init76() {this.paintEpoch = 0}
4440
4474
  /** Rendered effect paints by `effectPaintKey` (most recently used last). */
4441
4475
  __init77() {this.effectPaintPixels = /* @__PURE__ */ new Map()}
4442
- __init78() {this.mixerLoad = _chunkNIBFKXMDcjs.EMPTY_MIXER_LOAD}
4443
- __init79() {this.view = { ...DEFAULT_VIEW, pan: { ...DEFAULT_VIEW.pan } }}
4476
+ /** Primary path control name (`format: 'svg-path'`) per effect id, learned from `describeEffect`. */
4477
+ __init78() {this.effectPathControls = /* @__PURE__ */ new Map()}
4478
+ /** How many renders the running batch needs together (`prepareEffectPaints`; a synchronous replay reads them all). */
4479
+ __init79() {this.effectPaintBatch = 0}
4480
+ /** The hand-painted stroke waiting for its path render (`finishPathStroke`), or `null`. */
4481
+ __init80() {this.pathStroke = null}
4482
+ /**
4483
+ * The hand-painted path stroke's live preview: the effect rendered along the path drawn so far
4484
+ * (one render at a time; the newest path when it lands), repainted into the stroke as it lands.
4485
+ */
4486
+ __init81() {this.pathPreview = null}
4487
+ __init82() {this.mixerLoad = _chunkNIBFKXMDcjs.EMPTY_MIXER_LOAD}
4488
+ __init83() {this.view = { ...DEFAULT_VIEW, pan: { ...DEFAULT_VIEW.pan } }}
4444
4489
 
4445
- __init80() {this.selectedStroke = null}
4446
- __init81() {this.selectedSticker = null}
4490
+ __init84() {this.selectedStroke = null}
4491
+ __init85() {this.selectedSticker = null}
4447
4492
  /** 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}
4493
+ __init86() {this.stickerPreview = null}
4449
4494
 
4450
- __init83() {this.listeners = /* @__PURE__ */ new Set()}
4451
- __init84() {this.commitListeners = /* @__PURE__ */ new Set()}
4452
- __init85() {this.sampleListeners = /* @__PURE__ */ new Set()}
4495
+ __init87() {this.listeners = /* @__PURE__ */ new Set()}
4496
+ __init88() {this.commitListeners = /* @__PURE__ */ new Set()}
4497
+ __init89() {this.sampleListeners = /* @__PURE__ */ new Set()}
4453
4498
  /** Origins set by `withOrigin`, innermost last. */
4454
- __init86() {this.origins = []}
4499
+ __init90() {this.origins = []}
4455
4500
  /** `group` in progress: commits fold into one step, recorded when it ends. */
4456
- __init87() {this.grouping = null}
4501
+ __init91() {this.grouping = null}
4457
4502
  /** `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}
4503
+ __init92() {this.previewing = false}
4504
+ __init93() {this.version = 0}
4505
+ __init94() {this.cached = null}
4506
+ __init95() {this.session = null}
4507
+ __init96() {this.live = null}
4508
+ __init97() {this.liveLayers = null}
4509
+ __init98() {this.dirty = "all"}
4510
+ __init99() {this.seedCounter = 1}
4511
+ __init100() {this.strokeCounter = 1}
4467
4512
  /** 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()}
4513
+ __init101() {this.lightSpills = {}}
4514
+ __init102() {this.lightCaches = /* @__PURE__ */ new Map()}
4470
4515
  /** 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()}
4516
+ __init103() {this.backlightView = new BacklightCache()}
4517
+ __init104() {this.backlightCommitted = new BacklightCache()}
4473
4518
  /** 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}
4519
+ __init105() {this.effectPlaybackState = { playing: true, fps: 30 }}
4520
+ __init106() {this.effectTime = 0}
4476
4521
  /** While a frame is drawn: the time live effect strokes are drawn at (else their own time). */
4477
- __init103() {this.liveEffectAt = null}
4522
+ __init107() {this.liveEffectAt = null}
4478
4523
  /** 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()}
4524
+ __init108() {this.animatedLayers = /* @__PURE__ */ new Map()}
4480
4525
  /** `renderAnimationFrame` / `withEffectTime`: layer surfaces at another time, for one render. */
4481
- __init105() {this.frameOverride = null}
4526
+ __init109() {this.frameOverride = null}
4482
4527
  /** 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()}
4528
+ __init110() {this.paintedBounds = /* @__PURE__ */ new WeakMap()}
4484
4529
 
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()}
4530
+ __init111() {this.swatches = DEFAULT_SWATCHES.map((s) => ({ ...s }))}
4531
+ __init112() {this.pad = new MixingPad()}
4532
+ __init113() {this.savedPads = []}
4533
+ __init114() {this.nextPadId = 1}
4534
+ __init115() {this.tracingVersion = 1}
4535
+ __init116() {this.tracingCache = null}
4536
+ __init117() {this.imagePixels = /* @__PURE__ */ new Map()}
4537
+ __init118() {this.nextReferenceId = 1}
4538
+ __init119() {this.viewCompositor = createPaintCompositor()}
4539
+ __init120() {this.exportCompositor = createPaintCompositor()}
4495
4540
  /** Wet media: the simulation, its settings and time. */
4496
4541
 
4497
4542
 
4498
4543
  /** 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()}
4544
+ __init121() {this.lighting = { ...DEFAULT_LIGHTING }}
4545
+ __init122() {this.litCaches = /* @__PURE__ */ new Map()}
4501
4546
  /** The live impasto stroke's channels. */
4502
- __init119() {this.liveThick = null}
4547
+ __init123() {this.liveThick = null}
4503
4548
  /** Set while an operation that changes wet paint runs: the simulation before it (for undo). */
4504
- __init120() {this.wetOp = null}
4549
+ __init124() {this.wetOp = null}
4505
4550
  /** The effects provider slot (see `setEffectsProvider`). */
4506
- __init121() {this.effects = new (0, _chunkL2JTLW6Bcjs.EffectsSlot)()}
4551
+ __init125() {this.effects = new (0, _chunkL2JTLW6Bcjs.EffectsSlot)()}
4507
4552
  /** 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()}
4553
+ __init126() {this.stickers = new (0, _chunkRDFHWAHLcjs.StickersSlot)(_chunk3VHH6V67cjs.editorStickers.call(void 0, ))}
4554
+ __init127() {this.stickerArt = new StickerArtCache()}
4510
4555
  /** Image sources strokes draw with: the brush library's and the open painting's (saved with it). */
4511
- __init124() {this.brushSources = new BrushSourceArtCache()}
4556
+ __init128() {this.brushSources = new BrushSourceArtCache()}
4512
4557
  /** 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)}
4558
+ __init129() {this.stampArt = (ref2, variant) => _chunkEU2ZZA6Lcjs.isBrushSourceRef.call(void 0, ref2) ? this.brushSources.get(ref2) : this.stickerArt.get(ref2, variant)}
4514
4559
 
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);
4560
+ __init130() {this.effectsRenderer = new PaintEffectsRenderer()}
4561
+ __init131() {this.paperEffectNodeCache = null}
4562
+ 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
4563
  this.historyLimit = Math.max(1, _nullishCoalesce(options.historyLimit, () => ( 200)));
4519
4564
  this.rasterizeSticker = _nullishCoalesce(options.rasterizeSticker, () => ( defaultStickerRasterizer));
4520
4565
  if (options.stickers) this.stickers.set(options.stickers);
@@ -4536,12 +4581,12 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
4536
4581
  this.encodeImage = options.encodeImage;
4537
4582
  this.guides = defaultGuides(this.doc.canvas);
4538
4583
  this.wetOptions = options.wet;
4539
- this.wet = new (0, _chunk56RHCIJVcjs.PaintWetLayers)(
4584
+ this.wet = new (0, _chunkJJ2H25JGcjs.PaintWetLayers)(
4540
4585
  {
4541
4586
  canvas: () => this.doc.canvas,
4542
4587
  paper: () => this.doc.paper,
4543
4588
  layerSurface: (id) => {
4544
- const l = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _189 => _189.layer]);
4589
+ const l = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _205 => _205.layer]);
4545
4590
  return isPixelLayer(l) ? l.surface : null;
4546
4591
  },
4547
4592
  updateSurfaces: (surfaces, rects) => {
@@ -4550,7 +4595,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
4550
4595
  this.doc = { ...this.doc, layers };
4551
4596
  this.emit(rects.length ? rects : "all");
4552
4597
  },
4553
- layerLight: (id) => _nullishCoalesce(_optionalChain([this, 'access', _190 => _190.doc, 'access', _191 => _191.light, 'optionalAccess', _192 => _192[id]]), () => ( null)),
4598
+ layerLight: (id) => _nullishCoalesce(_optionalChain([this, 'access', _206 => _206.doc, 'access', _207 => _207.light, 'optionalAccess', _208 => _208[id]]), () => ( null)),
4554
4599
  updateLights: (lights) => {
4555
4600
  let light = this.doc.light;
4556
4601
  for (const [id, surface] of lights) if (_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, id)) light = withLayerLight(light, id, surface);
@@ -4561,7 +4606,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
4561
4606
  },
4562
4607
  options.wet
4563
4608
  );
4564
- this.wet.onDriverDone = () => _optionalChain([this, 'access', _193 => _193.session, 'optionalAccess', _194 => _194.completeWetEnd, 'call', _195 => _195()]);
4609
+ this.wet.onDriverDone = () => _optionalChain([this, 'access', _209 => _209.session, 'optionalAccess', _210 => _210.completeWetEnd, 'call', _211 => _211()]);
4565
4610
  }
4566
4611
  // --- State and events ----------------------------------------------------------
4567
4612
  subscribe(listener) {
@@ -4731,7 +4776,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
4731
4776
  if (placement.bottom) this.moveLayer(layer.id, 0, null);
4732
4777
  fn(layer.id);
4733
4778
  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]);
4779
+ const found = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, layer.id), 'optionalAccess', _212 => _212.layer]);
4735
4780
  const surface = found && isPixelLayer(found) ? found.surface : null;
4736
4781
  const bounds = surface ? _chunk474IQG74cjs.contentBounds.call(void 0, surface) : null;
4737
4782
  const box = bounds ? clipToCanvas(bounds, this.doc.canvas) : null;
@@ -4775,7 +4820,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
4775
4820
  secondaryColor: this.secondaryColor,
4776
4821
  paint: _nullishCoalesce(this.gradient, () => ( { type: "color", color: this.color })),
4777
4822
  effectPaint: _nullishCoalesce(this.effectPaintPending, () => ( this.effectPaint)),
4778
- effectPaintRendering: Boolean(this.effectPaintPending),
4823
+ effectPaintRendering: Boolean(this.effectPaintPending || this.pathStroke),
4779
4824
  mixerLoad: this.mixerLoad,
4780
4825
  view: this.view,
4781
4826
  hand: this.hand,
@@ -4784,8 +4829,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
4784
4829
  selectedSticker: this.selectedSticker,
4785
4830
  canUndo: this.undoStack.length > 0 && !this.session,
4786
4831
  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)),
4832
+ undoLabel: _nullishCoalesce(_optionalChain([last, 'optionalAccess', _213 => _213.label]), () => ( null)),
4833
+ redoLabel: _nullishCoalesce(_optionalChain([next, 'optionalAccess', _214 => _214.label]), () => ( null)),
4789
4834
  guides: this.guides,
4790
4835
  swatches: this.swatches,
4791
4836
  mixingPadVersion: this.pad.version,
@@ -4798,10 +4843,10 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
4798
4843
  overlay: this.wet.overlay,
4799
4844
  instantDry: this.wet.instantDry,
4800
4845
  speed: this.wet.speed,
4801
- clock: _nullishCoalesce(_optionalChain([this, 'access', _199 => _199.wet, 'access', _200 => _200.world, 'optionalAccess', _201 => _201.clock]), () => ( 0)),
4846
+ clock: _nullishCoalesce(_optionalChain([this, 'access', _215 => _215.wet, 'access', _216 => _216.world, 'optionalAccess', _217 => _217.clock]), () => ( 0)),
4802
4847
  tilt: { ...this.wet.tilt },
4803
4848
  gpu: this.wet.gpuMode,
4804
- gpuActive: Boolean(_optionalChain([this, 'access', _202 => _202.wet, 'access', _203 => _203.world, 'optionalAccess', _204 => _204.gpuActive]))
4849
+ gpuActive: Boolean(_optionalChain([this, 'access', _218 => _218.wet, 'access', _219 => _219.world, 'optionalAccess', _220 => _220.gpuActive]))
4805
4850
  },
4806
4851
  version: this.version
4807
4852
  };
@@ -4820,7 +4865,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
4820
4865
  return d;
4821
4866
  }
4822
4867
  // --- History -------------------------------------------------------------------
4823
- __init128() {this.docRevision = 0}
4868
+ __init132() {this.docRevision = 0}
4824
4869
  /**
4825
4870
  * Bumped on every change to the painting (a committed or amended step, undo, redo, opening a
4826
4871
  * document), not on wet-paint frames or view changes. `createPaintEditorDocument` uses it.
@@ -4831,13 +4876,14 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
4831
4876
  /** Why the document cannot be replaced or stepped through right now, or `null`. */
4832
4877
  busyReason() {
4833
4878
  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.`;
4879
+ 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
4880
  if (this.wet.busy) return "Wet paint is mid-step; wait a moment (wetIdle()) first.";
4836
4881
  return null;
4837
4882
  }
4838
4883
  requireIdle(what) {
4839
4884
  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}.`);
4885
+ 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}.`);
4886
+ 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
4887
  }
4842
4888
  commit(label, next, before = this.doc) {
4843
4889
  if (this.grouping) {
@@ -4913,9 +4959,9 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
4913
4959
  return wetIds;
4914
4960
  }
4915
4961
  /** Records a wet event (for replays) in the document being built. */
4916
- __init129() {this.pendingWetEvents = []}
4962
+ __init133() {this.pendingWetEvents = []}
4917
4963
  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 });
4964
+ 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
4965
  }
4920
4966
  /** The document with a paint event appended (for replays). */
4921
4967
  withPaintEvent(doc, e) {
@@ -4978,7 +5024,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
4978
5024
  // --- Canvas and paper ----------------------------------------------------------
4979
5025
  resolvePaper(paper) {
4980
5026
  if (typeof paper === "string") {
4981
- const p = _chunk56RHCIJVcjs.paperPreset.call(void 0, paper);
5027
+ const p = _chunkJJ2H25JGcjs.paperPreset.call(void 0, paper);
4982
5028
  if (!p) throw new PaintEditorError(`Unknown paper "${paper}". Call list_papers for the ids.`);
4983
5029
  return p;
4984
5030
  }
@@ -5061,7 +5107,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5061
5107
  }
5062
5108
  let next = { ...shiftDocument(this.withWetEvents(this.doc), left, top), canvas: { ...was, width, height } };
5063
5109
  for (const id of keptWet) {
5064
- const l = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, next.layers, id), 'optionalAccess', _212 => _212.layer]);
5110
+ const l = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, next.layers, id), 'optionalAccess', _228 => _228.layer]);
5065
5111
  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
5112
  }
5067
5113
  if (this.wet.world) {
@@ -5089,23 +5135,23 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5089
5135
  this.requireIdle("changing the paper");
5090
5136
  let base = this.doc.paper;
5091
5137
  if (update.preset !== void 0 && update.preset !== this.doc.paper.preset) {
5092
- const p = _chunk56RHCIJVcjs.paperPreset.call(void 0, update.preset);
5138
+ const p = _chunkJJ2H25JGcjs.paperPreset.call(void 0, update.preset);
5093
5139
  if (!p) throw new PaintEditorError(`Unknown paper "${update.preset}". Call list_papers for the ids.`);
5094
5140
  base = p;
5095
5141
  }
5096
5142
  const { preset: _p, ...rest } = update;
5097
5143
  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);
5144
+ const paper = _chunkJJ2H25JGcjs.normalizePaper.call(void 0, { ...rest, preset: base.preset, offset: _nullishCoalesce(rest.offset, () => ( this.doc.paper.offset)) }, base);
5099
5145
  const changedKeys = Object.keys(rest).filter((k) => k !== "name");
5100
5146
  if (changedKeys.length && update.preset === void 0) paper.preset = base.preset;
5101
5147
  if (this.wet.world) this.beginWetOp();
5102
5148
  this.commit("Paper", { ...this.doc, paper });
5103
5149
  this.wet.paperChanged();
5104
- return _chunk56RHCIJVcjs.clonePaper.call(void 0, paper);
5150
+ return _chunkJJ2H25JGcjs.clonePaper.call(void 0, paper);
5105
5151
  }
5106
5152
  // --- Layers --------------------------------------------------------------------
5107
5153
  getLayer(id) {
5108
- return _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _213 => _213.layer]);
5154
+ return _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _229 => _229.layer]);
5109
5155
  }
5110
5156
  /** The active pixel layer (or `undefined`). */
5111
5157
  getActiveLayer() {
@@ -5124,7 +5170,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5124
5170
  walk(this.doc.layers, null, 0);
5125
5171
  return out;
5126
5172
  }
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))) {
5173
+ 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
5174
  let bounds = null;
5129
5175
  if (l.type === "pixel") {
5130
5176
  const b = _chunk474IQG74cjs.contentBounds.call(void 0, l.surface);
@@ -5141,8 +5187,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5141
5187
  locks: { ..._nullishCoalesce(l.locks, () => ( {})) },
5142
5188
  active: l.id === this.doc.activeLayerId,
5143
5189
  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 } : {},
5190
+ ..._optionalChain([this, 'access', _234 => _234.doc, 'access', _235 => _235.liveStrokes, 'optionalAccess', _236 => _236[l.id]]) ? { liveStrokes: this.doc.liveStrokes[l.id].length } : {},
5191
+ ..._optionalChain([l, 'access', _237 => _237.effects, 'optionalAccess', _238 => _238.items, 'access', _239 => _239.length]) ? { effects: l.effects.items.length } : {},
5146
5192
  parentId,
5147
5193
  depth
5148
5194
  };
@@ -5174,7 +5220,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5174
5220
  this.requireIdle("adding a layer");
5175
5221
  const count = _chunkPVJMTLPJcjs.flattenLayers.call(void 0, this.doc.layers).length;
5176
5222
  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}`);
5223
+ 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
5224
  const layer = type === "group" ? { type: "group", id: newPaintLayerId(), name, visible: true, opacity: 1, blend: "pass-through", children: [] } : createPaintLayer(name);
5179
5225
  let parentId = null;
5180
5226
  let index;
@@ -5186,7 +5232,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5186
5232
  } else if (above) {
5187
5233
  const loc = _chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, above);
5188
5234
  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));
5235
+ parentId = _nullishCoalesce(_optionalChain([loc, 'access', _243 => _243.parent, 'optionalAccess', _244 => _244.id]), () => ( null));
5190
5236
  index = loc.index + 1;
5191
5237
  }
5192
5238
  const layers = _chunkPVJMTLPJcjs.insertLayer.call(void 0, this.doc.layers, layer, parentId, index);
@@ -5292,7 +5338,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5292
5338
  }
5293
5339
  requireEffect(id, effectId) {
5294
5340
  const l = this.requireLayer(id);
5295
- const items = _nullishCoalesce(_optionalChain([l, 'access', _229 => _229.effects, 'optionalAccess', _230 => _230.items]), () => ( []));
5341
+ const items = _nullishCoalesce(_optionalChain([l, 'access', _245 => _245.effects, 'optionalAccess', _246 => _246.items]), () => ( []));
5296
5342
  const i = items.findIndex((e) => e.id === effectId);
5297
5343
  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
5344
  return i;
@@ -5315,7 +5361,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5315
5361
  }
5316
5362
  const layers = _chunkPVJMTLPJcjs.mapLayer.call(void 0, this.doc.layers, id, () => null);
5317
5363
  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));
5364
+ 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
5365
  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
5366
  return { removed: id, activeLayerId: active };
5321
5367
  }
@@ -5341,7 +5387,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5341
5387
  return l.type === "group" ? { ...l, id: id2, children: l.children.map(copy) } : { ...l, id: id2 };
5342
5388
  };
5343
5389
  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);
5390
+ 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
5391
  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
5392
  return this.describeLayer(dup);
5347
5393
  }
@@ -5350,7 +5396,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5350
5396
  this.requireIdle("moving a layer");
5351
5397
  const loc = _chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, id);
5352
5398
  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;
5399
+ const target = parentId === void 0 ? _nullishCoalesce(_optionalChain([loc, 'access', _254 => _254.parent, 'optionalAccess', _255 => _255.id]), () => ( null)) : parentId;
5354
5400
  if (target) {
5355
5401
  const g = this.requireLayer(target);
5356
5402
  if (g.type !== "group") throw new PaintEditorError(`Layer "${g.name}" is not a group; pass a group id as parentId.`);
@@ -5369,7 +5415,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5369
5415
  const pre = _chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, id);
5370
5416
  if (pre) {
5371
5417
  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)));
5418
+ this.dryLayersFirst([id, _optionalChain([sib, 'access', _256 => _256[pre.index - 1], 'optionalAccess', _257 => _257.id])].filter((x) => Boolean(x)));
5373
5419
  }
5374
5420
  const loc = _chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, id);
5375
5421
  if (!loc) throw new PaintEditorError(`Unknown layer "${id}". Call list_layers for the ids.`);
@@ -5389,7 +5435,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5389
5435
  const merged = { ...below, surface, offset: { x: 0, y: 0 } };
5390
5436
  const layers = _chunkPVJMTLPJcjs.mapLayer.call(void 0, _chunkPVJMTLPJcjs.mapLayer.call(void 0, this.doc.layers, upper.id, () => null), below.id, () => merged);
5391
5437
  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;
5438
+ 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
5439
  const lightAfter = _nullishCoalesce(this.lightWithout([upper.id, below.id]).light, () => ( (this.doc.light ? { ...this.doc.light } : void 0)));
5394
5440
  const light = mergedLight ? { ..._nullishCoalesce(lightAfter, () => ( {})), [below.id]: mergedLight } : lightAfter;
5395
5441
  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 +5450,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5404
5450
  this.wet.world.removeLane(l.id);
5405
5451
  }
5406
5452
  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 }));
5453
+ 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
5454
  return { layerId: l.id, bounds };
5409
5455
  }
5410
5456
  /**
@@ -5414,8 +5460,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5414
5460
  fillLayer(options = {}) {
5415
5461
  this.requireIdle("filling");
5416
5462
  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).`);
5463
+ 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).`);
5464
+ 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
5465
  this.dryLayersFirst([_nullishCoalesce(_nullishCoalesce(options.layerId, () => ( this.doc.activeLayerId)), () => ( ""))]);
5420
5466
  const l = this.paintTarget(options.layerId, "fill");
5421
5467
  const color = options.color === void 0 ? this.color : parseColor(options.color);
@@ -5448,7 +5494,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5448
5494
  offset: l.offset
5449
5495
  };
5450
5496
  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]]);
5497
+ const lit = _optionalChain([this, 'access', _280 => _280.doc, 'access', _281 => _281.light, 'optionalAccess', _282 => _282[l.id]]);
5452
5498
  const light = lit ? withLayerLight(this.doc.light, l.id, scaleLight(lit, 1 - opacity)) : void 0;
5453
5499
  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
5500
  return { layerId: l.id, bounds: rect };
@@ -5458,7 +5504,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5458
5504
  const tiles = new Map(base.tiles);
5459
5505
  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
5506
  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)));
5507
+ 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
5508
  const tile = _chunk474IQG74cjs.finishTile.call(void 0, _chunkNIBFKXMDcjs.applyStrokeToTile.call(void 0, coverage, src, 4, tx, ty, apply), 4, 0);
5463
5509
  if (tile) tiles.set(key, tile);
5464
5510
  else tiles.delete(key);
@@ -5481,6 +5527,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5481
5527
  /** The provider's description of an effect, checked for `place` (rejects without a provider or for an unknown id). */
5482
5528
  async describeEffect(effect, place) {
5483
5529
  const d = await this.effectsRenderer.describe(this.effects.require(), effect);
5530
+ const pcs = _chunkL2JTLW6Bcjs.pathControlsOf.call(void 0, d);
5531
+ if (pcs.length) this.effectPathControls.set(d.id, pcs[0]);
5484
5532
  if (place) checkPaintEffectPlace(d, place);
5485
5533
  return d;
5486
5534
  }
@@ -5491,7 +5539,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5491
5539
  }
5492
5540
  /** The effect a layer is drawn from, or `undefined` for other layers. */
5493
5541
  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;
5542
+ 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
5543
  }
5496
5544
  /** The effect paper (without its pixels), or `null`. */
5497
5545
  getPaperEffect() {
@@ -5528,8 +5576,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5528
5576
  /** A pixel layer that takes effect pixels: unlocked, visible, no sticker layer, no wet paint. */
5529
5577
  effectTarget(layerId, what) {
5530
5578
  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).`);
5579
+ 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).`);
5580
+ 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
5581
  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
5582
  return l;
5535
5583
  }
@@ -5568,8 +5616,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5568
5616
  const was = this.doc.paperEffect;
5569
5617
  const paperEffect = {
5570
5618
  ...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")),
5619
+ opacity: _nullishCoalesce(_nullishCoalesce(options.opacity, () => ( _optionalChain([was, 'optionalAccess', _297 => _297.opacity]))), () => ( 1)),
5620
+ blend: _nullishCoalesce(_nullishCoalesce(options.blend, () => ( _optionalChain([was, 'optionalAccess', _298 => _298.blend]))), () => ( "multiply")),
5573
5621
  image: { width: pixels.width, height: pixels.height, data: new Uint8ClampedArray(pixels.data) },
5574
5622
  version: nextPaperEffectVersion()
5575
5623
  };
@@ -5622,8 +5670,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5622
5670
  const above = _nullishCoalesce(options.aboveId, () => ( this.doc.activeLayerId));
5623
5671
  const loc = above ? _chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, above) : null;
5624
5672
  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);
5673
+ 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")) };
5674
+ 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
5675
  const source = this.sourceOf(d, values, options.time);
5628
5676
  this.commit("Add effect layer", { ...this.doc, layers, activeLayerId: layer.id, effectLayers: { ..._nullishCoalesce(this.doc.effectLayers, () => ( {})), [layer.id]: source } });
5629
5677
  return { layer: this.describeLayer(layer), source };
@@ -5681,7 +5729,11 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5681
5729
  return { layerId: now.id, source: this.sourceOf(d, values, options.time) };
5682
5730
  }
5683
5731
  // --- Effect paint ----------------------------------------------------------------
5684
- /** At most this many rendered effect paints are kept (each is canvas-sized). */
5732
+ /**
5733
+ * At most this many rendered effect paints are kept (each is canvas-sized), more only while
5734
+ * something needs them all: a replay's batch, and the path-mapped strokes on stroke layers,
5735
+ * which each have a render of their own and are redrawn synchronously.
5736
+ */
5685
5737
  static __initStatic() {this.EFFECT_PAINT_CACHE = 6}
5686
5738
  /** The effect paint strokes use (or the one rendering), or `null`. */
5687
5739
  getEffectPaint() {
@@ -5693,15 +5745,17 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5693
5745
  * size, and brushes then take each pixel's colour (and alpha) from it, fixed to the canvas, as if
5694
5746
  * painting a hidden picture into view. `setColor` and `setPaint` go back to colour. Editor state,
5695
5747
  * 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`).
5748
+ * With `map: { by: 'stroke' }` the effect lies along each stroke as a strip; with
5749
+ * `map: { by: 'path' }` an effect with a path control (`format: 'svg-path'`) draws itself along
5750
+ * each stroke's centreline in canvas pixels; with `live`, strokes on a stroke layer keep playing
5751
+ * it (see `setEffectPlayback`).
5698
5752
  */
5699
5753
  async setEffectPaint(source) {
5700
5754
  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
5755
  this.checkTime(source.time);
5702
5756
  let map;
5703
5757
  try {
5704
- map = _chunk56RHCIJVcjs.readEffectStrokeMap.call(void 0, source.map);
5758
+ map = _chunkJJ2H25JGcjs.readEffectStrokeMap.call(void 0, source.map);
5705
5759
  } catch (e) {
5706
5760
  throw new PaintEditorError(e.message);
5707
5761
  }
@@ -5709,6 +5763,9 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5709
5763
  const epoch = ++this.paintEpoch;
5710
5764
  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
5765
  const d = await this.describeEffect(source.effect, "paint");
5766
+ if (_optionalChain([map, 'optionalAccess', _304 => _304.by]) === "path" && !_chunkL2JTLW6Bcjs.pathControlsOf.call(void 0, d).length) {
5767
+ 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).`);
5768
+ }
5712
5769
  const values = this.effectValues(d, { ...d.defaults }, source.values);
5713
5770
  if (epoch !== this.paintEpoch) throw changed(d.name);
5714
5771
  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 +5789,158 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5732
5789
  }
5733
5790
  /** The rendered pixels of an effect paint at the current canvas size, or `null` when it has not been rendered. */
5734
5791
  effectPaintImage(p) {
5735
- const key = _chunk56RHCIJVcjs.effectPaintKey.call(void 0, p);
5792
+ const key = _chunkJJ2H25JGcjs.effectPaintKey.call(void 0, p);
5736
5793
  const img = this.effectPaintPixels.get(key);
5737
- const size = _chunk56RHCIJVcjs.effectPaintSize.call(void 0, p, this.doc.canvas);
5794
+ const size = _chunkJJ2H25JGcjs.effectPaintSize.call(void 0, p, this.doc.canvas);
5738
5795
  if (!img || img.width !== size.width || img.height !== size.height) return null;
5739
5796
  this.effectPaintPixels.delete(key);
5740
5797
  this.effectPaintPixels.set(key, img);
5741
5798
  return img;
5742
5799
  }
5800
+ cacheEffectPaintPixels(p, pixels) {
5801
+ return this.cacheEffectPaintImage(p, toEffectPaintPixels(p, pixels));
5802
+ }
5803
+ cacheEffectPaintImage(p, img) {
5804
+ this.effectPaintPixels.set(_chunkJJ2H25JGcjs.effectPaintKey.call(void 0, p), img);
5805
+ this.trimEffectPaints();
5806
+ return img;
5807
+ }
5808
+ trimEffectPaints() {
5809
+ let live = 0;
5810
+ 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++;
5811
+ const limit = Math.max(_PaintEditorController.EFFECT_PAINT_CACHE, this.effectPaintBatch, live + 1);
5812
+ while (this.effectPaintPixels.size > limit) this.effectPaintPixels.delete(this.effectPaintPixels.keys().next().value);
5813
+ }
5814
+ /** Renders an effect paint on the caller's stack when its renderer is warm and has `renderSync`; otherwise `null`. */
5815
+ renderEffectPaintSync(p) {
5816
+ const have = this.effectPaintImage(p);
5817
+ if (have) return have;
5818
+ const provider = this.effects.provider;
5819
+ if (!provider || p.provider && provider.id !== p.provider) return null;
5820
+ const size = _chunkJJ2H25JGcjs.effectPaintSize.call(void 0, p, this.doc.canvas);
5821
+ const pixels = this.effectsRenderer.renderSync(provider, p.effect, size, { time: p.time, values: p.values });
5822
+ return pixels ? this.cacheEffectPaintPixels(p, pixels) : null;
5823
+ }
5743
5824
  /** Renders an effect paint at the canvas size into the cache (nothing when it is there already). */
5744
5825
  async renderEffectPaint(p) {
5745
5826
  const have = this.effectPaintImage(p);
5746
5827
  if (have) return have;
5828
+ return this.cacheEffectPaintImage(p, await this.renderEffectPaintPixels(p));
5829
+ }
5830
+ /** Renders an effect paint at the canvas size without keeping it. */
5831
+ async renderEffectPaintPixels(p) {
5747
5832
  const provider = this.effects.provider;
5748
5833
  const what = `the effect "${p.effect}"${p.provider ? ` from provider "${p.provider}"` : ""}`;
5749
5834
  if (!provider) throw new PaintEditorError(`Effect paint needs ${what}, but no effects provider is registered; register it (setEffectsProvider) and try again.`);
5750
5835
  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);
5836
+ const { width, height } = _chunkJJ2H25JGcjs.effectPaintSize.call(void 0, p, this.doc.canvas);
5752
5837
  let pixels;
5753
5838
  try {
5754
5839
  pixels = await this.effectsRenderer.render(provider, p.effect, { width, height }, { time: p.time, values: p.values });
5755
5840
  } catch (e) {
5756
5841
  throw new PaintEditorError(`Effect paint could not render ${what}: ${e instanceof Error ? e.message : String(e)}`);
5757
5842
  }
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;
5843
+ return toEffectPaintPixels(p, pixels);
5762
5844
  }
5763
5845
  /**
5764
5846
  * Renders effect paints that are not rendered yet (strokes and replays need them rendered
5765
5847
  * first, since strokes are synchronous). Throws naming the effect and provider when one cannot be.
5766
5848
  */
5767
5849
  async prepareEffectPaints(paints2) {
5850
+ const list = [...paints2];
5851
+ this.effectPaintBatch = new Set(list.map(_chunkJJ2H25JGcjs.effectPaintKey)).size;
5768
5852
  const seen = /* @__PURE__ */ new Set();
5769
- for (const p of paints2) {
5770
- const key = _chunk56RHCIJVcjs.effectPaintKey.call(void 0, p);
5853
+ for (const p of list) {
5854
+ const key = _chunkJJ2H25JGcjs.effectPaintKey.call(void 0, p);
5771
5855
  if (seen.has(key)) continue;
5772
5856
  seen.add(key);
5773
5857
  await this.renderEffectPaint(p);
5774
5858
  }
5775
5859
  }
5860
+ /**
5861
+ * Renders the path-mapped effect paint for one or more strokes' points before a synchronous
5862
+ * stroke call runs (`paint_stroke` and `stroke_path` do; `paintStroke` throws without it on a
5863
+ * provider that can't render synchronously). For a stroke layer edit, see `prepareStrokeEdit`.
5864
+ */
5865
+ async prepareStrokePathEffect(init, pointsList) {
5866
+ const brush = this.strokeBrush(init);
5867
+ if (!_chunkEU2ZZA6Lcjs.brushTakesPaint.call(void 0, brush)) return;
5868
+ let source = null;
5869
+ if (init.paint !== void 0) {
5870
+ if (!_chunkJJ2H25JGcjs.isPaintEffectPaint.call(void 0, init.paint)) return;
5871
+ source = _chunkJJ2H25JGcjs.readPaintEffectPaint.call(void 0, init.paint);
5872
+ } else if (init.color === void 0 && !brush.paint && !this.effectPaintPending) {
5873
+ source = this.effectPaint;
5874
+ }
5875
+ if (!source || _optionalChain([source, 'access', _310 => _310.map, 'optionalAccess', _311 => _311.by]) !== "path") return;
5876
+ if (!this.effectPathControls.has(source.effect)) await this.describeEffect(source.effect);
5877
+ const control = this.effectPathControls.get(source.effect);
5878
+ const paints2 = pointsList.filter((pts) => pts.length > 0).map((pts) => _chunkJJ2H25JGcjs.withStrokePath.call(void 0, source, pts, control));
5879
+ if (paints2.length) await this.prepareEffectPaints(paints2);
5880
+ }
5881
+ /**
5882
+ * Renders what an edit of a stroke layer's stroke paints with (`updateStroke`, `editStrokePoints`):
5883
+ * a new effect paint, or a path-mapped stroke's new path. Those calls are synchronous, and throw
5884
+ * without it on a provider that can't render synchronously. Bad edits are left for them to refuse.
5885
+ */
5886
+ async prepareStrokeEdit(id, edit) {
5887
+ const p = this.strokeEditPaint(id, edit);
5888
+ if (!p) return;
5889
+ if (_optionalChain([p, 'access', _312 => _312.map, 'optionalAccess', _313 => _313.by]) === "path" && !this.effectPathControls.has(p.effect)) await this.describeEffect(p.effect);
5890
+ await this.prepareEffectPaints([_nullishCoalesce(this.strokeEditPaint(id, edit), () => ( p))]);
5891
+ }
5892
+ /** Whether `prepareStrokeEdit` has to be awaited before this edit can run. */
5893
+ strokeEditNeedsRender(id, edit) {
5894
+ const p = this.strokeEditPaint(id, edit);
5895
+ return Boolean(p && !this.effectPaintImage(p) && !this.renderEffectPaintSync(p));
5896
+ }
5897
+ strokeEditPaint(id, edit) {
5898
+ const was = Object.values(_nullishCoalesce(this.doc.liveStrokes, () => ( {}))).flat().find((s) => s.id === id);
5899
+ if (!was) return null;
5900
+ try {
5901
+ if (edit.paint !== void 0) {
5902
+ if (!_chunkJJ2H25JGcjs.isPaintEffectPaint.call(void 0, edit.paint)) return null;
5903
+ const p = _chunkJJ2H25JGcjs.readPaintEffectPaint.call(void 0, edit.paint);
5904
+ return p && _chunkJJ2H25JGcjs.withStrokePath.call(void 0, p, was.points, this.effectPathControls.get(p.effect));
5905
+ }
5906
+ 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;
5907
+ if (edit.points !== void 0) return _chunkJJ2H25JGcjs.withStrokePath.call(void 0, was.paint, this.checkPoints(edit.points), this.effectPathControls.get(was.paint.effect));
5908
+ if (!edit.transform) return null;
5909
+ const varied = varyStroke(was, this.strokeTransform(was, edit.transform), {}).paint;
5910
+ return _optionalChain([varied, 'optionalAccess', _319 => _319.type]) === "effect" ? varied : null;
5911
+ } catch (e9) {
5912
+ return null;
5913
+ }
5914
+ }
5915
+ /** A stroke edit's transform as an affine map, checked. */
5916
+ strokeTransform(stroke, t) {
5917
+ 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.`);
5918
+ for (const k of ["dx", "dy", "rotate"]) if (t[k] !== void 0 && !Number.isFinite(t[k])) throw new PaintEditorError(`${k} must be a number.`);
5919
+ const b = strokeBounds(stroke.points);
5920
+ return variationAffine(t, _nullishCoalesce(t.origin, () => ( { x: b.x + b.width / 2, y: b.y + b.height / 2 })));
5921
+ }
5776
5922
  /** Renders the effect paints of recorded strokes (default all of them) before a replay. */
5777
- async prepareStrokeEffects(strokeIds) {
5923
+ async prepareStrokeEffects(strokeIds, variation) {
5778
5924
  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);
5925
+ const strokes = this.doc.strokes.filter((s) => (!ids || ids.has(s.id)) && _optionalChain([s, 'access', _320 => _320.paint, 'optionalAccess', _321 => _321.type]) === "effect");
5926
+ const paints2 = strokes.map((s) => s.paint);
5927
+ if (variation && strokes.length) {
5928
+ const repeat = Math.max(1, Math.min(100, _nullishCoalesce(variation.repeat, () => ( 1))));
5929
+ let origin = variation.origin;
5930
+ if (!origin) {
5931
+ const b = strokeBounds(strokes.flatMap((s) => s.points));
5932
+ origin = { x: b.x + b.width / 2, y: b.y + b.height / 2 };
5933
+ }
5934
+ const step = variationAffine(variation, origin);
5935
+ let m = IDENTITY_AFFINE;
5936
+ for (let k = 0; k < repeat; k++) {
5937
+ 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]];
5938
+ for (const s of strokes) {
5939
+ const v = varyStroke(s, m, variation);
5940
+ if (_optionalChain([v, 'access', _322 => _322.paint, 'optionalAccess', _323 => _323.type]) === "effect") paints2.push(v.paint);
5941
+ }
5942
+ }
5943
+ }
5780
5944
  await this.prepareEffectPaints(paints2);
5781
5945
  }
5782
5946
  /** A small preview of the effect paint (a PNG data URL `size` px wide), or `null` without a rendered one. */
@@ -5804,20 +5968,22 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5804
5968
  * Throws while the editor's is still rendering, for an engine that cannot paint with it, or when
5805
5969
  * its pixels are not rendered.
5806
5970
  */
5807
- strokeEffect(init, brush) {
5971
+ strokeEffect(init, brush, points) {
5808
5972
  if (!_chunkEU2ZZA6Lcjs.brushTakesPaint.call(void 0, brush)) return null;
5809
5973
  let source = null;
5810
5974
  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);
5975
+ if (!_chunkJJ2H25JGcjs.isPaintEffectPaint.call(void 0, init.paint)) return null;
5976
+ source = _chunkJJ2H25JGcjs.readPaintEffectPaint.call(void 0, init.paint);
5813
5977
  if (!source) throw new PaintEditorError("The stroke's effect paint needs an effect id and values (getEffectPaint returns one).");
5814
5978
  } else if (init.color === void 0 && !brush.paint) {
5815
5979
  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
5980
  source = this.effectPaint;
5817
5981
  }
5818
5982
  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.`);
5983
+ const path = _optionalChain([source, 'access', _324 => _324.map, 'optionalAccess', _325 => _325.by]) === "path";
5984
+ if (path && _optionalChain([points, 'optionalAccess', _326 => _326.length])) source = _chunkJJ2H25JGcjs.withStrokePath.call(void 0, source, points, this.effectPathControls.get(source.effect));
5985
+ const pixels = _nullishCoalesce(this.effectPaintImage(source), () => ( (path ? this.renderEffectPaintSync(source) : null)));
5986
+ 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
5987
  return { source, pixels };
5822
5988
  }
5823
5989
  /**
@@ -5839,14 +6005,14 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5839
6005
  const before = _chunk474IQG74cjs.readRegion.call(void 0, l.surface, rect);
5840
6006
  const inputs = { source: { width: rect.width, height: rect.height, data: before } };
5841
6007
  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]]);
6008
+ const relief = _optionalChain([this, 'access', _327 => _327.doc, 'access', _328 => _328.thick, 'optionalAccess', _329 => _329[l.id]]);
5843
6009
  if (heightInput && relief) {
5844
6010
  const h = _chunk474IQG74cjs.readRegion.call(void 0, relief.height, rect);
5845
6011
  const rgba = new Uint8ClampedArray(rect.width * rect.height * 4);
5846
6012
  for (let i = 0; i < h.length; i++) rgba.set([h[i], h[i], h[i], 255], i * 4);
5847
6013
  inputs[heightInput.name] = { width: rect.width, height: rect.height, data: rgba };
5848
6014
  }
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"));
6015
+ 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
6016
  if (sourceInput !== "source") {
5851
6017
  inputs[sourceInput] = inputs.source;
5852
6018
  delete inputs.source;
@@ -5862,7 +6028,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5862
6028
  return this.brushEntries.find((e) => e.brush.id === id);
5863
6029
  }
5864
6030
  findBrush(id) {
5865
- return _optionalChain([this, 'access', _298 => _298.findEntry, 'call', _299 => _299(id), 'optionalAccess', _300 => _300.brush]);
6031
+ return _optionalChain([this, 'access', _335 => _335.findEntry, 'call', _336 => _336(id), 'optionalAccess', _337 => _337.brush]);
5866
6032
  }
5867
6033
  requireEntry(id) {
5868
6034
  const e = this.findEntry(id);
@@ -5899,7 +6065,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5899
6065
  }
5900
6066
  /** A library brush by id as stored (its facets), or without an id the active brush as edited. */
5901
6067
  getBrushSpec(id) {
5902
- const spec = id === void 0 ? this.brushSpec : _optionalChain([this, 'access', _301 => _301.findEntry, 'call', _302 => _302(id), 'optionalAccess', _303 => _303.spec]);
6068
+ const spec = id === void 0 ? this.brushSpec : _optionalChain([this, 'access', _338 => _338.findEntry, 'call', _339 => _339(id), 'optionalAccess', _340 => _340.spec]);
5903
6069
  return spec ? copyJSON(spec) : void 0;
5904
6070
  }
5905
6071
  /**
@@ -5931,8 +6097,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5931
6097
  const base = copyJSON(entry ? entry.spec : this.brushSpec);
5932
6098
  for (const k of unset) delete base[k];
5933
6099
  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);
6100
+ if (entry || _optionalChain([patch, 'access', _341 => _341.colour, 'optionalAccess', _342 => _342.default]) !== void 0) this.takeBrushColour(spec);
6101
+ this.useBrush(unchanged && entry ? entry.brush : _chunkEU2ZZA6Lcjs.resolveBrush.call(void 0, spec), spec, unchanged && _optionalChain([entry, 'optionalAccess', _343 => _343.builtin]) === true);
5936
6102
  return { brush: this.brush, spec: copyJSON(this.brushSpec), problems };
5937
6103
  }
5938
6104
  /**
@@ -5942,7 +6108,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5942
6108
  */
5943
6109
  setBrushSpec(spec) {
5944
6110
  const problems = [];
5945
- const paint = _optionalChain([spec, 'access', _307 => _307.colour, 'optionalAccess', _308 => _308.default]);
6111
+ const paint = _optionalChain([spec, 'access', _344 => _344.colour, 'optionalAccess', _345 => _345.default]);
5946
6112
  if (paint && typeof paint === "object" && "type" in paint && paint.type === "gradient") this.readStrokePaint(paint);
5947
6113
  let next;
5948
6114
  try {
@@ -5965,7 +6131,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5965
6131
  }
5966
6132
  readBrushPatch(base, patch, problems) {
5967
6133
  const { id: _id, name, ...rest } = patch;
5968
- const paint = _optionalChain([rest, 'access', _309 => _309.colour, 'optionalAccess', _310 => _310.default]);
6134
+ const paint = _optionalChain([rest, 'access', _346 => _346.colour, 'optionalAccess', _347 => _347.default]);
5969
6135
  if (paint && typeof paint === "object" && "type" in paint && paint.type === "gradient") this.readStrokePaint(paint);
5970
6136
  try {
5971
6137
  return _chunkEU2ZZA6Lcjs.normalizeBrushSpec.call(void 0, _chunk3KNQ2W6Xcjs.mergeBrushPatch.call(void 0, base, { ...rest, ...name !== void 0 ? { name } : {} }), problems);
@@ -5981,7 +6147,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
5981
6147
  this.brushSpec = { ...copyJSON(spec), id: next.id, name: next.name };
5982
6148
  this.pendingBrushId = null;
5983
6149
  this.emit([]);
5984
- const refs = _chunk56RHCIJVcjs.brushStickerRefs.call(void 0, next);
6150
+ const refs = _chunkJJ2H25JGcjs.brushStickerRefs.call(void 0, next);
5985
6151
  if (refs.length) void this.prepareStickers(refs).catch(() => this.emit([]));
5986
6152
  }
5987
6153
  /**
@@ -6028,9 +6194,9 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6028
6194
  }
6029
6195
  // --- Colour --------------------------------------------------------------------
6030
6196
 
6031
- __init130() {this.colorLocked = false}
6197
+ __init134() {this.colorLocked = false}
6032
6198
  /** The brush default colour the paint colour came from (resolved again when the scheme changes), or `null`. */
6033
- __init131() {this.brushColour = null}
6199
+ __init135() {this.brushColour = null}
6034
6200
  /**
6035
6201
  * The host's colour scheme: a paint colour that came from a brush's light / dark default
6036
6202
  * resolves to the new side. Editor state, not an undo step.
@@ -6041,7 +6207,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6041
6207
  this.colorScheme = next;
6042
6208
  const hex2 = this.brushColour ? _chunkJBZRVLXVcjs.brushColourHex.call(void 0, this.brushColour, next) : null;
6043
6209
  if (hex2) this.color = hex2;
6044
- const refs = _chunk56RHCIJVcjs.brushStickerRefs.call(void 0, this.brush);
6210
+ const refs = _chunkJJ2H25JGcjs.brushStickerRefs.call(void 0, this.brush);
6045
6211
  if (refs.some((r) => !_chunkRDFHWAHLcjs.editorStampOf.call(void 0, r))) void this.prepareStickers(refs).catch(() => this.emit([]));
6046
6212
  this.emit([]);
6047
6213
  }
@@ -6058,7 +6224,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6058
6224
  */
6059
6225
  takeBrushColour(spec) {
6060
6226
  if (this.colorLocked) return;
6061
- const d = _optionalChain([spec, 'access', _311 => _311.colour, 'optionalAccess', _312 => _312.default]);
6227
+ const d = _optionalChain([spec, 'access', _348 => _348.colour, 'optionalAccess', _349 => _349.default]);
6062
6228
  const hex2 = d !== void 0 ? _chunkJBZRVLXVcjs.brushColourHex.call(void 0, d, this.colorScheme) : null;
6063
6229
  if (!hex2) return;
6064
6230
  this.color = hex2;
@@ -6069,8 +6235,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6069
6235
  }
6070
6236
  /** A brush that always paints its own colour (`colour.own`): that colour, resolved for the scheme now; else `null`. */
6071
6237
  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;
6238
+ const spec = brushId !== void 0 ? _optionalChain([this, 'access', _350 => _350.findEntry, 'call', _351 => _351(brushId), 'optionalAccess', _352 => _352.spec]) : this.brushSpec;
6239
+ const d = _optionalChain([spec, 'optionalAccess', _353 => _353.colour, 'optionalAccess', _354 => _354.own]) ? spec.colour.default : void 0;
6074
6240
  return d !== void 0 ? _chunkJBZRVLXVcjs.brushColourHex.call(void 0, d, this.colorScheme) : null;
6075
6241
  }
6076
6242
  /** Sets the paint colour (and goes back to one colour from gradient paint). */
@@ -6116,7 +6282,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6116
6282
  if (!_chunkEU2ZZA6Lcjs.brushTakesPaint.call(void 0, brush)) return null;
6117
6283
  let g = null;
6118
6284
  if (init.paint !== void 0) {
6119
- if (_chunk56RHCIJVcjs.isPaintEffectPaint.call(void 0, init.paint)) return null;
6285
+ if (_chunkJJ2H25JGcjs.isPaintEffectPaint.call(void 0, init.paint)) return null;
6120
6286
  const p = this.readStrokePaint(init.paint);
6121
6287
  g = p.type === "gradient" ? p : null;
6122
6288
  } else g = _nullishCoalesce(brush.paint, () => ( (init.color === void 0 ? this.gradient : null)));
@@ -6160,7 +6326,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6160
6326
  // --- Mixer Brush ---------------------------------------------------------------
6161
6327
  /** Fills the Mixer Brush reservoir with a colour (default the editor colour). */
6162
6328
  loadMixerBrush(color) {
6163
- const [r, g, b] = _chunk56RHCIJVcjs.hexToRgb8.call(void 0, color === void 0 ? this.color : parseColor(color));
6329
+ const [r, g, b] = _chunkJJ2H25JGcjs.hexToRgb8.call(void 0, color === void 0 ? this.color : parseColor(color));
6164
6330
  this.mixerLoad = _chunkNIBFKXMDcjs.loadMixer.call(void 0, this.mixerLoad, [r / 255, g / 255, b / 255]);
6165
6331
  this.emit([]);
6166
6332
  return this.mixerLoad;
@@ -6205,8 +6371,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6205
6371
  strokeCopies() {
6206
6372
  return symmetryCopies(this.guides.symmetry);
6207
6373
  }
6208
- sessionFor(doc, init, host) {
6209
- if (init.paint !== void 0 && !_chunk56RHCIJVcjs.isPaintEffectPaint.call(void 0, init.paint)) {
6374
+ sessionFor(doc, init, host, points) {
6375
+ if (init.paint !== void 0 && !_chunkJJ2H25JGcjs.isPaintEffectPaint.call(void 0, init.paint)) {
6210
6376
  const p = this.readStrokePaint(init.paint);
6211
6377
  if (p.type === "color") init = { ...init, color: p.color, paint: void 0 };
6212
6378
  else init = { ...init, paint: p };
@@ -6224,22 +6390,25 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6224
6390
  })();
6225
6391
  const brush = this.strokeBrush(init);
6226
6392
  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);
6393
+ const effect = this.strokeEffect(init, brush, points);
6394
+ if (!points && init.paint === void 0 && _optionalChain([effect, 'optionalAccess', _355 => _355.source, 'access', _356 => _356.map, 'optionalAccess', _357 => _357.by]) === "path" && _chunkEU2ZZA6Lcjs.isWetBrush.call(void 0, brush)) {
6395
+ 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.`);
6396
+ }
6228
6397
  if (brush.light.amount > 0) {
6229
6398
  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).`);
6230
6399
  }
6231
- if (_optionalChain([doc, 'access', _318 => _318.liveStrokes, 'optionalAccess', _319 => _319[layer.id]])) {
6400
+ if (_optionalChain([doc, 'access', _358 => _358.liveStrokes, 'optionalAccess', _359 => _359[layer.id]])) {
6232
6401
  const why = liveStrokeRefusal(brush);
6233
6402
  if (why) throw new PaintEditorError(`Layer "${layer.name}" is a stroke layer. ${why}`);
6234
6403
  }
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);
6404
+ if (_optionalChain([doc, 'access', _360 => _360.liveStrokes, 'optionalAccess', _361 => _361[layer.id]]) && _optionalChain([effect, 'optionalAccess', _362 => _362.source, 'access', _363 => _363.live])) {
6405
+ const key = _chunkJJ2H25JGcjs.effectPaintKey.call(void 0, effect.source);
6237
6406
  const { sources } = this.liveEffects(doc);
6238
- if (!sources.some((p) => _chunk56RHCIJVcjs.effectPaintKey.call(void 0, p) === key) && sources.length >= MAX_LIVE_EFFECT_SOURCES) {
6407
+ if (!sources.some((p) => _chunkJJ2H25JGcjs.effectPaintKey.call(void 0, p) === key) && sources.length >= MAX_LIVE_EFFECT_SOURCES) {
6239
6408
  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
6409
  }
6241
6410
  }
6242
- const stickerLayer = Boolean(_optionalChain([doc, 'access', _324 => _324.stickers, 'optionalAccess', _325 => _325[layer.id], 'optionalAccess', _326 => _326.length]));
6411
+ const stickerLayer = Boolean(_optionalChain([doc, 'access', _364 => _364.stickers, 'optionalAccess', _365 => _365[layer.id], 'optionalAccess', _366 => _366.length]));
6243
6412
  if (brush.engine === "sticker") {
6244
6413
  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
6414
  } else if (stickerLayer) {
@@ -6261,12 +6430,12 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6261
6430
  const world = this.wet.ensureLane(layer.id, brush.wet.medium);
6262
6431
  const id = layer.id;
6263
6432
  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);
6433
+ const [r, g, b] = _chunkJJ2H25JGcjs.hexToRgb8.call(void 0, wetColor);
6265
6434
  const wetGradient = this.strokeGradient(init, brush, wetColor);
6266
6435
  const load = _nullishCoalesce(init.load, () => ( brushLoadForStroke(brush, this.mixerLoad, [r / 255, g / 255, b / 255])));
6267
6436
  const seedW = _nullishCoalesce(init.seed, () => ( _chunk3K6HWEXZcjs.mix32.call(void 0, this.seedCounter * 2654435761 >>> 0) & 2147483647));
6268
6437
  const copiesW = (_nullishCoalesce(init.copies, () => ( this.strokeCopies()))).filter((m) => m.some((v, i) => v !== IDENTITY_AFFINE[i]));
6269
- const driver = new (0, _chunk56RHCIJVcjs.WetStrokeDriver)({
6438
+ const driver = new (0, _chunkJJ2H25JGcjs.WetStrokeDriver)({
6270
6439
  world,
6271
6440
  laneId: id,
6272
6441
  brush,
@@ -6274,12 +6443,12 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6274
6443
  load,
6275
6444
  grain: paperGrain(doc.paper),
6276
6445
  paperDepth: doc.paper.depth,
6277
- paperColor: _chunk56RHCIJVcjs.hexToRgb8.call(void 0, doc.paper.color),
6446
+ paperColor: _chunkJJ2H25JGcjs.hexToRgb8.call(void 0, doc.paper.color),
6278
6447
  seed: seedW,
6279
6448
  copies: [IDENTITY_AFFINE, ...copiesW].map(affineCopy),
6280
6449
  mask: init.maskStencils ? this.stencilSelection(init.maskStencils) : init.stencils !== false ? this.stencilSelection() : null,
6281
6450
  paint: effect ? null : wetGradient,
6282
- effect: _nullishCoalesce(_optionalChain([effect, 'optionalAccess', _327 => _327.pixels]), () => ( null))
6451
+ effect: _nullishCoalesce(_optionalChain([effect, 'optionalAccess', _367 => _367.pixels]), () => ( null))
6283
6452
  });
6284
6453
  init = { ...init, seed: seedW, load };
6285
6454
  wet = { driver, surface: () => world.display(id).surface };
@@ -6290,7 +6459,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6290
6459
  }
6291
6460
  let color = init.color === void 0 ? _nullishCoalesce(this.ownColour(init.brushId), () => ( this.color)) : parseColor(init.color);
6292
6461
  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));
6462
+ if (init.color === void 0 && init.start && _optionalChain([tracing, 'optionalAccess', _368 => _368.visible]) && tracing.sampleColors) color = _nullishCoalesce(this.sampleTracingColor(init.start.x, init.start.y), () => ( color));
6294
6463
  const perspective = this.guides.perspective;
6295
6464
  const snapper = init.snapToPerspective && perspective.enabled && perspective.snap ? new PerspectiveSnapper(perspective) : null;
6296
6465
  const useStencils = init.stencils !== false;
@@ -6323,9 +6492,9 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6323
6492
  mixerLoad: _nullishCoalesce(init.load, () => ( brushLoadForStroke(brush, this.mixerLoad, [rgba[0] / 255, rgba[1] / 255, rgba[2] / 255]))),
6324
6493
  secondary: rgbaOf(this.secondaryColor),
6325
6494
  wet,
6326
- thick: brush.engine === "impasto" ? { channels: _nullishCoalesce(_optionalChain([doc, 'access', _329 => _329.thick, 'optionalAccess', _330 => _330[layer.id]]), () => ( emptyThickChannels())) } : void 0,
6495
+ thick: brush.engine === "impasto" ? { channels: _nullishCoalesce(_optionalChain([doc, 'access', _369 => _369.thick, 'optionalAccess', _370 => _370[layer.id]]), () => ( emptyThickChannels())) } : void 0,
6327
6496
  // 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,
6497
+ light: !wet && brush.engine !== "sticker" && (brush.light.amount > 0 || _optionalChain([doc, 'access', _371 => _371.light, 'optionalAccess', _372 => _372[layer.id]])) ? { surface: _nullishCoalesce(_optionalChain([doc, 'access', _373 => _373.light, 'optionalAccess', _374 => _374[layer.id]]), () => ( emptyLight())) } : null,
6329
6498
  sticker: brush.engine === "sticker" ? { nextId: this.nextStickerNumber(doc), art: this.stickerArt.get, variant: (ref2) => this.stickerArt.variantFor(ref2, this.colorScheme === "dark") } : void 0,
6330
6499
  stampArt: this.stampArt,
6331
6500
  paint: effect ? null : this.strokeGradient(init, brush, color),
@@ -6365,25 +6534,35 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6365
6534
  const before = this.doc;
6366
6535
  const host = {
6367
6536
  update: (layerId, surface, rects) => {
6368
- if (_optionalChain([this, 'access', _335 => _335.session, 'optionalAccess', _336 => _336.init, 'access', _337 => _337.wet])) {
6537
+ if (_optionalChain([this, 'access', _375 => _375.session, 'optionalAccess', _376 => _376.init, 'access', _377 => _377.wet])) {
6369
6538
  this.wet.syncDisplays();
6370
6539
  return;
6371
6540
  }
6372
6541
  this.live = { layerId, surface };
6373
- const ch = _optionalChain([this, 'access', _338 => _338.session, 'optionalAccess', _339 => _339.thickChannels, 'call', _340 => _340()]);
6542
+ const ch = _optionalChain([this, 'access', _378 => _378.session, 'optionalAccess', _379 => _379.thickChannels, 'call', _380 => _380()]);
6374
6543
  this.liveThick = ch ? { layerId, channels: ch } : null;
6375
6544
  this.emit(rects);
6376
6545
  },
6377
- sampled: (s, points) => this.notifySample("points", s, points),
6546
+ sampled: (s, points) => {
6547
+ this.notifySample("points", s, points);
6548
+ this.previewPathStroke(s);
6549
+ },
6378
6550
  commit: (s, surface, cancelled) => {
6379
6551
  this.session = null;
6552
+ const preview = _optionalChain([this, 'access', _381 => _381.pathPreview, 'optionalAccess', _382 => _382.session]) === s ? this.pathPreview : null;
6553
+ this.pathPreview = null;
6554
+ const pathPaint = cancelled ? null : this.pathStrokePaint(s);
6555
+ if (pathPaint) {
6556
+ this.finishPathStroke(s, pathPaint, preview);
6557
+ return;
6558
+ }
6380
6559
  this.live = null;
6381
6560
  this.liveLayers = null;
6382
6561
  this.liveThick = null;
6383
6562
  const wetStroke = Boolean(s.init.wet);
6384
6563
  if (wetStroke) this.wet.driver = null;
6385
6564
  const brush = s.init.brush;
6386
- if (!cancelled && _optionalChain([s, 'access', _341 => _341.result, 'optionalAccess', _342 => _342.mixerLoad])) this.keepLoad(brush, s.result.mixerLoad);
6565
+ if (!cancelled && _optionalChain([s, 'access', _383 => _383.result, 'optionalAccess', _384 => _384.mixerLoad])) this.keepLoad(brush, s.result.mixerLoad);
6387
6566
  if (cancelled || !surface) {
6388
6567
  if (this.wetOp) {
6389
6568
  const snap = this.wetOp.before;
@@ -6399,7 +6578,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6399
6578
  }
6400
6579
  const stroke = this.record(s);
6401
6580
  s.result.strokeId = stroke.id;
6402
- this.paintedBounds.set(stroke, _nullishCoalesce(_optionalChain([s, 'access', _343 => _343.result, 'optionalAccess', _344 => _344.bounds]), () => ( null)));
6581
+ this.paintedBounds.set(stroke, _nullishCoalesce(_optionalChain([s, 'access', _385 => _385.result, 'optionalAccess', _386 => _386.bounds]), () => ( null)));
6403
6582
  if (wetStroke && this.wet.instantDry) {
6404
6583
  this.wet.dry(s.layerId);
6405
6584
  this.logWet({ kind: "dry", layerId: s.layerId, at: this.doc.strokes.length + 1 });
@@ -6410,8 +6589,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6410
6589
  const ch = s.thickChannels();
6411
6590
  const thick = ch ? { ..._nullishCoalesce(this.doc.thick, () => ( {})), [l.id]: ch } : this.doc.thick;
6412
6591
  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;
6592
+ const stickers = sprayed ? { ..._nullishCoalesce(this.doc.stickers, () => ( {})), [l.id]: [..._nullishCoalesce(_optionalChain([this, 'access', _387 => _387.doc, 'access', _388 => _388.stickers, 'optionalAccess', _389 => _389[l.id]]), () => ( [])), ...sprayed] } : this.doc.stickers;
6593
+ const wetLight = wetStroke && _optionalChain([this, 'access', _390 => _390.wet, 'access', _391 => _391.world, 'optionalAccess', _392 => _392.hasLane, 'call', _393 => _393(l.id)]) ? this.wet.world.lightDisplay(l.id) : null;
6415
6594
  const light = withLayerLight(this.doc.light, l.id, _nullishCoalesce(s.lightChannel(), () => ( wetLight)));
6416
6595
  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
6596
  this.notifySample("end", s, [], stroke.id);
@@ -6425,14 +6604,99 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6425
6604
  throw e;
6426
6605
  }
6427
6606
  this.session = session;
6607
+ if (_optionalChain([session, 'access', _394 => _394.init, 'access', _395 => _395.effect, 'optionalAccess', _396 => _396.source, 'access', _397 => _397.map, 'optionalAccess', _398 => _398.by]) === "path" && !session.init.wet) this.pathPreview = { session, key: "", pending: null, landed: null };
6428
6608
  this.emit([]);
6429
6609
  this.notifySample("begin", session);
6430
6610
  return session;
6431
6611
  }
6612
+ /**
6613
+ * Renders a hand-painted path stroke's effect along the path drawn so far and paints the stroke
6614
+ * again with it when it lands, so the effect follows the pen while it draws. One render at a
6615
+ * time: when one lands, the next takes the newest path. A failed render leaves the preview as it
6616
+ * was; the render on release reports it.
6617
+ */
6618
+ previewPathStroke(s) {
6619
+ const pv = this.pathPreview;
6620
+ if (!pv || pv.session !== s || pv.pending || !s.open) return;
6621
+ const paint = this.pathStrokePaint(s);
6622
+ if (!paint) return;
6623
+ const key = _chunkJJ2H25JGcjs.effectPaintKey.call(void 0, paint);
6624
+ if (key === pv.key) return;
6625
+ pv.key = key;
6626
+ const cached = this.effectPaintImage(paint);
6627
+ const pending = cached ? Promise.resolve(cached) : this.renderEffectPaintPixels(paint);
6628
+ pv.pending = pending;
6629
+ pending.then(
6630
+ (pixels) => {
6631
+ pv.pending = null;
6632
+ pv.landed = { key, pixels };
6633
+ if (this.pathPreview !== pv || !s.open) return;
6634
+ s.repaintEffect(pixels);
6635
+ this.previewPathStroke(s);
6636
+ },
6637
+ () => {
6638
+ pv.pending = null;
6639
+ }
6640
+ );
6641
+ }
6432
6642
  /** The current live stroke, if any. */
6433
6643
  get activeStroke() {
6434
6644
  return this.session;
6435
6645
  }
6646
+ /**
6647
+ * While a hand-painted stroke waits for its path render (`map: { by: 'path' }`), settles when it
6648
+ * has landed and rejects if it could not (the stroke is dropped); `null` otherwise. Until then
6649
+ * the editor is busy, as during a stroke, and shows the stroke as it was painted.
6650
+ */
6651
+ get strokeRendering() {
6652
+ return _nullishCoalesce(_optionalChain([this, 'access', _399 => _399.pathStroke, 'optionalAccess', _400 => _400.done]), () => ( null));
6653
+ }
6654
+ /** The paint a finished hand-painted stroke must be painted again with, or `null` when it already painted with it. */
6655
+ pathStrokePaint(s) {
6656
+ const source = _optionalChain([s, 'access', _401 => _401.init, 'access', _402 => _402.effect, 'optionalAccess', _403 => _403.source]);
6657
+ if (_optionalChain([source, 'optionalAccess', _404 => _404.map, 'optionalAccess', _405 => _405.by]) !== "path" || !s.points.length) return null;
6658
+ const paint = _chunkJJ2H25JGcjs.withStrokePath.call(void 0, source, s.points, this.effectPathControls.get(source.effect));
6659
+ return _chunkJJ2H25JGcjs.effectPaintKey.call(void 0, paint) === _chunkJJ2H25JGcjs.effectPaintKey.call(void 0, source) ? null : paint;
6660
+ }
6661
+ /**
6662
+ * Ends a hand-painted stroke with a path-mapped effect. Its whole path isn't known until now, so
6663
+ * the live stroke was only a preview from renders along the path so far (`previewPathStroke`):
6664
+ * nothing of it was committed. Paints it again with the path's own render, as one stroke and one undo step, at
6665
+ * once if that can render synchronously and when the render lands if not.
6666
+ */
6667
+ finishPathStroke(s, paint, preview) {
6668
+ const finish = () => {
6669
+ this.pathStroke = null;
6670
+ this.live = null;
6671
+ this.liveLayers = null;
6672
+ this.liveThick = null;
6673
+ const masks = s.init.selection ? (_nullishCoalesce(s.maskStencils, () => ( this.guides.stencils))).filter((x) => x.enabled && x.mode === "mask") : [];
6674
+ const load = s.init.mixerLoad;
6675
+ const result = this.paintStroke({ layerId: s.layerId, points: s.points, color: s.init.colorHex, brush: _chunkEU2ZZA6Lcjs.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 });
6676
+ Object.assign(s.result, result);
6677
+ this.notifySample("end", s, [], result.strokeId);
6678
+ };
6679
+ const key = _chunkJJ2H25JGcjs.effectPaintKey.call(void 0, paint);
6680
+ if (_optionalChain([preview, 'optionalAccess', _406 => _406.landed, 'optionalAccess', _407 => _407.key]) === key) this.cacheEffectPaintImage(paint, preview.landed.pixels);
6681
+ if (this.effectPaintImage(paint) || this.renderEffectPaintSync(paint)) {
6682
+ finish();
6683
+ return;
6684
+ }
6685
+ const render = _optionalChain([preview, 'optionalAccess', _408 => _408.pending]) && preview.key === key ? preview.pending.then((img) => this.cacheEffectPaintImage(paint, img)) : this.renderEffectPaint(paint);
6686
+ const done = render.then(finish, (e) => {
6687
+ this.pathStroke = null;
6688
+ this.live = null;
6689
+ this.liveLayers = null;
6690
+ this.liveThick = null;
6691
+ this.emit();
6692
+ this.notifySample("cancel", s, []);
6693
+ throw e;
6694
+ });
6695
+ done.catch(() => {
6696
+ });
6697
+ this.pathStroke = { effect: paint.effect, done };
6698
+ this.emit([]);
6699
+ }
6436
6700
  /** Runs a whole stroke against `doc` without touching the editor; returns the new document. */
6437
6701
  runStroke(doc, init, points) {
6438
6702
  let out = doc;
@@ -6443,23 +6707,23 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6443
6707
  if (cancelled || !surface) return;
6444
6708
  const stroke = this.record(s);
6445
6709
  s.result.strokeId = stroke.id;
6446
- this.paintedBounds.set(stroke, _nullishCoalesce(_optionalChain([s, 'access', _352 => _352.result, 'optionalAccess', _353 => _353.bounds]), () => ( null)));
6710
+ this.paintedBounds.set(stroke, _nullishCoalesce(_optionalChain([s, 'access', _409 => _409.result, 'optionalAccess', _410 => _410.bounds]), () => ( null)));
6447
6711
  const l = _chunkPVJMTLPJcjs.findLayer.call(void 0, out.layers, s.layerId).layer;
6448
6712
  const offset = s.init.wet ? { x: 0, y: 0 } : l.offset;
6449
6713
  const ch = s.thickChannels();
6450
6714
  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)));
6715
+ const lit = _nullishCoalesce(s.lightChannel(), () => ( (s.init.wet && _optionalChain([this, 'access', _411 => _411.wet, 'access', _412 => _412.world, 'optionalAccess', _413 => _413.hasLane, 'call', _414 => _414(l.id)]) ? this.wet.world.lightDisplay(l.id) : null)));
6452
6716
  out = withLiveStroke({
6453
6717
  ...out,
6454
6718
  layers: _chunkPVJMTLPJcjs.mapLayer.call(void 0, out.layers, l.id, () => ({ ...l, surface, offset })),
6455
6719
  strokes: [...out.strokes, stroke],
6456
6720
  ...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] } } : {},
6721
+ ...sprayed ? { stickers: { ..._nullishCoalesce(out.stickers, () => ( {})), [l.id]: [..._nullishCoalesce(_optionalChain([out, 'access', _415 => _415.stickers, 'optionalAccess', _416 => _416[l.id]]), () => ( [])), ...sprayed] } } : {},
6458
6722
  ...lit ? { light: withLayerLight(out.light, l.id, lit) } : {}
6459
6723
  }, stroke);
6460
6724
  }
6461
6725
  };
6462
- const session = this.sessionFor(doc, init, host);
6726
+ const session = this.sessionFor(doc, init, host, points);
6463
6727
  session.push(points);
6464
6728
  const result = session.end();
6465
6729
  if (session.init.wet) {
@@ -6527,11 +6791,11 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6527
6791
  throw e;
6528
6792
  }
6529
6793
  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);
6794
+ if (_optionalChain([run, 'optionalAccess', _417 => _417.result, 'access', _418 => _418.mixerLoad])) this.keepLoad(run.brush, run.result.mixerLoad);
6795
+ if (doc !== before || this.wetOp) this.commit(`${_nullishCoalesce(_optionalChain([run, 'optionalAccess', _419 => _419.brush, 'access', _420 => _420.name]), () => ( "Brush"))} path stroke`, this.withWetEvents(doc), before);
6532
6796
  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 } : {} };
6797
+ const layerId = _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(_optionalChain([run, 'optionalAccess', _421 => _421.result, 'access', _422 => _422.layerId]), () => ( stroke.layerId)), () => ( this.doc.activeLayerId)), () => ( ""));
6798
+ return { layerId, bounds, dabs, strokeIds, ..._optionalChain([run, 'optionalAccess', _423 => _423.result, 'access', _424 => _424.mixerLoad]) ? { mixerLoad: run.result.mixerLoad } : {}, ..._optionalChain([run, 'optionalAccess', _425 => _425.result, 'access', _426 => _426.wet]) !== void 0 ? { wet: run.result.wet } : {} };
6535
6799
  }
6536
6800
  /** Checks stroke samples (finite x and y, pressure 0..1) and returns them; throws a sentence naming the bad point. */
6537
6801
  checkPoints(points) {
@@ -6554,7 +6818,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6554
6818
  */
6555
6819
  replayStrokes(options) {
6556
6820
  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.");
6821
+ if (!_optionalChain([options, 'access', _427 => _427.strokeIds, 'optionalAccess', _428 => _428.length])) throw new PaintEditorError("strokeIds is empty; pass ids from list_strokes.");
6558
6822
  const strokes = options.strokeIds.map((id) => {
6559
6823
  const s = this.doc.strokes.find((x) => x.id === id);
6560
6824
  if (!s) throw new PaintEditorError(`Unknown stroke "${id}". Call list_strokes for the ids.`);
@@ -6568,7 +6832,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6568
6832
  if (options.layerId !== void 0) this.paintTarget(options.layerId, "replay onto");
6569
6833
  if (options.color === void 0) {
6570
6834
  for (const s of strokes) {
6571
- if (_optionalChain([s, 'access', _372 => _372.paint, 'optionalAccess', _373 => _373.type]) === "effect" && !this.effectPaintImage(s.paint)) {
6835
+ if (_optionalChain([s, 'access', _429 => _429.paint, 'optionalAccess', _430 => _430.type]) === "effect" && !this.effectPaintImage(s.paint)) {
6572
6836
  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
6837
  }
6574
6838
  }
@@ -6597,7 +6861,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6597
6861
  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
6862
  let load = s.load;
6599
6863
  if (load && options.color !== void 0 && load.reservoir) {
6600
- const [r, g, b] = _chunk56RHCIJVcjs.hexToRgb8.call(void 0, options.color);
6864
+ const [r, g, b] = _chunkJJ2H25JGcjs.hexToRgb8.call(void 0, options.color);
6601
6865
  load = { ...load, reservoir: [r / 255, g / 255, b / 255] };
6602
6866
  }
6603
6867
  const paint = v.paint && options.color === void 0 ? { paint: v.paint } : {};
@@ -6609,6 +6873,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6609
6873
  }
6610
6874
  }
6611
6875
  if (doc !== this.doc) this.commit(strokes.length === 1 && repeat === 1 ? "Replay stroke" : "Replay strokes", doc);
6876
+ this.effectPaintBatch = 0;
6877
+ this.trimEffectPaints();
6612
6878
  return { strokeIds: ids, bounds, layerIds: [...layerIds] };
6613
6879
  }
6614
6880
  // --- Light paint --------------------------------------------------------------------
@@ -6626,7 +6892,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6626
6892
  /** A layer's light paint: whether it has any, where (document pixels), its brightest value 0..255, and its spill. */
6627
6893
  lightOf(layerId) {
6628
6894
  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]]));
6895
+ const info = lightInfo(_optionalChain([this, 'access', _431 => _431.doc, 'access', _432 => _432.light, 'optionalAccess', _433 => _433[l.id]]));
6630
6896
  const bounds = info.bounds ? { ...info.bounds, x: info.bounds.x + l.offset.x, y: info.bounds.y + l.offset.y } : null;
6631
6897
  return { layerId: l.id, hasLight: info.peak > 0, bounds, peak: info.peak, spill: { ...this.lightSpillOf(l.id) } };
6632
6898
  }
@@ -6677,7 +6943,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6677
6943
  const id = _nullishCoalesce(layerId, () => ( this.doc.activeLayerId));
6678
6944
  if (!id) return null;
6679
6945
  this.requireLayer(id);
6680
- const ch = _optionalChain([this, 'access', _377 => _377.doc, 'access', _378 => _378.thick, 'optionalAccess', _379 => _379[id]]);
6946
+ const ch = _optionalChain([this, 'access', _434 => _434.doc, 'access', _435 => _435.thick, 'optionalAccess', _436 => _436[id]]);
6681
6947
  if (!ch) return null;
6682
6948
  const r = reliefInfo(ch);
6683
6949
  return { layerId: id, bounds: r.bounds, maxHeight: r.maxHeight };
@@ -6788,7 +7054,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6788
7054
  wetState() {
6789
7055
  const st = this.getState().wet;
6790
7056
  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() };
7057
+ return { ...st, layers: this.wet.wetLayerIds().map((id) => this.wet.info(id)), backend, message: _nullishCoalesce(_optionalChain([backend, 'optionalAccess', _437 => _437.message]), () => ( _chunkJ5VQYK7Tcjs.wetSupport.call(void 0, ).message)), engine: this.wet.engineInfo() };
6792
7058
  }
6793
7059
  /**
6794
7060
  * Engine B, the WebGPU accelerator for large wet areas: whether it may run, its state (`off`,
@@ -6806,7 +7072,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6806
7072
  */
6807
7073
  async setWetEngine(options) {
6808
7074
  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)}.`);
7075
+ if (!_chunkJJ2H25JGcjs.WET_GPU_MODES.includes(gpu)) throw new PaintEditorError(`gpu must be ${_chunkJJ2H25JGcjs.WET_GPU_MODES.join(" or ")}, not ${JSON.stringify(gpu)}.`);
6810
7076
  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
7077
  this.wet.setGpu(gpu, options.minTiles);
6812
7078
  this.emit();
@@ -6873,7 +7139,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6873
7139
  }
6874
7140
  /** Records a settings change as a wet event (not an undo step). */
6875
7141
  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 }] };
7142
+ this.doc = { ...this.doc, wetEvents: [..._nullishCoalesce(this.doc.wetEvents, () => ( [])), { clock: _nullishCoalesce(_optionalChain([this, 'access', _438 => _438.wet, 'access', _439 => _439.world, 'optionalAccess', _440 => _440.clock]), () => ( 0)), at: this.doc.strokes.length, ...e }] };
6877
7143
  }
6878
7144
  /** Changes a layer's wet settings (viscosity, evaporation, granulation…). Editor settings saved with the document, not an undo step. */
6879
7145
  setWetParams(layerId, update) {
@@ -6942,7 +7208,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6942
7208
  if (override) return Array.from(override).reduce((ls, [id, surface]) => _chunkPVJMTLPJcjs.mapLayer.call(void 0, ls, id, (l) => ({ ...l, surface })), this.doc.layers);
6943
7209
  const live = this.live;
6944
7210
  if (!live) return this.animatedView();
6945
- if (_optionalChain([this, 'access', _384 => _384.liveLayers, 'optionalAccess', _385 => _385.key]) === live.surface) return this.liveLayers.layers;
7211
+ if (_optionalChain([this, 'access', _441 => _441.liveLayers, 'optionalAccess', _442 => _442.key]) === live.surface) return this.liveLayers.layers;
6946
7212
  const layers = _chunkPVJMTLPJcjs.mapLayer.call(void 0, this.doc.layers, live.layerId, (l) => ({ ...l, surface: live.surface }));
6947
7213
  this.liveLayers = { key: live.surface, layers };
6948
7214
  return layers;
@@ -6965,7 +7231,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6965
7231
  tracingNode(t) {
6966
7232
  const { width, height } = this.doc.canvas;
6967
7233
  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;
7234
+ if (_optionalChain([this, 'access', _443 => _443.tracingCache, 'optionalAccess', _444 => _444.key]) === key && this.tracingCache.node.opacity === t.opacity) return this.tracingCache.node;
6969
7235
  const src = _nullishCoalesce(this.imagePixels.get(t.src), () => ( this.decodeImage(t.src)));
6970
7236
  const image = resampleInto(src, t.rect, width, height);
6971
7237
  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 +7258,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
6992
7258
  let out = layers;
6993
7259
  const ids = /* @__PURE__ */ new Set([...Object.keys(_nullishCoalesce(thick, () => ( {}))), ...live ? [live.layerId] : []]);
6994
7260
  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]);
7261
+ const ch = _optionalChain([live, 'optionalAccess', _445 => _445.layerId]) === id ? live.channels : _optionalChain([thick, 'optionalAccess', _446 => _446[id]]);
7262
+ const l = ch && _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, out, id), 'optionalAccess', _447 => _447.layer]);
6997
7263
  if (!ch || !isPixelLayer(l)) continue;
6998
7264
  let cache = this.litCaches.get(id);
6999
7265
  if (!cache) this.litCaches.set(id, cache = new LitCache());
@@ -7013,13 +7279,13 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7013
7279
  if (!ids.size) return layers;
7014
7280
  let out = layers;
7015
7281
  for (const id of ids) {
7016
- const l = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, out, id), 'optionalAccess', _391 => _391.layer]);
7282
+ const l = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, out, id), 'optionalAccess', _448 => _448.layer]);
7017
7283
  if (!isPixelLayer(l)) continue;
7018
7284
  let cache = this.lightCaches.get(id);
7019
7285
  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]]));
7286
+ const glowed = cache.glow(l.surface, light[id], _optionalChain([this, 'access', _449 => _449.liveThick, 'optionalAccess', _450 => _450.layerId]) === id ? this.liveThick.channels : _optionalChain([this, 'access', _451 => _451.doc, 'access', _452 => _452.thick, 'optionalAccess', _453 => _453[id]]));
7021
7287
  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]);
7288
+ const committed = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _454 => _454.layer]);
7023
7289
  const spill = light[id] && isPixelLayer(committed) ? cache.spill(committed.surface, light[id], this.lightSpillOf(id)) : null;
7024
7290
  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
7291
  }
@@ -7031,7 +7297,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7031
7297
  if (!l.visible) continue;
7032
7298
  if (l.type === "group") this.backlitLayers(l.children, committed, opacity * l.opacity, out);
7033
7299
  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]]);
7300
+ const thick = !committed && _optionalChain([this, 'access', _455 => _455.liveThick, 'optionalAccess', _456 => _456.layerId]) === l.id ? this.liveThick.channels : _optionalChain([this, 'access', _457 => _457.doc, 'access', _458 => _458.thick, 'optionalAccess', _459 => _459[l.id]]);
7035
7301
  out.push({ surface: l.surface, offset: l.offset, opacity: opacity * l.opacity, ...thick ? { thick } : {} });
7036
7302
  }
7037
7303
  }
@@ -7060,7 +7326,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7060
7326
  if (backlight) layers = [...layers, backlight];
7061
7327
  if (options.layerIds) {
7062
7328
  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))));
7329
+ for (const id of options.layerIds) picked.push(_nullishCoalesce(_optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, layers, id), 'optionalAccess', _460 => _460.layer]), () => ( this.requireLayer(id))));
7064
7330
  layers = picked.map((l) => ({ ...l, visible: true }));
7065
7331
  }
7066
7332
  const under = options.paper === false ? [] : [paperNode(this.doc.paper, this.lighting)];
@@ -7076,7 +7342,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7076
7342
  */
7077
7343
  compositeTiles(rect, onTile, options = {}) {
7078
7344
  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)) });
7345
+ this.viewCompositor.compositeTiles(this.renderLayers({ paper: options.paper }, true), rect, this.sources(), onTile, { dirty, checkpointLayerId: _nullishCoalesce(_optionalChain([this, 'access', _461 => _461.live, 'optionalAccess', _462 => _462.layerId]), () => ( this.doc.activeLayerId)) });
7080
7346
  }
7081
7347
  /** The canvas as canvas-sized RGBA (paper included by default). */
7082
7348
  compositePixels(options = {}) {
@@ -7160,7 +7426,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7160
7426
  const spills = Object.fromEntries(Object.entries(this.lightSpills).filter(([id]) => _chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, id)));
7161
7427
  if (Object.keys(spills).length) ext.lightSpill = spills;
7162
7428
  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])));
7429
+ const effectLayers = effectLayersToJSON(_nullishCoalesce(this.doc.effectLayers, () => ( {})), (id) => isPixelLayer(_optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _463 => _463.layer])));
7164
7430
  if (effectLayers) ext.effectLayers = effectLayers;
7165
7431
  else delete ext.effectLayers;
7166
7432
  if (this.doc.paperEffect) ext.paperEffect = paperEffectToJSON(this.doc.paperEffect);
@@ -7185,7 +7451,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7185
7451
  const stamp = _chunkRDFHWAHLcjs.editorStampOf.call(void 0, ref2);
7186
7452
  const { stamp: _old, variant, ...rest } = x;
7187
7453
  return [{ ...rest, ref: ref2, ...stamp ? { stamp } : {}, ...variant === "dark" && !stamp ? { variant } : {} }];
7188
- } catch (e9) {
7454
+ } catch (e10) {
7189
7455
  return [];
7190
7456
  }
7191
7457
  });
@@ -7197,7 +7463,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7197
7463
  if (ext.liveStrokes && typeof ext.liveStrokes === "object") {
7198
7464
  const liveStrokes = {};
7199
7465
  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;
7466
+ if (!isPixelLayer(_optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, state.layers, id), 'optionalAccess', _464 => _464.layer])) || !Array.isArray(list)) continue;
7201
7467
  const ok = list.map(normalizeBrushStroke).filter((x) => x !== null).map((x) => ({ ...x, layerId: id }));
7202
7468
  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
7469
  liveStrokes[id] = ok;
@@ -7207,7 +7473,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7207
7473
  if (ext.effectLayers && typeof ext.effectLayers === "object") {
7208
7474
  const effectLayers = {};
7209
7475
  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;
7476
+ if (!isPixelLayer(_optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, state.layers, id), 'optionalAccess', _465 => _465.layer]))) continue;
7211
7477
  const source = readPaintEffectSource(v);
7212
7478
  if (source) effectLayers[id] = source;
7213
7479
  else problems.push(`The effect of layer "${id}" could not be read; it loads as a plain layer.`);
@@ -7227,7 +7493,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7227
7493
  for (const [id, v] of Object.entries(ext.lightSpill)) {
7228
7494
  try {
7229
7495
  if (_chunkPVJMTLPJcjs.findLayer.call(void 0, state.layers, id)) this.lightSpills[id] = normalizeLightSpill(_nullishCoalesce(v, () => ( {})));
7230
- } catch (e10) {
7496
+ } catch (e11) {
7231
7497
  problems.push(`The light spill of layer "${id}" could not be read; it takes the defaults.`);
7232
7498
  }
7233
7499
  }
@@ -7235,7 +7501,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7235
7501
  if (ext.light && typeof ext.light === "object") {
7236
7502
  const light = {};
7237
7503
  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;
7504
+ if (!isPixelLayer(_optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, state.layers, id), 'optionalAccess', _466 => _466.layer]))) continue;
7239
7505
  try {
7240
7506
  light[id] = lightFromJSON(v);
7241
7507
  } catch (e) {
@@ -7271,7 +7537,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7271
7537
  this.readGuides(loaded.guides, loaded.state, loaded.problems);
7272
7538
  if (Array.isArray(loaded.swatches)) this.swatches = loaded.swatches.map(readSwatch).filter((x) => x !== null);
7273
7539
  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)));
7540
+ const n = Number(_nullishCoalesce(_optionalChain([/^s(\d+)$/, 'access', _467 => _467.exec, 'call', _468 => _468(s.id), 'optionalAccess', _469 => _469[1]]), () => ( 0)));
7275
7541
  if (n >= this.strokeCounter) this.strokeCounter = n + 1;
7276
7542
  }
7277
7543
  this.undoStack = [];
@@ -7279,7 +7545,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7279
7545
  this.doc = this.readThick(loaded.state, loaded.extensions, loaded.problems);
7280
7546
  for (const list of Object.values(_nullishCoalesce(this.doc.liveStrokes, () => ( {})))) {
7281
7547
  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)));
7548
+ const n = Number(_nullishCoalesce(_optionalChain([/^s(\d+)$/, 'access', _470 => _470.exec, 'call', _471 => _471(s.id), 'optionalAccess', _472 => _472[1]]), () => ( 0)));
7283
7549
  if (n >= this.strokeCounter) this.strokeCounter = n + 1;
7284
7550
  }
7285
7551
  }
@@ -7377,10 +7643,10 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7377
7643
  return next.type === "group" ? { ...next, children: toStandard(next.children) } : next;
7378
7644
  });
7379
7645
  const layers = toStandard(dried);
7380
- const result = _chunk4NMPUJUKcjs.exportPsd.call(void 0, { width, height, layers: [paperLayer, ...layers], merged, resolution: dpi });
7646
+ const result = _chunkDDL3ZBHKcjs.exportPsd.call(void 0, { width, height, layers: [paperLayer, ...layers], merged, resolution: dpi });
7381
7647
  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)));
7648
+ const label = _nullishCoalesce(_optionalChain([_chunk2VX55NFMcjs.BLEND_MODES, 'access', _473 => _473.find, 'call', _474 => _474((m) => m.id === mode), 'optionalAccess', _475 => _475.label]), () => ( mode));
7649
+ const std = _nullishCoalesce(_optionalChain([_chunk2VX55NFMcjs.BLEND_MODES, 'access', _476 => _476.find, 'call', _477 => _477((m) => m.id === _chunk2VX55NFMcjs.standardBlendMode.call(void 0, mode)), 'optionalAccess', _478 => _478.label]), () => ( _chunk2VX55NFMcjs.standardBlendMode.call(void 0, mode)));
7384
7650
  const list = names.map((n) => `"${n}"`).join(", ");
7385
7651
  const one = names.length === 1;
7386
7652
  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 +7768,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7502
7768
  const { src, pixels } = this.importImage(options, "The reference image");
7503
7769
  const ref2 = {
7504
7770
  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}`,
7771
+ name: _optionalChain([options, 'access', _479 => _479.name, 'optionalAccess', _480 => _480.trim, 'call', _481 => _481()]) || `Reference ${this.guides.references.length + 1}`,
7506
7772
  src,
7507
7773
  width: pixels.width,
7508
7774
  height: pixels.height,
@@ -7581,7 +7847,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7581
7847
  try {
7582
7848
  const px = this.decodeImage(ref2.src, `Reference "${ref2.name}"`);
7583
7849
  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)));
7850
+ const n = Number(_nullishCoalesce(_optionalChain([/^ref(\d+)$/, 'access', _482 => _482.exec, 'call', _483 => _483(ref2.id), 'optionalAccess', _484 => _484[1]]), () => ( 0)));
7585
7851
  if (n >= this.nextReferenceId) this.nextReferenceId = n + 1;
7586
7852
  } catch (e) {
7587
7853
  problems.push(e.message);
@@ -7592,7 +7858,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7592
7858
  guides.stencils = [];
7593
7859
  r.stencils.forEach((raw2, i) => {
7594
7860
  try {
7595
- const id = typeof _optionalChain([raw2, 'optionalAccess', _428 => _428.id]) === "string" && /^stencil\d+$/.test(raw2.id) ? raw2.id : `stencil${this.nextStencilId}`;
7861
+ const id = typeof _optionalChain([raw2, 'optionalAccess', _485 => _485.id]) === "string" && /^stencil\d+$/.test(raw2.id) ? raw2.id : `stencil${this.nextStencilId}`;
7596
7862
  guides.stencils.push(normalizeStencil(raw2, id));
7597
7863
  const n = Number(id.slice(7));
7598
7864
  if (n >= this.nextStencilId) this.nextStencilId = n + 1;
@@ -7615,12 +7881,12 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7615
7881
  /** The next free sticker number (ids `st<n>` are unique across the document). */
7616
7882
  nextStickerNumber(doc = this.doc) {
7617
7883
  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))));
7884
+ for (const list of Object.values(_nullishCoalesce(doc.stickers, () => ( {})))) for (const st of list) n = Math.max(n, Number(_nullishCoalesce(_optionalChain([/^st(\d+)$/, 'access', _486 => _486.exec, 'call', _487 => _487(st.id), 'optionalAccess', _488 => _488[1]]), () => ( 0))));
7619
7885
  return n + 1;
7620
7886
  }
7621
7887
  stickerLayer(layerId) {
7622
7888
  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]]);
7889
+ const stickers = _optionalChain([this, 'access', _489 => _489.doc, 'access', _490 => _490.stickers, 'optionalAccess', _491 => _491[l.id]]);
7624
7890
  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
7891
  return { layer: l, stickers };
7626
7892
  }
@@ -7696,7 +7962,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7696
7962
  const id = _nullishCoalesce(layerId, () => ( this.doc.activeLayerId));
7697
7963
  if (!id) return [];
7698
7964
  this.requireLayer(id);
7699
- return (_nullishCoalesce(_optionalChain([this, 'access', _435 => _435.doc, 'access', _436 => _436.stickers, 'optionalAccess', _437 => _437[id]]), () => ( []))).map((s) => ({ ...s }));
7965
+ return (_nullishCoalesce(_optionalChain([this, 'access', _492 => _492.doc, 'access', _493 => _493.stickers, 'optionalAccess', _494 => _494[id]]), () => ( []))).map((s) => ({ ...s }));
7700
7966
  }
7701
7967
  /**
7702
7968
  * Replaces a layer's stickers and redraws its pixels from them (one undo step). With `dirty`,
@@ -7717,7 +7983,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7717
7983
  }
7718
7984
  /** The document from before the sticker preview on screen, or `null` when none is (anything else changed the document since). */
7719
7985
  previewBase() {
7720
- return _optionalChain([this, 'access', _438 => _438.stickerPreview, 'optionalAccess', _439 => _439.shown]) === this.doc ? this.stickerPreview.base : null;
7986
+ return _optionalChain([this, 'access', _495 => _495.stickerPreview, 'optionalAccess', _496 => _496.shown]) === this.doc ? this.stickerPreview.base : null;
7721
7987
  }
7722
7988
  readStickerUpdate(update) {
7723
7989
  try {
@@ -7732,7 +7998,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7732
7998
  const id = _nullishCoalesce(layerId, () => ( this.doc.activeLayerId));
7733
7999
  if (!id) return null;
7734
8000
  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);
8001
+ const hit = stickerAt(_nullishCoalesce(_optionalChain([this, 'access', _497 => _497.doc, 'access', _498 => _498.stickers, 'optionalAccess', _499 => _499[id]]), () => ( [])), x, y, this.stickerArt.get);
7736
8002
  return hit ? { ...hit } : null;
7737
8003
  }
7738
8004
  /** Picks a sticker for the panel and canvas (`null` for none). Editor state, not an undo step. */
@@ -7789,8 +8055,8 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7789
8055
  const layer = this.wetLayer(layerId, "add stickers to");
7790
8056
  if (!input.length) throw new PaintEditorError("Pass at least one sticker (ref, x, y).");
7791
8057
  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])) {
8058
+ const existing = _optionalChain([this, 'access', _500 => _500.doc, 'access', _501 => _501.stickers, 'optionalAccess', _502 => _502[layer.id]]);
8059
+ if (!_optionalChain([existing, 'optionalAccess', _503 => _503.length])) {
7794
8060
  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
8061
  }
7796
8062
  let n = this.nextStickerNumber();
@@ -7807,7 +8073,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7807
8073
  const id = n++;
7808
8074
  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
8075
  });
7810
- this.commitStickers("Add stickers", layer, [..._nullishCoalesce(existing, () => ( [])), ...added], _optionalChain([existing, 'optionalAccess', _447 => _447.length]) ? added.map(stickerRect) : void 0);
8076
+ this.commitStickers("Add stickers", layer, [..._nullishCoalesce(existing, () => ( [])), ...added], _optionalChain([existing, 'optionalAccess', _504 => _504.length]) ? added.map(stickerRect) : void 0);
7811
8077
  return added.map((s) => ({ ...s }));
7812
8078
  }
7813
8079
  /** Brings stickers to the top (`front`) or bottom of their layer (one undo step). */
@@ -7846,20 +8112,20 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7846
8112
  }
7847
8113
  liveStrokeLayer(layerId, what) {
7848
8114
  const l = this.wetLayer(layerId, what);
7849
- const strokes = _optionalChain([this, 'access', _448 => _448.doc, 'access', _449 => _449.liveStrokes, 'optionalAccess', _450 => _450[l.id]]);
8115
+ const strokes = _optionalChain([this, 'access', _505 => _505.doc, 'access', _506 => _506.liveStrokes, 'optionalAccess', _507 => _507[l.id]]);
7850
8116
  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
8117
  return { layer: l, strokes };
7852
8118
  }
7853
8119
  /** Whether a layer is a live stroke layer. */
7854
8120
  isLiveStrokeLayer(layerId) {
7855
- return Boolean(_optionalChain([this, 'access', _451 => _451.doc, 'access', _452 => _452.liveStrokes, 'optionalAccess', _453 => _453[layerId]]));
8121
+ return Boolean(_optionalChain([this, 'access', _508 => _508.doc, 'access', _509 => _509.liveStrokes, 'optionalAccess', _510 => _510[layerId]]));
7856
8122
  }
7857
8123
  /** Makes an empty pixel layer a live stroke layer (one undo step). */
7858
8124
  convertToLiveStrokes(layerId) {
7859
8125
  this.requireIdle("converting a layer");
7860
8126
  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"}).`);
8127
+ if (_optionalChain([this, 'access', _511 => _511.doc, 'access', _512 => _512.liveStrokes, 'optionalAccess', _513 => _513[l.id]])) return this.describeLayer(l);
8128
+ if (_optionalChain([this, 'access', _514 => _514.doc, 'access', _515 => _515.stickers, 'optionalAccess', _516 => _516[l.id], 'optionalAccess', _517 => _517.length])) throw new PaintEditorError(`Layer "${l.name}" is a sticker layer; add a stroke layer instead (add_layer {type: "strokes"}).`);
7863
8129
  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
8130
  this.commit("Convert to stroke layer", { ...this.doc, liveStrokes: { ..._nullishCoalesce(this.doc.liveStrokes, () => ( {})), [l.id]: [] } });
7865
8131
  return this.describeLayer(this.getLayer(l.id));
@@ -7872,7 +8138,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7872
8138
  findLiveStroke(id) {
7873
8139
  for (const [layerId, strokes] of Object.entries(_nullishCoalesce(this.doc.liveStrokes, () => ( {})))) {
7874
8140
  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]);
8141
+ const layer = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.doc.layers, layerId), 'optionalAccess', _518 => _518.layer]);
7876
8142
  if (index >= 0 && isPixelLayer(layer)) return { layer, strokes, index };
7877
8143
  }
7878
8144
  const baked = this.doc.strokes.some((x) => x.id === id);
@@ -7911,9 +8177,10 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7911
8177
  }
7912
8178
  if (update.paint !== void 0) {
7913
8179
  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));
8180
+ else if (_chunkJJ2H25JGcjs.isPaintEffectPaint.call(void 0, update.paint)) {
8181
+ const ep = _optionalChain([update, 'access', _519 => _519.paint, 'access', _520 => _520.map, 'optionalAccess', _521 => _521.by]) === "path" ? _chunkJJ2H25JGcjs.withStrokePath.call(void 0, update.paint, next.points, this.effectPathControls.get(update.paint.effect)) : update.paint;
8182
+ 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).`);
8183
+ next.paint = JSON.parse(JSON.stringify(ep));
7917
8184
  } else {
7918
8185
  const p = this.readStrokePaint(update.paint);
7919
8186
  if (p.type === "color") {
@@ -7922,7 +8189,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7922
8189
  } else next.paint = JSON.parse(JSON.stringify(p));
7923
8190
  }
7924
8191
  }
7925
- const rgb = _chunk56RHCIJVcjs.hexToRgb8.call(void 0, next.color).map((v) => v / 255);
8192
+ const rgb = _chunkJJ2H25JGcjs.hexToRgb8.call(void 0, next.color).map((v) => v / 255);
7926
8193
  const load = brushLoadForStroke(brush, _chunkNIBFKXMDcjs.EMPTY_MIXER_LOAD, rgb);
7927
8194
  if (load.reservoir || load.pickup) next.load = load;
7928
8195
  else delete next.load;
@@ -7944,13 +8211,11 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7944
8211
  if (edit.points !== void 0) {
7945
8212
  const points = this.checkPoints(edit.points);
7946
8213
  next = { ...was, points: points.map((p) => ({ ...p })) };
8214
+ if (_optionalChain([next, 'access', _522 => _522.paint, 'optionalAccess', _523 => _523.type]) === "effect" && _optionalChain([next, 'access', _524 => _524.paint, 'access', _525 => _525.map, 'optionalAccess', _526 => _526.by]) === "path") {
8215
+ next.paint = _chunkJJ2H25JGcjs.withStrokePath.call(void 0, next.paint, next.points, this.effectPathControls.get(next.paint.effect));
8216
+ }
7947
8217
  } 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, {});
8218
+ next = varyStroke(was, this.strokeTransform(was, edit.transform), {});
7954
8219
  if (was.stencils) next.stencils = was.stencils;
7955
8220
  }
7956
8221
  const list = strokes.map((x, i) => i === index ? next : x);
@@ -7967,9 +8232,9 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
7967
8232
  const layers = /* @__PURE__ */ new Map();
7968
8233
  for (const f of found) layers.set(f.layer.id, f.layer);
7969
8234
  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));
8235
+ const gone = (_nullishCoalesce(_optionalChain([doc, 'access', _527 => _527.liveStrokes, 'optionalAccess', _528 => _528[layerId]]), () => ( []))).filter((x) => ids.includes(x.id));
7971
8236
  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));
8237
+ doc = this.withLiveStrokes(doc, layer, (_nullishCoalesce(_optionalChain([doc, 'access', _529 => _529.liveStrokes, 'optionalAccess', _530 => _530[layerId]]), () => ( []))).filter((x) => !ids.includes(x.id)), this.strokeAreas(gone));
7973
8238
  }
7974
8239
  this.commit(ids.length === 1 ? "Remove stroke" : "Remove strokes", doc);
7975
8240
  return { removed: [...ids], bounds };
@@ -8037,7 +8302,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
8037
8302
  }
8038
8303
  withLiveStrokes(doc, layer, list, dirty) {
8039
8304
  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]);
8305
+ const current = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, doc.layers, layer.id), 'optionalAccess', _531 => _531.layer]);
8041
8306
  const surface = this.drawLiveStrokes(_nullishCoalesce(current, () => ( layer)), list, dirty);
8042
8307
  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
8308
  return this.withPaintEvent(next, { kind: "live-strokes", layerId: layer.id, data: { strokes: list.map((x) => JSON.parse(JSON.stringify(x))) } });
@@ -8115,7 +8380,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
8115
8380
  if (!this.animatedLayers.size) return this.doc.layers;
8116
8381
  let layers = this.doc.layers;
8117
8382
  for (const [id, a] of this.animatedLayers) {
8118
- const l = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, layers, id), 'optionalAccess', _467 => _467.layer]);
8383
+ const l = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, layers, id), 'optionalAccess', _532 => _532.layer]);
8119
8384
  if (isPixelLayer(l) && l.surface === a.base) layers = _chunkPVJMTLPJcjs.mapLayer.call(void 0, layers, id, () => ({ ...l, surface: a.surface }));
8120
8385
  }
8121
8386
  return layers;
@@ -8125,11 +8390,11 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
8125
8390
  const layers = [];
8126
8391
  const sources = /* @__PURE__ */ new Map();
8127
8392
  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]);
8393
+ const layer = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, doc.layers, id), 'optionalAccess', _533 => _533.layer]);
8129
8394
  const live = strokes.filter(isLiveEffect);
8130
8395
  if (!isPixelLayer(layer) || !live.length) continue;
8131
8396
  layers.push({ layer, strokes });
8132
- for (const st of live) sources.set(_chunk56RHCIJVcjs.effectPaintKey.call(void 0, st.paint), st.paint);
8397
+ for (const st of live) sources.set(_chunkJJ2H25JGcjs.effectPaintKey.call(void 0, st.paint), st.paint);
8133
8398
  }
8134
8399
  return { layers, sources: [...sources.values()] };
8135
8400
  }
@@ -8250,13 +8515,13 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
8250
8515
  return this.withEffectTime(time, () => this.compositePixels(options));
8251
8516
  }
8252
8517
  // --- Stencils --------------------------------------------------------------------
8253
- __init132() {this.stencilCache = null}
8254
- __init133() {this.nextStencilId = 1}
8518
+ __init136() {this.stencilCache = null}
8519
+ __init137() {this.nextStencilId = 1}
8255
8520
  /** The mask stencils' coverage over the canvas (cached), or `null` when none masks. */
8256
8521
  stencilSelection(stencils = this.guides.stencils) {
8257
8522
  const { width, height } = this.doc.canvas;
8258
8523
  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;
8524
+ if (_optionalChain([this, 'access', _534 => _534.stencilCache, 'optionalAccess', _535 => _535.key]) === stencils && this.stencilCache.size === size) return this.stencilCache.mask;
8260
8525
  const mask = stencilMask(stencils, width, height);
8261
8526
  this.stencilCache = { key: stencils, size, mask };
8262
8527
  return mask;
@@ -8318,7 +8583,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
8318
8583
  makeSwatch(color, name) {
8319
8584
  const p = typeof color === "string" ? { type: "color", color: parseColor(color) } : this.readStrokePaint(color);
8320
8585
  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();
8586
+ if (_optionalChain([name, 'optionalAccess', _536 => _536.trim, 'call', _537 => _537()])) out.name = name.trim();
8322
8587
  if (p.type === "gradient") out.paint = p;
8323
8588
  return out;
8324
8589
  }
@@ -8370,7 +8635,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
8370
8635
  * mix becomes the paint colour. Returns the mixed colour and the pile's bounds.
8371
8636
  */
8372
8637
  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]) }));
8638
+ const parsed = (_nullishCoalesce(paints2, () => ( []))).map((p, i) => ({ color: parseColor(_optionalChain([p, 'optionalAccess', _538 => _538.color]), `paints[${i}].color`), parts: _optionalChain([p, 'optionalAccess', _539 => _539.parts]) }));
8374
8639
  let r;
8375
8640
  try {
8376
8641
  r = this.pad.mix(parsed, options);
@@ -8459,7 +8724,7 @@ var PaintEditorController = (_class14 = class _PaintEditorController {
8459
8724
  }
8460
8725
  /** A layer's tile surface (live while stroking), for thumbnails. */
8461
8726
  layerSurface(id) {
8462
- const l = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.currentLayers(), id), 'optionalAccess', _475 => _475.layer]);
8727
+ const l = _optionalChain([_chunkPVJMTLPJcjs.findLayer.call(void 0, this.currentLayers(), id), 'optionalAccess', _540 => _540.layer]);
8463
8728
  return isPixelLayer(l) ? l.surface : null;
8464
8729
  }
8465
8730
  }, _class14.__initStatic(), _class14);
@@ -8481,7 +8746,7 @@ function insertAfter(layers, id, node) {
8481
8746
  return layers.map((l) => l.type === "group" ? { ...l, children: insertAfter(l.children, id, node) } : l);
8482
8747
  }
8483
8748
  function isLiveEffect(s) {
8484
- return _optionalChain([s, 'access', _476 => _476.paint, 'optionalAccess', _477 => _477.type]) === "effect" && s.paint.live === true;
8749
+ return _optionalChain([s, 'access', _541 => _541.paint, 'optionalAccess', _542 => _542.type]) === "effect" && s.paint.live === true;
8485
8750
  }
8486
8751
  function framePaint(p, t) {
8487
8752
  return { ...p, time: p.time + t };
@@ -8506,7 +8771,7 @@ function clipRect(r, width, height) {
8506
8771
  return x1 > x0 && y1 > y0 ? { x: x0, y: y0, width: x1 - x0, height: y1 - y0 } : null;
8507
8772
  }
8508
8773
  function withLiveStroke(doc, stroke) {
8509
- const list = _optionalChain([doc, 'access', _478 => _478.liveStrokes, 'optionalAccess', _479 => _479[stroke.layerId]]);
8774
+ const list = _optionalChain([doc, 'access', _543 => _543.liveStrokes, 'optionalAccess', _544 => _544[stroke.layerId]]);
8510
8775
  return list ? { ...doc, liveStrokes: { ...doc.liveStrokes, [stroke.layerId]: [...list, stroke] } } : doc;
8511
8776
  }
8512
8777
  function shiftDocument(doc, dx, dy) {
@@ -8533,9 +8798,9 @@ function shiftDocument(doc, dx, dy) {
8533
8798
  if (doc.liveStrokes) out.liveStrokes = Object.fromEntries(Object.entries(doc.liveStrokes).map(([id, list]) => [id, list.map(moveStroke)]));
8534
8799
  if (doc.paintEvents) {
8535
8800
  out.paintEvents = doc.paintEvents.map((e) => {
8536
- const list = e.kind === "stickers" ? _optionalChain([e, 'access', _480 => _480.data, 'optionalAccess', _481 => _481.stickers]) : void 0;
8801
+ const list = e.kind === "stickers" ? _optionalChain([e, 'access', _545 => _545.data, 'optionalAccess', _546 => _546.stickers]) : void 0;
8537
8802
  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;
8803
+ const strokes = e.kind === "live-strokes" ? _optionalChain([e, 'access', _547 => _547.data, 'optionalAccess', _548 => _548.strokes]) : void 0;
8539
8804
  return strokes ? { ...e, data: { ...e.data, strokes: strokes.map(moveStroke) } } : e;
8540
8805
  });
8541
8806
  }
@@ -8606,6 +8871,9 @@ function clipToCanvas(rect, canvas) {
8606
8871
  const y1 = Math.min(canvas.height, rect.y + rect.height);
8607
8872
  return x1 > x0 && y1 > y0 ? { x: x0, y: y0, width: x1 - x0, height: y1 - y0 } : null;
8608
8873
  }
8874
+ function toEffectPaintPixels(p, pixels) {
8875
+ return { width: pixels.width, height: pixels.height, data: new Uint8ClampedArray(pixels.data), ..._optionalChain([p, 'access', _549 => _549.map, 'optionalAccess', _550 => _550.by]) === "stroke" ? { map: p.map } : {} };
8876
+ }
8609
8877
 
8610
8878
  // src/paint-editor/presence.ts
8611
8879
  var PaintPresence = class extends _chunkK7ENM55Pcjs.PresenceStore {
@@ -8624,8 +8892,8 @@ function strokeSchedule(points) {
8624
8892
  return total > 0 ? acc.map((d) => d / total) : points.map(() => 1);
8625
8893
  }
8626
8894
  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]);
8895
+ const t0 = _optionalChain([points, 'access', _551 => _551[0], 'optionalAccess', _552 => _552.t]);
8896
+ const t1 = _optionalChain([points, 'access', _553 => _553[points.length - 1], 'optionalAccess', _554 => _554.t]);
8629
8897
  let ms;
8630
8898
  if (points.every((p) => Number.isFinite(p.t)) && t1 > t0) ms = t1 - t0;
8631
8899
  else {
@@ -8679,7 +8947,7 @@ var PaintDirector = class {
8679
8947
  }
8680
8948
  where(id) {
8681
8949
  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)) };
8950
+ return { x: _nullishCoalesce(_optionalChain([a, 'optionalAccess', _555 => _555.x]), () => ( 0)), y: _nullishCoalesce(_optionalChain([a, 'optionalAccess', _556 => _556.y]), () => ( 0)) };
8683
8951
  }
8684
8952
  /** Glides to `to`; an actor that just appeared starts there instead of the corner. */
8685
8953
  async glide(id, to, ms = 380) {
@@ -8729,8 +8997,8 @@ var PaintDirector = class {
8729
8997
  }
8730
8998
  case "replay": {
8731
8999
  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]]);
9000
+ const source = c.getStrokes().filter((s) => _optionalChain([command, 'access', _557 => _557.replay, 'access', _558 => _558.strokeIds, 'optionalAccess', _559 => _559.includes, 'call', _560 => _560(s.id)]));
9001
+ const first = _optionalChain([source, 'access', _561 => _561[0], 'optionalAccess', _562 => _562.points, 'access', _563 => _563[0]]);
8734
9002
  if (first) await this.glide(id, first);
8735
9003
  const result = c.replayStrokes(command.replay);
8736
9004
  if (result.bounds) await this.glide(id, centre(result.bounds), 520);
@@ -8778,7 +9046,7 @@ var PaintDirector = class {
8778
9046
  const checked = inits.map((s) => ({ ...s, points: c.checkPoints(s.points) }));
8779
9047
  const first = checked[0];
8780
9048
  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`));
9049
+ const stepLabel = _nullishCoalesce(label, () => ( `${_nullishCoalesce(_optionalChain([base, 'optionalAccess', _564 => _564.name]), () => ( "Brush"))} path stroke`));
8782
9050
  return c.group(stepLabel, async (within) => {
8783
9051
  let layerId = _nullishCoalesce(_nullishCoalesce(first.layerId, () => ( c.document.activeLayerId)), () => ( ""));
8784
9052
  let bounds = null;
@@ -8798,8 +9066,8 @@ var PaintDirector = class {
8798
9066
  bounds,
8799
9067
  dabs,
8800
9068
  strokeIds,
8801
- ..._optionalChain([last, 'optionalAccess', _498 => _498.mixerLoad]) ? { mixerLoad: last.mixerLoad } : {},
8802
- ..._optionalChain([last, 'optionalAccess', _499 => _499.wet]) !== void 0 ? { wet: last.wet } : {}
9069
+ ..._optionalChain([last, 'optionalAccess', _565 => _565.mixerLoad]) ? { mixerLoad: last.mixerLoad } : {},
9070
+ ..._optionalChain([last, 'optionalAccess', _566 => _566.wet]) !== void 0 ? { wet: last.wet } : {}
8803
9071
  };
8804
9072
  });
8805
9073
  }
@@ -9971,8 +10239,8 @@ function createPaintEditorToolProvider(controller, options = {}) {
9971
10239
  inputSchema: EMPTY3,
9972
10240
  annotations: { title: "List papers", ...READ6 },
9973
10241
  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],
10242
+ papers: _chunkJJ2H25JGcjs.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 })),
10243
+ families: [..._chunkJJ2H25JGcjs.PAPER_FAMILIES],
9976
10244
  patterns: [..._chunkNIBFKXMDcjs.GRAIN_PATTERNS]
9977
10245
  })
9978
10246
  });
@@ -10207,7 +10475,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
10207
10475
  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 },
10208
10476
  annotations: { title: "Set the brush", ...SET4 },
10209
10477
  handler: async ({ id, unset, ...patch }) => {
10210
- const stamps = _optionalChain([patch, 'access', _500 => _500.tip, 'optionalAccess', _501 => _501.stamps]);
10478
+ const stamps = _optionalChain([patch, 'access', _567 => _567.tip, 'optionalAccess', _568 => _568.stamps]);
10211
10479
  if (stamps) await c.prepareStickers(stamps);
10212
10480
  const r = c.setBrushFacets(patch, id, unset);
10213
10481
  return { brush: r.spec, engine: r.brush.engine, problems: r.problems };
@@ -10316,10 +10584,11 @@ function createPaintEditorToolProvider(controller, options = {}) {
10316
10584
  const base = a.brushId ? c.getBrush(a.brushId) : c.getState().brush;
10317
10585
  const brush = a.brush ? c.brushChanges(a.brush, a.brushId) : void 0;
10318
10586
  if (base) {
10319
- const refs = _chunk56RHCIJVcjs.brushStickerRefs.call(void 0, _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, { ..._nullishCoalesce(brush, () => ( {})), id: base.id }, base));
10587
+ const refs = _chunkJJ2H25JGcjs.brushStickerRefs.call(void 0, _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, { ..._nullishCoalesce(brush, () => ( {})), id: base.id }, base));
10320
10588
  if (refs.length) await c.prepareStickers(refs);
10321
10589
  }
10322
10590
  const stroke = { points: a.points, layerId: a.layerId, brushId: a.brushId, brush, color: a.color, paint: a.paint, seed: a.seed, snapToPerspective: a.snapToPerspective };
10591
+ await c.prepareStrokePathEffect(stroke, [stroke.points]);
10323
10592
  const r = await act({ kind: "stroke", stroke }, () => c.paintStroke(stroke));
10324
10593
  return r.mixerLoad ? { ...r, mixerLoad: loadResult(r.mixerLoad) } : r;
10325
10594
  }
@@ -10352,11 +10621,18 @@ function createPaintEditorToolProvider(controller, options = {}) {
10352
10621
  const base = a.brushId ? c.getBrush(a.brushId) : c.getState().brush;
10353
10622
  const brush = a.brush ? c.brushChanges(a.brush, a.brushId) : void 0;
10354
10623
  if (base) {
10355
- const refs = _chunk56RHCIJVcjs.brushStickerRefs.call(void 0, _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, { ..._nullishCoalesce(brush, () => ( {})), id: base.id }, base));
10624
+ const refs = _chunkJJ2H25JGcjs.brushStickerRefs.call(void 0, _chunkEU2ZZA6Lcjs.normalizePaintBrush.call(void 0, { ..._nullishCoalesce(brush, () => ( {})), id: base.id }, base));
10356
10625
  if (refs.length) await c.prepareStickers(refs);
10357
10626
  }
10358
10627
  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
10628
  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 };
10629
+ if (typeof path === "string" && path.trim()) {
10630
+ try {
10631
+ const sampled = samplePath(path, init);
10632
+ await c.prepareStrokePathEffect(init, sampled);
10633
+ } catch (e12) {
10634
+ }
10635
+ }
10360
10636
  const r = await act(
10361
10637
  () => {
10362
10638
  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 +10645,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
10369
10645
  const { path: _path, spacing: _spacing, pressure: _pressure, speed: _speed, ...stroke } = init;
10370
10646
  return {
10371
10647
  kind: "strokes",
10372
- label: `${_nullishCoalesce(_optionalChain([base, 'optionalAccess', _502 => _502.name]), () => ( "Brush"))} path stroke`,
10648
+ label: `${_nullishCoalesce(_optionalChain([base, 'optionalAccess', _569 => _569.name]), () => ( "Brush"))} path stroke`,
10373
10649
  strokes: subpaths.map((points, i) => ({
10374
10650
  ...stroke,
10375
10651
  ...stroke.seed !== void 0 ? { seed: stroke.seed + i } : {},
@@ -10426,7 +10702,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
10426
10702
  if (ids) {
10427
10703
  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
10704
  }
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)) };
10705
+ return { total: all.length, strokes: picked.map((s) => strokeSummary(s, Boolean(ids), live ? true : liveIds.has(s.id) && _optionalChain([c, 'access', _570 => _570.document, 'access', _571 => _571.liveStrokes, 'optionalAccess', _572 => _572[s.layerId], 'optionalAccess', _573 => _573.includes, 'call', _574 => _574(s)]) === true)) };
10430
10706
  }
10431
10707
  });
10432
10708
  add({
@@ -10508,7 +10784,8 @@ function createPaintEditorToolProvider(controller, options = {}) {
10508
10784
  },
10509
10785
  annotations: { title: "Move or reshape a stroke", ...WRITE5 },
10510
10786
  coordinates: { in: ["points[]", "transform.origin"], out: ["bounds", "stroke.bounds", "stroke.points[]"] },
10511
- handler: ({ id, points, transform }) => {
10787
+ handler: async ({ id, points, transform }) => {
10788
+ await c.prepareStrokeEdit(id, { points, transform });
10512
10789
  const r = c.editStrokePoints(id, { points, transform });
10513
10790
  return { stroke: strokeSummary(r.stroke, true, true), bounds: r.bounds };
10514
10791
  }
@@ -10591,7 +10868,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
10591
10868
  coordinates: { in: ["origin"], out: ["bounds"] },
10592
10869
  handler: async (a) => {
10593
10870
  const replay = a;
10594
- if (replay.color === void 0) await c.prepareStrokeEffects(replay.strokeIds);
10871
+ if (replay.color === void 0) await c.prepareStrokeEffects(replay.strokeIds, replay);
10595
10872
  return act({ kind: "replay", replay }, () => c.replayStrokes(replay));
10596
10873
  }
10597
10874
  });
@@ -10710,7 +10987,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
10710
10987
  tools.push(..._chunk62MFUHSIcjs.createPigmentTools.call(void 0, ));
10711
10988
  tools.push(..._chunkPFHJS4HEcjs.createStickerTools.call(void 0, { provider: () => c.stickersProvider }));
10712
10989
  tools.push(
10713
- ..._chunk4NMPUJUKcjs.createLayerEffectTools.call(void 0,
10990
+ ..._chunkDDL3ZBHKcjs.createLayerEffectTools.call(void 0,
10714
10991
  {
10715
10992
  requireLayer: (id) => void c.getLayerEffects(id),
10716
10993
  getLayerEffects: (id) => c.getLayerEffects(id),
@@ -10735,16 +11012,16 @@ function createPaintEditorToolProvider(controller, options = {}) {
10735
11012
  }
10736
11013
  function hostTool({ coordinates, ...tool }, { origin, onChange }) {
10737
11014
  if (!origin && !onChange) return tool;
10738
- const write = !_optionalChain([tool, 'access', _508 => _508.annotations, 'optionalAccess', _509 => _509.readOnlyHint]);
11015
+ const write = !_optionalChain([tool, 'access', _575 => _575.annotations, 'optionalAccess', _576 => _576.readOnlyHint]);
10739
11016
  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;
11017
+ if (write) _optionalChain([onChange, 'optionalCall', _577 => _577({ tool: tool.name })]);
11018
+ return origin && _optionalChain([coordinates, 'optionalAccess', _578 => _578.out]) ? fromDocument(result, coordinates.out, origin) : result;
10742
11019
  };
10743
11020
  return {
10744
11021
  ...tool,
10745
11022
  ...origin ? { description: hostedText(_nullishCoalesce(tool.description, () => ( ""))), inputSchema: hostedSchema(tool.inputSchema) } : {},
10746
11023
  handler: (args, context) => {
10747
- const r = tool.handler(origin && _optionalChain([coordinates, 'optionalAccess', _512 => _512.in]) ? toDocument(args, coordinates.in, origin) : args, context);
11024
+ const r = tool.handler(origin && _optionalChain([coordinates, 'optionalAccess', _579 => _579.in]) ? toDocument(args, coordinates.in, origin) : args, context);
10748
11025
  return r instanceof Promise ? r.then(done) : done(r);
10749
11026
  }
10750
11027
  };
@@ -10761,17 +11038,17 @@ function strokeSummary(s, withPoints, live) {
10761
11038
  color: s.color,
10762
11039
  points: withPoints ? s.points : s.points.length,
10763
11040
  seed: s.seed,
10764
- copies: _nullishCoalesce(_optionalChain([s, 'access', _513 => _513.copies, 'optionalAccess', _514 => _514.length]), () => ( 0)),
11041
+ copies: _nullishCoalesce(_optionalChain([s, 'access', _580 => _580.copies, 'optionalAccess', _581 => _581.length]), () => ( 0)),
10765
11042
  live,
10766
11043
  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
11044
  };
10768
11045
  }
10769
11046
 
10770
11047
  // src/paint-editor/brush-library-tools.ts
10771
- function paintBrushPreviewRenderer(paper = () => _chunk56RHCIJVcjs.DEFAULT_PAPER, options = {}) {
11048
+ function paintBrushPreviewRenderer(paper = () => _chunkJJ2H25JGcjs.DEFAULT_PAPER, options = {}) {
10772
11049
  const sources = new BrushSourceArtCache();
10773
11050
  const draw = (brush, { width, height, color }) => {
10774
- const stickers = _optionalChain([options, 'access', _515 => _515.stampArt, 'optionalCall', _516 => _516()]);
11051
+ const stickers = _optionalChain([options, 'access', _582 => _582.stampArt, 'optionalCall', _583 => _583()]);
10775
11052
  const stampArt = sources.with(_nullishCoalesce(stickers, () => ( (() => void 0))));
10776
11053
  const t = renderBrushThumbnail(_chunkEU2ZZA6Lcjs.resolveBrush.call(void 0, brush), { paper: paper(), width, height, color: color.toLowerCase(), stampArt });
10777
11054
  return { data: _chunkW5M3J7PVcjs.bytesToBase64.call(void 0, _chunkW5M3J7PVcjs.encodePng.call(void 0, t.width, t.height, t.data)), mimeType: "image/png" };
@@ -10806,20 +11083,20 @@ var PAINT_TOOLS = [
10806
11083
  { id: "rotate", label: "Rotate view", key: "r" }
10807
11084
  ];
10808
11085
  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);
11086
+ 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
11087
  this.controller = controller;
10811
11088
  this.box = box;
10812
11089
  }
10813
11090
 
10814
11091
 
10815
- __init134() {this.tool = "brush"}
11092
+ __init138() {this.tool = "brush"}
10816
11093
  /** The last refusal (a hidden or locked layer), for the editor to show. */
10817
- __init135() {this.error = null}
11094
+ __init139() {this.error = null}
10818
11095
  /** 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}
11096
+ __init140() {this.predicted = []}
11097
+ __init141() {this.mode = null}
11098
+ __init142() {this.penAt = null}
11099
+ __init143() {this.penDown = false}
10823
11100
  doc(e) {
10824
11101
  const b = this.box();
10825
11102
  const s = this.controller.getState();
@@ -10875,13 +11152,13 @@ var PaintGesture = (_class15 = class {
10875
11152
  const p = this.doc(e);
10876
11153
  const s = this.controller.getState();
10877
11154
  const layerId = s.document.activeLayerId;
10878
- if (!layerId || !_optionalChain([s, 'access', _517 => _517.document, 'access', _518 => _518.liveStrokes, 'optionalAccess', _519 => _519[layerId]])) {
11155
+ if (!layerId || !_optionalChain([s, 'access', _584 => _584.document, 'access', _585 => _585.liveStrokes, 'optionalAccess', _586 => _586[layerId]])) {
10879
11156
  this.error = "Pick a stroke layer in the Layers panel (or add one) to select its strokes.";
10880
11157
  return false;
10881
11158
  }
10882
11159
  try {
10883
11160
  const hit = this.controller.liveStrokeAt(layerId, p.x, p.y);
10884
- this.controller.selectStroke(_nullishCoalesce(_optionalChain([hit, 'optionalAccess', _520 => _520.id]), () => ( null)));
11161
+ this.controller.selectStroke(_nullishCoalesce(_optionalChain([hit, 'optionalAccess', _587 => _587.id]), () => ( null)));
10885
11162
  if (!hit) return false;
10886
11163
  this.mode = { kind: "move-stroke", pointerId: e.pointerId, id: hit.id, from: p, to: p };
10887
11164
  return true;
@@ -10893,7 +11170,7 @@ var PaintGesture = (_class15 = class {
10893
11170
  /** While a stroke is dragged: how far it has moved (document pixels), to draw its outline there. */
10894
11171
  get strokeDrag() {
10895
11172
  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;
11173
+ return _optionalChain([m, 'optionalAccess', _588 => _588.kind]) === "move-stroke" ? { id: m.id, dx: m.to.x - m.from.x, dy: m.to.y - m.from.y } : null;
10897
11174
  }
10898
11175
  /**
10899
11176
  * The Stickers tool: pressing a sticker picks it and dragging moves it (one undo step at the
@@ -10967,15 +11244,28 @@ var PaintGesture = (_class15 = class {
10967
11244
  if (!m || m.pointerId !== e.pointerId) return;
10968
11245
  this.mode = null;
10969
11246
  this.predicted = [];
10970
- if (m.kind === "stroke") _optionalChain([this, 'access', _522 => _522.controller, 'access', _523 => _523.activeStroke, 'optionalAccess', _524 => _524.end, 'call', _525 => _525()]);
11247
+ if (m.kind === "stroke") {
11248
+ _optionalChain([this, 'access', _589 => _589.controller, 'access', _590 => _590.activeStroke, 'optionalAccess', _591 => _591.end, 'call', _592 => _592()]);
11249
+ _optionalChain([this, 'access', _593 => _593.controller, 'access', _594 => _594.strokeRendering, 'optionalAccess', _595 => _595.catch, 'call', _596 => _596((err) => {
11250
+ this.error = err instanceof Error ? err.message : String(err);
11251
+ })]);
11252
+ }
10971
11253
  if (m.kind === "move-stroke") {
10972
11254
  const dx = Math.round((this.doc(e).x - m.from.x) * 100) / 100;
10973
11255
  const dy = Math.round((this.doc(e).y - m.from.y) * 100) / 100;
10974
11256
  if (dx || dy) {
10975
- try {
10976
- this.controller.editStrokePoints(m.id, { transform: { dx, dy } });
10977
- } catch (err) {
11257
+ const edit = { transform: { dx, dy } };
11258
+ const failed = (err) => {
10978
11259
  this.error = err instanceof Error ? err.message : String(err);
11260
+ };
11261
+ if (this.controller.strokeEditNeedsRender(m.id, edit)) {
11262
+ this.controller.prepareStrokeEdit(m.id, edit).then(() => this.controller.editStrokePoints(m.id, edit)).catch(failed);
11263
+ } else {
11264
+ try {
11265
+ this.controller.editStrokePoints(m.id, edit);
11266
+ } catch (err) {
11267
+ failed(err);
11268
+ }
10979
11269
  }
10980
11270
  }
10981
11271
  }
@@ -10991,8 +11281,8 @@ var PaintGesture = (_class15 = class {
10991
11281
  cancel() {
10992
11282
  this.penDown = false;
10993
11283
  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();
11284
+ if (_optionalChain([this, 'access', _597 => _597.mode, 'optionalAccess', _598 => _598.kind]) === "stroke") _optionalChain([this, 'access', _599 => _599.controller, 'access', _600 => _600.activeStroke, 'optionalAccess', _601 => _601.cancel, 'call', _602 => _602()]);
11285
+ if (_optionalChain([this, 'access', _603 => _603.mode, 'optionalAccess', _604 => _604.kind]) === "sticker") this.controller.cancelStickerPreview();
10996
11286
  this.mode = null;
10997
11287
  }
10998
11288
  get active() {
@@ -11057,13 +11347,13 @@ function handlePaintShortcut(controller, gesture, e) {
11057
11347
  return true;
11058
11348
  }
11059
11349
  var PaintCanvasPresenter = (_class16 = class {
11060
- constructor(controller) {;_class16.prototype.__init140.call(this);_class16.prototype.__init141.call(this);_class16.prototype.__init142.call(this);
11350
+ constructor(controller) {;_class16.prototype.__init144.call(this);_class16.prototype.__init145.call(this);_class16.prototype.__init146.call(this);
11061
11351
  this.controller = controller;
11062
11352
  }
11063
11353
 
11064
- __init140() {this.uploaded = /* @__PURE__ */ new Map()}
11065
- __init141() {this.scratch = null}
11066
- __init142() {this.size = ""}
11354
+ __init144() {this.uploaded = /* @__PURE__ */ new Map()}
11355
+ __init145() {this.scratch = null}
11356
+ __init146() {this.size = ""}
11067
11357
  /** Draws what changed into `ctx` (a canvas the size of the document); returns the tiles drawn. */
11068
11358
  render(ctx) {
11069
11359
  const { width, height } = this.controller.document.canvas;
@@ -11095,7 +11385,7 @@ function guideOverlay(controller, drag) {
11095
11385
  const size = s.document.canvas;
11096
11386
  const out = [];
11097
11387
  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;
11388
+ const strokePicked = layerId && s.selectedStroke ? _optionalChain([s, 'access', _605 => _605.document, 'access', _606 => _606.liveStrokes, 'optionalAccess', _607 => _607[layerId], 'optionalAccess', _608 => _608.some, 'call', _609 => _609((x) => x.id === s.selectedStroke)]) : false;
11099
11389
  const area = strokePicked ? controller.liveStrokeArea(s.selectedStroke) : null;
11100
11390
  if (area) {
11101
11391
  const dx = drag && drag.id === s.selectedStroke ? drag.dx : 0;
@@ -11108,7 +11398,7 @@ function guideOverlay(controller, drag) {
11108
11398
  ];
11109
11399
  for (let i = 0; i < 4; i++) out.push({ from: box[i], to: box[(i + 1) % 4], kind: "stroke" });
11110
11400
  }
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;
11401
+ const picked = layerId && s.selectedSticker ? _optionalChain([s, 'access', _610 => _610.document, 'access', _611 => _611.stickers, 'optionalAccess', _612 => _612[layerId], 'optionalAccess', _613 => _613.find, 'call', _614 => _614((x) => x.id === s.selectedSticker)]) : void 0;
11112
11402
  if (picked) {
11113
11403
  const r = picked.size / 2 + 2;
11114
11404
  const a = picked.rotation * Math.PI / 180;
@@ -11138,7 +11428,7 @@ var PAPER_SLIDERS = [
11138
11428
  ];
11139
11429
  function readPath(obj, path) {
11140
11430
  let v = obj;
11141
- for (const k of path.split(".")) v = _optionalChain([v, 'optionalAccess', _544 => _544[k]]);
11431
+ for (const k of path.split(".")) v = _optionalChain([v, 'optionalAccess', _615 => _615[k]]);
11142
11432
  return typeof v === "number" ? v : 0;
11143
11433
  }
11144
11434
  function patchPath(obj, path, value) {
@@ -11254,7 +11544,7 @@ function startWetClock(controller, frame, cancel) {
11254
11544
  id = raf(loop);
11255
11545
  return () => {
11256
11546
  stopped = true;
11257
- _optionalChain([caf, 'optionalCall', _545 => _545(id)]);
11547
+ _optionalChain([caf, 'optionalCall', _616 => _616(id)]);
11258
11548
  };
11259
11549
  }
11260
11550
  function drawWaterOverlay(controller, ctx) {
@@ -11482,9 +11772,9 @@ function createPaintEffectsToolProvider(controller, options = {}) {
11482
11772
  time: { type: "number", minimum: 0, description: "Which moment of an animated effect to paint with, in ms (default 0)." },
11483
11773
  map: {
11484
11774
  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).",
11775
+ 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
11776
  properties: {
11487
- by: { type: "string", enum: ["canvas", "stroke"], description: "canvas (default) or stroke." },
11777
+ 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
11778
  length: { type: "number", minimum: 16, maximum: 4096, description: "by stroke: px of stroke per repeat of the effect (default 300)." },
11489
11779
  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
11780
  },
@@ -11612,7 +11902,7 @@ function createPaintChangeFeed(controller, options = {}) {
11612
11902
  const doc = state.document;
11613
11903
  const layers = /* @__PURE__ */ new Map();
11614
11904
  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 };
11905
+ return { doc, strokes: new Map(doc.strokes.map((s) => [s.id, s])), events: _nullishCoalesce(_optionalChain([doc, 'access', _617 => _617.paintEvents, 'optionalAccess', _618 => _618.length]), () => ( 0)), layers, stroking: state.stroking };
11616
11906
  };
11617
11907
  let last = take();
11618
11908
  const check = () => {
@@ -11643,7 +11933,7 @@ function createPaintChangeFeed(controller, options = {}) {
11643
11933
  if (edited) pending = void 0;
11644
11934
  const change = {
11645
11935
  seq: ++seq,
11646
- origin: _nullishCoalesce(_optionalChain([commit, 'optionalAccess', _548 => _548.origin]), () => ( "user")),
11936
+ origin: _nullishCoalesce(_optionalChain([commit, 'optionalAccess', _619 => _619.origin]), () => ( "user")),
11647
11937
  ...commit ? { commit } : {},
11648
11938
  addedStrokes,
11649
11939
  removedStrokes,
@@ -11710,7 +12000,7 @@ function createPaintProposals(options) {
11710
12000
  };
11711
12001
  const strokeIds = () => new Set(controller.getStrokes().map((s) => s.id));
11712
12002
  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.");
12003
+ if (!_optionalChain([input, 'access', _620 => _620.title, 'optionalAccess', _621 => _621.trim, 'call', _622 => _622()])) throw new PaintEditorError("A proposal needs a title: what it adds, in a few words.");
11714
12004
  if (!Array.isArray(input.ops) || !input.ops.length) throw new PaintEditorError("A proposal needs at least one op (stroke, wash or echo).");
11715
12005
  const place = _nullishCoalesce(input.place, () => ( "top"));
11716
12006
  if (place === "above") {
@@ -11722,7 +12012,7 @@ function createPaintProposals(options) {
11722
12012
  input.ops.forEach((op, i) => {
11723
12013
  const at = `ops[${i}]`;
11724
12014
  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.`);
12015
+ if (!_optionalChain([op, 'access', _623 => _623.points, 'optionalAccess', _624 => _624.length])) throw new PaintEditorError(`${at}: a stroke needs points in document pixels.`);
11726
12016
  points += op.points.length;
11727
12017
  if (op.color !== void 0 && !HEX3.test(op.color)) throw new PaintEditorError(`${at}: color "${op.color}" is not #rrggbb.`);
11728
12018
  const brush = op.brushId ? controller.getBrush(op.brushId) : controller.getState().brush;
@@ -11734,7 +12024,7 @@ function createPaintProposals(options) {
11734
12024
  if (!HEX3.test(_nullishCoalesce(op.color, () => ( "")))) throw new PaintEditorError(`${at}: a wash needs color as #rrggbb.`);
11735
12025
  if (op.opacity !== void 0 && !(op.opacity > 0 && op.opacity <= 1)) throw new PaintEditorError(`${at}: opacity must be in (0, 1].`);
11736
12026
  } 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).`);
12027
+ if (!_optionalChain([op, 'access', _625 => _625.strokeIds, 'optionalAccess', _626 => _626.length])) throw new PaintEditorError(`${at}: an echo needs strokeIds (list_strokes).`);
11738
12028
  const unknown = op.strokeIds.filter((id) => !known.has(id));
11739
12029
  if (unknown.length) throw new PaintEditorError(`${at}: unknown stroke ${unknown.map((u) => `"${u}"`).join(", ")}. Call list_strokes for the ids.`);
11740
12030
  if (op.color !== void 0 && !HEX3.test(op.color)) throw new PaintEditorError(`${at}: color "${op.color}" is not #rrggbb.`);
@@ -11783,7 +12073,7 @@ function createPaintProposals(options) {
11783
12073
  ...input.layerId ? { layerId: input.layerId } : {},
11784
12074
  ...input.layerName ? { layerName: input.layerName } : {}
11785
12075
  });
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]);
12076
+ const topLayerId = () => _optionalChain([controller, 'access', _627 => _627.listLayers, 'call', _628 => _628(), 'access', _629 => _629.find, 'call', _630 => _630((l) => l.parentId === null), 'optionalAccess', _631 => _631.id]);
11787
12077
  return {
11788
12078
  getState: () => state,
11789
12079
  subscribe(listener) {
@@ -11970,7 +12260,7 @@ function createPaintProposalToolProvider(proposals, options = {}) {
11970
12260
  },
11971
12261
  annotations: { title: "Propose paint", ...WRITE6 },
11972
12262
  handler: (args, context) => {
11973
- const origin = _optionalChain([context, 'access', _561 => _561.actor, 'optionalAccess', _562 => _562.id]) ? `agent:${context.actor.id}` : options.fallbackOrigin;
12263
+ const origin = _optionalChain([context, 'access', _632 => _632.actor, 'optionalAccess', _633 => _633.id]) ? `agent:${context.actor.id}` : options.fallbackOrigin;
11974
12264
  const proposal = proposals.propose({ ...args, ...origin ? { origin } : {} });
11975
12265
  const { id: _id, missing: _missing, createdAt: _createdAt, ...rest } = describe(proposal);
11976
12266
  return { proposalId: proposal.id, ...rest };
@@ -12092,7 +12382,7 @@ function toolList(provider) {
12092
12382
  function uiTables() {
12093
12383
  return {
12094
12384
  tools: PAINT_TOOLS,
12095
- brushOptions: _chunk4NMPUJUKcjs.BRUSH_OPTION_CONTROLS,
12385
+ brushOptions: _chunkDDL3ZBHKcjs.BRUSH_OPTION_CONTROLS,
12096
12386
  blendMenu: BLEND_MENU_GROUPS,
12097
12387
  layerEffects: _chunkPVJMTLPJcjs.LAYER_EFFECT_MENU.map(({ kind, label }) => ({ kind, label, controls: _chunkPVJMTLPJcjs.layerEffectControls.call(void 0, _chunkPVJMTLPJcjs.defaultLayerEffect.call(void 0, kind, kind)) })),
12098
12388
  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 },
@@ -12525,4 +12815,8 @@ function createPaintConformanceHost(setup, options) {
12525
12815
 
12526
12816
 
12527
12817
 
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;
12818
+
12819
+
12820
+
12821
+
12822
+ 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 = _chunkJJ2H25JGcjs.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 = _chunkJJ2H25JGcjs.DryStroke; exports.EFFECT_MAP_REPEATS = _chunkJJ2H25JGcjs.EFFECT_MAP_REPEATS; exports.EFFECT_STRIP_HEIGHT = _chunkJJ2H25JGcjs.EFFECT_STRIP_HEIGHT; exports.GPU_LEAD = _chunkJJ2H25JGcjs.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 = _chunkJJ2H25JGcjs.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_EFFECT_PATH_POINTS = _chunkJJ2H25JGcjs.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 = _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 = _chunkJJ2H25JGcjs.PAPER_FAMILIES; exports.PAPER_LIBRARY = _chunkJJ2H25JGcjs.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 = _chunkJJ2H25JGcjs.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 = _chunkJJ2H25JGcjs.PaintWetLayers; exports.PaperGrain = _chunkNIBFKXMDcjs.PaperGrain; exports.ParticleStroke = ParticleStroke; exports.PenDabWalker = _chunkJJ2H25JGcjs.PenDabWalker; exports.PenSmoother = _chunkJJ2H25JGcjs.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 = _chunkJJ2H25JGcjs.TipGrain; exports.WET_FLOW_KINDS = _chunkJ5VQYK7Tcjs.WET_FLOW_KINDS; exports.WET_GPU_MODES = _chunkJJ2H25JGcjs.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 = _chunkJJ2H25JGcjs.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 = _chunkJJ2H25JGcjs.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 = _chunkJJ2H25JGcjs.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 = _chunkJJ2H25JGcjs.effectDabField; exports.effectLayersToJSON = effectLayersToJSON; exports.effectPaintKey = _chunkJJ2H25JGcjs.effectPaintKey; exports.effectPaintSize = _chunkJJ2H25JGcjs.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 = _chunkJJ2H25JGcjs.hexToRgb8; exports.hslToRgb = hslToRgb; exports.hsvToRgb = hsvToRgb; exports.hueToWheel = _chunkI3Y2Q3PMcjs.hueToWheel; exports.inferEffectPathControl = _chunkJJ2H25JGcjs.inferEffectPathControl; exports.invertAffine = invertAffine; exports.isBlendMode = _chunk2VX55NFMcjs.isBlendMode; exports.isGradientPaint = _chunkNIBFKXMDcjs.isGradientPaint; exports.isPaintEffectPaint = _chunkJJ2H25JGcjs.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 = _chunkJJ2H25JGcjs.mixerTip; exports.multiColorForDab = _chunkJJ2H25JGcjs.multiColorForDab; exports.multiColorGradient = _chunkJJ2H25JGcjs.multiColorGradient; exports.multiColorPalette = _chunkJJ2H25JGcjs.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 = _chunkJJ2H25JGcjs.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 = _chunkJJ2H25JGcjs.paperPreset; exports.parseBrushLibrary = _chunkEU2ZZA6Lcjs.parseBrushLibrary; exports.parseHexColor = parseHexColor; exports.parsePaintSource = _chunkNIBFKXMDcjs.parsePaintSource; exports.patchBrushValue = _chunk3KNQ2W6Xcjs.patchBrushValue; exports.patchPath = patchPath; exports.penOrientation = _chunkJJ2H25JGcjs.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 = _chunkJJ2H25JGcjs.readEffectStrokeMap; exports.readPaintEffectPaint = _chunkJJ2H25JGcjs.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 = _chunkJJ2H25JGcjs.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 = _chunkJJ2H25JGcjs.sampleEffectAt; exports.sampleEffectField = _chunkJJ2H25JGcjs.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 = _chunkJJ2H25JGcjs.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 = _chunkJJ2H25JGcjs.tiltToOrientation; exports.timeLapseVideo = timeLapseVideo; exports.timeLapseZip = timeLapseZip; exports.toStrokePoint = _chunkJJ2H25JGcjs.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 = _chunkJJ2H25JGcjs.wetPaperInput; exports.wetPigmentOf = _chunkJJ2H25JGcjs.wetPigmentOf; exports.wetSupport = _chunkJ5VQYK7Tcjs.wetSupport; exports.wheelAngle = wheelAngle; exports.wheelPick = wheelPick; exports.wheelPoint = wheelPoint; exports.wheelToHue = _chunkI3Y2Q3PMcjs.wheelToHue; exports.withPaintPlayback = withPaintPlayback; exports.withStrokePath = _chunkJJ2H25JGcjs.withStrokePath;