@pixerate/editor 0.240.0 → 0.242.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 (67) hide show
  1. package/dist/animation-editor/controller.d.cts +10 -0
  2. package/dist/animation-editor/controller.d.ts +10 -0
  3. package/dist/animation-editor/effects.d.cts +1 -1
  4. package/dist/animation-editor/effects.d.ts +1 -1
  5. package/dist/animation-editor/index.cjs +195 -146
  6. package/dist/animation-editor/index.js +63 -14
  7. package/dist/{brushstrokeRender-WB67GMUP.js → brushstrokeRender-MOYGEXOC.js} +2 -2
  8. package/dist/{brushstrokeRender-MPOM7BFW.cjs → brushstrokeRender-UKADOV5D.cjs} +5 -5
  9. package/dist/canvas/index.cjs +15 -15
  10. package/dist/canvas/index.js +2 -2
  11. package/dist/{chunk-NKTNLJUJ.cjs → chunk-5BR7LC24.cjs} +99 -11
  12. package/dist/{chunk-ZXNO3ZOX.cjs → chunk-7F4G74UQ.cjs} +35 -35
  13. package/dist/{chunk-A7PQNIBX.cjs → chunk-7V7QMFTI.cjs} +14 -14
  14. package/dist/{chunk-AD7GA3TL.cjs → chunk-AFLMXITL.cjs} +23 -23
  15. package/dist/{chunk-JAOSL334.cjs → chunk-GHCSC2WP.cjs} +38 -16
  16. package/dist/{chunk-PP6BXVRL.cjs → chunk-HGGJ36HR.cjs} +1 -1
  17. package/dist/{chunk-BBUE3UJL.cjs → chunk-HW72ABGR.cjs} +86 -86
  18. package/dist/{chunk-7YGBSFC6.js → chunk-ILM6GYAX.js} +1 -1
  19. package/dist/{chunk-JWCKJNDR.cjs → chunk-K5DS2JTA.cjs} +6 -6
  20. package/dist/{chunk-THXFU3JB.cjs → chunk-KCMV2534.cjs} +2 -2
  21. package/dist/{chunk-WDDUPWVG.js → chunk-L3JFOTBQ.js} +1 -1
  22. package/dist/{chunk-3E36VDMJ.js → chunk-NE6OOKWJ.js} +1 -1
  23. package/dist/{chunk-SIK3LT6M.js → chunk-OFH6Q67U.js} +28 -6
  24. package/dist/{chunk-RV5DKZHU.js → chunk-QP2B3MID.js} +1 -1
  25. package/dist/{chunk-G3RUKJ5C.js → chunk-RXZL4NG5.js} +1 -1
  26. package/dist/{chunk-UUBO6RB5.js → chunk-UDBDYZET.js} +1 -1
  27. package/dist/{chunk-TEFQISBY.js → chunk-X3ZINLIP.js} +1 -1
  28. package/dist/{chunk-PJYG6FCF.js → chunk-XBZK47LV.js} +98 -10
  29. package/dist/{chunk-ZQIWBJGH.cjs → chunk-XNZFVYC2.cjs} +7 -7
  30. package/dist/{chunk-XK4SST43.js → chunk-ZDPLZDTT.js} +1 -1
  31. package/dist/effects/fake.d.cts +4 -0
  32. package/dist/effects/fake.d.ts +4 -0
  33. package/dist/effects/helpers.d.cts +6 -0
  34. package/dist/effects/helpers.d.ts +6 -0
  35. package/dist/effects/index.cjs +222 -94
  36. package/dist/effects/index.js +131 -3
  37. package/dist/effects/types.d.cts +31 -0
  38. package/dist/effects/types.d.ts +31 -0
  39. package/dist/image-editor/index.cjs +788 -788
  40. package/dist/image-editor/index.js +5 -5
  41. package/dist/paint-editor/controller.d.cts +67 -0
  42. package/dist/paint-editor/controller.d.ts +67 -0
  43. package/dist/paint-editor/effect-paint.d.cts +60 -3
  44. package/dist/paint-editor/effect-paint.d.ts +60 -3
  45. package/dist/paint-editor/index.cjs +682 -436
  46. package/dist/paint-editor/index.js +284 -38
  47. package/dist/paint-editor/stickers.d.cts +6 -0
  48. package/dist/paint-editor/stickers.d.ts +6 -0
  49. package/dist/paint-editor/thick.d.cts +4 -0
  50. package/dist/paint-editor/thick.d.ts +4 -0
  51. package/dist/paint-editor/wet.d.cts +8 -0
  52. package/dist/paint-editor/wet.d.ts +8 -0
  53. package/dist/vector/index.cjs +968 -968
  54. package/dist/vector/index.js +5 -5
  55. package/dist/video-editor/controller.d.cts +49 -1
  56. package/dist/video-editor/controller.d.ts +49 -1
  57. package/dist/video-editor/effect-path.d.cts +66 -0
  58. package/dist/video-editor/effect-path.d.ts +66 -0
  59. package/dist/video-editor/index.cjs +616 -427
  60. package/dist/video-editor/index.d.cts +1 -0
  61. package/dist/video-editor/index.d.ts +1 -0
  62. package/dist/video-editor/index.js +193 -4
  63. package/package.json +1 -1
  64. package/skills/pixerate-animation-editor/SKILL.md +1 -1
  65. package/skills/pixerate-paint-editor/SKILL.md +17 -21
  66. package/skills/pixerate-paint-editor/references/effect-paint.md +25 -0
  67. package/skills/pixerate-video-editor/SKILL.md +9 -2
@@ -1,13 +1,13 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4; var _class5; var _class6; var _class7; var _class8; var _class9; var _class10; var _class11; var _class12;
2
2
 
3
- var _chunkZQIWBJGHcjs = require('../chunk-ZQIWBJGH.cjs');
3
+ var _chunkXNZFVYC2cjs = require('../chunk-XNZFVYC2.cjs');
4
4
 
5
5
 
6
6
 
7
7
 
8
8
 
9
9
 
10
- var _chunkBBUE3UJLcjs = require('../chunk-BBUE3UJL.cjs');
10
+ var _chunkHW72ABGRcjs = require('../chunk-HW72ABGR.cjs');
11
11
  require('../chunk-A2IS7EHE.cjs');
12
12
  require('../chunk-SS53NNZO.cjs');
13
13
 
@@ -55,7 +55,7 @@ var _chunkJLWLX52Lcjs = require('../chunk-JLWLX52L.cjs');
55
55
 
56
56
 
57
57
  var _chunkK7ENM55Pcjs = require('../chunk-K7ENM55P.cjs');
58
- require('../chunk-THXFU3JB.cjs');
58
+ require('../chunk-KCMV2534.cjs');
59
59
 
60
60
 
61
61
 
@@ -126,7 +126,12 @@ require('../chunk-THXFU3JB.cjs');
126
126
 
127
127
 
128
128
 
129
- var _chunkNKTNLJUJcjs = require('../chunk-NKTNLJUJ.cjs');
129
+
130
+
131
+
132
+
133
+
134
+ var _chunk5BR7LC24cjs = require('../chunk-5BR7LC24.cjs');
130
135
  require('../chunk-CVFAAZXE.cjs');
131
136
  require('../chunk-GF2RBSDM.cjs');
132
137
  require('../chunk-NM3G4VQT.cjs');
@@ -138,7 +143,7 @@ var _chunkPY4GWSE2cjs = require('../chunk-PY4GWSE2.cjs');
138
143
 
139
144
 
140
145
 
141
- var _chunkJAOSL334cjs = require('../chunk-JAOSL334.cjs');
146
+ var _chunkGHCSC2WPcjs = require('../chunk-GHCSC2WP.cjs');
142
147
  require('../chunk-WOFXZ3XU.cjs');
143
148
 
144
149
 
