@pixerate/editor 0.226.0 → 0.227.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 (48) hide show
  1. package/dist/animation-editor/index.cjs +57 -57
  2. package/dist/animation-editor/index.js +3 -3
  3. package/dist/{brushstrokeRender-C3UU6GVC.js → brushstrokeRender-MAHOXL7K.js} +2 -2
  4. package/dist/{brushstrokeRender-EAJNE6WP.cjs → brushstrokeRender-WDTKD54B.cjs} +5 -5
  5. package/dist/canvas/index.cjs +8 -8
  6. package/dist/canvas/index.js +1 -1
  7. package/dist/{chunk-LCCMOWR7.cjs → chunk-ATKKG76G.cjs} +23 -23
  8. package/dist/{chunk-QAUIZPYI.cjs → chunk-BQE3Y6ZO.cjs} +2 -2
  9. package/dist/{chunk-G4E6RUPC.js → chunk-CDP2AKMA.js} +1 -1
  10. package/dist/{chunk-NDMXB4PR.js → chunk-CU6ANS5L.js} +1 -1
  11. package/dist/{chunk-ROVK6AXX.cjs → chunk-GNZI3KYK.cjs} +95 -23
  12. package/dist/{chunk-I7G3RSUJ.cjs → chunk-GXLZZVR5.cjs} +35 -35
  13. package/dist/{chunk-5YLOU7VF.js → chunk-KN3Y3FRY.js} +1 -1
  14. package/dist/{chunk-IWMDW7LB.cjs → chunk-MXJP77K4.cjs} +86 -86
  15. package/dist/{chunk-F7YA3MMC.js → chunk-TQOL6CF7.js} +76 -4
  16. package/dist/{chunk-ZMHPQ6HP.cjs → chunk-V3L7U63N.cjs} +1 -1
  17. package/dist/{chunk-DJBYJOHM.js → chunk-XSVUNSDJ.js} +1 -1
  18. package/dist/{chunk-BGOCAUXH.js → chunk-YMREOA67.js} +1 -1
  19. package/dist/image-editor/index.cjs +771 -771
  20. package/dist/image-editor/index.js +4 -4
  21. package/dist/paint-editor/controller.d.cts +54 -3
  22. package/dist/paint-editor/controller.d.ts +54 -3
  23. package/dist/paint-editor/dab-stroke.d.cts +3 -0
  24. package/dist/paint-editor/dab-stroke.d.ts +3 -0
  25. package/dist/paint-editor/effect-paint.d.cts +47 -0
  26. package/dist/paint-editor/effect-paint.d.ts +47 -0
  27. package/dist/paint-editor/effect-tools.d.cts +4 -2
  28. package/dist/paint-editor/effect-tools.d.ts +4 -2
  29. package/dist/paint-editor/effects.d.cts +3 -0
  30. package/dist/paint-editor/effects.d.ts +3 -0
  31. package/dist/paint-editor/engine.d.cts +4 -0
  32. package/dist/paint-editor/engine.d.ts +4 -0
  33. package/dist/paint-editor/index.cjs +536 -309
  34. package/dist/paint-editor/index.d.cts +1 -0
  35. package/dist/paint-editor/index.d.ts +1 -0
  36. package/dist/paint-editor/index.js +250 -23
  37. package/dist/paint-editor/procedural.d.cts +4 -0
  38. package/dist/paint-editor/procedural.d.ts +4 -0
  39. package/dist/paint-editor/stroke.d.cts +9 -0
  40. package/dist/paint-editor/stroke.d.ts +9 -0
  41. package/dist/paint-editor/strokes.d.cts +6 -2
  42. package/dist/paint-editor/strokes.d.ts +6 -2
  43. package/dist/vector/index.cjs +962 -962
  44. package/dist/vector/index.js +4 -4
  45. package/package.json +1 -1
  46. package/skills/pixerate-canvas/SKILL.md +2 -1
  47. package/skills/pixerate-paint-editor/SKILL.md +42 -6
  48. package/skills/pixerate-paint-sketch-to-finish/SKILL.md +7 -0
@@ -7,7 +7,7 @@ var _chunkC6CMQXMIcjs = require('../chunk-C6CMQXMI.cjs');
7
7
 
8
8
 
9
9
 
10
- var _chunkIWMDW7LBcjs = require('../chunk-IWMDW7LB.cjs');
10
+ var _chunkMXJP77K4cjs = require('../chunk-MXJP77K4.cjs');
11
11
  require('../chunk-A2IS7EHE.cjs');
12
12
  require('../chunk-SS53NNZO.cjs');
13
13
 
@@ -58,7 +58,7 @@ var _chunkJLWLX52Lcjs = require('../chunk-JLWLX52L.cjs');
58
58
 
59
59
 
60
60
  var _chunkK7ENM55Pcjs = require('../chunk-K7ENM55P.cjs');
61
- require('../chunk-QAUIZPYI.cjs');
61
+ require('../chunk-BQE3Y6ZO.cjs');
62
62
 
63
63
 
64
64
 
@@ -123,7 +123,12 @@ require('../chunk-QAUIZPYI.cjs');
123
123
 
124
124
 
125
125
 
126
- var _chunkROVK6AXXcjs = require('../chunk-ROVK6AXX.cjs');
126
+
127
+
128
+
129
+
130
+
131
+ var _chunkGNZI3KYKcjs = require('../chunk-GNZI3KYK.cjs');
127
132
  require('../chunk-CVFAAZXE.cjs');
128
133
  require('../chunk-GF2RBSDM.cjs');
129
134
  require('../chunk-NM3G4VQT.cjs');
@@ -278,7 +283,7 @@ function normalizeCanvas(raw) {
278
283
  function createPaintDocument(options = {}) {
279
284
  const canvas = normalizeCanvas({ width: _nullishCoalesce(options.width, () => ( 2048)), height: _nullishCoalesce(options.height, () => ( 1536)), dpi: options.dpi });
280
285
  const layer = createPaintLayer("Layer 1");
281
- return { canvas, paper: _chunkROVK6AXXcjs.normalizePaper.call(void 0, _nullishCoalesce(options.paper, () => ( {}))), layers: [layer], activeLayerId: layer.id, strokes: [] };
286
+ return { canvas, paper: _chunkGNZI3KYKcjs.normalizePaper.call(void 0, _nullishCoalesce(options.paper, () => ( {}))), layers: [layer], activeLayerId: layer.id, strokes: [] };
282
287
  }
283
288
 
284
289
  // src/paint-editor/dab-stroke.ts
@@ -332,13 +337,13 @@ var PaintDabStroke = (_class = class {
332
337
  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);
333
338
  this.brush = brush;
334
339
  this.options = options;
335
- this.smoother = new (0, _chunkROVK6AXXcjs.PenSmoother)(brush.tip.smoothing, brush.pressureSmoothing);
336
- this.copies = _optionalChain([options, 'access', _2 => _2.copies, 'optionalAccess', _3 => _3.length]) ? options.copies : [_chunkROVK6AXXcjs.IDENTITY_COPY];
340
+ this.smoother = new (0, _chunkGNZI3KYKcjs.PenSmoother)(brush.tip.smoothing, brush.pressureSmoothing);
341
+ this.copies = _optionalChain([options, 'access', _2 => _2.copies, 'optionalAccess', _3 => _3.length]) ? options.copies : [_chunkGNZI3KYKcjs.IDENTITY_COPY];
337
342
  const exchanging = brush.engine === "mixer" || brush.engine === "dab";
338
343
  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);
339
344
  this.mixing = brush.engine === "mixer" ? brush.mixer.mixing : brush.behavior.mixing;
340
345
  this.states = this.copies.map((c, i) => ({
341
- walker: new (0, _chunkROVK6AXXcjs.PenDabWalker)(brush, (_nullishCoalesce(options.seed, () => ( 0))) + i * 7919 | 0, c.linear),
346
+ walker: new (0, _chunkGNZI3KYKcjs.PenDabWalker)(brush, (_nullishCoalesce(options.seed, () => ( 0))) + i * 7919 | 0, c.linear),
342
347
  exchange: exchanging ? new (0, _chunkPQ3H2AANcjs.PaintExchange)(rates, options.load) : null,
343
348
  smudge: brush.engine === "smudge" ? new (0, _chunkPQ3H2AANcjs.SmudgeTip)(brush.smudge, brush.tip.size * (1 + brush.dynamics.tiltSize * 1.5)) : null
344
349
  }));
@@ -449,7 +454,11 @@ var PaintDabStroke = (_class = class {
449
454
  const ex = st.exchange;
450
455
  ex.pickUp(this.medium.sample(rect, tip));
451
456
  let flow = 1;
452
- if (this.sampler && !this.gradient) {
457
+ if (this.options.effect) {
458
+ const rgb = [0, 0, 0];
459
+ flow = _chunkGNZI3KYKcjs.sampleEffectAt.call(void 0, this.options.effect, d.x, d.y, rgb);
460
+ ex.setReservoirColor(rgb[0], rgb[1], rgb[2]);
461
+ } else if (this.sampler && !this.gradient) {
453
462
  const g = this.sampler.dab(d, this.sample);
454
463
  ex.setReservoirColor(g.rgb[0], g.rgb[1], g.rgb[2]);
455
464
  flow = g.alpha;
@@ -678,12 +687,12 @@ var ThickStrokeDriver = (_class3 = class {
678
687
  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);
679
688
  this.init = init;
680
689
  const b = init.brush;
681
- this.smoother = new (0, _chunkROVK6AXXcjs.PenSmoother)(b.tip.smoothing, b.pressureSmoothing);
682
- const copies = init.copies.length ? init.copies : [_chunkROVK6AXXcjs.IDENTITY_COPY];
690
+ this.smoother = new (0, _chunkGNZI3KYKcjs.PenSmoother)(b.tip.smoothing, b.pressureSmoothing);
691
+ const copies = init.copies.length ? init.copies : [_chunkGNZI3KYKcjs.IDENTITY_COPY];
683
692
  this.copies = copies;
684
693
  const rates = _chunkPQ3H2AANcjs.exchangeRates.call(void 0, b.behavior.pickup, b.behavior.mix, 1, b.behavior.mixing);
685
694
  this.states = copies.map((c, i) => ({
686
- walker: new (0, _chunkROVK6AXXcjs.PenDabWalker)(b, init.seed + i * 7919 | 0, c.linear),
695
+ walker: new (0, _chunkGNZI3KYKcjs.PenDabWalker)(b, init.seed + i * 7919 | 0, c.linear),
687
696
  exchange: new (0, _chunkPQ3H2AANcjs.PaintExchange)(rates, init.load),
688
697
  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,
689
698
  carried: null,
@@ -981,9 +990,11 @@ var PaintStrokeSession = (_class4 = class {
981
990
  this.layerId = init.layerId;
982
991
  this.base = init.surface;
983
992
  this.live = new Map(this.base.tiles);
984
- this.copies = init.copies.length ? init.copies : [_chunkROVK6AXXcjs.IDENTITY_COPY];
993
+ this.copies = init.copies.length ? init.copies : [_chunkGNZI3KYKcjs.IDENTITY_COPY];
985
994
  const brush = init.brush;
986
995
  if (init.wet) this.wetDriver = init.wet.driver;
996
+ const effect = _nullishCoalesce(_optionalChain([init, 'access', _15 => _15.effect, 'optionalAccess', _16 => _16.pixels]), () => ( null));
997
+ if (effect && (init.wet || init.thick || init.sticker)) throw new Error(`The ${brush.name} brush (${brush.engine} engine) cannot paint with effect paint.`);
987
998
  this.apply = {
988
999
  mode: brush.engine === "eraser" ? "erase" : "paint",
989
1000
  color: init.color,
@@ -996,11 +1007,11 @@ var PaintStrokeSession = (_class4 = class {
996
1007
  };
997
1008
  if (this.wetDriver) {
998
1009
  } else if (init.sticker) {
999
- this.stickerSpray = new (0, _chunkROVK6AXXcjs.StickerSpray)({ brush, target: this.tileTarget(), color: init.colorHex, seed: init.seed, copies: this.copies, nextId: init.sticker.nextId, paint: _nullishCoalesce(init.paint, () => ( null)) });
1010
+ this.stickerSpray = new (0, _chunkGNZI3KYKcjs.StickerSpray)({ brush, target: this.tileTarget(), color: init.colorHex, seed: init.seed, copies: this.copies, nextId: init.sticker.nextId, paint: _nullishCoalesce(init.paint, () => ( null)) });
1000
1011
  } else if (init.thick) {
1001
1012
  const rgb = (c) => [c[0] / 255, c[1] / 255, c[2] / 255];
1002
1013
  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)) });
1003
- } else if (brush.engine === "mixer" || brush.engine === "blender" || brush.engine === "smudge" || _chunkROVK6AXXcjs.usesPaintExchange.call(void 0, brush, Boolean(init.paint))) {
1014
+ } else if (brush.engine === "mixer" || brush.engine === "blender" || brush.engine === "smudge" || _chunkGNZI3KYKcjs.usesPaintExchange.call(void 0, brush, Boolean(init.paint))) {
1004
1015
  const rgb = (c) => [c[0] / 255, c[1] / 255, c[2] / 255];
1005
1016
  this.wet = new PaintDabStroke(brush, {
1006
1017
  target: this.tileTarget(),
@@ -1011,11 +1022,12 @@ var PaintStrokeSession = (_class4 = class {
1011
1022
  paperDepth: init.paperDepth,
1012
1023
  seed: init.seed,
1013
1024
  copies: this.copies,
1014
- paint: _nullishCoalesce(init.paint, () => ( null))
1025
+ paint: _nullishCoalesce(init.paint, () => ( null)),
1026
+ effect
1015
1027
  });
1016
1028
  } else {
1017
- const opts = { grain: init.grain, paperDepth: init.paperDepth, seed: init.seed, copies: this.copies, paint: _nullishCoalesce(init.paint, () => ( null)) };
1018
- this.dry = brush.engine === "particle" ? new (0, _chunkROVK6AXXcjs.ParticleStroke)(brush, opts) : brush.engine === "bristle" ? new (0, _chunkROVK6AXXcjs.BristleStroke)(brush, opts) : new (0, _chunkROVK6AXXcjs.DryStroke)(brush, opts);
1029
+ const opts = { grain: init.grain, paperDepth: init.paperDepth, seed: init.seed, copies: this.copies, paint: _nullishCoalesce(init.paint, () => ( null)), effect };
1030
+ this.dry = brush.engine === "particle" ? new (0, _chunkGNZI3KYKcjs.ParticleStroke)(brush, opts) : brush.engine === "bristle" ? new (0, _chunkGNZI3KYKcjs.BristleStroke)(brush, opts) : new (0, _chunkGNZI3KYKcjs.DryStroke)(brush, opts);
1019
1031
  }
1020
1032
  }
1021
1033
 
@@ -1047,11 +1059,11 @@ var PaintStrokeSession = (_class4 = class {
1047
1059
  offset: this.init.offset,
1048
1060
  lockTransparency: this.init.lockTransparency,
1049
1061
  selection: _nullishCoalesce(this.init.selection, () => ( null)),
1050
- readTile: (tx, ty) => _nullishCoalesce(_optionalChain([this, 'access', _15 => _15.live, 'access', _16 => _16.get, 'call', _17 => _17(_chunk474IQG74cjs.tileKey.call(void 0, tx, ty)), 'optionalAccess', _18 => _18.data]), () => ( null)),
1062
+ readTile: (tx, ty) => _nullishCoalesce(_optionalChain([this, 'access', _17 => _17.live, 'access', _18 => _18.get, 'call', _19 => _19(_chunk474IQG74cjs.tileKey.call(void 0, tx, ty)), 'optionalAccess', _20 => _20.data]), () => ( null)),
1051
1063
  writeTile: (tx, ty) => {
1052
1064
  const key = _chunk474IQG74cjs.tileKey.call(void 0, tx, ty);
1053
1065
  if (!this.touched.has(key)) {
1054
- const src = _nullishCoalesce(_optionalChain([this, 'access', _19 => _19.base, 'access', _20 => _20.tiles, 'access', _21 => _21.get, 'call', _22 => _22(key), 'optionalAccess', _23 => _23.data]), () => ( defaultTile(this.base)));
1066
+ const src = _nullishCoalesce(_optionalChain([this, 'access', _21 => _21.base, 'access', _22 => _22.tiles, 'access', _23 => _23.get, 'call', _24 => _24(key), 'optionalAccess', _25 => _25.data]), () => ( defaultTile(this.base)));
1055
1067
  this.live.set(key, { data: new Uint8ClampedArray(src), uniform: null });
1056
1068
  this.touched.add(key);
1057
1069
  }
@@ -1082,7 +1094,7 @@ var PaintStrokeSession = (_class4 = class {
1082
1094
  }
1083
1095
  /** Impasto strokes: the layer's thick-paint channels with the stroke so far. */
1084
1096
  thickChannels() {
1085
- return _nullishCoalesce(_optionalChain([this, 'access', _24 => _24.thickDriver, 'optionalAccess', _25 => _25.channels, 'call', _26 => _26()]), () => ( null));
1097
+ return _nullishCoalesce(_optionalChain([this, 'access', _26 => _26.thickDriver, 'optionalAccess', _27 => _27.channels, 'call', _28 => _28()]), () => ( null));
1086
1098
  }
1087
1099
  /** Shows a wet stroke's progress (the wet layer's display). */
1088
1100
  wetUpdate(rects) {
@@ -1128,8 +1140,8 @@ var PaintStrokeSession = (_class4 = class {
1128
1140
  }
1129
1141
  }
1130
1142
  for (const [key, { tx, ty, r }] of regions) {
1131
- const src = _nullishCoalesce(_optionalChain([this, 'access', _27 => _27.base, 'access', _28 => _28.tiles, 'access', _29 => _29.get, 'call', _30 => _30(key), 'optionalAccess', _31 => _31.data]), () => ( defaultTile(this.base)));
1132
- const prev = this.touched.has(key) ? _optionalChain([this, 'access', _32 => _32.live, 'access', _33 => _33.get, 'call', _34 => _34(key), 'optionalAccess', _35 => _35.data]) : void 0;
1143
+ const src = _nullishCoalesce(_optionalChain([this, 'access', _29 => _29.base, 'access', _30 => _30.tiles, 'access', _31 => _31.get, 'call', _32 => _32(key), 'optionalAccess', _33 => _33.data]), () => ( defaultTile(this.base)));
1144
+ const prev = this.touched.has(key) ? _optionalChain([this, 'access', _34 => _34.live, 'access', _35 => _35.get, 'call', _36 => _36(key), 'optionalAccess', _37 => _37.data]) : void 0;
1133
1145
  this.touched.add(key);
1134
1146
  const data = _chunkPQ3H2AANcjs.applyStrokeToTile.call(void 0, this.dry.coverage, src, ch, tx, ty, this.apply, prev ? { into: prev, region: r } : {});
1135
1147
  this.live.set(key, { data, uniform: null });
@@ -1165,7 +1177,7 @@ var PaintStrokeSession = (_class4 = class {
1165
1177
  const surface = changed ? new (0, _chunk474IQG74cjs.TiledSurface)(ch, tiles, this.base.defaultValue) : null;
1166
1178
  const dabs = this.dry ? this.dry.dabCount : this.thickDriver ? this.thickDriver.dabCount : this.stickerSpray ? this.stickerSpray.dabCount : this.wet.dabCount;
1167
1179
  this.result = { layerId: this.layerId, bounds: changed ? this.bounds : null, dabs, strokeId: null };
1168
- const carried = _nullishCoalesce(_optionalChain([this, 'access', _36 => _36.wet, 'optionalAccess', _37 => _37.load]), () => ( _optionalChain([this, 'access', _38 => _38.thickDriver, 'optionalAccess', _39 => _39.load])));
1180
+ const carried = _nullishCoalesce(_optionalChain([this, 'access', _38 => _38.wet, 'optionalAccess', _39 => _39.load]), () => ( _optionalChain([this, 'access', _40 => _40.thickDriver, 'optionalAccess', _41 => _41.load])));
1169
1181
  if (carried) this.result.mixerLoad = this.init.brush.behavior.dirty ? carried : _chunkPQ3H2AANcjs.cleanMixer.call(void 0, carried);
1170
1182
  this.host.commit(this, surface, false);
1171
1183
  return this.result;
@@ -1186,7 +1198,7 @@ function brushLoadForStroke(brush, current, color) {
1186
1198
  if (brush.engine === "mixer") return mixerLoadForStroke(brush, current, color);
1187
1199
  if (brush.engine === "impasto") return { reservoir: [color[0], color[1], color[2]], amount: 1, pickup: brush.behavior.dirty ? current.pickup : null };
1188
1200
  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;
1189
- if (_chunkROVK6AXXcjs.usesPaintExchange.call(void 0, brush)) return { reservoir: [color[0], color[1], color[2]], amount: 1, pickup: brush.behavior.dirty ? current.pickup : null };
1201
+ if (_chunkGNZI3KYKcjs.usesPaintExchange.call(void 0, brush)) return { reservoir: [color[0], color[1], color[2]], amount: 1, pickup: brush.behavior.dirty ? current.pickup : null };
1190
1202
  return _chunkPQ3H2AANcjs.EMPTY_MIXER_LOAD;
1191
1203
  }
1192
1204
 
@@ -1196,36 +1208,36 @@ var STENCIL_SHAPES = ["rect", "ellipse", "polygon"];
1196
1208
  var finite = (v) => typeof v === "number" && Number.isFinite(v);
1197
1209
  var pt = (p) => p && finite(p.x) && finite(p.y) ? { x: p.x, y: p.y } : void 0;
1198
1210
  function normalizeStencil(raw, id, base) {
1199
- const kind = STENCIL_KINDS.includes(raw.kind) ? raw.kind : _optionalChain([base, 'optionalAccess', _40 => _40.kind]);
1211
+ const kind = STENCIL_KINDS.includes(raw.kind) ? raw.kind : _optionalChain([base, 'optionalAccess', _42 => _42.kind]);
1200
1212
  if (!kind) throw new Error(`kind ${JSON.stringify(raw.kind)} is not a stencil; use ${STENCIL_KINDS.join(", ")}.`);
1201
1213
  const s = {
1202
1214
  id,
1203
1215
  kind,
1204
- mode: raw.mode === "guide" || raw.mode === "mask" ? raw.mode : _nullishCoalesce(_optionalChain([base, 'optionalAccess', _41 => _41.mode]), () => ( (kind === "ruler" || kind === "arc" ? "guide" : "mask"))),
1205
- enabled: typeof raw.enabled === "boolean" ? raw.enabled : _nullishCoalesce(_optionalChain([base, 'optionalAccess', _42 => _42.enabled]), () => ( true)),
1206
- invert: typeof raw.invert === "boolean" ? raw.invert : _nullishCoalesce(_optionalChain([base, 'optionalAccess', _43 => _43.invert]), () => ( false)),
1207
- snap: finite(raw.snap) ? Math.min(400, Math.max(1, raw.snap)) : _nullishCoalesce(_optionalChain([base, 'optionalAccess', _44 => _44.snap]), () => ( 40)),
1208
- feather: finite(raw.feather) ? Math.min(100, Math.max(0, raw.feather)) : _nullishCoalesce(_optionalChain([base, 'optionalAccess', _45 => _45.feather]), () => ( 1))
1216
+ mode: raw.mode === "guide" || raw.mode === "mask" ? raw.mode : _nullishCoalesce(_optionalChain([base, 'optionalAccess', _43 => _43.mode]), () => ( (kind === "ruler" || kind === "arc" ? "guide" : "mask"))),
1217
+ enabled: typeof raw.enabled === "boolean" ? raw.enabled : _nullishCoalesce(_optionalChain([base, 'optionalAccess', _44 => _44.enabled]), () => ( true)),
1218
+ invert: typeof raw.invert === "boolean" ? raw.invert : _nullishCoalesce(_optionalChain([base, 'optionalAccess', _45 => _45.invert]), () => ( false)),
1219
+ snap: finite(raw.snap) ? Math.min(400, Math.max(1, raw.snap)) : _nullishCoalesce(_optionalChain([base, 'optionalAccess', _46 => _46.snap]), () => ( 40)),
1220
+ feather: finite(raw.feather) ? Math.min(100, Math.max(0, raw.feather)) : _nullishCoalesce(_optionalChain([base, 'optionalAccess', _47 => _47.feather]), () => ( 1))
1209
1221
  };
1210
1222
  if (kind === "ruler" || kind === "line") {
1211
- s.from = _nullishCoalesce(pt(raw.from), () => ( _optionalChain([base, 'optionalAccess', _46 => _46.from])));
1212
- s.to = _nullishCoalesce(pt(raw.to), () => ( _optionalChain([base, 'optionalAccess', _47 => _47.to])));
1223
+ s.from = _nullishCoalesce(pt(raw.from), () => ( _optionalChain([base, 'optionalAccess', _48 => _48.from])));
1224
+ s.to = _nullishCoalesce(pt(raw.to), () => ( _optionalChain([base, 'optionalAccess', _49 => _49.to])));
1213
1225
  if (!s.from || !s.to) throw new Error(`A ${kind} needs from and to points ({x, y} in document pixels).`);
1214
1226
  if (Math.hypot(s.to.x - s.from.x, s.to.y - s.from.y) < 1) throw new Error(`A ${kind}'s from and to must be at least 1 px apart.`);
1215
1227
  } else if (kind === "arc") {
1216
- s.center = _nullishCoalesce(pt(raw.center), () => ( _optionalChain([base, 'optionalAccess', _48 => _48.center])));
1217
- s.radius = finite(raw.radius) ? raw.radius : _optionalChain([base, 'optionalAccess', _49 => _49.radius]);
1228
+ s.center = _nullishCoalesce(pt(raw.center), () => ( _optionalChain([base, 'optionalAccess', _50 => _50.center])));
1229
+ s.radius = finite(raw.radius) ? raw.radius : _optionalChain([base, 'optionalAccess', _51 => _51.radius]);
1218
1230
  if (!s.center || !(s.radius > 0)) throw new Error("An arc needs a center ({x, y}) and a radius above 0.");
1219
- s.startAngle = finite(raw.startAngle) ? raw.startAngle : _nullishCoalesce(_optionalChain([base, 'optionalAccess', _50 => _50.startAngle]), () => ( 0));
1220
- s.endAngle = finite(raw.endAngle) ? raw.endAngle : _nullishCoalesce(_optionalChain([base, 'optionalAccess', _51 => _51.endAngle]), () => ( 360));
1231
+ s.startAngle = finite(raw.startAngle) ? raw.startAngle : _nullishCoalesce(_optionalChain([base, 'optionalAccess', _52 => _52.startAngle]), () => ( 0));
1232
+ s.endAngle = finite(raw.endAngle) ? raw.endAngle : _nullishCoalesce(_optionalChain([base, 'optionalAccess', _53 => _53.endAngle]), () => ( 360));
1221
1233
  } else {
1222
- s.shape = STENCIL_SHAPES.includes(raw.shape) ? raw.shape : _nullishCoalesce(_optionalChain([base, 'optionalAccess', _52 => _52.shape]), () => ( "rect"));
1234
+ s.shape = STENCIL_SHAPES.includes(raw.shape) ? raw.shape : _nullishCoalesce(_optionalChain([base, 'optionalAccess', _54 => _54.shape]), () => ( "rect"));
1223
1235
  if (s.shape === "polygon") {
1224
- const pts = Array.isArray(raw.points) ? raw.points.map(pt).filter((p) => Boolean(p)) : _optionalChain([base, 'optionalAccess', _53 => _53.points]);
1236
+ const pts = Array.isArray(raw.points) ? raw.points.map(pt).filter((p) => Boolean(p)) : _optionalChain([base, 'optionalAccess', _55 => _55.points]);
1225
1237
  if (!pts || pts.length < 3) throw new Error("A polygon stencil needs at least 3 points.");
1226
1238
  s.points = pts;
1227
1239
  } else {
1228
- const r = _nullishCoalesce(raw.rect, () => ( _optionalChain([base, 'optionalAccess', _54 => _54.rect])));
1240
+ const r = _nullishCoalesce(raw.rect, () => ( _optionalChain([base, 'optionalAccess', _56 => _56.rect])));
1229
1241
  if (!r || !finite(r.x) || !finite(r.y) || !(r.width > 0) || !(r.height > 0)) throw new Error(`A ${s.shape} stencil needs rect {x, y, width, height} with a width and height above 0.`);
1230
1242
  s.rect = { x: r.x, y: r.y, width: r.width, height: r.height };
1231
1243
  }
@@ -1307,7 +1319,7 @@ var StencilSnapper = class {
1307
1319
  const { distance } = nearestOnStencil(s, p);
1308
1320
  if (distance <= s.snap && (!best || distance < best.d)) best = { s, d: distance };
1309
1321
  }
1310
- this.guide = _nullishCoalesce(_optionalChain([best, 'optionalAccess', _55 => _55.s]), () => ( null));
1322
+ this.guide = _nullishCoalesce(_optionalChain([best, 'optionalAccess', _57 => _57.s]), () => ( null));
1311
1323
  }
1312
1324
  if (!this.guide) return p;
1313
1325
  const q = nearestOnStencil(this.guide, p).point;
@@ -1454,7 +1466,7 @@ function normalizeBrushStroke(raw) {
1454
1466
  const out = {
1455
1467
  id: r.id,
1456
1468
  layerId: r.layerId,
1457
- brush: _chunkROVK6AXXcjs.normalizePaintBrush.call(void 0, _nullishCoalesce(r.brush, () => ( {}))),
1469
+ brush: _chunkGNZI3KYKcjs.normalizePaintBrush.call(void 0, _nullishCoalesce(r.brush, () => ( {}))),
1458
1470
  color: typeof r.color === "string" && /^#[0-9a-f]{6}$/i.test(r.color) ? r.color.toLowerCase() : "#000000",
1459
1471
  points,
1460
1472
  seed: finite2(r.seed) ? r.seed | 0 : 0
@@ -1467,14 +1479,16 @@ function normalizeBrushStroke(raw) {
1467
1479
  const st = [];
1468
1480
  for (const raw2 of r.stencils) {
1469
1481
  try {
1470
- st.push(normalizeStencil(raw2, typeof _optionalChain([raw2, 'optionalAccess', _56 => _56.id]) === "string" ? raw2.id : "stencil"));
1482
+ st.push(normalizeStencil(raw2, typeof _optionalChain([raw2, 'optionalAccess', _58 => _58.id]) === "string" ? raw2.id : "stencil"));
1471
1483
  } catch (e2) {
1472
1484
  }
1473
1485
  }
1474
1486
  if (st.length) out.stencils = st;
1475
1487
  }
1476
- const paint = _chunkPQ3H2AANcjs.readPaintSource.call(void 0, r.paint);
1477
- if (paint && paint.type === "gradient") out.paint = paint;
1488
+ const effect = _chunkGNZI3KYKcjs.readPaintEffectPaint.call(void 0, r.paint);
1489
+ const paint = effect ? null : _chunkPQ3H2AANcjs.readPaintSource.call(void 0, r.paint);
1490
+ if (effect) out.paint = effect;
1491
+ else if (paint && paint.type === "gradient") out.paint = paint;
1478
1492
  if (Array.isArray(r.steps) && r.steps.length === points.length && r.steps.every((v) => Number.isInteger(v) && v >= 0)) out.steps = [...r.steps];
1479
1493
  return out;
1480
1494
  }
@@ -1510,10 +1524,10 @@ function varyStroke(stroke, m, v) {
1510
1524
  if (ps !== 1) q.pressure = Math.min(1, Math.max(0, (_nullishCoalesce(p.pressure, () => ( 1))) * ps));
1511
1525
  return q;
1512
1526
  });
1513
- const brush = s !== 1 ? _chunkROVK6AXXcjs.normalizePaintBrush.call(void 0, { ...stroke.brush, tip: { ...stroke.brush.tip, size: stroke.brush.tip.size * s } }) : stroke.brush;
1527
+ const brush = s !== 1 ? _chunkGNZI3KYKcjs.normalizePaintBrush.call(void 0, { ...stroke.brush, tip: { ...stroke.brush.tip, size: stroke.brush.tip.size * s } }) : stroke.brush;
1514
1528
  const out = { ...stroke, brush, points };
1515
- if (stroke.paint && s !== 1) out.paint = _chunkPQ3H2AANcjs.scalePaintGradient.call(void 0, stroke.paint, s);
1516
- if (_optionalChain([stroke, 'access', _57 => _57.copies, 'optionalAccess', _58 => _58.length])) {
1529
+ if (_optionalChain([stroke, 'access', _59 => _59.paint, 'optionalAccess', _60 => _60.type]) === "gradient" && s !== 1) out.paint = _chunkPQ3H2AANcjs.scalePaintGradient.call(void 0, stroke.paint, s);
1530
+ if (_optionalChain([stroke, 'access', _61 => _61.copies, 'optionalAccess', _62 => _62.length])) {
1517
1531
  const inv = invertAffine(m);
1518
1532
  out.copies = stroke.copies.map((c) => composeAffine(m, composeAffine(c, inv)));
1519
1533
  }
@@ -1532,7 +1546,7 @@ var paperNodes = /* @__PURE__ */ new WeakMap();
1532
1546
  function paperNode(paper, light) {
1533
1547
  let n = paperNodes.get(paper);
1534
1548
  const metal = (_nullishCoalesce(paper.metallic, () => ( 0))) > 0;
1535
- if (!n || metal && (_optionalChain([n, 'access', _59 => _59.light, 'optionalAccess', _60 => _60.azimuth]) !== _optionalChain([light, 'optionalAccess', _61 => _61.azimuth]) || _optionalChain([n, 'access', _62 => _62.light, 'optionalAccess', _63 => _63.elevation]) !== _optionalChain([light, 'optionalAccess', _64 => _64.elevation]))) {
1549
+ 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]))) {
1536
1550
  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 } } : {} };
1537
1551
  paperNodes.set(paper, n);
1538
1552
  }
@@ -1554,7 +1568,7 @@ function paperTile(paper, r, light) {
1554
1568
  const key = `${paperKey(paper, light)}|${r.x},${r.y},${r.width},${r.height}`;
1555
1569
  let t = tileCache.get(key);
1556
1570
  if (!t) {
1557
- t = _chunkROVK6AXXcjs.renderPaper.call(void 0, paper, r, paperGrain(paper), light);
1571
+ t = _chunkGNZI3KYKcjs.renderPaper.call(void 0, paper, r, paperGrain(paper), light);
1558
1572
  if (tileCache.size > 512) tileCache.delete(tileCache.keys().next().value);
1559
1573
  tileCache.set(key, t);
1560
1574
  }
@@ -1653,17 +1667,17 @@ function header(state, options) {
1653
1667
  if (options.swatches !== void 0) out.swatches = JSON.parse(JSON.stringify(options.swatches));
1654
1668
  if (options.mixingPad !== void 0) out.mixingPad = JSON.parse(JSON.stringify(options.mixingPad));
1655
1669
  if (options.wet !== void 0) out.wet = JSON.parse(JSON.stringify(options.wet));
1656
- if (_optionalChain([state, 'access', _65 => _65.wetEvents, 'optionalAccess', _66 => _66.length])) out.wetEvents = JSON.parse(JSON.stringify(state.wetEvents));
1657
- if (_optionalChain([state, 'access', _67 => _67.paintEvents, 'optionalAccess', _68 => _68.length])) out.paintEvents = JSON.parse(JSON.stringify(state.paintEvents));
1670
+ if (_optionalChain([state, 'access', _69 => _69.wetEvents, 'optionalAccess', _70 => _70.length])) out.wetEvents = JSON.parse(JSON.stringify(state.wetEvents));
1671
+ if (_optionalChain([state, 'access', _71 => _71.paintEvents, 'optionalAccess', _72 => _72.length])) out.paintEvents = JSON.parse(JSON.stringify(state.paintEvents));
1658
1672
  if (state.origin && (state.origin.x || state.origin.y)) out.origin = { ...state.origin };
1659
1673
  return out;
1660
1674
  }
1661
1675
  function serializePaintDocument(state, options = {}) {
1662
- const { layers, assets } = _chunkIWMDW7LBcjs.serializeLayers.call(void 0, state.layers);
1676
+ const { layers, assets } = _chunkMXJP77K4cjs.serializeLayers.call(void 0, state.layers);
1663
1677
  return { ...header(state, options), layers, assets };
1664
1678
  }
1665
1679
  async function serializePaintDocumentExternal(state, store, options = {}) {
1666
- const { layers, assets } = await _chunkIWMDW7LBcjs.serializeLayersExternal.call(void 0, state.layers, store);
1680
+ const { layers, assets } = await _chunkMXJP77K4cjs.serializeLayersExternal.call(void 0, state.layers, store);
1667
1681
  return { ...header(state, options), layers, assets };
1668
1682
  }
1669
1683
  function paintLayersOnly(layers, problems) {
@@ -1671,7 +1685,7 @@ function paintLayersOnly(layers, problems) {
1671
1685
  for (const l of layers) {
1672
1686
  if (l.type === "pixel") {
1673
1687
  const { filters, source, ...rest } = l;
1674
- if (_optionalChain([filters, 'optionalAccess', _69 => _69.length])) problems.push(`Layer "${l.name}": its filters are an image editor feature and were dropped.`);
1688
+ if (_optionalChain([filters, 'optionalAccess', _73 => _73.length])) problems.push(`Layer "${l.name}": its filters are an image editor feature and were dropped.`);
1675
1689
  if (source) problems.push(`Layer "${l.name}" refers to an image editor source image; it loads empty.`);
1676
1690
  out.push(rest);
1677
1691
  } else if (l.type === "group") out.push({ ...l, children: paintLayersOnly(l.children, problems) });
@@ -1698,11 +1712,11 @@ function deserializePaintDocument(raw) {
1698
1712
  }
1699
1713
  const problems = [];
1700
1714
  const canvas = normalizeCanvas({ width: r.width, height: r.height, dpi: _nullishCoalesce(r.dpi, () => ( void 0)) });
1701
- const paper = _chunkROVK6AXXcjs.normalizePaper.call(void 0, _nullishCoalesce(r.paper, () => ( {})));
1715
+ const paper = _chunkGNZI3KYKcjs.normalizePaper.call(void 0, _nullishCoalesce(r.paper, () => ( {})));
1702
1716
  const assets = r.assets && typeof r.assets === "object" ? r.assets : {};
1703
- const layers = paintLayersOnly(_chunkIWMDW7LBcjs.deserializeLayers.call(void 0, r.layers, { assets, problems }), problems);
1717
+ const layers = paintLayersOnly(_chunkMXJP77K4cjs.deserializeLayers.call(void 0, r.layers, { assets, problems }), problems);
1704
1718
  const wanted = typeof r.activeLayerId === "string" ? r.activeLayerId : null;
1705
- const activeLayerId = wanted && _chunkB46UQUDCcjs.findLayer.call(void 0, layers, wanted) ? wanted : _nullishCoalesce(_optionalChain([_chunkB46UQUDCcjs.flattenLayers.call(void 0, layers), 'access', _70 => _70.filter, 'call', _71 => _71((l) => l.type === "pixel"), 'access', _72 => _72.pop, 'call', _73 => _73(), 'optionalAccess', _74 => _74.id]), () => ( null));
1719
+ const activeLayerId = wanted && _chunkB46UQUDCcjs.findLayer.call(void 0, layers, wanted) ? wanted : _nullishCoalesce(_optionalChain([_chunkB46UQUDCcjs.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));
1706
1720
  const wetEvents = Array.isArray(r.wetEvents) ? r.wetEvents.filter((e) => e && typeof e === "object" && Number.isInteger(e.clock) && typeof e.kind === "string") : [];
1707
1721
  const state = { canvas, paper, layers, activeLayerId, strokes: readStrokes(r.strokes, problems) };
1708
1722
  if (wetEvents.length) state.wetEvents = wetEvents;
@@ -1716,7 +1730,7 @@ async function deserializePaintDocumentAsync(raw, store) {
1716
1730
  if (!raw || typeof raw !== "object") throw new Error("Not a paint document: expected a JSON object.");
1717
1731
  const r = raw;
1718
1732
  const problems = [];
1719
- const assets = await _chunkIWMDW7LBcjs.resolveExternalAssets.call(void 0, _nullishCoalesce(r.assets, () => ( {})), store, problems);
1733
+ const assets = await _chunkMXJP77K4cjs.resolveExternalAssets.call(void 0, _nullishCoalesce(r.assets, () => ( {})), store, problems);
1720
1734
  const loaded = deserializePaintDocument({ ...r, assets });
1721
1735
  return { ...loaded, problems: [...problems, ...loaded.problems] };
1722
1736
  }
@@ -1799,7 +1813,7 @@ function pointerToPenPoint(e, x, y, view) {
1799
1813
  const p = { x, y, pressure: samplePressure(e) };
1800
1814
  if (typeof e.timeStamp === "number" && Number.isFinite(e.timeStamp)) p.t = e.timeStamp;
1801
1815
  if (e.pointerType !== "pen") return p;
1802
- const o = _chunkROVK6AXXcjs.penOrientation.call(void 0, {
1816
+ const o = _chunkGNZI3KYKcjs.penOrientation.call(void 0, {
1803
1817
  x,
1804
1818
  y,
1805
1819
  altitude: typeof e.altitudeAngle === "number" ? e.altitudeAngle : void 0,
@@ -1847,7 +1861,7 @@ async function decodeImageBlob(blob) {
1847
1861
  if (!ctx) throw new Error("No 2D context to decode with.");
1848
1862
  ctx.drawImage(bitmap, 0, 0);
1849
1863
  const data = new Uint8ClampedArray(ctx.getImageData(0, 0, bitmap.width, bitmap.height).data);
1850
- _optionalChain([bitmap, 'access', _75 => _75.close, 'optionalCall', _76 => _76()]);
1864
+ _optionalChain([bitmap, 'access', _79 => _79.close, 'optionalCall', _80 => _80()]);
1851
1865
  return { width: bitmap.width, height: bitmap.height, data };
1852
1866
  }
1853
1867
  function downloadBytes(bytes, fileName, mimeType) {
@@ -1878,7 +1892,7 @@ function wetPaperInput(paper) {
1878
1892
  absorption: paper.absorption,
1879
1893
  permeability: paper.permeability,
1880
1894
  roughness: flat ? 0 : paper.roughness,
1881
- color: _chunkROVK6AXXcjs.hexToRgb8.call(void 0, paper.color),
1895
+ color: _chunkGNZI3KYKcjs.hexToRgb8.call(void 0, paper.color),
1882
1896
  heightAt: flat ? () => 0.5 : (x, y) => grain.at(x, y)
1883
1897
  };
1884
1898
  }
@@ -1886,8 +1900,8 @@ var WetStrokeDriver = (_class5 = class {
1886
1900
  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);
1887
1901
  this.init = init;
1888
1902
  const brush = init.brush;
1889
- this.smoother = new (0, _chunkROVK6AXXcjs.PenSmoother)(brush.tip.smoothing, brush.pressureSmoothing);
1890
- const copies = init.copies.length ? init.copies : [_chunkROVK6AXXcjs.IDENTITY_COPY];
1903
+ this.smoother = new (0, _chunkGNZI3KYKcjs.PenSmoother)(brush.tip.smoothing, brush.pressureSmoothing);
1904
+ const copies = init.copies.length ? init.copies : [_chunkGNZI3KYKcjs.IDENTITY_COPY];
1891
1905
  const wet = brush.wet;
1892
1906
  const spacing = Math.max(0.02, brush.tip.spacing);
1893
1907
  const perDab = Math.min(1, spacing * 1.2);
@@ -1899,7 +1913,7 @@ var WetStrokeDriver = (_class5 = class {
1899
1913
  });
1900
1914
  const rates = _chunkPQ3H2AANcjs.exchangeRates.call(void 0, brush.behavior.pickup, brush.behavior.mix, wet.load, brush.behavior.mixing);
1901
1915
  this.states = copies.map((c, i) => ({
1902
- walker: new (0, _chunkROVK6AXXcjs.PenDabWalker)(brush, init.seed + i * 7919 | 0, c.linear),
1916
+ walker: new (0, _chunkGNZI3KYKcjs.PenDabWalker)(brush, init.seed + i * 7919 | 0, c.linear),
1903
1917
  exchange: wet.tool === "paint" ? new (0, _chunkPQ3H2AANcjs.PaintExchange)(rates, init.load) : null,
1904
1918
  last: null
1905
1919
  }));
@@ -1930,7 +1944,7 @@ var WetStrokeDriver = (_class5 = class {
1930
1944
 
1931
1945
  /** What copy 0's brush carries after the dabs so far. */
1932
1946
  get load() {
1933
- return _nullishCoalesce(_optionalChain([this, 'access', _77 => _77.states, 'access', _78 => _78[0], 'access', _79 => _79.exchange, 'optionalAccess', _80 => _80.load]), () => ( null));
1947
+ return _nullishCoalesce(_optionalChain([this, 'access', _81 => _81.states, 'access', _82 => _82[0], 'access', _83 => _83.exchange, 'optionalAccess', _84 => _84.load]), () => ( null));
1934
1948
  }
1935
1949
  /** Whether every point (and the end) has been applied. */
1936
1950
  get done() {
@@ -2139,8 +2153,8 @@ var PaintWetLayers = (_class6 = class {
2139
2153
  if (mode === this.gpuMode) return this.engineInfo();
2140
2154
  this.gpuMode = mode;
2141
2155
  if (mode === "off") {
2142
- _optionalChain([this, 'access', _81 => _81.world, 'optionalAccess', _82 => _82.attachGpu, 'call', _83 => _83(null)]);
2143
- _optionalChain([this, 'access', _84 => _84.gpu, 'optionalAccess', _85 => _85.destroy, 'call', _86 => _86()]);
2156
+ _optionalChain([this, 'access', _85 => _85.world, 'optionalAccess', _86 => _86.attachGpu, 'call', _87 => _87(null)]);
2157
+ _optionalChain([this, 'access', _88 => _88.gpu, 'optionalAccess', _89 => _89.destroy, 'call', _90 => _90()]);
2144
2158
  this.gpu = null;
2145
2159
  this.gpuSupport = null;
2146
2160
  } else if (this.world) this.startGpu();
@@ -2148,13 +2162,13 @@ var PaintWetLayers = (_class6 = class {
2148
2162
  }
2149
2163
  engineInfo() {
2150
2164
  const w = this.world;
2151
- const base = { mode: this.gpuMode, adapter: _nullishCoalesce(_optionalChain([this, 'access', _87 => _87.gpuSupport, 'optionalAccess', _88 => _88.adapter]), () => ( null)), maxTiles: _nullishCoalesce(_optionalChain([this, 'access', _89 => _89.gpuSupport, 'optionalAccess', _90 => _90.maxSlots]), () => ( 0)), minTiles: this.gpuMinTiles, activeTiles: _nullishCoalesce(_optionalChain([w, 'optionalAccess', _91 => _91.activeTiles, 'call', _92 => _92()]), () => ( 0)), cpu: this.backend() };
2165
+ 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() };
2152
2166
  if (this.gpuMode === "off") return { ...base, state: "off", reason: "Forced to the CPU." };
2153
2167
  if (this.gpuStarting) return { ...base, state: "starting", reason: null };
2154
- if (_optionalChain([w, 'optionalAccess', _93 => _93.gpuError])) return { ...base, state: "failed", reason: w.gpuError };
2168
+ if (_optionalChain([w, 'optionalAccess', _97 => _97.gpuError])) return { ...base, state: "failed", reason: w.gpuError };
2155
2169
  if (this.gpuSupport && !this.gpuSupport.supported) return { ...base, state: "unavailable", reason: this.gpuSupport.reason };
2156
2170
  if (!this.gpu) return { ...base, state: "not-started", reason: "Starts with the first wet stroke." };
2157
- if (_optionalChain([w, 'optionalAccess', _94 => _94.gpuActive])) return { ...base, state: "active", reason: null };
2171
+ if (_optionalChain([w, 'optionalAccess', _98 => _98.gpuActive])) return { ...base, state: "active", reason: null };
2158
2172
  return { ...base, state: "standby", reason: `The GPU takes over at ${this.gpuMinTiles} wet tiles (256 px).` };
2159
2173
  }
2160
2174
  /** The world (made on first use, at the canvas size). */
@@ -2193,13 +2207,13 @@ var PaintWetLayers = (_class6 = class {
2193
2207
  if (!this.canExtend(left, top)) throw new Error("Wet paint only moves by whole 256 px tiles, between strokes.");
2194
2208
  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 } } });
2195
2209
  const old = this.world;
2196
- const snap = _optionalChain([old, 'optionalAccess', _95 => _95.laneIds, 'call', _96 => _96(), 'access', _97 => _97.length]) ? old.snapshot() : null;
2210
+ const snap = _optionalChain([old, 'optionalAccess', _99 => _99.laneIds, 'call', _100 => _100(), 'access', _101 => _101.length]) ? old.snapshot() : null;
2197
2211
  this.dropWorld();
2198
2212
  this.lastTick = null;
2199
2213
  this.stepsOwed = 0;
2200
2214
  if (!old || !snap) return;
2201
2215
  const moved = _chunkXFYLA3ZOcjs.moveWetSnapshot.call(void 0, snap, old, { width, height }, left, top, (l) => {
2202
- const flow = _optionalChain([this, 'access', _98 => _98.settings, 'access', _99 => _99.get, 'call', _100 => _100(l.id), 'optionalAccess', _101 => _101.flow]);
2216
+ const flow = _optionalChain([this, 'access', _102 => _102.settings, 'access', _103 => _103.get, 'call', _104 => _104(l.id), 'optionalAccess', _105 => _105.flow]);
2203
2217
  return {
2204
2218
  base: _chunk474IQG74cjs.translateSurface.call(void 0, l.base, left, top),
2205
2219
  flow: l.flow && flow && flow.kind !== "none" ? _chunkXFYLA3ZOcjs.flowField.call(void 0, flow, width, height) : l.flow
@@ -2217,11 +2231,11 @@ var PaintWetLayers = (_class6 = class {
2217
2231
  }
2218
2232
  /** Layers holding a wet layer (wet or drying). */
2219
2233
  wetLayerIds() {
2220
- return _nullishCoalesce(_optionalChain([this, 'access', _102 => _102.world, 'optionalAccess', _103 => _103.laneIds, 'call', _104 => _104()]), () => ( []));
2234
+ return _nullishCoalesce(_optionalChain([this, 'access', _106 => _106.world, 'optionalAccess', _107 => _107.laneIds, 'call', _108 => _108()]), () => ( []));
2221
2235
  }
2222
2236
  /** Whether a batch is running (edits wait). */
2223
2237
  get busy() {
2224
- return Boolean(_optionalChain([this, 'access', _105 => _105.world, 'optionalAccess', _106 => _106.busy]));
2238
+ return Boolean(_optionalChain([this, 'access', _109 => _109.world, 'optionalAccess', _110 => _110.busy]));
2225
2239
  }
2226
2240
  /** Resolves when no batch is running. */
2227
2241
  async idle() {
@@ -2250,13 +2264,13 @@ var PaintWetLayers = (_class6 = class {
2250
2264
  setParams(layerId, update) {
2251
2265
  const s = this.settingsOf(layerId);
2252
2266
  s.params = _chunkXFYLA3ZOcjs.normalizeWetParams.call(void 0, update, s.params);
2253
- if (_optionalChain([this, 'access', _107 => _107.world, 'optionalAccess', _108 => _108.hasLane, 'call', _109 => _109(layerId)])) this.world.setParams(layerId, s.params);
2267
+ if (_optionalChain([this, 'access', _111 => _111.world, 'optionalAccess', _112 => _112.hasLane, 'call', _113 => _113(layerId)])) this.world.setParams(layerId, s.params);
2254
2268
  return { ...s.params };
2255
2269
  }
2256
2270
  setFlow(layerId, update) {
2257
2271
  const s = this.settingsOf(layerId);
2258
2272
  s.flow = _chunkXFYLA3ZOcjs.normalizeFlow.call(void 0, update, s.flow);
2259
- if (_optionalChain([this, 'access', _110 => _110.world, 'optionalAccess', _111 => _111.hasLane, 'call', _112 => _112(layerId)])) {
2273
+ if (_optionalChain([this, 'access', _114 => _114.world, 'optionalAccess', _115 => _115.hasLane, 'call', _116 => _116(layerId)])) {
2260
2274
  const { width, height } = this.host.canvas();
2261
2275
  this.world.setFlow(layerId, _chunkXFYLA3ZOcjs.flowField.call(void 0, s.flow, width, height), s.flow.strength);
2262
2276
  }
@@ -2264,29 +2278,29 @@ var PaintWetLayers = (_class6 = class {
2264
2278
  }
2265
2279
  setTilt(update) {
2266
2280
  this.tilt = _chunkXFYLA3ZOcjs.normalizeTilt.call(void 0, update, this.tilt);
2267
- _optionalChain([this, 'access', _113 => _113.world, 'optionalAccess', _114 => _114.setTilt, 'call', _115 => _115(this.tilt)]);
2281
+ _optionalChain([this, 'access', _117 => _117.world, 'optionalAccess', _118 => _118.setTilt, 'call', _119 => _119(this.tilt)]);
2268
2282
  return { ...this.tilt };
2269
2283
  }
2270
2284
  /** The paper changed. */
2271
2285
  paperChanged() {
2272
- _optionalChain([this, 'access', _116 => _116.world, 'optionalAccess', _117 => _117.setPaper, 'call', _118 => _118(wetPaperInput(this.host.paper()))]);
2286
+ _optionalChain([this, 'access', _120 => _120.world, 'optionalAccess', _121 => _121.setPaper, 'call', _122 => _122(wetPaperInput(this.host.paper()))]);
2273
2287
  }
2274
2288
  /** A layer as tools describe it. */
2275
2289
  info(layerId) {
2276
2290
  const s = this.settingsOf(layerId);
2277
- const st = _optionalChain([this, 'access', _119 => _119.world, 'optionalAccess', _120 => _120.hasLane, 'call', _121 => _121(layerId)]) ? this.world.stats(layerId) : null;
2291
+ const st = _optionalChain([this, 'access', _123 => _123.world, 'optionalAccess', _124 => _124.hasLane, 'call', _125 => _125(layerId)]) ? this.world.stats(layerId) : null;
2278
2292
  return {
2279
2293
  layerId,
2280
2294
  wet: Boolean(st && st.wetCells > 0),
2281
- wetCells: _nullishCoalesce(_optionalChain([st, 'optionalAccess', _122 => _122.wetCells]), () => ( 0)),
2282
- wetBounds: _nullishCoalesce(_optionalChain([st, 'optionalAccess', _123 => _123.wetBounds]), () => ( null)),
2283
- activeTiles: _nullishCoalesce(_optionalChain([st, 'optionalAccess', _124 => _124.activeTiles]), () => ( 0)),
2295
+ wetCells: _nullishCoalesce(_optionalChain([st, 'optionalAccess', _126 => _126.wetCells]), () => ( 0)),
2296
+ wetBounds: _nullishCoalesce(_optionalChain([st, 'optionalAccess', _127 => _127.wetBounds]), () => ( null)),
2297
+ activeTiles: _nullishCoalesce(_optionalChain([st, 'optionalAccess', _128 => _128.activeTiles]), () => ( 0)),
2284
2298
  params: { ...s.params },
2285
2299
  flow: { ...s.flow }
2286
2300
  };
2287
2301
  }
2288
2302
  backend() {
2289
- return _nullishCoalesce(_optionalChain([this, 'access', _125 => _125.world, 'optionalAccess', _126 => _126.backend, 'call', _127 => _127()]), () => ( null));
2303
+ return _nullishCoalesce(_optionalChain([this, 'access', _129 => _129.world, 'optionalAccess', _130 => _130.backend, 'call', _131 => _131()]), () => ( null));
2290
2304
  }
2291
2305
  /** Shows the current wet pixels (at most `maxTiles` reshaded per layer). */
2292
2306
  syncDisplays(maxTiles = Infinity) {
@@ -2322,7 +2336,7 @@ var PaintWetLayers = (_class6 = class {
2322
2336
  const w = this.world;
2323
2337
  if (!w) return;
2324
2338
  for (const id of w.laneIds()) {
2325
- if (w.isActive(id) || _optionalChain([this, 'access', _128 => _128.driver, 'optionalAccess', _129 => _129.init, 'access', _130 => _130.laneId]) === id) continue;
2339
+ if (w.isActive(id) || _optionalChain([this, 'access', _132 => _132.driver, 'optionalAccess', _133 => _133.init, 'access', _134 => _134.laneId]) === id) continue;
2326
2340
  const base = w.getBase(id);
2327
2341
  w.removeLane(id);
2328
2342
  this.host.updateSurfaces(/* @__PURE__ */ new Map([[id, base]]), []);
@@ -2402,7 +2416,7 @@ var PaintWetLayers = (_class6 = class {
2402
2416
  if (!d || !this.world) return;
2403
2417
  const rects = d.flush();
2404
2418
  if (rects.length) this.syncDisplays(DISPLAY_TILES_PER_TICK);
2405
- if (d.done) _optionalChain([this, 'access', _131 => _131.onDriverDone, 'optionalCall', _132 => _132(d)]);
2419
+ if (d.done) _optionalChain([this, 'access', _135 => _135.onDriverDone, 'optionalCall', _136 => _136(d)]);
2406
2420
  }
2407
2421
  /** Called when a live stroke that ended mid-batch has finished applying. */
2408
2422
  __init62() {this.onDriverDone = null}
@@ -2446,7 +2460,7 @@ var PaintWetLayers = (_class6 = class {
2446
2460
  /** The layer's pixels with all its wet paint dried (deterministic), without changing anything. */
2447
2461
  bakedSurface(layerId) {
2448
2462
  const w = this.world;
2449
- if (!_optionalChain([w, 'optionalAccess', _133 => _133.hasLane, 'call', _134 => _134(layerId)])) return null;
2463
+ if (!_optionalChain([w, 'optionalAccess', _137 => _137.hasLane, 'call', _138 => _138(layerId)])) return null;
2450
2464
  return w.bakedSurface(layerId);
2451
2465
  }
2452
2466
  /** A snapshot of the world for undo (`null` when there is none). */
@@ -2467,13 +2481,13 @@ var PaintWetLayers = (_class6 = class {
2467
2481
  this.syncDisplays();
2468
2482
  }
2469
2483
  dropWorld() {
2470
- _optionalChain([this, 'access', _135 => _135.world, 'optionalAccess', _136 => _136.destroy, 'call', _137 => _137()]);
2484
+ _optionalChain([this, 'access', _139 => _139.world, 'optionalAccess', _140 => _140.destroy, 'call', _141 => _141()]);
2471
2485
  this.world = null;
2472
2486
  this.driver = null;
2473
2487
  }
2474
2488
  /** Forgets everything wet (a new canvas, a resize, opening a document). */
2475
2489
  reset() {
2476
- _optionalChain([this, 'access', _138 => _138.world, 'optionalAccess', _139 => _139.destroy, 'call', _140 => _140()]);
2490
+ _optionalChain([this, 'access', _142 => _142.world, 'optionalAccess', _143 => _143.destroy, 'call', _144 => _144()]);
2477
2491
  this.world = null;
2478
2492
  this.driver = null;
2479
2493
  this.settings.clear();
@@ -2503,14 +2517,14 @@ var PaintWetLayers = (_class6 = class {
2503
2517
  return out;
2504
2518
  }
2505
2519
  destroy() {
2506
- _optionalChain([this, 'access', _141 => _141.world, 'optionalAccess', _142 => _142.destroy, 'call', _143 => _143()]);
2520
+ _optionalChain([this, 'access', _145 => _145.world, 'optionalAccess', _146 => _146.destroy, 'call', _147 => _147()]);
2507
2521
  this.world = null;
2508
- _optionalChain([this, 'access', _144 => _144.gpu, 'optionalAccess', _145 => _145.destroy, 'call', _146 => _146()]);
2522
+ _optionalChain([this, 'access', _148 => _148.gpu, 'optionalAccess', _149 => _149.destroy, 'call', _150 => _150()]);
2509
2523
  this.gpu = null;
2510
2524
  }
2511
2525
  }, _class6);
2512
2526
  function wetPigmentOf(hex, body) {
2513
- const [r, g, b] = _chunkROVK6AXXcjs.hexToRgb8.call(void 0, hex);
2527
+ const [r, g, b] = _chunkGNZI3KYKcjs.hexToRgb8.call(void 0, hex);
2514
2528
  return Array.from(_chunkXFYLA3ZOcjs.pigmentOf.call(void 0, [r / 255, g / 255, b / 255], body));
2515
2529
  }
2516
2530
 
@@ -2518,13 +2532,13 @@ function wetPigmentOf(hex, body) {
2518
2532
  var thumbWorld = null;
2519
2533
  function paintWetTestStroke(brush, paper, color, width, height) {
2520
2534
  if (!thumbWorld || thumbWorld.width !== width || thumbWorld.height !== height) {
2521
- _optionalChain([thumbWorld, 'optionalAccess', _147 => _147.destroy, 'call', _148 => _148()]);
2535
+ _optionalChain([thumbWorld, 'optionalAccess', _151 => _151.destroy, 'call', _152 => _152()]);
2522
2536
  thumbWorld = new (0, _chunkXFYLA3ZOcjs.WetWorld)(width, height, wetPaperInput(paper), { kernel: "typescript", threads: 0 });
2523
2537
  } else thumbWorld.setPaper(wetPaperInput(paper));
2524
2538
  const w = thumbWorld;
2525
2539
  if (w.hasLane("thumb")) w.removeLane("thumb");
2526
2540
  w.ensureLane("thumb");
2527
- const [r, g, b] = _chunkROVK6AXXcjs.hexToRgb8.call(void 0, color);
2541
+ const [r, g, b] = _chunkGNZI3KYKcjs.hexToRgb8.call(void 0, color);
2528
2542
  if (brush.wet.tool !== "paint" && brush.wet.tool !== "water") {
2529
2543
  const half = Math.ceil(height / 2);
2530
2544
  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));
@@ -2538,9 +2552,9 @@ function paintWetTestStroke(brush, paper, color, width, height) {
2538
2552
  load: brushLoadForStroke(brush, _chunkPQ3H2AANcjs.EMPTY_MIXER_LOAD, [r / 255, g / 255, b / 255]),
2539
2553
  grain: paperGrain(paper),
2540
2554
  paperDepth: paper.depth,
2541
- paperColor: _chunkROVK6AXXcjs.hexToRgb8.call(void 0, paper.color),
2555
+ paperColor: _chunkGNZI3KYKcjs.hexToRgb8.call(void 0, paper.color),
2542
2556
  seed: 7,
2543
- copies: [_chunkROVK6AXXcjs.IDENTITY_COPY]
2557
+ copies: [_chunkGNZI3KYKcjs.IDENTITY_COPY]
2544
2558
  });
2545
2559
  driver.push(thumbnailStroke(width, height));
2546
2560
  driver.finish();
@@ -2560,7 +2574,7 @@ function thumbnailStroke(width, height) {
2560
2574
  return pts;
2561
2575
  }
2562
2576
  function paintTestStroke(surface, brush, paper, color, width, height) {
2563
- const [r, g, b] = _chunkROVK6AXXcjs.hexToRgb8.call(void 0, color);
2577
+ const [r, g, b] = _chunkGNZI3KYKcjs.hexToRgb8.call(void 0, color);
2564
2578
  let result = surface;
2565
2579
  let thick = null;
2566
2580
  const session = new PaintStrokeSession(
@@ -2579,13 +2593,13 @@ function paintTestStroke(surface, brush, paper, color, width, height) {
2579
2593
  lockTransparency: false,
2580
2594
  brush,
2581
2595
  color: [r, g, b, 255],
2582
- background: [..._chunkROVK6AXXcjs.hexToRgb8.call(void 0, paper.color), 255],
2596
+ background: [..._chunkGNZI3KYKcjs.hexToRgb8.call(void 0, paper.color), 255],
2583
2597
  grain: paperGrain(paper),
2584
2598
  paperDepth: paper.depth,
2585
2599
  seed: 7,
2586
2600
  colorHex: color,
2587
2601
  affineCopies: [],
2588
- copies: [_chunkROVK6AXXcjs.IDENTITY_COPY],
2602
+ copies: [_chunkGNZI3KYKcjs.IDENTITY_COPY],
2589
2603
  mixerLoad: brushLoadForStroke(brush, _chunkPQ3H2AANcjs.EMPTY_MIXER_LOAD, [r / 255, g / 255, b / 255]),
2590
2604
  thick: brush.engine === "impasto" ? { channels: emptyThickChannels() } : void 0,
2591
2605
  sticker: brush.engine === "sticker" ? { nextId: 1 } : void 0
@@ -2599,8 +2613,8 @@ function renderBrushThumbnail(brush, options) {
2599
2613
  const width = Math.max(16, Math.min(512, Math.round(_nullishCoalesce(options.width, () => ( 160)))));
2600
2614
  const height = Math.max(16, Math.min(512, Math.round(_nullishCoalesce(options.height, () => ( 48)))));
2601
2615
  const maxSize = height * 0.42;
2602
- const b = brush.tip.size > maxSize ? _chunkROVK6AXXcjs.normalizePaintBrush.call(void 0, { tip: { ...brush.tip, size: maxSize } }, brush) : brush;
2603
- const rgba = [..._chunkROVK6AXXcjs.hexToRgb8.call(void 0, options.color), 255];
2616
+ const b = brush.tip.size > maxSize ? _chunkGNZI3KYKcjs.normalizePaintBrush.call(void 0, { tip: { ...brush.tip, size: maxSize } }, brush) : brush;
2617
+ const rgba = [..._chunkGNZI3KYKcjs.hexToRgb8.call(void 0, options.color), 255];
2604
2618
  let surface = _chunk474IQG74cjs.emptySurface.call(void 0, 4);
2605
2619
  if (b.engine === "eraser") {
2606
2620
  surface = _chunk474IQG74cjs.fillRect.call(void 0, surface, { x: 0, y: 0, width, height }, rgba);
@@ -2853,11 +2867,11 @@ function readSwatch(raw) {
2853
2867
  if (!raw || typeof raw !== "object") return null;
2854
2868
  const r = raw;
2855
2869
  const g = _chunkPQ3H2AANcjs.readPaintSource.call(void 0, r.paint);
2856
- const color = typeof r.color === "string" && /^#[0-9a-f]{6}$/i.test(r.color) ? r.color.toLowerCase() : _optionalChain([g, 'optionalAccess', _149 => _149.type]) === "gradient" ? _chunkPQ3H2AANcjs.paintSourceColor.call(void 0, g) : null;
2870
+ 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;
2857
2871
  if (!color) return null;
2858
2872
  const out = { color };
2859
2873
  if (typeof r.name === "string" && r.name.trim()) out.name = r.name.trim().slice(0, 80);
2860
- if (_optionalChain([g, 'optionalAccess', _150 => _150.type]) === "gradient") out.paint = g;
2874
+ if (_optionalChain([g, 'optionalAccess', _154 => _154.type]) === "gradient") out.paint = g;
2861
2875
  return out;
2862
2876
  }
2863
2877
  var DEFAULT_SWATCHES = [
@@ -2876,7 +2890,7 @@ var DEFAULT_SWATCHES = [
2876
2890
  // src/paint-editor/mixing-pad.ts
2877
2891
  var MIXING_PAD_WIDTH = 360;
2878
2892
  var MIXING_PAD_HEIGHT = 220;
2879
- var PAD_PAINT = _chunkROVK6AXXcjs.normalizePaintBrush.call(void 0, {
2893
+ var PAD_PAINT = _chunkGNZI3KYKcjs.normalizePaintBrush.call(void 0, {
2880
2894
  id: "pad-paint",
2881
2895
  name: "Pad paint",
2882
2896
  category: "mixer",
@@ -2884,7 +2898,7 @@ var PAD_PAINT = _chunkROVK6AXXcjs.normalizePaintBrush.call(void 0, {
2884
2898
  tip: { size: 28, hardness: 0.75, spacing: 0.1, opacity: 1, flow: 0.7, pressureSize: false, pressureOpacity: false },
2885
2899
  mixer: { wet: 0.45, load: 1, mix: 0.4, loadEachStroke: true, cleanEachStroke: true, mixing: "pigment" }
2886
2900
  });
2887
- var PAD_KNIFE = _chunkROVK6AXXcjs.normalizePaintBrush.call(void 0, {
2901
+ var PAD_KNIFE = _chunkGNZI3KYKcjs.normalizePaintBrush.call(void 0, {
2888
2902
  id: "pad-knife",
2889
2903
  name: "Palette knife",
2890
2904
  category: "smudge",
@@ -2894,7 +2908,7 @@ var PAD_KNIFE = _chunkROVK6AXXcjs.normalizePaintBrush.call(void 0, {
2894
2908
  // A knife drags streaks of paint and folds them into each other, mixing them as pigment.
2895
2909
  smudge: { strength: 0.6, length: 0.8, mixing: "pigment" }
2896
2910
  });
2897
- var PAD_BLOB = _chunkROVK6AXXcjs.normalizePaintBrush.call(void 0, {
2911
+ var PAD_BLOB = _chunkGNZI3KYKcjs.normalizePaintBrush.call(void 0, {
2898
2912
  id: "pad-blob",
2899
2913
  name: "Pad blob",
2900
2914
  category: "custom",
@@ -2916,12 +2930,12 @@ var MixingPad = (_class8 = class {constructor() { _class8.prototype.__init65.cal
2916
2930
  }
2917
2931
  }
2918
2932
  let brush = options.tool === "knife" ? PAD_KNIFE : PAD_PAINT;
2919
- if (options.size !== void 0) brush = _chunkROVK6AXXcjs.normalizePaintBrush.call(void 0, { tip: { ...brush.tip, size: options.size } }, brush);
2933
+ if (options.size !== void 0) brush = _chunkGNZI3KYKcjs.normalizePaintBrush.call(void 0, { tip: { ...brush.tip, size: options.size } }, brush);
2920
2934
  return this.run(brush, points, options.color);
2921
2935
  }
2922
2936
  /** Paints `points` with `brush` in `color` on the pad. */
2923
2937
  run(brush, points, color) {
2924
- const [r, g, b] = _chunkROVK6AXXcjs.hexToRgb8.call(void 0, color);
2938
+ const [r, g, b] = _chunkGNZI3KYKcjs.hexToRgb8.call(void 0, color);
2925
2939
  let result = null;
2926
2940
  const session = new PaintStrokeSession(
2927
2941
  { update: () => {
@@ -2939,7 +2953,7 @@ var MixingPad = (_class8 = class {constructor() { _class8.prototype.__init65.cal
2939
2953
  seed: 1,
2940
2954
  colorHex: color,
2941
2955
  affineCopies: [],
2942
- copies: [_chunkROVK6AXXcjs.IDENTITY_COPY],
2956
+ copies: [_chunkGNZI3KYKcjs.IDENTITY_COPY],
2943
2957
  mixerLoad: brushLoadForStroke(brush, _chunkPQ3H2AANcjs.EMPTY_MIXER_LOAD, [r / 255, g / 255, b / 255])
2944
2958
  }
2945
2959
  );
@@ -3015,10 +3029,10 @@ var MixingPad = (_class8 = class {constructor() { _class8.prototype.__init65.cal
3015
3029
  const off = used.length === 1 ? 0 : 0.45 * R;
3016
3030
  const x = Math.min(cx + R - r, Math.max(cx - R + r, cx + Math.cos(a) * off));
3017
3031
  const y = Math.min(cy + R - r, Math.max(cy - R + r, cy + Math.sin(a) * off));
3018
- const blob = _chunkROVK6AXXcjs.normalizePaintBrush.call(void 0, { tip: { ...PAD_BLOB.tip, size: Math.max(2, 2 * r) } }, PAD_BLOB);
3032
+ const blob = _chunkGNZI3KYKcjs.normalizePaintBrush.call(void 0, { tip: { ...PAD_BLOB.tip, size: Math.max(2, 2 * r) } }, PAD_BLOB);
3019
3033
  this.run(blob, [{ x, y }], p.color.toLowerCase());
3020
3034
  });
3021
- const knife = _chunkROVK6AXXcjs.normalizePaintBrush.call(void 0, { tip: { ...PAD_KNIFE.tip, size: Math.max(12, R * 0.5) } }, PAD_KNIFE);
3035
+ const knife = _chunkGNZI3KYKcjs.normalizePaintBrush.call(void 0, { tip: { ...PAD_KNIFE.tip, size: Math.max(12, R * 0.5) } }, PAD_KNIFE);
3022
3036
  for (let k = 0; k < passes; k++) {
3023
3037
  const stir = [];
3024
3038
  const turns = 1.6;
@@ -3030,10 +3044,10 @@ var MixingPad = (_class8 = class {constructor() { _class8.prototype.__init65.cal
3030
3044
  this.run(knife, stir, "#000000");
3031
3045
  }
3032
3046
  const mixed = _chunkOLNIPTB3cjs.mixPigments.call(void 0,
3033
- paints.map((p) => _chunkROVK6AXXcjs.hexToRgb8.call(void 0, p.color).map((v) => v / 255)),
3047
+ paints.map((p) => _chunkGNZI3KYKcjs.hexToRgb8.call(void 0, p.color).map((v) => v / 255)),
3034
3048
  paints.map((p) => p.parts)
3035
3049
  );
3036
- const core = _chunkROVK6AXXcjs.normalizePaintBrush.call(void 0, { tip: { ...PAD_BLOB.tip, size: R * 1.1, hardness: 0.55 } }, PAD_BLOB);
3050
+ const core = _chunkGNZI3KYKcjs.normalizePaintBrush.call(void 0, { tip: { ...PAD_BLOB.tip, size: R * 1.1, hardness: 0.55 } }, PAD_BLOB);
3037
3051
  const hex = "#" + mixed.map((v) => Math.round(v * 255).toString(16).padStart(2, "0")).join("");
3038
3052
  this.run(core, [{ x: cx, y: cy }], hex);
3039
3053
  return { color: this.pick(cx, cy, 2), bounds };
@@ -3044,7 +3058,7 @@ var MixingPad = (_class8 = class {constructor() { _class8.prototype.__init65.cal
3044
3058
  }
3045
3059
  /** Replaces the pad with a PNG (data URL or base64) of the pad's size, as `toPng` writes. */
3046
3060
  fromPng(png) {
3047
- const bytes = png.startsWith("data:") ? _optionalChain([_chunkOLNIPTB3cjs.parseDataUrl.call(void 0, png), 'optionalAccess', _151 => _151.bytes]) : _chunkOLNIPTB3cjs.base64ToBytes.call(void 0, png);
3061
+ const bytes = png.startsWith("data:") ? _optionalChain([_chunkOLNIPTB3cjs.parseDataUrl.call(void 0, png), 'optionalAccess', _155 => _155.bytes]) : _chunkOLNIPTB3cjs.base64ToBytes.call(void 0, png);
3048
3062
  if (!bytes || !_chunkOLNIPTB3cjs.isPng.call(void 0, bytes)) throw new Error("The pad image is not a PNG data URL or base64 PNG.");
3049
3063
  const img = _chunkOLNIPTB3cjs.decodePng.call(void 0, bytes);
3050
3064
  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}.`);
@@ -3091,6 +3105,7 @@ async function replayPainting(source, target, options = {}) {
3091
3105
  const maxStrokes = _nullishCoalesce(options.strokes, () => ( source.strokes.length));
3092
3106
  const chunk = Math.max(1, _nullishCoalesce(options.wetChunk, () => ( 0))) || Infinity;
3093
3107
  let strokes = 0;
3108
+ await target.prepareEffectPaints(source.strokes.slice(0, maxStrokes).flatMap((st) => _optionalChain([st, 'access', _156 => _156.paint, 'optionalAccess', _157 => _157.type]) === "effect" ? [st.paint] : []));
3094
3109
  const advanceTo = async (clock) => {
3095
3110
  const now = target.getState().wet.clock;
3096
3111
  let left = clock - now;
@@ -3098,7 +3113,7 @@ async function replayPainting(source, target, options = {}) {
3098
3113
  const n = Math.min(left, chunk);
3099
3114
  await target.advanceWet({ steps: n });
3100
3115
  left -= n;
3101
- if (Number.isFinite(chunk)) await _optionalChain([options, 'access', _152 => _152.onWetSteps, 'optionalCall', _153 => _153(target.getState().wet.clock)]);
3116
+ if (Number.isFinite(chunk)) await _optionalChain([options, 'access', _158 => _158.onWetSteps, 'optionalCall', _159 => _159(target.getState().wet.clock)]);
3102
3117
  }
3103
3118
  };
3104
3119
  const sr = (r) => ({ x: r.x * s, y: r.y * s, width: r.width * s, height: r.height * s });
@@ -3110,7 +3125,7 @@ async function replayPainting(source, target, options = {}) {
3110
3125
  if (e.kind === "fill") target.fillLayer({ layerId: e.layerId, ...e.data });
3111
3126
  else if (e.kind === "clear") target.clearLayer(e.layerId);
3112
3127
  else if (e.kind === "stickers") {
3113
- const list = (_nullishCoalesce(_optionalChain([e, 'access', _154 => _154.data, 'optionalAccess', _155 => _155.stickers]), () => ( []))).map((x) => s === 1 ? x : { ...x, x: x.x * s, y: x.y * s, size: x.size * s });
3128
+ const list = (_nullishCoalesce(_optionalChain([e, 'access', _160 => _160.data, 'optionalAccess', _161 => _161.stickers]), () => ( []))).map((x) => s === 1 ? x : { ...x, x: x.x * s, y: x.y * s, size: x.size * s });
3114
3129
  target.replaceStickers(e.layerId, list);
3115
3130
  } else target.flattenRelief(e.layerId);
3116
3131
  continue;
@@ -3123,8 +3138,8 @@ async function replayPainting(source, target, options = {}) {
3123
3138
  switch (e.kind) {
3124
3139
  case "dry": {
3125
3140
  const rect = e.data;
3126
- const ids = _optionalChain([e, 'access', _156 => _156.layerId, 'optionalAccess', _157 => _157.split, 'call', _158 => _158(","), 'access', _159 => _159.filter, 'call', _160 => _160(Boolean)]);
3127
- if (_optionalChain([ids, 'optionalAccess', _161 => _161.length])) for (const id of ids) target.dryPaint({ layerId: id, rect: rect ? sr(rect) : void 0 });
3141
+ const ids = _optionalChain([e, 'access', _162 => _162.layerId, 'optionalAccess', _163 => _163.split, 'call', _164 => _164(","), 'access', _165 => _165.filter, 'call', _166 => _166(Boolean)]);
3142
+ if (_optionalChain([ids, 'optionalAccess', _167 => _167.length])) for (const id of ids) target.dryPaint({ layerId: id, rect: rect ? sr(rect) : void 0 });
3128
3143
  else target.dryPaint({ rect: rect ? sr(rect) : void 0 });
3129
3144
  break;
3130
3145
  }
@@ -3155,7 +3170,7 @@ async function replayPainting(source, target, options = {}) {
3155
3170
  strokes++;
3156
3171
  if (!target.getLayer(st.layerId)) continue;
3157
3172
  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)) };
3158
- if (st.brush.engine === "wet" && _optionalChain([st, 'access', _162 => _162.steps, 'optionalAccess', _163 => _163.length]) === st.points.length) {
3173
+ if (st.brush.engine === "wet" && _optionalChain([st, 'access', _168 => _168.steps, 'optionalAccess', _169 => _169.length]) === st.points.length) {
3159
3174
  await target.wetIdle();
3160
3175
  await advanceTo(st.steps[0]);
3161
3176
  const session = target.beginStroke({ ...init, start: st.points[0] });
@@ -3175,7 +3190,7 @@ async function replayPainting(source, target, options = {}) {
3175
3190
  await target.wetIdle();
3176
3191
  target.paintStroke({ ...init, points: st.points });
3177
3192
  }
3178
- await _optionalChain([options, 'access', _164 => _164.onStroke, 'optionalCall', _165 => _165(strokes)]);
3193
+ await _optionalChain([options, 'access', _170 => _170.onStroke, 'optionalCall', _171 => _171(strokes)]);
3179
3194
  }
3180
3195
  void IDENTITY_AFFINE;
3181
3196
  }
@@ -3220,7 +3235,7 @@ async function buildTimeLapse(source, target, options = {}) {
3220
3235
  wetChunk: wetEvery > 0 ? wetEvery : 0,
3221
3236
  onStroke: (i) => {
3222
3237
  if (i % perFrame === 0 || i === total) shoot(i);
3223
- _optionalChain([options, 'access', _166 => _166.onProgress, 'optionalCall', _167 => _167(total ? i / total : 1)]);
3238
+ _optionalChain([options, 'access', _172 => _172.onProgress, 'optionalCall', _173 => _173(total ? i / total : 1)]);
3224
3239
  },
3225
3240
  onWetSteps: wetEvery > 0 ? () => shoot(-1) : void 0
3226
3241
  });
@@ -3262,19 +3277,23 @@ var PAINT_EFFECT_PLACES = {
3262
3277
  /** An effect fill: composited onto a layer's pixels. */
3263
3278
  fill: ["generator", "overlay", "title"],
3264
3279
  /** Light (or any filter) on a layer's dried paint. */
3265
- light: ["filter"]
3280
+ light: ["filter"],
3281
+ /** Effect paint: brushes take each pixel's colour from it. */
3282
+ paint: ["generator", "overlay", "title"]
3266
3283
  };
3267
3284
  var PLACE_WORDS = {
3268
3285
  paper: "effect paper takes generator effects",
3269
3286
  layer: "an effect layer takes generator, overlay or title effects",
3270
3287
  fill: "an effect fill takes generator, overlay or title effects",
3271
- light: "light on dried paint takes filter effects"
3288
+ light: "light on dried paint takes filter effects",
3289
+ paint: "effect paint takes generator, overlay or title effects"
3272
3290
  };
3273
3291
  function checkPaintEffectPlace(d, place) {
3274
3292
  const allowed = PAINT_EFFECT_PLACES[place];
3275
3293
  if (d.kind !== "motion" && d.kind !== "vector" && d.uses.some((u) => allowed.includes(u))) return;
3276
3294
  let instead = "";
3277
- if (d.uses.includes("filter") && place !== "light") instead = "; run it on a layer's dried paint with apply_effect instead";
3295
+ if (d.uses.includes("filter") && place === "paint") instead = "; paint with a generator, overlay or title effect, or run the filter on the painted layer with apply_effect";
3296
+ else if (d.uses.includes("filter") && place !== "light") instead = "; run it on a layer's dried paint with apply_effect instead";
3278
3297
  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";
3279
3298
  else if (place === "paper" && d.uses.some((u) => u === "overlay" || u === "title")) instead = "; add it as an effect layer with add_effect_layer instead";
3280
3299
  throw new (0, _chunkABQ2VGUBcjs.EffectUnsupportedError)(`"${d.id}" (${d.name}) is a ${d.uses.join(" / ") || d.kind} effect, and ${PLACE_WORDS[place]}${instead}.`, d.id);
@@ -3390,7 +3409,7 @@ function parseColor(value, what = "color") {
3390
3409
  return value.trim().toLowerCase();
3391
3410
  }
3392
3411
  function rgbaOf(hex) {
3393
- const [r, g, b] = _chunkROVK6AXXcjs.hexToRgb8.call(void 0, hex);
3412
+ const [r, g, b] = _chunkGNZI3KYKcjs.hexToRgb8.call(void 0, hex);
3394
3413
  return [r, g, b, 255];
3395
3414
  }
3396
3415
  function rgbToHex(r, g, b) {
@@ -3403,7 +3422,7 @@ function unionRect(a, b) {
3403
3422
  const y = Math.min(a.y, b.y);
3404
3423
  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 };
3405
3424
  }
3406
- var isPixelLayer = (l) => _optionalChain([l, 'optionalAccess', _168 => _168.type]) === "pixel";
3425
+ var isPixelLayer = (l) => _optionalChain([l, 'optionalAccess', _174 => _174.type]) === "pixel";
3407
3426
  var PaintEditorController = (_class10 = class _PaintEditorController {
3408
3427
 
3409
3428
  __init72() {this.extensions = {}}
@@ -3418,50 +3437,57 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3418
3437
  __init76() {this.secondaryColor = "#ffffff"}
3419
3438
  /** Gradient paint chosen with `setPaint` (`null`: the paint colour). */
3420
3439
  __init77() {this.gradient = null}
3421
- __init78() {this.mixerLoad = _chunkPQ3H2AANcjs.EMPTY_MIXER_LOAD}
3422
- __init79() {this.view = { ...DEFAULT_VIEW, pan: { ...DEFAULT_VIEW.pan } }}
3440
+ /** Effect paint chosen with `setEffectPaint` (rendered), and one still rendering. */
3441
+ __init78() {this.effectPaint = null}
3442
+ __init79() {this.effectPaintPending = null}
3443
+ /** Changes whenever the paint is chosen, so an effect paint that finishes rendering late does not take over. */
3444
+ __init80() {this.paintEpoch = 0}
3445
+ /** Rendered effect paints by `effectPaintKey` (most recently used last). */
3446
+ __init81() {this.effectPaintPixels = /* @__PURE__ */ new Map()}
3447
+ __init82() {this.mixerLoad = _chunkPQ3H2AANcjs.EMPTY_MIXER_LOAD}
3448
+ __init83() {this.view = { ...DEFAULT_VIEW, pan: { ...DEFAULT_VIEW.pan } }}
3423
3449
 
3424
3450
 
3425
- __init80() {this.listeners = /* @__PURE__ */ new Set()}
3426
- __init81() {this.version = 0}
3427
- __init82() {this.cached = null}
3428
- __init83() {this.session = null}
3429
- __init84() {this.live = null}
3430
- __init85() {this.liveLayers = null}
3431
- __init86() {this.dirty = "all"}
3432
- __init87() {this.seedCounter = 1}
3433
- __init88() {this.strokeCounter = 1}
3451
+ __init84() {this.listeners = /* @__PURE__ */ new Set()}
3452
+ __init85() {this.version = 0}
3453
+ __init86() {this.cached = null}
3454
+ __init87() {this.session = null}
3455
+ __init88() {this.live = null}
3456
+ __init89() {this.liveLayers = null}
3457
+ __init90() {this.dirty = "all"}
3458
+ __init91() {this.seedCounter = 1}
3459
+ __init92() {this.strokeCounter = 1}
3434
3460
 
3435
- __init89() {this.swatches = DEFAULT_SWATCHES.map((s) => ({ ...s }))}
3436
- __init90() {this.pad = new MixingPad()}
3437
- __init91() {this.savedPads = []}
3438
- __init92() {this.nextPadId = 1}
3439
- __init93() {this.tracingVersion = 1}
3440
- __init94() {this.tracingCache = null}
3441
- __init95() {this.imagePixels = /* @__PURE__ */ new Map()}
3442
- __init96() {this.nextReferenceId = 1}
3443
- __init97() {this.viewCompositor = createPaintCompositor()}
3444
- __init98() {this.exportCompositor = createPaintCompositor()}
3461
+ __init93() {this.swatches = DEFAULT_SWATCHES.map((s) => ({ ...s }))}
3462
+ __init94() {this.pad = new MixingPad()}
3463
+ __init95() {this.savedPads = []}
3464
+ __init96() {this.nextPadId = 1}
3465
+ __init97() {this.tracingVersion = 1}
3466
+ __init98() {this.tracingCache = null}
3467
+ __init99() {this.imagePixels = /* @__PURE__ */ new Map()}
3468
+ __init100() {this.nextReferenceId = 1}
3469
+ __init101() {this.viewCompositor = createPaintCompositor()}
3470
+ __init102() {this.exportCompositor = createPaintCompositor()}
3445
3471
  /** Wet media: the simulation, its settings and time. */
3446
3472
 
3447
3473
 
3448
3474
  /** Where the light comes from for thick paint (saved with the document, not undo steps). */
3449
- __init99() {this.lighting = { ...DEFAULT_LIGHTING }}
3450
- __init100() {this.litCaches = /* @__PURE__ */ new Map()}
3475
+ __init103() {this.lighting = { ...DEFAULT_LIGHTING }}
3476
+ __init104() {this.litCaches = /* @__PURE__ */ new Map()}
3451
3477
  /** The live impasto stroke's channels. */
3452
- __init101() {this.liveThick = null}
3478
+ __init105() {this.liveThick = null}
3453
3479
  /** Set while an operation that changes wet paint runs: the simulation before it (for undo). */
3454
- __init102() {this.wetOp = null}
3480
+ __init106() {this.wetOp = null}
3455
3481
  /** The effects provider slot (see `setEffectsProvider`). */
3456
- __init103() {this.effects = new (0, _chunkABQ2VGUBcjs.EffectsSlot)()}
3457
- __init104() {this.effectsRenderer = new PaintEffectsRenderer()}
3458
- __init105() {this.paperEffectNodeCache = null}
3459
- 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);
3482
+ __init107() {this.effects = new (0, _chunkABQ2VGUBcjs.EffectsSlot)()}
3483
+ __init108() {this.effectsRenderer = new PaintEffectsRenderer()}
3484
+ __init109() {this.paperEffectNodeCache = null}
3485
+ 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);
3460
3486
  this.historyLimit = Math.max(1, _nullishCoalesce(options.historyLimit, () => ( 200)));
3461
3487
  this.doc = createPaintDocument({ width: options.width, height: options.height, dpi: options.dpi, paper: this.resolvePaper(options.paper) });
3462
- this.userBrushes = (_nullishCoalesce(options.brushes, () => ( []))).map((b) => _chunkROVK6AXXcjs.normalizePaintBrush.call(void 0, { ...b, builtin: false }));
3463
- const start = _nullishCoalesce(this.findBrush(_nullishCoalesce(options.brushId, () => ( _chunkROVK6AXXcjs.DEFAULT_BRUSH_ID))), () => ( this.findBrush(_chunkROVK6AXXcjs.DEFAULT_BRUSH_ID)));
3464
- this.brush = _chunkROVK6AXXcjs.normalizePaintBrush.call(void 0, start);
3488
+ this.userBrushes = (_nullishCoalesce(options.brushes, () => ( []))).map((b) => _chunkGNZI3KYKcjs.normalizePaintBrush.call(void 0, { ...b, builtin: false }));
3489
+ const start = _nullishCoalesce(this.findBrush(_nullishCoalesce(options.brushId, () => ( _chunkGNZI3KYKcjs.DEFAULT_BRUSH_ID))), () => ( this.findBrush(_chunkGNZI3KYKcjs.DEFAULT_BRUSH_ID)));
3490
+ this.brush = _chunkGNZI3KYKcjs.normalizePaintBrush.call(void 0, start);
3465
3491
  this.color = options.color ? parseColor(options.color) : "#1f2937";
3466
3492
  this.hand = options.hand === "left" ? "left" : "right";
3467
3493
  this.encodeImage = options.encodeImage;
@@ -3472,7 +3498,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3472
3498
  canvas: () => this.doc.canvas,
3473
3499
  paper: () => this.doc.paper,
3474
3500
  layerSurface: (id) => {
3475
- const l = _optionalChain([_chunkB46UQUDCcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _169 => _169.layer]);
3501
+ const l = _optionalChain([_chunkB46UQUDCcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _175 => _175.layer]);
3476
3502
  return isPixelLayer(l) ? l.surface : null;
3477
3503
  },
3478
3504
  updateSurfaces: (surfaces, rects) => {
@@ -3486,7 +3512,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3486
3512
  },
3487
3513
  options.wet
3488
3514
  );
3489
- this.wet.onDriverDone = () => _optionalChain([this, 'access', _170 => _170.session, 'optionalAccess', _171 => _171.completeWetEnd, 'call', _172 => _172()]);
3515
+ this.wet.onDriverDone = () => _optionalChain([this, 'access', _176 => _176.session, 'optionalAccess', _177 => _177.completeWetEnd, 'call', _178 => _178()]);
3490
3516
  }
3491
3517
  // --- State and events ----------------------------------------------------------
3492
3518
  subscribe(listener) {
@@ -3508,17 +3534,19 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3508
3534
  this.cached = {
3509
3535
  document: this.doc,
3510
3536
  brush: this.brush,
3511
- brushes: this.library ??= [..._chunkROVK6AXXcjs.BUILTIN_BRUSHES, ...this.userBrushes],
3537
+ brushes: this.library ??= [..._chunkGNZI3KYKcjs.BUILTIN_BRUSHES, ...this.userBrushes],
3512
3538
  color: this.color,
3513
3539
  secondaryColor: this.secondaryColor,
3514
3540
  paint: _nullishCoalesce(this.gradient, () => ( { type: "color", color: this.color })),
3541
+ effectPaint: _nullishCoalesce(this.effectPaintPending, () => ( this.effectPaint)),
3542
+ effectPaintRendering: Boolean(this.effectPaintPending),
3515
3543
  mixerLoad: this.mixerLoad,
3516
3544
  view: this.view,
3517
3545
  hand: this.hand,
3518
3546
  canUndo: this.undoStack.length > 0 && !this.session,
3519
3547
  canRedo: this.redoStack.length > 0 && !this.session,
3520
- undoLabel: _nullishCoalesce(_optionalChain([last, 'optionalAccess', _173 => _173.label]), () => ( null)),
3521
- redoLabel: _nullishCoalesce(_optionalChain([next, 'optionalAccess', _174 => _174.label]), () => ( null)),
3548
+ undoLabel: _nullishCoalesce(_optionalChain([last, 'optionalAccess', _179 => _179.label]), () => ( null)),
3549
+ redoLabel: _nullishCoalesce(_optionalChain([next, 'optionalAccess', _180 => _180.label]), () => ( null)),
3522
3550
  guides: this.guides,
3523
3551
  swatches: this.swatches,
3524
3552
  mixingPadVersion: this.pad.version,
@@ -3531,10 +3559,10 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3531
3559
  overlay: this.wet.overlay,
3532
3560
  instantDry: this.wet.instantDry,
3533
3561
  speed: this.wet.speed,
3534
- clock: _nullishCoalesce(_optionalChain([this, 'access', _175 => _175.wet, 'access', _176 => _176.world, 'optionalAccess', _177 => _177.clock]), () => ( 0)),
3562
+ clock: _nullishCoalesce(_optionalChain([this, 'access', _181 => _181.wet, 'access', _182 => _182.world, 'optionalAccess', _183 => _183.clock]), () => ( 0)),
3535
3563
  tilt: { ...this.wet.tilt },
3536
3564
  gpu: this.wet.gpuMode,
3537
- gpuActive: Boolean(_optionalChain([this, 'access', _178 => _178.wet, 'access', _179 => _179.world, 'optionalAccess', _180 => _180.gpuActive]))
3565
+ gpuActive: Boolean(_optionalChain([this, 'access', _184 => _184.wet, 'access', _185 => _185.world, 'optionalAccess', _186 => _186.gpuActive]))
3538
3566
  },
3539
3567
  version: this.version
3540
3568
  };
@@ -3553,7 +3581,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3553
3581
  return d;
3554
3582
  }
3555
3583
  // --- History -------------------------------------------------------------------
3556
- __init106() {this.docRevision = 0}
3584
+ __init110() {this.docRevision = 0}
3557
3585
  /**
3558
3586
  * Bumped on every change to the painting (a committed or amended step, undo, redo, opening a
3559
3587
  * document), not on wet-paint frames or view changes. `createPaintEditorDocument` uses it.
@@ -3636,9 +3664,9 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3636
3664
  return wetIds;
3637
3665
  }
3638
3666
  /** Records a wet event (for replays) in the document being built. */
3639
- __init107() {this.pendingWetEvents = []}
3667
+ __init111() {this.pendingWetEvents = []}
3640
3668
  logWet(e) {
3641
- this.pendingWetEvents.push({ clock: _nullishCoalesce(_optionalChain([this, 'access', _181 => _181.wet, 'access', _182 => _182.world, 'optionalAccess', _183 => _183.clock]), () => ( 0)), at: this.doc.strokes.length, ...e });
3669
+ this.pendingWetEvents.push({ clock: _nullishCoalesce(_optionalChain([this, 'access', _187 => _187.wet, 'access', _188 => _188.world, 'optionalAccess', _189 => _189.clock]), () => ( 0)), at: this.doc.strokes.length, ...e });
3642
3670
  }
3643
3671
  /** The document with a paint event appended (for replays). */
3644
3672
  withPaintEvent(doc, e) {
@@ -3699,7 +3727,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3699
3727
  // --- Canvas and paper ----------------------------------------------------------
3700
3728
  resolvePaper(paper) {
3701
3729
  if (typeof paper === "string") {
3702
- const p = _chunkROVK6AXXcjs.paperPreset.call(void 0, paper);
3730
+ const p = _chunkGNZI3KYKcjs.paperPreset.call(void 0, paper);
3703
3731
  if (!p) throw new PaintEditorError(`Unknown paper "${paper}". Call list_papers for the ids.`);
3704
3732
  return p;
3705
3733
  }
@@ -3782,7 +3810,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3782
3810
  }
3783
3811
  let next = { ...shiftDocument(this.withWetEvents(this.doc), left, top), canvas: { ...was, width, height } };
3784
3812
  for (const id of keptWet) {
3785
- const l = _optionalChain([_chunkB46UQUDCcjs.findLayer.call(void 0, next.layers, id), 'optionalAccess', _184 => _184.layer]);
3813
+ const l = _optionalChain([_chunkB46UQUDCcjs.findLayer.call(void 0, next.layers, id), 'optionalAccess', _190 => _190.layer]);
3786
3814
  if (isPixelLayer(l)) next = { ...next, layers: _chunkB46UQUDCcjs.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 } })) };
3787
3815
  }
3788
3816
  if (this.wet.world) {
@@ -3810,23 +3838,23 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3810
3838
  this.requireIdle("changing the paper");
3811
3839
  let base = this.doc.paper;
3812
3840
  if (update.preset !== void 0 && update.preset !== this.doc.paper.preset) {
3813
- const p = _chunkROVK6AXXcjs.paperPreset.call(void 0, update.preset);
3841
+ const p = _chunkGNZI3KYKcjs.paperPreset.call(void 0, update.preset);
3814
3842
  if (!p) throw new PaintEditorError(`Unknown paper "${update.preset}". Call list_papers for the ids.`);
3815
3843
  base = p;
3816
3844
  }
3817
3845
  const { preset: _p, ...rest } = update;
3818
3846
  if (rest.color !== void 0) parseColor(rest.color, "paper color");
3819
- const paper = _chunkROVK6AXXcjs.normalizePaper.call(void 0, { ...rest, preset: base.preset, offset: _nullishCoalesce(rest.offset, () => ( this.doc.paper.offset)) }, base);
3847
+ const paper = _chunkGNZI3KYKcjs.normalizePaper.call(void 0, { ...rest, preset: base.preset, offset: _nullishCoalesce(rest.offset, () => ( this.doc.paper.offset)) }, base);
3820
3848
  const changedKeys = Object.keys(rest).filter((k) => k !== "name");
3821
3849
  if (changedKeys.length && update.preset === void 0) paper.preset = base.preset;
3822
3850
  if (this.wet.world) this.beginWetOp();
3823
3851
  this.commit("Paper", { ...this.doc, paper });
3824
3852
  this.wet.paperChanged();
3825
- return _chunkROVK6AXXcjs.clonePaper.call(void 0, paper);
3853
+ return _chunkGNZI3KYKcjs.clonePaper.call(void 0, paper);
3826
3854
  }
3827
3855
  // --- Layers --------------------------------------------------------------------
3828
3856
  getLayer(id) {
3829
- return _optionalChain([_chunkB46UQUDCcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _185 => _185.layer]);
3857
+ return _optionalChain([_chunkB46UQUDCcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _191 => _191.layer]);
3830
3858
  }
3831
3859
  /** The active pixel layer (or `undefined`). */
3832
3860
  getActiveLayer() {
@@ -3845,7 +3873,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3845
3873
  walk(this.doc.layers, null, 0);
3846
3874
  return out;
3847
3875
  }
3848
- describeLayer(l, parentId = _nullishCoalesce(_optionalChain([_chunkB46UQUDCcjs.findLayer.call(void 0, this.doc.layers, l.id), 'optionalAccess', _186 => _186.parent, 'optionalAccess', _187 => _187.id]), () => ( null)), depth = _nullishCoalesce(_optionalChain([_chunkB46UQUDCcjs.findLayer.call(void 0, this.doc.layers, l.id), 'optionalAccess', _188 => _188.path, 'access', _189 => _189.length]), () => ( 0))) {
3876
+ describeLayer(l, parentId = _nullishCoalesce(_optionalChain([_chunkB46UQUDCcjs.findLayer.call(void 0, this.doc.layers, l.id), 'optionalAccess', _192 => _192.parent, 'optionalAccess', _193 => _193.id]), () => ( null)), depth = _nullishCoalesce(_optionalChain([_chunkB46UQUDCcjs.findLayer.call(void 0, this.doc.layers, l.id), 'optionalAccess', _194 => _194.path, 'access', _195 => _195.length]), () => ( 0))) {
3849
3877
  let bounds = null;
3850
3878
  if (l.type === "pixel") {
3851
3879
  const b = _chunk474IQG74cjs.contentBounds.call(void 0, l.surface);
@@ -3892,7 +3920,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3892
3920
  this.requireIdle("adding a layer");
3893
3921
  const count = _chunkB46UQUDCcjs.flattenLayers.call(void 0, this.doc.layers).length;
3894
3922
  const type = _nullishCoalesce(options.type, () => ( "pixel"));
3895
- const name = _optionalChain([options, 'access', _190 => _190.name, 'optionalAccess', _191 => _191.trim, 'call', _192 => _192()]) || (type === "group" ? `Group ${count + 1}` : `Layer ${count + 1}`);
3923
+ const name = _optionalChain([options, 'access', _196 => _196.name, 'optionalAccess', _197 => _197.trim, 'call', _198 => _198()]) || (type === "group" ? `Group ${count + 1}` : `Layer ${count + 1}`);
3896
3924
  const layer = type === "group" ? { type: "group", id: newPaintLayerId(), name, visible: true, opacity: 1, blend: "pass-through", children: [] } : createPaintLayer(name);
3897
3925
  let parentId = null;
3898
3926
  let index;
@@ -3904,7 +3932,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3904
3932
  } else if (above) {
3905
3933
  const loc = _chunkB46UQUDCcjs.findLayer.call(void 0, this.doc.layers, above);
3906
3934
  if (!loc) throw new PaintEditorError(`Unknown layer "${above}". Call list_layers for the ids.`);
3907
- parentId = _nullishCoalesce(_optionalChain([loc, 'access', _193 => _193.parent, 'optionalAccess', _194 => _194.id]), () => ( null));
3935
+ parentId = _nullishCoalesce(_optionalChain([loc, 'access', _199 => _199.parent, 'optionalAccess', _200 => _200.id]), () => ( null));
3908
3936
  index = loc.index + 1;
3909
3937
  }
3910
3938
  const layers = _chunkB46UQUDCcjs.insertLayer.call(void 0, this.doc.layers, layer, parentId, index);
@@ -3944,7 +3972,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3944
3972
  }
3945
3973
  const layers = _chunkB46UQUDCcjs.mapLayer.call(void 0, this.doc.layers, id, () => null);
3946
3974
  let active = this.doc.activeLayerId;
3947
- if (active && !_chunkB46UQUDCcjs.findLayer.call(void 0, layers, active)) active = _nullishCoalesce(_optionalChain([_chunkB46UQUDCcjs.flattenLayers.call(void 0, layers), 'access', _195 => _195.filter, 'call', _196 => _196((x) => x.type === "pixel"), 'access', _197 => _197.pop, 'call', _198 => _198(), 'optionalAccess', _199 => _199.id]), () => ( null));
3975
+ if (active && !_chunkB46UQUDCcjs.findLayer.call(void 0, layers, active)) active = _nullishCoalesce(_optionalChain([_chunkB46UQUDCcjs.flattenLayers.call(void 0, layers), 'access', _201 => _201.filter, 'call', _202 => _202((x) => x.type === "pixel"), 'access', _203 => _203.pop, 'call', _204 => _204(), 'optionalAccess', _205 => _205.id]), () => ( null));
3948
3976
  this.commit("Remove layer", { ...this.doc, layers, activeLayerId: active, ...this.thickWithout(_chunkB46UQUDCcjs.flattenLayers.call(void 0, [l]).map((x) => x.id)), ...this.stickersWithout(_chunkB46UQUDCcjs.flattenLayers.call(void 0, [l]).map((x) => x.id)) });
3949
3977
  return { removed: id, activeLayerId: active };
3950
3978
  }
@@ -3965,7 +3993,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3965
3993
  return l.type === "group" ? { ...l, id: id2, children: l.children.map(copy) } : { ...l, id: id2 };
3966
3994
  };
3967
3995
  const dup = { ...copy(loc.layer), name: `${loc.layer.name} copy` };
3968
- const layers = _chunkB46UQUDCcjs.insertLayer.call(void 0, this.doc.layers, dup, _nullishCoalesce(_optionalChain([loc, 'access', _200 => _200.parent, 'optionalAccess', _201 => _201.id]), () => ( null)), loc.index + 1);
3996
+ const layers = _chunkB46UQUDCcjs.insertLayer.call(void 0, this.doc.layers, dup, _nullishCoalesce(_optionalChain([loc, 'access', _206 => _206.parent, 'optionalAccess', _207 => _207.id]), () => ( null)), loc.index + 1);
3969
3997
  this.commit("Duplicate layer", this.withWetEvents({ ...this.doc, layers, activeLayerId: dup.id, ...this.doc.thick ? { thick } : {}, ...this.doc.stickers ? { stickers } : {} }));
3970
3998
  return this.describeLayer(dup);
3971
3999
  }
@@ -3974,7 +4002,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3974
4002
  this.requireIdle("moving a layer");
3975
4003
  const loc = _chunkB46UQUDCcjs.findLayer.call(void 0, this.doc.layers, id);
3976
4004
  if (!loc) throw new PaintEditorError(`Unknown layer "${id}". Call list_layers for the ids.`);
3977
- const target = parentId === void 0 ? _nullishCoalesce(_optionalChain([loc, 'access', _202 => _202.parent, 'optionalAccess', _203 => _203.id]), () => ( null)) : parentId;
4005
+ const target = parentId === void 0 ? _nullishCoalesce(_optionalChain([loc, 'access', _208 => _208.parent, 'optionalAccess', _209 => _209.id]), () => ( null)) : parentId;
3978
4006
  if (target) {
3979
4007
  const g = this.requireLayer(target);
3980
4008
  if (g.type !== "group") throw new PaintEditorError(`Layer "${g.name}" is not a group; pass a group id as parentId.`);
@@ -3993,7 +4021,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
3993
4021
  const pre = _chunkB46UQUDCcjs.findLayer.call(void 0, this.doc.layers, id);
3994
4022
  if (pre) {
3995
4023
  const sib = pre.parent ? pre.parent.children : this.doc.layers;
3996
- this.dryLayersFirst([id, _optionalChain([sib, 'access', _204 => _204[pre.index - 1], 'optionalAccess', _205 => _205.id])].filter((x) => Boolean(x)));
4024
+ this.dryLayersFirst([id, _optionalChain([sib, 'access', _210 => _210[pre.index - 1], 'optionalAccess', _211 => _211.id])].filter((x) => Boolean(x)));
3997
4025
  }
3998
4026
  const loc = _chunkB46UQUDCcjs.findLayer.call(void 0, this.doc.layers, id);
3999
4027
  if (!loc) throw new PaintEditorError(`Unknown layer "${id}". Call list_layers for the ids.`);
@@ -4034,7 +4062,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4034
4062
  fillLayer(options = {}) {
4035
4063
  this.requireIdle("filling");
4036
4064
  const fillTarget = this.paintTarget(options.layerId, "fill");
4037
- if (_optionalChain([this, 'access', _206 => _206.doc, 'access', _207 => _207.stickers, 'optionalAccess', _208 => _208[fillTarget.id], 'optionalAccess', _209 => _209.length])) throw new PaintEditorError(`Layer "${fillTarget.name}" is a sticker layer; fill another layer (add_layer).`);
4065
+ if (_optionalChain([this, 'access', _212 => _212.doc, 'access', _213 => _213.stickers, 'optionalAccess', _214 => _214[fillTarget.id], 'optionalAccess', _215 => _215.length])) throw new PaintEditorError(`Layer "${fillTarget.name}" is a sticker layer; fill another layer (add_layer).`);
4038
4066
  this.dryLayersFirst([_nullishCoalesce(_nullishCoalesce(options.layerId, () => ( this.doc.activeLayerId)), () => ( ""))]);
4039
4067
  const l = this.paintTarget(options.layerId, "fill");
4040
4068
  const color = options.color === void 0 ? this.color : parseColor(options.color);
@@ -4075,7 +4103,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4075
4103
  const tiles = new Map(base.tiles);
4076
4104
  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 })) {
4077
4105
  const key = _chunk474IQG74cjs.tileKey.call(void 0, tx, ty);
4078
- const src = _nullishCoalesce(_optionalChain([base, 'access', _210 => _210.tiles, 'access', _211 => _211.get, 'call', _212 => _212(key), 'optionalAccess', _213 => _213.data]), () => ( new Uint8ClampedArray(_chunk474IQG74cjs.TILE * _chunk474IQG74cjs.TILE * 4)));
4106
+ const src = _nullishCoalesce(_optionalChain([base, 'access', _216 => _216.tiles, 'access', _217 => _217.get, 'call', _218 => _218(key), 'optionalAccess', _219 => _219.data]), () => ( new Uint8ClampedArray(_chunk474IQG74cjs.TILE * _chunk474IQG74cjs.TILE * 4)));
4079
4107
  const tile = _chunk474IQG74cjs.finishTile.call(void 0, _chunkPQ3H2AANcjs.applyStrokeToTile.call(void 0, coverage, src, 4, tx, ty, apply), 4, 0);
4080
4108
  if (tile) tiles.set(key, tile);
4081
4109
  else tiles.delete(key);
@@ -4108,7 +4136,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4108
4136
  }
4109
4137
  /** The effect a layer is drawn from, or `undefined` for other layers. */
4110
4138
  getEffectLayer(layerId) {
4111
- return _chunkB46UQUDCcjs.findLayer.call(void 0, this.doc.layers, layerId) ? _optionalChain([this, 'access', _214 => _214.doc, 'access', _215 => _215.effectLayers, 'optionalAccess', _216 => _216[layerId]]) : void 0;
4139
+ return _chunkB46UQUDCcjs.findLayer.call(void 0, this.doc.layers, layerId) ? _optionalChain([this, 'access', _220 => _220.doc, 'access', _221 => _221.effectLayers, 'optionalAccess', _222 => _222[layerId]]) : void 0;
4112
4140
  }
4113
4141
  /** The effect paper (without its pixels), or `null`. */
4114
4142
  getPaperEffect() {
@@ -4145,7 +4173,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4145
4173
  /** A pixel layer that takes effect pixels: unlocked, visible, no sticker layer, no wet paint. */
4146
4174
  effectTarget(layerId, what) {
4147
4175
  const l = this.paintTarget(layerId, what);
4148
- if (_optionalChain([this, 'access', _217 => _217.doc, 'access', _218 => _218.stickers, 'optionalAccess', _219 => _219[l.id], 'optionalAccess', _220 => _220.length])) throw new PaintEditorError(`Layer "${l.name}" is a sticker layer; ${what} another layer (add_layer).`);
4176
+ if (_optionalChain([this, 'access', _223 => _223.doc, 'access', _224 => _224.stickers, 'optionalAccess', _225 => _225[l.id], 'optionalAccess', _226 => _226.length])) throw new PaintEditorError(`Layer "${l.name}" is a sticker layer; ${what} another layer (add_layer).`);
4149
4177
  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.`);
4150
4178
  return l;
4151
4179
  }
@@ -4184,8 +4212,8 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4184
4212
  const was = this.doc.paperEffect;
4185
4213
  const paperEffect = {
4186
4214
  ...this.sourceOf(d, values, options.time),
4187
- opacity: _nullishCoalesce(_nullishCoalesce(options.opacity, () => ( _optionalChain([was, 'optionalAccess', _221 => _221.opacity]))), () => ( 1)),
4188
- blend: _nullishCoalesce(_nullishCoalesce(options.blend, () => ( _optionalChain([was, 'optionalAccess', _222 => _222.blend]))), () => ( "multiply")),
4215
+ opacity: _nullishCoalesce(_nullishCoalesce(options.opacity, () => ( _optionalChain([was, 'optionalAccess', _227 => _227.opacity]))), () => ( 1)),
4216
+ blend: _nullishCoalesce(_nullishCoalesce(options.blend, () => ( _optionalChain([was, 'optionalAccess', _228 => _228.blend]))), () => ( "multiply")),
4189
4217
  image: { width: pixels.width, height: pixels.height, data: new Uint8ClampedArray(pixels.data) },
4190
4218
  version: nextPaperEffectVersion()
4191
4219
  };
@@ -4238,8 +4266,8 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4238
4266
  const above = _nullishCoalesce(options.aboveId, () => ( this.doc.activeLayerId));
4239
4267
  const loc = above ? _chunkB46UQUDCcjs.findLayer.call(void 0, this.doc.layers, above) : null;
4240
4268
  if (options.aboveId !== void 0 && !loc) throw new PaintEditorError(`Layer "${options.aboveId}" was removed while the effect rendered.`);
4241
- const layer = { ...createPaintLayer(_optionalChain([options, 'access', _223 => _223.name, 'optionalAccess', _224 => _224.trim, 'call', _225 => _225()]) || d.name), surface: _chunk474IQG74cjs.surfaceFromPixels.call(void 0, pixels, 4), opacity: _nullishCoalesce(options.opacity, () => ( 1)), blend: _nullishCoalesce(options.blend, () => ( "normal")) };
4242
- const layers = _chunkB46UQUDCcjs.insertLayer.call(void 0, this.doc.layers, layer, _nullishCoalesce(_optionalChain([loc, 'optionalAccess', _226 => _226.parent, 'optionalAccess', _227 => _227.id]), () => ( null)), loc ? loc.index + 1 : void 0);
4269
+ const layer = { ...createPaintLayer(_optionalChain([options, 'access', _229 => _229.name, 'optionalAccess', _230 => _230.trim, 'call', _231 => _231()]) || d.name), surface: _chunk474IQG74cjs.surfaceFromPixels.call(void 0, pixels, 4), opacity: _nullishCoalesce(options.opacity, () => ( 1)), blend: _nullishCoalesce(options.blend, () => ( "normal")) };
4270
+ const layers = _chunkB46UQUDCcjs.insertLayer.call(void 0, this.doc.layers, layer, _nullishCoalesce(_optionalChain([loc, 'optionalAccess', _232 => _232.parent, 'optionalAccess', _233 => _233.id]), () => ( null)), loc ? loc.index + 1 : void 0);
4243
4271
  const source = this.sourceOf(d, values, options.time);
4244
4272
  this.commit("Add effect layer", { ...this.doc, layers, activeLayerId: layer.id, effectLayers: { ..._nullishCoalesce(this.doc.effectLayers, () => ( {})), [layer.id]: source } });
4245
4273
  return { layer: this.describeLayer(layer), source };
@@ -4296,6 +4324,141 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4296
4324
  this.commit("Effect fill", { ...this.doc, layers: _chunkB46UQUDCcjs.mapLayer.call(void 0, this.doc.layers, now.id, () => ({ ...now, surface })) });
4297
4325
  return { layerId: now.id, source: this.sourceOf(d, values, options.time) };
4298
4326
  }
4327
+ // --- Effect paint ----------------------------------------------------------------
4328
+ /** At most this many rendered effect paints are kept (each is canvas-sized). */
4329
+ static __initStatic() {this.EFFECT_PAINT_CACHE = 6}
4330
+ /** The effect paint strokes use (or the one rendering), or `null`. */
4331
+ getEffectPaint() {
4332
+ const p = _nullishCoalesce(this.effectPaintPending, () => ( this.effectPaint));
4333
+ return p ? { ...p, values: JSON.parse(JSON.stringify(p.values)) } : null;
4334
+ }
4335
+ /**
4336
+ * Paints with a provider generator, overlay or title effect: it is rendered once at the canvas
4337
+ * size, and brushes then take each pixel's colour (and alpha) from it, fixed to the canvas, as if
4338
+ * painting a hidden picture into view. `setColor` and `setPaint` go back to colour. Editor state,
4339
+ * not an undo step. Strokes that would paint with it throw while it renders. Returns the paint.
4340
+ */
4341
+ async setEffectPaint(source) {
4342
+ 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).");
4343
+ this.checkTime(source.time);
4344
+ const epoch = ++this.paintEpoch;
4345
+ 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.`);
4346
+ const d = await this.describeEffect(source.effect, "paint");
4347
+ const values = this.effectValues(d, { ...d.defaults }, source.values);
4348
+ if (epoch !== this.paintEpoch) throw changed(d.name);
4349
+ const paint = { type: "effect", effect: d.id, provider: this.effects.require().id, values, time: _nullishCoalesce(source.time, () => ( 0)) };
4350
+ this.effectPaintPending = paint;
4351
+ this.emit([]);
4352
+ try {
4353
+ await this.renderEffectPaint(paint);
4354
+ } catch (e) {
4355
+ if (this.effectPaintPending === paint) {
4356
+ this.effectPaintPending = null;
4357
+ this.emit([]);
4358
+ }
4359
+ throw e;
4360
+ }
4361
+ if (this.effectPaintPending !== paint || epoch !== this.paintEpoch) throw changed(d.name);
4362
+ this.effectPaintPending = null;
4363
+ this.effectPaint = paint;
4364
+ this.gradient = null;
4365
+ this.emit([]);
4366
+ return this.getEffectPaint();
4367
+ }
4368
+ /** The rendered pixels of an effect paint at the current canvas size, or `null` when it has not been rendered. */
4369
+ effectPaintImage(p) {
4370
+ const key = _chunkGNZI3KYKcjs.effectPaintKey.call(void 0, p);
4371
+ const img = this.effectPaintPixels.get(key);
4372
+ if (!img || img.width !== this.doc.canvas.width || img.height !== this.doc.canvas.height) return null;
4373
+ this.effectPaintPixels.delete(key);
4374
+ this.effectPaintPixels.set(key, img);
4375
+ return img;
4376
+ }
4377
+ /** Renders an effect paint at the canvas size into the cache (nothing when it is there already). */
4378
+ async renderEffectPaint(p) {
4379
+ const have = this.effectPaintImage(p);
4380
+ if (have) return have;
4381
+ const provider = this.effects.provider;
4382
+ const what = `the effect "${p.effect}"${p.provider ? ` from provider "${p.provider}"` : ""}`;
4383
+ if (!provider) throw new PaintEditorError(`Effect paint needs ${what}, but no effects provider is registered; register it (setEffectsProvider) and try again.`);
4384
+ 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.`);
4385
+ const { width, height } = this.doc.canvas;
4386
+ let pixels;
4387
+ try {
4388
+ pixels = await this.effectsRenderer.render(provider, p.effect, { width, height }, { time: p.time, values: p.values });
4389
+ } catch (e) {
4390
+ throw new PaintEditorError(`Effect paint could not render ${what}: ${e instanceof Error ? e.message : String(e)}`);
4391
+ }
4392
+ const img = { width, height, data: new Uint8ClampedArray(pixels.data) };
4393
+ this.effectPaintPixels.set(_chunkGNZI3KYKcjs.effectPaintKey.call(void 0, p), img);
4394
+ while (this.effectPaintPixels.size > _PaintEditorController.EFFECT_PAINT_CACHE) this.effectPaintPixels.delete(this.effectPaintPixels.keys().next().value);
4395
+ return img;
4396
+ }
4397
+ /**
4398
+ * Renders effect paints that are not rendered yet (strokes and replays need them rendered
4399
+ * first, since strokes are synchronous). Throws naming the effect and provider when one cannot be.
4400
+ */
4401
+ async prepareEffectPaints(paints) {
4402
+ const seen = /* @__PURE__ */ new Set();
4403
+ for (const p of paints) {
4404
+ const key = _chunkGNZI3KYKcjs.effectPaintKey.call(void 0, p);
4405
+ if (seen.has(key)) continue;
4406
+ seen.add(key);
4407
+ await this.renderEffectPaint(p);
4408
+ }
4409
+ }
4410
+ /** Renders the effect paints of recorded strokes (default all of them) before a replay. */
4411
+ async prepareStrokeEffects(strokeIds) {
4412
+ const ids = strokeIds ? new Set(strokeIds) : null;
4413
+ const paints = this.doc.strokes.filter((s) => (!ids || ids.has(s.id)) && _optionalChain([s, 'access', _234 => _234.paint, 'optionalAccess', _235 => _235.type]) === "effect").map((s) => s.paint);
4414
+ await this.prepareEffectPaints(paints);
4415
+ }
4416
+ /** A small preview of the effect paint (a PNG data URL `size` px wide), or `null` without a rendered one. */
4417
+ effectPaintThumbnail(size = 48) {
4418
+ const p = this.effectPaint;
4419
+ const img = p ? this.effectPaintImage(p) : null;
4420
+ if (!img) return null;
4421
+ const w = Math.max(1, Math.min(img.width, Math.round(size)));
4422
+ const h = Math.max(1, Math.round(img.height / img.width * w));
4423
+ const out = new Uint8ClampedArray(w * h * 4);
4424
+ for (let y = 0; y < h; y++) {
4425
+ const sy = Math.min(img.height - 1, Math.floor((y + 0.5) * img.height / h));
4426
+ for (let x = 0; x < w; x++) {
4427
+ const sx = Math.min(img.width - 1, Math.floor((x + 0.5) * img.width / w));
4428
+ const i = (sy * img.width + sx) * 4;
4429
+ const o = (y * w + x) * 4;
4430
+ for (let c = 0; c < 4; c++) out[o + c] = img.data[i + c];
4431
+ }
4432
+ }
4433
+ return _chunkOLNIPTB3cjs.pngDataUrl.call(void 0, w, h, out);
4434
+ }
4435
+ /**
4436
+ * The effect paint a stroke paints with and its pixels, or `null`: the stroke's own effect
4437
+ * `paint`, else (without its own `paint` or `color`, and with no brush gradient) the editor's.
4438
+ * Throws while the editor's is still rendering, for an engine that cannot paint with it, or when
4439
+ * its pixels are not rendered.
4440
+ */
4441
+ strokeEffect(init, brush) {
4442
+ if (!_chunkGNZI3KYKcjs.brushTakesPaint.call(void 0, brush)) return null;
4443
+ let source = null;
4444
+ if (init.paint !== void 0) {
4445
+ if (!_chunkGNZI3KYKcjs.isPaintEffectPaint.call(void 0, init.paint)) return null;
4446
+ source = _chunkGNZI3KYKcjs.readPaintEffectPaint.call(void 0, init.paint);
4447
+ if (!source) throw new PaintEditorError("The stroke's effect paint needs an effect id and values (getEffectPaint returns one).");
4448
+ } else if (init.color === void 0 && !brush.paint) {
4449
+ if (this.effectPaintPending) throw new PaintEditorError(`The effect paint "${this.effectPaintPending.effect}" is still rendering; wait for set_effect_paint to finish, then paint.`);
4450
+ source = this.effectPaint;
4451
+ }
4452
+ if (!source) return null;
4453
+ if (brush.engine === "wet" || brush.engine === "impasto" || brush.engine === "sticker") {
4454
+ throw new PaintEditorError(
4455
+ `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}.`
4456
+ );
4457
+ }
4458
+ const pixels = this.effectPaintImage(source);
4459
+ 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.`);
4460
+ return { source, pixels };
4461
+ }
4299
4462
  /**
4300
4463
  * Runs a filter effect (light, glow, colour grade …) on a layer's dried paint and bakes it in, at
4301
4464
  * `amount` strength (0..1, default 1). Transparent areas stay transparent; thick paint keeps its
@@ -4315,14 +4478,14 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4315
4478
  const before = _chunk474IQG74cjs.readRegion.call(void 0, l.surface, rect);
4316
4479
  const inputs = { source: { width: rect.width, height: rect.height, data: before } };
4317
4480
  const heightInput = d.inputs.find((i) => i.kind === "image" && /^(height|depth|relief)$/i.test(i.name));
4318
- const relief = _optionalChain([this, 'access', _228 => _228.doc, 'access', _229 => _229.thick, 'optionalAccess', _230 => _230[l.id]]);
4481
+ const relief = _optionalChain([this, 'access', _236 => _236.doc, 'access', _237 => _237.thick, 'optionalAccess', _238 => _238[l.id]]);
4319
4482
  if (heightInput && relief) {
4320
4483
  const h = _chunk474IQG74cjs.readRegion.call(void 0, relief.height, rect);
4321
4484
  const rgba = new Uint8ClampedArray(rect.width * rect.height * 4);
4322
4485
  for (let i = 0; i < h.length; i++) rgba.set([h[i], h[i], h[i], 255], i * 4);
4323
4486
  inputs[heightInput.name] = { width: rect.width, height: rect.height, data: rgba };
4324
4487
  }
4325
- const sourceInput = _nullishCoalesce(_optionalChain([d, 'access', _231 => _231.inputs, 'access', _232 => _232.find, 'call', _233 => _233((i) => i.kind === "image" && i.name !== _optionalChain([heightInput, 'optionalAccess', _234 => _234.name])), 'optionalAccess', _235 => _235.name]), () => ( "source"));
4488
+ const sourceInput = _nullishCoalesce(_optionalChain([d, 'access', _239 => _239.inputs, 'access', _240 => _240.find, 'call', _241 => _241((i) => i.kind === "image" && i.name !== _optionalChain([heightInput, 'optionalAccess', _242 => _242.name])), 'optionalAccess', _243 => _243.name]), () => ( "source"));
4326
4489
  if (sourceInput !== "source") {
4327
4490
  inputs[sourceInput] = inputs.source;
4328
4491
  delete inputs.source;
@@ -4335,12 +4498,12 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4335
4498
  }
4336
4499
  // --- Brushes -------------------------------------------------------------------
4337
4500
  findBrush(id) {
4338
- return _nullishCoalesce(_chunkROVK6AXXcjs.BUILTIN_BRUSHES.find((b) => b.id === id), () => ( this.userBrushes.find((b) => b.id === id)));
4501
+ return _nullishCoalesce(_chunkGNZI3KYKcjs.BUILTIN_BRUSHES.find((b) => b.id === id), () => ( this.userBrushes.find((b) => b.id === id)));
4339
4502
  }
4340
4503
  /** A library brush by id (`undefined` when unknown). */
4341
4504
  getBrush(id) {
4342
4505
  const b = this.findBrush(id);
4343
- return b ? _chunkROVK6AXXcjs.normalizePaintBrush.call(void 0, b, b) : void 0;
4506
+ return b ? _chunkGNZI3KYKcjs.normalizePaintBrush.call(void 0, b, b) : void 0;
4344
4507
  }
4345
4508
  requireBrush(id) {
4346
4509
  const b = this.findBrush(id);
@@ -4355,7 +4518,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4355
4518
  const { id, ...changes } = update;
4356
4519
  const base = id !== void 0 ? this.requireBrush(id) : this.brush;
4357
4520
  if (changes.paint !== void 0 && changes.paint !== null) this.readStrokePaint(changes.paint);
4358
- const next = _chunkROVK6AXXcjs.normalizePaintBrush.call(void 0, { ...changes, id: base.id }, base);
4521
+ const next = _chunkGNZI3KYKcjs.normalizePaintBrush.call(void 0, { ...changes, id: base.id }, base);
4359
4522
  if (base.builtin && !Object.keys(changes).length) next.builtin = true;
4360
4523
  else delete next.builtin;
4361
4524
  this.brush = next;
@@ -4364,10 +4527,10 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4364
4527
  }
4365
4528
  /** Saves the active brush (or `brush`) into the user library under `id` / `name`. */
4366
4529
  saveBrush(options) {
4367
- if (!_chunkROVK6AXXcjs.BRUSH_ID.test(options.id)) throw new PaintEditorError(`Brush id "${options.id}" is invalid; use lowercase letters, digits and dashes (e.g. "my-pencil").`);
4368
- if (_chunkROVK6AXXcjs.BUILTIN_BRUSHES.some((b) => b.id === options.id)) throw new PaintEditorError(`"${options.id}" is a built-in brush; save under another id.`);
4369
- const source = options.brush ? _chunkROVK6AXXcjs.normalizePaintBrush.call(void 0, options.brush, this.brush) : this.brush;
4370
- const saved = _chunkROVK6AXXcjs.normalizePaintBrush.call(void 0, { ...source, id: options.id, name: _nullishCoalesce(options.name, () => ( source.name)) });
4530
+ if (!_chunkGNZI3KYKcjs.BRUSH_ID.test(options.id)) throw new PaintEditorError(`Brush id "${options.id}" is invalid; use lowercase letters, digits and dashes (e.g. "my-pencil").`);
4531
+ if (_chunkGNZI3KYKcjs.BUILTIN_BRUSHES.some((b) => b.id === options.id)) throw new PaintEditorError(`"${options.id}" is a built-in brush; save under another id.`);
4532
+ const source = options.brush ? _chunkGNZI3KYKcjs.normalizePaintBrush.call(void 0, options.brush, this.brush) : this.brush;
4533
+ const saved = _chunkGNZI3KYKcjs.normalizePaintBrush.call(void 0, { ...source, id: options.id, name: _nullishCoalesce(options.name, () => ( source.name)) });
4371
4534
  delete saved.builtin;
4372
4535
  const i = this.userBrushes.findIndex((b) => b.id === options.id);
4373
4536
  if (i >= 0) this.userBrushes[i] = saved;
@@ -4377,7 +4540,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4377
4540
  return saved;
4378
4541
  }
4379
4542
  removeBrush(id) {
4380
- if (_chunkROVK6AXXcjs.BUILTIN_BRUSHES.some((b) => b.id === id)) throw new PaintEditorError(`"${id}" is a built-in brush and cannot be removed.`);
4543
+ if (_chunkGNZI3KYKcjs.BUILTIN_BRUSHES.some((b) => b.id === id)) throw new PaintEditorError(`"${id}" is a built-in brush and cannot be removed.`);
4381
4544
  const i = this.userBrushes.findIndex((b) => b.id === id);
4382
4545
  if (i < 0) throw new PaintEditorError(`Unknown brush "${id}". Call list_brushes for the ids.`);
4383
4546
  this.userBrushes.splice(i, 1);
@@ -4386,12 +4549,12 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4386
4549
  }
4387
4550
  /** The user's saved brushes. */
4388
4551
  getUserBrushes() {
4389
- return this.userBrushes.map((b) => _chunkROVK6AXXcjs.normalizePaintBrush.call(void 0, b, b));
4552
+ return this.userBrushes.map((b) => _chunkGNZI3KYKcjs.normalizePaintBrush.call(void 0, b, b));
4390
4553
  }
4391
4554
  /** A brush library file of the given brushes (default: the user's brushes). */
4392
4555
  exportBrushes(ids) {
4393
4556
  const list = ids ? ids.map((id) => this.requireBrush(id)) : this.userBrushes;
4394
- return { format: "pixerate-brushes", version: 1, brushes: list.map(_chunkROVK6AXXcjs.brushToJSON) };
4557
+ return { format: "pixerate-brushes", version: 1, brushes: list.map(_chunkGNZI3KYKcjs.brushToJSON) };
4395
4558
  }
4396
4559
  /**
4397
4560
  * Adds the brushes of a library file to the user library. A brush whose id is taken is skipped
@@ -4401,14 +4564,14 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4401
4564
  const problems = [];
4402
4565
  let list;
4403
4566
  try {
4404
- list = _chunkROVK6AXXcjs.parseBrushLibrary.call(void 0, file, problems);
4567
+ list = _chunkGNZI3KYKcjs.parseBrushLibrary.call(void 0, file, problems);
4405
4568
  } catch (e) {
4406
4569
  throw new PaintEditorError(e.message);
4407
4570
  }
4408
4571
  const added = [];
4409
4572
  const skipped = [];
4410
4573
  for (const b of list) {
4411
- if (_chunkROVK6AXXcjs.BUILTIN_BRUSHES.some((x) => x.id === b.id)) {
4574
+ if (_chunkGNZI3KYKcjs.BUILTIN_BRUSHES.some((x) => x.id === b.id)) {
4412
4575
  skipped.push(b.id);
4413
4576
  problems.push(`"${b.id}" is a built-in brush id; rename it to import it.`);
4414
4577
  continue;
@@ -4438,6 +4601,8 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4438
4601
  setColor(color) {
4439
4602
  this.color = parseColor(color);
4440
4603
  this.gradient = null;
4604
+ this.effectPaint = this.effectPaintPending = null;
4605
+ this.paintEpoch++;
4441
4606
  this.emit([]);
4442
4607
  return this.color;
4443
4608
  }
@@ -4460,6 +4625,8 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4460
4625
  return p;
4461
4626
  }
4462
4627
  this.gradient = p;
4628
+ this.effectPaint = this.effectPaintPending = null;
4629
+ this.paintEpoch++;
4463
4630
  this.emit([]);
4464
4631
  return p;
4465
4632
  }
@@ -4469,9 +4636,10 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4469
4636
  * brush's gradient, else the editor's gradient paint. Erasers, blenders and smudges take none.
4470
4637
  */
4471
4638
  strokeGradient(init, brush, color) {
4472
- if (!_chunkROVK6AXXcjs.brushTakesPaint.call(void 0, brush)) return null;
4639
+ if (!_chunkGNZI3KYKcjs.brushTakesPaint.call(void 0, brush)) return null;
4473
4640
  let g = null;
4474
4641
  if (init.paint !== void 0) {
4642
+ if (_chunkGNZI3KYKcjs.isPaintEffectPaint.call(void 0, init.paint)) return null;
4475
4643
  const p = this.readStrokePaint(init.paint);
4476
4644
  g = p.type === "gradient" ? p : null;
4477
4645
  } else g = _nullishCoalesce(brush.paint, () => ( (init.color === void 0 ? this.gradient : null)));
@@ -4515,7 +4683,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4515
4683
  // --- Mixer Brush ---------------------------------------------------------------
4516
4684
  /** Fills the Mixer Brush reservoir with a colour (default the editor colour). */
4517
4685
  loadMixerBrush(color) {
4518
- const [r, g, b] = _chunkROVK6AXXcjs.hexToRgb8.call(void 0, color === void 0 ? this.color : parseColor(color));
4686
+ const [r, g, b] = _chunkGNZI3KYKcjs.hexToRgb8.call(void 0, color === void 0 ? this.color : parseColor(color));
4519
4687
  this.mixerLoad = _chunkPQ3H2AANcjs.loadMixer.call(void 0, this.mixerLoad, [r / 255, g / 255, b / 255]);
4520
4688
  this.emit([]);
4521
4689
  return this.mixerLoad;
@@ -4545,7 +4713,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4545
4713
  // --- Strokes -------------------------------------------------------------------
4546
4714
  strokeBrush(init) {
4547
4715
  let brush = init.brushId !== void 0 ? this.requireBrush(init.brushId) : this.brush;
4548
- if (init.brush) brush = _chunkROVK6AXXcjs.normalizePaintBrush.call(void 0, { ...init.brush, id: brush.id }, brush);
4716
+ if (init.brush) brush = _chunkGNZI3KYKcjs.normalizePaintBrush.call(void 0, { ...init.brush, id: brush.id }, brush);
4549
4717
  return brush;
4550
4718
  }
4551
4719
  /**
@@ -4561,7 +4729,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4561
4729
  return symmetryCopies(this.guides.symmetry);
4562
4730
  }
4563
4731
  sessionFor(doc, init, host) {
4564
- if (init.paint !== void 0) {
4732
+ if (init.paint !== void 0 && !_chunkGNZI3KYKcjs.isPaintEffectPaint.call(void 0, init.paint)) {
4565
4733
  const p = this.readStrokePaint(init.paint);
4566
4734
  if (p.type === "color") init = { ...init, color: p.color, paint: void 0 };
4567
4735
  else init = { ...init, paint: p };
@@ -4578,14 +4746,15 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4578
4746
  return l;
4579
4747
  })();
4580
4748
  const brush = this.strokeBrush(init);
4581
- const stickerLayer = Boolean(_optionalChain([doc, 'access', _236 => _236.stickers, 'optionalAccess', _237 => _237[layer.id], 'optionalAccess', _238 => _238.length]));
4749
+ const effect = this.strokeEffect(init, brush);
4750
+ const stickerLayer = Boolean(_optionalChain([doc, 'access', _244 => _244.stickers, 'optionalAccess', _245 => _245[layer.id], 'optionalAccess', _246 => _246.length]));
4582
4751
  if (brush.engine === "sticker") {
4583
4752
  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.`);
4584
4753
  } else if (stickerLayer) {
4585
4754
  throw new PaintEditorError(`Layer "${layer.name}" is a sticker layer (its pixels are drawn from its stickers); paint on another layer (add_layer).`);
4586
4755
  }
4587
4756
  let wet;
4588
- if (_chunkROVK6AXXcjs.isWetBrush.call(void 0, brush)) {
4757
+ if (_chunkGNZI3KYKcjs.isWetBrush.call(void 0, brush)) {
4589
4758
  this.requireWetIdle("painting");
4590
4759
  if (layer.offset.x || layer.offset.y) {
4591
4760
  const moved = { ...layer, surface: _chunk474IQG74cjs.translateSurface.call(void 0, layer.surface, layer.offset.x, layer.offset.y), offset: { x: 0, y: 0 } };
@@ -4600,7 +4769,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4600
4769
  const world = this.wet.ensureLane(layer.id, brush.wet.medium);
4601
4770
  const id = layer.id;
4602
4771
  const wetColor = init.color === void 0 ? this.color : parseColor(init.color);
4603
- const [r, g, b] = _chunkROVK6AXXcjs.hexToRgb8.call(void 0, wetColor);
4772
+ const [r, g, b] = _chunkGNZI3KYKcjs.hexToRgb8.call(void 0, wetColor);
4604
4773
  const wetGradient = this.strokeGradient(init, brush, wetColor);
4605
4774
  const load = _nullishCoalesce(init.load, () => ( brushLoadForStroke(brush, this.mixerLoad, [r / 255, g / 255, b / 255])));
4606
4775
  const seedW = _nullishCoalesce(init.seed, () => ( _chunkPQ3H2AANcjs.mix32.call(void 0, this.seedCounter * 2654435761 >>> 0) & 2147483647));
@@ -4613,7 +4782,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4613
4782
  load,
4614
4783
  grain: paperGrain(doc.paper),
4615
4784
  paperDepth: doc.paper.depth,
4616
- paperColor: _chunkROVK6AXXcjs.hexToRgb8.call(void 0, doc.paper.color),
4785
+ paperColor: _chunkGNZI3KYKcjs.hexToRgb8.call(void 0, doc.paper.color),
4617
4786
  seed: seedW,
4618
4787
  copies: [IDENTITY_AFFINE, ...copiesW].map(affineCopy),
4619
4788
  mask: init.maskStencils ? this.stencilSelection(init.maskStencils) : init.stencils !== false ? this.stencilSelection() : null,
@@ -4628,7 +4797,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4628
4797
  }
4629
4798
  let color = init.color === void 0 ? this.color : parseColor(init.color);
4630
4799
  const tracing = this.guides.tracing;
4631
- if (init.color === void 0 && init.start && _optionalChain([tracing, 'optionalAccess', _239 => _239.visible]) && tracing.sampleColors) color = _nullishCoalesce(this.sampleTracingColor(init.start.x, init.start.y), () => ( color));
4800
+ if (init.color === void 0 && init.start && _optionalChain([tracing, 'optionalAccess', _247 => _247.visible]) && tracing.sampleColors) color = _nullishCoalesce(this.sampleTracingColor(init.start.x, init.start.y), () => ( color));
4632
4801
  const perspective = this.guides.perspective;
4633
4802
  const snapper = init.snapToPerspective && perspective.enabled && perspective.snap ? new PerspectiveSnapper(perspective) : null;
4634
4803
  const useStencils = init.stencils !== false;
@@ -4657,9 +4826,10 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4657
4826
  mixerLoad: _nullishCoalesce(init.load, () => ( brushLoadForStroke(brush, this.mixerLoad, [rgba[0] / 255, rgba[1] / 255, rgba[2] / 255]))),
4658
4827
  secondary: rgbaOf(this.secondaryColor),
4659
4828
  wet,
4660
- thick: brush.engine === "impasto" ? { channels: _nullishCoalesce(_optionalChain([doc, 'access', _240 => _240.thick, 'optionalAccess', _241 => _241[layer.id]]), () => ( emptyThickChannels())) } : void 0,
4829
+ thick: brush.engine === "impasto" ? { channels: _nullishCoalesce(_optionalChain([doc, 'access', _248 => _248.thick, 'optionalAccess', _249 => _249[layer.id]]), () => ( emptyThickChannels())) } : void 0,
4661
4830
  sticker: brush.engine === "sticker" ? { nextId: this.nextStickerNumber(doc) } : void 0,
4662
- paint: this.strokeGradient(init, brush, color)
4831
+ paint: effect ? null : this.strokeGradient(init, brush, color),
4832
+ effect
4663
4833
  });
4664
4834
  if (wet) this.wet.driver = wet.driver;
4665
4835
  if (init.maskStencils) session.maskStencils = init.maskStencils;
@@ -4670,13 +4840,14 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4670
4840
  const stroke = {
4671
4841
  id: `s${this.strokeCounter++}`,
4672
4842
  layerId: session.layerId,
4673
- brush: _chunkROVK6AXXcjs.brushToJSON.call(void 0, init.brush),
4843
+ brush: _chunkGNZI3KYKcjs.brushToJSON.call(void 0, init.brush),
4674
4844
  color: init.colorHex,
4675
4845
  points: session.points.map((p) => ({ ...p })),
4676
4846
  seed: init.seed
4677
4847
  };
4678
4848
  if (init.affineCopies.length) stroke.copies = init.affineCopies.map((m) => [...m]);
4679
- if (init.paint) stroke.paint = JSON.parse(JSON.stringify(init.paint));
4849
+ if (init.effect) stroke.paint = JSON.parse(JSON.stringify(init.effect.source));
4850
+ else if (init.paint) stroke.paint = JSON.parse(JSON.stringify(init.paint));
4680
4851
  if (init.mixerLoad.reservoir || init.mixerLoad.pickup) stroke.load = JSON.parse(JSON.stringify(init.mixerLoad));
4681
4852
  if (init.wet) stroke.steps = [...init.wet.driver.steps];
4682
4853
  if (init.selection) {
@@ -4694,12 +4865,12 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4694
4865
  const before = this.doc;
4695
4866
  const host = {
4696
4867
  update: (layerId, surface, rects) => {
4697
- if (_optionalChain([this, 'access', _242 => _242.session, 'optionalAccess', _243 => _243.init, 'access', _244 => _244.wet])) {
4868
+ if (_optionalChain([this, 'access', _250 => _250.session, 'optionalAccess', _251 => _251.init, 'access', _252 => _252.wet])) {
4698
4869
  this.wet.syncDisplays();
4699
4870
  return;
4700
4871
  }
4701
4872
  this.live = { layerId, surface };
4702
- const ch = _optionalChain([this, 'access', _245 => _245.session, 'optionalAccess', _246 => _246.thickChannels, 'call', _247 => _247()]);
4873
+ const ch = _optionalChain([this, 'access', _253 => _253.session, 'optionalAccess', _254 => _254.thickChannels, 'call', _255 => _255()]);
4703
4874
  this.liveThick = ch ? { layerId, channels: ch } : null;
4704
4875
  this.emit(rects);
4705
4876
  },
@@ -4711,7 +4882,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4711
4882
  const wetStroke = Boolean(s.init.wet);
4712
4883
  if (wetStroke) this.wet.driver = null;
4713
4884
  const brush = s.init.brush;
4714
- if (!cancelled && _optionalChain([s, 'access', _248 => _248.result, 'optionalAccess', _249 => _249.mixerLoad])) this.keepLoad(brush, s.result.mixerLoad);
4885
+ if (!cancelled && _optionalChain([s, 'access', _256 => _256.result, 'optionalAccess', _257 => _257.mixerLoad])) this.keepLoad(brush, s.result.mixerLoad);
4715
4886
  if (cancelled || !surface) {
4716
4887
  if (this.wetOp) {
4717
4888
  const snap = this.wetOp.before;
@@ -4736,7 +4907,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4736
4907
  const ch = s.thickChannels();
4737
4908
  const thick = ch ? { ..._nullishCoalesce(this.doc.thick, () => ( {})), [l.id]: ch } : this.doc.thick;
4738
4909
  const sprayed = s.stickers();
4739
- const stickers = sprayed ? { ..._nullishCoalesce(this.doc.stickers, () => ( {})), [l.id]: [..._nullishCoalesce(_optionalChain([this, 'access', _250 => _250.doc, 'access', _251 => _251.stickers, 'optionalAccess', _252 => _252[l.id]]), () => ( [])), ...sprayed] } : this.doc.stickers;
4910
+ const stickers = sprayed ? { ..._nullishCoalesce(this.doc.stickers, () => ( {})), [l.id]: [..._nullishCoalesce(_optionalChain([this, 'access', _258 => _258.doc, 'access', _259 => _259.stickers, 'optionalAccess', _260 => _260[l.id]]), () => ( [])), ...sprayed] } : this.doc.stickers;
4740
4911
  this.commit(`${brush.name} stroke`, this.withWetEvents({ ...this.doc, layers: _chunkB46UQUDCcjs.mapLayer.call(void 0, this.doc.layers, l.id, () => ({ ...l, surface })), strokes: [...this.doc.strokes, stroke], ...thick ? { thick } : {}, ...stickers ? { stickers } : {} }), wetStroke ? before : this.doc);
4741
4912
  }
4742
4913
  };
@@ -4774,7 +4945,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4774
4945
  layers: _chunkB46UQUDCcjs.mapLayer.call(void 0, out.layers, l.id, () => ({ ...l, surface, offset })),
4775
4946
  strokes: [...out.strokes, stroke],
4776
4947
  ...ch ? { thick: { ..._nullishCoalesce(out.thick, () => ( {})), [l.id]: ch } } : {},
4777
- ...sprayed ? { stickers: { ..._nullishCoalesce(out.stickers, () => ( {})), [l.id]: [..._nullishCoalesce(_optionalChain([out, 'access', _253 => _253.stickers, 'optionalAccess', _254 => _254[l.id]]), () => ( [])), ...sprayed] } } : {}
4948
+ ...sprayed ? { stickers: { ..._nullishCoalesce(out.stickers, () => ( {})), [l.id]: [..._nullishCoalesce(_optionalChain([out, 'access', _261 => _261.stickers, 'optionalAccess', _262 => _262[l.id]]), () => ( [])), ...sprayed] } } : {}
4778
4949
  };
4779
4950
  }
4780
4951
  };
@@ -4832,7 +5003,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4832
5003
  */
4833
5004
  replayStrokes(options) {
4834
5005
  this.requireIdle("replaying");
4835
- if (!_optionalChain([options, 'access', _255 => _255.strokeIds, 'optionalAccess', _256 => _256.length])) throw new PaintEditorError("strokeIds is empty; pass ids from list_strokes.");
5006
+ if (!_optionalChain([options, 'access', _263 => _263.strokeIds, 'optionalAccess', _264 => _264.length])) throw new PaintEditorError("strokeIds is empty; pass ids from list_strokes.");
4836
5007
  const strokes = options.strokeIds.map((id) => {
4837
5008
  const s = this.doc.strokes.find((x) => x.id === id);
4838
5009
  if (!s) throw new PaintEditorError(`Unknown stroke "${id}". Call list_strokes for the ids.`);
@@ -4844,6 +5015,13 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4844
5015
  if (options.color !== void 0) parseColor(options.color);
4845
5016
  if (options.brushId !== void 0) this.requireBrush(options.brushId);
4846
5017
  if (options.layerId !== void 0) this.paintTarget(options.layerId, "replay onto");
5018
+ if (options.color === void 0) {
5019
+ for (const s of strokes) {
5020
+ if (_optionalChain([s, 'access', _265 => _265.paint, 'optionalAccess', _266 => _266.type]) === "effect" && !this.effectPaintImage(s.paint)) {
5021
+ 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.`);
5022
+ }
5023
+ }
5024
+ }
4847
5025
  let origin = options.origin;
4848
5026
  if (!origin) {
4849
5027
  const b = strokeBounds(strokes.flatMap((s) => s.points));
@@ -4862,13 +5040,13 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4862
5040
  let brush = v.brush;
4863
5041
  if (options.brushId !== void 0) {
4864
5042
  const b = this.requireBrush(options.brushId);
4865
- brush = _chunkROVK6AXXcjs.normalizePaintBrush.call(void 0, { tip: { ...b.tip, size: b.tip.size * (v.brush.tip.size / s.brush.tip.size) } }, b);
5043
+ brush = _chunkGNZI3KYKcjs.normalizePaintBrush.call(void 0, { tip: { ...b.tip, size: b.tip.size * (v.brush.tip.size / s.brush.tip.size) } }, b);
4866
5044
  }
4867
5045
  const layerId = _nullishCoalesce(options.layerId, () => ( s.layerId));
4868
5046
  if (!_chunkB46UQUDCcjs.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.`);
4869
5047
  let load = s.load;
4870
5048
  if (load && options.color !== void 0 && load.reservoir) {
4871
- const [r, g, b] = _chunkROVK6AXXcjs.hexToRgb8.call(void 0, options.color);
5049
+ const [r, g, b] = _chunkGNZI3KYKcjs.hexToRgb8.call(void 0, options.color);
4872
5050
  load = { ...load, reservoir: [r / 255, g / 255, b / 255] };
4873
5051
  }
4874
5052
  const paint = v.paint && options.color === void 0 ? { paint: v.paint } : {};
@@ -4908,7 +5086,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4908
5086
  const id = _nullishCoalesce(layerId, () => ( this.doc.activeLayerId));
4909
5087
  if (!id) return null;
4910
5088
  this.requireLayer(id);
4911
- const ch = _optionalChain([this, 'access', _257 => _257.doc, 'access', _258 => _258.thick, 'optionalAccess', _259 => _259[id]]);
5089
+ const ch = _optionalChain([this, 'access', _267 => _267.doc, 'access', _268 => _268.thick, 'optionalAccess', _269 => _269[id]]);
4912
5090
  if (!ch) return null;
4913
5091
  const r = reliefInfo(ch);
4914
5092
  return { layerId: id, bounds: r.bounds, maxHeight: r.maxHeight };
@@ -4938,6 +5116,8 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4938
5116
  const paper = { ...this.doc.paper, scale: Math.min(8, this.doc.paper.scale * scale) };
4939
5117
  target.adopt({ state: { canvas: target.doc.canvas, paper, layers: emptiedLayers(this.doc.layers), activeLayerId: this.doc.activeLayerId, strokes: [] }, extensions: {}, problems: [] });
4940
5118
  target.lighting = { ...this.lighting };
5119
+ target.effects.set(this.effects.provider);
5120
+ if (w === width && h === height) for (const [key, img] of this.effectPaintPixels) target.effectPaintPixels.set(key, img);
4941
5121
  return target;
4942
5122
  }
4943
5123
  /**
@@ -4989,6 +5169,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
4989
5169
  dispose() {
4990
5170
  this.wet.destroy();
4991
5171
  this.effectsRenderer.dispose();
5172
+ this.effectPaintPixels.clear();
4992
5173
  }
4993
5174
  /** Resolves when wet paint is between steps (edits, undo and exports can run). */
4994
5175
  wetIdle() {
@@ -5013,7 +5194,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5013
5194
  wetState() {
5014
5195
  const st = this.getState().wet;
5015
5196
  const backend = this.wet.backend();
5016
- return { ...st, layers: this.wet.wetLayerIds().map((id) => this.wet.info(id)), backend, message: _nullishCoalesce(_optionalChain([backend, 'optionalAccess', _260 => _260.message]), () => ( _chunkXFYLA3ZOcjs.wetSupport.call(void 0, ).message)), engine: this.wet.engineInfo() };
5197
+ return { ...st, layers: this.wet.wetLayerIds().map((id) => this.wet.info(id)), backend, message: _nullishCoalesce(_optionalChain([backend, 'optionalAccess', _270 => _270.message]), () => ( _chunkXFYLA3ZOcjs.wetSupport.call(void 0, ).message)), engine: this.wet.engineInfo() };
5017
5198
  }
5018
5199
  /**
5019
5200
  * Engine B, the WebGPU accelerator for large wet areas: whether it may run, its state (`off`,
@@ -5098,7 +5279,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5098
5279
  }
5099
5280
  /** Records a settings change as a wet event (not an undo step). */
5100
5281
  recordWetSetting(e) {
5101
- this.doc = { ...this.doc, wetEvents: [..._nullishCoalesce(this.doc.wetEvents, () => ( [])), { clock: _nullishCoalesce(_optionalChain([this, 'access', _261 => _261.wet, 'access', _262 => _262.world, 'optionalAccess', _263 => _263.clock]), () => ( 0)), at: this.doc.strokes.length, ...e }] };
5282
+ this.doc = { ...this.doc, wetEvents: [..._nullishCoalesce(this.doc.wetEvents, () => ( [])), { clock: _nullishCoalesce(_optionalChain([this, 'access', _271 => _271.wet, 'access', _272 => _272.world, 'optionalAccess', _273 => _273.clock]), () => ( 0)), at: this.doc.strokes.length, ...e }] };
5102
5283
  }
5103
5284
  /** Changes a layer's wet settings (viscosity, evaporation, granulation…). Editor settings saved with the document, not an undo step. */
5104
5285
  setWetParams(layerId, update) {
@@ -5165,7 +5346,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5165
5346
  currentLayers() {
5166
5347
  const live = this.live;
5167
5348
  if (!live) return this.doc.layers;
5168
- if (_optionalChain([this, 'access', _264 => _264.liveLayers, 'optionalAccess', _265 => _265.key]) === live.surface) return this.liveLayers.layers;
5349
+ if (_optionalChain([this, 'access', _274 => _274.liveLayers, 'optionalAccess', _275 => _275.key]) === live.surface) return this.liveLayers.layers;
5169
5350
  const layers = _chunkB46UQUDCcjs.mapLayer.call(void 0, this.doc.layers, live.layerId, (l) => ({ ...l, surface: live.surface }));
5170
5351
  this.liveLayers = { key: live.surface, layers };
5171
5352
  return layers;
@@ -5188,7 +5369,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5188
5369
  tracingNode(t) {
5189
5370
  const { width, height } = this.doc.canvas;
5190
5371
  const key = this.tracingVersion * 100003 + width * 7 + height;
5191
- if (_optionalChain([this, 'access', _266 => _266.tracingCache, 'optionalAccess', _267 => _267.key]) === key && this.tracingCache.node.opacity === t.opacity) return this.tracingCache.node;
5372
+ if (_optionalChain([this, 'access', _276 => _276.tracingCache, 'optionalAccess', _277 => _277.key]) === key && this.tracingCache.node.opacity === t.opacity) return this.tracingCache.node;
5192
5373
  const src = _nullishCoalesce(this.imagePixels.get(t.src), () => ( this.decodeImage(t.src)));
5193
5374
  const image = resampleInto(src, t.rect, width, height);
5194
5375
  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 };
@@ -5215,8 +5396,8 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5215
5396
  let out = layers;
5216
5397
  const ids = /* @__PURE__ */ new Set([...Object.keys(_nullishCoalesce(thick, () => ( {}))), ...live ? [live.layerId] : []]);
5217
5398
  for (const id of ids) {
5218
- const ch = _optionalChain([live, 'optionalAccess', _268 => _268.layerId]) === id ? live.channels : _optionalChain([thick, 'optionalAccess', _269 => _269[id]]);
5219
- const l = ch && _optionalChain([_chunkB46UQUDCcjs.findLayer.call(void 0, out, id), 'optionalAccess', _270 => _270.layer]);
5399
+ const ch = _optionalChain([live, 'optionalAccess', _278 => _278.layerId]) === id ? live.channels : _optionalChain([thick, 'optionalAccess', _279 => _279[id]]);
5400
+ const l = ch && _optionalChain([_chunkB46UQUDCcjs.findLayer.call(void 0, out, id), 'optionalAccess', _280 => _280.layer]);
5220
5401
  if (!ch || !isPixelLayer(l)) continue;
5221
5402
  let cache = this.litCaches.get(id);
5222
5403
  if (!cache) this.litCaches.set(id, cache = new LitCache());
@@ -5229,7 +5410,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5229
5410
  let layers = this.litLayers((_nullishCoalesce(options.wet, () => ( "display"))) === "dried" ? this.driedLayers() : this.currentLayers());
5230
5411
  if (options.layerIds) {
5231
5412
  const picked = [];
5232
- for (const id of options.layerIds) picked.push(_nullishCoalesce(_optionalChain([_chunkB46UQUDCcjs.findLayer.call(void 0, layers, id), 'optionalAccess', _271 => _271.layer]), () => ( this.requireLayer(id))));
5413
+ for (const id of options.layerIds) picked.push(_nullishCoalesce(_optionalChain([_chunkB46UQUDCcjs.findLayer.call(void 0, layers, id), 'optionalAccess', _281 => _281.layer]), () => ( this.requireLayer(id))));
5233
5414
  layers = picked.map((l) => ({ ...l, visible: true }));
5234
5415
  }
5235
5416
  const under = options.paper === false ? [] : [paperNode(this.doc.paper, this.lighting)];
@@ -5245,7 +5426,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5245
5426
  */
5246
5427
  compositeTiles(rect, onTile, options = {}) {
5247
5428
  const dirty = options.dirty === "all" ? void 0 : options.dirty;
5248
- this.viewCompositor.compositeTiles(this.renderLayers({ paper: options.paper }, true), rect, this.sources(), onTile, { dirty, checkpointLayerId: _nullishCoalesce(_optionalChain([this, 'access', _272 => _272.live, 'optionalAccess', _273 => _273.layerId]), () => ( this.doc.activeLayerId)) });
5429
+ this.viewCompositor.compositeTiles(this.renderLayers({ paper: options.paper }, true), rect, this.sources(), onTile, { dirty, checkpointLayerId: _nullishCoalesce(_optionalChain([this, 'access', _282 => _282.live, 'optionalAccess', _283 => _283.layerId]), () => ( this.doc.activeLayerId)) });
5249
5430
  }
5250
5431
  /** The canvas as canvas-sized RGBA (paper included by default). */
5251
5432
  compositePixels(options = {}) {
@@ -5309,7 +5490,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5309
5490
  for (const [id, list] of Object.entries(_nullishCoalesce(this.doc.stickers, () => ( {})))) if (list.length && _chunkB46UQUDCcjs.findLayer.call(void 0, this.doc.layers, id)) stickers[id] = list.map((x) => ({ ...x }));
5310
5491
  if (Object.keys(stickers).length) ext.stickers = stickers;
5311
5492
  else delete ext.stickers;
5312
- const effectLayers = effectLayersToJSON(_nullishCoalesce(this.doc.effectLayers, () => ( {})), (id) => isPixelLayer(_optionalChain([_chunkB46UQUDCcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _274 => _274.layer])));
5493
+ const effectLayers = effectLayersToJSON(_nullishCoalesce(this.doc.effectLayers, () => ( {})), (id) => isPixelLayer(_optionalChain([_chunkB46UQUDCcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _284 => _284.layer])));
5313
5494
  if (effectLayers) ext.effectLayers = effectLayers;
5314
5495
  else delete ext.effectLayers;
5315
5496
  if (this.doc.paperEffect) ext.paperEffect = paperEffectToJSON(this.doc.paperEffect);
@@ -5326,7 +5507,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5326
5507
  const stickers = {};
5327
5508
  for (const [id, list] of Object.entries(ext.stickers)) {
5328
5509
  if (!_chunkB46UQUDCcjs.findLayer.call(void 0, state.layers, id) || !Array.isArray(list)) continue;
5329
- const ok = list.filter((x) => x && typeof x.id === "string" && _chunkROVK6AXXcjs.STAMP_KINDS.includes(x.stamp) && Number.isFinite(x.x) && Number.isFinite(x.y) && x.size > 0);
5510
+ const ok = list.filter((x) => x && typeof x.id === "string" && _chunkGNZI3KYKcjs.STAMP_KINDS.includes(x.stamp) && Number.isFinite(x.x) && Number.isFinite(x.y) && x.size > 0);
5330
5511
  if (ok.length !== list.length) problems.push(`Some stickers of layer "${id}" could not be read; they were dropped.`);
5331
5512
  stickers[id] = ok.map((x) => ({ ...x }));
5332
5513
  }
@@ -5335,7 +5516,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5335
5516
  if (ext.effectLayers && typeof ext.effectLayers === "object") {
5336
5517
  const effectLayers = {};
5337
5518
  for (const [id, v] of Object.entries(ext.effectLayers)) {
5338
- if (!isPixelLayer(_optionalChain([_chunkB46UQUDCcjs.findLayer.call(void 0, state.layers, id), 'optionalAccess', _275 => _275.layer]))) continue;
5519
+ if (!isPixelLayer(_optionalChain([_chunkB46UQUDCcjs.findLayer.call(void 0, state.layers, id), 'optionalAccess', _285 => _285.layer]))) continue;
5339
5520
  const source = readPaintEffectSource(v);
5340
5521
  if (source) effectLayers[id] = source;
5341
5522
  else problems.push(`The effect of layer "${id}" could not be read; it loads as a plain layer.`);
@@ -5376,7 +5557,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5376
5557
  this.readGuides(loaded.guides, loaded.state, loaded.problems);
5377
5558
  if (Array.isArray(loaded.swatches)) this.swatches = loaded.swatches.map(readSwatch).filter((x) => x !== null);
5378
5559
  for (const s of loaded.state.strokes) {
5379
- const n = Number(_nullishCoalesce(_optionalChain([/^s(\d+)$/, 'access', _276 => _276.exec, 'call', _277 => _277(s.id), 'optionalAccess', _278 => _278[1]]), () => ( 0)));
5560
+ const n = Number(_nullishCoalesce(_optionalChain([/^s(\d+)$/, 'access', _286 => _286.exec, 'call', _287 => _287(s.id), 'optionalAccess', _288 => _288[1]]), () => ( 0)));
5380
5561
  if (n >= this.strokeCounter) this.strokeCounter = n + 1;
5381
5562
  }
5382
5563
  this.undoStack = [];
@@ -5468,10 +5649,10 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5468
5649
  return next.type === "group" ? { ...next, children: toStandard(next.children) } : next;
5469
5650
  });
5470
5651
  const layers = toStandard(dried);
5471
- const result = _chunkIWMDW7LBcjs.exportPsd.call(void 0, { width, height, layers: [paperLayer, ...layers], merged, resolution: dpi });
5652
+ const result = _chunkMXJP77K4cjs.exportPsd.call(void 0, { width, height, layers: [paperLayer, ...layers], merged, resolution: dpi });
5472
5653
  for (const [mode, names] of changed) {
5473
- const label = _nullishCoalesce(_optionalChain([_chunkOLNIPTB3cjs.BLEND_MODES, 'access', _279 => _279.find, 'call', _280 => _280((m) => m.id === mode), 'optionalAccess', _281 => _281.label]), () => ( mode));
5474
- const std = _nullishCoalesce(_optionalChain([_chunkOLNIPTB3cjs.BLEND_MODES, 'access', _282 => _282.find, 'call', _283 => _283((m) => m.id === _chunkOLNIPTB3cjs.standardBlendMode.call(void 0, mode)), 'optionalAccess', _284 => _284.label]), () => ( _chunkOLNIPTB3cjs.standardBlendMode.call(void 0, mode)));
5654
+ const label = _nullishCoalesce(_optionalChain([_chunkOLNIPTB3cjs.BLEND_MODES, 'access', _289 => _289.find, 'call', _290 => _290((m) => m.id === mode), 'optionalAccess', _291 => _291.label]), () => ( mode));
5655
+ const std = _nullishCoalesce(_optionalChain([_chunkOLNIPTB3cjs.BLEND_MODES, 'access', _292 => _292.find, 'call', _293 => _293((m) => m.id === _chunkOLNIPTB3cjs.standardBlendMode.call(void 0, mode)), 'optionalAccess', _294 => _294.label]), () => ( _chunkOLNIPTB3cjs.standardBlendMode.call(void 0, mode)));
5475
5656
  const list = names.map((n) => `"${n}"`).join(", ");
5476
5657
  const one = names.length === 1;
5477
5658
  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).`);
@@ -5587,7 +5768,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5587
5768
  const { src, pixels } = this.importImage(options, "The reference image");
5588
5769
  const ref2 = {
5589
5770
  id: `ref${this.nextReferenceId++}`,
5590
- name: _optionalChain([options, 'access', _285 => _285.name, 'optionalAccess', _286 => _286.trim, 'call', _287 => _287()]) || `Reference ${this.guides.references.length + 1}`,
5771
+ name: _optionalChain([options, 'access', _295 => _295.name, 'optionalAccess', _296 => _296.trim, 'call', _297 => _297()]) || `Reference ${this.guides.references.length + 1}`,
5591
5772
  src,
5592
5773
  width: pixels.width,
5593
5774
  height: pixels.height,
@@ -5666,7 +5847,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5666
5847
  try {
5667
5848
  const px = this.decodeImage(ref2.src, `Reference "${ref2.name}"`);
5668
5849
  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 });
5669
- const n = Number(_nullishCoalesce(_optionalChain([/^ref(\d+)$/, 'access', _288 => _288.exec, 'call', _289 => _289(ref2.id), 'optionalAccess', _290 => _290[1]]), () => ( 0)));
5850
+ const n = Number(_nullishCoalesce(_optionalChain([/^ref(\d+)$/, 'access', _298 => _298.exec, 'call', _299 => _299(ref2.id), 'optionalAccess', _300 => _300[1]]), () => ( 0)));
5670
5851
  if (n >= this.nextReferenceId) this.nextReferenceId = n + 1;
5671
5852
  } catch (e) {
5672
5853
  problems.push(e.message);
@@ -5677,7 +5858,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5677
5858
  guides.stencils = [];
5678
5859
  r.stencils.forEach((raw2, i) => {
5679
5860
  try {
5680
- const id = typeof _optionalChain([raw2, 'optionalAccess', _291 => _291.id]) === "string" && /^stencil\d+$/.test(raw2.id) ? raw2.id : `stencil${this.nextStencilId}`;
5861
+ const id = typeof _optionalChain([raw2, 'optionalAccess', _301 => _301.id]) === "string" && /^stencil\d+$/.test(raw2.id) ? raw2.id : `stencil${this.nextStencilId}`;
5681
5862
  guides.stencils.push(normalizeStencil(raw2, id));
5682
5863
  const n = Number(id.slice(7));
5683
5864
  if (n >= this.nextStencilId) this.nextStencilId = n + 1;
@@ -5700,12 +5881,12 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5700
5881
  /** The next free sticker number (ids `st<n>` are unique across the document). */
5701
5882
  nextStickerNumber(doc = this.doc) {
5702
5883
  let n = 0;
5703
- for (const list of Object.values(_nullishCoalesce(doc.stickers, () => ( {})))) for (const st of list) n = Math.max(n, Number(_nullishCoalesce(_optionalChain([/^st(\d+)$/, 'access', _292 => _292.exec, 'call', _293 => _293(st.id), 'optionalAccess', _294 => _294[1]]), () => ( 0))));
5884
+ for (const list of Object.values(_nullishCoalesce(doc.stickers, () => ( {})))) for (const st of list) n = Math.max(n, Number(_nullishCoalesce(_optionalChain([/^st(\d+)$/, 'access', _302 => _302.exec, 'call', _303 => _303(st.id), 'optionalAccess', _304 => _304[1]]), () => ( 0))));
5704
5885
  return n + 1;
5705
5886
  }
5706
5887
  stickerLayer(layerId) {
5707
5888
  const l = this.wetLayer(layerId, "edit the stickers of");
5708
- const stickers = _optionalChain([this, 'access', _295 => _295.doc, 'access', _296 => _296.stickers, 'optionalAccess', _297 => _297[l.id]]);
5889
+ const stickers = _optionalChain([this, 'access', _305 => _305.doc, 'access', _306 => _306.stickers, 'optionalAccess', _307 => _307[l.id]]);
5709
5890
  if (!stickers) throw new PaintEditorError(`Layer "${l.name}" has no stickers; spray some with a sticker brush (list_brushes category sticker).`);
5710
5891
  return { layer: l, stickers };
5711
5892
  }
@@ -5714,12 +5895,12 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5714
5895
  const id = _nullishCoalesce(layerId, () => ( this.doc.activeLayerId));
5715
5896
  if (!id) return [];
5716
5897
  this.requireLayer(id);
5717
- return (_nullishCoalesce(_optionalChain([this, 'access', _298 => _298.doc, 'access', _299 => _299.stickers, 'optionalAccess', _300 => _300[id]]), () => ( []))).map((s) => ({ ...s }));
5898
+ return (_nullishCoalesce(_optionalChain([this, 'access', _308 => _308.doc, 'access', _309 => _309.stickers, 'optionalAccess', _310 => _310[id]]), () => ( []))).map((s) => ({ ...s }));
5718
5899
  }
5719
5900
  /** Replaces a layer's stickers and redraws its pixels from them (one undo step). */
5720
5901
  commitStickers(label, layer, stickers) {
5721
5902
  if (_chunkB46UQUDCcjs.isLayerLocked.call(void 0, layer, "pixels")) throw new PaintEditorError(`Layer "${layer.name}" has its pixels locked; unlock it first.`);
5722
- const surface = _chunkROVK6AXXcjs.stickerSurface.call(void 0, stickers);
5903
+ const surface = _chunkGNZI3KYKcjs.stickerSurface.call(void 0, stickers);
5723
5904
  const doc = { ...this.doc, layers: _chunkB46UQUDCcjs.mapLayer.call(void 0, this.doc.layers, layer.id, () => ({ ...layer, surface, offset: { x: 0, y: 0 } })), stickers: { ..._nullishCoalesce(this.doc.stickers, () => ( {})), [layer.id]: stickers } };
5724
5905
  this.commit(label, this.withPaintEvent(doc, { kind: "stickers", layerId: layer.id, data: { stickers: stickers.map((s) => ({ ...s })) } }));
5725
5906
  }
@@ -5730,7 +5911,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5730
5911
  if (i < 0) throw new PaintEditorError(`Layer "${layer.name}" has no sticker "${id}". Call list_stickers for the ids.`);
5731
5912
  let u;
5732
5913
  try {
5733
- u = _chunkROVK6AXXcjs.normalizeStickerUpdate.call(void 0, update);
5914
+ u = _chunkGNZI3KYKcjs.normalizeStickerUpdate.call(void 0, update);
5734
5915
  } catch (e) {
5735
5916
  throw new PaintEditorError(e.message);
5736
5917
  }
@@ -5764,13 +5945,13 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5764
5945
  this.commitStickers("Stickers", l, stickers.map((s) => ({ ...s })));
5765
5946
  }
5766
5947
  // --- Stencils --------------------------------------------------------------------
5767
- __init108() {this.stencilCache = null}
5768
- __init109() {this.nextStencilId = 1}
5948
+ __init112() {this.stencilCache = null}
5949
+ __init113() {this.nextStencilId = 1}
5769
5950
  /** The mask stencils' coverage over the canvas (cached), or `null` when none masks. */
5770
5951
  stencilSelection(stencils = this.guides.stencils) {
5771
5952
  const { width, height } = this.doc.canvas;
5772
5953
  const size = `${width}x${height}`;
5773
- if (_optionalChain([this, 'access', _301 => _301.stencilCache, 'optionalAccess', _302 => _302.key]) === stencils && this.stencilCache.size === size) return this.stencilCache.mask;
5954
+ if (_optionalChain([this, 'access', _311 => _311.stencilCache, 'optionalAccess', _312 => _312.key]) === stencils && this.stencilCache.size === size) return this.stencilCache.mask;
5774
5955
  const mask = stencilMask(stencils, width, height);
5775
5956
  this.stencilCache = { key: stencils, size, mask };
5776
5957
  return mask;
@@ -5832,7 +6013,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5832
6013
  makeSwatch(color, name) {
5833
6014
  const p = typeof color === "string" ? { type: "color", color: parseColor(color) } : this.readStrokePaint(color);
5834
6015
  const out = { color: _chunkPQ3H2AANcjs.paintSourceColor.call(void 0, p, { paint: this.color, secondary: this.secondaryColor }) };
5835
- if (_optionalChain([name, 'optionalAccess', _303 => _303.trim, 'call', _304 => _304()])) out.name = name.trim();
6016
+ if (_optionalChain([name, 'optionalAccess', _313 => _313.trim, 'call', _314 => _314()])) out.name = name.trim();
5836
6017
  if (p.type === "gradient") out.paint = p;
5837
6018
  return out;
5838
6019
  }
@@ -5884,7 +6065,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5884
6065
  * mix becomes the paint colour. Returns the mixed colour and the pile's bounds.
5885
6066
  */
5886
6067
  mixOnPad(paints, options = {}) {
5887
- const parsed = (_nullishCoalesce(paints, () => ( []))).map((p, i) => ({ color: parseColor(_optionalChain([p, 'optionalAccess', _305 => _305.color]), `paints[${i}].color`), parts: _optionalChain([p, 'optionalAccess', _306 => _306.parts]) }));
6068
+ const parsed = (_nullishCoalesce(paints, () => ( []))).map((p, i) => ({ color: parseColor(_optionalChain([p, 'optionalAccess', _315 => _315.color]), `paints[${i}].color`), parts: _optionalChain([p, 'optionalAccess', _316 => _316.parts]) }));
5888
6069
  let r;
5889
6070
  try {
5890
6071
  r = this.pad.mix(parsed, options);
@@ -5973,10 +6154,10 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5973
6154
  }
5974
6155
  /** A layer's tile surface (live while stroking), for thumbnails. */
5975
6156
  layerSurface(id) {
5976
- const l = _optionalChain([_chunkB46UQUDCcjs.findLayer.call(void 0, this.currentLayers(), id), 'optionalAccess', _307 => _307.layer]);
6157
+ const l = _optionalChain([_chunkB46UQUDCcjs.findLayer.call(void 0, this.currentLayers(), id), 'optionalAccess', _317 => _317.layer]);
5977
6158
  return isPixelLayer(l) ? l.surface : null;
5978
6159
  }
5979
- }, _class10);
6160
+ }, _class10.__initStatic(), _class10);
5980
6161
  var MAX_IMAGE_SIDE = 8192;
5981
6162
  var movePoint = (p, dx, dy) => ({ x: p.x + dx, y: p.y + dy });
5982
6163
  var moveRect = (r, dx, dy) => ({ ...r, x: r.x + dx, y: r.y + dy });
@@ -5999,7 +6180,7 @@ function shiftDocument(doc, dx, dy) {
5999
6180
  if (doc.stickers) out.stickers = Object.fromEntries(Object.entries(doc.stickers).map(([id, list]) => [id, moveStickers(list)]));
6000
6181
  if (doc.paintEvents) {
6001
6182
  out.paintEvents = doc.paintEvents.map((e) => {
6002
- const list = e.kind === "stickers" ? _optionalChain([e, 'access', _308 => _308.data, 'optionalAccess', _309 => _309.stickers]) : void 0;
6183
+ const list = e.kind === "stickers" ? _optionalChain([e, 'access', _318 => _318.data, 'optionalAccess', _319 => _319.stickers]) : void 0;
6003
6184
  return list ? { ...e, data: { ...e.data, stickers: moveStickers(list) } } : e;
6004
6185
  });
6005
6186
  }
@@ -6081,8 +6262,8 @@ function strokeSchedule(points) {
6081
6262
  return total > 0 ? acc.map((d) => d / total) : points.map(() => 1);
6082
6263
  }
6083
6264
  function strokeDuration(points, max = 1800) {
6084
- const t0 = _optionalChain([points, 'access', _310 => _310[0], 'optionalAccess', _311 => _311.t]);
6085
- const t1 = _optionalChain([points, 'access', _312 => _312[points.length - 1], 'optionalAccess', _313 => _313.t]);
6265
+ const t0 = _optionalChain([points, 'access', _320 => _320[0], 'optionalAccess', _321 => _321.t]);
6266
+ const t1 = _optionalChain([points, 'access', _322 => _322[points.length - 1], 'optionalAccess', _323 => _323.t]);
6086
6267
  let ms;
6087
6268
  if (points.every((p) => Number.isFinite(p.t)) && t1 > t0) ms = t1 - t0;
6088
6269
  else {
@@ -6136,7 +6317,7 @@ var PaintDirector = class {
6136
6317
  }
6137
6318
  where(id) {
6138
6319
  const a = this.presence.get(id);
6139
- return { x: _nullishCoalesce(_optionalChain([a, 'optionalAccess', _314 => _314.x]), () => ( 0)), y: _nullishCoalesce(_optionalChain([a, 'optionalAccess', _315 => _315.y]), () => ( 0)) };
6320
+ return { x: _nullishCoalesce(_optionalChain([a, 'optionalAccess', _324 => _324.x]), () => ( 0)), y: _nullishCoalesce(_optionalChain([a, 'optionalAccess', _325 => _325.y]), () => ( 0)) };
6140
6321
  }
6141
6322
  /** Glides to `to`; an actor that just appeared starts there instead of the corner. */
6142
6323
  async glide(id, to, ms = 380) {
@@ -6183,8 +6364,8 @@ var PaintDirector = class {
6183
6364
  }
6184
6365
  case "replay": {
6185
6366
  await this.say(id, command.note, 500);
6186
- const source = c.getStrokes().filter((s) => _optionalChain([command, 'access', _316 => _316.replay, 'access', _317 => _317.strokeIds, 'optionalAccess', _318 => _318.includes, 'call', _319 => _319(s.id)]));
6187
- const first = _optionalChain([source, 'access', _320 => _320[0], 'optionalAccess', _321 => _321.points, 'access', _322 => _322[0]]);
6367
+ const source = c.getStrokes().filter((s) => _optionalChain([command, 'access', _326 => _326.replay, 'access', _327 => _327.strokeIds, 'optionalAccess', _328 => _328.includes, 'call', _329 => _329(s.id)]));
6368
+ const first = _optionalChain([source, 'access', _330 => _330[0], 'optionalAccess', _331 => _331.points, 'access', _332 => _332[0]]);
6188
6369
  if (first) await this.glide(id, first);
6189
6370
  const result = c.replayStrokes(command.replay);
6190
6371
  if (result.bounds) await this.glide(id, centre(result.bounds), 520);
@@ -6340,7 +6521,7 @@ function createPaintStickerTools(c) {
6340
6521
  properties: {
6341
6522
  layerId: LAYER_ID,
6342
6523
  id: { type: "string", description: "Sticker id from list_stickers." },
6343
- stamp: { type: "string", enum: [..._chunkROVK6AXXcjs.STAMP_KINDS], description: "Another stamp." },
6524
+ stamp: { type: "string", enum: [..._chunkGNZI3KYKcjs.STAMP_KINDS], description: "Another stamp." },
6344
6525
  x: { type: "number", description: "Centre x in document pixels." },
6345
6526
  y: { type: "number", description: "Centre y in document pixels." },
6346
6527
  size: { type: "number", minimum: 2, maximum: 2048, description: "Diameter in pixels." },
@@ -7218,7 +7399,7 @@ var BEHAVIOR = {
7218
7399
  type: "object",
7219
7400
  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.",
7220
7401
  properties: {
7221
- mode: { type: "string", enum: [..._chunkROVK6AXXcjs.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." },
7402
+ mode: { type: "string", enum: [..._chunkGNZI3KYKcjs.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." },
7222
7403
  colors: { type: "array", maxItems: 8, items: { ...COLOR3 }, description: "2..8 colours #rrggbb; fewer than 2 uses the paint colour and the secondary colour." },
7223
7404
  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)." },
7224
7405
  length: { type: "integer", minimum: 1, maximum: 500, description: "dab mode: dabs per colour (default 12)." },
@@ -7259,10 +7440,10 @@ var WET_BRUSH = {
7259
7440
  properties: {
7260
7441
  tool: {
7261
7442
  type: "string",
7262
- enum: [..._chunkROVK6AXXcjs.WET_TOOLS],
7443
+ enum: [..._chunkGNZI3KYKcjs.WET_TOOLS],
7263
7444
  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)."
7264
7445
  },
7265
- medium: { type: "string", enum: [..._chunkROVK6AXXcjs.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)." },
7446
+ medium: { type: "string", enum: [..._chunkGNZI3KYKcjs.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)." },
7266
7447
  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)." },
7267
7448
  thinner: { type: "number", minimum: 0, maximum: 1, description: "Thinner (water or solvent): more transparent, runnier paint." },
7268
7449
  water: { type: "number", minimum: 0, maximum: 1, description: "Wetness: water laid per stroke, 0.2 a damp brush .. 1 a dripping one." },
@@ -7279,7 +7460,7 @@ var IMPASTO_BRUSH = {
7279
7460
  properties: {
7280
7461
  tool: {
7281
7462
  type: "string",
7282
- enum: [..._chunkROVK6AXXcjs.IMPASTO_TOOLS],
7463
+ enum: [..._chunkGNZI3KYKcjs.IMPASTO_TOOLS],
7283
7464
  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."
7284
7465
  },
7285
7466
  thickness: { type: "number", minimum: 0, maximum: 1, description: "How far the paint stands up." },
@@ -7295,8 +7476,8 @@ var PARTICLE_BRUSH = {
7295
7476
  type: "object",
7296
7477
  description: "Particle engine settings (procedural brushes). Missing fields keep their current values.",
7297
7478
  properties: {
7298
- kind: { type: "string", enum: [..._chunkROVK6AXXcjs.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." },
7299
- render: { type: "string", enum: [..._chunkROVK6AXXcjs.PARTICLE_RENDERS], description: "dot: a mark at each step; line: each particle draws a continuous line; sequence: beads spaced along each path." },
7479
+ kind: { type: "string", enum: [..._chunkGNZI3KYKcjs.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." },
7480
+ render: { type: "string", enum: [..._chunkGNZI3KYKcjs.PARTICLE_RENDERS], description: "dot: a mark at each step; line: each particle draws a continuous line; sequence: beads spaced along each path." },
7300
7481
  count: { type: "integer", minimum: 1, maximum: 64, description: "Particles (flow: how many are thrown per tip of travel)." },
7301
7482
  size: { type: "number", minimum: 0, maximum: 1, description: "Mark size as a fraction of the tip size." },
7302
7483
  spread: { type: "number", minimum: 0, maximum: 1, description: "How far apart the particles start, as a fraction of the tip size." },
@@ -7326,7 +7507,7 @@ var STICKER_BRUSH = {
7326
7507
  type: "object",
7327
7508
  description: "Sticker engine settings: stamps sprayed along the stroke as editable stickers. Missing fields keep their current values.",
7328
7509
  properties: {
7329
- stamps: { type: "array", minItems: 1, maxItems: 9, items: { type: "string", enum: [..._chunkROVK6AXXcjs.STAMP_KINDS], description: "A stamp." }, description: "The stamps to spray (one picked at random per sticker)." },
7510
+ stamps: { type: "array", minItems: 1, maxItems: 9, items: { type: "string", enum: [..._chunkGNZI3KYKcjs.STAMP_KINDS], description: "A stamp." }, description: "The stamps to spray (one picked at random per sticker)." },
7330
7511
  density: { type: "number", minimum: 0, maximum: 1, description: "Stickers per distance travelled." },
7331
7512
  sizeJitter: { type: "number", minimum: 0, maximum: 1, description: "Random size change." },
7332
7513
  rotationJitter: { type: "number", minimum: 0, maximum: 1, description: "Random turn as a fraction of \xB1180\xB0." },
@@ -7337,16 +7518,16 @@ var STICKER_BRUSH = {
7337
7518
  };
7338
7519
  var BRUSH_FIELDS = {
7339
7520
  name: { type: "string", minLength: 1, maxLength: 80, description: "Display name." },
7340
- category: { type: "string", enum: [..._chunkROVK6AXXcjs.PAINT_BRUSH_CATEGORIES], description: "Library category." },
7521
+ category: { type: "string", enum: [..._chunkGNZI3KYKcjs.PAINT_BRUSH_CATEGORIES], description: "Library category." },
7341
7522
  engine: {
7342
7523
  type: "string",
7343
- enum: [..._chunkROVK6AXXcjs.PAINT_BRUSH_ENGINES],
7524
+ enum: [..._chunkGNZI3KYKcjs.PAINT_BRUSH_ENGINES],
7344
7525
  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)."
7345
7526
  },
7346
7527
  tip: TIP,
7347
7528
  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." },
7348
7529
  pressureSmoothing: { type: "number", minimum: 0, maximum: 0.95, description: "Pressure smoothing, separate from the tip position smoothing." },
7349
- rotation: { type: "string", enum: [..._chunkROVK6AXXcjs.BRUSH_ROTATIONS], description: "What turns the tip: fixed (tip.angle), stroke (follows the direction of travel) or barrel (the pen barrel rotation, twist)." },
7530
+ rotation: { type: "string", enum: [..._chunkGNZI3KYKcjs.BRUSH_ROTATIONS], description: "What turns the tip: fixed (tip.angle), stroke (follows the direction of travel) or barrel (the pen barrel rotation, twist)." },
7350
7531
  dynamics: DYNAMICS,
7351
7532
  mixer: MIXER,
7352
7533
  loadsColor: { type: "boolean", description: "Mixer engine: load the colour each stroke (false for a mixer that only moves paint)." },
@@ -7396,7 +7577,7 @@ function brushSummary(b) {
7396
7577
  size: b.tip.size,
7397
7578
  grain: b.grain,
7398
7579
  rotation: b.rotation,
7399
- wetCapable: _chunkROVK6AXXcjs.isWetCapable.call(void 0, b),
7580
+ wetCapable: _chunkGNZI3KYKcjs.isWetCapable.call(void 0, b),
7400
7581
  pickup: b.behavior.pickup,
7401
7582
  dirty: b.behavior.dirty,
7402
7583
  multicolor: b.behavior.multicolor.mode,
@@ -7504,8 +7685,8 @@ function createPaintEditorToolProvider(controller, options = {}) {
7504
7685
  inputSchema: EMPTY3,
7505
7686
  annotations: { title: "List papers", ...READ6 },
7506
7687
  handler: () => ({
7507
- papers: _chunkROVK6AXXcjs.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 })),
7508
- families: [..._chunkROVK6AXXcjs.PAPER_FAMILIES],
7688
+ papers: _chunkGNZI3KYKcjs.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 })),
7689
+ families: [..._chunkGNZI3KYKcjs.PAPER_FAMILIES],
7509
7690
  patterns: [..._chunkPQ3H2AANcjs.GRAIN_PATTERNS]
7510
7691
  })
7511
7692
  });
@@ -7725,7 +7906,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
7725
7906
  annotations: { title: "List brushes", ...READ6 },
7726
7907
  handler: () => {
7727
7908
  const s = c.getState();
7728
- return { activeBrushId: s.brush.id, activeEdited: !s.brush.builtin && Boolean(_optionalChain([c, 'access', _323 => _323.getBrush, 'call', _324 => _324(s.brush.id), 'optionalAccess', _325 => _325.builtin])), brushes: s.brushes.map(brushSummary) };
7909
+ return { activeBrushId: s.brush.id, activeEdited: !s.brush.builtin && Boolean(_optionalChain([c, 'access', _333 => _333.getBrush, 'call', _334 => _334(s.brush.id), 'optionalAccess', _335 => _335.builtin])), brushes: s.brushes.map(brushSummary) };
7729
7910
  }
7730
7911
  });
7731
7912
  add({
@@ -7736,10 +7917,10 @@ function createPaintEditorToolProvider(controller, options = {}) {
7736
7917
  annotations: { title: "Get a brush", ...READ6 },
7737
7918
  handler: ({ id }) => {
7738
7919
  const st = c.getState();
7739
- if (id === void 0) return { ..._chunkROVK6AXXcjs.brushToJSON.call(void 0, st.brush), strokePaint: _nullishCoalesce(st.brush.paint, () => ( st.paint)) };
7920
+ if (id === void 0) return { ..._chunkGNZI3KYKcjs.brushToJSON.call(void 0, st.brush), strokePaint: _nullishCoalesce(st.brush.paint, () => ( st.paint)) };
7740
7921
  const b = c.getBrush(id);
7741
7922
  if (!b) throw new Error(`Unknown brush "${id}". Call list_brushes for the ids.`);
7742
- return { ..._chunkROVK6AXXcjs.brushToJSON.call(void 0, b), builtin: Boolean(b.builtin), strokePaint: _nullishCoalesce(b.paint, () => ( st.paint)) };
7923
+ return { ..._chunkGNZI3KYKcjs.brushToJSON.call(void 0, b), builtin: Boolean(b.builtin), strokePaint: _nullishCoalesce(b.paint, () => ( st.paint)) };
7743
7924
  }
7744
7925
  });
7745
7926
  add({
@@ -7748,7 +7929,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
7748
7929
  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.",
7749
7930
  inputSchema: { type: "object", properties: { id: { type: "string", description: "Brush id from list_brushes to start from." }, ...BRUSH_FIELDS }, additionalProperties: false },
7750
7931
  annotations: { title: "Set the brush", ...SET4 },
7751
- handler: (a) => _chunkROVK6AXXcjs.brushToJSON.call(void 0, c.setBrush(a))
7932
+ handler: (a) => _chunkGNZI3KYKcjs.brushToJSON.call(void 0, c.setBrush(a))
7752
7933
  });
7753
7934
  add({
7754
7935
  name: "save_brush",
@@ -7764,7 +7945,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
7764
7945
  additionalProperties: false
7765
7946
  },
7766
7947
  annotations: { title: "Save a brush", ...SET4 },
7767
- handler: ({ id, name }) => _chunkROVK6AXXcjs.brushToJSON.call(void 0, c.saveBrush({ id, name }))
7948
+ handler: ({ id, name }) => _chunkGNZI3KYKcjs.brushToJSON.call(void 0, c.saveBrush({ id, name }))
7768
7949
  });
7769
7950
  add({
7770
7951
  name: "remove_brush",
@@ -7833,7 +8014,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
7833
8014
  add({
7834
8015
  name: "set_color",
7835
8016
  title: "Set the paint colour",
7836
- description: "Sets the paint colour (and optionally the second colour) that strokes and fills use by default. Editor state, not an undo step. Returns both colours.",
8017
+ description: "Sets the paint colour (and optionally the second colour) that strokes and fills use by default. Setting color goes back to one colour from gradient paint (set_paint) or effect paint (set_effect_paint). Editor state, not an undo step. Returns both colours.",
7837
8018
  inputSchema: {
7838
8019
  type: "object",
7839
8020
  properties: { color: { ...COLOR3, description: "Paint colour #rrggbb." }, secondaryColor: { ...COLOR3, description: "Second colour #rrggbb." } },
@@ -7850,7 +8031,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
7850
8031
  add({
7851
8032
  name: "set_paint",
7852
8033
  title: "Set the paint (colour or gradient)",
7853
- description: 'Sets what strokes paint with: one colour, or gradient paint that changes colour as the stroke goes. Gradient paint: 2..16 stops sorted by offset (#rrggbb, or "paint" / "secondary" for the two editor colours), space pigment (default: mixes like paint) / oklab / srgb, and map: distance (default: the colour changes as the stroke is dragged out, 300 px then mirrored back), pressure, tilt, velocity, direction, time, across-tip or random. Every stroking brush samples it per dab (dab, mixer, watercolour and gouache, oil and impasto, particle, bristle, sticker); erasers, blenders and smudges ignore it, and a brush with its own gradient (get_brush paint) paints that instead. set_color goes back to one colour. Editor state, not an undo step. Returns paint, color and secondaryColor.',
8034
+ description: 'Sets what strokes paint with: one colour, or gradient paint that changes colour as the stroke goes. Gradient paint: 2..16 stops sorted by offset (#rrggbb, or "paint" / "secondary" for the two editor colours), space pigment (default: mixes like paint) / oklab / srgb, and map: distance (default: the colour changes as the stroke is dragged out, 300 px then mirrored back), pressure, tilt, velocity, direction, time, across-tip or random. Every stroking brush samples it per dab (dab, mixer, watercolour and gouache, oil and impasto, particle, bristle, sticker); erasers, blenders and smudges ignore it, and a brush with its own gradient (get_brush paint) paints that instead. It also ends effect paint (set_effect_paint); set_color goes back to one colour. Editor state, not an undo step. Returns paint, color and secondaryColor.',
7854
8035
  inputSchema: { type: "object", properties: { paint: _chunkPQ3H2AANcjs.PAINT_SOURCE_JSON_SCHEMA }, required: ["paint"], additionalProperties: false },
7855
8036
  annotations: { title: "Set the paint (colour or gradient)", ...SET4 },
7856
8037
  handler: ({ paint }) => {
@@ -7963,7 +8144,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
7963
8144
  color: s.color,
7964
8145
  points: ids ? s.points : s.points.length,
7965
8146
  seed: s.seed,
7966
- copies: _nullishCoalesce(_optionalChain([s, 'access', _326 => _326.copies, 'optionalAccess', _327 => _327.length]), () => ( 0)),
8147
+ copies: _nullishCoalesce(_optionalChain([s, 'access', _336 => _336.copies, 'optionalAccess', _337 => _337.length]), () => ( 0)),
7967
8148
  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) }
7968
8149
  };
7969
8150
  })
@@ -8001,8 +8182,9 @@ function createPaintEditorToolProvider(controller, options = {}) {
8001
8182
  },
8002
8183
  annotations: { title: "Replay strokes, varied", ...WRITE5 },
8003
8184
  coordinates: { in: ["origin"], out: ["bounds"] },
8004
- handler: (a) => {
8185
+ handler: async (a) => {
8005
8186
  const replay = a;
8187
+ if (replay.color === void 0) await c.prepareStrokeEffects(replay.strokeIds);
8006
8188
  return act({ kind: "replay", replay }, () => c.replayStrokes(replay));
8007
8189
  }
8008
8190
  });
@@ -8130,16 +8312,16 @@ function createPaintEditorToolProvider(controller, options = {}) {
8130
8312
  }
8131
8313
  function hostTool({ coordinates, ...tool }, { origin, onChange }) {
8132
8314
  if (!origin && !onChange) return tool;
8133
- const write = !_optionalChain([tool, 'access', _328 => _328.annotations, 'optionalAccess', _329 => _329.readOnlyHint]);
8315
+ const write = !_optionalChain([tool, 'access', _338 => _338.annotations, 'optionalAccess', _339 => _339.readOnlyHint]);
8134
8316
  const done = (result) => {
8135
- if (write) _optionalChain([onChange, 'optionalCall', _330 => _330({ tool: tool.name })]);
8136
- return origin && _optionalChain([coordinates, 'optionalAccess', _331 => _331.out]) ? fromDocument(result, coordinates.out, origin) : result;
8317
+ if (write) _optionalChain([onChange, 'optionalCall', _340 => _340({ tool: tool.name })]);
8318
+ return origin && _optionalChain([coordinates, 'optionalAccess', _341 => _341.out]) ? fromDocument(result, coordinates.out, origin) : result;
8137
8319
  };
8138
8320
  return {
8139
8321
  ...tool,
8140
8322
  ...origin ? { description: hostedText(_nullishCoalesce(tool.description, () => ( ""))), inputSchema: hostedSchema(tool.inputSchema) } : {},
8141
8323
  handler: (args, context) => {
8142
- const r = tool.handler(origin && _optionalChain([coordinates, 'optionalAccess', _332 => _332.in]) ? toDocument(args, coordinates.in, origin) : args, context);
8324
+ const r = tool.handler(origin && _optionalChain([coordinates, 'optionalAccess', _342 => _342.in]) ? toDocument(args, coordinates.in, origin) : args, context);
8143
8325
  return r instanceof Promise ? r.then(done) : done(r);
8144
8326
  }
8145
8327
  };
@@ -8153,20 +8335,20 @@ var PAINT_TOOLS = [
8153
8335
  { id: "rotate", label: "Rotate view", key: "r" }
8154
8336
  ];
8155
8337
  var PaintGesture = (_class11 = class {
8156
- constructor(controller, box) {;_class11.prototype.__init110.call(this);_class11.prototype.__init111.call(this);_class11.prototype.__init112.call(this);_class11.prototype.__init113.call(this);_class11.prototype.__init114.call(this);_class11.prototype.__init115.call(this);
8338
+ constructor(controller, box) {;_class11.prototype.__init114.call(this);_class11.prototype.__init115.call(this);_class11.prototype.__init116.call(this);_class11.prototype.__init117.call(this);_class11.prototype.__init118.call(this);_class11.prototype.__init119.call(this);
8157
8339
  this.controller = controller;
8158
8340
  this.box = box;
8159
8341
  }
8160
8342
 
8161
8343
 
8162
- __init110() {this.tool = "brush"}
8344
+ __init114() {this.tool = "brush"}
8163
8345
  /** The last refusal (a hidden or locked layer), for the editor to show. */
8164
- __init111() {this.error = null}
8346
+ __init115() {this.error = null}
8165
8347
  /** The predicted tail of the current stroke in document pixels (draw it as a thin preview). */
8166
- __init112() {this.predicted = []}
8167
- __init113() {this.mode = null}
8168
- __init114() {this.penAt = null}
8169
- __init115() {this.penDown = false}
8348
+ __init116() {this.predicted = []}
8349
+ __init117() {this.mode = null}
8350
+ __init118() {this.penAt = null}
8351
+ __init119() {this.penDown = false}
8170
8352
  doc(e) {
8171
8353
  const b = this.box();
8172
8354
  const s = this.controller.getState();
@@ -8247,12 +8429,12 @@ var PaintGesture = (_class11 = class {
8247
8429
  if (!m || m.pointerId !== e.pointerId) return;
8248
8430
  this.mode = null;
8249
8431
  this.predicted = [];
8250
- if (m.kind === "stroke") _optionalChain([this, 'access', _333 => _333.controller, 'access', _334 => _334.activeStroke, 'optionalAccess', _335 => _335.end, 'call', _336 => _336()]);
8432
+ if (m.kind === "stroke") _optionalChain([this, 'access', _343 => _343.controller, 'access', _344 => _344.activeStroke, 'optionalAccess', _345 => _345.end, 'call', _346 => _346()]);
8251
8433
  }
8252
8434
  cancel() {
8253
8435
  this.penDown = false;
8254
8436
  this.predicted = [];
8255
- if (_optionalChain([this, 'access', _337 => _337.mode, 'optionalAccess', _338 => _338.kind]) === "stroke") _optionalChain([this, 'access', _339 => _339.controller, 'access', _340 => _340.activeStroke, 'optionalAccess', _341 => _341.cancel, 'call', _342 => _342()]);
8437
+ if (_optionalChain([this, 'access', _347 => _347.mode, 'optionalAccess', _348 => _348.kind]) === "stroke") _optionalChain([this, 'access', _349 => _349.controller, 'access', _350 => _350.activeStroke, 'optionalAccess', _351 => _351.cancel, 'call', _352 => _352()]);
8256
8438
  this.mode = null;
8257
8439
  }
8258
8440
  get active() {
@@ -8313,13 +8495,13 @@ function handlePaintShortcut(controller, gesture, e) {
8313
8495
  return false;
8314
8496
  }
8315
8497
  var PaintCanvasPresenter = (_class12 = class {
8316
- constructor(controller) {;_class12.prototype.__init116.call(this);_class12.prototype.__init117.call(this);_class12.prototype.__init118.call(this);
8498
+ constructor(controller) {;_class12.prototype.__init120.call(this);_class12.prototype.__init121.call(this);_class12.prototype.__init122.call(this);
8317
8499
  this.controller = controller;
8318
8500
  }
8319
8501
 
8320
- __init116() {this.uploaded = /* @__PURE__ */ new Map()}
8321
- __init117() {this.scratch = null}
8322
- __init118() {this.size = ""}
8502
+ __init120() {this.uploaded = /* @__PURE__ */ new Map()}
8503
+ __init121() {this.scratch = null}
8504
+ __init122() {this.size = ""}
8323
8505
  /** Draws what changed into `ctx` (a canvas the size of the document); returns the tiles drawn. */
8324
8506
  render(ctx) {
8325
8507
  const { width, height } = this.controller.document.canvas;
@@ -8386,7 +8568,7 @@ var PAPER_SLIDERS = [
8386
8568
  ];
8387
8569
  function readPath(obj, path) {
8388
8570
  let v = obj;
8389
- for (const k of path.split(".")) v = _optionalChain([v, 'optionalAccess', _343 => _343[k]]);
8571
+ for (const k of path.split(".")) v = _optionalChain([v, 'optionalAccess', _353 => _353[k]]);
8390
8572
  return typeof v === "number" ? v : 0;
8391
8573
  }
8392
8574
  function patchPath(obj, path, value) {
@@ -8508,7 +8690,7 @@ function brushEngineControls(brush) {
8508
8690
  impastoTool: true
8509
8691
  };
8510
8692
  case "wet": {
8511
- const tool = _nullishCoalesce(_optionalChain([brush, 'access', _344 => _344.wet, 'optionalAccess', _345 => _345.tool]), () => ( "paint"));
8693
+ const tool = _nullishCoalesce(_optionalChain([brush, 'access', _354 => _354.wet, 'optionalAccess', _355 => _355.tool]), () => ( "paint"));
8512
8694
  const sliders = tool === "paint" ? [
8513
8695
  { path: "wet.water", label: "Water", min: 0, max: 1, step: 0.01 },
8514
8696
  { path: "wet.pigment", label: "Pigment", min: 0, max: 1, step: 0.01 },
@@ -8641,7 +8823,7 @@ function startWetClock(controller, frame, cancel) {
8641
8823
  id = raf(loop);
8642
8824
  return () => {
8643
8825
  stopped = true;
8644
- _optionalChain([caf, 'optionalCall', _346 => _346(id)]);
8826
+ _optionalChain([caf, 'optionalCall', _356 => _356(id)]);
8645
8827
  };
8646
8828
  }
8647
8829
  function drawWaterOverlay(controller, ctx) {
@@ -8692,6 +8874,7 @@ function quickStencil(kind, canvas) {
8692
8874
 
8693
8875
  // src/paint-editor/effect-tools.ts
8694
8876
  var PAPER_TARGET = "paper";
8877
+ var PAINT_TARGET = "paint";
8695
8878
  var ref = (s) => ({ effect: s.effect, ...s.name ? { name: s.name } : {}, ...s.provider ? { provider: s.provider } : {} });
8696
8879
  function createPaintEffectsToolProvider(controller, options = {}) {
8697
8880
  const readOnlyReason = () => {
@@ -8702,6 +8885,10 @@ function createPaintEffectsToolProvider(controller, options = {}) {
8702
8885
  const p = controller.getPaperEffect();
8703
8886
  return p ? [{ id: PAPER_TARGET, ...ref(p), role: "effect paper", enabled: true, opacity: p.opacity, blend: p.blend, values: p.values, ...p.time ? { time: p.time } : {} }] : [];
8704
8887
  };
8888
+ const paintInfo = () => {
8889
+ const p = controller.getEffectPaint();
8890
+ 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 } : {} }] : [];
8891
+ };
8705
8892
  const layerInfo = (layerId) => {
8706
8893
  const s = controller.getEffectLayer(layerId);
8707
8894
  return s ? [{ id: "effect", ...ref(s), role: "effect layer", enabled: true, values: s.values, ...s.time ? { time: s.time } : {} }] : [];
@@ -8714,14 +8901,14 @@ function createPaintEffectsToolProvider(controller, options = {}) {
8714
8901
  }
8715
8902
  return l;
8716
8903
  };
8717
- const effectsOf = (target) => target === PAPER_TARGET ? paperInfo() : layerInfo(target);
8904
+ const effectsOf = (target) => target === PAPER_TARGET ? paperInfo() : target === PAINT_TARGET ? paintInfo() : layerInfo(target);
8718
8905
  const instanceCheck = (target, instance) => {
8719
- const want = target === PAPER_TARGET ? PAPER_TARGET : "effect";
8720
- if (target !== PAPER_TARGET) requireLayer(target);
8906
+ const want = target === PAPER_TARGET || target === PAINT_TARGET ? target : "effect";
8907
+ if (target !== PAPER_TARGET && target !== PAINT_TARGET) requireLayer(target);
8721
8908
  if (instance !== want || !effectsOf(target).length) {
8722
8909
  const have = effectsOf(target).map((e) => `"${e.id}"`);
8723
8910
  throw new Error(
8724
- `${target === PAPER_TARGET ? "The paper" : `Layer "${target}"`} has no provider effect "${instance}"; its effects are ${have.join(", ") || "none"} (list_applied_effects). Light baked into paint is part of the pixels: undo takes it back.`
8911
+ `${target === PAPER_TARGET ? "The paper" : target === PAINT_TARGET ? "The paint" : `Layer "${target}"`} has no provider effect "${instance}"; its effects are ${have.join(", ") || "none"} (list_applied_effects). Light baked into paint is part of the pixels: undo takes it back.`
8725
8912
  );
8726
8913
  }
8727
8914
  };
@@ -8736,24 +8923,27 @@ function createPaintEffectsToolProvider(controller, options = {}) {
8736
8923
  title: "Paint effects",
8737
8924
  description: "Provider effects on paint layers and on the effect paper.",
8738
8925
  skill: "pixerate-paint-editor",
8739
- target: { noun: "layer", id: `A pixel layer id from list_layers ("${PAPER_TARGET}" is the effect paper, for list, update and remove).` },
8926
+ target: { noun: "layer", id: `A pixel layer id from list_layers ("${PAPER_TARGET}" is the effect paper and "${PAINT_TARGET}" the effect paint, for list, update and remove).` },
8740
8927
  applyUses: ["filter"],
8741
8928
  applyDetails: "Light on dried paint: the filter (search_effects with use filter, e.g. a light, glow or grade) runs on the layer's paint at the canvas size and is baked into its pixels; transparent areas stay transparent, and thick paint keeps its relief (an effect with a height input gets it). opacity is the strength (default 1). Wet paint is refused: dry it first (dry_paint). It is one undo step and is not listed afterwards (it is part of the pixels). Generators go on the paper (set_paper_effect), on their own layer (add_effect_layer) or into a layer (fill_layer_with_effect).",
8742
8929
  provider: () => controller.effectsProvider,
8743
8930
  readOnlyReason,
8744
8931
  list: (target) => {
8745
8932
  if (target === PAPER_TARGET) return [{ target: PAPER_TARGET, name: "Paper", effects: paperInfo() }];
8933
+ if (target === PAINT_TARGET) return [{ target: PAINT_TARGET, name: "Paint", effects: paintInfo() }];
8746
8934
  if (target) {
8747
8935
  const l = requireLayer(target);
8748
8936
  return [{ target, name: l.name, effects: layerInfo(target) }];
8749
8937
  }
8750
8938
  const out = [];
8939
+ if (paintInfo().length) out.push({ target: PAINT_TARGET, name: "Paint", effects: paintInfo() });
8751
8940
  if (paperInfo().length) out.push({ target: PAPER_TARGET, name: "Paper", effects: paperInfo() });
8752
8941
  for (const e of controller.listEffectLayers()) out.push({ target: e.layerId, name: e.name, effects: layerInfo(e.layerId) });
8753
8942
  return out;
8754
8943
  },
8755
8944
  apply: async (target, effect, args) => {
8756
8945
  if (target === PAPER_TARGET) throw new Error("The paper takes generator effects through set_paper_effect; apply_effect runs a filter on a layer's paint.");
8946
+ if (target === PAINT_TARGET) throw new Error("Brushes paint with an effect through set_effect_paint; apply_effect runs a filter on a layer's paint.");
8757
8947
  noStackArgs(args);
8758
8948
  requireLayer(target);
8759
8949
  const r = await controller.applyLightEffect(target, effect, { values: values(args.values), amount: args.opacity });
@@ -8763,6 +8953,13 @@ function createPaintEffectsToolProvider(controller, options = {}) {
8763
8953
  update: async (target, instance, changes) => {
8764
8954
  instanceCheck(target, instance);
8765
8955
  noStackArgs(changes);
8956
+ if (target === PAINT_TARGET) {
8957
+ if (changes.opacity !== void 0) throw new Error("opacity does not apply to the effect paint: change the brush opacity (set_brush tip.opacity).");
8958
+ const p = controller.getEffectPaint();
8959
+ await controller.setEffectPaint({ effect: p.effect, values: { ...p.values, ..._nullishCoalesce(changes.values, () => ( {})) }, time: p.time });
8960
+ const effects2 = paintInfo();
8961
+ return { target, effect: effects2[0], effects: effects2 };
8962
+ }
8766
8963
  if (target === PAPER_TARGET) {
8767
8964
  await controller.updatePaperEffect({ values: changes.values, opacity: changes.opacity });
8768
8965
  const effects2 = paperInfo();
@@ -8776,6 +8973,10 @@ function createPaintEffectsToolProvider(controller, options = {}) {
8776
8973
  remove: async (target, instance) => {
8777
8974
  instanceCheck(target, instance);
8778
8975
  const was = effectsOf(target)[0];
8976
+ if (target === PAINT_TARGET) {
8977
+ controller.setColor(controller.getState().color);
8978
+ return { target, effect: was, effects: [] };
8979
+ }
8779
8980
  if (target === PAPER_TARGET) await controller.setPaperEffect(null);
8780
8981
  else controller.rasterizeEffectLayer(target);
8781
8982
  return { target, effect: was, effects: [], ...target === PAPER_TARGET ? {} : { keptPixels: true } };
@@ -8811,6 +9012,26 @@ function createPaintEffectsToolProvider(controller, options = {}) {
8811
9012
  return { paperEffect: await controller.setPaperEffect(args.effect, { values: values(args.values), opacity: args.opacity, blend: args.blend, time: args.time }) };
8812
9013
  }
8813
9014
  },
9015
+ {
9016
+ name: "set_effect_paint",
9017
+ title: "Paint with an effect",
9018
+ 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).`,
9019
+ inputSchema: {
9020
+ type: "object",
9021
+ properties: {
9022
+ effect: ctx.effectIdSchema(["generator", "overlay", "title"]),
9023
+ values: ctx.valuesSchema("Control values over the effect's defaults"),
9024
+ time: { type: "number", minimum: 0, description: "Which moment of an animated effect to paint with, in ms (default 0)." }
9025
+ },
9026
+ required: ["effect"],
9027
+ additionalProperties: false
9028
+ },
9029
+ annotations: { title: "Paint with an effect", ...ctx.annotations.writeIdempotent },
9030
+ handler: async (args) => {
9031
+ ctx.requireProvider();
9032
+ return { effectPaint: await controller.setEffectPaint({ effect: args.effect, values: values(args.values), time: args.time }) };
9033
+ }
9034
+ },
8814
9035
  {
8815
9036
  name: "add_effect_layer",
8816
9037
  title: "Add an effect layer",
@@ -9199,4 +9420,10 @@ function createPaintEditorDocument(controller, options = {}) {
9199
9420
 
9200
9421
 
9201
9422
 
9202
- exports.BLEND_MENU_GROUPS = BLEND_MENU_GROUPS; exports.BLEND_MODES = _chunkOLNIPTB3cjs.BLEND_MODES; exports.BRUSH_ID = _chunkROVK6AXXcjs.BRUSH_ID; exports.BRUSH_ROTATIONS = _chunkROVK6AXXcjs.BRUSH_ROTATIONS; exports.BRUSH_SLIDERS = BRUSH_SLIDERS; exports.BUILTIN_BRUSHES = _chunkROVK6AXXcjs.BUILTIN_BRUSHES; exports.BristleStroke = _chunkROVK6AXXcjs.BristleStroke; exports.DEFAULT_BEHAVIOR = _chunkROVK6AXXcjs.DEFAULT_BEHAVIOR; exports.DEFAULT_BRISTLE = _chunkROVK6AXXcjs.DEFAULT_BRISTLE; exports.DEFAULT_BRUSH_ID = _chunkROVK6AXXcjs.DEFAULT_BRUSH_ID; exports.DEFAULT_DPI = DEFAULT_DPI; exports.DEFAULT_DYNAMICS = _chunkROVK6AXXcjs.DEFAULT_DYNAMICS; exports.DEFAULT_FLOW = _chunkXFYLA3ZOcjs.DEFAULT_FLOW; exports.DEFAULT_IMPASTO = _chunkROVK6AXXcjs.DEFAULT_IMPASTO; exports.DEFAULT_LIGHTING = DEFAULT_LIGHTING; exports.DEFAULT_MULTI_COLOR = _chunkROVK6AXXcjs.DEFAULT_MULTI_COLOR; exports.DEFAULT_PAINT_GRADIENT = _chunkPQ3H2AANcjs.DEFAULT_PAINT_GRADIENT; exports.DEFAULT_PAINT_GRADIENT_MAPPING = _chunkPQ3H2AANcjs.DEFAULT_PAINT_GRADIENT_MAPPING; exports.DEFAULT_PAPER = _chunkROVK6AXXcjs.DEFAULT_PAPER; exports.DEFAULT_PARTICLE = _chunkROVK6AXXcjs.DEFAULT_PARTICLE; exports.DEFAULT_STICKER = _chunkROVK6AXXcjs.DEFAULT_STICKER; exports.DEFAULT_SWATCHES = DEFAULT_SWATCHES; exports.DEFAULT_VIEW = DEFAULT_VIEW; exports.DEFAULT_WET_BRUSH = _chunkROVK6AXXcjs.DEFAULT_WET_BRUSH; exports.DEFAULT_WET_PARAMS = _chunkXFYLA3ZOcjs.DEFAULT_WET_PARAMS; exports.DryStroke = _chunkROVK6AXXcjs.DryStroke; exports.GPU_LEAD = GPU_LEAD; exports.GRAIN_PATTERNS = _chunkPQ3H2AANcjs.GRAIN_PATTERNS; exports.GRAIN_TILE = _chunkPQ3H2AANcjs.GRAIN_TILE; exports.HARMONY_KINDS = _chunkEUIDTZNQcjs.HARMONY_KINDS; exports.IDENTITY_AFFINE = IDENTITY_AFFINE; exports.IDENTITY_COPY = _chunkROVK6AXXcjs.IDENTITY_COPY; exports.IMPASTO_TOOLS = _chunkROVK6AXXcjs.IMPASTO_TOOLS; exports.IMPASTO_TOOL_LABELS = IMPASTO_TOOL_LABELS; exports.LIGHT_SLIDERS = LIGHT_SLIDERS; 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 = _chunkROVK6AXXcjs.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 = _chunkROVK6AXXcjs.PAINT_BRUSH_CATEGORIES; exports.PAINT_BRUSH_ENGINES = _chunkROVK6AXXcjs.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_TOOLS = PAINT_TOOLS; exports.PAPER_EFFECT_BLENDS = PAPER_EFFECT_BLENDS; exports.PAPER_EFFECT_NODE_ID = PAPER_EFFECT_NODE_ID; exports.PAPER_FAMILIES = _chunkROVK6AXXcjs.PAPER_FAMILIES; exports.PAPER_LIBRARY = _chunkROVK6AXXcjs.PAPER_LIBRARY; exports.PAPER_NODE_ID = PAPER_NODE_ID; exports.PAPER_SLIDERS = PAPER_SLIDERS; exports.PAPER_TARGET = PAPER_TARGET; exports.PARTICLE_KINDS = _chunkROVK6AXXcjs.PARTICLE_KINDS; exports.PARTICLE_KIND_LABELS = PARTICLE_KIND_LABELS; exports.PARTICLE_RENDERS = _chunkROVK6AXXcjs.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 = _chunkROVK6AXXcjs.ParticleStroke; exports.PenDabWalker = _chunkROVK6AXXcjs.PenDabWalker; exports.PenSmoother = _chunkROVK6AXXcjs.PenSmoother; exports.PerspectiveSnapper = PerspectiveSnapper; exports.SNAP_DECIDE_DISTANCE = SNAP_DECIDE_DISTANCE; exports.STAMP_KINDS = _chunkROVK6AXXcjs.STAMP_KINDS; exports.STAMP_LABELS = STAMP_LABELS; exports.STENCIL_KINDS = STENCIL_KINDS; exports.STENCIL_SHAPES = STENCIL_SHAPES; exports.STICKER_SLIDERS = STICKER_SLIDERS; exports.SYMMETRY_MODES = SYMMETRY_MODES; exports.StencilSnapper = StencilSnapper; exports.StickerSpray = _chunkROVK6AXXcjs.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 = _chunkROVK6AXXcjs.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 = _chunkROVK6AXXcjs.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 = _chunkROVK6AXXcjs.brushTakesPaint; exports.brushToJSON = _chunkROVK6AXXcjs.brushToJSON; exports.buildTimeLapse = buildTimeLapse; exports.checkPaintEffectPlace = checkPaintEffectPlace; exports.clonePaper = _chunkROVK6AXXcjs.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 = _chunkROVK6AXXcjs.drawSticker; exports.drawWaterOverlay = drawWaterOverlay; exports.effectLayersToJSON = effectLayersToJSON; 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 = _chunkROVK6AXXcjs.hexToRgb8; exports.hslToRgb = hslToRgb; exports.hsvToRgb = hsvToRgb; exports.hueToWheel = _chunkEUIDTZNQcjs.hueToWheel; exports.invertAffine = invertAffine; exports.isBlendMode = _chunkOLNIPTB3cjs.isBlendMode; exports.isGradientPaint = _chunkPQ3H2AANcjs.isGradientPaint; exports.isPainterlyBlendMode = _chunkOLNIPTB3cjs.isPainterlyBlendMode; exports.isPalmTouch = isPalmTouch; exports.isWetBrush = _chunkROVK6AXXcjs.isWetBrush; exports.isWetCapable = _chunkROVK6AXXcjs.isWetCapable; exports.lightTile = lightTile; exports.lightingKey = lightingKey; exports.mapPenPoint = mapPenPoint; exports.mix32 = _chunkPQ3H2AANcjs.mix32; exports.mixPixels = mixPixels; exports.mixerLoadForStroke = mixerLoadForStroke; exports.mixerTip = _chunkROVK6AXXcjs.mixerTip; exports.multiColorForDab = multiColorForDab; exports.multiColorGradient = multiColorGradient; exports.multiColorPalette = multiColorPalette; exports.multiColorSliders = multiColorSliders; exports.multiColorToPaint = _chunkROVK6AXXcjs.multiColorToPaint; exports.newPaintLayerId = newPaintLayerId; exports.nextPaperEffectVersion = nextPaperEffectVersion; exports.normalizeBehavior = _chunkROVK6AXXcjs.normalizeBehavior; exports.normalizeBristle = _chunkROVK6AXXcjs.normalizeBristle; exports.normalizeBrushStroke = normalizeBrushStroke; exports.normalizeCanvas = normalizeCanvas; exports.normalizeDynamics = _chunkROVK6AXXcjs.normalizeDynamics; exports.normalizeFlow = _chunkXFYLA3ZOcjs.normalizeFlow; exports.normalizeHexColor = _chunkPQ3H2AANcjs.normalizeHexColor; exports.normalizeImpasto = _chunkROVK6AXXcjs.normalizeImpasto; exports.normalizeLighting = normalizeLighting; exports.normalizeMultiColor = _chunkROVK6AXXcjs.normalizeMultiColor; exports.normalizePaintBrush = _chunkROVK6AXXcjs.normalizePaintBrush; exports.normalizePaper = _chunkROVK6AXXcjs.normalizePaper; exports.normalizeParticle = _chunkROVK6AXXcjs.normalizeParticle; exports.normalizePerspective = normalizePerspective; exports.normalizeRotation = normalizeRotation; exports.normalizeStencil = normalizeStencil; exports.normalizeStickerSettings = _chunkROVK6AXXcjs.normalizeStickerSettings; exports.normalizeStickerUpdate = _chunkROVK6AXXcjs.normalizeStickerUpdate; exports.normalizeSymmetry = normalizeSymmetry; exports.normalizeView = normalizeView; exports.normalizeWetBrush = _chunkROVK6AXXcjs.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 = _chunkROVK6AXXcjs.paintToMultiColor; exports.paperEffectFromJSON = paperEffectFromJSON; exports.paperEffectToJSON = paperEffectToJSON; exports.paperGrain = paperGrain; exports.paperKey = paperKey; exports.paperNode = paperNode; exports.paperPreset = _chunkROVK6AXXcjs.paperPreset; exports.parseBrushLibrary = _chunkROVK6AXXcjs.parseBrushLibrary; exports.parseHexColor = parseHexColor; exports.parsePaintSource = _chunkPQ3H2AANcjs.parsePaintSource; exports.patchBrushValue = patchBrushValue; exports.patchPath = patchPath; exports.penOrientation = _chunkROVK6AXXcjs.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.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 = _chunkROVK6AXXcjs.renderPaper; exports.renderStickers = _chunkROVK6AXXcjs.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.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 = _chunkROVK6AXXcjs.stampCoverage; exports.standardBlendMode = _chunkOLNIPTB3cjs.standardBlendMode; exports.startWetClock = startWetClock; exports.stencilMask = stencilMask; exports.stencilOutline = stencilOutline; exports.stickerRect = _chunkROVK6AXXcjs.stickerRect; exports.stickerSurface = _chunkROVK6AXXcjs.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 = _chunkROVK6AXXcjs.tiltToOrientation; exports.timeLapseVideo = timeLapseVideo; exports.timeLapseZip = timeLapseZip; exports.toStrokePoint = _chunkROVK6AXXcjs.toStrokePoint; exports.toggleStamp = toggleStamp; exports.translateStencil = translateStencil; exports.updatePaintGradientStop = _chunkPQ3H2AANcjs.updatePaintGradientStop; exports.usesPaintExchange = _chunkROVK6AXXcjs.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 = _chunkEUIDTZNQcjs.wheelToHue; exports.withPaintPlayback = withPaintPlayback;
9423
+
9424
+
9425
+
9426
+
9427
+
9428
+
9429
+ exports.BLEND_MENU_GROUPS = BLEND_MENU_GROUPS; exports.BLEND_MODES = _chunkOLNIPTB3cjs.BLEND_MODES; exports.BRUSH_ID = _chunkGNZI3KYKcjs.BRUSH_ID; exports.BRUSH_ROTATIONS = _chunkGNZI3KYKcjs.BRUSH_ROTATIONS; exports.BRUSH_SLIDERS = BRUSH_SLIDERS; exports.BUILTIN_BRUSHES = _chunkGNZI3KYKcjs.BUILTIN_BRUSHES; exports.BristleStroke = _chunkGNZI3KYKcjs.BristleStroke; exports.DEFAULT_BEHAVIOR = _chunkGNZI3KYKcjs.DEFAULT_BEHAVIOR; exports.DEFAULT_BRISTLE = _chunkGNZI3KYKcjs.DEFAULT_BRISTLE; exports.DEFAULT_BRUSH_ID = _chunkGNZI3KYKcjs.DEFAULT_BRUSH_ID; exports.DEFAULT_DPI = DEFAULT_DPI; exports.DEFAULT_DYNAMICS = _chunkGNZI3KYKcjs.DEFAULT_DYNAMICS; exports.DEFAULT_FLOW = _chunkXFYLA3ZOcjs.DEFAULT_FLOW; exports.DEFAULT_IMPASTO = _chunkGNZI3KYKcjs.DEFAULT_IMPASTO; exports.DEFAULT_LIGHTING = DEFAULT_LIGHTING; exports.DEFAULT_MULTI_COLOR = _chunkGNZI3KYKcjs.DEFAULT_MULTI_COLOR; exports.DEFAULT_PAINT_GRADIENT = _chunkPQ3H2AANcjs.DEFAULT_PAINT_GRADIENT; exports.DEFAULT_PAINT_GRADIENT_MAPPING = _chunkPQ3H2AANcjs.DEFAULT_PAINT_GRADIENT_MAPPING; exports.DEFAULT_PAPER = _chunkGNZI3KYKcjs.DEFAULT_PAPER; exports.DEFAULT_PARTICLE = _chunkGNZI3KYKcjs.DEFAULT_PARTICLE; exports.DEFAULT_STICKER = _chunkGNZI3KYKcjs.DEFAULT_STICKER; exports.DEFAULT_SWATCHES = DEFAULT_SWATCHES; exports.DEFAULT_VIEW = DEFAULT_VIEW; exports.DEFAULT_WET_BRUSH = _chunkGNZI3KYKcjs.DEFAULT_WET_BRUSH; exports.DEFAULT_WET_PARAMS = _chunkXFYLA3ZOcjs.DEFAULT_WET_PARAMS; exports.DryStroke = _chunkGNZI3KYKcjs.DryStroke; exports.GPU_LEAD = GPU_LEAD; exports.GRAIN_PATTERNS = _chunkPQ3H2AANcjs.GRAIN_PATTERNS; exports.GRAIN_TILE = _chunkPQ3H2AANcjs.GRAIN_TILE; exports.HARMONY_KINDS = _chunkEUIDTZNQcjs.HARMONY_KINDS; exports.IDENTITY_AFFINE = IDENTITY_AFFINE; exports.IDENTITY_COPY = _chunkGNZI3KYKcjs.IDENTITY_COPY; exports.IMPASTO_TOOLS = _chunkGNZI3KYKcjs.IMPASTO_TOOLS; exports.IMPASTO_TOOL_LABELS = IMPASTO_TOOL_LABELS; exports.LIGHT_SLIDERS = LIGHT_SLIDERS; 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 = _chunkGNZI3KYKcjs.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 = _chunkGNZI3KYKcjs.PAINT_BRUSH_CATEGORIES; exports.PAINT_BRUSH_ENGINES = _chunkGNZI3KYKcjs.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 = _chunkGNZI3KYKcjs.PAPER_FAMILIES; exports.PAPER_LIBRARY = _chunkGNZI3KYKcjs.PAPER_LIBRARY; exports.PAPER_NODE_ID = PAPER_NODE_ID; exports.PAPER_SLIDERS = PAPER_SLIDERS; exports.PAPER_TARGET = PAPER_TARGET; exports.PARTICLE_KINDS = _chunkGNZI3KYKcjs.PARTICLE_KINDS; exports.PARTICLE_KIND_LABELS = PARTICLE_KIND_LABELS; exports.PARTICLE_RENDERS = _chunkGNZI3KYKcjs.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 = _chunkGNZI3KYKcjs.ParticleStroke; exports.PenDabWalker = _chunkGNZI3KYKcjs.PenDabWalker; exports.PenSmoother = _chunkGNZI3KYKcjs.PenSmoother; exports.PerspectiveSnapper = PerspectiveSnapper; exports.SNAP_DECIDE_DISTANCE = SNAP_DECIDE_DISTANCE; exports.STAMP_KINDS = _chunkGNZI3KYKcjs.STAMP_KINDS; exports.STAMP_LABELS = STAMP_LABELS; exports.STENCIL_KINDS = STENCIL_KINDS; exports.STENCIL_SHAPES = STENCIL_SHAPES; exports.STICKER_SLIDERS = STICKER_SLIDERS; exports.SYMMETRY_MODES = SYMMETRY_MODES; exports.StencilSnapper = StencilSnapper; exports.StickerSpray = _chunkGNZI3KYKcjs.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 = _chunkGNZI3KYKcjs.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 = _chunkGNZI3KYKcjs.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 = _chunkGNZI3KYKcjs.brushTakesPaint; exports.brushToJSON = _chunkGNZI3KYKcjs.brushToJSON; exports.buildTimeLapse = buildTimeLapse; exports.checkPaintEffectPlace = checkPaintEffectPlace; exports.clonePaper = _chunkGNZI3KYKcjs.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 = _chunkGNZI3KYKcjs.drawSticker; exports.drawWaterOverlay = drawWaterOverlay; exports.effectLayersToJSON = effectLayersToJSON; exports.effectPaintKey = _chunkGNZI3KYKcjs.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 = _chunkGNZI3KYKcjs.hexToRgb8; exports.hslToRgb = hslToRgb; exports.hsvToRgb = hsvToRgb; exports.hueToWheel = _chunkEUIDTZNQcjs.hueToWheel; exports.invertAffine = invertAffine; exports.isBlendMode = _chunkOLNIPTB3cjs.isBlendMode; exports.isGradientPaint = _chunkPQ3H2AANcjs.isGradientPaint; exports.isPaintEffectPaint = _chunkGNZI3KYKcjs.isPaintEffectPaint; exports.isPainterlyBlendMode = _chunkOLNIPTB3cjs.isPainterlyBlendMode; exports.isPalmTouch = isPalmTouch; exports.isWetBrush = _chunkGNZI3KYKcjs.isWetBrush; exports.isWetCapable = _chunkGNZI3KYKcjs.isWetCapable; exports.lightTile = lightTile; exports.lightingKey = lightingKey; exports.mapPenPoint = mapPenPoint; exports.mix32 = _chunkPQ3H2AANcjs.mix32; exports.mixPixels = mixPixels; exports.mixerLoadForStroke = mixerLoadForStroke; exports.mixerTip = _chunkGNZI3KYKcjs.mixerTip; exports.multiColorForDab = multiColorForDab; exports.multiColorGradient = multiColorGradient; exports.multiColorPalette = multiColorPalette; exports.multiColorSliders = multiColorSliders; exports.multiColorToPaint = _chunkGNZI3KYKcjs.multiColorToPaint; exports.newPaintLayerId = newPaintLayerId; exports.nextPaperEffectVersion = nextPaperEffectVersion; exports.normalizeBehavior = _chunkGNZI3KYKcjs.normalizeBehavior; exports.normalizeBristle = _chunkGNZI3KYKcjs.normalizeBristle; exports.normalizeBrushStroke = normalizeBrushStroke; exports.normalizeCanvas = normalizeCanvas; exports.normalizeDynamics = _chunkGNZI3KYKcjs.normalizeDynamics; exports.normalizeFlow = _chunkXFYLA3ZOcjs.normalizeFlow; exports.normalizeHexColor = _chunkPQ3H2AANcjs.normalizeHexColor; exports.normalizeImpasto = _chunkGNZI3KYKcjs.normalizeImpasto; exports.normalizeLighting = normalizeLighting; exports.normalizeMultiColor = _chunkGNZI3KYKcjs.normalizeMultiColor; exports.normalizePaintBrush = _chunkGNZI3KYKcjs.normalizePaintBrush; exports.normalizePaper = _chunkGNZI3KYKcjs.normalizePaper; exports.normalizeParticle = _chunkGNZI3KYKcjs.normalizeParticle; exports.normalizePerspective = normalizePerspective; exports.normalizeRotation = normalizeRotation; exports.normalizeStencil = normalizeStencil; exports.normalizeStickerSettings = _chunkGNZI3KYKcjs.normalizeStickerSettings; exports.normalizeStickerUpdate = _chunkGNZI3KYKcjs.normalizeStickerUpdate; exports.normalizeSymmetry = normalizeSymmetry; exports.normalizeView = normalizeView; exports.normalizeWetBrush = _chunkGNZI3KYKcjs.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 = _chunkGNZI3KYKcjs.paintToMultiColor; exports.paperEffectFromJSON = paperEffectFromJSON; exports.paperEffectToJSON = paperEffectToJSON; exports.paperGrain = paperGrain; exports.paperKey = paperKey; exports.paperNode = paperNode; exports.paperPreset = _chunkGNZI3KYKcjs.paperPreset; exports.parseBrushLibrary = _chunkGNZI3KYKcjs.parseBrushLibrary; exports.parseHexColor = parseHexColor; exports.parsePaintSource = _chunkPQ3H2AANcjs.parsePaintSource; exports.patchBrushValue = patchBrushValue; exports.patchPath = patchPath; exports.penOrientation = _chunkGNZI3KYKcjs.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 = _chunkGNZI3KYKcjs.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 = _chunkGNZI3KYKcjs.renderPaper; exports.renderStickers = _chunkGNZI3KYKcjs.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 = _chunkGNZI3KYKcjs.sampleEffectAt; exports.sampleEffectField = _chunkGNZI3KYKcjs.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 = _chunkGNZI3KYKcjs.stampCoverage; exports.standardBlendMode = _chunkOLNIPTB3cjs.standardBlendMode; exports.startWetClock = startWetClock; exports.stencilMask = stencilMask; exports.stencilOutline = stencilOutline; exports.stickerRect = _chunkGNZI3KYKcjs.stickerRect; exports.stickerSurface = _chunkGNZI3KYKcjs.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 = _chunkGNZI3KYKcjs.tiltToOrientation; exports.timeLapseVideo = timeLapseVideo; exports.timeLapseZip = timeLapseZip; exports.toStrokePoint = _chunkGNZI3KYKcjs.toStrokePoint; exports.toggleStamp = toggleStamp; exports.translateStencil = translateStencil; exports.updatePaintGradientStop = _chunkPQ3H2AANcjs.updatePaintGradientStop; exports.usesPaintExchange = _chunkGNZI3KYKcjs.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 = _chunkEUIDTZNQcjs.wheelToHue; exports.withPaintPlayback = withPaintPlayback;