@@ -285,7 +290,7 @@ function normalizeCanvas(raw) {
285
290
  function createPaintDocument(options = {}) {
286
291
  const canvas = normalizeCanvas({ width: _nullishCoalesce(options.width, () => ( 2048)), height: _nullishCoalesce(options.height, () => ( 1536)), dpi: options.dpi });
287
292
  const layer = createPaintLayer("Layer 1");
288
- return { canvas, paper: _chunkNKTNLJUJcjs.normalizePaper.call(void 0, _nullishCoalesce(options.paper, () => ( {}))), layers: [layer], activeLayerId: layer.id, strokes: [] };
293
+ return { canvas, paper: _chunk5BR7LC24cjs.normalizePaper.call(void 0, _nullishCoalesce(options.paper, () => ( {}))), layers: [layer], activeLayerId: layer.id, strokes: [] };
289
294
  }
290
295
 
291
296
  // src/paint-editor/dab-stroke.ts
@@ -339,13 +344,13 @@ var PaintDabStroke = (_class = class {
339
344
  constructor(brush, options) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);_class.prototype.__init4.call(this);_class.prototype.__init5.call(this);_class.prototype.__init6.call(this);_class.prototype.__init7.call(this);_class.prototype.__init8.call(this);_class.prototype.__init9.call(this);_class.prototype.__init10.call(this);
340
345
  this.brush = brush;
341
346
  this.options = options;
342
- this.smoother = new (0, _chunkNKTNLJUJcjs.PenSmoother)(brush.tip.smoothing, brush.pressureSmoothing);
343
- this.copies = _optionalChain([options, 'access', _2 => _2.copies, 'optionalAccess', _3 => _3.length]) ? options.copies : [_chunkNKTNLJUJcjs.IDENTITY_COPY];
347
+ this.smoother = new (0, _chunk5BR7LC24cjs.PenSmoother)(brush.tip.smoothing, brush.pressureSmoothing);
348
+ this.copies = _optionalChain([options, 'access', _2 => _2.copies, 'optionalAccess', _3 => _3.length]) ? options.copies : [_chunk5BR7LC24cjs.IDENTITY_COPY];
344
349
  const exchanging = brush.engine === "mixer" || brush.engine === "dab";
345
350
  const rates = brush.engine === "mixer" ? _chunkPQ3H2AANcjs.mixerRates.call(void 0, brush.mixer) : _chunkPQ3H2AANcjs.exchangeRates.call(void 0, brush.behavior.pickup, brush.behavior.mix, 1, brush.behavior.mixing);
346
351
  this.mixing = brush.engine === "mixer" ? brush.mixer.mixing : brush.behavior.mixing;
347
352
  this.states = this.copies.map((c, i) => ({
348
- walker: new (0, _chunkNKTNLJUJcjs.PenDabWalker)(brush, (_nullishCoalesce(options.seed, () => ( 0))) + i * 7919 | 0, c.linear),
353
+ walker: new (0, _chunk5BR7LC24cjs.PenDabWalker)(brush, (_nullishCoalesce(options.seed, () => ( 0))) + i * 7919 | 0, c.linear),
349
354
  exchange: exchanging ? new (0, _chunkPQ3H2AANcjs.PaintExchange)(rates, options.load) : null,
350
355
  smudge: brush.engine === "smudge" ? new (0, _chunkPQ3H2AANcjs.SmudgeTip)(brush.smudge, brush.tip.size * (1 + brush.dynamics.tiltSize * 1.5)) : null
351
356
  }));
@@ -458,7 +463,7 @@ var PaintDabStroke = (_class = class {
458
463
  let flow = 1;
459
464
  if (this.options.effect) {
460
465
  const rgb = [0, 0, 0];
461
- flow = _chunkNKTNLJUJcjs.sampleEffectAt.call(void 0, this.options.effect, d.x, d.y, rgb);
466
+ flow = _chunk5BR7LC24cjs.sampleEffectAt.call(void 0, this.options.effect, d.x, d.y, rgb, d);
462
467
  ex.setReservoirColor(rgb[0], rgb[1], rgb[2]);
463
468
  } else if (this.sampler && !this.gradient) {
464
469
  const g = this.sampler.dab(d, this.sample);
@@ -686,15 +691,15 @@ function expand(t, channels) {
686
691
  return out;
687
692
  }
688
693
  var ThickStrokeDriver = (_class3 = class {
689
- constructor(init) {;_class3.prototype.__init12.call(this);_class3.prototype.__init13.call(this);_class3.prototype.__init14.call(this);_class3.prototype.__init15.call(this);_class3.prototype.__init16.call(this);_class3.prototype.__init17.call(this);_class3.prototype.__init18.call(this);_class3.prototype.__init19.call(this);_class3.prototype.__init20.call(this);
694
+ constructor(init) {;_class3.prototype.__init12.call(this);_class3.prototype.__init13.call(this);_class3.prototype.__init14.call(this);_class3.prototype.__init15.call(this);_class3.prototype.__init16.call(this);_class3.prototype.__init17.call(this);_class3.prototype.__init18.call(this);_class3.prototype.__init19.call(this);_class3.prototype.__init20.call(this);_class3.prototype.__init21.call(this);
690
695
  this.init = init;
691
696
  const b = init.brush;
692
- this.smoother = new (0, _chunkNKTNLJUJcjs.PenSmoother)(b.tip.smoothing, b.pressureSmoothing);
693
- const copies = init.copies.length ? init.copies : [_chunkNKTNLJUJcjs.IDENTITY_COPY];
697
+ this.smoother = new (0, _chunk5BR7LC24cjs.PenSmoother)(b.tip.smoothing, b.pressureSmoothing);
698
+ const copies = init.copies.length ? init.copies : [_chunk5BR7LC24cjs.IDENTITY_COPY];
694
699
  this.copies = copies;
695
700
  const rates = _chunkPQ3H2AANcjs.exchangeRates.call(void 0, b.behavior.pickup, b.behavior.mix, 1, b.behavior.mixing);
696
701
  this.states = copies.map((c, i) => ({
697
- walker: new (0, _chunkNKTNLJUJcjs.PenDabWalker)(b, init.seed + i * 7919 | 0, c.linear),
702
+ walker: new (0, _chunk5BR7LC24cjs.PenDabWalker)(b, init.seed + i * 7919 | 0, c.linear),
698
703
  exchange: new (0, _chunkPQ3H2AANcjs.PaintExchange)(rates, init.load),
699
704
  smudge: b.impasto.tool === "knife" ? new (0, _chunkPQ3H2AANcjs.SmudgeTip)({ strength: 0.85, length: 0.6 + 0.38 * b.impasto.drag, mixing: b.behavior.mixing }, b.tip.size * 1.2) : null,
700
705
  carried: null,
@@ -711,13 +716,14 @@ var ThickStrokeDriver = (_class3 = class {
711
716
  __init13() {this.height = /* @__PURE__ */ new Map()}
712
717
  __init14() {this.material = /* @__PURE__ */ new Map()}
713
718
  __init15() {this.paint = [0, 0, 0]}
714
- __init16() {this.tip = new Float32Array(0)}
715
- __init17() {this.lastRaw = null}
716
- __init18() {this.lastFed = null}
717
- __init19() {this.version = 0}
719
+ __init16() {this.centre = [0, 0, 0]}
720
+ __init17() {this.tip = new Float32Array(0)}
721
+ __init18() {this.lastRaw = null}
722
+ __init19() {this.lastFed = null}
723
+ __init20() {this.version = 0}
718
724
 
719
725
 
720
- __init20() {this.sample = { rgb: [0, 0, 0], alpha: 1 }}
726
+ __init21() {this.sample = { rgb: [0, 0, 0], alpha: 1 }}
721
727
  /** What copy 0 carries after the dabs so far. */
722
728
  get load() {
723
729
  return this.states[0].exchange.load;
@@ -837,7 +843,11 @@ var ThickStrokeDriver = (_class3 = class {
837
843
  }
838
844
  const ex = st.exchange;
839
845
  let flow = 1;
840
- if (this.sampler) {
846
+ const effect = this.init.effect;
847
+ if (effect) {
848
+ _chunk5BR7LC24cjs.sampleEffectAt.call(void 0, effect, d.x, d.y, this.centre, d);
849
+ ex.setReservoirColor(this.centre[0], this.centre[1], this.centre[2]);
850
+ } else if (this.sampler) {
841
851
  const g = this.sampler.dab(d, this.sample);
842
852
  ex.setReservoirColor(g.rgb[0], g.rgb[1], g.rgb[2]);
843
853
  flow = g.alpha;
@@ -849,7 +859,12 @@ var ThickStrokeDriver = (_class3 = class {
849
859
  if (dep > 0) {
850
860
  const cov = new Float32Array(n);
851
861
  for (let p = 0; p < n; p++) cov[p] = tip[p] > 0 ? Math.min(1, tip[p] * (im.tool === "roller" || im.tool === "gloop" || im.tool === "tube" ? 1.6 : 1.1)) : 0;
852
- this.medium.deposit(rect, cov, dep, this.paint, ex.paintPigment);
862
+ let field = null;
863
+ if (effect) {
864
+ field = new Float32Array(n * 3);
865
+ _chunk5BR7LC24cjs.effectDabField.call(void 0, effect, rect, cov, this.centre, this.paint, field, 0, d);
866
+ }
867
+ this.medium.deposit(rect, cov, dep, this.paint, ex.paintPigment, field);
853
868
  }
854
869
  const seed = this.init.seed;
855
870
  for (let yy = 0, p = 0; yy < rect.height; yy++) {
@@ -986,17 +1001,16 @@ function union(a, b) {
986
1001
  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 };
987
1002
  }
988
1003
  var PaintStrokeSession = (_class4 = class {
989
- constructor(host, init) {;_class4.prototype.__init21.call(this);_class4.prototype.__init22.call(this);_class4.prototype.__init23.call(this);_class4.prototype.__init24.call(this);_class4.prototype.__init25.call(this);_class4.prototype.__init26.call(this);_class4.prototype.__init27.call(this);_class4.prototype.__init28.call(this);_class4.prototype.__init29.call(this);_class4.prototype.__init30.call(this);_class4.prototype.__init31.call(this);_class4.prototype.__init32.call(this);_class4.prototype.__init33.call(this);_class4.prototype.__init34.call(this);
1004
+ constructor(host, init) {;_class4.prototype.__init22.call(this);_class4.prototype.__init23.call(this);_class4.prototype.__init24.call(this);_class4.prototype.__init25.call(this);_class4.prototype.__init26.call(this);_class4.prototype.__init27.call(this);_class4.prototype.__init28.call(this);_class4.prototype.__init29.call(this);_class4.prototype.__init30.call(this);_class4.prototype.__init31.call(this);_class4.prototype.__init32.call(this);_class4.prototype.__init33.call(this);_class4.prototype.__init34.call(this);_class4.prototype.__init35.call(this);
990
1005
  this.host = host;
991
1006
  this.init = init;
992
1007
  this.layerId = init.layerId;
993
1008
  this.base = init.surface;
994
1009
  this.live = new Map(this.base.tiles);
995
- this.copies = init.copies.length ? init.copies : [_chunkNKTNLJUJcjs.IDENTITY_COPY];
1010
+ this.copies = init.copies.length ? init.copies : [_chunk5BR7LC24cjs.IDENTITY_COPY];
996
1011
  const brush = init.brush;
997
1012
  if (init.wet) this.wetDriver = init.wet.driver;
998
1013
  const effect = _nullishCoalesce(_optionalChain([init, 'access', _15 => _15.effect, 'optionalAccess', _16 => _16.pixels]), () => ( null));
999
- if (effect && (init.wet || init.thick || init.sticker)) throw new Error(`The ${brush.name} brush (${brush.engine} engine) cannot paint with effect paint.`);
1000
1014
  this.apply = {
1001
1015
  mode: brush.engine === "eraser" ? "erase" : "paint",
1002
1016
  color: init.color,
@@ -1009,11 +1023,11 @@ var PaintStrokeSession = (_class4 = class {
1009
1023
  };
1010
1024
  if (this.wetDriver) {
1011
1025
  } else if (init.sticker) {
1012
- this.stickerSpray = new (0, _chunkNKTNLJUJcjs.StickerSpray)({ brush, target: this.tileTarget(), color: init.colorHex, seed: init.seed, copies: this.copies, nextId: init.sticker.nextId, paint: _nullishCoalesce(init.paint, () => ( null)) });
1026
+ this.stickerSpray = new (0, _chunk5BR7LC24cjs.StickerSpray)({ brush, target: this.tileTarget(), color: init.colorHex, seed: init.seed, copies: this.copies, nextId: init.sticker.nextId, paint: _nullishCoalesce(init.paint, () => ( null)), effect });
1013
1027
  } else if (init.thick) {
1014
1028
  const rgb = (c) => [c[0] / 255, c[1] / 255, c[2] / 255];
1015
- 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)) });
1016
- } else if (brush.engine === "mixer" || brush.engine === "blender" || brush.engine === "smudge" || _chunkNKTNLJUJcjs.usesPaintExchange.call(void 0, brush, Boolean(init.paint))) {
1029
+ 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 });
1030
+ } else if (brush.engine === "mixer" || brush.engine === "blender" || brush.engine === "smudge" || _chunk5BR7LC24cjs.usesPaintExchange.call(void 0, brush, Boolean(init.paint))) {
1017
1031
  const rgb = (c) => [c[0] / 255, c[1] / 255, c[2] / 255];
1018
1032
  this.wet = new PaintDabStroke(brush, {
1019
1033
  target: this.tileTarget(),
@@ -1029,33 +1043,33 @@ var PaintStrokeSession = (_class4 = class {
1029
1043
  });
1030
1044
  } else {
1031
1045
  const opts = { grain: init.grain, paperDepth: init.paperDepth, seed: init.seed, copies: this.copies, paint: _nullishCoalesce(init.paint, () => ( null)), effect };
1032
- this.dry = brush.engine === "particle" ? new (0, _chunkNKTNLJUJcjs.ParticleStroke)(brush, opts) : brush.engine === "bristle" ? new (0, _chunkNKTNLJUJcjs.BristleStroke)(brush, opts) : new (0, _chunkNKTNLJUJcjs.DryStroke)(brush, opts);
1046
+ this.dry = brush.engine === "particle" ? new (0, _chunk5BR7LC24cjs.ParticleStroke)(brush, opts) : brush.engine === "bristle" ? new (0, _chunk5BR7LC24cjs.BristleStroke)(brush, opts) : new (0, _chunk5BR7LC24cjs.DryStroke)(brush, opts);
1033
1047
  }
1034
1048
  }
1035
1049
 
1036
1050
 
1037
1051
 
1038
1052
  /** The raw input so far (what a replay feeds back in). */
1039
- __init21() {this.points = []}
1053
+ __init22() {this.points = []}
1040
1054
 
1041
1055
 
1042
- __init22() {this.touched = /* @__PURE__ */ new Set()}
1043
- __init23() {this.fresh = /* @__PURE__ */ new Set()}
1044
- __init24() {this.dry = null}
1045
- __init25() {this.wet = null}
1046
- __init26() {this.wetDriver = null}
1047
- __init27() {this.thickDriver = null}
1048
- __init28() {this.stickerSpray = null}
1056
+ __init23() {this.touched = /* @__PURE__ */ new Set()}
1057
+ __init24() {this.fresh = /* @__PURE__ */ new Set()}
1058
+ __init25() {this.dry = null}
1059
+ __init26() {this.wet = null}
1060
+ __init27() {this.wetDriver = null}
1061
+ __init28() {this.thickDriver = null}
1062
+ __init29() {this.stickerSpray = null}
1049
1063
  /** A wet stroke that ended while the simulation was mid-batch: it commits when the driver catches up. */
1050
- __init29() {this.wetEndPending = false}
1064
+ __init30() {this.wetEndPending = false}
1051
1065
 
1052
1066
 
1053
- __init30() {this.bounds = null}
1054
- __init31() {this.lastRaw = null}
1055
- __init32() {this.closed = false}
1056
- __init33() {this.result = null}
1067
+ __init31() {this.bounds = null}
1068
+ __init32() {this.lastRaw = null}
1069
+ __init33() {this.closed = false}
1070
+ __init34() {this.result = null}
1057
1071
  /** The mask stencils this stroke was painted with when they are not the editor's (replays). */
1058
- __init34() {this.maskStencils = null}
1072
+ __init35() {this.maskStencils = null}
1059
1073
  tileTarget() {
1060
1074
  return {
1061
1075
  offset: this.init.offset,
@@ -1200,7 +1214,7 @@ function brushLoadForStroke(brush, current, color) {
1200
1214
  if (brush.engine === "mixer") return mixerLoadForStroke(brush, current, color);
1201
1215
  if (brush.engine === "impasto") return { reservoir: [color[0], color[1], color[2]], amount: 1, pickup: brush.behavior.dirty ? current.pickup : null };
1202
1216
  if (brush.engine === "wet") return brush.wet.tool === "paint" ? { reservoir: [color[0], color[1], color[2]], amount: 1, pickup: brush.behavior.dirty ? current.pickup : null } : _chunkPQ3H2AANcjs.EMPTY_MIXER_LOAD;
1203
- if (_chunkNKTNLJUJcjs.usesPaintExchange.call(void 0, brush)) return { reservoir: [color[0], color[1], color[2]], amount: 1, pickup: brush.behavior.dirty ? current.pickup : null };
1217
+ if (_chunk5BR7LC24cjs.usesPaintExchange.call(void 0, brush)) return { reservoir: [color[0], color[1], color[2]], amount: 1, pickup: brush.behavior.dirty ? current.pickup : null };
1204
1218
  return _chunkPQ3H2AANcjs.EMPTY_MIXER_LOAD;
1205
1219
  }
1206
1220
 
@@ -1468,7 +1482,7 @@ function normalizeBrushStroke(raw) {
1468
1482
  const out = {
1469
1483
  id: r.id,
1470
1484
  layerId: r.layerId,
1471
- brush: _chunkNKTNLJUJcjs.normalizePaintBrush.call(void 0, _nullishCoalesce(r.brush, () => ( {}))),
1485
+ brush: _chunk5BR7LC24cjs.normalizePaintBrush.call(void 0, _nullishCoalesce(r.brush, () => ( {}))),
1472
1486
  color: typeof r.color === "string" && /^#[0-9a-f]{6}$/i.test(r.color) ? r.color.toLowerCase() : "#000000",
1473
1487
  points,
1474
1488
  seed: finite2(r.seed) ? r.seed | 0 : 0
@@ -1487,7 +1501,7 @@ function normalizeBrushStroke(raw) {
1487
1501
  }
1488
1502
  if (st.length) out.stencils = st;
1489
1503
  }
1490
- const effect = _chunkNKTNLJUJcjs.readPaintEffectPaint.call(void 0, r.paint);
1504
+ const effect = _chunk5BR7LC24cjs.readPaintEffectPaint.call(void 0, r.paint);
1491
1505
  const paint = effect ? null : _chunkPQ3H2AANcjs.readPaintSource.call(void 0, r.paint);
1492
1506
  if (effect) out.paint = effect;
1493
1507
  else if (paint && paint.type === "gradient") out.paint = paint;
@@ -1527,10 +1541,11 @@ function varyStroke(stroke, m, v) {
1527
1541
  if (ps !== 1) q.pressure = Math.min(1, Math.max(0, (_nullishCoalesce(p.pressure, () => ( 1))) * ps));
1528
1542
  return q;
1529
1543
  });
1530
- const brush = s !== 1 ? _chunkNKTNLJUJcjs.normalizePaintBrush.call(void 0, { ...stroke.brush, tip: { ...stroke.brush.tip, size: stroke.brush.tip.size * s } }) : stroke.brush;
1544
+ const brush = s !== 1 ? _chunk5BR7LC24cjs.normalizePaintBrush.call(void 0, { ...stroke.brush, tip: { ...stroke.brush.tip, size: stroke.brush.tip.size * s } }) : stroke.brush;
1531
1545
  const out = { ...stroke, brush, points };
1532
1546
  if (_optionalChain([stroke, 'access', _59 => _59.paint, 'optionalAccess', _60 => _60.type]) === "gradient" && s !== 1) out.paint = _chunkPQ3H2AANcjs.scalePaintGradient.call(void 0, stroke.paint, s);
1533
- if (_optionalChain([stroke, 'access', _61 => _61.copies, 'optionalAccess', _62 => _62.length])) {
1547
+ if (_optionalChain([stroke, 'access', _61 => _61.paint, 'optionalAccess', _62 => _62.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))) } };
1548
+ if (_optionalChain([stroke, 'access', _63 => _63.copies, 'optionalAccess', _64 => _64.length])) {
1534
1549
  const inv = invertAffine(m);
1535
1550
  out.copies = stroke.copies.map((c) => composeAffine(m, composeAffine(c, inv)));
1536
1551
  }
@@ -1549,7 +1564,7 @@ var paperNodes = /* @__PURE__ */ new WeakMap();
1549
1564
  function paperNode(paper, light) {
1550
1565
  let n = paperNodes.get(paper);
1551
1566
  const metal = (_nullishCoalesce(paper.metallic, () => ( 0))) > 0;
1552
- if (!n || metal && (_optionalChain([n, 'access', _63 => _63.light, 'optionalAccess', _64 => _64.azimuth]) !== _optionalChain([light, 'optionalAccess', _65 => _65.azimuth]) || _optionalChain([n, 'access', _66 => _66.light, 'optionalAccess', _67 => _67.elevation]) !== _optionalChain([light, 'optionalAccess', _68 => _68.elevation]))) {
1567
+ if (!n || metal && (_optionalChain([n, 'access', _65 => _65.light, 'optionalAccess', _66 => _66.azimuth]) !== _optionalChain([light, 'optionalAccess', _67 => _67.azimuth]) || _optionalChain([n, 'access', _68 => _68.light, 'optionalAccess', _69 => _69.elevation]) !== _optionalChain([light, 'optionalAccess', _70 => _70.elevation]))) {
1553
1568
  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 } } : {} };
1554
1569
  paperNodes.set(paper, n);
1555
1570
  }
@@ -1571,7 +1586,7 @@ function paperTile(paper, r, light) {
1571
1586
  const key = `${paperKey(paper, light)}|${r.x},${r.y},${r.width},${r.height}`;
1572
1587
  let t = tileCache.get(key);
1573
1588
  if (!t) {
1574
- t = _chunkNKTNLJUJcjs.renderPaper.call(void 0, paper, r, paperGrain(paper), light);
1589
+ t = _chunk5BR7LC24cjs.renderPaper.call(void 0, paper, r, paperGrain(paper), light);
1575
1590
  if (tileCache.size > 512) tileCache.delete(tileCache.keys().next().value);
1576
1591
  tileCache.set(key, t);
1577
1592
  }
@@ -1670,17 +1685,17 @@ function header(state, options) {
1670
1685
  if (options.swatches !== void 0) out.swatches = JSON.parse(JSON.stringify(options.swatches));
1671
1686
  if (options.mixingPad !== void 0) out.mixingPad = JSON.parse(JSON.stringify(options.mixingPad));
1672
1687
  if (options.wet !== void 0) out.wet = JSON.parse(JSON.stringify(options.wet));
1673
- if (_optionalChain([state, 'access', _69 => _69.wetEvents, 'optionalAccess', _70 => _70.length])) out.wetEvents = JSON.parse(JSON.stringify(state.wetEvents));
1674
- if (_optionalChain([state, 'access', _71 => _71.paintEvents, 'optionalAccess', _72 => _72.length])) out.paintEvents = JSON.parse(JSON.stringify(state.paintEvents));
1688
+ if (_optionalChain([state, 'access', _71 => _71.wetEvents, 'optionalAccess', _72 => _72.length])) out.wetEvents = JSON.parse(JSON.stringify(state.wetEvents));
1689
+ if (_optionalChain([state, 'access', _73 => _73.paintEvents, 'optionalAccess', _74 => _74.length])) out.paintEvents = JSON.parse(JSON.stringify(state.paintEvents));
1675
1690
  if (state.origin && (state.origin.x || state.origin.y)) out.origin = { ...state.origin };
1676
1691
  return out;
1677
1692
  }
1678
1693
  function serializePaintDocument(state, options = {}) {
1679
- const { layers, assets } = _chunkBBUE3UJLcjs.serializeLayers.call(void 0, state.layers);
1694
+ const { layers, assets } = _chunkHW72ABGRcjs.serializeLayers.call(void 0, state.layers);
1680
1695
  return { ...header(state, options), layers, assets };
1681
1696
  }
1682
1697
  async function serializePaintDocumentExternal(state, store, options = {}) {
1683
- const { layers, assets } = await _chunkBBUE3UJLcjs.serializeLayersExternal.call(void 0, state.layers, store);
1698
+ const { layers, assets } = await _chunkHW72ABGRcjs.serializeLayersExternal.call(void 0, state.layers, store);
1684
1699
  return { ...header(state, options), layers, assets };
1685
1700
  }
1686
1701
  function paintLayersOnly(layers, problems) {
@@ -1688,7 +1703,7 @@ function paintLayersOnly(layers, problems) {
1688
1703
  for (const l of layers) {
1689
1704
  if (l.type === "pixel") {
1690
1705
  const { filters, source, ...rest } = l;
1691
- if (_optionalChain([filters, 'optionalAccess', _73 => _73.length])) problems.push(`Layer "${l.name}": its filters are an image editor feature and were dropped.`);
1706
+ if (_optionalChain([filters, 'optionalAccess', _75 => _75.length])) problems.push(`Layer "${l.name}": its filters are an image editor feature and were dropped.`);
1692
1707
  if (source) problems.push(`Layer "${l.name}" refers to an image editor source image; it loads empty.`);
1693
1708
  out.push(rest);
1694
1709
  } else if (l.type === "group") out.push({ ...l, children: paintLayersOnly(l.children, problems) });
@@ -1715,11 +1730,11 @@ function deserializePaintDocument(raw) {
1715
1730
  }
1716
1731
  const problems = [];
1717
1732
  const canvas = normalizeCanvas({ width: r.width, height: r.height, dpi: _nullishCoalesce(r.dpi, () => ( void 0)) });
1718
- const paper = _chunkNKTNLJUJcjs.normalizePaper.call(void 0, _nullishCoalesce(r.paper, () => ( {})));
1733
+ const paper = _chunk5BR7LC24cjs.normalizePaper.call(void 0, _nullishCoalesce(r.paper, () => ( {})));
1719
1734
  const assets = r.assets && typeof r.assets === "object" ? r.assets : {};
1720
- const layers = paintLayersOnly(_chunkBBUE3UJLcjs.deserializeLayers.call(void 0, r.layers, { assets, problems }), problems);
1735
+ const layers = paintLayersOnly(_chunkHW72ABGRcjs.deserializeLayers.call(void 0, r.layers, { assets, problems }), problems);
1721
1736
  const wanted = typeof r.activeLayerId === "string" ? r.activeLayerId : null;
1722
- const activeLayerId = wanted && _chunkHB4ICNNAcjs.findLayer.call(void 0, layers, wanted) ? wanted : _nullishCoalesce(_optionalChain([_chunkHB4ICNNAcjs.flattenLayers.call(void 0, layers), 'access', _74 => _74.filter, 'call', _75 => _75((l) => l.type === "pixel"), 'access', _76 => _76.pop, 'call', _77 => _77(), 'optionalAccess', _78 => _78.id]), () => ( null));
1737
+ const activeLayerId = wanted && _chunkHB4ICNNAcjs.findLayer.call(void 0, layers, wanted) ? wanted : _nullishCoalesce(_optionalChain([_chunkHB4ICNNAcjs.flattenLayers.call(void 0, layers), 'access', _76 => _76.filter, 'call', _77 => _77((l) => l.type === "pixel"), 'access', _78 => _78.pop, 'call', _79 => _79(), 'optionalAccess', _80 => _80.id]), () => ( null));
1723
1738
  const wetEvents = Array.isArray(r.wetEvents) ? r.wetEvents.filter((e) => e && typeof e === "object" && Number.isInteger(e.clock) && typeof e.kind === "string") : [];
1724
1739
  const state = { canvas, paper, layers, activeLayerId, strokes: readStrokes(r.strokes, problems) };
1725
1740
  if (wetEvents.length) state.wetEvents = wetEvents;
@@ -1733,7 +1748,7 @@ async function deserializePaintDocumentAsync(raw, store) {
1733
1748
  if (!raw || typeof raw !== "object") throw new Error("Not a paint document: expected a JSON object.");
1734
1749
  const r = raw;
1735
1750
  const problems = [];
1736
- const assets = await _chunkBBUE3UJLcjs.resolveExternalAssets.call(void 0, _nullishCoalesce(r.assets, () => ( {})), store, problems);
1751
+ const assets = await _chunkHW72ABGRcjs.resolveExternalAssets.call(void 0, _nullishCoalesce(r.assets, () => ( {})), store, problems);
1737
1752
  const loaded = deserializePaintDocument({ ...r, assets });
1738
1753
  return { ...loaded, problems: [...problems, ...loaded.problems] };
1739
1754
  }
@@ -1816,7 +1831,7 @@ function pointerToPenPoint(e, x, y, view) {
1816
1831
  const p = { x, y, pressure: samplePressure(e) };
1817
1832
  if (typeof e.timeStamp === "number" && Number.isFinite(e.timeStamp)) p.t = e.timeStamp;
1818
1833
  if (e.pointerType !== "pen") return p;
1819
- const o = _chunkNKTNLJUJcjs.penOrientation.call(void 0, {
1834
+ const o = _chunk5BR7LC24cjs.penOrientation.call(void 0, {
1820
1835
  x,
1821
1836
  y,
1822
1837
  altitude: typeof e.altitudeAngle === "number" ? e.altitudeAngle : void 0,
@@ -1864,7 +1879,7 @@ async function decodeImageBlob(blob) {
1864
1879
  if (!ctx) throw new Error("No 2D context to decode with.");
1865
1880
  ctx.drawImage(bitmap, 0, 0);
1866
1881
  const data = new Uint8ClampedArray(ctx.getImageData(0, 0, bitmap.width, bitmap.height).data);
1867
- _optionalChain([bitmap, 'access', _79 => _79.close, 'optionalCall', _80 => _80()]);
1882
+ _optionalChain([bitmap, 'access', _81 => _81.close, 'optionalCall', _82 => _82()]);
1868
1883
  return { width: bitmap.width, height: bitmap.height, data };
1869
1884
  }
1870
1885
  function downloadBytes(bytes, fileName, mimeType) {
@@ -1895,16 +1910,16 @@ function wetPaperInput(paper) {
1895
1910
  absorption: paper.absorption,
1896
1911
  permeability: paper.permeability,
1897
1912
  roughness: flat ? 0 : paper.roughness,
1898
- color: _chunkNKTNLJUJcjs.hexToRgb8.call(void 0, paper.color),
1913
+ color: _chunk5BR7LC24cjs.hexToRgb8.call(void 0, paper.color),
1899
1914
  heightAt: flat ? () => 0.5 : (x, y) => grain.at(x, y)
1900
1915
  };
1901
1916
  }
1902
1917
  var WetStrokeDriver = (_class5 = class {
1903
- constructor(init) {;_class5.prototype.__init35.call(this);_class5.prototype.__init36.call(this);_class5.prototype.__init37.call(this);_class5.prototype.__init38.call(this);_class5.prototype.__init39.call(this);_class5.prototype.__init40.call(this);_class5.prototype.__init41.call(this);_class5.prototype.__init42.call(this);_class5.prototype.__init43.call(this);_class5.prototype.__init44.call(this);_class5.prototype.__init45.call(this);_class5.prototype.__init46.call(this);
1918
+ constructor(init) {;_class5.prototype.__init36.call(this);_class5.prototype.__init37.call(this);_class5.prototype.__init38.call(this);_class5.prototype.__init39.call(this);_class5.prototype.__init40.call(this);_class5.prototype.__init41.call(this);_class5.prototype.__init42.call(this);_class5.prototype.__init43.call(this);_class5.prototype.__init44.call(this);_class5.prototype.__init45.call(this);_class5.prototype.__init46.call(this);_class5.prototype.__init47.call(this);_class5.prototype.__init48.call(this);
1904
1919
  this.init = init;
1905
1920
  const brush = init.brush;
1906
- this.smoother = new (0, _chunkNKTNLJUJcjs.PenSmoother)(brush.tip.smoothing, brush.pressureSmoothing);
1907
- const copies = init.copies.length ? init.copies : [_chunkNKTNLJUJcjs.IDENTITY_COPY];
1921
+ this.smoother = new (0, _chunk5BR7LC24cjs.PenSmoother)(brush.tip.smoothing, brush.pressureSmoothing);
1922
+ const copies = init.copies.length ? init.copies : [_chunk5BR7LC24cjs.IDENTITY_COPY];
1908
1923
  const wet = brush.wet;
1909
1924
  const spacing = Math.max(0.02, brush.tip.spacing);
1910
1925
  const perDab = Math.min(1, spacing * 1.2);
@@ -1916,7 +1931,7 @@ var WetStrokeDriver = (_class5 = class {
1916
1931
  });
1917
1932
  const rates = _chunkPQ3H2AANcjs.exchangeRates.call(void 0, brush.behavior.pickup, brush.behavior.mix, wet.load, brush.behavior.mixing);
1918
1933
  this.states = copies.map((c, i) => ({
1919
- walker: new (0, _chunkNKTNLJUJcjs.PenDabWalker)(brush, init.seed + i * 7919 | 0, c.linear),
1934
+ walker: new (0, _chunk5BR7LC24cjs.PenDabWalker)(brush, init.seed + i * 7919 | 0, c.linear),
1920
1935
  exchange: wet.tool === "paint" ? new (0, _chunkPQ3H2AANcjs.PaintExchange)(rates, init.load) : null,
1921
1936
  last: null
1922
1937
  }));
@@ -1926,28 +1941,29 @@ var WetStrokeDriver = (_class5 = class {
1926
1941
  this.sampler = g ? new (0, _chunkPQ3H2AANcjs.PaintGradientSampler)(g.map.by === "across-tip" ? { ...g, map: { by: "distance", length: 300, repeat: "mirror" } } : g, init.seed) : null;
1927
1942
  }
1928
1943
 
1929
- __init35() {this.dabCount = 0}
1930
- __init36() {this.bounds = null}
1944
+ __init36() {this.dabCount = 0}
1945
+ __init37() {this.bounds = null}
1931
1946
  /** The world's clock at which each raw point was applied (recorded with the stroke). */
1932
- __init37() {this.steps = []}
1947
+ __init38() {this.steps = []}
1933
1948
 
1934
1949
 
1935
1950
 
1936
- __init38() {this.queue = []}
1937
- __init39() {this.finishing = false}
1938
- __init40() {this.finished = false}
1939
- __init41() {this.lastRaw = null}
1940
- __init42() {this.lastFed = null}
1941
- __init43() {this.tip = new Float32Array(0)}
1942
- __init44() {this.cov = new Float32Array(0)}
1943
- __init45() {this.paint = [0, 0, 0]}
1951
+ __init39() {this.queue = []}
1952
+ __init40() {this.finishing = false}
1953
+ __init41() {this.finished = false}
1954
+ __init42() {this.lastRaw = null}
1955
+ __init43() {this.lastFed = null}
1956
+ __init44() {this.tip = new Float32Array(0)}
1957
+ __init45() {this.cov = new Float32Array(0)}
1958
+ __init46() {this.paint = [0, 0, 0]}
1959
+ __init47() {this.centre = [0, 0, 0]}
1944
1960
 
1945
1961
 
1946
- __init46() {this.sample = { rgb: [0, 0, 0], alpha: 1 }}
1962
+ __init48() {this.sample = { rgb: [0, 0, 0], alpha: 1 }}
1947
1963
 
1948
1964
  /** What copy 0's brush carries after the dabs so far. */
1949
1965
  get load() {
1950
- return _nullishCoalesce(_optionalChain([this, 'access', _81 => _81.states, 'access', _82 => _82[0], 'access', _83 => _83.exchange, 'optionalAccess', _84 => _84.load]), () => ( null));
1966
+ return _nullishCoalesce(_optionalChain([this, 'access', _83 => _83.states, 'access', _84 => _84[0], 'access', _85 => _85.exchange, 'optionalAccess', _86 => _86.load]), () => ( null));
1951
1967
  }
1952
1968
  /** Whether every point (and the end) has been applied. */
1953
1969
  get done() {
@@ -2041,14 +2057,23 @@ var WetStrokeDriver = (_class5 = class {
2041
2057
  case "paint": {
2042
2058
  const ex = st.exchange;
2043
2059
  let flow = 1;
2044
- if (this.sampler) {
2060
+ const effect = this.init.effect;
2061
+ if (effect) {
2062
+ _chunk5BR7LC24cjs.sampleEffectAt.call(void 0, effect, d.x, d.y, this.centre, d);
2063
+ ex.setReservoirColor(this.centre[0], this.centre[1], this.centre[2]);
2064
+ } else if (this.sampler) {
2045
2065
  const g = this.sampler.dab(d, this.sample);
2046
2066
  ex.setReservoirColor(g.rgb[0], g.rgb[1], g.rgb[2]);
2047
2067
  flow = g.alpha;
2048
2068
  }
2049
2069
  ex.pickUp(this.medium.sample(rect, tip));
2050
2070
  const total = ex.paint(this.paint);
2051
- if (total > 0 && flow > 0) this.medium.deposit(rect, cov, Math.min(1, total) * k * flow, this.paint, null);
2071
+ if (total > 0 && flow > 0 && effect) {
2072
+ const ec = cov.slice();
2073
+ const field = new Float32Array(ec.length * 3);
2074
+ _chunk5BR7LC24cjs.effectDabField.call(void 0, effect, rect, ec, this.centre, this.paint, field, COVERAGE_STEPS, d);
2075
+ this.medium.deposit(rect, ec, Math.min(1, total) * k, this.paint, null, field);
2076
+ } else if (total > 0 && flow > 0) this.medium.deposit(rect, cov, Math.min(1, total) * k * flow, this.paint, null);
2052
2077
  else world.paint(laneId, rect, cov, this.medium.options.water * k, null);
2053
2078
  ex.drain();
2054
2079
  if (wet.rewet > 0) world.rewet(laneId, rect, cov, wet.rewet * k * 0.15, this.init.paperColor);
@@ -2090,7 +2115,7 @@ var WET_GPU_MODES = ["auto", "off"];
2090
2115
  var GPU_LEAD = 16;
2091
2116
  var DISPLAY_TILES_PER_TICK = 24;
2092
2117
  var PaintWetLayers = (_class6 = class {
2093
- constructor(host, options = {}) {;_class6.prototype.__init47.call(this);_class6.prototype.__init48.call(this);_class6.prototype.__init49.call(this);_class6.prototype.__init50.call(this);_class6.prototype.__init51.call(this);_class6.prototype.__init52.call(this);_class6.prototype.__init53.call(this);_class6.prototype.__init54.call(this);_class6.prototype.__init55.call(this);_class6.prototype.__init56.call(this);_class6.prototype.__init57.call(this);_class6.prototype.__init58.call(this);_class6.prototype.__init59.call(this);_class6.prototype.__init60.call(this);_class6.prototype.__init61.call(this);_class6.prototype.__init62.call(this);
2118
+ constructor(host, options = {}) {;_class6.prototype.__init49.call(this);_class6.prototype.__init50.call(this);_class6.prototype.__init51.call(this);_class6.prototype.__init52.call(this);_class6.prototype.__init53.call(this);_class6.prototype.__init54.call(this);_class6.prototype.__init55.call(this);_class6.prototype.__init56.call(this);_class6.prototype.__init57.call(this);_class6.prototype.__init58.call(this);_class6.prototype.__init59.call(this);_class6.prototype.__init60.call(this);_class6.prototype.__init61.call(this);_class6.prototype.__init62.call(this);_class6.prototype.__init63.call(this);_class6.prototype.__init64.call(this);
2094
2119
  this.host = host;
2095
2120
  this.options = options;
2096
2121
  this.speed = Math.max(1, Math.min(2e3, _nullishCoalesce(options.speed, () => ( 120))));
@@ -2100,27 +2125,27 @@ var PaintWetLayers = (_class6 = class {
2100
2125
  }
2101
2126
 
2102
2127
 
2103
- __init47() {this.world = null}
2104
- __init48() {this.tilt = { ..._chunkXFYLA3ZOcjs.FLAT }}
2105
- __init49() {this.settings = /* @__PURE__ */ new Map()}
2106
- __init50() {this.paused = false}
2128
+ __init49() {this.world = null}
2129
+ __init50() {this.tilt = { ..._chunkXFYLA3ZOcjs.FLAT }}
2130
+ __init51() {this.settings = /* @__PURE__ */ new Map()}
2131
+ __init52() {this.paused = false}
2107
2132
  /** Wet strokes dry as soon as they end (one undo step with the stroke). */
2108
- __init51() {this.instantDry = false}
2133
+ __init53() {this.instantDry = false}
2109
2134
 
2110
- __init52() {this.overlay = false}
2135
+ __init54() {this.overlay = false}
2111
2136
 
2112
2137
  /** The live wet stroke, if any. */
2113
- __init53() {this.driver = null}
2114
- __init54() {this.lastTick = null}
2115
- __init55() {this.ticking = null}
2116
- __init56() {this.stepsOwed = 0}
2117
- __init57() {this.displaying = null}
2118
- __init58() {this.leadAt = 0}
2138
+ __init55() {this.driver = null}
2139
+ __init56() {this.lastTick = null}
2140
+ __init57() {this.ticking = null}
2141
+ __init58() {this.stepsOwed = 0}
2142
+ __init59() {this.displaying = null}
2143
+ __init60() {this.leadAt = 0}
2119
2144
 
2120
2145
 
2121
- __init59() {this.gpu = null}
2122
- __init60() {this.gpuSupport = null}
2123
- __init61() {this.gpuStarting = null}
2146
+ __init61() {this.gpu = null}
2147
+ __init62() {this.gpuSupport = null}
2148
+ __init63() {this.gpuStarting = null}
2124
2149
  // --- Engine B ------------------------------------------------------------------
2125
2150
  /** Starts the GPU engine for the world (once; it may turn out unavailable). */
2126
2151
  startGpu() {
@@ -2156,8 +2181,8 @@ var PaintWetLayers = (_class6 = class {
2156
2181
  if (mode === this.gpuMode) return this.engineInfo();
2157
2182
  this.gpuMode = mode;
2158
2183
  if (mode === "off") {
2159
- _optionalChain([this, 'access', _85 => _85.world, 'optionalAccess', _86 => _86.attachGpu, 'call', _87 => _87(null)]);
2160
- _optionalChain([this, 'access', _88 => _88.gpu, 'optionalAccess', _89 => _89.destroy, 'call', _90 => _90()]);
2184
+ _optionalChain([this, 'access', _87 => _87.world, 'optionalAccess', _88 => _88.attachGpu, 'call', _89 => _89(null)]);
2185
+ _optionalChain([this, 'access', _90 => _90.gpu, 'optionalAccess', _91 => _91.destroy, 'call', _92 => _92()]);
2161
2186
  this.gpu = null;
2162
2187
  this.gpuSupport = null;
2163
2188
  } else if (this.world) this.startGpu();
@@ -2165,13 +2190,13 @@ var PaintWetLayers = (_class6 = class {
2165
2190
  }
2166
2191
  engineInfo() {
2167
2192
  const w = this.world;
2168
- const base = { mode: this.gpuMode, adapter: _nullishCoalesce(_optionalChain([this, 'access', _91 => _91.gpuSupport, 'optionalAccess', _92 => _92.adapter]), () => ( null)), maxTiles: _nullishCoalesce(_optionalChain([this, 'access', _93 => _93.gpuSupport, 'optionalAccess', _94 => _94.maxSlots]), () => ( 0)), minTiles: this.gpuMinTiles, activeTiles: _nullishCoalesce(_optionalChain([w, 'optionalAccess', _95 => _95.activeTiles, 'call', _96 => _96()]), () => ( 0)), cpu: this.backend() };
2193
+ const base = { mode: this.gpuMode, adapter: _nullishCoalesce(_optionalChain([this, 'access', _93 => _93.gpuSupport, 'optionalAccess', _94 => _94.adapter]), () => ( null)), maxTiles: _nullishCoalesce(_optionalChain([this, 'access', _95 => _95.gpuSupport, 'optionalAccess', _96 => _96.maxSlots]), () => ( 0)), minTiles: this.gpuMinTiles, activeTiles: _nullishCoalesce(_optionalChain([w, 'optionalAccess', _97 => _97.activeTiles, 'call', _98 => _98()]), () => ( 0)), cpu: this.backend() };
2169
2194
  if (this.gpuMode === "off") return { ...base, state: "off", reason: "Forced to the CPU." };
2170
2195
  if (this.gpuStarting) return { ...base, state: "starting", reason: null };
2171
- if (_optionalChain([w, 'optionalAccess', _97 => _97.gpuError])) return { ...base, state: "failed", reason: w.gpuError };
2196
+ if (_optionalChain([w, 'optionalAccess', _99 => _99.gpuError])) return { ...base, state: "failed", reason: w.gpuError };
2172
2197
  if (this.gpuSupport && !this.gpuSupport.supported) return { ...base, state: "unavailable", reason: this.gpuSupport.reason };
2173
2198
  if (!this.gpu) return { ...base, state: "not-started", reason: "Starts with the first wet stroke." };
2174
- if (_optionalChain([w, 'optionalAccess', _98 => _98.gpuActive])) return { ...base, state: "active", reason: null };
2199
+ if (_optionalChain([w, 'optionalAccess', _100 => _100.gpuActive])) return { ...base, state: "active", reason: null };
2175
2200
  return { ...base, state: "standby", reason: `The GPU takes over at ${this.gpuMinTiles} wet tiles (256 px).` };
2176
2201
  }
2177
2202
  /** The world (made on first use, at the canvas size). */
@@ -2210,13 +2235,13 @@ var PaintWetLayers = (_class6 = class {
2210
2235
  if (!this.canExtend(left, top)) throw new Error("Wet paint only moves by whole 256 px tiles, between strokes.");
2211
2236
  for (const [id, s] of this.settings) if (s.flow.center) this.settings.set(id, { ...s, flow: { ...s.flow, center: { x: s.flow.center.x + left, y: s.flow.center.y + top } } });
2212
2237
  const old = this.world;
2213
- const snap = _optionalChain([old, 'optionalAccess', _99 => _99.laneIds, 'call', _100 => _100(), 'access', _101 => _101.length]) ? old.snapshot() : null;
2238
+ const snap = _optionalChain([old, 'optionalAccess', _101 => _101.laneIds, 'call', _102 => _102(), 'access', _103 => _103.length]) ? old.snapshot() : null;
2214
2239
  this.dropWorld();
2215
2240
  this.lastTick = null;
2216
2241
  this.stepsOwed = 0;
2217
2242
  if (!old || !snap) return;
2218
2243
  const moved = _chunkXFYLA3ZOcjs.moveWetSnapshot.call(void 0, snap, old, { width, height }, left, top, (l) => {
2219
- const flow = _optionalChain([this, 'access', _102 => _102.settings, 'access', _103 => _103.get, 'call', _104 => _104(l.id), 'optionalAccess', _105 => _105.flow]);
2244
+ const flow = _optionalChain([this, 'access', _104 => _104.settings, 'access', _105 => _105.get, 'call', _106 => _106(l.id), 'optionalAccess', _107 => _107.flow]);
2220
2245
  return {
2221
2246
  base: _chunk474IQG74cjs.translateSurface.call(void 0, l.base, left, top),
2222
2247
  flow: l.flow && flow && flow.kind !== "none" ? _chunkXFYLA3ZOcjs.flowField.call(void 0, flow, width, height) : l.flow
@@ -2234,11 +2259,11 @@ var PaintWetLayers = (_class6 = class {
2234
2259
  }
2235
2260
  /** Layers holding a wet layer (wet or drying). */
2236
2261
  wetLayerIds() {
2237
- return _nullishCoalesce(_optionalChain([this, 'access', _106 => _106.world, 'optionalAccess', _107 => _107.laneIds, 'call', _108 => _108()]), () => ( []));
2262
+ return _nullishCoalesce(_optionalChain([this, 'access', _108 => _108.world, 'optionalAccess', _109 => _109.laneIds, 'call', _110 => _110()]), () => ( []));
2238
2263
  }
2239
2264
  /** Whether a batch is running (edits wait). */
2240
2265
  get busy() {
2241
- return Boolean(_optionalChain([this, 'access', _109 => _109.world, 'optionalAccess', _110 => _110.busy]));
2266
+ return Boolean(_optionalChain([this, 'access', _111 => _111.world, 'optionalAccess', _112 => _112.busy]));
2242
2267
  }
2243
2268
  /** Resolves when no batch is running. */
2244
2269
  async idle() {
@@ -2267,13 +2292,13 @@ var PaintWetLayers = (_class6 = class {
2267
2292
  setParams(layerId, update) {
2268
2293
  const s = this.settingsOf(layerId);
2269
2294
  s.params = _chunkXFYLA3ZOcjs.normalizeWetParams.call(void 0, update, s.params);
2270
- if (_optionalChain([this, 'access', _111 => _111.world, 'optionalAccess', _112 => _112.hasLane, 'call', _113 => _113(layerId)])) this.world.setParams(layerId, s.params);
2295
+ if (_optionalChain([this, 'access', _113 => _113.world, 'optionalAccess', _114 => _114.hasLane, 'call', _115 => _115(layerId)])) this.world.setParams(layerId, s.params);
2271
2296
  return { ...s.params };
2272
2297
  }
2273
2298
  setFlow(layerId, update) {
2274
2299
  const s = this.settingsOf(layerId);
2275
2300
  s.flow = _chunkXFYLA3ZOcjs.normalizeFlow.call(void 0, update, s.flow);
2276
- if (_optionalChain([this, 'access', _114 => _114.world, 'optionalAccess', _115 => _115.hasLane, 'call', _116 => _116(layerId)])) {
2301
+ if (_optionalChain([this, 'access', _116 => _116.world, 'optionalAccess', _117 => _117.hasLane, 'call', _118 => _118(layerId)])) {
2277
2302
  const { width, height } = this.host.canvas();
2278
2303
  this.world.setFlow(layerId, _chunkXFYLA3ZOcjs.flowField.call(void 0, s.flow, width, height), s.flow.strength);
2279
2304
  }
@@ -2281,29 +2306,29 @@ var PaintWetLayers = (_class6 = class {
2281
2306
  }
2282
2307
  setTilt(update) {
2283
2308
  this.tilt = _chunkXFYLA3ZOcjs.normalizeTilt.call(void 0, update, this.tilt);
2284
- _optionalChain([this, 'access', _117 => _117.world, 'optionalAccess', _118 => _118.setTilt, 'call', _119 => _119(this.tilt)]);
2309
+ _optionalChain([this, 'access', _119 => _119.world, 'optionalAccess', _120 => _120.setTilt, 'call', _121 => _121(this.tilt)]);
2285
2310
  return { ...this.tilt };
2286
2311
  }
2287
2312
  /** The paper changed. */
2288
2313
  paperChanged() {
2289
- _optionalChain([this, 'access', _120 => _120.world, 'optionalAccess', _121 => _121.setPaper, 'call', _122 => _122(wetPaperInput(this.host.paper()))]);
2314
+ _optionalChain([this, 'access', _122 => _122.world, 'optionalAccess', _123 => _123.setPaper, 'call', _124 => _124(wetPaperInput(this.host.paper()))]);
2290
2315
  }
2291
2316
  /** A layer as tools describe it. */
2292
2317
  info(layerId) {
2293
2318
  const s = this.settingsOf(layerId);
2294
- const st = _optionalChain([this, 'access', _123 => _123.world, 'optionalAccess', _124 => _124.hasLane, 'call', _125 => _125(layerId)]) ? this.world.stats(layerId) : null;
2319
+ const st = _optionalChain([this, 'access', _125 => _125.world, 'optionalAccess', _126 => _126.hasLane, 'call', _127 => _127(layerId)]) ? this.world.stats(layerId) : null;
2295
2320
  return {
2296
2321
  layerId,
2297
2322
  wet: Boolean(st && st.wetCells > 0),
2298
- wetCells: _nullishCoalesce(_optionalChain([st, 'optionalAccess', _126 => _126.wetCells]), () => ( 0)),
2299
- wetBounds: _nullishCoalesce(_optionalChain([st, 'optionalAccess', _127 => _127.wetBounds]), () => ( null)),
2300
- activeTiles: _nullishCoalesce(_optionalChain([st, 'optionalAccess', _128 => _128.activeTiles]), () => ( 0)),
2323
+ wetCells: _nullishCoalesce(_optionalChain([st, 'optionalAccess', _128 => _128.wetCells]), () => ( 0)),
2324
+ wetBounds: _nullishCoalesce(_optionalChain([st, 'optionalAccess', _129 => _129.wetBounds]), () => ( null)),
2325
+ activeTiles: _nullishCoalesce(_optionalChain([st, 'optionalAccess', _130 => _130.activeTiles]), () => ( 0)),
2301
2326
  params: { ...s.params },
2302
2327
  flow: { ...s.flow }
2303
2328
  };
2304
2329
  }
2305
2330
  backend() {
2306
- return _nullishCoalesce(_optionalChain([this, 'access', _129 => _129.world, 'optionalAccess', _130 => _130.backend, 'call', _131 => _131()]), () => ( null));
2331
+ return _nullishCoalesce(_optionalChain([this, 'access', _131 => _131.world, 'optionalAccess', _132 => _132.backend, 'call', _133 => _133()]), () => ( null));
2307
2332
  }
2308
2333
  /** Shows the current wet pixels (at most `maxTiles` reshaded per layer). */
2309
2334
  syncDisplays(maxTiles = Infinity) {
@@ -2339,7 +2364,7 @@ var PaintWetLayers = (_class6 = class {
2339
2364
  const w = this.world;
2340
2365
  if (!w) return;
2341
2366
  for (const id of w.laneIds()) {
2342
- if (w.isActive(id) || _optionalChain([this, 'access', _132 => _132.driver, 'optionalAccess', _133 => _133.init, 'access', _134 => _134.laneId]) === id) continue;
2367
+ if (w.isActive(id) || _optionalChain([this, 'access', _134 => _134.driver, 'optionalAccess', _135 => _135.init, 'access', _136 => _136.laneId]) === id) continue;
2343
2368
  const base = w.getBase(id);
2344
2369
  w.removeLane(id);
2345
2370
  this.host.updateSurfaces(/* @__PURE__ */ new Map([[id, base]]), []);
@@ -2419,10 +2444,10 @@ var PaintWetLayers = (_class6 = class {
2419
2444
  if (!d || !this.world) return;
2420
2445
  const rects = d.flush();
2421
2446
  if (rects.length) this.syncDisplays(DISPLAY_TILES_PER_TICK);
2422
- if (d.done) _optionalChain([this, 'access', _135 => _135.onDriverDone, 'optionalCall', _136 => _136(d)]);
2447
+ if (d.done) _optionalChain([this, 'access', _137 => _137.onDriverDone, 'optionalCall', _138 => _138(d)]);
2423
2448
  }
2424
2449
  /** Called when a live stroke that ended mid-batch has finished applying. */
2425
- __init62() {this.onDriverDone = null}
2450
+ __init64() {this.onDriverDone = null}
2426
2451
  /** Steps `steps` times now (agents, tests). Returns the steps run. */
2427
2452
  async advance(steps) {
2428
2453
  await this.idle();
@@ -2463,7 +2488,7 @@ var PaintWetLayers = (_class6 = class {
2463
2488
  /** The layer's pixels with all its wet paint dried (deterministic), without changing anything. */
2464
2489
  bakedSurface(layerId) {
2465
2490
  const w = this.world;
2466
- if (!_optionalChain([w, 'optionalAccess', _137 => _137.hasLane, 'call', _138 => _138(layerId)])) return null;
2491
+ if (!_optionalChain([w, 'optionalAccess', _139 => _139.hasLane, 'call', _140 => _140(layerId)])) return null;
2467
2492
  return w.bakedSurface(layerId);
2468
2493
  }
2469
2494
  /** A snapshot of the world for undo (`null` when there is none). */
@@ -2484,13 +2509,13 @@ var PaintWetLayers = (_class6 = class {
2484
2509
  this.syncDisplays();
2485
2510
  }
2486
2511
  dropWorld() {
2487
- _optionalChain([this, 'access', _139 => _139.world, 'optionalAccess', _140 => _140.destroy, 'call', _141 => _141()]);
2512
+ _optionalChain([this, 'access', _141 => _141.world, 'optionalAccess', _142 => _142.destroy, 'call', _143 => _143()]);
2488
2513
  this.world = null;
2489
2514
  this.driver = null;
2490
2515
  }
2491
2516
  /** Forgets everything wet (a new canvas, a resize, opening a document). */
2492
2517
  reset() {
2493
- _optionalChain([this, 'access', _142 => _142.world, 'optionalAccess', _143 => _143.destroy, 'call', _144 => _144()]);
2518
+ _optionalChain([this, 'access', _144 => _144.world, 'optionalAccess', _145 => _145.destroy, 'call', _146 => _146()]);
2494
2519
  this.world = null;
2495
2520
  this.driver = null;
2496
2521
  this.settings.clear();
@@ -2520,14 +2545,14 @@ var PaintWetLayers = (_class6 = class {
2520
2545
  return out;
2521
2546
  }
2522
2547
  destroy() {
2523
- _optionalChain([this, 'access', _145 => _145.world, 'optionalAccess', _146 => _146.destroy, 'call', _147 => _147()]);
2548
+ _optionalChain([this, 'access', _147 => _147.world, 'optionalAccess', _148 => _148.destroy, 'call', _149 => _149()]);
2524
2549
  this.world = null;
2525
- _optionalChain([this, 'access', _148 => _148.gpu, 'optionalAccess', _149 => _149.destroy, 'call', _150 => _150()]);
2550
+ _optionalChain([this, 'access', _150 => _150.gpu, 'optionalAccess', _151 => _151.destroy, 'call', _152 => _152()]);
2526
2551
  this.gpu = null;
2527
2552
  }
2528
2553
  }, _class6);
2529
2554
  function wetPigmentOf(hex, body) {
2530
- const [r, g, b] = _chunkNKTNLJUJcjs.hexToRgb8.call(void 0, hex);
2555
+ const [r, g, b] = _chunk5BR7LC24cjs.hexToRgb8.call(void 0, hex);
2531
2556
  return Array.from(_chunkXFYLA3ZOcjs.pigmentOf.call(void 0, [r / 255, g / 255, b / 255], body));
2532
2557
  }
2533
2558
 
@@ -2535,13 +2560,13 @@ function wetPigmentOf(hex, body) {
2535
2560
  var thumbWorld = null;
2536
2561
  function paintWetTestStroke(brush, paper, color, width, height) {
2537
2562
  if (!thumbWorld || thumbWorld.width !== width || thumbWorld.height !== height) {
2538
- _optionalChain([thumbWorld, 'optionalAccess', _151 => _151.destroy, 'call', _152 => _152()]);
2563
+ _optionalChain([thumbWorld, 'optionalAccess', _153 => _153.destroy, 'call', _154 => _154()]);
2539
2564
  thumbWorld = new (0, _chunkXFYLA3ZOcjs.WetWorld)(width, height, wetPaperInput(paper), { kernel: "typescript", threads: 0 });
2540
2565
  } else thumbWorld.setPaper(wetPaperInput(paper));
2541
2566
  const w = thumbWorld;
2542
2567
  if (w.hasLane("thumb")) w.removeLane("thumb");
2543
2568
  w.ensureLane("thumb");
2544
- const [r, g, b] = _chunkNKTNLJUJcjs.hexToRgb8.call(void 0, color);
2569
+ const [r, g, b] = _chunk5BR7LC24cjs.hexToRgb8.call(void 0, color);
2545
2570
  if (brush.wet.tool !== "paint" && brush.wet.tool !== "water") {
2546
2571
  const half = Math.ceil(height / 2);
2547
2572
  w.paint("thumb", { x: 0, y: 0, width, height: half }, null, 0.4, Array.from(_chunkXFYLA3ZOcjs.pigmentOf.call(void 0, [r / 255, g / 255, b / 255], 0), (v) => v * 0.05));
@@ -2555,9 +2580,9 @@ function paintWetTestStroke(brush, paper, color, width, height) {
2555
2580
  load: brushLoadForStroke(brush, _chunkPQ3H2AANcjs.EMPTY_MIXER_LOAD, [r / 255, g / 255, b / 255]),
2556
2581
  grain: paperGrain(paper),
2557
2582
  paperDepth: paper.depth,
2558
- paperColor: _chunkNKTNLJUJcjs.hexToRgb8.call(void 0, paper.color),
2583
+ paperColor: _chunk5BR7LC24cjs.hexToRgb8.call(void 0, paper.color),
2559
2584
  seed: 7,
2560
- copies: [_chunkNKTNLJUJcjs.IDENTITY_COPY]
2585
+ copies: [_chunk5BR7LC24cjs.IDENTITY_COPY]
2561
2586
  });
2562
2587
  driver.push(thumbnailStroke(width, height));
2563
2588
  driver.finish();
@@ -2577,7 +2602,7 @@ function thumbnailStroke(width, height) {
2577
2602
  return pts;
2578
2603
  }
2579
2604
  function paintTestStroke(surface, brush, paper, color, width, height) {
2580
- const [r, g, b] = _chunkNKTNLJUJcjs.hexToRgb8.call(void 0, color);
2605
+ const [r, g, b] = _chunk5BR7LC24cjs.hexToRgb8.call(void 0, color);
2581
2606
  let result = surface;
2582
2607
  let thick = null;
2583
2608
  const session = new PaintStrokeSession(
@@ -2596,13 +2621,13 @@ function paintTestStroke(surface, brush, paper, color, width, height) {
2596
2621
  lockTransparency: false,
2597
2622
  brush,
2598
2623
  color: [r, g, b, 255],
2599
- background: [..._chunkNKTNLJUJcjs.hexToRgb8.call(void 0, paper.color), 255],
2624
+ background: [..._chunk5BR7LC24cjs.hexToRgb8.call(void 0, paper.color), 255],
2600
2625
  grain: paperGrain(paper),
2601
2626
  paperDepth: paper.depth,
2602
2627
  seed: 7,
2603
2628
  colorHex: color,
2604
2629
  affineCopies: [],
2605
- copies: [_chunkNKTNLJUJcjs.IDENTITY_COPY],
2630
+ copies: [_chunk5BR7LC24cjs.IDENTITY_COPY],
2606
2631
  mixerLoad: brushLoadForStroke(brush, _chunkPQ3H2AANcjs.EMPTY_MIXER_LOAD, [r / 255, g / 255, b / 255]),
2607
2632
  thick: brush.engine === "impasto" ? { channels: emptyThickChannels() } : void 0,
2608
2633
  sticker: brush.engine === "sticker" ? { nextId: 1 } : void 0
@@ -2616,8 +2641,8 @@ function renderBrushThumbnail(brush, options) {
2616
2641
  const width = Math.max(16, Math.min(512, Math.round(_nullishCoalesce(options.width, () => ( 160)))));
2617
2642
  const height = Math.max(16, Math.min(512, Math.round(_nullishCoalesce(options.height, () => ( 48)))));
2618
2643
  const maxSize = height * 0.42;
2619
- const b = brush.tip.size > maxSize ? _chunkNKTNLJUJcjs.normalizePaintBrush.call(void 0, { tip: { ...brush.tip, size: maxSize } }, brush) : brush;
2620
- const rgba = [..._chunkNKTNLJUJcjs.hexToRgb8.call(void 0, options.color), 255];
2644
+ const b = brush.tip.size > maxSize ? _chunk5BR7LC24cjs.normalizePaintBrush.call(void 0, { tip: { ...brush.tip, size: maxSize } }, brush) : brush;
2645
+ const rgba = [..._chunk5BR7LC24cjs.hexToRgb8.call(void 0, options.color), 255];
2621
2646
  let surface = _chunk474IQG74cjs.emptySurface.call(void 0, 4);
2622
2647
  if (b.engine === "eraser") {
2623
2648
  surface = _chunk474IQG74cjs.fillRect.call(void 0, surface, { x: 0, y: 0, width, height }, rgba);
@@ -2759,12 +2784,12 @@ function perspectiveDirections(g, p) {
2759
2784
  }
2760
2785
  var SNAP_DECIDE_DISTANCE = 6;
2761
2786
  var PerspectiveSnapper = (_class7 = class {
2762
- constructor(guide) {;_class7.prototype.__init63.call(this);_class7.prototype.__init64.call(this);
2787
+ constructor(guide) {;_class7.prototype.__init65.call(this);_class7.prototype.__init66.call(this);
2763
2788
  this.guide = guide;
2764
2789
  }
2765
2790
 
2766
- __init63() {this.start = null}
2767
- __init64() {this.dir = null}
2791
+ __init65() {this.start = null}
2792
+ __init66() {this.dir = null}
2768
2793
  /** The line the stroke follows, once chosen. */
2769
2794
  get line() {
2770
2795
  return this.start && this.dir ? { from: this.start, direction: this.dir } : null;
@@ -2870,11 +2895,11 @@ function readSwatch(raw) {
2870
2895
  if (!raw || typeof raw !== "object") return null;
2871
2896
  const r = raw;
2872
2897
  const g = _chunkPQ3H2AANcjs.readPaintSource.call(void 0, r.paint);
2873
- const color = typeof r.color === "string" && /^#[0-9a-f]{6}$/i.test(r.color) ? r.color.toLowerCase() : _optionalChain([g, 'optionalAccess', _153 => _153.type]) === "gradient" ? _chunkPQ3H2AANcjs.paintSourceColor.call(void 0, g) : null;
2898
+ const color = typeof r.color === "string" && /^#[0-9a-f]{6}$/i.test(r.color) ? r.color.toLowerCase() : _optionalChain([g, 'optionalAccess', _155 => _155.type]) === "gradient" ? _chunkPQ3H2AANcjs.paintSourceColor.call(void 0, g) : null;
2874
2899
  if (!color) return null;
2875
2900
  const out = { color };
2876
2901
  if (typeof r.name === "string" && r.name.trim()) out.name = r.name.trim().slice(0, 80);
2877
- if (_optionalChain([g, 'optionalAccess', _154 => _154.type]) === "gradient") out.paint = g;
2902
+ if (_optionalChain([g, 'optionalAccess', _156 => _156.type]) === "gradient") out.paint = g;
2878
2903
  return out;
2879
2904
  }
2880
2905
  var DEFAULT_SWATCHES = [
@@ -2893,7 +2918,7 @@ var DEFAULT_SWATCHES = [
2893
2918
  // src/paint-editor/mixing-pad.ts
2894
2919
  var MIXING_PAD_WIDTH = 360;
2895
2920
  var MIXING_PAD_HEIGHT = 220;
2896
- var PAD_PAINT = _chunkNKTNLJUJcjs.normalizePaintBrush.call(void 0, {
2921
+ var PAD_PAINT = _chunk5BR7LC24cjs.normalizePaintBrush.call(void 0, {
2897
2922
  id: "pad-paint",
2898
2923
  name: "Pad paint",
2899
2924
  category: "mixer",
@@ -2901,7 +2926,7 @@ var PAD_PAINT = _chunkNKTNLJUJcjs.normalizePaintBrush.call(void 0, {
2901
2926
  tip: { size: 28, hardness: 0.75, spacing: 0.1, opacity: 1, flow: 0.7, pressureSize: false, pressureOpacity: false },
2902
2927
  mixer: { wet: 0.45, load: 1, mix: 0.4, loadEachStroke: true, cleanEachStroke: true, mixing: "pigment" }
2903
2928
  });
2904
- var PAD_KNIFE = _chunkNKTNLJUJcjs.normalizePaintBrush.call(void 0, {
2929
+ var PAD_KNIFE = _chunk5BR7LC24cjs.normalizePaintBrush.call(void 0, {
2905
2930
  id: "pad-knife",
2906
2931
  name: "Palette knife",
2907
2932
  category: "smudge",
@@ -2911,19 +2936,19 @@ var PAD_KNIFE = _chunkNKTNLJUJcjs.normalizePaintBrush.call(void 0, {
2911
2936
  // A knife drags streaks of paint and folds them into each other, mixing them as pigment.
2912
2937
  smudge: { strength: 0.6, length: 0.8, mixing: "pigment" }
2913
2938
  });
2914
- var PAD_BLOB = _chunkNKTNLJUJcjs.normalizePaintBrush.call(void 0, {
2939
+ var PAD_BLOB = _chunk5BR7LC24cjs.normalizePaintBrush.call(void 0, {
2915
2940
  id: "pad-blob",
2916
2941
  name: "Pad blob",
2917
2942
  category: "custom",
2918
2943
  engine: "dab",
2919
2944
  tip: { size: 20, hardness: 1, spacing: 0.1, opacity: 1, flow: 1, pressureSize: false, pressureOpacity: false }
2920
2945
  });
2921
- var MixingPad = (_class8 = class {constructor() { _class8.prototype.__init65.call(this);_class8.prototype.__init66.call(this);_class8.prototype.__init67.call(this);_class8.prototype.__init68.call(this); }
2922
- __init65() {this.width = MIXING_PAD_WIDTH}
2923
- __init66() {this.height = MIXING_PAD_HEIGHT}
2924
- __init67() {this.surface = _chunk474IQG74cjs.emptySurface.call(void 0, 4)}
2946
+ var MixingPad = (_class8 = class {constructor() { _class8.prototype.__init67.call(this);_class8.prototype.__init68.call(this);_class8.prototype.__init69.call(this);_class8.prototype.__init70.call(this); }
2947
+ __init67() {this.width = MIXING_PAD_WIDTH}
2948
+ __init68() {this.height = MIXING_PAD_HEIGHT}
2949
+ __init69() {this.surface = _chunk474IQG74cjs.emptySurface.call(void 0, 4)}
2925
2950
  /** Increments on every change (for redrawing). */
2926
- __init68() {this.version = 0}
2951
+ __init70() {this.version = 0}
2927
2952
  /** Paints (`paint`, with `color`) or smears (`knife`) through `points` in pad pixels. */
2928
2953
  stroke(points, options) {
2929
2954
  if (!points.length) throw new Error("points is empty; give at least one {x, y} in pad pixels.");
@@ -2933,12 +2958,12 @@ var MixingPad = (_class8 = class {constructor() { _class8.prototype.__init65.cal
2933
2958
  }
2934
2959
  }
2935
2960
  let brush = options.tool === "knife" ? PAD_KNIFE : PAD_PAINT;
2936
- if (options.size !== void 0) brush = _chunkNKTNLJUJcjs.normalizePaintBrush.call(void 0, { tip: { ...brush.tip, size: options.size } }, brush);
2961
+ if (options.size !== void 0) brush = _chunk5BR7LC24cjs.normalizePaintBrush.call(void 0, { tip: { ...brush.tip, size: options.size } }, brush);
2937
2962
  return this.run(brush, points, options.color);
2938
2963
  }
2939
2964
  /** Paints `points` with `brush` in `color` on the pad. */
2940
2965
  run(brush, points, color) {
2941
- const [r, g, b] = _chunkNKTNLJUJcjs.hexToRgb8.call(void 0, color);
2966
+ const [r, g, b] = _chunk5BR7LC24cjs.hexToRgb8.call(void 0, color);
2942
2967
  let result = null;
2943
2968
  const session = new PaintStrokeSession(
2944
2969
  { update: () => {
@@ -2956,7 +2981,7 @@ var MixingPad = (_class8 = class {constructor() { _class8.prototype.__init65.cal
2956
2981
  seed: 1,
2957
2982
  colorHex: color,
2958
2983
  affineCopies: [],
2959
- copies: [_chunkNKTNLJUJcjs.IDENTITY_COPY],
2984
+ copies: [_chunk5BR7LC24cjs.IDENTITY_COPY],
2960
2985
  mixerLoad: brushLoadForStroke(brush, _chunkPQ3H2AANcjs.EMPTY_MIXER_LOAD, [r / 255, g / 255, b / 255])
2961
2986
  }
2962
2987
  );
@@ -3032,10 +3057,10 @@ var MixingPad = (_class8 = class {constructor() { _class8.prototype.__init65.cal
3032
3057
  const off = used.length === 1 ? 0 : 0.45 * R;
3033
3058
  const x = Math.min(cx + R - r, Math.max(cx - R + r, cx + Math.cos(a) * off));
3034
3059
  const y = Math.min(cy + R - r, Math.max(cy - R + r, cy + Math.sin(a) * off));
3035
- const blob = _chunkNKTNLJUJcjs.normalizePaintBrush.call(void 0, { tip: { ...PAD_BLOB.tip, size: Math.max(2, 2 * r) } }, PAD_BLOB);
3060
+ const blob = _chunk5BR7LC24cjs.normalizePaintBrush.call(void 0, { tip: { ...PAD_BLOB.tip, size: Math.max(2, 2 * r) } }, PAD_BLOB);
3036
3061
  this.run(blob, [{ x, y }], p.color.toLowerCase());
3037
3062
  });
3038
- const knife = _chunkNKTNLJUJcjs.normalizePaintBrush.call(void 0, { tip: { ...PAD_KNIFE.tip, size: Math.max(12, R * 0.5) } }, PAD_KNIFE);
3063
+ const knife = _chunk5BR7LC24cjs.normalizePaintBrush.call(void 0, { tip: { ...PAD_KNIFE.tip, size: Math.max(12, R * 0.5) } }, PAD_KNIFE);
3039
3064
  for (let k = 0; k < passes; k++) {
3040
3065
  const stir = [];
3041
3066
  const turns = 1.6;
@@ -3047,10 +3072,10 @@ var MixingPad = (_class8 = class {constructor() { _class8.prototype.__init65.cal
3047
3072
  this.run(knife, stir, "#000000");
3048
3073
  }
3049
3074
  const mixed = _chunkOLNIPTB3cjs.mixPigments.call(void 0,
3050
- paints.map((p) => _chunkNKTNLJUJcjs.hexToRgb8.call(void 0, p.color).map((v) => v / 255)),
3075
+ paints.map((p) => _chunk5BR7LC24cjs.hexToRgb8.call(void 0, p.color).map((v) => v / 255)),
3051
3076
  paints.map((p) => p.parts)
3052
3077
  );
3053
- const core = _chunkNKTNLJUJcjs.normalizePaintBrush.call(void 0, { tip: { ...PAD_BLOB.tip, size: R * 1.1, hardness: 0.55 } }, PAD_BLOB);
3078
+ const core = _chunk5BR7LC24cjs.normalizePaintBrush.call(void 0, { tip: { ...PAD_BLOB.tip, size: R * 1.1, hardness: 0.55 } }, PAD_BLOB);
3054
3079
  const hex = "#" + mixed.map((v) => Math.round(v * 255).toString(16).padStart(2, "0")).join("");
3055
3080
  this.run(core, [{ x: cx, y: cy }], hex);
3056
3081
  return { color: this.pick(cx, cy, 2), bounds };
@@ -3061,7 +3086,7 @@ var MixingPad = (_class8 = class {constructor() { _class8.prototype.__init65.cal
3061
3086
  }
3062
3087
  /** Replaces the pad with a PNG (data URL or base64) of the pad's size, as `toPng` writes. */
3063
3088
  fromPng(png) {
3064
- const bytes = png.startsWith("data:") ? _optionalChain([_chunkOLNIPTB3cjs.parseDataUrl.call(void 0, png), 'optionalAccess', _155 => _155.bytes]) : _chunkOLNIPTB3cjs.base64ToBytes.call(void 0, png);
3089
+ const bytes = png.startsWith("data:") ? _optionalChain([_chunkOLNIPTB3cjs.parseDataUrl.call(void 0, png), 'optionalAccess', _157 => _157.bytes]) : _chunkOLNIPTB3cjs.base64ToBytes.call(void 0, png);
3065
3090
  if (!bytes || !_chunkOLNIPTB3cjs.isPng.call(void 0, bytes)) throw new Error("The pad image is not a PNG data URL or base64 PNG.");
3066
3091
  const img = _chunkOLNIPTB3cjs.decodePng.call(void 0, bytes);
3067
3092
  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}.`);
@@ -3145,7 +3170,7 @@ async function replayPainting(source, target, options = {}) {
3145
3170
  const maxStrokes = _nullishCoalesce(options.strokes, () => ( source.strokes.length));
3146
3171
  const chunk = Math.max(1, _nullishCoalesce(options.wetChunk, () => ( 0))) || Infinity;
3147
3172
  let strokes = 0;
3148
- await target.prepareEffectPaints(source.strokes.slice(0, maxStrokes).flatMap((st) => _optionalChain([st, 'access', _156 => _156.paint, 'optionalAccess', _157 => _157.type]) === "effect" ? [st.paint] : []));
3173
+ await target.prepareEffectPaints(source.strokes.slice(0, maxStrokes).flatMap((st) => _optionalChain([st, 'access', _158 => _158.paint, 'optionalAccess', _159 => _159.type]) === "effect" ? [st.paint] : []));
3149
3174
  const advanceTo = async (clock) => {
3150
3175
  const now = target.getState().wet.clock;
3151
3176
  let left = clock - now;
@@ -3153,7 +3178,7 @@ async function replayPainting(source, target, options = {}) {
3153
3178
  const n = Math.min(left, chunk);
3154
3179
  await target.advanceWet({ steps: n });
3155
3180
  left -= n;
3156
- if (Number.isFinite(chunk)) await _optionalChain([options, 'access', _158 => _158.onWetSteps, 'optionalCall', _159 => _159(target.getState().wet.clock)]);
3181
+ if (Number.isFinite(chunk)) await _optionalChain([options, 'access', _160 => _160.onWetSteps, 'optionalCall', _161 => _161(target.getState().wet.clock)]);
3157
3182
  }
3158
3183
  };
3159
3184
  const sr = (r) => ({ x: r.x * s, y: r.y * s, width: r.width * s, height: r.height * s });
@@ -3166,14 +3191,14 @@ async function replayPainting(source, target, options = {}) {
3166
3191
  else if (e.kind === "clear") target.clearLayer(e.layerId);
3167
3192
  else if (e.kind === "live-strokes") {
3168
3193
  const d = e.data;
3169
- if (_optionalChain([d, 'optionalAccess', _160 => _160.rasterized])) target.replaceLiveStrokes(e.layerId, null);
3194
+ if (_optionalChain([d, 'optionalAccess', _162 => _162.rasterized])) target.replaceLiveStrokes(e.layerId, null);
3170
3195
  else {
3171
- const list = (_nullishCoalesce(_optionalChain([d, 'optionalAccess', _161 => _161.strokes]), () => ( []))).map((st2) => s === 1 ? st2 : { ...varyStroke(st2, scaleM, { scale: s }), ...st2.stencils ? { stencils: st2.stencils.map((x) => scaleStencil(x, s)) } : {} });
3172
- await target.prepareEffectPaints(list.flatMap((st2) => _optionalChain([st2, 'access', _162 => _162.paint, 'optionalAccess', _163 => _163.type]) === "effect" ? [st2.paint] : []));
3196
+ const list = (_nullishCoalesce(_optionalChain([d, 'optionalAccess', _163 => _163.strokes]), () => ( []))).map((st2) => s === 1 ? st2 : { ...varyStroke(st2, scaleM, { scale: s }), ...st2.stencils ? { stencils: st2.stencils.map((x) => scaleStencil(x, s)) } : {} });
3197
+ await target.prepareEffectPaints(list.flatMap((st2) => _optionalChain([st2, 'access', _164 => _164.paint, 'optionalAccess', _165 => _165.type]) === "effect" ? [st2.paint] : []));
3173
3198
  target.replaceLiveStrokes(e.layerId, list);
3174
3199
  }
3175
3200
  } else if (e.kind === "stickers") {
3176
- const list = (_nullishCoalesce(_optionalChain([e, 'access', _164 => _164.data, 'optionalAccess', _165 => _165.stickers]), () => ( []))).map((x) => s === 1 ? x : { ...x, x: x.x * s, y: x.y * s, size: x.size * s });
3201
+ const list = (_nullishCoalesce(_optionalChain([e, 'access', _166 => _166.data, 'optionalAccess', _167 => _167.stickers]), () => ( []))).map((x) => s === 1 ? x : { ...x, x: x.x * s, y: x.y * s, size: x.size * s });
3177
3202
  target.replaceStickers(e.layerId, list);
3178
3203
  } else target.flattenRelief(e.layerId);
3179
3204
  continue;
@@ -3186,8 +3211,8 @@ async function replayPainting(source, target, options = {}) {
3186
3211
  switch (e.kind) {
3187
3212
  case "dry": {
3188
3213
  const rect = e.data;
3189
- const ids = _optionalChain([e, 'access', _166 => _166.layerId, 'optionalAccess', _167 => _167.split, 'call', _168 => _168(","), 'access', _169 => _169.filter, 'call', _170 => _170(Boolean)]);
3190
- if (_optionalChain([ids, 'optionalAccess', _171 => _171.length])) for (const id of ids) target.dryPaint({ layerId: id, rect: rect ? sr(rect) : void 0 });
3214
+ const ids = _optionalChain([e, 'access', _168 => _168.layerId, 'optionalAccess', _169 => _169.split, 'call', _170 => _170(","), 'access', _171 => _171.filter, 'call', _172 => _172(Boolean)]);
3215
+ if (_optionalChain([ids, 'optionalAccess', _173 => _173.length])) for (const id of ids) target.dryPaint({ layerId: id, rect: rect ? sr(rect) : void 0 });
3191
3216
  else target.dryPaint({ rect: rect ? sr(rect) : void 0 });
3192
3217
  break;
3193
3218
  }
@@ -3218,7 +3243,7 @@ async function replayPainting(source, target, options = {}) {
3218
3243
  strokes++;
3219
3244
  if (!target.getLayer(st.layerId)) continue;
3220
3245
  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)) };
3221
- if (st.brush.engine === "wet" && _optionalChain([st, 'access', _172 => _172.steps, 'optionalAccess', _173 => _173.length]) === st.points.length) {
3246
+ if (st.brush.engine === "wet" && _optionalChain([st, 'access', _174 => _174.steps, 'optionalAccess', _175 => _175.length]) === st.points.length) {
3222
3247
  await target.wetIdle();
3223
3248
  await advanceTo(st.steps[0]);
3224
3249
  const session = target.beginStroke({ ...init, start: st.points[0] });
@@ -3238,7 +3263,7 @@ async function replayPainting(source, target, options = {}) {
3238
3263
  await target.wetIdle();
3239
3264
  target.paintStroke({ ...init, points: st.points });
3240
3265
  }
3241
- await _optionalChain([options, 'access', _174 => _174.onStroke, 'optionalCall', _175 => _175(strokes)]);
3266
+ await _optionalChain([options, 'access', _176 => _176.onStroke, 'optionalCall', _177 => _177(strokes)]);
3242
3267
  }
3243
3268
  void IDENTITY_AFFINE;
3244
3269
  }
@@ -3261,7 +3286,7 @@ function timeLapseVideo(frameCount, width, height, fps, holdMs, name = "Time-lap
3261
3286
  }
3262
3287
  const video = { version: 1, name, width: w, height: h, fps, background: "#000000", assets, tracks: [{ id: "v1", kind: "video", clips }] };
3263
3288
  const durationMs = frameCount ? clips[clips.length - 1].start + clips[clips.length - 1].duration : 0;
3264
- return { video, ffmpeg: _chunkZQIWBJGHcjs.toVideoFfmpeg.call(void 0, video, { output: "timelapse.mp4" }), durationMs };
3289
+ return { video, ffmpeg: _chunkXNZFVYC2cjs.toVideoFfmpeg.call(void 0, video, { output: "timelapse.mp4" }), durationMs };
3265
3290
  }
3266
3291
  async function buildTimeLapse(source, target, options = {}) {
3267
3292
  const maxSide = Math.max(32, Math.min(4096, Math.round(_nullishCoalesce(options.maxSide, () => ( 720)))));
@@ -3283,7 +3308,7 @@ async function buildTimeLapse(source, target, options = {}) {
3283
3308
  wetChunk: wetEvery > 0 ? wetEvery : 0,
3284
3309
  onStroke: (i) => {
3285
3310
  if (i % perFrame === 0 || i === total) shoot(i);
3286
- _optionalChain([options, 'access', _176 => _176.onProgress, 'optionalCall', _177 => _177(total ? i / total : 1)]);
3311
+ _optionalChain([options, 'access', _178 => _178.onProgress, 'optionalCall', _179 => _179(total ? i / total : 1)]);
3287
3312
  },
3288
3313
  onWetSteps: wetEvery > 0 ? () => shoot(-1) : void 0
3289
3314
  });
@@ -3344,7 +3369,7 @@ function checkPaintEffectPlace(d, place) {
3344
3369
  else if (d.uses.includes("filter") && place !== "light") instead = "; run it on a layer's dried paint with apply_effect instead";
3345
3370
  else if (place === "light" && d.uses.some((u) => PAINT_EFFECT_PLACES.layer.includes(u))) instead = "; add it as an effect layer (add_effect_layer) or fill a layer with it (fill_layer_with_effect) instead";
3346
3371
  else if (place === "paper" && d.uses.some((u) => u === "overlay" || u === "title")) instead = "; add it as an effect layer with add_effect_layer instead";
3347
- throw new (0, _chunkJAOSL334cjs.EffectUnsupportedError)(`"${d.id}" (${d.name}) is a ${d.uses.join(" / ") || d.kind} effect, and ${PLACE_WORDS[place]}${instead}.`, d.id);
3372
+ throw new (0, _chunkGHCSC2WPcjs.EffectUnsupportedError)(`"${d.id}" (${d.name}) is a ${d.uses.join(" / ") || d.kind} effect, and ${PLACE_WORDS[place]}${instead}.`, d.id);
3348
3373
  }
3349
3374
  var PAPER_EFFECT_BLENDS = ["multiply", "normal", "overlay", "soft-light", "screen", "color"];
3350
3375
  var paperVersion = 1;
@@ -3370,10 +3395,10 @@ function mixPixels(before, after, amount) {
3370
3395
  }
3371
3396
  return out;
3372
3397
  }
3373
- var PaintEffectsRenderer = (_class9 = class {constructor() { _class9.prototype.__init69.call(this);_class9.prototype.__init70.call(this);_class9.prototype.__init71.call(this); }
3374
- __init69() {this.pool = new (0, _chunkPY4GWSE2cjs.EffectRendererPool)({ maxRenderers: 3 })}
3375
- __init70() {this.descriptions = /* @__PURE__ */ new Map()}
3376
- __init71() {this.provider = null}
3398
+ var PaintEffectsRenderer = (_class9 = class {constructor() { _class9.prototype.__init71.call(this);_class9.prototype.__init72.call(this);_class9.prototype.__init73.call(this); }
3399
+ __init71() {this.pool = new (0, _chunkPY4GWSE2cjs.EffectRendererPool)({ maxRenderers: 3 })}
3400
+ __init72() {this.descriptions = /* @__PURE__ */ new Map()}
3401
+ __init73() {this.provider = null}
3377
3402
  /** Forgets cached descriptions and renderers when the provider changes. */
3378
3403
  follow(provider) {
3379
3404
  if (provider === this.provider) return;
@@ -3458,7 +3483,7 @@ function parseColor(value, what = "color") {
3458
3483
  return value.trim().toLowerCase();
3459
3484
  }
3460
3485
  function rgbaOf(hex) {
3461
- const [r, g, b] = _chunkNKTNLJUJcjs.hexToRgb8.call(void 0, hex);
3486
+ const [r, g, b] = _chunk5BR7LC24cjs.hexToRgb8.call(void 0, hex);
3462
3487
  return [r, g, b, 255];
3463
3488
  }
3464
3489
  function rgbToHex(r, g, b) {
@@ -3471,78 +3496,87 @@ function unionRect(a, b) {
3471
3496
  const y = Math.min(a.y, b.y);
3472
3497
  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 };
3473
3498
  }
3474
- var isPixelLayer = (l) => _optionalChain([l, 'optionalAccess', _178 => _178.type]) === "pixel";
3499
+ var isPixelLayer = (l) => _optionalChain([l, 'optionalAccess', _180 => _180.type]) === "pixel";
3475
3500
  var PaintEditorController = (_class10 = class _PaintEditorController {
3476
3501
 
3477
- __init72() {this.extensions = {}}
3478
- __init73() {this.undoStack = []}
3479
- __init74() {this.redoStack = []}
3502
+ __init74() {this.extensions = {}}
3503
+ __init75() {this.undoStack = []}
3504
+ __init76() {this.redoStack = []}
3480
3505
 
3481
3506
 
3482
3507
 
3483
3508
  /** The library list in the state (the same array until the user brushes change, so thumbnails are not redrawn). */
3484
- __init75() {this.library = null}
3509
+ __init77() {this.library = null}
3485
3510
 
3486
- __init76() {this.secondaryColor = "#ffffff"}
3511
+ __init78() {this.secondaryColor = "#ffffff"}
3487
3512
  /** Gradient paint chosen with `setPaint` (`null`: the paint colour). */
3488
- __init77() {this.gradient = null}
3513
+ __init79() {this.gradient = null}
3489
3514
  /** Effect paint chosen with `setEffectPaint` (rendered), and one still rendering. */
3490
- __init78() {this.effectPaint = null}
3491
- __init79() {this.effectPaintPending = null}
3515
+ __init80() {this.effectPaint = null}
3516
+ __init81() {this.effectPaintPending = null}
3492
3517
  /** Changes whenever the paint is chosen, so an effect paint that finishes rendering late does not take over. */
3493
- __init80() {this.paintEpoch = 0}
3518
+ __init82() {this.paintEpoch = 0}
3494
3519
  /** Rendered effect paints by `effectPaintKey` (most recently used last). */
3495
- __init81() {this.effectPaintPixels = /* @__PURE__ */ new Map()}
3496
- __init82() {this.mixerLoad = _chunkPQ3H2AANcjs.EMPTY_MIXER_LOAD}
3497
- __init83() {this.view = { ...DEFAULT_VIEW, pan: { ...DEFAULT_VIEW.pan } }}
3520
+ __init83() {this.effectPaintPixels = /* @__PURE__ */ new Map()}
3521
+ __init84() {this.mixerLoad = _chunkPQ3H2AANcjs.EMPTY_MIXER_LOAD}
3522
+ __init85() {this.view = { ...DEFAULT_VIEW, pan: { ...DEFAULT_VIEW.pan } }}
3498
3523
 
3499
- __init84() {this.selectedStroke = null}
3500
- __init85() {this.selectedSticker = null}
3524
+ __init86() {this.selectedStroke = null}
3525
+ __init87() {this.selectedSticker = null}
3501
3526
  /** A sticker drag in progress (`previewSticker`): the document before it, so the drop undoes in one step, and the one it showed last. */
3502
- __init86() {this.stickerPreview = null}
3527
+ __init88() {this.stickerPreview = null}
3503
3528
 
3504
- __init87() {this.listeners = /* @__PURE__ */ new Set()}
3505
- __init88() {this.version = 0}
3506
- __init89() {this.cached = null}
3507
- __init90() {this.session = null}
3508
- __init91() {this.live = null}
3509
- __init92() {this.liveLayers = null}
3510
- __init93() {this.dirty = "all"}
3511
- __init94() {this.seedCounter = 1}
3512
- __init95() {this.strokeCounter = 1}
3529
+ __init89() {this.listeners = /* @__PURE__ */ new Set()}
3530
+ __init90() {this.version = 0}
3531
+ __init91() {this.cached = null}
3532
+ __init92() {this.session = null}
3533
+ __init93() {this.live = null}
3534
+ __init94() {this.liveLayers = null}
3535
+ __init95() {this.dirty = "all"}
3536
+ __init96() {this.seedCounter = 1}
3537
+ __init97() {this.strokeCounter = 1}
3538
+ /** Live effect paint: playing and the frame rate cap (editor state), and the time the view shows. */
3539
+ __init98() {this.effectPlaybackState = { playing: true, fps: 30 }}
3540
+ __init99() {this.effectTime = 0}
3541
+ /** While a frame is drawn: the time live effect strokes are drawn at (else their own time). */
3542
+ __init100() {this.liveEffectAt = null}
3543
+ /** The view's stroke layers at `effectTime`, each with the document surface it was drawn from (stale once that changes). */
3544
+ __init101() {this.animatedLayers = /* @__PURE__ */ new Map()}
3545
+ /** `renderAnimationFrame` / `withEffectTime`: layer surfaces at another time, for one render. */
3546
+ __init102() {this.frameOverride = null}
3513
3547
  /** 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`). */
3514
- __init96() {this.paintedBounds = /* @__PURE__ */ new WeakMap()}
3548
+ __init103() {this.paintedBounds = /* @__PURE__ */ new WeakMap()}
3515
3549
 
3516
- __init97() {this.swatches = DEFAULT_SWATCHES.map((s) => ({ ...s }))}
3517
- __init98() {this.pad = new MixingPad()}
3518
- __init99() {this.savedPads = []}
3519
- __init100() {this.nextPadId = 1}
3520
- __init101() {this.tracingVersion = 1}
3521
- __init102() {this.tracingCache = null}
3522
- __init103() {this.imagePixels = /* @__PURE__ */ new Map()}
3523
- __init104() {this.nextReferenceId = 1}
3524
- __init105() {this.viewCompositor = createPaintCompositor()}
3525
- __init106() {this.exportCompositor = createPaintCompositor()}
3550
+ __init104() {this.swatches = DEFAULT_SWATCHES.map((s) => ({ ...s }))}
3551
+ __init105() {this.pad = new MixingPad()}
3552
+ __init106() {this.savedPads = []}
3553
+ __init107() {this.nextPadId = 1}
3554
+ __init108() {this.tracingVersion = 1}
3555
+ __init109() {this.tracingCache = null}
3556
+ __init110() {this.imagePixels = /* @__PURE__ */ new Map()}
3557
+ __init111() {this.nextReferenceId = 1}
3558
+ __init112() {this.viewCompositor = createPaintCompositor()}
3559
+ __init113() {this.exportCompositor = createPaintCompositor()}
3526
3560
  /** Wet media: the simulation, its settings and time. */
3527
3561
 
3528
3562
 
3529
3563
  /** Where the light comes from for thick paint (saved with the document, not undo steps). */
3530
- __init107() {this.lighting = { ...DEFAULT_LIGHTING }}
3531
- __init108() {this.litCaches = /* @__PURE__ */ new Map()}
3564
+ __init114() {this.lighting = { ...DEFAULT_LIGHTING }}
3565
+ __init115() {this.litCaches = /* @__PURE__ */ new Map()}
3532
3566
  /** The live impasto stroke's channels. */
3533
- __init109() {this.liveThick = null}
3567
+ __init116() {this.liveThick = null}
3534
3568
  /** Set while an operation that changes wet paint runs: the simulation before it (for undo). */
3535
- __init110() {this.wetOp = null}
3569
+ __init117() {this.wetOp = null}
3536
3570
  /** The effects provider slot (see `setEffectsProvider`). */
3537
- __init111() {this.effects = new (0, _chunkJAOSL334cjs.EffectsSlot)()}
3538
- __init112() {this.effectsRenderer = new PaintEffectsRenderer()}
3539
- __init113() {this.paperEffectNodeCache = null}
3540
- constructor(options = {}) {;_class10.prototype.__init72.call(this);_class10.prototype.__init73.call(this);_class10.prototype.__init74.call(this);_class10.prototype.__init75.call(this);_class10.prototype.__init76.call(this);_class10.prototype.__init77.call(this);_class10.prototype.__init78.call(this);_class10.prototype.__init79.call(this);_class10.prototype.__init80.call(this);_class10.prototype.__init81.call(this);_class10.prototype.__init82.call(this);_class10.prototype.__init83.call(this);_class10.prototype.__init84.call(this);_class10.prototype.__init85.call(this);_class10.prototype.__init86.call(this);_class10.prototype.__init87.call(this);_class10.prototype.__init88.call(this);_class10.prototype.__init89.call(this);_class10.prototype.__init90.call(this);_class10.prototype.__init91.call(this);_class10.prototype.__init92.call(this);_class10.prototype.__init93.call(this);_class10.prototype.__init94.call(this);_class10.prototype.__init95.call(this);_class10.prototype.__init96.call(this);_class10.prototype.__init97.call(this);_class10.prototype.__init98.call(this);_class10.prototype.__init99.call(this);_class10.prototype.__init100.call(this);_class10.prototype.__init101.call(this);_class10.prototype.__init102.call(this);_class10.prototype.__init103.call(this);_class10.prototype.__init104.call(this);_class10.prototype.__init105.call(this);_class10.prototype.__init106.call(this);_class10.prototype.__init107.call(this);_class10.prototype.__init108.call(this);_class10.prototype.__init109.call(this);_class10.prototype.__init110.call(this);_class10.prototype.__init111.call(this);_class10.prototype.__init112.call(this);_class10.prototype.__init113.call(this);_class10.prototype.__init114.call(this);_class10.prototype.__init115.call(this);_class10.prototype.__init116.call(this);_class10.prototype.__init117.call(this);
3571
+ __init118() {this.effects = new (0, _chunkGHCSC2WPcjs.EffectsSlot)()}
3572
+ __init119() {this.effectsRenderer = new PaintEffectsRenderer()}
3573
+ __init120() {this.paperEffectNodeCache = null}
3574
+ constructor(options = {}) {;_class10.prototype.__init74.call(this);_class10.prototype.__init75.call(this);_class10.prototype.__init76.call(this);_class10.prototype.__init77.call(this);_class10.prototype.__init78.call(this);_class10.prototype.__init79.call(this);_class10.prototype.__init80.call(this);_class10.prototype.__init81.call(this);_class10.prototype.__init82.call(this);_class10.prototype.__init83.call(this);_class10.prototype.__init84.call(this);_class10.prototype.__init85.call(this);_class10.prototype.__init86.call(this);_class10.prototype.__init87.call(this);_class10.prototype.__init88.call(this);_class10.prototype.__init89.call(this);_class10.prototype.__init90.call(this);_class10.prototype.__init91.call(this);_class10.prototype.__init92.call(this);_class10.prototype.__init93.call(this);_class10.prototype.__init94.call(this);_class10.prototype.__init95.call(this);_class10.prototype.__init96.call(this);_class10.prototype.__init97.call(this);_class10.prototype.__init98.call(this);_class10.prototype.__init99.call(this);_class10.prototype.__init100.call(this);_class10.prototype.__init101.call(this);_class10.prototype.__init102.call(this);_class10.prototype.__init103.call(this);_class10.prototype.__init104.call(this);_class10.prototype.__init105.call(this);_class10.prototype.__init106.call(this);_class10.prototype.__init107.call(this);_class10.prototype.__init108.call(this);_class10.prototype.__init109.call(this);_class10.prototype.__init110.call(this);_class10.prototype.__init111.call(this);_class10.prototype.__init112.call(this);_class10.prototype.__init113.call(this);_class10.prototype.__init114.call(this);_class10.prototype.__init115.call(this);_class10.prototype.__init116.call(this);_class10.prototype.__init117.call(this);_class10.prototype.__init118.call(this);_class10.prototype.__init119.call(this);_class10.prototype.__init120.call(this);_class10.prototype.__init121.call(this);_class10.prototype.__init122.call(this);_class10.prototype.__init123.call(this);_class10.prototype.__init124.call(this);
3541
3575
  this.historyLimit = Math.max(1, _nullishCoalesce(options.historyLimit, () => ( 200)));
3542
3576
  this.doc = createPaintDocument({ width: options.width, height: options.height, dpi: options.dpi, paper: this.resolvePaper(options.paper) });
3543
- this.userBrushes = (_nullishCoalesce(options.brushes, () => ( []))).map((b) => _chunkNKTNLJUJcjs.normalizePaintBrush.call(void 0, { ...b, builtin: false }));
3544
- const start = _nullishCoalesce(this.findBrush(_nullishCoalesce(options.brushId, () => ( _chunkNKTNLJUJcjs.DEFAULT_BRUSH_ID))), () => ( this.findBrush(_chunkNKTNLJUJcjs.DEFAULT_BRUSH_ID)));
3545
- this.brush = _chunkNKTNLJUJcjs.normalizePaintBrush.call(void 0, start);
3577
+ this.userBrushes = (_nullishCoalesce(options.brushes, () => ( []))).map((b) => _chunk5BR7LC24cjs.normalizePaintBrush.call(void 0, { ...b, builtin: false }));
3578
+ const start = _nullishCoalesce(this.findBrush(_nullishCoalesce(options.brushId, () => ( _chunk5BR7LC24cjs.DEFAULT_BRUSH_ID))), () => ( this.findBrush(_chunk5BR7LC24cjs.DEFAULT_BRUSH_ID)));
3579
+ this.brush = _chunk5BR7LC24cjs.normalizePaintBrush.call(void 0, start);
3546
3580
  this.color = options.color ? parseColor(options.color) : "#1f2937";
3547
3581
  this.hand = options.hand === "left" ? "left" : "right";
3548
3582
  this.encodeImage = options.encodeImage;
@@ -3553,7 +3587,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3553
3587
  canvas: () => this.doc.canvas,
3554
3588
  paper: () => this.doc.paper,
3555
3589
  layerSurface: (id) => {
3556
- const l = _optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _179 => _179.layer]);
3590
+ const l = _optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _181 => _181.layer]);
3557
3591
  return isPixelLayer(l) ? l.surface : null;
3558
3592
  },
3559
3593
  updateSurfaces: (surfaces, rects) => {
@@ -3567,7 +3601,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3567
3601
  },
3568
3602
  options.wet
3569
3603
  );
3570
- this.wet.onDriverDone = () => _optionalChain([this, 'access', _180 => _180.session, 'optionalAccess', _181 => _181.completeWetEnd, 'call', _182 => _182()]);
3604
+ this.wet.onDriverDone = () => _optionalChain([this, 'access', _182 => _182.session, 'optionalAccess', _183 => _183.completeWetEnd, 'call', _184 => _184()]);
3571
3605
  }
3572
3606
  // --- State and events ----------------------------------------------------------
3573
3607
  subscribe(listener) {
@@ -3589,7 +3623,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3589
3623
  this.cached = {
3590
3624
  document: this.doc,
3591
3625
  brush: this.brush,
3592
- brushes: this.library ??= [..._chunkNKTNLJUJcjs.BUILTIN_BRUSHES, ...this.userBrushes],
3626
+ brushes: this.library ??= [..._chunk5BR7LC24cjs.BUILTIN_BRUSHES, ...this.userBrushes],
3593
3627
  color: this.color,
3594
3628
  secondaryColor: this.secondaryColor,
3595
3629
  paint: _nullishCoalesce(this.gradient, () => ( { type: "color", color: this.color })),
@@ -3598,12 +3632,13 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3598
3632
  mixerLoad: this.mixerLoad,
3599
3633
  view: this.view,
3600
3634
  hand: this.hand,
3635
+ effectPlayback: { ...this.effectPlaybackState, time: this.effectTime },
3601
3636
  selectedStroke: this.selectedStroke,
3602
3637
  selectedSticker: this.selectedSticker,
3603
3638
  canUndo: this.undoStack.length > 0 && !this.session,
3604
3639
  canRedo: this.redoStack.length > 0 && !this.session,
3605
- undoLabel: _nullishCoalesce(_optionalChain([last, 'optionalAccess', _183 => _183.label]), () => ( null)),
3606
- redoLabel: _nullishCoalesce(_optionalChain([next, 'optionalAccess', _184 => _184.label]), () => ( null)),
3640
+ undoLabel: _nullishCoalesce(_optionalChain([last, 'optionalAccess', _185 => _185.label]), () => ( null)),
3641
+ redoLabel: _nullishCoalesce(_optionalChain([next, 'optionalAccess', _186 => _186.label]), () => ( null)),
3607
3642
  guides: this.guides,
3608
3643
  swatches: this.swatches,
3609
3644
  mixingPadVersion: this.pad.version,
@@ -3616,10 +3651,10 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3616
3651
  overlay: this.wet.overlay,
3617
3652
  instantDry: this.wet.instantDry,
3618
3653
  speed: this.wet.speed,
3619
- clock: _nullishCoalesce(_optionalChain([this, 'access', _185 => _185.wet, 'access', _186 => _186.world, 'optionalAccess', _187 => _187.clock]), () => ( 0)),
3654
+ clock: _nullishCoalesce(_optionalChain([this, 'access', _187 => _187.wet, 'access', _188 => _188.world, 'optionalAccess', _189 => _189.clock]), () => ( 0)),
3620
3655
  tilt: { ...this.wet.tilt },
3621
3656
  gpu: this.wet.gpuMode,
3622
- gpuActive: Boolean(_optionalChain([this, 'access', _188 => _188.wet, 'access', _189 => _189.world, 'optionalAccess', _190 => _190.gpuActive]))
3657
+ gpuActive: Boolean(_optionalChain([this, 'access', _190 => _190.wet, 'access', _191 => _191.world, 'optionalAccess', _192 => _192.gpuActive]))
3623
3658
  },
3624
3659
  version: this.version
3625
3660
  };
@@ -3638,7 +3673,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3638
3673
  return d;
3639
3674
  }
3640
3675
  // --- History -------------------------------------------------------------------
3641
- __init114() {this.docRevision = 0}
3676
+ __init121() {this.docRevision = 0}
3642
3677
  /**
3643
3678
  * Bumped on every change to the painting (a committed or amended step, undo, redo, opening a
3644
3679
  * document), not on wet-paint frames or view changes. `createPaintEditorDocument` uses it.
@@ -3721,9 +3756,9 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3721
3756
  return wetIds;
3722
3757
  }
3723
3758
  /** Records a wet event (for replays) in the document being built. */
3724
- __init115() {this.pendingWetEvents = []}
3759
+ __init122() {this.pendingWetEvents = []}
3725
3760
  logWet(e) {
3726
- this.pendingWetEvents.push({ clock: _nullishCoalesce(_optionalChain([this, 'access', _191 => _191.wet, 'access', _192 => _192.world, 'optionalAccess', _193 => _193.clock]), () => ( 0)), at: this.doc.strokes.length, ...e });
3761
+ this.pendingWetEvents.push({ clock: _nullishCoalesce(_optionalChain([this, 'access', _193 => _193.wet, 'access', _194 => _194.world, 'optionalAccess', _195 => _195.clock]), () => ( 0)), at: this.doc.strokes.length, ...e });
3727
3762
  }
3728
3763
  /** The document with a paint event appended (for replays). */
3729
3764
  withPaintEvent(doc, e) {
@@ -3784,7 +3819,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3784
3819
  // --- Canvas and paper ----------------------------------------------------------
3785
3820
  resolvePaper(paper) {
3786
3821
  if (typeof paper === "string") {
3787
- const p = _chunkNKTNLJUJcjs.paperPreset.call(void 0, paper);
3822
+ const p = _chunk5BR7LC24cjs.paperPreset.call(void 0, paper);
3788
3823
  if (!p) throw new PaintEditorError(`Unknown paper "${paper}". Call list_papers for the ids.`);
3789
3824
  return p;
3790
3825
  }
@@ -3867,7 +3902,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3867
3902
  }
3868
3903
  let next = { ...shiftDocument(this.withWetEvents(this.doc), left, top), canvas: { ...was, width, height } };
3869
3904
  for (const id of keptWet) {
3870
- const l = _optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, next.layers, id), 'optionalAccess', _194 => _194.layer]);
3905
+ const l = _optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, next.layers, id), 'optionalAccess', _196 => _196.layer]);
3871
3906
  if (isPixelLayer(l)) next = { ...next, layers: _chunkHB4ICNNAcjs.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 } })) };
3872
3907
  }
3873
3908
  if (this.wet.world) {
@@ -3895,23 +3930,23 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3895
3930
  this.requireIdle("changing the paper");
3896
3931
  let base = this.doc.paper;
3897
3932
  if (update.preset !== void 0 && update.preset !== this.doc.paper.preset) {
3898
- const p = _chunkNKTNLJUJcjs.paperPreset.call(void 0, update.preset);
3933
+ const p = _chunk5BR7LC24cjs.paperPreset.call(void 0, update.preset);
3899
3934
  if (!p) throw new PaintEditorError(`Unknown paper "${update.preset}". Call list_papers for the ids.`);
3900
3935
  base = p;
3901
3936
  }
3902
3937
  const { preset: _p, ...rest } = update;
3903
3938
  if (rest.color !== void 0) parseColor(rest.color, "paper color");
3904
- const paper = _chunkNKTNLJUJcjs.normalizePaper.call(void 0, { ...rest, preset: base.preset, offset: _nullishCoalesce(rest.offset, () => ( this.doc.paper.offset)) }, base);
3939
+ const paper = _chunk5BR7LC24cjs.normalizePaper.call(void 0, { ...rest, preset: base.preset, offset: _nullishCoalesce(rest.offset, () => ( this.doc.paper.offset)) }, base);
3905
3940
  const changedKeys = Object.keys(rest).filter((k) => k !== "name");
3906
3941
  if (changedKeys.length && update.preset === void 0) paper.preset = base.preset;
3907
3942
  if (this.wet.world) this.beginWetOp();
3908
3943
  this.commit("Paper", { ...this.doc, paper });
3909
3944
  this.wet.paperChanged();
3910
- return _chunkNKTNLJUJcjs.clonePaper.call(void 0, paper);
3945
+ return _chunk5BR7LC24cjs.clonePaper.call(void 0, paper);
3911
3946
  }
3912
3947
  // --- Layers --------------------------------------------------------------------
3913
3948
  getLayer(id) {
3914
- return _optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _195 => _195.layer]);
3949
+ return _optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _197 => _197.layer]);
3915
3950
  }
3916
3951
  /** The active pixel layer (or `undefined`). */
3917
3952
  getActiveLayer() {
@@ -3930,7 +3965,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3930
3965
  walk(this.doc.layers, null, 0);
3931
3966
  return out;
3932
3967
  }
3933
- describeLayer(l, parentId = _nullishCoalesce(_optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, this.doc.layers, l.id), 'optionalAccess', _196 => _196.parent, 'optionalAccess', _197 => _197.id]), () => ( null)), depth = _nullishCoalesce(_optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, this.doc.layers, l.id), 'optionalAccess', _198 => _198.path, 'access', _199 => _199.length]), () => ( 0))) {
3968
+ describeLayer(l, parentId = _nullishCoalesce(_optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, this.doc.layers, l.id), 'optionalAccess', _198 => _198.parent, 'optionalAccess', _199 => _199.id]), () => ( null)), depth = _nullishCoalesce(_optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, this.doc.layers, l.id), 'optionalAccess', _200 => _200.path, 'access', _201 => _201.length]), () => ( 0))) {
3934
3969
  let bounds = null;
3935
3970
  if (l.type === "pixel") {
3936
3971
  const b = _chunk474IQG74cjs.contentBounds.call(void 0, l.surface);
@@ -3947,7 +3982,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3947
3982
  locks: { ..._nullishCoalesce(l.locks, () => ( {})) },
3948
3983
  active: l.id === this.doc.activeLayerId,
3949
3984
  bounds,
3950
- ..._optionalChain([this, 'access', _200 => _200.doc, 'access', _201 => _201.liveStrokes, 'optionalAccess', _202 => _202[l.id]]) ? { liveStrokes: this.doc.liveStrokes[l.id].length } : {},
3985
+ ..._optionalChain([this, 'access', _202 => _202.doc, 'access', _203 => _203.liveStrokes, 'optionalAccess', _204 => _204[l.id]]) ? { liveStrokes: this.doc.liveStrokes[l.id].length } : {},
3951
3986
  parentId,
3952
3987
  depth
3953
3988
  };
@@ -3979,7 +4014,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3979
4014
  this.requireIdle("adding a layer");
3980
4015
  const count = _chunkHB4ICNNAcjs.flattenLayers.call(void 0, this.doc.layers).length;
3981
4016
  const type = _nullishCoalesce(options.type, () => ( "pixel"));
3982
- const name = _optionalChain([options, 'access', _203 => _203.name, 'optionalAccess', _204 => _204.trim, 'call', _205 => _205()]) || (type === "group" ? `Group ${count + 1}` : type === "strokes" ? `Strokes ${count + 1}` : `Layer ${count + 1}`);
4017
+ const name = _optionalChain([options, 'access', _205 => _205.name, 'optionalAccess', _206 => _206.trim, 'call', _207 => _207()]) || (type === "group" ? `Group ${count + 1}` : type === "strokes" ? `Strokes ${count + 1}` : `Layer ${count + 1}`);
3983
4018
  const layer = type === "group" ? { type: "group", id: newPaintLayerId(), name, visible: true, opacity: 1, blend: "pass-through", children: [] } : createPaintLayer(name);
3984
4019
  let parentId = null;
3985
4020
  let index;
@@ -3991,7 +4026,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3991
4026
  } else if (above) {
3992
4027
  const loc = _chunkHB4ICNNAcjs.findLayer.call(void 0, this.doc.layers, above);
3993
4028
  if (!loc) throw new PaintEditorError(`Unknown layer "${above}". Call list_layers for the ids.`);
3994
- parentId = _nullishCoalesce(_optionalChain([loc, 'access', _206 => _206.parent, 'optionalAccess', _207 => _207.id]), () => ( null));
4029
+ parentId = _nullishCoalesce(_optionalChain([loc, 'access', _208 => _208.parent, 'optionalAccess', _209 => _209.id]), () => ( null));
3995
4030
  index = loc.index + 1;
3996
4031
  }
3997
4032
  const layers = _chunkHB4ICNNAcjs.insertLayer.call(void 0, this.doc.layers, layer, parentId, index);
@@ -4032,7 +4067,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4032
4067
  }
4033
4068
  const layers = _chunkHB4ICNNAcjs.mapLayer.call(void 0, this.doc.layers, id, () => null);
4034
4069
  let active = this.doc.activeLayerId;
4035
- if (active && !_chunkHB4ICNNAcjs.findLayer.call(void 0, layers, active)) active = _nullishCoalesce(_optionalChain([_chunkHB4ICNNAcjs.flattenLayers.call(void 0, layers), 'access', _208 => _208.filter, 'call', _209 => _209((x) => x.type === "pixel"), 'access', _210 => _210.pop, 'call', _211 => _211(), 'optionalAccess', _212 => _212.id]), () => ( null));
4070
+ if (active && !_chunkHB4ICNNAcjs.findLayer.call(void 0, layers, active)) active = _nullishCoalesce(_optionalChain([_chunkHB4ICNNAcjs.flattenLayers.call(void 0, layers), 'access', _210 => _210.filter, 'call', _211 => _211((x) => x.type === "pixel"), 'access', _212 => _212.pop, 'call', _213 => _213(), 'optionalAccess', _214 => _214.id]), () => ( null));
4036
4071
  this.commit("Remove layer", { ...this.doc, layers, activeLayerId: active, ...this.thickWithout(_chunkHB4ICNNAcjs.flattenLayers.call(void 0, [l]).map((x) => x.id)), ...this.stickersWithout(_chunkHB4ICNNAcjs.flattenLayers.call(void 0, [l]).map((x) => x.id)), ...this.liveStrokesWithout(_chunkHB4ICNNAcjs.flattenLayers.call(void 0, [l]).map((x) => x.id)) });
4037
4072
  return { removed: id, activeLayerId: active };
4038
4073
  }
@@ -4055,7 +4090,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4055
4090
  return l.type === "group" ? { ...l, id: id2, children: l.children.map(copy) } : { ...l, id: id2 };
4056
4091
  };
4057
4092
  const dup = { ...copy(loc.layer), name: `${loc.layer.name} copy` };
4058
- const layers = _chunkHB4ICNNAcjs.insertLayer.call(void 0, this.doc.layers, dup, _nullishCoalesce(_optionalChain([loc, 'access', _213 => _213.parent, 'optionalAccess', _214 => _214.id]), () => ( null)), loc.index + 1);
4093
+ const layers = _chunkHB4ICNNAcjs.insertLayer.call(void 0, this.doc.layers, dup, _nullishCoalesce(_optionalChain([loc, 'access', _215 => _215.parent, 'optionalAccess', _216 => _216.id]), () => ( null)), loc.index + 1);
4059
4094
  this.commit("Duplicate layer", this.withWetEvents({ ...this.doc, layers, activeLayerId: dup.id, ...this.doc.thick ? { thick } : {}, ...this.doc.stickers ? { stickers } : {}, ...this.doc.liveStrokes ? { liveStrokes } : {} }));
4060
4095
  return this.describeLayer(dup);
4061
4096
  }
@@ -4064,7 +4099,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4064
4099
  this.requireIdle("moving a layer");
4065
4100
  const loc = _chunkHB4ICNNAcjs.findLayer.call(void 0, this.doc.layers, id);
4066
4101
  if (!loc) throw new PaintEditorError(`Unknown layer "${id}". Call list_layers for the ids.`);
4067
- const target = parentId === void 0 ? _nullishCoalesce(_optionalChain([loc, 'access', _215 => _215.parent, 'optionalAccess', _216 => _216.id]), () => ( null)) : parentId;
4102
+ const target = parentId === void 0 ? _nullishCoalesce(_optionalChain([loc, 'access', _217 => _217.parent, 'optionalAccess', _218 => _218.id]), () => ( null)) : parentId;
4068
4103
  if (target) {
4069
4104
  const g = this.requireLayer(target);
4070
4105
  if (g.type !== "group") throw new PaintEditorError(`Layer "${g.name}" is not a group; pass a group id as parentId.`);
@@ -4083,7 +4118,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4083
4118
  const pre = _chunkHB4ICNNAcjs.findLayer.call(void 0, this.doc.layers, id);
4084
4119
  if (pre) {
4085
4120
  const sib = pre.parent ? pre.parent.children : this.doc.layers;
4086
- this.dryLayersFirst([id, _optionalChain([sib, 'access', _217 => _217[pre.index - 1], 'optionalAccess', _218 => _218.id])].filter((x) => Boolean(x)));
4121
+ this.dryLayersFirst([id, _optionalChain([sib, 'access', _219 => _219[pre.index - 1], 'optionalAccess', _220 => _220.id])].filter((x) => Boolean(x)));
4087
4122
  }
4088
4123
  const loc = _chunkHB4ICNNAcjs.findLayer.call(void 0, this.doc.layers, id);
4089
4124
  if (!loc) throw new PaintEditorError(`Unknown layer "${id}". Call list_layers for the ids.`);
@@ -4114,7 +4149,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4114
4149
  this.wet.world.removeLane(l.id);
4115
4150
  }
4116
4151
  const bounds = this.describeLayer(l).bounds;
4117
- this.commit("Clear layer", this.withPaintEvent({ ...this.doc, layers: _chunkHB4ICNNAcjs.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', _219 => _219.doc, 'access', _220 => _220.liveStrokes, 'optionalAccess', _221 => _221[l.id]]) ? { liveStrokes: { ...this.doc.liveStrokes, [l.id]: [] } } : {} }, { kind: "clear", layerId: l.id }));
4152
+ this.commit("Clear layer", this.withPaintEvent({ ...this.doc, layers: _chunkHB4ICNNAcjs.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', _221 => _221.doc, 'access', _222 => _222.liveStrokes, 'optionalAccess', _223 => _223[l.id]]) ? { liveStrokes: { ...this.doc.liveStrokes, [l.id]: [] } } : {} }, { kind: "clear", layerId: l.id }));
4118
4153
  return { layerId: l.id, bounds };
4119
4154
  }
4120
4155
  /**
@@ -4124,8 +4159,8 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4124
4159
  fillLayer(options = {}) {
4125
4160
  this.requireIdle("filling");
4126
4161
  const fillTarget = this.paintTarget(options.layerId, "fill");
4127
- if (_optionalChain([this, 'access', _222 => _222.doc, 'access', _223 => _223.stickers, 'optionalAccess', _224 => _224[fillTarget.id], 'optionalAccess', _225 => _225.length])) throw new PaintEditorError(`Layer "${fillTarget.name}" is a sticker layer; fill another layer (add_layer).`);
4128
- if (_optionalChain([this, 'access', _226 => _226.doc, 'access', _227 => _227.liveStrokes, 'optionalAccess', _228 => _228[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).`);
4162
+ if (_optionalChain([this, 'access', _224 => _224.doc, 'access', _225 => _225.stickers, 'optionalAccess', _226 => _226[fillTarget.id], 'optionalAccess', _227 => _227.length])) throw new PaintEditorError(`Layer "${fillTarget.name}" is a sticker layer; fill another layer (add_layer).`);
4163
+ if (_optionalChain([this, 'access', _228 => _228.doc, 'access', _229 => _229.liveStrokes, 'optionalAccess', _230 => _230[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).`);
4129
4164
  this.dryLayersFirst([_nullishCoalesce(_nullishCoalesce(options.layerId, () => ( this.doc.activeLayerId)), () => ( ""))]);
4130
4165
  const l = this.paintTarget(options.layerId, "fill");
4131
4166
  const color = options.color === void 0 ? this.color : parseColor(options.color);
@@ -4166,7 +4201,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4166
4201
  const tiles = new Map(base.tiles);
4167
4202
  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 })) {
4168
4203
  const key = _chunk474IQG74cjs.tileKey.call(void 0, tx, ty);
4169
- const src = _nullishCoalesce(_optionalChain([base, 'access', _229 => _229.tiles, 'access', _230 => _230.get, 'call', _231 => _231(key), 'optionalAccess', _232 => _232.data]), () => ( new Uint8ClampedArray(_chunk474IQG74cjs.TILE * _chunk474IQG74cjs.TILE * 4)));
4204
+ const src = _nullishCoalesce(_optionalChain([base, 'access', _231 => _231.tiles, 'access', _232 => _232.get, 'call', _233 => _233(key), 'optionalAccess', _234 => _234.data]), () => ( new Uint8ClampedArray(_chunk474IQG74cjs.TILE * _chunk474IQG74cjs.TILE * 4)));
4170
4205
  const tile = _chunk474IQG74cjs.finishTile.call(void 0, _chunkPQ3H2AANcjs.applyStrokeToTile.call(void 0, coverage, src, 4, tx, ty, apply), 4, 0);
4171
4206
  if (tile) tiles.set(key, tile);
4172
4207
  else tiles.delete(key);
@@ -4199,7 +4234,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4199
4234
  }
4200
4235
  /** The effect a layer is drawn from, or `undefined` for other layers. */
4201
4236
  getEffectLayer(layerId) {
4202
- return _chunkHB4ICNNAcjs.findLayer.call(void 0, this.doc.layers, layerId) ? _optionalChain([this, 'access', _233 => _233.doc, 'access', _234 => _234.effectLayers, 'optionalAccess', _235 => _235[layerId]]) : void 0;
4237
+ return _chunkHB4ICNNAcjs.findLayer.call(void 0, this.doc.layers, layerId) ? _optionalChain([this, 'access', _235 => _235.doc, 'access', _236 => _236.effectLayers, 'optionalAccess', _237 => _237[layerId]]) : void 0;
4203
4238
  }
4204
4239
  /** The effect paper (without its pixels), or `null`. */
4205
4240
  getPaperEffect() {
@@ -4217,7 +4252,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4217
4252
  if (v === null) merged[k] = d.defaults[k];
4218
4253
  else given[k] = v;
4219
4254
  }
4220
- return { ...merged, ..._chunkJAOSL334cjs.resolveEffectValues.call(void 0, { ...d, defaults: merged }, given) };
4255
+ return { ...merged, ..._chunkGHCSC2WPcjs.resolveEffectValues.call(void 0, { ...d, defaults: merged }, given) };
4221
4256
  }
4222
4257
  /** Renders a generator, overlay or title effect at the canvas size. */
4223
4258
  renderEffectCanvas(d, values, time = 0) {
@@ -4236,8 +4271,8 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4236
4271
  /** A pixel layer that takes effect pixels: unlocked, visible, no sticker layer, no wet paint. */
4237
4272
  effectTarget(layerId, what) {
4238
4273
  const l = this.paintTarget(layerId, what);
4239
- if (_optionalChain([this, 'access', _236 => _236.doc, 'access', _237 => _237.stickers, 'optionalAccess', _238 => _238[l.id], 'optionalAccess', _239 => _239.length])) throw new PaintEditorError(`Layer "${l.name}" is a sticker layer; ${what} another layer (add_layer).`);
4240
- if (_optionalChain([this, 'access', _240 => _240.doc, 'access', _241 => _241.liveStrokes, 'optionalAccess', _242 => _242[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).`);
4274
+ if (_optionalChain([this, 'access', _238 => _238.doc, 'access', _239 => _239.stickers, 'optionalAccess', _240 => _240[l.id], 'optionalAccess', _241 => _241.length])) throw new PaintEditorError(`Layer "${l.name}" is a sticker layer; ${what} another layer (add_layer).`);
4275
+ if (_optionalChain([this, 'access', _242 => _242.doc, 'access', _243 => _243.liveStrokes, 'optionalAccess', _244 => _244[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).`);
4241
4276
  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.`);
4242
4277
  return l;
4243
4278
  }
@@ -4276,8 +4311,8 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4276
4311
  const was = this.doc.paperEffect;
4277
4312
  const paperEffect = {
4278
4313
  ...this.sourceOf(d, values, options.time),
4279
- opacity: _nullishCoalesce(_nullishCoalesce(options.opacity, () => ( _optionalChain([was, 'optionalAccess', _243 => _243.opacity]))), () => ( 1)),
4280
- blend: _nullishCoalesce(_nullishCoalesce(options.blend, () => ( _optionalChain([was, 'optionalAccess', _244 => _244.blend]))), () => ( "multiply")),
4314
+ opacity: _nullishCoalesce(_nullishCoalesce(options.opacity, () => ( _optionalChain([was, 'optionalAccess', _245 => _245.opacity]))), () => ( 1)),
4315
+ blend: _nullishCoalesce(_nullishCoalesce(options.blend, () => ( _optionalChain([was, 'optionalAccess', _246 => _246.blend]))), () => ( "multiply")),
4281
4316
  image: { width: pixels.width, height: pixels.height, data: new Uint8ClampedArray(pixels.data) },
4282
4317
  version: nextPaperEffectVersion()
4283
4318
  };
@@ -4330,8 +4365,8 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4330
4365
  const above = _nullishCoalesce(options.aboveId, () => ( this.doc.activeLayerId));
4331
4366
  const loc = above ? _chunkHB4ICNNAcjs.findLayer.call(void 0, this.doc.layers, above) : null;
4332
4367
  if (options.aboveId !== void 0 && !loc) throw new PaintEditorError(`Layer "${options.aboveId}" was removed while the effect rendered.`);
4333
- const layer = { ...createPaintLayer(_optionalChain([options, 'access', _245 => _245.name, 'optionalAccess', _246 => _246.trim, 'call', _247 => _247()]) || d.name), surface: _chunk474IQG74cjs.surfaceFromPixels.call(void 0, pixels, 4), opacity: _nullishCoalesce(options.opacity, () => ( 1)), blend: _nullishCoalesce(options.blend, () => ( "normal")) };
4334
- const layers = _chunkHB4ICNNAcjs.insertLayer.call(void 0, this.doc.layers, layer, _nullishCoalesce(_optionalChain([loc, 'optionalAccess', _248 => _248.parent, 'optionalAccess', _249 => _249.id]), () => ( null)), loc ? loc.index + 1 : void 0);
4368
+ const layer = { ...createPaintLayer(_optionalChain([options, 'access', _247 => _247.name, 'optionalAccess', _248 => _248.trim, 'call', _249 => _249()]) || d.name), surface: _chunk474IQG74cjs.surfaceFromPixels.call(void 0, pixels, 4), opacity: _nullishCoalesce(options.opacity, () => ( 1)), blend: _nullishCoalesce(options.blend, () => ( "normal")) };
4369
+ const layers = _chunkHB4ICNNAcjs.insertLayer.call(void 0, this.doc.layers, layer, _nullishCoalesce(_optionalChain([loc, 'optionalAccess', _250 => _250.parent, 'optionalAccess', _251 => _251.id]), () => ( null)), loc ? loc.index + 1 : void 0);
4335
4370
  const source = this.sourceOf(d, values, options.time);
4336
4371
  this.commit("Add effect layer", { ...this.doc, layers, activeLayerId: layer.id, effectLayers: { ..._nullishCoalesce(this.doc.effectLayers, () => ( {})), [layer.id]: source } });
4337
4372
  return { layer: this.describeLayer(layer), source };
@@ -4401,16 +4436,25 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4401
4436
  * size, and brushes then take each pixel's colour (and alpha) from it, fixed to the canvas, as if
4402
4437
  * painting a hidden picture into view. `setColor` and `setPaint` go back to colour. Editor state,
4403
4438
  * not an undo step. Strokes that would paint with it throw while it renders. Returns the paint.
4439
+ * With `map: { by: 'stroke' }` the effect lies along each stroke instead of the canvas; with
4440
+ * `live`, strokes on a stroke layer keep playing it (see `setEffectPlayback`).
4404
4441
  */
4405
4442
  async setEffectPaint(source) {
4406
4443
  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).");
4407
4444
  this.checkTime(source.time);
4445
+ let map;
4446
+ try {
4447
+ map = _chunk5BR7LC24cjs.readEffectStrokeMap.call(void 0, source.map);
4448
+ } catch (e) {
4449
+ throw new PaintEditorError(e.message);
4450
+ }
4451
+ if (source.live !== void 0 && typeof source.live !== "boolean") throw new PaintEditorError("live must be true or false.");
4408
4452
  const epoch = ++this.paintEpoch;
4409
4453
  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.`);
4410
4454
  const d = await this.describeEffect(source.effect, "paint");
4411
4455
  const values = this.effectValues(d, { ...d.defaults }, source.values);
4412
4456
  if (epoch !== this.paintEpoch) throw changed(d.name);
4413
- const paint = { type: "effect", effect: d.id, provider: this.effects.require().id, values, time: _nullishCoalesce(source.time, () => ( 0)) };
4457
+ const paint = { type: "effect", effect: d.id, provider: this.effects.require().id, values, time: _nullishCoalesce(source.time, () => ( 0)), ...map ? { map } : {}, ...source.live ? { live: true } : {} };
4414
4458
  this.effectPaintPending = paint;
4415
4459
  this.emit([]);
4416
4460
  try {
@@ -4431,9 +4475,10 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4431
4475
  }
4432
4476
  /** The rendered pixels of an effect paint at the current canvas size, or `null` when it has not been rendered. */
4433
4477
  effectPaintImage(p) {
4434
- const key = _chunkNKTNLJUJcjs.effectPaintKey.call(void 0, p);
4478
+ const key = _chunk5BR7LC24cjs.effectPaintKey.call(void 0, p);
4435
4479
  const img = this.effectPaintPixels.get(key);
4436
- if (!img || img.width !== this.doc.canvas.width || img.height !== this.doc.canvas.height) return null;
4480
+ const size = _chunk5BR7LC24cjs.effectPaintSize.call(void 0, p, this.doc.canvas);
4481
+ if (!img || img.width !== size.width || img.height !== size.height) return null;
4437
4482
  this.effectPaintPixels.delete(key);
4438
4483
  this.effectPaintPixels.set(key, img);
4439
4484
  return img;
@@ -4446,15 +4491,15 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4446
4491
  const what = `the effect "${p.effect}"${p.provider ? ` from provider "${p.provider}"` : ""}`;
4447
4492
  if (!provider) throw new PaintEditorError(`Effect paint needs ${what}, but no effects provider is registered; register it (setEffectsProvider) and try again.`);
4448
4493
  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.`);
4449
- const { width, height } = this.doc.canvas;
4494
+ const { width, height } = _chunk5BR7LC24cjs.effectPaintSize.call(void 0, p, this.doc.canvas);
4450
4495
  let pixels;
4451
4496
  try {
4452
4497
  pixels = await this.effectsRenderer.render(provider, p.effect, { width, height }, { time: p.time, values: p.values });
4453
4498
  } catch (e) {
4454
4499
  throw new PaintEditorError(`Effect paint could not render ${what}: ${e instanceof Error ? e.message : String(e)}`);
4455
4500
  }
4456
- const img = { width, height, data: new Uint8ClampedArray(pixels.data) };
4457
- this.effectPaintPixels.set(_chunkNKTNLJUJcjs.effectPaintKey.call(void 0, p), img);
4501
+ const img = { width, height, data: new Uint8ClampedArray(pixels.data), ...p.map ? { map: p.map } : {} };
4502
+ this.effectPaintPixels.set(_chunk5BR7LC24cjs.effectPaintKey.call(void 0, p), img);
4458
4503
  while (this.effectPaintPixels.size > _PaintEditorController.EFFECT_PAINT_CACHE) this.effectPaintPixels.delete(this.effectPaintPixels.keys().next().value);
4459
4504
  return img;
4460
4505
  }
@@ -4465,7 +4510,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4465
4510
  async prepareEffectPaints(paints) {
4466
4511
  const seen = /* @__PURE__ */ new Set();
4467
4512
  for (const p of paints) {
4468
- const key = _chunkNKTNLJUJcjs.effectPaintKey.call(void 0, p);
4513
+ const key = _chunk5BR7LC24cjs.effectPaintKey.call(void 0, p);
4469
4514
  if (seen.has(key)) continue;
4470
4515
  seen.add(key);
4471
4516
  await this.renderEffectPaint(p);
@@ -4474,7 +4519,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4474
4519
  /** Renders the effect paints of recorded strokes (default all of them) before a replay. */
4475
4520
  async prepareStrokeEffects(strokeIds) {
4476
4521
  const ids = strokeIds ? new Set(strokeIds) : null;
4477
- const paints = this.doc.strokes.filter((s) => (!ids || ids.has(s.id)) && _optionalChain([s, 'access', _250 => _250.paint, 'optionalAccess', _251 => _251.type]) === "effect").map((s) => s.paint);
4522
+ const paints = this.doc.strokes.filter((s) => (!ids || ids.has(s.id)) && _optionalChain([s, 'access', _252 => _252.paint, 'optionalAccess', _253 => _253.type]) === "effect").map((s) => s.paint);
4478
4523
  await this.prepareEffectPaints(paints);
4479
4524
  }
4480
4525
  /** A small preview of the effect paint (a PNG data URL `size` px wide), or `null` without a rendered one. */
@@ -4503,22 +4548,17 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4503
4548
  * its pixels are not rendered.
4504
4549
  */
4505
4550
  strokeEffect(init, brush) {
4506
- if (!_chunkNKTNLJUJcjs.brushTakesPaint.call(void 0, brush)) return null;
4551
+ if (!_chunk5BR7LC24cjs.brushTakesPaint.call(void 0, brush)) return null;
4507
4552
  let source = null;
4508
4553
  if (init.paint !== void 0) {
4509
- if (!_chunkNKTNLJUJcjs.isPaintEffectPaint.call(void 0, init.paint)) return null;
4510
- source = _chunkNKTNLJUJcjs.readPaintEffectPaint.call(void 0, init.paint);
4554
+ if (!_chunk5BR7LC24cjs.isPaintEffectPaint.call(void 0, init.paint)) return null;
4555
+ source = _chunk5BR7LC24cjs.readPaintEffectPaint.call(void 0, init.paint);
4511
4556
  if (!source) throw new PaintEditorError("The stroke's effect paint needs an effect id and values (getEffectPaint returns one).");
4512
4557
  } else if (init.color === void 0 && !brush.paint) {
4513
4558
  if (this.effectPaintPending) throw new PaintEditorError(`The effect paint "${this.effectPaintPending.effect}" is still rendering; wait for set_effect_paint to finish, then paint.`);
4514
4559
  source = this.effectPaint;
4515
4560
  }
4516
4561
  if (!source) return null;
4517
- if (brush.engine === "wet" || brush.engine === "impasto" || brush.engine === "sticker") {
4518
- throw new PaintEditorError(
4519
- `The ${brush.name} brush (${brush.engine} engine) cannot paint with effect paint: it carries one colour as ${brush.engine === "sticker" ? "stickers" : brush.engine === "wet" ? "wet pigment" : "thick paint"}. Paint with a dry brush (a dab, particle, bristle or mixer brush), or paint the shape first and fill it with fill_layer_with_effect {lockTransparency: true}.`
4520
- );
4521
- }
4522
4562
  const pixels = this.effectPaintImage(source);
4523
4563
  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.`);
4524
4564
  return { source, pixels };
@@ -4542,14 +4582,14 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4542
4582
  const before = _chunk474IQG74cjs.readRegion.call(void 0, l.surface, rect);
4543
4583
  const inputs = { source: { width: rect.width, height: rect.height, data: before } };
4544
4584
  const heightInput = d.inputs.find((i) => i.kind === "image" && /^(height|depth|relief)$/i.test(i.name));
4545
- const relief = _optionalChain([this, 'access', _252 => _252.doc, 'access', _253 => _253.thick, 'optionalAccess', _254 => _254[l.id]]);
4585
+ const relief = _optionalChain([this, 'access', _254 => _254.doc, 'access', _255 => _255.thick, 'optionalAccess', _256 => _256[l.id]]);
4546
4586
  if (heightInput && relief) {
4547
4587
  const h = _chunk474IQG74cjs.readRegion.call(void 0, relief.height, rect);
4548
4588
  const rgba = new Uint8ClampedArray(rect.width * rect.height * 4);
4549
4589
  for (let i = 0; i < h.length; i++) rgba.set([h[i], h[i], h[i], 255], i * 4);
4550
4590
  inputs[heightInput.name] = { width: rect.width, height: rect.height, data: rgba };
4551
4591
  }
4552
- const sourceInput = _nullishCoalesce(_optionalChain([d, 'access', _255 => _255.inputs, 'access', _256 => _256.find, 'call', _257 => _257((i) => i.kind === "image" && i.name !== _optionalChain([heightInput, 'optionalAccess', _258 => _258.name])), 'optionalAccess', _259 => _259.name]), () => ( "source"));
4592
+ const sourceInput = _nullishCoalesce(_optionalChain([d, 'access', _257 => _257.inputs, 'access', _258 => _258.find, 'call', _259 => _259((i) => i.kind === "image" && i.name !== _optionalChain([heightInput, 'optionalAccess', _260 => _260.name])), 'optionalAccess', _261 => _261.name]), () => ( "source"));
4553
4593
  if (sourceInput !== "source") {
4554
4594
  inputs[sourceInput] = inputs.source;
4555
4595
  delete inputs.source;
@@ -4562,12 +4602,12 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4562
4602
  }
4563
4603
  // --- Brushes -------------------------------------------------------------------
4564
4604
  findBrush(id) {
4565
- return _nullishCoalesce(_chunkNKTNLJUJcjs.BUILTIN_BRUSHES.find((b) => b.id === id), () => ( this.userBrushes.find((b) => b.id === id)));
4605
+ return _nullishCoalesce(_chunk5BR7LC24cjs.BUILTIN_BRUSHES.find((b) => b.id === id), () => ( this.userBrushes.find((b) => b.id === id)));
4566
4606
  }
4567
4607
  /** A library brush by id (`undefined` when unknown). */
4568
4608
  getBrush(id) {
4569
4609
  const b = this.findBrush(id);
4570
- return b ? _chunkNKTNLJUJcjs.normalizePaintBrush.call(void 0, b, b) : void 0;
4610
+ return b ? _chunk5BR7LC24cjs.normalizePaintBrush.call(void 0, b, b) : void 0;
4571
4611
  }
4572
4612
  requireBrush(id) {
4573
4613
  const b = this.findBrush(id);
@@ -4582,7 +4622,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4582
4622
  const { id, ...changes } = update;
4583
4623
  const base = id !== void 0 ? this.requireBrush(id) : this.brush;
4584
4624
  if (changes.paint !== void 0 && changes.paint !== null) this.readStrokePaint(changes.paint);
4585
- const next = _chunkNKTNLJUJcjs.normalizePaintBrush.call(void 0, { ...changes, id: base.id }, base);
4625
+ const next = _chunk5BR7LC24cjs.normalizePaintBrush.call(void 0, { ...changes, id: base.id }, base);
4586
4626
  if (base.builtin && !Object.keys(changes).length) next.builtin = true;
4587
4627
  else delete next.builtin;
4588
4628
  this.brush = next;
@@ -4591,10 +4631,10 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4591
4631
  }
4592
4632
  /** Saves the active brush (or `brush`) into the user library under `id` / `name`. */
4593
4633
  saveBrush(options) {
4594
- if (!_chunkNKTNLJUJcjs.BRUSH_ID.test(options.id)) throw new PaintEditorError(`Brush id "${options.id}" is invalid; use lowercase letters, digits and dashes (e.g. "my-pencil").`);
4595
- if (_chunkNKTNLJUJcjs.BUILTIN_BRUSHES.some((b) => b.id === options.id)) throw new PaintEditorError(`"${options.id}" is a built-in brush; save under another id.`);
4596
- const source = options.brush ? _chunkNKTNLJUJcjs.normalizePaintBrush.call(void 0, options.brush, this.brush) : this.brush;
4597
- const saved = _chunkNKTNLJUJcjs.normalizePaintBrush.call(void 0, { ...source, id: options.id, name: _nullishCoalesce(options.name, () => ( source.name)) });
4634
+ if (!_chunk5BR7LC24cjs.BRUSH_ID.test(options.id)) throw new PaintEditorError(`Brush id "${options.id}" is invalid; use lowercase letters, digits and dashes (e.g. "my-pencil").`);
4635
+ if (_chunk5BR7LC24cjs.BUILTIN_BRUSHES.some((b) => b.id === options.id)) throw new PaintEditorError(`"${options.id}" is a built-in brush; save under another id.`);
4636
+ const source = options.brush ? _chunk5BR7LC24cjs.normalizePaintBrush.call(void 0, options.brush, this.brush) : this.brush;
4637
+ const saved = _chunk5BR7LC24cjs.normalizePaintBrush.call(void 0, { ...source, id: options.id, name: _nullishCoalesce(options.name, () => ( source.name)) });
4598
4638
  delete saved.builtin;
4599
4639
  const i = this.userBrushes.findIndex((b) => b.id === options.id);
4600
4640
  if (i >= 0) this.userBrushes[i] = saved;
@@ -4604,7 +4644,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4604
4644
  return saved;
4605
4645
  }
4606
4646
  removeBrush(id) {
4607
- if (_chunkNKTNLJUJcjs.BUILTIN_BRUSHES.some((b) => b.id === id)) throw new PaintEditorError(`"${id}" is a built-in brush and cannot be removed.`);
4647
+ if (_chunk5BR7LC24cjs.BUILTIN_BRUSHES.some((b) => b.id === id)) throw new PaintEditorError(`"${id}" is a built-in brush and cannot be removed.`);
4608
4648
  const i = this.userBrushes.findIndex((b) => b.id === id);
4609
4649
  if (i < 0) throw new PaintEditorError(`Unknown brush "${id}". Call list_brushes for the ids.`);
4610
4650
  this.userBrushes.splice(i, 1);
@@ -4613,12 +4653,12 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4613
4653
  }
4614
4654
  /** The user's saved brushes. */
4615
4655
  getUserBrushes() {
4616
- return this.userBrushes.map((b) => _chunkNKTNLJUJcjs.normalizePaintBrush.call(void 0, b, b));
4656
+ return this.userBrushes.map((b) => _chunk5BR7LC24cjs.normalizePaintBrush.call(void 0, b, b));
4617
4657
  }
4618
4658
  /** A brush library file of the given brushes (default: the user's brushes). */
4619
4659
  exportBrushes(ids) {
4620
4660
  const list = ids ? ids.map((id) => this.requireBrush(id)) : this.userBrushes;
4621
- return { format: "pixerate-brushes", version: 1, brushes: list.map(_chunkNKTNLJUJcjs.brushToJSON) };
4661
+ return { format: "pixerate-brushes", version: 1, brushes: list.map(_chunk5BR7LC24cjs.brushToJSON) };
4622
4662
  }
4623
4663
  /**
4624
4664
  * Adds the brushes of a library file to the user library. A brush whose id is taken is skipped
@@ -4628,14 +4668,14 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4628
4668
  const problems = [];
4629
4669
  let list;
4630
4670
  try {
4631
- list = _chunkNKTNLJUJcjs.parseBrushLibrary.call(void 0, file, problems);
4671
+ list = _chunk5BR7LC24cjs.parseBrushLibrary.call(void 0, file, problems);
4632
4672
  } catch (e) {
4633
4673
  throw new PaintEditorError(e.message);
4634
4674
  }
4635
4675
  const added = [];
4636
4676
  const skipped = [];
4637
4677
  for (const b of list) {
4638
- if (_chunkNKTNLJUJcjs.BUILTIN_BRUSHES.some((x) => x.id === b.id)) {
4678
+ if (_chunk5BR7LC24cjs.BUILTIN_BRUSHES.some((x) => x.id === b.id)) {
4639
4679
  skipped.push(b.id);
4640
4680
  problems.push(`"${b.id}" is a built-in brush id; rename it to import it.`);
4641
4681
  continue;
@@ -4700,10 +4740,10 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4700
4740
  * brush's gradient, else the editor's gradient paint. Erasers, blenders and smudges take none.
4701
4741
  */
4702
4742
  strokeGradient(init, brush, color) {
4703
- if (!_chunkNKTNLJUJcjs.brushTakesPaint.call(void 0, brush)) return null;
4743
+ if (!_chunk5BR7LC24cjs.brushTakesPaint.call(void 0, brush)) return null;
4704
4744
  let g = null;
4705
4745
  if (init.paint !== void 0) {
4706
- if (_chunkNKTNLJUJcjs.isPaintEffectPaint.call(void 0, init.paint)) return null;
4746
+ if (_chunk5BR7LC24cjs.isPaintEffectPaint.call(void 0, init.paint)) return null;
4707
4747
  const p = this.readStrokePaint(init.paint);
4708
4748
  g = p.type === "gradient" ? p : null;
4709
4749
  } else g = _nullishCoalesce(brush.paint, () => ( (init.color === void 0 ? this.gradient : null)));
@@ -4747,7 +4787,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4747
4787
  // --- Mixer Brush ---------------------------------------------------------------
4748
4788
  /** Fills the Mixer Brush reservoir with a colour (default the editor colour). */
4749
4789
  loadMixerBrush(color) {
4750
- const [r, g, b] = _chunkNKTNLJUJcjs.hexToRgb8.call(void 0, color === void 0 ? this.color : parseColor(color));
4790
+ const [r, g, b] = _chunk5BR7LC24cjs.hexToRgb8.call(void 0, color === void 0 ? this.color : parseColor(color));
4751
4791
  this.mixerLoad = _chunkPQ3H2AANcjs.loadMixer.call(void 0, this.mixerLoad, [r / 255, g / 255, b / 255]);
4752
4792
  this.emit([]);
4753
4793
  return this.mixerLoad;
@@ -4777,7 +4817,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4777
4817
  // --- Strokes -------------------------------------------------------------------
4778
4818
  strokeBrush(init) {
4779
4819
  let brush = init.brushId !== void 0 ? this.requireBrush(init.brushId) : this.brush;
4780
- if (init.brush) brush = _chunkNKTNLJUJcjs.normalizePaintBrush.call(void 0, { ...init.brush, id: brush.id }, brush);
4820
+ if (init.brush) brush = _chunk5BR7LC24cjs.normalizePaintBrush.call(void 0, { ...init.brush, id: brush.id }, brush);
4781
4821
  return brush;
4782
4822
  }
4783
4823
  /**
@@ -4793,7 +4833,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4793
4833
  return symmetryCopies(this.guides.symmetry);
4794
4834
  }
4795
4835
  sessionFor(doc, init, host) {
4796
- if (init.paint !== void 0 && !_chunkNKTNLJUJcjs.isPaintEffectPaint.call(void 0, init.paint)) {
4836
+ if (init.paint !== void 0 && !_chunk5BR7LC24cjs.isPaintEffectPaint.call(void 0, init.paint)) {
4797
4837
  const p = this.readStrokePaint(init.paint);
4798
4838
  if (p.type === "color") init = { ...init, color: p.color, paint: void 0 };
4799
4839
  else init = { ...init, paint: p };
@@ -4811,18 +4851,25 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4811
4851
  })();
4812
4852
  const brush = this.strokeBrush(init);
4813
4853
  const effect = this.strokeEffect(init, brush);
4814
- if (_optionalChain([doc, 'access', _260 => _260.liveStrokes, 'optionalAccess', _261 => _261[layer.id]])) {
4854
+ if (_optionalChain([doc, 'access', _262 => _262.liveStrokes, 'optionalAccess', _263 => _263[layer.id]])) {
4815
4855
  const why = liveStrokeRefusal(brush);
4816
4856
  if (why) throw new PaintEditorError(`Layer "${layer.name}" is a stroke layer. ${why}`);
4817
4857
  }
4818
- const stickerLayer = Boolean(_optionalChain([doc, 'access', _262 => _262.stickers, 'optionalAccess', _263 => _263[layer.id], 'optionalAccess', _264 => _264.length]));
4858
+ if (_optionalChain([doc, 'access', _264 => _264.liveStrokes, 'optionalAccess', _265 => _265[layer.id]]) && _optionalChain([effect, 'optionalAccess', _266 => _266.source, 'access', _267 => _267.live])) {
4859
+ const key = _chunk5BR7LC24cjs.effectPaintKey.call(void 0, effect.source);
4860
+ const { sources } = this.liveEffects(doc);
4861
+ if (!sources.some((p) => _chunk5BR7LC24cjs.effectPaintKey.call(void 0, p) === key) && sources.length >= MAX_LIVE_EFFECT_SOURCES) {
4862
+ 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.`);
4863
+ }
4864
+ }
4865
+ const stickerLayer = Boolean(_optionalChain([doc, 'access', _268 => _268.stickers, 'optionalAccess', _269 => _269[layer.id], 'optionalAccess', _270 => _270.length]));
4819
4866
  if (brush.engine === "sticker") {
4820
4867
  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.`);
4821
4868
  } else if (stickerLayer) {
4822
4869
  throw new PaintEditorError(`Layer "${layer.name}" is a sticker layer (its pixels are drawn from its stickers); paint on another layer (add_layer).`);
4823
4870
  }
4824
4871
  let wet;
4825
- if (_chunkNKTNLJUJcjs.isWetBrush.call(void 0, brush)) {
4872
+ if (_chunk5BR7LC24cjs.isWetBrush.call(void 0, brush)) {
4826
4873
  this.requireWetIdle("painting");
4827
4874
  if (layer.offset.x || layer.offset.y) {
4828
4875
  const moved = { ...layer, surface: _chunk474IQG74cjs.translateSurface.call(void 0, layer.surface, layer.offset.x, layer.offset.y), offset: { x: 0, y: 0 } };
@@ -4837,7 +4884,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4837
4884
  const world = this.wet.ensureLane(layer.id, brush.wet.medium);
4838
4885
  const id = layer.id;
4839
4886
  const wetColor = init.color === void 0 ? this.color : parseColor(init.color);
4840
- const [r, g, b] = _chunkNKTNLJUJcjs.hexToRgb8.call(void 0, wetColor);
4887
+ const [r, g, b] = _chunk5BR7LC24cjs.hexToRgb8.call(void 0, wetColor);
4841
4888
  const wetGradient = this.strokeGradient(init, brush, wetColor);
4842
4889
  const load = _nullishCoalesce(init.load, () => ( brushLoadForStroke(brush, this.mixerLoad, [r / 255, g / 255, b / 255])));
4843
4890
  const seedW = _nullishCoalesce(init.seed, () => ( _chunkPQ3H2AANcjs.mix32.call(void 0, this.seedCounter * 2654435761 >>> 0) & 2147483647));
@@ -4850,11 +4897,12 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4850
4897
  load,
4851
4898
  grain: paperGrain(doc.paper),
4852
4899
  paperDepth: doc.paper.depth,
4853
- paperColor: _chunkNKTNLJUJcjs.hexToRgb8.call(void 0, doc.paper.color),
4900
+ paperColor: _chunk5BR7LC24cjs.hexToRgb8.call(void 0, doc.paper.color),
4854
4901
  seed: seedW,
4855
4902
  copies: [IDENTITY_AFFINE, ...copiesW].map(affineCopy),
4856
4903
  mask: init.maskStencils ? this.stencilSelection(init.maskStencils) : init.stencils !== false ? this.stencilSelection() : null,
4857
- paint: wetGradient
4904
+ paint: effect ? null : wetGradient,
4905
+ effect: _nullishCoalesce(_optionalChain([effect, 'optionalAccess', _271 => _271.pixels]), () => ( null))
4858
4906
  });
4859
4907
  init = { ...init, seed: seedW, load };
4860
4908
  wet = { driver, surface: () => world.display(id).surface };
@@ -4865,7 +4913,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4865
4913
  }
4866
4914
  let color = init.color === void 0 ? this.color : parseColor(init.color);
4867
4915
  const tracing = this.guides.tracing;
4868
- if (init.color === void 0 && init.start && _optionalChain([tracing, 'optionalAccess', _265 => _265.visible]) && tracing.sampleColors) color = _nullishCoalesce(this.sampleTracingColor(init.start.x, init.start.y), () => ( color));
4916
+ if (init.color === void 0 && init.start && _optionalChain([tracing, 'optionalAccess', _272 => _272.visible]) && tracing.sampleColors) color = _nullishCoalesce(this.sampleTracingColor(init.start.x, init.start.y), () => ( color));
4869
4917
  const perspective = this.guides.perspective;
4870
4918
  const snapper = init.snapToPerspective && perspective.enabled && perspective.snap ? new PerspectiveSnapper(perspective) : null;
4871
4919
  const useStencils = init.stencils !== false;
@@ -4898,7 +4946,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4898
4946
  mixerLoad: _nullishCoalesce(init.load, () => ( brushLoadForStroke(brush, this.mixerLoad, [rgba[0] / 255, rgba[1] / 255, rgba[2] / 255]))),
4899
4947
  secondary: rgbaOf(this.secondaryColor),
4900
4948
  wet,
4901
- thick: brush.engine === "impasto" ? { channels: _nullishCoalesce(_optionalChain([doc, 'access', _266 => _266.thick, 'optionalAccess', _267 => _267[layer.id]]), () => ( emptyThickChannels())) } : void 0,
4949
+ thick: brush.engine === "impasto" ? { channels: _nullishCoalesce(_optionalChain([doc, 'access', _273 => _273.thick, 'optionalAccess', _274 => _274[layer.id]]), () => ( emptyThickChannels())) } : void 0,
4902
4950
  sticker: brush.engine === "sticker" ? { nextId: this.nextStickerNumber(doc) } : void 0,
4903
4951
  paint: effect ? null : this.strokeGradient(init, brush, color),
4904
4952
  effect
@@ -4912,7 +4960,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4912
4960
  const stroke = {
4913
4961
  id: `s${this.strokeCounter++}`,
4914
4962
  layerId: session.layerId,
4915
- brush: _chunkNKTNLJUJcjs.brushToJSON.call(void 0, init.brush),
4963
+ brush: _chunk5BR7LC24cjs.brushToJSON.call(void 0, init.brush),
4916
4964
  color: init.colorHex,
4917
4965
  points: session.points.map((p) => ({ ...p })),
4918
4966
  seed: init.seed
@@ -4937,12 +4985,12 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4937
4985
  const before = this.doc;
4938
4986
  const host = {
4939
4987
  update: (layerId, surface, rects) => {
4940
- if (_optionalChain([this, 'access', _268 => _268.session, 'optionalAccess', _269 => _269.init, 'access', _270 => _270.wet])) {
4988
+ if (_optionalChain([this, 'access', _275 => _275.session, 'optionalAccess', _276 => _276.init, 'access', _277 => _277.wet])) {
4941
4989
  this.wet.syncDisplays();
4942
4990
  return;
4943
4991
  }
4944
4992
  this.live = { layerId, surface };
4945
- const ch = _optionalChain([this, 'access', _271 => _271.session, 'optionalAccess', _272 => _272.thickChannels, 'call', _273 => _273()]);
4993
+ const ch = _optionalChain([this, 'access', _278 => _278.session, 'optionalAccess', _279 => _279.thickChannels, 'call', _280 => _280()]);
4946
4994
  this.liveThick = ch ? { layerId, channels: ch } : null;
4947
4995
  this.emit(rects);
4948
4996
  },
@@ -4954,7 +5002,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4954
5002
  const wetStroke = Boolean(s.init.wet);
4955
5003
  if (wetStroke) this.wet.driver = null;
4956
5004
  const brush = s.init.brush;
4957
- if (!cancelled && _optionalChain([s, 'access', _274 => _274.result, 'optionalAccess', _275 => _275.mixerLoad])) this.keepLoad(brush, s.result.mixerLoad);
5005
+ if (!cancelled && _optionalChain([s, 'access', _281 => _281.result, 'optionalAccess', _282 => _282.mixerLoad])) this.keepLoad(brush, s.result.mixerLoad);
4958
5006
  if (cancelled || !surface) {
4959
5007
  if (this.wetOp) {
4960
5008
  const snap = this.wetOp.before;
@@ -4969,7 +5017,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4969
5017
  }
4970
5018
  const stroke = this.record(s);
4971
5019
  s.result.strokeId = stroke.id;
4972
- this.paintedBounds.set(stroke, _nullishCoalesce(_optionalChain([s, 'access', _276 => _276.result, 'optionalAccess', _277 => _277.bounds]), () => ( null)));
5020
+ this.paintedBounds.set(stroke, _nullishCoalesce(_optionalChain([s, 'access', _283 => _283.result, 'optionalAccess', _284 => _284.bounds]), () => ( null)));
4973
5021
  if (wetStroke && this.wet.instantDry) {
4974
5022
  this.wet.dry(s.layerId);
4975
5023
  this.logWet({ kind: "dry", layerId: s.layerId, at: this.doc.strokes.length + 1 });
@@ -4980,7 +5028,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4980
5028
  const ch = s.thickChannels();
4981
5029
  const thick = ch ? { ..._nullishCoalesce(this.doc.thick, () => ( {})), [l.id]: ch } : this.doc.thick;
4982
5030
  const sprayed = s.stickers();
4983
- const stickers = sprayed ? { ..._nullishCoalesce(this.doc.stickers, () => ( {})), [l.id]: [..._nullishCoalesce(_optionalChain([this, 'access', _278 => _278.doc, 'access', _279 => _279.stickers, 'optionalAccess', _280 => _280[l.id]]), () => ( [])), ...sprayed] } : this.doc.stickers;
5031
+ const stickers = sprayed ? { ..._nullishCoalesce(this.doc.stickers, () => ( {})), [l.id]: [..._nullishCoalesce(_optionalChain([this, 'access', _285 => _285.doc, 'access', _286 => _286.stickers, 'optionalAccess', _287 => _287[l.id]]), () => ( [])), ...sprayed] } : this.doc.stickers;
4984
5032
  this.commit(`${brush.name} stroke`, this.withWetEvents(withLiveStroke({ ...this.doc, layers: _chunkHB4ICNNAcjs.mapLayer.call(void 0, this.doc.layers, l.id, () => ({ ...l, surface })), strokes: [...this.doc.strokes, stroke], ...thick ? { thick } : {}, ...stickers ? { stickers } : {} }, stroke)), wetStroke ? before : this.doc);
4985
5033
  }
4986
5034
  };
@@ -5009,7 +5057,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5009
5057
  if (cancelled || !surface) return;
5010
5058
  const stroke = this.record(s);
5011
5059
  s.result.strokeId = stroke.id;
5012
- this.paintedBounds.set(stroke, _nullishCoalesce(_optionalChain([s, 'access', _281 => _281.result, 'optionalAccess', _282 => _282.bounds]), () => ( null)));
5060
+ this.paintedBounds.set(stroke, _nullishCoalesce(_optionalChain([s, 'access', _288 => _288.result, 'optionalAccess', _289 => _289.bounds]), () => ( null)));
5013
5061
  const l = _chunkHB4ICNNAcjs.findLayer.call(void 0, out.layers, s.layerId).layer;
5014
5062
  const offset = s.init.wet ? { x: 0, y: 0 } : l.offset;
5015
5063
  const ch = s.thickChannels();
@@ -5019,7 +5067,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5019
5067
  layers: _chunkHB4ICNNAcjs.mapLayer.call(void 0, out.layers, l.id, () => ({ ...l, surface, offset })),
5020
5068
  strokes: [...out.strokes, stroke],
5021
5069
  ...ch ? { thick: { ..._nullishCoalesce(out.thick, () => ( {})), [l.id]: ch } } : {},
5022
- ...sprayed ? { stickers: { ..._nullishCoalesce(out.stickers, () => ( {})), [l.id]: [..._nullishCoalesce(_optionalChain([out, 'access', _283 => _283.stickers, 'optionalAccess', _284 => _284[l.id]]), () => ( [])), ...sprayed] } } : {}
5070
+ ...sprayed ? { stickers: { ..._nullishCoalesce(out.stickers, () => ( {})), [l.id]: [..._nullishCoalesce(_optionalChain([out, 'access', _290 => _290.stickers, 'optionalAccess', _291 => _291[l.id]]), () => ( [])), ...sprayed] } } : {}
5023
5071
  }, stroke);
5024
5072
  }
5025
5073
  };
@@ -5077,7 +5125,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5077
5125
  */
5078
5126
  replayStrokes(options) {
5079
5127
  this.requireIdle("replaying");
5080
- if (!_optionalChain([options, 'access', _285 => _285.strokeIds, 'optionalAccess', _286 => _286.length])) throw new PaintEditorError("strokeIds is empty; pass ids from list_strokes.");
5128
+ if (!_optionalChain([options, 'access', _292 => _292.strokeIds, 'optionalAccess', _293 => _293.length])) throw new PaintEditorError("strokeIds is empty; pass ids from list_strokes.");
5081
5129
  const strokes = options.strokeIds.map((id) => {
5082
5130
  const s = this.doc.strokes.find((x) => x.id === id);
5083
5131
  if (!s) throw new PaintEditorError(`Unknown stroke "${id}". Call list_strokes for the ids.`);
@@ -5091,7 +5139,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5091
5139
  if (options.layerId !== void 0) this.paintTarget(options.layerId, "replay onto");
5092
5140
  if (options.color === void 0) {
5093
5141
  for (const s of strokes) {
5094
- if (_optionalChain([s, 'access', _287 => _287.paint, 'optionalAccess', _288 => _288.type]) === "effect" && !this.effectPaintImage(s.paint)) {
5142
+ if (_optionalChain([s, 'access', _294 => _294.paint, 'optionalAccess', _295 => _295.type]) === "effect" && !this.effectPaintImage(s.paint)) {
5095
5143
  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.`);
5096
5144
  }
5097
5145
  }
@@ -5114,13 +5162,13 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5114
5162
  let brush = v.brush;
5115
5163
  if (options.brushId !== void 0) {
5116
5164
  const b = this.requireBrush(options.brushId);
5117
- brush = _chunkNKTNLJUJcjs.normalizePaintBrush.call(void 0, { tip: { ...b.tip, size: b.tip.size * (v.brush.tip.size / s.brush.tip.size) } }, b);
5165
+ brush = _chunk5BR7LC24cjs.normalizePaintBrush.call(void 0, { tip: { ...b.tip, size: b.tip.size * (v.brush.tip.size / s.brush.tip.size) } }, b);
5118
5166
  }
5119
5167
  const layerId = _nullishCoalesce(options.layerId, () => ( s.layerId));
5120
5168
  if (!_chunkHB4ICNNAcjs.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.`);
5121
5169
  let load = s.load;
5122
5170
  if (load && options.color !== void 0 && load.reservoir) {
5123
- const [r, g, b] = _chunkNKTNLJUJcjs.hexToRgb8.call(void 0, options.color);
5171
+ const [r, g, b] = _chunk5BR7LC24cjs.hexToRgb8.call(void 0, options.color);
5124
5172
  load = { ...load, reservoir: [r / 255, g / 255, b / 255] };
5125
5173
  }
5126
5174
  const paint = v.paint && options.color === void 0 ? { paint: v.paint } : {};
@@ -5160,7 +5208,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5160
5208
  const id = _nullishCoalesce(layerId, () => ( this.doc.activeLayerId));
5161
5209
  if (!id) return null;
5162
5210
  this.requireLayer(id);
5163
- const ch = _optionalChain([this, 'access', _289 => _289.doc, 'access', _290 => _290.thick, 'optionalAccess', _291 => _291[id]]);
5211
+ const ch = _optionalChain([this, 'access', _296 => _296.doc, 'access', _297 => _297.thick, 'optionalAccess', _298 => _298[id]]);
5164
5212
  if (!ch) return null;
5165
5213
  const r = reliefInfo(ch);
5166
5214
  return { layerId: id, bounds: r.bounds, maxHeight: r.maxHeight };
@@ -5268,7 +5316,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5268
5316
  wetState() {
5269
5317
  const st = this.getState().wet;
5270
5318
  const backend = this.wet.backend();
5271
- return { ...st, layers: this.wet.wetLayerIds().map((id) => this.wet.info(id)), backend, message: _nullishCoalesce(_optionalChain([backend, 'optionalAccess', _292 => _292.message]), () => ( _chunkXFYLA3ZOcjs.wetSupport.call(void 0, ).message)), engine: this.wet.engineInfo() };
5319
+ return { ...st, layers: this.wet.wetLayerIds().map((id) => this.wet.info(id)), backend, message: _nullishCoalesce(_optionalChain([backend, 'optionalAccess', _299 => _299.message]), () => ( _chunkXFYLA3ZOcjs.wetSupport.call(void 0, ).message)), engine: this.wet.engineInfo() };
5272
5320
  }
5273
5321
  /**
5274
5322
  * Engine B, the WebGPU accelerator for large wet areas: whether it may run, its state (`off`,
@@ -5353,7 +5401,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5353
5401
  }
5354
5402
  /** Records a settings change as a wet event (not an undo step). */
5355
5403
  recordWetSetting(e) {
5356
- this.doc = { ...this.doc, wetEvents: [..._nullishCoalesce(this.doc.wetEvents, () => ( [])), { clock: _nullishCoalesce(_optionalChain([this, 'access', _293 => _293.wet, 'access', _294 => _294.world, 'optionalAccess', _295 => _295.clock]), () => ( 0)), at: this.doc.strokes.length, ...e }] };
5404
+ this.doc = { ...this.doc, wetEvents: [..._nullishCoalesce(this.doc.wetEvents, () => ( [])), { clock: _nullishCoalesce(_optionalChain([this, 'access', _300 => _300.wet, 'access', _301 => _301.world, 'optionalAccess', _302 => _302.clock]), () => ( 0)), at: this.doc.strokes.length, ...e }] };
5357
5405
  }
5358
5406
  /** Changes a layer's wet settings (viscosity, evaporation, granulation…). Editor settings saved with the document, not an undo step. */
5359
5407
  setWetParams(layerId, update) {
@@ -5418,9 +5466,11 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5418
5466
  }
5419
5467
  /** The layers with the live stroke's surface in place. */
5420
5468
  currentLayers() {
5469
+ const override = this.frameOverride;
5470
+ if (override) return Array.from(override).reduce((ls, [id, surface]) => _chunkHB4ICNNAcjs.mapLayer.call(void 0, ls, id, (l) => ({ ...l, surface })), this.doc.layers);
5421
5471
  const live = this.live;
5422
- if (!live) return this.doc.layers;
5423
- if (_optionalChain([this, 'access', _296 => _296.liveLayers, 'optionalAccess', _297 => _297.key]) === live.surface) return this.liveLayers.layers;
5472
+ if (!live) return this.animatedView();
5473
+ if (_optionalChain([this, 'access', _303 => _303.liveLayers, 'optionalAccess', _304 => _304.key]) === live.surface) return this.liveLayers.layers;
5424
5474
  const layers = _chunkHB4ICNNAcjs.mapLayer.call(void 0, this.doc.layers, live.layerId, (l) => ({ ...l, surface: live.surface }));
5425
5475
  this.liveLayers = { key: live.surface, layers };
5426
5476
  return layers;
@@ -5443,7 +5493,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5443
5493
  tracingNode(t) {
5444
5494
  const { width, height } = this.doc.canvas;
5445
5495
  const key = this.tracingVersion * 100003 + width * 7 + height;
5446
- if (_optionalChain([this, 'access', _298 => _298.tracingCache, 'optionalAccess', _299 => _299.key]) === key && this.tracingCache.node.opacity === t.opacity) return this.tracingCache.node;
5496
+ if (_optionalChain([this, 'access', _305 => _305.tracingCache, 'optionalAccess', _306 => _306.key]) === key && this.tracingCache.node.opacity === t.opacity) return this.tracingCache.node;
5447
5497
  const src = _nullishCoalesce(this.imagePixels.get(t.src), () => ( this.decodeImage(t.src)));
5448
5498
  const image = resampleInto(src, t.rect, width, height);
5449
5499
  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 };
@@ -5470,8 +5520,8 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5470
5520
  let out = layers;
5471
5521
  const ids = /* @__PURE__ */ new Set([...Object.keys(_nullishCoalesce(thick, () => ( {}))), ...live ? [live.layerId] : []]);
5472
5522
  for (const id of ids) {
5473
- const ch = _optionalChain([live, 'optionalAccess', _300 => _300.layerId]) === id ? live.channels : _optionalChain([thick, 'optionalAccess', _301 => _301[id]]);
5474
- const l = ch && _optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, out, id), 'optionalAccess', _302 => _302.layer]);
5523
+ const ch = _optionalChain([live, 'optionalAccess', _307 => _307.layerId]) === id ? live.channels : _optionalChain([thick, 'optionalAccess', _308 => _308[id]]);
5524
+ const l = ch && _optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, out, id), 'optionalAccess', _309 => _309.layer]);
5475
5525
  if (!ch || !isPixelLayer(l)) continue;
5476
5526
  let cache = this.litCaches.get(id);
5477
5527
  if (!cache) this.litCaches.set(id, cache = new LitCache());
@@ -5484,7 +5534,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5484
5534
  let layers = this.litLayers((_nullishCoalesce(options.wet, () => ( "display"))) === "dried" ? this.driedLayers() : this.currentLayers());
5485
5535
  if (options.layerIds) {
5486
5536
  const picked = [];
5487
- for (const id of options.layerIds) picked.push(_nullishCoalesce(_optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, layers, id), 'optionalAccess', _303 => _303.layer]), () => ( this.requireLayer(id))));
5537
+ for (const id of options.layerIds) picked.push(_nullishCoalesce(_optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, layers, id), 'optionalAccess', _310 => _310.layer]), () => ( this.requireLayer(id))));
5488
5538
  layers = picked.map((l) => ({ ...l, visible: true }));
5489
5539
  }
5490
5540
  const under = options.paper === false ? [] : [paperNode(this.doc.paper, this.lighting)];
@@ -5500,7 +5550,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5500
5550
  */
5501
5551
  compositeTiles(rect, onTile, options = {}) {
5502
5552
  const dirty = options.dirty === "all" ? void 0 : options.dirty;
5503
- this.viewCompositor.compositeTiles(this.renderLayers({ paper: options.paper }, true), rect, this.sources(), onTile, { dirty, checkpointLayerId: _nullishCoalesce(_optionalChain([this, 'access', _304 => _304.live, 'optionalAccess', _305 => _305.layerId]), () => ( this.doc.activeLayerId)) });
5553
+ this.viewCompositor.compositeTiles(this.renderLayers({ paper: options.paper }, true), rect, this.sources(), onTile, { dirty, checkpointLayerId: _nullishCoalesce(_optionalChain([this, 'access', _311 => _311.live, 'optionalAccess', _312 => _312.layerId]), () => ( this.doc.activeLayerId)) });
5504
5554
  }
5505
5555
  /** The canvas as canvas-sized RGBA (paper included by default). */
5506
5556
  compositePixels(options = {}) {
@@ -5568,7 +5618,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5568
5618
  for (const [id, list] of Object.entries(_nullishCoalesce(this.doc.liveStrokes, () => ( {})))) if (_chunkHB4ICNNAcjs.findLayer.call(void 0, this.doc.layers, id)) liveStrokes[id] = list.map((x) => JSON.parse(JSON.stringify(x)));
5569
5619
  if (Object.keys(liveStrokes).length) ext.liveStrokes = liveStrokes;
5570
5620
  else delete ext.liveStrokes;
5571
- const effectLayers = effectLayersToJSON(_nullishCoalesce(this.doc.effectLayers, () => ( {})), (id) => isPixelLayer(_optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _306 => _306.layer])));
5621
+ const effectLayers = effectLayersToJSON(_nullishCoalesce(this.doc.effectLayers, () => ( {})), (id) => isPixelLayer(_optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _313 => _313.layer])));
5572
5622
  if (effectLayers) ext.effectLayers = effectLayers;
5573
5623
  else delete ext.effectLayers;
5574
5624
  if (this.doc.paperEffect) ext.paperEffect = paperEffectToJSON(this.doc.paperEffect);
@@ -5585,7 +5635,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5585
5635
  const stickers = {};
5586
5636
  for (const [id, list] of Object.entries(ext.stickers)) {
5587
5637
  if (!_chunkHB4ICNNAcjs.findLayer.call(void 0, state.layers, id) || !Array.isArray(list)) continue;
5588
- const ok = list.filter((x) => x && typeof x.id === "string" && _chunkNKTNLJUJcjs.STAMP_KINDS.includes(x.stamp) && Number.isFinite(x.x) && Number.isFinite(x.y) && x.size > 0);
5638
+ const ok = list.filter((x) => x && typeof x.id === "string" && _chunk5BR7LC24cjs.STAMP_KINDS.includes(x.stamp) && Number.isFinite(x.x) && Number.isFinite(x.y) && x.size > 0);
5589
5639
  if (ok.length !== list.length) problems.push(`Some stickers of layer "${id}" could not be read; they were dropped.`);
5590
5640
  stickers[id] = ok.map((x) => ({ ...x }));
5591
5641
  }
@@ -5594,7 +5644,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5594
5644
  if (ext.liveStrokes && typeof ext.liveStrokes === "object") {
5595
5645
  const liveStrokes = {};
5596
5646
  for (const [id, list] of Object.entries(ext.liveStrokes)) {
5597
- if (!isPixelLayer(_optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, state.layers, id), 'optionalAccess', _307 => _307.layer])) || !Array.isArray(list)) continue;
5647
+ if (!isPixelLayer(_optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, state.layers, id), 'optionalAccess', _314 => _314.layer])) || !Array.isArray(list)) continue;
5598
5648
  const ok = list.map(normalizeBrushStroke).filter((x) => x !== null).map((x) => ({ ...x, layerId: id }));
5599
5649
  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).`);
5600
5650
  liveStrokes[id] = ok;
@@ -5604,7 +5654,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5604
5654
  if (ext.effectLayers && typeof ext.effectLayers === "object") {
5605
5655
  const effectLayers = {};
5606
5656
  for (const [id, v] of Object.entries(ext.effectLayers)) {
5607
- if (!isPixelLayer(_optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, state.layers, id), 'optionalAccess', _308 => _308.layer]))) continue;
5657
+ if (!isPixelLayer(_optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, state.layers, id), 'optionalAccess', _315 => _315.layer]))) continue;
5608
5658
  const source = readPaintEffectSource(v);
5609
5659
  if (source) effectLayers[id] = source;
5610
5660
  else problems.push(`The effect of layer "${id}" could not be read; it loads as a plain layer.`);
@@ -5645,7 +5695,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5645
5695
  this.readGuides(loaded.guides, loaded.state, loaded.problems);
5646
5696
  if (Array.isArray(loaded.swatches)) this.swatches = loaded.swatches.map(readSwatch).filter((x) => x !== null);
5647
5697
  for (const s of loaded.state.strokes) {
5648
- const n = Number(_nullishCoalesce(_optionalChain([/^s(\d+)$/, 'access', _309 => _309.exec, 'call', _310 => _310(s.id), 'optionalAccess', _311 => _311[1]]), () => ( 0)));
5698
+ const n = Number(_nullishCoalesce(_optionalChain([/^s(\d+)$/, 'access', _316 => _316.exec, 'call', _317 => _317(s.id), 'optionalAccess', _318 => _318[1]]), () => ( 0)));
5649
5699
  if (n >= this.strokeCounter) this.strokeCounter = n + 1;
5650
5700
  }
5651
5701
  this.undoStack = [];
@@ -5653,7 +5703,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5653
5703
  this.doc = this.readThick(loaded.state, loaded.extensions, loaded.problems);
5654
5704
  for (const list of Object.values(_nullishCoalesce(this.doc.liveStrokes, () => ( {})))) {
5655
5705
  for (const s of list) {
5656
- const n = Number(_nullishCoalesce(_optionalChain([/^s(\d+)$/, 'access', _312 => _312.exec, 'call', _313 => _313(s.id), 'optionalAccess', _314 => _314[1]]), () => ( 0)));
5706
+ const n = Number(_nullishCoalesce(_optionalChain([/^s(\d+)$/, 'access', _319 => _319.exec, 'call', _320 => _320(s.id), 'optionalAccess', _321 => _321[1]]), () => ( 0)));
5657
5707
  if (n >= this.strokeCounter) this.strokeCounter = n + 1;
5658
5708
  }
5659
5709
  }
@@ -5744,10 +5794,10 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5744
5794
  return next.type === "group" ? { ...next, children: toStandard(next.children) } : next;
5745
5795
  });
5746
5796
  const layers = toStandard(dried);
5747
- const result = _chunkBBUE3UJLcjs.exportPsd.call(void 0, { width, height, layers: [paperLayer, ...layers], merged, resolution: dpi });
5797
+ const result = _chunkHW72ABGRcjs.exportPsd.call(void 0, { width, height, layers: [paperLayer, ...layers], merged, resolution: dpi });
5748
5798
  for (const [mode, names] of changed) {
5749
- const label = _nullishCoalesce(_optionalChain([_chunkOLNIPTB3cjs.BLEND_MODES, 'access', _315 => _315.find, 'call', _316 => _316((m) => m.id === mode), 'optionalAccess', _317 => _317.label]), () => ( mode));
5750
- const std = _nullishCoalesce(_optionalChain([_chunkOLNIPTB3cjs.BLEND_MODES, 'access', _318 => _318.find, 'call', _319 => _319((m) => m.id === _chunkOLNIPTB3cjs.standardBlendMode.call(void 0, mode)), 'optionalAccess', _320 => _320.label]), () => ( _chunkOLNIPTB3cjs.standardBlendMode.call(void 0, mode)));
5799
+ const label = _nullishCoalesce(_optionalChain([_chunkOLNIPTB3cjs.BLEND_MODES, 'access', _322 => _322.find, 'call', _323 => _323((m) => m.id === mode), 'optionalAccess', _324 => _324.label]), () => ( mode));
5800
+ const std = _nullishCoalesce(_optionalChain([_chunkOLNIPTB3cjs.BLEND_MODES, 'access', _325 => _325.find, 'call', _326 => _326((m) => m.id === _chunkOLNIPTB3cjs.standardBlendMode.call(void 0, mode)), 'optionalAccess', _327 => _327.label]), () => ( _chunkOLNIPTB3cjs.standardBlendMode.call(void 0, mode)));
5751
5801
  const list = names.map((n) => `"${n}"`).join(", ");
5752
5802
  const one = names.length === 1;
5753
5803
  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).`);
@@ -5863,7 +5913,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5863
5913
  const { src, pixels } = this.importImage(options, "The reference image");
5864
5914
  const ref2 = {
5865
5915
  id: `ref${this.nextReferenceId++}`,
5866
- name: _optionalChain([options, 'access', _321 => _321.name, 'optionalAccess', _322 => _322.trim, 'call', _323 => _323()]) || `Reference ${this.guides.references.length + 1}`,
5916
+ name: _optionalChain([options, 'access', _328 => _328.name, 'optionalAccess', _329 => _329.trim, 'call', _330 => _330()]) || `Reference ${this.guides.references.length + 1}`,
5867
5917
  src,
5868
5918
  width: pixels.width,
5869
5919
  height: pixels.height,
@@ -5942,7 +5992,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5942
5992
  try {
5943
5993
  const px = this.decodeImage(ref2.src, `Reference "${ref2.name}"`);
5944
5994
  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 });
5945
- const n = Number(_nullishCoalesce(_optionalChain([/^ref(\d+)$/, 'access', _324 => _324.exec, 'call', _325 => _325(ref2.id), 'optionalAccess', _326 => _326[1]]), () => ( 0)));
5995
+ const n = Number(_nullishCoalesce(_optionalChain([/^ref(\d+)$/, 'access', _331 => _331.exec, 'call', _332 => _332(ref2.id), 'optionalAccess', _333 => _333[1]]), () => ( 0)));
5946
5996
  if (n >= this.nextReferenceId) this.nextReferenceId = n + 1;
5947
5997
  } catch (e) {
5948
5998
  problems.push(e.message);
@@ -5953,7 +6003,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5953
6003
  guides.stencils = [];
5954
6004
  r.stencils.forEach((raw2, i) => {
5955
6005
  try {
5956
- const id = typeof _optionalChain([raw2, 'optionalAccess', _327 => _327.id]) === "string" && /^stencil\d+$/.test(raw2.id) ? raw2.id : `stencil${this.nextStencilId}`;
6006
+ const id = typeof _optionalChain([raw2, 'optionalAccess', _334 => _334.id]) === "string" && /^stencil\d+$/.test(raw2.id) ? raw2.id : `stencil${this.nextStencilId}`;
5957
6007
  guides.stencils.push(normalizeStencil(raw2, id));
5958
6008
  const n = Number(id.slice(7));
5959
6009
  if (n >= this.nextStencilId) this.nextStencilId = n + 1;
@@ -5976,12 +6026,12 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5976
6026
  /** The next free sticker number (ids `st<n>` are unique across the document). */
5977
6027
  nextStickerNumber(doc = this.doc) {
5978
6028
  let n = 0;
5979
- for (const list of Object.values(_nullishCoalesce(doc.stickers, () => ( {})))) for (const st of list) n = Math.max(n, Number(_nullishCoalesce(_optionalChain([/^st(\d+)$/, 'access', _328 => _328.exec, 'call', _329 => _329(st.id), 'optionalAccess', _330 => _330[1]]), () => ( 0))));
6029
+ for (const list of Object.values(_nullishCoalesce(doc.stickers, () => ( {})))) for (const st of list) n = Math.max(n, Number(_nullishCoalesce(_optionalChain([/^st(\d+)$/, 'access', _335 => _335.exec, 'call', _336 => _336(st.id), 'optionalAccess', _337 => _337[1]]), () => ( 0))));
5980
6030
  return n + 1;
5981
6031
  }
5982
6032
  stickerLayer(layerId) {
5983
6033
  const l = this.wetLayer(layerId, "edit the stickers of");
5984
- const stickers = _optionalChain([this, 'access', _331 => _331.doc, 'access', _332 => _332.stickers, 'optionalAccess', _333 => _333[l.id]]);
6034
+ const stickers = _optionalChain([this, 'access', _338 => _338.doc, 'access', _339 => _339.stickers, 'optionalAccess', _340 => _340[l.id]]);
5985
6035
  if (!stickers) throw new PaintEditorError(`Layer "${l.name}" has no stickers; spray some with a sticker brush (list_brushes category sticker).`);
5986
6036
  return { layer: l, stickers };
5987
6037
  }
@@ -5990,7 +6040,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5990
6040
  const id = _nullishCoalesce(layerId, () => ( this.doc.activeLayerId));
5991
6041
  if (!id) return [];
5992
6042
  this.requireLayer(id);
5993
- return (_nullishCoalesce(_optionalChain([this, 'access', _334 => _334.doc, 'access', _335 => _335.stickers, 'optionalAccess', _336 => _336[id]]), () => ( []))).map((s) => ({ ...s }));
6043
+ return (_nullishCoalesce(_optionalChain([this, 'access', _341 => _341.doc, 'access', _342 => _342.stickers, 'optionalAccess', _343 => _343[id]]), () => ( []))).map((s) => ({ ...s }));
5994
6044
  }
5995
6045
  /**
5996
6046
  * Replaces a layer's stickers and redraws its pixels from them (one undo step). With `dirty`,
@@ -6006,15 +6056,15 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
6006
6056
  }
6007
6057
  redrawStickers(layer, stickers, dirty) {
6008
6058
  const partial = dirty && !layer.offset.x && !layer.offset.y;
6009
- return partial ? _chunkNKTNLJUJcjs.stickerSurface.call(void 0, stickers, layer.surface, dirty) : _chunkNKTNLJUJcjs.stickerSurface.call(void 0, stickers);
6059
+ return partial ? _chunk5BR7LC24cjs.stickerSurface.call(void 0, stickers, layer.surface, dirty) : _chunk5BR7LC24cjs.stickerSurface.call(void 0, stickers);
6010
6060
  }
6011
6061
  /** The document from before the sticker preview on screen, or `null` when none is (anything else changed the document since). */
6012
6062
  previewBase() {
6013
- return _optionalChain([this, 'access', _337 => _337.stickerPreview, 'optionalAccess', _338 => _338.shown]) === this.doc ? this.stickerPreview.base : null;
6063
+ return _optionalChain([this, 'access', _344 => _344.stickerPreview, 'optionalAccess', _345 => _345.shown]) === this.doc ? this.stickerPreview.base : null;
6014
6064
  }
6015
6065
  readStickerUpdate(update) {
6016
6066
  try {
6017
- return _chunkNKTNLJUJcjs.normalizeStickerUpdate.call(void 0, update);
6067
+ return _chunk5BR7LC24cjs.normalizeStickerUpdate.call(void 0, update);
6018
6068
  } catch (e) {
6019
6069
  throw new PaintEditorError(e.message);
6020
6070
  }
@@ -6025,7 +6075,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
6025
6075
  const id = _nullishCoalesce(layerId, () => ( this.doc.activeLayerId));
6026
6076
  if (!id) return null;
6027
6077
  this.requireLayer(id);
6028
- const hit = _chunkNKTNLJUJcjs.stickerAt.call(void 0, _nullishCoalesce(_optionalChain([this, 'access', _339 => _339.doc, 'access', _340 => _340.stickers, 'optionalAccess', _341 => _341[id]]), () => ( [])), x, y);
6078
+ const hit = _chunk5BR7LC24cjs.stickerAt.call(void 0, _nullishCoalesce(_optionalChain([this, 'access', _346 => _346.doc, 'access', _347 => _347.stickers, 'optionalAccess', _348 => _348[id]]), () => ( [])), x, y);
6029
6079
  return hit ? { ...hit } : null;
6030
6080
  }
6031
6081
  /** Picks a sticker for the panel and canvas (`null` for none). Editor state, not an undo step. */
@@ -6046,7 +6096,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
6046
6096
  if (i < 0) throw new PaintEditorError(`Layer "${layer.name}" has no sticker "${id}". Call list_stickers for the ids.`);
6047
6097
  const next = { ...stickers[i], ...this.readStickerUpdate(update) };
6048
6098
  const list = stickers.map((s, j) => j === i ? next : s);
6049
- const dirty = [_chunkNKTNLJUJcjs.stickerRect.call(void 0, stickers[i]), _chunkNKTNLJUJcjs.stickerRect.call(void 0, next)];
6099
+ const dirty = [_chunk5BR7LC24cjs.stickerRect.call(void 0, stickers[i]), _chunk5BR7LC24cjs.stickerRect.call(void 0, next)];
6050
6100
  const base = _nullishCoalesce(this.previewBase(), () => ( this.doc));
6051
6101
  const surface = this.redrawStickers(layer, list, dirty);
6052
6102
  this.doc = { ...this.doc, layers: _chunkHB4ICNNAcjs.mapLayer.call(void 0, this.doc.layers, layer.id, () => ({ ...layer, surface, offset: { x: 0, y: 0 } })), stickers: { ..._nullishCoalesce(this.doc.stickers, () => ( {})), [layer.id]: list } };
@@ -6069,7 +6119,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
6069
6119
  if (i < 0) throw new PaintEditorError(`Layer "${layer.name}" has no sticker "${id}". Call list_stickers for the ids.`);
6070
6120
  const u = this.readStickerUpdate(update);
6071
6121
  const next = { ...stickers[i], ...u };
6072
- this.commitStickers("Edit sticker", layer, stickers.map((s, j) => j === i ? next : s), [_chunkNKTNLJUJcjs.stickerRect.call(void 0, stickers[i]), _chunkNKTNLJUJcjs.stickerRect.call(void 0, next)]);
6122
+ this.commitStickers("Edit sticker", layer, stickers.map((s, j) => j === i ? next : s), [_chunk5BR7LC24cjs.stickerRect.call(void 0, stickers[i]), _chunk5BR7LC24cjs.stickerRect.call(void 0, next)]);
6073
6123
  return { ...next };
6074
6124
  }
6075
6125
  /**
@@ -6081,8 +6131,8 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
6081
6131
  const layer = this.wetLayer(layerId, "add stickers to");
6082
6132
  if (!input.length) throw new PaintEditorError("Pass at least one sticker (stamp, x, y).");
6083
6133
  if (input.length > MAX_ADD_STICKERS) throw new PaintEditorError(`At most ${MAX_ADD_STICKERS} stickers per call; split them over several calls.`);
6084
- const existing = _optionalChain([this, 'access', _342 => _342.doc, 'access', _343 => _343.stickers, 'optionalAccess', _344 => _344[layer.id]]);
6085
- if (!_optionalChain([existing, 'optionalAccess', _345 => _345.length])) {
6134
+ const existing = _optionalChain([this, 'access', _349 => _349.doc, 'access', _350 => _350.stickers, 'optionalAccess', _351 => _351[layer.id]]);
6135
+ if (!_optionalChain([existing, 'optionalAccess', _352 => _352.length])) {
6086
6136
  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.`);
6087
6137
  }
6088
6138
  let n = this.nextStickerNumber();
@@ -6098,7 +6148,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
6098
6148
  const id = n++;
6099
6149
  return { id: `st${id}`, size: 48, rotation: 0, color: this.color, opacity: 1, seed: _nullishCoalesce(raw.seed, () => ( _chunkPQ3H2AANcjs.mix32.call(void 0, id * 2654435761 >>> 0) & 2147483647)), ...u };
6100
6150
  });
6101
- this.commitStickers("Add stickers", layer, [..._nullishCoalesce(existing, () => ( [])), ...added], _optionalChain([existing, 'optionalAccess', _346 => _346.length]) ? added.map(_chunkNKTNLJUJcjs.stickerRect) : void 0);
6151
+ this.commitStickers("Add stickers", layer, [..._nullishCoalesce(existing, () => ( [])), ...added], _optionalChain([existing, 'optionalAccess', _353 => _353.length]) ? added.map(_chunk5BR7LC24cjs.stickerRect) : void 0);
6102
6152
  return added.map((s) => ({ ...s }));
6103
6153
  }
6104
6154
  /** Brings stickers to the top (`front`) or bottom of their layer (one undo step). */
@@ -6108,7 +6158,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
6108
6158
  const picked = stickers.filter((s) => ids.includes(s.id));
6109
6159
  const rest = stickers.filter((s) => !ids.includes(s.id));
6110
6160
  const next = to === "front" ? [...rest, ...picked] : [...picked, ...rest];
6111
- this.commitStickers("Arrange stickers", layer, next, picked.map(_chunkNKTNLJUJcjs.stickerRect));
6161
+ this.commitStickers("Arrange stickers", layer, next, picked.map(_chunk5BR7LC24cjs.stickerRect));
6112
6162
  return next.map((s) => s.id);
6113
6163
  }
6114
6164
  /** Deletes stickers (`ids`, or all of them on the layer) (one undo step). Returns the ids removed. */
@@ -6118,7 +6168,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
6118
6168
  for (const id of ids) if (!stickers.some((s) => s.id === id)) throw new PaintEditorError(`Layer "${layer.name}" has no sticker "${id}". Call list_stickers for the ids.`);
6119
6169
  }
6120
6170
  const removed = ids ? [...ids] : stickers.map((s) => s.id);
6121
- this.commitStickers("Remove stickers", layer, stickers.filter((s) => !removed.includes(s.id)), ids ? stickers.filter((s) => removed.includes(s.id)).map(_chunkNKTNLJUJcjs.stickerRect) : void 0);
6171
+ this.commitStickers("Remove stickers", layer, stickers.filter((s) => !removed.includes(s.id)), ids ? stickers.filter((s) => removed.includes(s.id)).map(_chunk5BR7LC24cjs.stickerRect) : void 0);
6122
6172
  return removed;
6123
6173
  }
6124
6174
  /** Sets a layer's stickers (replays). */
@@ -6137,20 +6187,20 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
6137
6187
  }
6138
6188
  liveStrokeLayer(layerId, what) {
6139
6189
  const l = this.wetLayer(layerId, what);
6140
- const strokes = _optionalChain([this, 'access', _347 => _347.doc, 'access', _348 => _348.liveStrokes, 'optionalAccess', _349 => _349[l.id]]);
6190
+ const strokes = _optionalChain([this, 'access', _354 => _354.doc, 'access', _355 => _355.liveStrokes, 'optionalAccess', _356 => _356[l.id]]);
6141
6191
  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.`);
6142
6192
  return { layer: l, strokes };
6143
6193
  }
6144
6194
  /** Whether a layer is a live stroke layer. */
6145
6195
  isLiveStrokeLayer(layerId) {
6146
- return Boolean(_optionalChain([this, 'access', _350 => _350.doc, 'access', _351 => _351.liveStrokes, 'optionalAccess', _352 => _352[layerId]]));
6196
+ return Boolean(_optionalChain([this, 'access', _357 => _357.doc, 'access', _358 => _358.liveStrokes, 'optionalAccess', _359 => _359[layerId]]));
6147
6197
  }
6148
6198
  /** Makes an empty pixel layer a live stroke layer (one undo step). */
6149
6199
  convertToLiveStrokes(layerId) {
6150
6200
  this.requireIdle("converting a layer");
6151
6201
  const l = this.paintTarget(layerId, "convert");
6152
- if (_optionalChain([this, 'access', _353 => _353.doc, 'access', _354 => _354.liveStrokes, 'optionalAccess', _355 => _355[l.id]])) return this.describeLayer(l);
6153
- if (_optionalChain([this, 'access', _356 => _356.doc, 'access', _357 => _357.stickers, 'optionalAccess', _358 => _358[l.id], 'optionalAccess', _359 => _359.length])) throw new PaintEditorError(`Layer "${l.name}" is a sticker layer; add a stroke layer instead (add_layer {type: "strokes"}).`);
6202
+ if (_optionalChain([this, 'access', _360 => _360.doc, 'access', _361 => _361.liveStrokes, 'optionalAccess', _362 => _362[l.id]])) return this.describeLayer(l);
6203
+ if (_optionalChain([this, 'access', _363 => _363.doc, 'access', _364 => _364.stickers, 'optionalAccess', _365 => _365[l.id], 'optionalAccess', _366 => _366.length])) throw new PaintEditorError(`Layer "${l.name}" is a sticker layer; add a stroke layer instead (add_layer {type: "strokes"}).`);
6154
6204
  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"}).`);
6155
6205
  this.commit("Convert to stroke layer", { ...this.doc, liveStrokes: { ..._nullishCoalesce(this.doc.liveStrokes, () => ( {})), [l.id]: [] } });
6156
6206
  return this.describeLayer(this.getLayer(l.id));
@@ -6163,7 +6213,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
6163
6213
  findLiveStroke(id) {
6164
6214
  for (const [layerId, strokes] of Object.entries(_nullishCoalesce(this.doc.liveStrokes, () => ( {})))) {
6165
6215
  const index = strokes.findIndex((x) => x.id === id);
6166
- const layer = _optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, this.doc.layers, layerId), 'optionalAccess', _360 => _360.layer]);
6216
+ const layer = _optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, this.doc.layers, layerId), 'optionalAccess', _367 => _367.layer]);
6167
6217
  if (index >= 0 && isPixelLayer(layer)) return { layer, strokes, index };
6168
6218
  }
6169
6219
  const baked = this.doc.strokes.some((x) => x.id === id);
@@ -6183,15 +6233,15 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
6183
6233
  let brush = was.brush;
6184
6234
  if (update.brushId !== void 0) {
6185
6235
  const b = this.requireBrush(update.brushId);
6186
- brush = _chunkNKTNLJUJcjs.normalizePaintBrush.call(void 0, { tip: { ...b.tip, size: was.brush.tip.size } }, b);
6236
+ brush = _chunk5BR7LC24cjs.normalizePaintBrush.call(void 0, { tip: { ...b.tip, size: was.brush.tip.size } }, b);
6187
6237
  }
6188
6238
  if (update.brush !== void 0) {
6189
6239
  if (!update.brush || typeof update.brush !== "object") throw new PaintEditorError("brush must be an object of brush settings (as set_brush takes).");
6190
- brush = _chunkNKTNLJUJcjs.normalizePaintBrush.call(void 0, { ...update.brush, id: brush.id }, brush);
6240
+ brush = _chunk5BR7LC24cjs.normalizePaintBrush.call(void 0, { ...update.brush, id: brush.id }, brush);
6191
6241
  }
6192
6242
  const why = liveStrokeRefusal(brush);
6193
6243
  if (why) throw new PaintEditorError(why);
6194
- const next = { ...was, brush: _chunkNKTNLJUJcjs.brushToJSON.call(void 0, brush) };
6244
+ const next = { ...was, brush: _chunk5BR7LC24cjs.brushToJSON.call(void 0, brush) };
6195
6245
  if (update.seed !== void 0) {
6196
6246
  if (!Number.isInteger(update.seed) || update.seed < 0) throw new PaintEditorError(`seed ${update.seed} must be a whole number of 0 or more.`);
6197
6247
  next.seed = update.seed;
@@ -6202,7 +6252,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
6202
6252
  }
6203
6253
  if (update.paint !== void 0) {
6204
6254
  if (update.paint === null) delete next.paint;
6205
- else if (_chunkNKTNLJUJcjs.isPaintEffectPaint.call(void 0, update.paint)) {
6255
+ else if (_chunk5BR7LC24cjs.isPaintEffectPaint.call(void 0, update.paint)) {
6206
6256
  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).`);
6207
6257
  next.paint = JSON.parse(JSON.stringify(update.paint));
6208
6258
  } else {
@@ -6213,7 +6263,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
6213
6263
  } else next.paint = JSON.parse(JSON.stringify(p));
6214
6264
  }
6215
6265
  }
6216
- const rgb = _chunkNKTNLJUJcjs.hexToRgb8.call(void 0, next.color).map((v) => v / 255);
6266
+ const rgb = _chunk5BR7LC24cjs.hexToRgb8.call(void 0, next.color).map((v) => v / 255);
6217
6267
  const load = brushLoadForStroke(brush, _chunkPQ3H2AANcjs.EMPTY_MIXER_LOAD, rgb);
6218
6268
  if (load.reservoir || load.pickup) next.load = load;
6219
6269
  else delete next.load;
@@ -6258,9 +6308,9 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
6258
6308
  const layers = /* @__PURE__ */ new Map();
6259
6309
  for (const f of found) layers.set(f.layer.id, f.layer);
6260
6310
  for (const [layerId, layer] of layers) {
6261
- const gone = (_nullishCoalesce(_optionalChain([doc, 'access', _361 => _361.liveStrokes, 'optionalAccess', _362 => _362[layerId]]), () => ( []))).filter((x) => ids.includes(x.id));
6311
+ const gone = (_nullishCoalesce(_optionalChain([doc, 'access', _368 => _368.liveStrokes, 'optionalAccess', _369 => _369[layerId]]), () => ( []))).filter((x) => ids.includes(x.id));
6262
6312
  for (const x of gone) bounds = unionRect(bounds, this.strokeArea(x));
6263
- doc = this.withLiveStrokes(doc, layer, (_nullishCoalesce(_optionalChain([doc, 'access', _363 => _363.liveStrokes, 'optionalAccess', _364 => _364[layerId]]), () => ( []))).filter((x) => !ids.includes(x.id)), this.strokeAreas(gone));
6313
+ doc = this.withLiveStrokes(doc, layer, (_nullishCoalesce(_optionalChain([doc, 'access', _370 => _370.liveStrokes, 'optionalAccess', _371 => _371[layerId]]), () => ( []))).filter((x) => !ids.includes(x.id)), this.strokeAreas(gone));
6264
6314
  }
6265
6315
  this.commit(ids.length === 1 ? "Remove stroke" : "Remove strokes", doc);
6266
6316
  return { removed: [...ids], bounds };
@@ -6328,7 +6378,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
6328
6378
  }
6329
6379
  withLiveStrokes(doc, layer, list, dirty) {
6330
6380
  if (_chunkHB4ICNNAcjs.isLayerLocked.call(void 0, layer, "pixels")) throw new PaintEditorError(`Layer "${layer.name}" has its pixels locked; unlock it (update_layer locks) first.`);
6331
- const current = _optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, doc.layers, layer.id), 'optionalAccess', _365 => _365.layer]);
6381
+ const current = _optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, doc.layers, layer.id), 'optionalAccess', _372 => _372.layer]);
6332
6382
  const surface = this.drawLiveStrokes(_nullishCoalesce(current, () => ( layer)), list, dirty);
6333
6383
  const next = { ...doc, layers: _chunkHB4ICNNAcjs.mapLayer.call(void 0, doc.layers, layer.id, (l) => ({ ...l, surface, offset: { x: 0, y: 0 } })), liveStrokes: { ..._nullishCoalesce(doc.liveStrokes, () => ( {})), [layer.id]: [...list] } };
6334
6384
  return this.withPaintEvent(next, { kind: "live-strokes", layerId: layer.id, data: { strokes: list.map((x) => JSON.parse(JSON.stringify(x))) } });
@@ -6357,11 +6407,13 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
6357
6407
  if (!cancelled && drawn) out = drawn;
6358
6408
  }
6359
6409
  };
6360
- const init = { layerId: plain.id, 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, () => ( [])) };
6410
+ const paint = st.paint && this.liveEffectAt !== null && isLiveEffect(st) ? framePaint(st.paint, this.liveEffectAt) : st.paint;
6411
+ const init = { layerId: plain.id, color: st.color, brush: st.brush, seed: st.seed, copies: _nullishCoalesce(st.copies, () => ( [])), ...st.load ? { load: st.load } : {}, ...paint ? { paint } : {}, snapToPerspective: false, stencils: false, maskStencils: _nullishCoalesce(st.stencils, () => ( [])) };
6361
6412
  const session = this.sessionFor({ ...doc, layers: _chunkHB4ICNNAcjs.mapLayer.call(void 0, doc.layers, plain.id, () => ({ ...plain, surface })) }, init, host);
6362
6413
  session.push(st.points);
6363
6414
  const result = session.end();
6364
- this.paintedBounds.set(st, result.bounds);
6415
+ const had = this.paintedBounds.get(st);
6416
+ this.paintedBounds.set(st, had && result.bounds ? unionRect(had, result.bounds) : _nullishCoalesce(_nullishCoalesce(result.bounds, () => ( had)), () => ( null)));
6365
6417
  return { surface: out, bounds: result.bounds };
6366
6418
  }
6367
6419
  /**
@@ -6398,14 +6450,154 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
6398
6450
  for (const r of rects) surface = _chunk474IQG74cjs.writeRegion.call(void 0, surface, r, _chunk474IQG74cjs.readRegion.call(void 0, drawn, r));
6399
6451
  return surface;
6400
6452
  }
6453
+ // --- Live effect paint ------------------------------------------------------------
6454
+ /** The view's layers: stroke layers playing live effects at `effectTime`, the rest as they are. */
6455
+ animatedView() {
6456
+ if (!this.animatedLayers.size) return this.doc.layers;
6457
+ let layers = this.doc.layers;
6458
+ for (const [id, a] of this.animatedLayers) {
6459
+ const l = _optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, layers, id), 'optionalAccess', _373 => _373.layer]);
6460
+ if (isPixelLayer(l) && l.surface === a.base) layers = _chunkHB4ICNNAcjs.mapLayer.call(void 0, layers, id, () => ({ ...l, surface: a.surface }));
6461
+ }
6462
+ return layers;
6463
+ }
6464
+ /** Stroke layers with live effect strokes, and the distinct live sources (frame 0). */
6465
+ liveEffects(doc = this.doc) {
6466
+ const layers = [];
6467
+ const sources = /* @__PURE__ */ new Map();
6468
+ for (const [id, strokes] of Object.entries(_nullishCoalesce(doc.liveStrokes, () => ( {})))) {
6469
+ const layer = _optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, doc.layers, id), 'optionalAccess', _374 => _374.layer]);
6470
+ const live = strokes.filter(isLiveEffect);
6471
+ if (!isPixelLayer(layer) || !live.length) continue;
6472
+ layers.push({ layer, strokes });
6473
+ for (const st of live) sources.set(_chunk5BR7LC24cjs.effectPaintKey.call(void 0, st.paint), st.paint);
6474
+ }
6475
+ return { layers, sources: [...sources.values()] };
6476
+ }
6477
+ /** What plays: the live effect strokes and their layers, or `null` when nothing does. */
6478
+ getAnimation() {
6479
+ const { layers, sources } = this.liveEffects();
6480
+ if (!layers.length) return null;
6481
+ return { layerIds: layers.map((x) => x.layer.id), strokes: layers.reduce((n, x) => n + x.strokes.filter(isLiveEffect).length, 0), sources: sources.length };
6482
+ }
6483
+ /** Plays or pauses live effect paint, and caps its frame rate (1..60). Editor state, not an undo step. */
6484
+ setEffectPlayback(update) {
6485
+ if (update.playing !== void 0 && typeof update.playing !== "boolean") throw new PaintEditorError("playing must be true or false.");
6486
+ if (update.fps !== void 0 && !(Number.isInteger(update.fps) && update.fps >= 1 && update.fps <= 60)) throw new PaintEditorError(`fps ${update.fps} is out of range; use a whole number 1..60.`);
6487
+ this.effectPlaybackState = { ...this.effectPlaybackState, ...update };
6488
+ this.emit([]);
6489
+ return { ...this.effectPlaybackState, time: this.effectTime };
6490
+ }
6491
+ /** The surfaces of every stroke layer with live effects at `time` ms, drawn in full (frames rendered first). */
6492
+ async liveSurfacesAt(time) {
6493
+ const { layers, sources } = this.liveEffects();
6494
+ await this.prepareEffectPaints(sources.map((p) => framePaint(p, time)));
6495
+ const out = /* @__PURE__ */ new Map();
6496
+ this.liveEffectAt = time;
6497
+ try {
6498
+ for (const { layer, strokes } of layers) out.set(layer.id, this.drawLiveStrokes({ ...layer, offset: { x: 0, y: 0 } }, strokes));
6499
+ } finally {
6500
+ this.liveEffectAt = null;
6501
+ }
6502
+ return out;
6503
+ }
6504
+ /**
6505
+ * Shows the live effects at `time` ms (each live stroke's effect at its own time plus `time`):
6506
+ * renders their frames, then redraws only where live effect strokes paint. Nothing in the
6507
+ * document changes. Resolves `false` when the document changed while frames rendered (the next
6508
+ * frame catches up).
6509
+ */
6510
+ async showEffectTime(time) {
6511
+ this.checkTime(time);
6512
+ const { layers, sources } = this.liveEffects();
6513
+ const revision = this.docRevision;
6514
+ await this.prepareEffectPaints(sources.map((p) => framePaint(p, time)));
6515
+ if (revision !== this.docRevision || this.session) return false;
6516
+ const next = /* @__PURE__ */ new Map();
6517
+ const dirty = [];
6518
+ this.liveEffectAt = time;
6519
+ try {
6520
+ for (const { layer, strokes } of layers) {
6521
+ const shown = this.animatedLayers.get(layer.id);
6522
+ const from = shown && shown.base === layer.surface ? shown.surface : layer.surface;
6523
+ const areas = strokes.filter(isLiveEffect).flatMap((st) => [liveStrokeBounds(st), ...this.paintedBounds.get(st) ? [this.paintedBounds.get(st)] : []]);
6524
+ const surface = this.drawLiveStrokes({ ...layer, surface: from, offset: { x: 0, y: 0 } }, strokes, layer.offset.x || layer.offset.y ? null : areas);
6525
+ next.set(layer.id, { base: layer.surface, surface });
6526
+ dirty.push(...areas);
6527
+ }
6528
+ } finally {
6529
+ this.liveEffectAt = null;
6530
+ }
6531
+ this.animatedLayers = next;
6532
+ this.effectTime = time;
6533
+ this.emit(dirty);
6534
+ return true;
6535
+ }
6536
+ /**
6537
+ * Plays live effect paint in the view until `stop`: a frame per tick of `clock` (default
6538
+ * animation frames) at most `fps` a second, one render in flight. Idle while paused, while a
6539
+ * stroke is painted, or when nothing is live. The bindings start it while the editor is shown.
6540
+ */
6541
+ playEffects(clock = defaultEffectClock) {
6542
+ let stopped = false;
6543
+ let cancel = () => {
6544
+ };
6545
+ let last = -Infinity;
6546
+ let started = clock.now() - this.effectTime;
6547
+ const tick = () => {
6548
+ if (stopped) return;
6549
+ const now = clock.now();
6550
+ const { playing, fps } = this.effectPlaybackState;
6551
+ if (!playing) started = now - this.effectTime;
6552
+ if (!playing || this.session || now - last < 1e3 / fps - 1 || !this.liveEffects().layers.length) {
6553
+ cancel = clock.frame(tick);
6554
+ return;
6555
+ }
6556
+ last = now;
6557
+ this.showEffectTime(Math.max(0, now - started)).then(
6558
+ () => {
6559
+ if (!stopped) cancel = clock.frame(tick);
6560
+ },
6561
+ () => {
6562
+ if (!stopped) cancel = clock.frame(tick);
6563
+ }
6564
+ );
6565
+ };
6566
+ cancel = clock.frame(tick);
6567
+ return {
6568
+ stop() {
6569
+ stopped = true;
6570
+ cancel();
6571
+ }
6572
+ };
6573
+ }
6574
+ /**
6575
+ * Runs `fn` with the painting as it is `time` ms into its live effects (see `getAnimation`): for
6576
+ * exports at a moment. Nothing in the document changes.
6577
+ */
6578
+ async withEffectTime(time, fn) {
6579
+ this.checkTime(time);
6580
+ const surfaces = await this.liveSurfacesAt(time);
6581
+ const was = this.frameOverride;
6582
+ this.frameOverride = surfaces;
6583
+ try {
6584
+ return await fn();
6585
+ } finally {
6586
+ this.frameOverride = was;
6587
+ }
6588
+ }
6589
+ /** The painting composited `time` ms into its live effects, like `compositePixels`. Nothing in the document changes. */
6590
+ async renderAnimationFrame(time, options = {}) {
6591
+ return this.withEffectTime(time, () => this.compositePixels(options));
6592
+ }
6401
6593
  // --- Stencils --------------------------------------------------------------------
6402
- __init116() {this.stencilCache = null}
6403
- __init117() {this.nextStencilId = 1}
6594
+ __init123() {this.stencilCache = null}
6595
+ __init124() {this.nextStencilId = 1}
6404
6596
  /** The mask stencils' coverage over the canvas (cached), or `null` when none masks. */
6405
6597
  stencilSelection(stencils = this.guides.stencils) {
6406
6598
  const { width, height } = this.doc.canvas;
6407
6599
  const size = `${width}x${height}`;
6408
- if (_optionalChain([this, 'access', _366 => _366.stencilCache, 'optionalAccess', _367 => _367.key]) === stencils && this.stencilCache.size === size) return this.stencilCache.mask;
6600
+ if (_optionalChain([this, 'access', _375 => _375.stencilCache, 'optionalAccess', _376 => _376.key]) === stencils && this.stencilCache.size === size) return this.stencilCache.mask;
6409
6601
  const mask = stencilMask(stencils, width, height);
6410
6602
  this.stencilCache = { key: stencils, size, mask };
6411
6603
  return mask;
@@ -6467,7 +6659,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
6467
6659
  makeSwatch(color, name) {
6468
6660
  const p = typeof color === "string" ? { type: "color", color: parseColor(color) } : this.readStrokePaint(color);
6469
6661
  const out = { color: _chunkPQ3H2AANcjs.paintSourceColor.call(void 0, p, { paint: this.color, secondary: this.secondaryColor }) };
6470
- if (_optionalChain([name, 'optionalAccess', _368 => _368.trim, 'call', _369 => _369()])) out.name = name.trim();
6662
+ if (_optionalChain([name, 'optionalAccess', _377 => _377.trim, 'call', _378 => _378()])) out.name = name.trim();
6471
6663
  if (p.type === "gradient") out.paint = p;
6472
6664
  return out;
6473
6665
  }
@@ -6519,7 +6711,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
6519
6711
  * mix becomes the paint colour. Returns the mixed colour and the pile's bounds.
6520
6712
  */
6521
6713
  mixOnPad(paints, options = {}) {
6522
- const parsed = (_nullishCoalesce(paints, () => ( []))).map((p, i) => ({ color: parseColor(_optionalChain([p, 'optionalAccess', _370 => _370.color]), `paints[${i}].color`), parts: _optionalChain([p, 'optionalAccess', _371 => _371.parts]) }));
6714
+ const parsed = (_nullishCoalesce(paints, () => ( []))).map((p, i) => ({ color: parseColor(_optionalChain([p, 'optionalAccess', _379 => _379.color]), `paints[${i}].color`), parts: _optionalChain([p, 'optionalAccess', _380 => _380.parts]) }));
6523
6715
  let r;
6524
6716
  try {
6525
6717
  r = this.pad.mix(parsed, options);
@@ -6608,13 +6800,31 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
6608
6800
  }
6609
6801
  /** A layer's tile surface (live while stroking), for thumbnails. */
6610
6802
  layerSurface(id) {
6611
- const l = _optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, this.currentLayers(), id), 'optionalAccess', _372 => _372.layer]);
6803
+ const l = _optionalChain([_chunkHB4ICNNAcjs.findLayer.call(void 0, this.currentLayers(), id), 'optionalAccess', _381 => _381.layer]);
6612
6804
  return isPixelLayer(l) ? l.surface : null;
6613
6805
  }
6614
6806
  }, _class10.__initStatic(), _class10);
6615
6807
  var MAX_IMAGE_SIDE = 8192;
6616
6808
  var movePoint = (p, dx, dy) => ({ x: p.x + dx, y: p.y + dy });
6617
6809
  var moveRect = (r, dx, dy) => ({ ...r, x: r.x + dx, y: r.y + dy });
6810
+ function isLiveEffect(s) {
6811
+ return _optionalChain([s, 'access', _382 => _382.paint, 'optionalAccess', _383 => _383.type]) === "effect" && s.paint.live === true;
6812
+ }
6813
+ function framePaint(p, t) {
6814
+ return { ...p, time: p.time + t };
6815
+ }
6816
+ var MAX_LIVE_EFFECT_SOURCES = 8;
6817
+ var defaultEffectClock = {
6818
+ now: () => typeof performance !== "undefined" ? performance.now() : Date.now(),
6819
+ frame: (cb) => {
6820
+ if (typeof requestAnimationFrame === "undefined") {
6821
+ const t = setTimeout(cb, 16);
6822
+ return () => clearTimeout(t);
6823
+ }
6824
+ const id = requestAnimationFrame(cb);
6825
+ return () => cancelAnimationFrame(id);
6826
+ }
6827
+ };
6618
6828
  function clipRect(r, width, height) {
6619
6829
  const x0 = Math.max(0, Math.floor(r.x));
6620
6830
  const y0 = Math.max(0, Math.floor(r.y));
@@ -6623,7 +6833,7 @@ function clipRect(r, width, height) {
6623
6833
  return x1 > x0 && y1 > y0 ? { x: x0, y: y0, width: x1 - x0, height: y1 - y0 } : null;
6624
6834
  }
6625
6835
  function withLiveStroke(doc, stroke) {
6626
- const list = _optionalChain([doc, 'access', _373 => _373.liveStrokes, 'optionalAccess', _374 => _374[stroke.layerId]]);
6836
+ const list = _optionalChain([doc, 'access', _384 => _384.liveStrokes, 'optionalAccess', _385 => _385[stroke.layerId]]);
6627
6837
  return list ? { ...doc, liveStrokes: { ...doc.liveStrokes, [stroke.layerId]: [...list, stroke] } } : doc;
6628
6838
  }
6629
6839
  function shiftDocument(doc, dx, dy) {
@@ -6650,9 +6860,9 @@ function shiftDocument(doc, dx, dy) {
6650
6860
  if (doc.liveStrokes) out.liveStrokes = Object.fromEntries(Object.entries(doc.liveStrokes).map(([id, list]) => [id, list.map(moveStroke)]));
6651
6861
  if (doc.paintEvents) {
6652
6862
  out.paintEvents = doc.paintEvents.map((e) => {
6653
- const list = e.kind === "stickers" ? _optionalChain([e, 'access', _375 => _375.data, 'optionalAccess', _376 => _376.stickers]) : void 0;
6863
+ const list = e.kind === "stickers" ? _optionalChain([e, 'access', _386 => _386.data, 'optionalAccess', _387 => _387.stickers]) : void 0;
6654
6864
  if (list) return { ...e, data: { ...e.data, stickers: moveStickers(list) } };
6655
- const strokes = e.kind === "live-strokes" ? _optionalChain([e, 'access', _377 => _377.data, 'optionalAccess', _378 => _378.strokes]) : void 0;
6865
+ const strokes = e.kind === "live-strokes" ? _optionalChain([e, 'access', _388 => _388.data, 'optionalAccess', _389 => _389.strokes]) : void 0;
6656
6866
  return strokes ? { ...e, data: { ...e.data, strokes: strokes.map(moveStroke) } } : e;
6657
6867
  });
6658
6868
  }
@@ -6734,8 +6944,8 @@ function strokeSchedule(points) {
6734
6944
  return total > 0 ? acc.map((d) => d / total) : points.map(() => 1);
6735
6945
  }
6736
6946
  function strokeDuration(points, max = 1800) {
6737
- const t0 = _optionalChain([points, 'access', _379 => _379[0], 'optionalAccess', _380 => _380.t]);
6738
- const t1 = _optionalChain([points, 'access', _381 => _381[points.length - 1], 'optionalAccess', _382 => _382.t]);
6947
+ const t0 = _optionalChain([points, 'access', _390 => _390[0], 'optionalAccess', _391 => _391.t]);
6948
+ const t1 = _optionalChain([points, 'access', _392 => _392[points.length - 1], 'optionalAccess', _393 => _393.t]);
6739
6949
  let ms;
6740
6950
  if (points.every((p) => Number.isFinite(p.t)) && t1 > t0) ms = t1 - t0;
6741
6951
  else {
@@ -6789,7 +6999,7 @@ var PaintDirector = class {
6789
6999
  }
6790
7000
  where(id) {
6791
7001
  const a = this.presence.get(id);
6792
- return { x: _nullishCoalesce(_optionalChain([a, 'optionalAccess', _383 => _383.x]), () => ( 0)), y: _nullishCoalesce(_optionalChain([a, 'optionalAccess', _384 => _384.y]), () => ( 0)) };
7002
+ return { x: _nullishCoalesce(_optionalChain([a, 'optionalAccess', _394 => _394.x]), () => ( 0)), y: _nullishCoalesce(_optionalChain([a, 'optionalAccess', _395 => _395.y]), () => ( 0)) };
6793
7003
  }
6794
7004
  /** Glides to `to`; an actor that just appeared starts there instead of the corner. */
6795
7005
  async glide(id, to, ms = 380) {
@@ -6836,8 +7046,8 @@ var PaintDirector = class {
6836
7046
  }
6837
7047
  case "replay": {
6838
7048
  await this.say(id, command.note, 500);
6839
- const source = c.getStrokes().filter((s) => _optionalChain([command, 'access', _385 => _385.replay, 'access', _386 => _386.strokeIds, 'optionalAccess', _387 => _387.includes, 'call', _388 => _388(s.id)]));
6840
- const first = _optionalChain([source, 'access', _389 => _389[0], 'optionalAccess', _390 => _390.points, 'access', _391 => _391[0]]);
7049
+ const source = c.getStrokes().filter((s) => _optionalChain([command, 'access', _396 => _396.replay, 'access', _397 => _397.strokeIds, 'optionalAccess', _398 => _398.includes, 'call', _399 => _399(s.id)]));
7050
+ const first = _optionalChain([source, 'access', _400 => _400[0], 'optionalAccess', _401 => _401.points, 'access', _402 => _402[0]]);
6841
7051
  if (first) await this.glide(id, first);
6842
7052
  const result = c.replayStrokes(command.replay);
6843
7053
  if (result.bounds) await this.glide(id, centre(result.bounds), 520);
@@ -7018,7 +7228,7 @@ function createPaintStickerTools(c) {
7018
7228
  items: {
7019
7229
  type: "object",
7020
7230
  properties: {
7021
- stamp: { type: "string", enum: [..._chunkNKTNLJUJcjs.STAMP_KINDS], description: "The stamp." },
7231
+ stamp: { type: "string", enum: [..._chunk5BR7LC24cjs.STAMP_KINDS], description: "The stamp." },
7022
7232
  x: { type: "number", description: "Centre x in document pixels." },
7023
7233
  y: { type: "number", description: "Centre y in document pixels." },
7024
7234
  size: { type: "number", minimum: 2, maximum: 2048, description: "Diameter in pixels (default 48)." },
@@ -7048,7 +7258,7 @@ function createPaintStickerTools(c) {
7048
7258
  properties: {
7049
7259
  layerId: LAYER_ID,
7050
7260
  id: { type: "string", description: "Sticker id from list_stickers." },
7051
- stamp: { type: "string", enum: [..._chunkNKTNLJUJcjs.STAMP_KINDS], description: "Another stamp." },
7261
+ stamp: { type: "string", enum: [..._chunk5BR7LC24cjs.STAMP_KINDS], description: "Another stamp." },
7052
7262
  x: { type: "number", description: "Centre x in document pixels." },
7053
7263
  y: { type: "number", description: "Centre y in document pixels." },
7054
7264
  size: { type: "number", minimum: 2, maximum: 2048, description: "Diameter in pixels." },
@@ -7926,7 +8136,7 @@ var BEHAVIOR = {
7926
8136
  type: "object",
7927
8137
  description: "Multi-coloured brush (the older form of paint, the brush's own gradient: tip is across-tip, dab is distance in dabs or random). Read back from paint when it has a multi-colour equivalent. Missing fields keep their current values.",
7928
8138
  properties: {
7929
- mode: { type: "string", enum: [..._chunkNKTNLJUJcjs.MULTI_COLOR_MODES], description: "off; tip: the colours lie side by side across the tip (stripes along the stroke, like a brush loaded with several paints); dab: the colour changes along the stroke." },
8139
+ mode: { type: "string", enum: [..._chunk5BR7LC24cjs.MULTI_COLOR_MODES], description: "off; tip: the colours lie side by side across the tip (stripes along the stroke, like a brush loaded with several paints); dab: the colour changes along the stroke." },
7930
8140
  colors: { type: "array", maxItems: 8, items: { ...COLOR3 }, description: "2..8 colours #rrggbb; fewer than 2 uses the paint colour and the secondary colour." },
7931
8141
  order: { type: "string", enum: ["sequence", "random"], description: "dab mode: sequence runs through the colours in order, blending between them; random picks one per run of dabs (seeded)." },
7932
8142
  length: { type: "integer", minimum: 1, maximum: 500, description: "dab mode: dabs per colour (default 12)." },
@@ -7967,10 +8177,10 @@ var WET_BRUSH = {
7967
8177
  properties: {
7968
8178
  tool: {
7969
8179
  type: "string",
7970
- enum: [..._chunkNKTNLJUJcjs.WET_TOOLS],
8180
+ enum: [..._chunk5BR7LC24cjs.WET_TOOLS],
7971
8181
  description: "paint: water and pigment (picks up and mixes wet paint by behavior.pickup / mix); water: clear water (with rewet it lifts dried paint); dry: a hair dryer, takes water; blow: pushes the water along the stroke; blend: evens out wet pigment; smudge: drags wet paint; blot: a tissue, takes wet paint up (erase wet)."
7972
8182
  },
7973
- medium: { type: "string", enum: [..._chunkNKTNLJUJcjs.WET_MEDIA], description: "The medium: watercolor, gouache or oil. A layer takes the medium's wet settings the first time it holds wet paint (oil: thick, barely flows, stays wet long and blends into the wet paint it meets)." },
8183
+ medium: { type: "string", enum: [..._chunk5BR7LC24cjs.WET_MEDIA], description: "The medium: watercolor, gouache or oil. A layer takes the medium's wet settings the first time it holds wet paint (oil: thick, barely flows, stays wet long and blends into the wet paint it meets)." },
7974
8184
  load: { type: "number", minimum: 0, maximum: 1, description: "Paint loading: 1 never runs out; lower, the brush runs dry along a long stroke (each stroke reloads)." },
7975
8185
  thinner: { type: "number", minimum: 0, maximum: 1, description: "Thinner (water or solvent): more transparent, runnier paint." },
7976
8186
  water: { type: "number", minimum: 0, maximum: 1, description: "Wetness: water laid per stroke, 0.2 a damp brush .. 1 a dripping one." },
@@ -7987,7 +8197,7 @@ var IMPASTO_BRUSH = {
7987
8197
  properties: {
7988
8198
  tool: {
7989
8199
  type: "string",
7990
- enum: [..._chunkNKTNLJUJcjs.IMPASTO_TOOLS],
8200
+ enum: [..._chunk5BR7LC24cjs.IMPASTO_TOOLS],
7991
8201
  description: "brush: thick paint with bristle ridges along the stroke; tube: blobs squeezed from the tube; knife: a palette knife that scrapes the relief flat and smears the paint; roller: a flat stippled band; gloop: a thick, glossy, rounded bead."
7992
8202
  },
7993
8203
  thickness: { type: "number", minimum: 0, maximum: 1, description: "How far the paint stands up." },
@@ -8003,8 +8213,8 @@ var PARTICLE_BRUSH = {
8003
8213
  type: "object",
8004
8214
  description: "Particle engine settings (procedural brushes). Missing fields keep their current values.",
8005
8215
  properties: {
8006
- kind: { type: "string", enum: [..._chunkNKTNLJUJcjs.PARTICLE_KINDS], description: "string: strands of masses on springs dragged behind the pen (hair, fur, wet string); spring: particles on springs to the pen, overshooting and wobbling; orbit: particles circling the pen (curls); flow: particles thrown off the pen into a swirling flow until they fade." },
8007
- render: { type: "string", enum: [..._chunkNKTNLJUJcjs.PARTICLE_RENDERS], description: "dot: a mark at each step; line: each particle draws a continuous line; sequence: beads spaced along each path." },
8216
+ kind: { type: "string", enum: [..._chunk5BR7LC24cjs.PARTICLE_KINDS], description: "string: strands of masses on springs dragged behind the pen (hair, fur, wet string); spring: particles on springs to the pen, overshooting and wobbling; orbit: particles circling the pen (curls); flow: particles thrown off the pen into a swirling flow until they fade." },
8217
+ render: { type: "string", enum: [..._chunk5BR7LC24cjs.PARTICLE_RENDERS], description: "dot: a mark at each step; line: each particle draws a continuous line; sequence: beads spaced along each path." },
8008
8218
  count: { type: "integer", minimum: 1, maximum: 64, description: "Particles (flow: how many are thrown per tip of travel)." },
8009
8219
  size: { type: "number", minimum: 0, maximum: 1, description: "Mark size as a fraction of the tip size." },
8010
8220
  spread: { type: "number", minimum: 0, maximum: 1, description: "How far apart the particles start, as a fraction of the tip size." },
@@ -8034,7 +8244,7 @@ var STICKER_BRUSH = {
8034
8244
  type: "object",
8035
8245
  description: "Sticker engine settings: stamps sprayed along the stroke as editable stickers. Missing fields keep their current values.",
8036
8246
  properties: {
8037
- stamps: { type: "array", minItems: 1, maxItems: 9, items: { type: "string", enum: [..._chunkNKTNLJUJcjs.STAMP_KINDS], description: "A stamp." }, description: "The stamps to spray (one picked at random per sticker)." },
8247
+ stamps: { type: "array", minItems: 1, maxItems: 9, items: { type: "string", enum: [..._chunk5BR7LC24cjs.STAMP_KINDS], description: "A stamp." }, description: "The stamps to spray (one picked at random per sticker)." },
8038
8248
  density: { type: "number", minimum: 0, maximum: 1, description: "How closely stickers follow each other: about density \xD7 4 stickers per tip diameter of travel (0.25 \u2248 one per diameter, 1 \u2248 four). Default 0.4." },
8039
8249
  sizeJitter: { type: "number", minimum: 0, maximum: 1, description: "Random size change." },
8040
8250
  rotationJitter: { type: "number", minimum: 0, maximum: 1, description: "Random turn as a fraction of \xB1180\xB0." },
@@ -8045,16 +8255,16 @@ var STICKER_BRUSH = {
8045
8255
  };
8046
8256
  var BRUSH_FIELDS = {
8047
8257
  name: { type: "string", minLength: 1, maxLength: 80, description: "Display name." },
8048
- category: { type: "string", enum: [..._chunkNKTNLJUJcjs.PAINT_BRUSH_CATEGORIES], description: "Library category." },
8258
+ category: { type: "string", enum: [..._chunk5BR7LC24cjs.PAINT_BRUSH_CATEGORIES], description: "Library category." },
8049
8259
  engine: {
8050
8260
  type: "string",
8051
- enum: [..._chunkNKTNLJUJcjs.PAINT_BRUSH_ENGINES],
8261
+ enum: [..._chunk5BR7LC24cjs.PAINT_BRUSH_ENGINES],
8052
8262
  description: "dab: paints dabs (with behavior.pickup or gradient paint it paints dab by dab, lifting and mixing paint); eraser: removes paint; mixer: the Mixer Brush (a reservoir plus picked-up paint); blender: mixes the colours under and near the tip; smudge: drags paint along the stroke; wet: watercolour, gouache, oil and the wet tools on a simulated wet layer (see wet); impasto: thick paint with relief (see impasto); particle: procedural particle brushes (see particle); bristle: a tuft of bristles that bend and splay (see bristle); sticker: sprays editable sticker stamps (see sticker)."
8053
8263
  },
8054
8264
  tip: TIP,
8055
8265
  grain: { type: "number", minimum: 0, maximum: 1, description: "Paper grain response: 0 ignores the grain, 1 catches only its peaks at light pressure (pencil, pastel, charcoal). Multiplied by the paper depth." },
8056
8266
  pressureSmoothing: { type: "number", minimum: 0, maximum: 0.95, description: "Pressure smoothing, separate from the tip position smoothing." },
8057
- rotation: { type: "string", enum: [..._chunkNKTNLJUJcjs.BRUSH_ROTATIONS], description: "What turns the tip: fixed (tip.angle), stroke (follows the direction of travel) or barrel (the pen barrel rotation, twist)." },
8267
+ rotation: { type: "string", enum: [..._chunk5BR7LC24cjs.BRUSH_ROTATIONS], description: "What turns the tip: fixed (tip.angle), stroke (follows the direction of travel) or barrel (the pen barrel rotation, twist)." },
8058
8268
  dynamics: DYNAMICS,
8059
8269
  mixer: MIXER,
8060
8270
  loadsColor: { type: "boolean", description: "Mixer engine: load the colour each stroke (false for a mixer that only moves paint)." },
@@ -8068,6 +8278,7 @@ var BRUSH_FIELDS = {
8068
8278
  sticker: STICKER_BRUSH,
8069
8279
  paint: BRUSH_PAINT
8070
8280
  };
8281
+ var TIME = { type: "number", minimum: 0, description: "Draw live effect paint (strokes on stroke layers painted with live effect paint) this many ms into its animation (default: as painted, its own time)." };
8071
8282
  var POINTS = {
8072
8283
  type: "array",
8073
8284
  minItems: 1,
@@ -8104,7 +8315,7 @@ function brushSummary(b) {
8104
8315
  size: b.tip.size,
8105
8316
  grain: b.grain,
8106
8317
  rotation: b.rotation,
8107
- wetCapable: _chunkNKTNLJUJcjs.isWetCapable.call(void 0, b),
8318
+ wetCapable: _chunk5BR7LC24cjs.isWetCapable.call(void 0, b),
8108
8319
  pickup: b.behavior.pickup,
8109
8320
  dirty: b.behavior.dirty,
8110
8321
  multicolor: b.behavior.multicolor.mode,
@@ -8212,8 +8423,8 @@ function createPaintEditorToolProvider(controller, options = {}) {
8212
8423
  inputSchema: EMPTY3,
8213
8424
  annotations: { title: "List papers", ...READ6 },
8214
8425
  handler: () => ({
8215
- papers: _chunkNKTNLJUJcjs.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 })),
8216
- families: [..._chunkNKTNLJUJcjs.PAPER_FAMILIES],
8426
+ papers: _chunk5BR7LC24cjs.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 })),
8427
+ families: [..._chunk5BR7LC24cjs.PAPER_FAMILIES],
8217
8428
  patterns: [..._chunkPQ3H2AANcjs.GRAIN_PATTERNS]
8218
8429
  })
8219
8430
  });
@@ -8433,7 +8644,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
8433
8644
  annotations: { title: "List brushes", ...READ6 },
8434
8645
  handler: () => {
8435
8646
  const s = c.getState();
8436
- return { activeBrushId: s.brush.id, activeEdited: !s.brush.builtin && Boolean(_optionalChain([c, 'access', _392 => _392.getBrush, 'call', _393 => _393(s.brush.id), 'optionalAccess', _394 => _394.builtin])), brushes: s.brushes.map(brushSummary) };
8647
+ return { activeBrushId: s.brush.id, activeEdited: !s.brush.builtin && Boolean(_optionalChain([c, 'access', _403 => _403.getBrush, 'call', _404 => _404(s.brush.id), 'optionalAccess', _405 => _405.builtin])), brushes: s.brushes.map(brushSummary) };
8437
8648
  }
8438
8649
  });
8439
8650
  add({
@@ -8444,10 +8655,10 @@ function createPaintEditorToolProvider(controller, options = {}) {
8444
8655
  annotations: { title: "Get a brush", ...READ6 },
8445
8656
  handler: ({ id }) => {
8446
8657
  const st = c.getState();
8447
- if (id === void 0) return { ..._chunkNKTNLJUJcjs.brushToJSON.call(void 0, st.brush), strokePaint: _nullishCoalesce(st.brush.paint, () => ( st.paint)) };
8658
+ if (id === void 0) return { ..._chunk5BR7LC24cjs.brushToJSON.call(void 0, st.brush), strokePaint: _nullishCoalesce(st.brush.paint, () => ( st.paint)) };
8448
8659
  const b = c.getBrush(id);
8449
8660
  if (!b) throw new Error(`Unknown brush "${id}". Call list_brushes for the ids.`);
8450
- return { ..._chunkNKTNLJUJcjs.brushToJSON.call(void 0, b), builtin: Boolean(b.builtin), strokePaint: _nullishCoalesce(b.paint, () => ( st.paint)) };
8661
+ return { ..._chunk5BR7LC24cjs.brushToJSON.call(void 0, b), builtin: Boolean(b.builtin), strokePaint: _nullishCoalesce(b.paint, () => ( st.paint)) };
8451
8662
  }
8452
8663
  });
8453
8664
  add({
@@ -8456,7 +8667,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
8456
8667
  description: "Chooses the active brush (id) and / or changes its settings; strokes without a brush use it. Editor state, not an undo step. Changes stay on the active brush until save_brush stores them. Returns the active brush.",
8457
8668
  inputSchema: { type: "object", properties: { id: { type: "string", description: "Brush id from list_brushes to start from." }, ...BRUSH_FIELDS }, additionalProperties: false },
8458
8669
  annotations: { title: "Set the brush", ...SET4 },
8459
- handler: (a) => _chunkNKTNLJUJcjs.brushToJSON.call(void 0, c.setBrush(a))
8670
+ handler: (a) => _chunk5BR7LC24cjs.brushToJSON.call(void 0, c.setBrush(a))
8460
8671
  });
8461
8672
  add({
8462
8673
  name: "save_brush",
@@ -8472,7 +8683,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
8472
8683
  additionalProperties: false
8473
8684
  },
8474
8685
  annotations: { title: "Save a brush", ...SET4 },
8475
- handler: ({ id, name }) => _chunkNKTNLJUJcjs.brushToJSON.call(void 0, c.saveBrush({ id, name }))
8686
+ handler: ({ id, name }) => _chunk5BR7LC24cjs.brushToJSON.call(void 0, c.saveBrush({ id, name }))
8476
8687
  });
8477
8688
  add({
8478
8689
  name: "remove_brush",
@@ -8663,7 +8874,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
8663
8874
  if (ids) {
8664
8875
  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.`);
8665
8876
  }
8666
- return { total: all.length, strokes: picked.map((s) => strokeSummary(s, Boolean(ids), live ? true : liveIds.has(s.id) && _optionalChain([c, 'access', _395 => _395.document, 'access', _396 => _396.liveStrokes, 'optionalAccess', _397 => _397[s.layerId], 'optionalAccess', _398 => _398.includes, 'call', _399 => _399(s)]) === true)) };
8877
+ return { total: all.length, strokes: picked.map((s) => strokeSummary(s, Boolean(ids), live ? true : liveIds.has(s.id) && _optionalChain([c, 'access', _406 => _406.document, 'access', _407 => _407.liveStrokes, 'optionalAccess', _408 => _408[s.layerId], 'optionalAccess', _409 => _409.includes, 'call', _410 => _410(s)]) === true)) };
8667
8878
  }
8668
8879
  });
8669
8880
  add({
@@ -8904,20 +9115,22 @@ function createPaintEditorToolProvider(controller, options = {}) {
8904
9115
  add({
8905
9116
  name: "export_image",
8906
9117
  title: "Export the painting",
8907
- description: "Exports the painting as PNG, JPEG or WebP (base64). JPEG always includes the paper; JPEG and WebP need a browser canvas. Changes nothing. Returns the data, its MIME type and size.",
9118
+ description: "Exports the painting as PNG, JPEG or WebP (base64). JPEG always includes the paper; JPEG and WebP need a browser canvas. With time, live effect paint is drawn at that moment (get_effect_playback / set_effect_playback). Changes nothing. Returns the data, its MIME type and size.",
8908
9119
  inputSchema: {
8909
9120
  type: "object",
8910
9121
  properties: {
8911
9122
  format: { type: "string", enum: ["image/png", "image/jpeg", "image/webp"], description: "File type (default image/png)." },
8912
9123
  quality: { type: "number", minimum: 0, maximum: 1, description: "JPEG / WebP quality 0..1 (default 0.92)." },
8913
9124
  scale: { type: "number", exclusiveMinimum: 0, maximum: 1, description: "Shrink by this factor (default 1)." },
8914
- paper: { type: "boolean", description: "Include the paper (default true)." }
9125
+ paper: { type: "boolean", description: "Include the paper (default true)." },
9126
+ time: TIME
8915
9127
  },
8916
9128
  additionalProperties: false
8917
9129
  },
8918
9130
  annotations: { title: "Export the painting", ...READ6 },
8919
- handler: async ({ format, quality, scale, paper }) => {
8920
- const bytes = await c.exportImage({ format, quality, scale, paper });
9131
+ handler: async ({ format, quality, scale, paper, time }) => {
9132
+ const run = () => c.exportImage({ format, quality, scale, paper });
9133
+ const bytes = time === void 0 ? await run() : await c.withEffectTime(time, run);
8921
9134
  return { mimeType: _nullishCoalesce(format, () => ( "image/png")), bytes: bytes.length, data: _chunkOLNIPTB3cjs.bytesToBase64.call(void 0, bytes) };
8922
9135
  }
8923
9136
  });
@@ -8925,10 +9138,10 @@ function createPaintEditorToolProvider(controller, options = {}) {
8925
9138
  name: "export_psd",
8926
9139
  title: "Export as PSD",
8927
9140
  description: 'Writes the painting as an 8-bit RGB PSD (PSB above 30000 px) through the shared PSD writer: every layer and group with its opacity, blend, mask and locks, the paper as a locked "Paper" pixel layer at the bottom, and the composite as the merged image. Changes nothing. Returns the file as base64, its size, whether it is a PSB, and warnings (pigment and painterly blend modes have no PSD equivalent: they are written as the nearest standard mode, see list_blend_modes).',
8928
- inputSchema: EMPTY3,
9141
+ inputSchema: { type: "object", properties: { time: TIME }, additionalProperties: false },
8929
9142
  annotations: { title: "Export as PSD", ...READ6 },
8930
- handler: () => {
8931
- const r = c.exportPsd();
9143
+ handler: async ({ time }) => {
9144
+ const r = time === void 0 ? c.exportPsd() : await c.withEffectTime(time, () => c.exportPsd());
8932
9145
  return { data: _chunkOLNIPTB3cjs.bytesToBase64.call(void 0, r.bytes), bytes: r.bytes.length, psb: r.psb, warnings: r.warnings };
8933
9146
  }
8934
9147
  });
@@ -8951,16 +9164,16 @@ function createPaintEditorToolProvider(controller, options = {}) {
8951
9164
  }
8952
9165
  function hostTool({ coordinates, ...tool }, { origin, onChange }) {
8953
9166
  if (!origin && !onChange) return tool;
8954
- const write = !_optionalChain([tool, 'access', _400 => _400.annotations, 'optionalAccess', _401 => _401.readOnlyHint]);
9167
+ const write = !_optionalChain([tool, 'access', _411 => _411.annotations, 'optionalAccess', _412 => _412.readOnlyHint]);
8955
9168
  const done = (result) => {
8956
- if (write) _optionalChain([onChange, 'optionalCall', _402 => _402({ tool: tool.name })]);
8957
- return origin && _optionalChain([coordinates, 'optionalAccess', _403 => _403.out]) ? fromDocument(result, coordinates.out, origin) : result;
9169
+ if (write) _optionalChain([onChange, 'optionalCall', _413 => _413({ tool: tool.name })]);
9170
+ return origin && _optionalChain([coordinates, 'optionalAccess', _414 => _414.out]) ? fromDocument(result, coordinates.out, origin) : result;
8958
9171
  };
8959
9172
  return {
8960
9173
  ...tool,
8961
9174
  ...origin ? { description: hostedText(_nullishCoalesce(tool.description, () => ( ""))), inputSchema: hostedSchema(tool.inputSchema) } : {},
8962
9175
  handler: (args, context) => {
8963
- const r = tool.handler(origin && _optionalChain([coordinates, 'optionalAccess', _404 => _404.in]) ? toDocument(args, coordinates.in, origin) : args, context);
9176
+ const r = tool.handler(origin && _optionalChain([coordinates, 'optionalAccess', _415 => _415.in]) ? toDocument(args, coordinates.in, origin) : args, context);
8964
9177
  return r instanceof Promise ? r.then(done) : done(r);
8965
9178
  }
8966
9179
  };
@@ -8977,7 +9190,7 @@ function strokeSummary(s, withPoints, live) {
8977
9190
  color: s.color,
8978
9191
  points: withPoints ? s.points : s.points.length,
8979
9192
  seed: s.seed,
8980
- copies: _nullishCoalesce(_optionalChain([s, 'access', _405 => _405.copies, 'optionalAccess', _406 => _406.length]), () => ( 0)),
9193
+ copies: _nullishCoalesce(_optionalChain([s, 'access', _416 => _416.copies, 'optionalAccess', _417 => _417.length]), () => ( 0)),
8981
9194
  live,
8982
9195
  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) }
8983
9196
  };
@@ -8993,20 +9206,20 @@ var PAINT_TOOLS = [
8993
9206
  { id: "rotate", label: "Rotate view", key: "r" }
8994
9207
  ];
8995
9208
  var PaintGesture = (_class11 = class {
8996
- constructor(controller, box) {;_class11.prototype.__init118.call(this);_class11.prototype.__init119.call(this);_class11.prototype.__init120.call(this);_class11.prototype.__init121.call(this);_class11.prototype.__init122.call(this);_class11.prototype.__init123.call(this);
9209
+ constructor(controller, box) {;_class11.prototype.__init125.call(this);_class11.prototype.__init126.call(this);_class11.prototype.__init127.call(this);_class11.prototype.__init128.call(this);_class11.prototype.__init129.call(this);_class11.prototype.__init130.call(this);
8997
9210
  this.controller = controller;
8998
9211
  this.box = box;
8999
9212
  }
9000
9213
 
9001
9214
 
9002
- __init118() {this.tool = "brush"}
9215
+ __init125() {this.tool = "brush"}
9003
9216
  /** The last refusal (a hidden or locked layer), for the editor to show. */
9004
- __init119() {this.error = null}
9217
+ __init126() {this.error = null}
9005
9218
  /** The predicted tail of the current stroke in document pixels (draw it as a thin preview). */
9006
- __init120() {this.predicted = []}
9007
- __init121() {this.mode = null}
9008
- __init122() {this.penAt = null}
9009
- __init123() {this.penDown = false}
9219
+ __init127() {this.predicted = []}
9220
+ __init128() {this.mode = null}
9221
+ __init129() {this.penAt = null}
9222
+ __init130() {this.penDown = false}
9010
9223
  doc(e) {
9011
9224
  const b = this.box();
9012
9225
  const s = this.controller.getState();
@@ -9062,13 +9275,13 @@ var PaintGesture = (_class11 = class {
9062
9275
  const p = this.doc(e);
9063
9276
  const s = this.controller.getState();
9064
9277
  const layerId = s.document.activeLayerId;
9065
- if (!layerId || !_optionalChain([s, 'access', _407 => _407.document, 'access', _408 => _408.liveStrokes, 'optionalAccess', _409 => _409[layerId]])) {
9278
+ if (!layerId || !_optionalChain([s, 'access', _418 => _418.document, 'access', _419 => _419.liveStrokes, 'optionalAccess', _420 => _420[layerId]])) {
9066
9279
  this.error = "Pick a stroke layer in the Layers panel (or add one) to select its strokes.";
9067
9280
  return false;
9068
9281
  }
9069
9282
  try {
9070
9283
  const hit = this.controller.liveStrokeAt(layerId, p.x, p.y);
9071
- this.controller.selectStroke(_nullishCoalesce(_optionalChain([hit, 'optionalAccess', _410 => _410.id]), () => ( null)));
9284
+ this.controller.selectStroke(_nullishCoalesce(_optionalChain([hit, 'optionalAccess', _421 => _421.id]), () => ( null)));
9072
9285
  if (!hit) return false;
9073
9286
  this.mode = { kind: "move-stroke", pointerId: e.pointerId, id: hit.id, from: p, to: p };
9074
9287
  return true;
@@ -9080,7 +9293,7 @@ var PaintGesture = (_class11 = class {
9080
9293
  /** While a stroke is dragged: how far it has moved (document pixels), to draw its outline there. */
9081
9294
  get strokeDrag() {
9082
9295
  const m = this.mode;
9083
- return _optionalChain([m, 'optionalAccess', _411 => _411.kind]) === "move-stroke" ? { id: m.id, dx: m.to.x - m.from.x, dy: m.to.y - m.from.y } : null;
9296
+ return _optionalChain([m, 'optionalAccess', _422 => _422.kind]) === "move-stroke" ? { id: m.id, dx: m.to.x - m.from.x, dy: m.to.y - m.from.y } : null;
9084
9297
  }
9085
9298
  /**
9086
9299
  * The Stickers tool: pressing a sticker picks it and dragging moves it (one undo step at the
@@ -9154,7 +9367,7 @@ var PaintGesture = (_class11 = class {
9154
9367
  if (!m || m.pointerId !== e.pointerId) return;
9155
9368
  this.mode = null;
9156
9369
  this.predicted = [];
9157
- if (m.kind === "stroke") _optionalChain([this, 'access', _412 => _412.controller, 'access', _413 => _413.activeStroke, 'optionalAccess', _414 => _414.end, 'call', _415 => _415()]);
9370
+ if (m.kind === "stroke") _optionalChain([this, 'access', _423 => _423.controller, 'access', _424 => _424.activeStroke, 'optionalAccess', _425 => _425.end, 'call', _426 => _426()]);
9158
9371
  if (m.kind === "move-stroke") {
9159
9372
  const dx = Math.round((this.doc(e).x - m.from.x) * 100) / 100;
9160
9373
  const dy = Math.round((this.doc(e).y - m.from.y) * 100) / 100;
@@ -9178,8 +9391,8 @@ var PaintGesture = (_class11 = class {
9178
9391
  cancel() {
9179
9392
  this.penDown = false;
9180
9393
  this.predicted = [];
9181
- if (_optionalChain([this, 'access', _416 => _416.mode, 'optionalAccess', _417 => _417.kind]) === "stroke") _optionalChain([this, 'access', _418 => _418.controller, 'access', _419 => _419.activeStroke, 'optionalAccess', _420 => _420.cancel, 'call', _421 => _421()]);
9182
- if (_optionalChain([this, 'access', _422 => _422.mode, 'optionalAccess', _423 => _423.kind]) === "sticker") this.controller.cancelStickerPreview();
9394
+ if (_optionalChain([this, 'access', _427 => _427.mode, 'optionalAccess', _428 => _428.kind]) === "stroke") _optionalChain([this, 'access', _429 => _429.controller, 'access', _430 => _430.activeStroke, 'optionalAccess', _431 => _431.cancel, 'call', _432 => _432()]);
9395
+ if (_optionalChain([this, 'access', _433 => _433.mode, 'optionalAccess', _434 => _434.kind]) === "sticker") this.controller.cancelStickerPreview();
9183
9396
  this.mode = null;
9184
9397
  }
9185
9398
  get active() {
@@ -9241,13 +9454,13 @@ function handlePaintShortcut(controller, gesture, e) {
9241
9454
  return false;
9242
9455
  }
9243
9456
  var PaintCanvasPresenter = (_class12 = class {
9244
- constructor(controller) {;_class12.prototype.__init124.call(this);_class12.prototype.__init125.call(this);_class12.prototype.__init126.call(this);
9457
+ constructor(controller) {;_class12.prototype.__init131.call(this);_class12.prototype.__init132.call(this);_class12.prototype.__init133.call(this);
9245
9458
  this.controller = controller;
9246
9459
  }
9247
9460
 
9248
- __init124() {this.uploaded = /* @__PURE__ */ new Map()}
9249
- __init125() {this.scratch = null}
9250
- __init126() {this.size = ""}
9461
+ __init131() {this.uploaded = /* @__PURE__ */ new Map()}
9462
+ __init132() {this.scratch = null}
9463
+ __init133() {this.size = ""}
9251
9464
  /** Draws what changed into `ctx` (a canvas the size of the document); returns the tiles drawn. */
9252
9465
  render(ctx) {
9253
9466
  const { width, height } = this.controller.document.canvas;
@@ -9279,7 +9492,7 @@ function guideOverlay(controller, drag) {
9279
9492
  const size = s.document.canvas;
9280
9493
  const out = [];
9281
9494
  const layerId = s.document.activeLayerId;
9282
- const strokePicked = layerId && s.selectedStroke ? _optionalChain([s, 'access', _424 => _424.document, 'access', _425 => _425.liveStrokes, 'optionalAccess', _426 => _426[layerId], 'optionalAccess', _427 => _427.some, 'call', _428 => _428((x) => x.id === s.selectedStroke)]) : false;
9495
+ const strokePicked = layerId && s.selectedStroke ? _optionalChain([s, 'access', _435 => _435.document, 'access', _436 => _436.liveStrokes, 'optionalAccess', _437 => _437[layerId], 'optionalAccess', _438 => _438.some, 'call', _439 => _439((x) => x.id === s.selectedStroke)]) : false;
9283
9496
  const area = strokePicked ? controller.liveStrokeArea(s.selectedStroke) : null;
9284
9497
  if (area) {
9285
9498
  const dx = drag && drag.id === s.selectedStroke ? drag.dx : 0;
@@ -9292,7 +9505,7 @@ function guideOverlay(controller, drag) {
9292
9505
  ];
9293
9506
  for (let i = 0; i < 4; i++) out.push({ from: box[i], to: box[(i + 1) % 4], kind: "stroke" });
9294
9507
  }
9295
- const picked = layerId && s.selectedSticker ? _optionalChain([s, 'access', _429 => _429.document, 'access', _430 => _430.stickers, 'optionalAccess', _431 => _431[layerId], 'optionalAccess', _432 => _432.find, 'call', _433 => _433((x) => x.id === s.selectedSticker)]) : void 0;
9508
+ const picked = layerId && s.selectedSticker ? _optionalChain([s, 'access', _440 => _440.document, 'access', _441 => _441.stickers, 'optionalAccess', _442 => _442[layerId], 'optionalAccess', _443 => _443.find, 'call', _444 => _444((x) => x.id === s.selectedSticker)]) : void 0;
9296
9509
  if (picked) {
9297
9510
  const r = picked.size / 2 + 2;
9298
9511
  const a = picked.rotation * Math.PI / 180;
@@ -9336,7 +9549,7 @@ var PAPER_SLIDERS = [
9336
9549
  ];
9337
9550
  function readPath(obj, path) {
9338
9551
  let v = obj;
9339
- for (const k of path.split(".")) v = _optionalChain([v, 'optionalAccess', _434 => _434[k]]);
9552
+ for (const k of path.split(".")) v = _optionalChain([v, 'optionalAccess', _445 => _445[k]]);
9340
9553
  return typeof v === "number" ? v : 0;
9341
9554
  }
9342
9555
  function patchPath(obj, path, value) {
@@ -9458,7 +9671,7 @@ function brushEngineControls(brush) {
9458
9671
  impastoTool: true
9459
9672
  };
9460
9673
  case "wet": {
9461
- const tool = _nullishCoalesce(_optionalChain([brush, 'access', _435 => _435.wet, 'optionalAccess', _436 => _436.tool]), () => ( "paint"));
9674
+ const tool = _nullishCoalesce(_optionalChain([brush, 'access', _446 => _446.wet, 'optionalAccess', _447 => _447.tool]), () => ( "paint"));
9462
9675
  const sliders = tool === "paint" ? [
9463
9676
  { path: "wet.water", label: "Water", min: 0, max: 1, step: 0.01 },
9464
9677
  { path: "wet.pigment", label: "Pigment", min: 0, max: 1, step: 0.01 },
@@ -9591,7 +9804,7 @@ function startWetClock(controller, frame, cancel) {
9591
9804
  id = raf(loop);
9592
9805
  return () => {
9593
9806
  stopped = true;
9594
- _optionalChain([caf, 'optionalCall', _437 => _437(id)]);
9807
+ _optionalChain([caf, 'optionalCall', _448 => _448(id)]);
9595
9808
  };
9596
9809
  }
9597
9810
  function drawWaterOverlay(controller, ctx) {
@@ -9660,7 +9873,7 @@ function createPaintEffectsToolProvider(controller, options = {}) {
9660
9873
  };
9661
9874
  const paintInfo = () => {
9662
9875
  const p = controller.getEffectPaint();
9663
- return p ? [{ id: PAINT_TARGET, effect: p.effect, provider: p.provider, role: controller.getState().effectPaintRendering ? "effect paint (rendering)" : "effect paint", enabled: true, values: p.values, ...p.time ? { time: p.time } : {} }] : [];
9876
+ return p ? [{ id: PAINT_TARGET, effect: p.effect, provider: p.provider, role: controller.getState().effectPaintRendering ? "effect paint (rendering)" : "effect paint", enabled: true, values: p.values, ...p.time ? { time: p.time } : {}, ...p.map ? { map: p.map } : {}, ...p.live ? { live: true } : {} }] : [];
9664
9877
  };
9665
9878
  const layerInfo = (layerId) => {
9666
9879
  const s = controller.getEffectLayer(layerId);
@@ -9690,7 +9903,7 @@ function createPaintEffectsToolProvider(controller, options = {}) {
9690
9903
  if (changes.enabled !== void 0) throw new Error("enabled does not apply here: hide an effect layer with update_layer visible false, or remove the effect paper.");
9691
9904
  };
9692
9905
  const values = (v) => v;
9693
- return withPaintPlayback(_chunkJAOSL334cjs.createEffectToolProvider.call(void 0, {
9906
+ return withPaintPlayback(_chunkGHCSC2WPcjs.createEffectToolProvider.call(void 0, {
9694
9907
  id: _nullishCoalesce(options.id, () => ( "paint-effects")),
9695
9908
  namespace: options.namespace,
9696
9909
  title: "Paint effects",
@@ -9729,7 +9942,7 @@ function createPaintEffectsToolProvider(controller, options = {}) {
9729
9942
  if (target === PAINT_TARGET) {
9730
9943
  if (changes.opacity !== void 0) throw new Error("opacity does not apply to the effect paint: change the brush opacity (set_brush tip.opacity).");
9731
9944
  const p = controller.getEffectPaint();
9732
- await controller.setEffectPaint({ effect: p.effect, values: { ...p.values, ..._nullishCoalesce(changes.values, () => ( {})) }, time: p.time });
9945
+ await controller.setEffectPaint({ effect: p.effect, values: { ...p.values, ..._nullishCoalesce(changes.values, () => ( {})) }, time: p.time, map: p.map, live: p.live });
9733
9946
  const effects2 = paintInfo();
9734
9947
  return { target, effect: effects2[0], effects: effects2 };
9735
9948
  }
@@ -9788,13 +10001,25 @@ function createPaintEffectsToolProvider(controller, options = {}) {
9788
10001
  {
9789
10002
  name: "set_effect_paint",
9790
10003
  title: "Paint with an effect",
9791
- description: `Makes brushes paint with a provider generator, overlay or title effect (search_effects with use generator, overlay or title): it is rendered once at the canvas size, and each stroke then takes every pixel's colour from it, fixed to the canvas, as if painting a hidden picture into view (the effect's transparency paints nothing). Dab, particle and bristle brushes take the colour per pixel; mixer brushes and dab brushes that pick up paint take it per dab, at its centre. Wet, impasto and sticker brushes refuse it (paint the shape and use fill_layer_with_effect with lockTransparency instead); erasers, blenders and smudges ignore it. It replaces the paint colour or gradient until set_color or set_paint; a brush with its own gradient paints that instead. Strokes record it and replay exactly. Editor state, not an undo step. Returns the effect paint: { effect, provider, values (every control), time } (list_applied_effects target "paint" shows it; update_effect / remove_effect with target and effect "paint" change or clear it).`,
10004
+ description: `Makes brushes paint with a provider generator, overlay or title effect (search_effects with use generator, overlay or title): it is rendered once at the canvas size, and each stroke then takes every pixel's colour from it, fixed to the canvas, as if painting a hidden picture into view (the effect's transparency paints nothing). Dab, particle and bristle brushes take the colour per pixel; mixer brushes and dab brushes that pick up paint take it per dab, at its centre. Watercolour, gouache, oil and impasto brushes take it per pixel too, shifted by paint they pick up (in wet paint the pattern then flows with the water; impasto keeps its relief), and sprayed stickers take the colour at their centre. Erasers, blenders and smudges ignore it. It replaces the paint colour or gradient until set_color or set_paint; a brush with its own gradient paints that instead. Strokes record it and replay exactly. Editor state, not an undo step. Returns the effect paint: { effect, provider, values (every control), time } (list_applied_effects target "paint" shows it; update_effect / remove_effect with target and effect "paint" change or clear it).`,
9792
10005
  inputSchema: {
9793
10006
  type: "object",
9794
10007
  properties: {
9795
10008
  effect: ctx.effectIdSchema(["generator", "overlay", "title"]),
9796
10009
  values: ctx.valuesSchema("Control values over the effect's defaults"),
9797
- time: { type: "number", minimum: 0, description: "Which moment of an animated effect to paint with, in ms (default 0)." }
10010
+ time: { type: "number", minimum: 0, description: "Which moment of an animated effect to paint with, in ms (default 0)." },
10011
+ map: {
10012
+ type: "object",
10013
+ 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).",
10014
+ properties: {
10015
+ by: { type: "string", enum: ["canvas", "stroke"], description: "canvas (default) or stroke." },
10016
+ length: { type: "number", minimum: 16, maximum: 4096, description: "by stroke: px of stroke per repeat of the effect (default 300)." },
10017
+ repeat: { type: "string", enum: ["repeat", "mirror", "clamp"], description: "by stroke: past the strip end start again (default), run back, or hold the last colour." }
10018
+ },
10019
+ required: ["by"],
10020
+ additionalProperties: false
10021
+ },
10022
+ live: { type: "boolean", description: "Live effect paint (default false): strokes on a stroke layer (add_layer type strokes) keep playing the effect, so the paint moves (set_effect_playback); elsewhere strokes bake the frame at time." }
9798
10023
  },
9799
10024
  required: ["effect"],
9800
10025
  additionalProperties: false
@@ -9802,9 +10027,24 @@ function createPaintEffectsToolProvider(controller, options = {}) {
9802
10027
  annotations: { title: "Paint with an effect", ...ctx.annotations.writeIdempotent },
9803
10028
  handler: async (args) => {
9804
10029
  ctx.requireProvider();
9805
- return { effectPaint: await controller.setEffectPaint({ effect: args.effect, values: values(args.values), time: args.time }) };
10030
+ return { effectPaint: await controller.setEffectPaint({ effect: args.effect, values: values(args.values), time: args.time, map: args.map, live: args.live }) };
9806
10031
  }
9807
10032
  },
10033
+ {
10034
+ name: "set_effect_playback",
10035
+ title: "Play or pause live effect paint",
10036
+ description: "Plays or pauses live effect paint (strokes painted on stroke layers with set_effect_paint live true) in the editor view, and caps its frame rate. Exports draw it at a chosen time with export_image / export_psd time. Editor state, not an undo step. Returns playing, fps, the time the view shows (ms) and what plays (animation: layer ids, live strokes, sources; null when nothing does).",
10037
+ inputSchema: {
10038
+ type: "object",
10039
+ properties: {
10040
+ playing: { type: "boolean", description: "Play (true, the default state) or pause at the current frame." },
10041
+ fps: { type: "integer", minimum: 1, maximum: 60, description: "Frame rate cap, frames a second (default 30); lower it on large canvases." }
10042
+ },
10043
+ additionalProperties: false
10044
+ },
10045
+ annotations: { title: "Play or pause live effect paint", ...ctx.annotations.writeIdempotent },
10046
+ handler: async (args) => ({ ...controller.setEffectPlayback({ playing: args.playing, fps: args.fps }), animation: controller.getAnimation() })
10047
+ },
9808
10048
  {
9809
10049
  name: "add_effect_layer",
9810
10050
  title: "Add an effect layer",
@@ -10204,4 +10444,10 @@ function createPaintEditorDocument(controller, options = {}) {
10204
10444
 
10205
10445
 
10206
10446
 
10207
- exports.BLEND_MENU_GROUPS = BLEND_MENU_GROUPS; exports.BLEND_MODES = _chunkOLNIPTB3cjs.BLEND_MODES; exports.BRUSH_ID = _chunkNKTNLJUJcjs.BRUSH_ID; exports.BRUSH_ROTATIONS = _chunkNKTNLJUJcjs.BRUSH_ROTATIONS; exports.BRUSH_SLIDERS = BRUSH_SLIDERS; exports.BUILTIN_BRUSHES = _chunkNKTNLJUJcjs.BUILTIN_BRUSHES; exports.BristleStroke = _chunkNKTNLJUJcjs.BristleStroke; exports.DEFAULT_BEHAVIOR = _chunkNKTNLJUJcjs.DEFAULT_BEHAVIOR; exports.DEFAULT_BRISTLE = _chunkNKTNLJUJcjs.DEFAULT_BRISTLE; exports.DEFAULT_BRUSH_ID = _chunkNKTNLJUJcjs.DEFAULT_BRUSH_ID; exports.DEFAULT_DPI = DEFAULT_DPI; exports.DEFAULT_DYNAMICS = _chunkNKTNLJUJcjs.DEFAULT_DYNAMICS; exports.DEFAULT_FLOW = _chunkXFYLA3ZOcjs.DEFAULT_FLOW; exports.DEFAULT_IMPASTO = _chunkNKTNLJUJcjs.DEFAULT_IMPASTO; exports.DEFAULT_LIGHTING = DEFAULT_LIGHTING; exports.DEFAULT_MULTI_COLOR = _chunkNKTNLJUJcjs.DEFAULT_MULTI_COLOR; exports.DEFAULT_PAINT_GRADIENT = _chunkPQ3H2AANcjs.DEFAULT_PAINT_GRADIENT; exports.DEFAULT_PAINT_GRADIENT_MAPPING = _chunkPQ3H2AANcjs.DEFAULT_PAINT_GRADIENT_MAPPING; exports.DEFAULT_PAPER = _chunkNKTNLJUJcjs.DEFAULT_PAPER; exports.DEFAULT_PARTICLE = _chunkNKTNLJUJcjs.DEFAULT_PARTICLE; exports.DEFAULT_STICKER = _chunkNKTNLJUJcjs.DEFAULT_STICKER; exports.DEFAULT_SWATCHES = DEFAULT_SWATCHES; exports.DEFAULT_VIEW = DEFAULT_VIEW; exports.DEFAULT_WET_BRUSH = _chunkNKTNLJUJcjs.DEFAULT_WET_BRUSH; exports.DEFAULT_WET_PARAMS = _chunkXFYLA3ZOcjs.DEFAULT_WET_PARAMS; exports.DryStroke = _chunkNKTNLJUJcjs.DryStroke; exports.GPU_LEAD = GPU_LEAD; exports.GRAIN_PATTERNS = _chunkPQ3H2AANcjs.GRAIN_PATTERNS; exports.GRAIN_TILE = _chunkPQ3H2AANcjs.GRAIN_TILE; exports.HARMONY_KINDS = _chunk7PT4RJL5cjs.HARMONY_KINDS; exports.IDENTITY_AFFINE = IDENTITY_AFFINE; exports.IDENTITY_COPY = _chunkNKTNLJUJcjs.IDENTITY_COPY; exports.IMPASTO_TOOLS = _chunkNKTNLJUJcjs.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 = _chunkPQ3H2AANcjs.MAX_BRUSH_SIZE; exports.MAX_CANVAS_SIDE = MAX_CANVAS_SIDE; exports.MAX_COORDINATE = MAX_COORDINATE; exports.MAX_IMAGE_SIDE = MAX_IMAGE_SIDE; 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 = _chunkNKTNLJUJcjs.MULTI_COLOR_MODES; exports.MixingPad = MixingPad; exports.PAD_SAMPLE_SIZES = PAD_SAMPLE_SIZES; exports.PAINTERLY_BLEND_MODES = _chunkOLNIPTB3cjs.PAINTERLY_BLEND_MODES; exports.PAINT_BRUSH_CATEGORIES = _chunkNKTNLJUJcjs.PAINT_BRUSH_CATEGORIES; exports.PAINT_BRUSH_ENGINES = _chunkNKTNLJUJcjs.PAINT_BRUSH_ENGINES; exports.PAINT_COLOR_JSON_SCHEMA = _chunkPQ3H2AANcjs.PAINT_COLOR_JSON_SCHEMA; exports.PAINT_EFFECT_PLACES = PAINT_EFFECT_PLACES; exports.PAINT_FORMAT = PAINT_FORMAT; exports.PAINT_GRADIENT_FULL_SPEED = _chunkPQ3H2AANcjs.PAINT_GRADIENT_FULL_SPEED; exports.PAINT_GRADIENT_JSON_SCHEMA = _chunkPQ3H2AANcjs.PAINT_GRADIENT_JSON_SCHEMA; exports.PAINT_GRADIENT_KIT = _chunkPQ3H2AANcjs.PAINT_GRADIENT_KIT; exports.PAINT_GRADIENT_MAPPINGS = _chunkPQ3H2AANcjs.PAINT_GRADIENT_MAPPINGS; exports.PAINT_GRADIENT_MAPPING_LABELS = _chunkPQ3H2AANcjs.PAINT_GRADIENT_MAPPING_LABELS; exports.PAINT_GRADIENT_PRESETS = _chunkPQ3H2AANcjs.PAINT_GRADIENT_PRESETS; exports.PAINT_GRADIENT_REPEATS = _chunkPQ3H2AANcjs.PAINT_GRADIENT_REPEATS; exports.PAINT_GRADIENT_REPEAT_LABELS = _chunkPQ3H2AANcjs.PAINT_GRADIENT_REPEAT_LABELS; exports.PAINT_GRADIENT_SPACES = _chunkPQ3H2AANcjs.PAINT_GRADIENT_SPACES; exports.PAINT_GRADIENT_SPACE_LABELS = _chunkPQ3H2AANcjs.PAINT_GRADIENT_SPACE_LABELS; exports.PAINT_SCHEMA_VERSION = PAINT_SCHEMA_VERSION; exports.PAINT_SOURCE_JSON_SCHEMA = _chunkPQ3H2AANcjs.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 = _chunkNKTNLJUJcjs.PAPER_FAMILIES; exports.PAPER_LIBRARY = _chunkNKTNLJUJcjs.PAPER_LIBRARY; exports.PAPER_NODE_ID = PAPER_NODE_ID; exports.PAPER_SLIDERS = PAPER_SLIDERS; exports.PAPER_TARGET = PAPER_TARGET; exports.PARTICLE_KINDS = _chunkNKTNLJUJcjs.PARTICLE_KINDS; exports.PARTICLE_KIND_LABELS = PARTICLE_KIND_LABELS; exports.PARTICLE_RENDERS = _chunkNKTNLJUJcjs.PARTICLE_RENDERS; exports.PARTICLE_RENDER_LABELS = PARTICLE_RENDER_LABELS; exports.PaintCanvasPresenter = PaintCanvasPresenter; exports.PaintDabStroke = PaintDabStroke; exports.PaintDirector = PaintDirector; exports.PaintDocumentError = PaintDocumentError; exports.PaintEditorController = PaintEditorController; exports.PaintEditorError = PaintEditorError; exports.PaintEffectsRenderer = PaintEffectsRenderer; exports.PaintGesture = PaintGesture; exports.PaintGradientSampler = _chunkPQ3H2AANcjs.PaintGradientSampler; exports.PaintPresence = PaintPresence; exports.PaintSourceError = _chunkPQ3H2AANcjs.PaintSourceError; exports.PaintStrokeSession = PaintStrokeSession; exports.PaintWetLayers = PaintWetLayers; exports.PaperGrain = _chunkPQ3H2AANcjs.PaperGrain; exports.ParticleStroke = _chunkNKTNLJUJcjs.ParticleStroke; exports.PenDabWalker = _chunkNKTNLJUJcjs.PenDabWalker; exports.PenSmoother = _chunkNKTNLJUJcjs.PenSmoother; exports.PerspectiveSnapper = PerspectiveSnapper; exports.SNAP_DECIDE_DISTANCE = SNAP_DECIDE_DISTANCE; exports.STAMP_KINDS = _chunkNKTNLJUJcjs.STAMP_KINDS; exports.STAMP_LABELS = STAMP_LABELS; exports.STENCIL_KINDS = STENCIL_KINDS; exports.STENCIL_SHAPES = STENCIL_SHAPES; exports.STICKER_SLIDERS = STICKER_SLIDERS; exports.STROKE_SLIDERS = STROKE_SLIDERS; exports.SYMMETRY_MODES = SYMMETRY_MODES; exports.StencilSnapper = StencilSnapper; exports.StickerSpray = _chunkNKTNLJUJcjs.StickerSpray; exports.TRACING_NODE_ID = TRACING_NODE_ID; exports.ThickStrokeDriver = ThickStrokeDriver; exports.TileableNoise = _chunkPQ3H2AANcjs.TileableNoise; exports.WET_FLOW_KINDS = _chunkXFYLA3ZOcjs.WET_FLOW_KINDS; exports.WET_GPU_MODES = WET_GPU_MODES; exports.WET_GPU_OPTIONS = WET_GPU_OPTIONS; exports.WET_MEDIA = _chunkNKTNLJUJcjs.WET_MEDIA; exports.WET_MEDIUM_LABELS = WET_MEDIUM_LABELS; exports.WET_MEDIUM_PARAMS = WET_MEDIUM_PARAMS; exports.WET_PARAM_KEYS = _chunkXFYLA3ZOcjs.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 = _chunkNKTNLJUJcjs.WET_TOOLS; exports.WET_TOOL_LABELS = WET_TOOL_LABELS; exports.WetStrokeDriver = WetStrokeDriver; exports.addPaintGradientStop = _chunkPQ3H2AANcjs.addPaintGradientStop; exports.affineCopy = affineCopy; exports.applyAffine = applyAffine; exports.brushEngineControls = brushEngineControls; exports.brushLoadColor = brushLoadColor; exports.brushLoadForStroke = brushLoadForStroke; exports.brushTakesPaint = _chunkNKTNLJUJcjs.brushTakesPaint; exports.brushToJSON = _chunkNKTNLJUJcjs.brushToJSON; exports.buildTimeLapse = buildTimeLapse; exports.checkPaintEffectPlace = checkPaintEffectPlace; exports.clonePaper = _chunkNKTNLJUJcjs.clonePaper; exports.colorHarmony = colorHarmony2; exports.composeAffine = composeAffine; exports.contactSheet = contactSheet; exports.createPaintCompositor = createPaintCompositor; exports.createPaintDocument = createPaintDocument; exports.createPaintEditorDocument = createPaintEditorDocument; exports.createPaintEditorToolProvider = createPaintEditorToolProvider; exports.createPaintEffectsToolProvider = createPaintEffectsToolProvider; exports.createPaintLayer = createPaintLayer; exports.createPaintReplayTools = createPaintReplayTools; exports.createPaintStickerTools = createPaintStickerTools; exports.createPaintThickTools = createPaintThickTools; exports.createPaintWetTools = createPaintWetTools; exports.decodeImageBlob = decodeImageBlob; exports.defaultGuides = defaultGuides; exports.defaultImageEncoder = defaultImageEncoder; exports.deserializePaintDocument = deserializePaintDocument; exports.deserializePaintDocumentAsync = deserializePaintDocumentAsync; exports.documentExtensions = documentExtensions; exports.documentToScreen = documentToScreen; exports.downloadBytes = downloadBytes; exports.downsampleRgba = downsampleRgba; exports.drawSticker = _chunkNKTNLJUJcjs.drawSticker; exports.drawWaterOverlay = drawWaterOverlay; exports.effectLayersToJSON = effectLayersToJSON; exports.effectPaintKey = _chunkNKTNLJUJcjs.effectPaintKey; exports.emptiedLayers = emptiedLayers; exports.emptyThickChannels = emptyThickChannels; exports.fitZoom = fitZoom; exports.grainCatch = _chunkPQ3H2AANcjs.grainCatch; exports.grainHeights = _chunkPQ3H2AANcjs.grainHeights; exports.guideOverlay = guideOverlay; exports.handlePaintShortcut = handlePaintShortcut; exports.hash2 = _chunkPQ3H2AANcjs.hash2; exports.hexToPaintRgb = _chunkPQ3H2AANcjs.hexToPaintRgb; exports.hexToRgb8 = _chunkNKTNLJUJcjs.hexToRgb8; exports.hslToRgb = hslToRgb; exports.hsvToRgb = hsvToRgb; exports.hueToWheel = _chunk7PT4RJL5cjs.hueToWheel; exports.invertAffine = invertAffine; exports.isBlendMode = _chunkOLNIPTB3cjs.isBlendMode; exports.isGradientPaint = _chunkPQ3H2AANcjs.isGradientPaint; exports.isPaintEffectPaint = _chunkNKTNLJUJcjs.isPaintEffectPaint; exports.isPainterlyBlendMode = _chunkOLNIPTB3cjs.isPainterlyBlendMode; exports.isPalmTouch = isPalmTouch; exports.isWetBrush = _chunkNKTNLJUJcjs.isWetBrush; exports.isWetCapable = _chunkNKTNLJUJcjs.isWetCapable; exports.lightTile = lightTile; exports.lightingKey = lightingKey; exports.liveStrokeBounds = liveStrokeBounds; exports.liveStrokeRefusal = liveStrokeRefusal; exports.mapPenPoint = mapPenPoint; exports.mix32 = _chunkPQ3H2AANcjs.mix32; exports.mixPixels = mixPixels; exports.mixerLoadForStroke = mixerLoadForStroke; exports.mixerTip = _chunkNKTNLJUJcjs.mixerTip; exports.multiColorForDab = multiColorForDab; exports.multiColorGradient = multiColorGradient; exports.multiColorPalette = multiColorPalette; exports.multiColorSliders = multiColorSliders; exports.multiColorToPaint = _chunkNKTNLJUJcjs.multiColorToPaint; exports.newPaintLayerId = newPaintLayerId; exports.nextPaperEffectVersion = nextPaperEffectVersion; exports.normalizeBehavior = _chunkNKTNLJUJcjs.normalizeBehavior; exports.normalizeBristle = _chunkNKTNLJUJcjs.normalizeBristle; exports.normalizeBrushStroke = normalizeBrushStroke; exports.normalizeCanvas = normalizeCanvas; exports.normalizeDynamics = _chunkNKTNLJUJcjs.normalizeDynamics; exports.normalizeFlow = _chunkXFYLA3ZOcjs.normalizeFlow; exports.normalizeHexColor = _chunkPQ3H2AANcjs.normalizeHexColor; exports.normalizeImpasto = _chunkNKTNLJUJcjs.normalizeImpasto; exports.normalizeLighting = normalizeLighting; exports.normalizeMultiColor = _chunkNKTNLJUJcjs.normalizeMultiColor; exports.normalizePaintBrush = _chunkNKTNLJUJcjs.normalizePaintBrush; exports.normalizePaper = _chunkNKTNLJUJcjs.normalizePaper; exports.normalizeParticle = _chunkNKTNLJUJcjs.normalizeParticle; exports.normalizePerspective = normalizePerspective; exports.normalizeRotation = normalizeRotation; exports.normalizeStencil = normalizeStencil; exports.normalizeStickerSettings = _chunkNKTNLJUJcjs.normalizeStickerSettings; exports.normalizeStickerUpdate = _chunkNKTNLJUJcjs.normalizeStickerUpdate; exports.normalizeSymmetry = normalizeSymmetry; exports.normalizeView = normalizeView; exports.normalizeWetBrush = _chunkNKTNLJUJcjs.normalizeWetBrush; exports.normalizeWetParams = _chunkXFYLA3ZOcjs.normalizeWetParams; exports.overPixels = overPixels; exports.padSampleRadius = padSampleRadius; exports.paintGradientMappingFor = _chunkPQ3H2AANcjs.paintGradientMappingFor; exports.paintPlaybackPanel = paintPlaybackPanel; exports.paintSourceColor = _chunkPQ3H2AANcjs.paintSourceColor; exports.paintSourceCss = _chunkPQ3H2AANcjs.paintSourceCss; exports.paintToMultiColor = _chunkNKTNLJUJcjs.paintToMultiColor; exports.paperEffectFromJSON = paperEffectFromJSON; exports.paperEffectToJSON = paperEffectToJSON; exports.paperGrain = paperGrain; exports.paperKey = paperKey; exports.paperNode = paperNode; exports.paperPreset = _chunkNKTNLJUJcjs.paperPreset; exports.parseBrushLibrary = _chunkNKTNLJUJcjs.parseBrushLibrary; exports.parseHexColor = parseHexColor; exports.parsePaintSource = _chunkPQ3H2AANcjs.parsePaintSource; exports.patchBrushValue = patchBrushValue; exports.patchPath = patchPath; exports.penOrientation = _chunkNKTNLJUJcjs.penOrientation; exports.perspectiveDirections = perspectiveDirections; exports.perspectiveGuideLines = perspectiveGuideLines; exports.planPaintToolPlayback = planPaintToolPlayback; exports.pointerToPenPoint = pointerToPenPoint; exports.quickStencil = quickStencil; exports.rand01 = _chunkPQ3H2AANcjs.rand01; exports.randSigned = _chunkPQ3H2AANcjs.randSigned; exports.readPaintEffectPaint = _chunkNKTNLJUJcjs.readPaintEffectPaint; exports.readPaintEffectSource = readPaintEffectSource; exports.readPaintSource = _chunkPQ3H2AANcjs.readPaintSource; exports.readPath = readPath; exports.readSwatch = readSwatch; exports.reliefInfo = reliefInfo; exports.removePaintGradientStop = _chunkPQ3H2AANcjs.removePaintGradientStop; exports.renderBrushThumbnail = renderBrushThumbnail; exports.renderColorWheel = renderColorWheel; exports.renderPaper = _chunkNKTNLJUJcjs.renderPaper; exports.renderStickers = _chunkNKTNLJUJcjs.renderStickers; exports.replayFrame = replayFrame; exports.replayItems = replayItems; exports.replayPainting = replayPainting; exports.resolvePaintGradient = _chunkPQ3H2AANcjs.resolvePaintGradient; exports.reversePaintGradient = _chunkPQ3H2AANcjs.reversePaintGradient; exports.rgbToHexColor = rgbToHexColor; exports.rgbToHsl = rgbToHsl; exports.rgbToHsv = rgbToHsv; exports.sampleEffectAt = _chunkNKTNLJUJcjs.sampleEffectAt; exports.sampleEffectField = _chunkNKTNLJUJcjs.sampleEffectField; exports.samplePressure = samplePressure; exports.scalePaintGradient = _chunkPQ3H2AANcjs.scalePaintGradient; exports.scaleStencil = scaleStencil; exports.screenToDocument = screenToDocument; exports.seedFromString = _chunkPQ3H2AANcjs.seedFromString; exports.serializePaintDocument = serializePaintDocument; exports.serializePaintDocumentExternal = serializePaintDocumentExternal; exports.solidPaint = _chunkPQ3H2AANcjs.solidPaint; exports.stampCoverage = _chunkNKTNLJUJcjs.stampCoverage; exports.standardBlendMode = _chunkOLNIPTB3cjs.standardBlendMode; exports.startWetClock = startWetClock; exports.stencilMask = stencilMask; exports.stencilOutline = stencilOutline; exports.stickerAt = _chunkNKTNLJUJcjs.stickerAt; exports.stickerRect = _chunkNKTNLJUJcjs.stickerRect; exports.stickerSurface = _chunkNKTNLJUJcjs.stickerSurface; exports.strokeBounds = strokeBounds; exports.strokeDuration = strokeDuration; exports.strokeSchedule = strokeSchedule; exports.sweepPath = sweepPath; exports.symmetryAxisAngles = symmetryAxisAngles; exports.symmetryAxisSegments = symmetryAxisSegments; exports.symmetryCopies = symmetryCopies; exports.thickFromJSON = thickFromJSON; exports.thickToJSON = thickToJSON; exports.thumbnailStroke = thumbnailStroke; exports.tiltToOrientation = _chunkNKTNLJUJcjs.tiltToOrientation; exports.timeLapseVideo = timeLapseVideo; exports.timeLapseZip = timeLapseZip; exports.toStrokePoint = _chunkNKTNLJUJcjs.toStrokePoint; exports.toggleStamp = toggleStamp; exports.translateStencil = translateStencil; exports.updatePaintGradientStop = _chunkPQ3H2AANcjs.updatePaintGradientStop; exports.usesPaintExchange = _chunkNKTNLJUJcjs.usesPaintExchange; exports.variationAffine = variationAffine; exports.varyStroke = varyStroke; exports.viewCssTransform = viewCssTransform; exports.viewMatrix = viewMatrix; exports.viewPenToDocument = viewPenToDocument; exports.wetEngineSummary = wetEngineSummary; exports.wetPaperInput = wetPaperInput; exports.wetPigmentOf = wetPigmentOf; exports.wetSupport = _chunkXFYLA3ZOcjs.wetSupport; exports.wheelAngle = wheelAngle; exports.wheelPick = wheelPick; exports.wheelPoint = wheelPoint; exports.wheelToHue = _chunk7PT4RJL5cjs.wheelToHue; exports.withPaintPlayback = withPaintPlayback;
10447
+
10448
+
10449
+
10450
+
10451
+
10452
+
10453
+ exports.BLEND_MENU_GROUPS = BLEND_MENU_GROUPS; exports.BLEND_MODES = _chunkOLNIPTB3cjs.BLEND_MODES; exports.BRUSH_ID = _chunk5BR7LC24cjs.BRUSH_ID; exports.BRUSH_ROTATIONS = _chunk5BR7LC24cjs.BRUSH_ROTATIONS; exports.BRUSH_SLIDERS = BRUSH_SLIDERS; exports.BUILTIN_BRUSHES = _chunk5BR7LC24cjs.BUILTIN_BRUSHES; exports.BristleStroke = _chunk5BR7LC24cjs.BristleStroke; exports.DEFAULT_BEHAVIOR = _chunk5BR7LC24cjs.DEFAULT_BEHAVIOR; exports.DEFAULT_BRISTLE = _chunk5BR7LC24cjs.DEFAULT_BRISTLE; exports.DEFAULT_BRUSH_ID = _chunk5BR7LC24cjs.DEFAULT_BRUSH_ID; exports.DEFAULT_DPI = DEFAULT_DPI; exports.DEFAULT_DYNAMICS = _chunk5BR7LC24cjs.DEFAULT_DYNAMICS; exports.DEFAULT_FLOW = _chunkXFYLA3ZOcjs.DEFAULT_FLOW; exports.DEFAULT_IMPASTO = _chunk5BR7LC24cjs.DEFAULT_IMPASTO; exports.DEFAULT_LIGHTING = DEFAULT_LIGHTING; exports.DEFAULT_MULTI_COLOR = _chunk5BR7LC24cjs.DEFAULT_MULTI_COLOR; exports.DEFAULT_PAINT_GRADIENT = _chunkPQ3H2AANcjs.DEFAULT_PAINT_GRADIENT; exports.DEFAULT_PAINT_GRADIENT_MAPPING = _chunkPQ3H2AANcjs.DEFAULT_PAINT_GRADIENT_MAPPING; exports.DEFAULT_PAPER = _chunk5BR7LC24cjs.DEFAULT_PAPER; exports.DEFAULT_PARTICLE = _chunk5BR7LC24cjs.DEFAULT_PARTICLE; exports.DEFAULT_STICKER = _chunk5BR7LC24cjs.DEFAULT_STICKER; exports.DEFAULT_SWATCHES = DEFAULT_SWATCHES; exports.DEFAULT_VIEW = DEFAULT_VIEW; exports.DEFAULT_WET_BRUSH = _chunk5BR7LC24cjs.DEFAULT_WET_BRUSH; exports.DEFAULT_WET_PARAMS = _chunkXFYLA3ZOcjs.DEFAULT_WET_PARAMS; exports.DryStroke = _chunk5BR7LC24cjs.DryStroke; exports.EFFECT_MAP_REPEATS = _chunk5BR7LC24cjs.EFFECT_MAP_REPEATS; exports.EFFECT_STRIP_HEIGHT = _chunk5BR7LC24cjs.EFFECT_STRIP_HEIGHT; exports.GPU_LEAD = GPU_LEAD; exports.GRAIN_PATTERNS = _chunkPQ3H2AANcjs.GRAIN_PATTERNS; exports.GRAIN_TILE = _chunkPQ3H2AANcjs.GRAIN_TILE; exports.HARMONY_KINDS = _chunk7PT4RJL5cjs.HARMONY_KINDS; exports.IDENTITY_AFFINE = IDENTITY_AFFINE; exports.IDENTITY_COPY = _chunk5BR7LC24cjs.IDENTITY_COPY; exports.IMPASTO_TOOLS = _chunk5BR7LC24cjs.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 = _chunkPQ3H2AANcjs.MAX_BRUSH_SIZE; exports.MAX_CANVAS_SIDE = MAX_CANVAS_SIDE; exports.MAX_COORDINATE = MAX_COORDINATE; exports.MAX_IMAGE_SIDE = MAX_IMAGE_SIDE; exports.MAX_LIVE_EFFECT_SOURCES = MAX_LIVE_EFFECT_SOURCES; 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 = _chunk5BR7LC24cjs.MULTI_COLOR_MODES; exports.MixingPad = MixingPad; exports.PAD_SAMPLE_SIZES = PAD_SAMPLE_SIZES; exports.PAINTERLY_BLEND_MODES = _chunkOLNIPTB3cjs.PAINTERLY_BLEND_MODES; exports.PAINT_BRUSH_CATEGORIES = _chunk5BR7LC24cjs.PAINT_BRUSH_CATEGORIES; exports.PAINT_BRUSH_ENGINES = _chunk5BR7LC24cjs.PAINT_BRUSH_ENGINES; exports.PAINT_COLOR_JSON_SCHEMA = _chunkPQ3H2AANcjs.PAINT_COLOR_JSON_SCHEMA; exports.PAINT_EFFECT_PLACES = PAINT_EFFECT_PLACES; exports.PAINT_FORMAT = PAINT_FORMAT; exports.PAINT_GRADIENT_FULL_SPEED = _chunkPQ3H2AANcjs.PAINT_GRADIENT_FULL_SPEED; exports.PAINT_GRADIENT_JSON_SCHEMA = _chunkPQ3H2AANcjs.PAINT_GRADIENT_JSON_SCHEMA; exports.PAINT_GRADIENT_KIT = _chunkPQ3H2AANcjs.PAINT_GRADIENT_KIT; exports.PAINT_GRADIENT_MAPPINGS = _chunkPQ3H2AANcjs.PAINT_GRADIENT_MAPPINGS; exports.PAINT_GRADIENT_MAPPING_LABELS = _chunkPQ3H2AANcjs.PAINT_GRADIENT_MAPPING_LABELS; exports.PAINT_GRADIENT_PRESETS = _chunkPQ3H2AANcjs.PAINT_GRADIENT_PRESETS; exports.PAINT_GRADIENT_REPEATS = _chunkPQ3H2AANcjs.PAINT_GRADIENT_REPEATS; exports.PAINT_GRADIENT_REPEAT_LABELS = _chunkPQ3H2AANcjs.PAINT_GRADIENT_REPEAT_LABELS; exports.PAINT_GRADIENT_SPACES = _chunkPQ3H2AANcjs.PAINT_GRADIENT_SPACES; exports.PAINT_GRADIENT_SPACE_LABELS = _chunkPQ3H2AANcjs.PAINT_GRADIENT_SPACE_LABELS; exports.PAINT_SCHEMA_VERSION = PAINT_SCHEMA_VERSION; exports.PAINT_SOURCE_JSON_SCHEMA = _chunkPQ3H2AANcjs.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 = _chunk5BR7LC24cjs.PAPER_FAMILIES; exports.PAPER_LIBRARY = _chunk5BR7LC24cjs.PAPER_LIBRARY; exports.PAPER_NODE_ID = PAPER_NODE_ID; exports.PAPER_SLIDERS = PAPER_SLIDERS; exports.PAPER_TARGET = PAPER_TARGET; exports.PARTICLE_KINDS = _chunk5BR7LC24cjs.PARTICLE_KINDS; exports.PARTICLE_KIND_LABELS = PARTICLE_KIND_LABELS; exports.PARTICLE_RENDERS = _chunk5BR7LC24cjs.PARTICLE_RENDERS; exports.PARTICLE_RENDER_LABELS = PARTICLE_RENDER_LABELS; exports.PaintCanvasPresenter = PaintCanvasPresenter; exports.PaintDabStroke = PaintDabStroke; exports.PaintDirector = PaintDirector; exports.PaintDocumentError = PaintDocumentError; exports.PaintEditorController = PaintEditorController; exports.PaintEditorError = PaintEditorError; exports.PaintEffectsRenderer = PaintEffectsRenderer; exports.PaintGesture = PaintGesture; exports.PaintGradientSampler = _chunkPQ3H2AANcjs.PaintGradientSampler; exports.PaintPresence = PaintPresence; exports.PaintSourceError = _chunkPQ3H2AANcjs.PaintSourceError; exports.PaintStrokeSession = PaintStrokeSession; exports.PaintWetLayers = PaintWetLayers; exports.PaperGrain = _chunkPQ3H2AANcjs.PaperGrain; exports.ParticleStroke = _chunk5BR7LC24cjs.ParticleStroke; exports.PenDabWalker = _chunk5BR7LC24cjs.PenDabWalker; exports.PenSmoother = _chunk5BR7LC24cjs.PenSmoother; exports.PerspectiveSnapper = PerspectiveSnapper; exports.SNAP_DECIDE_DISTANCE = SNAP_DECIDE_DISTANCE; exports.STAMP_KINDS = _chunk5BR7LC24cjs.STAMP_KINDS; exports.STAMP_LABELS = STAMP_LABELS; exports.STENCIL_KINDS = STENCIL_KINDS; exports.STENCIL_SHAPES = STENCIL_SHAPES; exports.STICKER_SLIDERS = STICKER_SLIDERS; exports.STROKE_SLIDERS = STROKE_SLIDERS; exports.SYMMETRY_MODES = SYMMETRY_MODES; exports.StencilSnapper = StencilSnapper; exports.StickerSpray = _chunk5BR7LC24cjs.StickerSpray; exports.TRACING_NODE_ID = TRACING_NODE_ID; exports.ThickStrokeDriver = ThickStrokeDriver; exports.TileableNoise = _chunkPQ3H2AANcjs.TileableNoise; exports.WET_FLOW_KINDS = _chunkXFYLA3ZOcjs.WET_FLOW_KINDS; exports.WET_GPU_MODES = WET_GPU_MODES; exports.WET_GPU_OPTIONS = WET_GPU_OPTIONS; exports.WET_MEDIA = _chunk5BR7LC24cjs.WET_MEDIA; exports.WET_MEDIUM_LABELS = WET_MEDIUM_LABELS; exports.WET_MEDIUM_PARAMS = WET_MEDIUM_PARAMS; exports.WET_PARAM_KEYS = _chunkXFYLA3ZOcjs.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 = _chunk5BR7LC24cjs.WET_TOOLS; exports.WET_TOOL_LABELS = WET_TOOL_LABELS; exports.WetStrokeDriver = WetStrokeDriver; exports.addPaintGradientStop = _chunkPQ3H2AANcjs.addPaintGradientStop; exports.affineCopy = affineCopy; exports.applyAffine = applyAffine; exports.brushEngineControls = brushEngineControls; exports.brushLoadColor = brushLoadColor; exports.brushLoadForStroke = brushLoadForStroke; exports.brushTakesPaint = _chunk5BR7LC24cjs.brushTakesPaint; exports.brushToJSON = _chunk5BR7LC24cjs.brushToJSON; exports.buildTimeLapse = buildTimeLapse; exports.checkPaintEffectPlace = checkPaintEffectPlace; exports.clonePaper = _chunk5BR7LC24cjs.clonePaper; exports.colorHarmony = colorHarmony2; exports.composeAffine = composeAffine; exports.contactSheet = contactSheet; exports.createPaintCompositor = createPaintCompositor; exports.createPaintDocument = createPaintDocument; exports.createPaintEditorDocument = createPaintEditorDocument; exports.createPaintEditorToolProvider = createPaintEditorToolProvider; exports.createPaintEffectsToolProvider = createPaintEffectsToolProvider; exports.createPaintLayer = createPaintLayer; exports.createPaintReplayTools = createPaintReplayTools; exports.createPaintStickerTools = createPaintStickerTools; exports.createPaintThickTools = createPaintThickTools; exports.createPaintWetTools = createPaintWetTools; exports.decodeImageBlob = decodeImageBlob; exports.defaultGuides = defaultGuides; exports.defaultImageEncoder = defaultImageEncoder; exports.deserializePaintDocument = deserializePaintDocument; exports.deserializePaintDocumentAsync = deserializePaintDocumentAsync; exports.documentExtensions = documentExtensions; exports.documentToScreen = documentToScreen; exports.downloadBytes = downloadBytes; exports.downsampleRgba = downsampleRgba; exports.drawSticker = _chunk5BR7LC24cjs.drawSticker; exports.drawWaterOverlay = drawWaterOverlay; exports.effectDabField = _chunk5BR7LC24cjs.effectDabField; exports.effectLayersToJSON = effectLayersToJSON; exports.effectPaintKey = _chunk5BR7LC24cjs.effectPaintKey; exports.effectPaintSize = _chunk5BR7LC24cjs.effectPaintSize; exports.emptiedLayers = emptiedLayers; exports.emptyThickChannels = emptyThickChannels; exports.fitZoom = fitZoom; exports.grainCatch = _chunkPQ3H2AANcjs.grainCatch; exports.grainHeights = _chunkPQ3H2AANcjs.grainHeights; exports.guideOverlay = guideOverlay; exports.handlePaintShortcut = handlePaintShortcut; exports.hash2 = _chunkPQ3H2AANcjs.hash2; exports.hexToPaintRgb = _chunkPQ3H2AANcjs.hexToPaintRgb; exports.hexToRgb8 = _chunk5BR7LC24cjs.hexToRgb8; exports.hslToRgb = hslToRgb; exports.hsvToRgb = hsvToRgb; exports.hueToWheel = _chunk7PT4RJL5cjs.hueToWheel; exports.invertAffine = invertAffine; exports.isBlendMode = _chunkOLNIPTB3cjs.isBlendMode; exports.isGradientPaint = _chunkPQ3H2AANcjs.isGradientPaint; exports.isPaintEffectPaint = _chunk5BR7LC24cjs.isPaintEffectPaint; exports.isPainterlyBlendMode = _chunkOLNIPTB3cjs.isPainterlyBlendMode; exports.isPalmTouch = isPalmTouch; exports.isWetBrush = _chunk5BR7LC24cjs.isWetBrush; exports.isWetCapable = _chunk5BR7LC24cjs.isWetCapable; exports.lightTile = lightTile; exports.lightingKey = lightingKey; exports.liveStrokeBounds = liveStrokeBounds; exports.liveStrokeRefusal = liveStrokeRefusal; exports.mapPenPoint = mapPenPoint; exports.mix32 = _chunkPQ3H2AANcjs.mix32; exports.mixPixels = mixPixels; exports.mixerLoadForStroke = mixerLoadForStroke; exports.mixerTip = _chunk5BR7LC24cjs.mixerTip; exports.multiColorForDab = multiColorForDab; exports.multiColorGradient = multiColorGradient; exports.multiColorPalette = multiColorPalette; exports.multiColorSliders = multiColorSliders; exports.multiColorToPaint = _chunk5BR7LC24cjs.multiColorToPaint; exports.newPaintLayerId = newPaintLayerId; exports.nextPaperEffectVersion = nextPaperEffectVersion; exports.normalizeBehavior = _chunk5BR7LC24cjs.normalizeBehavior; exports.normalizeBristle = _chunk5BR7LC24cjs.normalizeBristle; exports.normalizeBrushStroke = normalizeBrushStroke; exports.normalizeCanvas = normalizeCanvas; exports.normalizeDynamics = _chunk5BR7LC24cjs.normalizeDynamics; exports.normalizeFlow = _chunkXFYLA3ZOcjs.normalizeFlow; exports.normalizeHexColor = _chunkPQ3H2AANcjs.normalizeHexColor; exports.normalizeImpasto = _chunk5BR7LC24cjs.normalizeImpasto; exports.normalizeLighting = normalizeLighting; exports.normalizeMultiColor = _chunk5BR7LC24cjs.normalizeMultiColor; exports.normalizePaintBrush = _chunk5BR7LC24cjs.normalizePaintBrush; exports.normalizePaper = _chunk5BR7LC24cjs.normalizePaper; exports.normalizeParticle = _chunk5BR7LC24cjs.normalizeParticle; exports.normalizePerspective = normalizePerspective; exports.normalizeRotation = normalizeRotation; exports.normalizeStencil = normalizeStencil; exports.normalizeStickerSettings = _chunk5BR7LC24cjs.normalizeStickerSettings; exports.normalizeStickerUpdate = _chunk5BR7LC24cjs.normalizeStickerUpdate; exports.normalizeSymmetry = normalizeSymmetry; exports.normalizeView = normalizeView; exports.normalizeWetBrush = _chunk5BR7LC24cjs.normalizeWetBrush; exports.normalizeWetParams = _chunkXFYLA3ZOcjs.normalizeWetParams; exports.overPixels = overPixels; exports.padSampleRadius = padSampleRadius; exports.paintGradientMappingFor = _chunkPQ3H2AANcjs.paintGradientMappingFor; exports.paintPlaybackPanel = paintPlaybackPanel; exports.paintSourceColor = _chunkPQ3H2AANcjs.paintSourceColor; exports.paintSourceCss = _chunkPQ3H2AANcjs.paintSourceCss; exports.paintToMultiColor = _chunk5BR7LC24cjs.paintToMultiColor; exports.paperEffectFromJSON = paperEffectFromJSON; exports.paperEffectToJSON = paperEffectToJSON; exports.paperGrain = paperGrain; exports.paperKey = paperKey; exports.paperNode = paperNode; exports.paperPreset = _chunk5BR7LC24cjs.paperPreset; exports.parseBrushLibrary = _chunk5BR7LC24cjs.parseBrushLibrary; exports.parseHexColor = parseHexColor; exports.parsePaintSource = _chunkPQ3H2AANcjs.parsePaintSource; exports.patchBrushValue = patchBrushValue; exports.patchPath = patchPath; exports.penOrientation = _chunk5BR7LC24cjs.penOrientation; exports.perspectiveDirections = perspectiveDirections; exports.perspectiveGuideLines = perspectiveGuideLines; exports.planPaintToolPlayback = planPaintToolPlayback; exports.pointerToPenPoint = pointerToPenPoint; exports.quickStencil = quickStencil; exports.rand01 = _chunkPQ3H2AANcjs.rand01; exports.randSigned = _chunkPQ3H2AANcjs.randSigned; exports.readEffectStrokeMap = _chunk5BR7LC24cjs.readEffectStrokeMap; exports.readPaintEffectPaint = _chunk5BR7LC24cjs.readPaintEffectPaint; exports.readPaintEffectSource = readPaintEffectSource; exports.readPaintSource = _chunkPQ3H2AANcjs.readPaintSource; exports.readPath = readPath; exports.readSwatch = readSwatch; exports.reliefInfo = reliefInfo; exports.removePaintGradientStop = _chunkPQ3H2AANcjs.removePaintGradientStop; exports.renderBrushThumbnail = renderBrushThumbnail; exports.renderColorWheel = renderColorWheel; exports.renderPaper = _chunk5BR7LC24cjs.renderPaper; exports.renderStickers = _chunk5BR7LC24cjs.renderStickers; exports.replayFrame = replayFrame; exports.replayItems = replayItems; exports.replayPainting = replayPainting; exports.resolvePaintGradient = _chunkPQ3H2AANcjs.resolvePaintGradient; exports.reversePaintGradient = _chunkPQ3H2AANcjs.reversePaintGradient; exports.rgbToHexColor = rgbToHexColor; exports.rgbToHsl = rgbToHsl; exports.rgbToHsv = rgbToHsv; exports.sampleEffectAt = _chunk5BR7LC24cjs.sampleEffectAt; exports.sampleEffectField = _chunk5BR7LC24cjs.sampleEffectField; exports.samplePressure = samplePressure; exports.scalePaintGradient = _chunkPQ3H2AANcjs.scalePaintGradient; exports.scaleStencil = scaleStencil; exports.screenToDocument = screenToDocument; exports.seedFromString = _chunkPQ3H2AANcjs.seedFromString; exports.serializePaintDocument = serializePaintDocument; exports.serializePaintDocumentExternal = serializePaintDocumentExternal; exports.solidPaint = _chunkPQ3H2AANcjs.solidPaint; exports.stampCoverage = _chunk5BR7LC24cjs.stampCoverage; exports.standardBlendMode = _chunkOLNIPTB3cjs.standardBlendMode; exports.startWetClock = startWetClock; exports.stencilMask = stencilMask; exports.stencilOutline = stencilOutline; exports.stickerAt = _chunk5BR7LC24cjs.stickerAt; exports.stickerRect = _chunk5BR7LC24cjs.stickerRect; exports.stickerSurface = _chunk5BR7LC24cjs.stickerSurface; exports.strokeBounds = strokeBounds; exports.strokeDuration = strokeDuration; exports.strokeSchedule = strokeSchedule; exports.sweepPath = sweepPath; exports.symmetryAxisAngles = symmetryAxisAngles; exports.symmetryAxisSegments = symmetryAxisSegments; exports.symmetryCopies = symmetryCopies; exports.thickFromJSON = thickFromJSON; exports.thickToJSON = thickToJSON; exports.thumbnailStroke = thumbnailStroke; exports.tiltToOrientation = _chunk5BR7LC24cjs.tiltToOrientation; exports.timeLapseVideo = timeLapseVideo; exports.timeLapseZip = timeLapseZip; exports.toStrokePoint = _chunk5BR7LC24cjs.toStrokePoint; exports.toggleStamp = toggleStamp; exports.translateStencil = translateStencil; exports.updatePaintGradientStop = _chunkPQ3H2AANcjs.updatePaintGradientStop; exports.usesPaintExchange = _chunk5BR7LC24cjs.usesPaintExchange; exports.variationAffine = variationAffine; exports.varyStroke = varyStroke; exports.viewCssTransform = viewCssTransform; exports.viewMatrix = viewMatrix; exports.viewPenToDocument = viewPenToDocument; exports.wetEngineSummary = wetEngineSummary; exports.wetPaperInput = wetPaperInput; exports.wetPigmentOf = wetPigmentOf; exports.wetSupport = _chunkXFYLA3ZOcjs.wetSupport; exports.wheelAngle = wheelAngle; exports.wheelPick = wheelPick; exports.wheelPoint = wheelPoint; exports.wheelToHue = _chunk7PT4RJL5cjs.wheelToHue; exports.withPaintPlayback = withPaintPlayback;