@pixerate/editor 0.125.0 → 0.127.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 (124) hide show
  1. package/dist/animation/index.d.cts +2 -3
  2. package/dist/animation/index.d.ts +2 -3
  3. package/dist/animation-editor/index.cjs +71 -73
  4. package/dist/animation-editor/index.cjs.map +1 -1
  5. package/dist/animation-editor/index.d.cts +6 -8
  6. package/dist/animation-editor/index.d.ts +6 -8
  7. package/dist/animation-editor/index.js +11 -13
  8. package/dist/animation-editor/index.js.map +1 -1
  9. package/dist/{bezier-CBzKKDjl.d.cts → bezier-DBz0IgEt.d.cts} +22 -2
  10. package/dist/{bezier-CWv6LQal.d.ts → bezier-DWI5MEkI.d.ts} +22 -2
  11. package/dist/{brushstrokeRender-LRV7GXGD.js → brushstrokeRender-7RUITO42.js} +3 -3
  12. package/dist/{brushstrokeRender-EELTV7U4.cjs → brushstrokeRender-OW6ENCZG.cjs} +7 -7
  13. package/dist/{brushstrokeRender-EELTV7U4.cjs.map → brushstrokeRender-OW6ENCZG.cjs.map} +1 -1
  14. package/dist/canvas/index.cjs +423 -37
  15. package/dist/canvas/index.cjs.map +1 -1
  16. package/dist/canvas/index.d.cts +189 -11
  17. package/dist/canvas/index.d.ts +189 -11
  18. package/dist/canvas/index.js +395 -9
  19. package/dist/canvas/index.js.map +1 -1
  20. package/dist/{chunk-7LQO6OHH.cjs → chunk-33SO3QWP.cjs} +4 -4
  21. package/dist/{chunk-7LQO6OHH.cjs.map → chunk-33SO3QWP.cjs.map} +1 -1
  22. package/dist/{chunk-MPQAO33O.js → chunk-A6KHMKI4.js} +3 -3
  23. package/dist/{chunk-V5YGPRCZ.cjs → chunk-BEGEWQHD.cjs} +41 -41
  24. package/dist/{chunk-V5YGPRCZ.cjs.map → chunk-BEGEWQHD.cjs.map} +1 -1
  25. package/dist/{chunk-N3FVUOZD.cjs → chunk-BJTCSLF6.cjs} +7 -7
  26. package/dist/{chunk-N3FVUOZD.cjs.map → chunk-BJTCSLF6.cjs.map} +1 -1
  27. package/dist/{chunk-WUDPFWAN.js → chunk-F7Q2NE2Y.js} +3 -3
  28. package/dist/{chunk-G6WXWS4Y.js → chunk-FICSDDDF.js} +2 -2
  29. package/dist/{chunk-GUZ47CJM.cjs → chunk-IZ4WRXZA.cjs} +1 -1
  30. package/dist/{chunk-GUZ47CJM.cjs.map → chunk-IZ4WRXZA.cjs.map} +1 -1
  31. package/dist/{chunk-QDJKUBWE.cjs → chunk-JODTP4DP.cjs} +176 -5
  32. package/dist/chunk-JODTP4DP.cjs.map +1 -0
  33. package/dist/{chunk-GLWZXQ4Q.js → chunk-KHNZ6MOU.js} +1 -1
  34. package/dist/chunk-KHNZ6MOU.js.map +1 -0
  35. package/dist/{chunk-GCJWMEYW.cjs → chunk-KSJLDRHK.cjs} +46 -46
  36. package/dist/{chunk-GCJWMEYW.cjs.map → chunk-KSJLDRHK.cjs.map} +1 -1
  37. package/dist/{chunk-QQKTOA4U.cjs → chunk-ORE334I6.cjs} +132 -132
  38. package/dist/{chunk-QQKTOA4U.cjs.map → chunk-ORE334I6.cjs.map} +1 -1
  39. package/dist/{chunk-X6KTSFAE.js → chunk-Q4NBEVV5.js} +2 -2
  40. package/dist/{chunk-XZWOLXWA.js → chunk-QFSTQHZY.js} +174 -3
  41. package/dist/chunk-QFSTQHZY.js.map +1 -0
  42. package/dist/{chunk-FPRIUR4T.js → chunk-ROZFX4QI.js} +3 -3
  43. package/dist/{chunk-UXFI3CDZ.cjs → chunk-SFCPGMCT.cjs} +8 -8
  44. package/dist/{chunk-UXFI3CDZ.cjs.map → chunk-SFCPGMCT.cjs.map} +1 -1
  45. package/dist/{chunk-J67OLQUQ.js → chunk-UABQTYQF.js} +3 -3
  46. package/dist/{chunk-O5RVCDEC.cjs → chunk-XLUYXUBD.cjs} +88 -88
  47. package/dist/{chunk-O5RVCDEC.cjs.map → chunk-XLUYXUBD.cjs.map} +1 -1
  48. package/dist/{chunk-FG274FYT.js → chunk-YGJIER2R.js} +2 -2
  49. package/dist/effects/index.cjs +32 -34
  50. package/dist/effects/index.cjs.map +1 -1
  51. package/dist/effects/index.d.cts +6 -38
  52. package/dist/effects/index.d.ts +6 -38
  53. package/dist/effects/index.js +3 -5
  54. package/dist/effects/index.js.map +1 -1
  55. package/dist/evaluate-BbCeF6pt.d.ts +114 -0
  56. package/dist/evaluate-BsxYieLN.d.cts +114 -0
  57. package/dist/{export-DVl4fWy5.d.cts → export-Cbr9IqpJ.d.cts} +1 -1
  58. package/dist/{export-Bp7ji2r4.d.cts → export-CcldobdN.d.cts} +3 -3
  59. package/dist/{export-C1s4eolZ.d.ts → export-ClPKUB-v.d.ts} +1 -1
  60. package/dist/{export-DAyPY94f.d.ts → export-PGhOpDmz.d.ts} +3 -3
  61. package/dist/{helpers-i95Ob6Vi.d.cts → helpers-C5aAd44p.d.cts} +67 -4
  62. package/dist/{helpers-BBLlekuM.d.ts → helpers-CPWcK504.d.ts} +67 -4
  63. package/dist/image-editor/index.cjs +619 -621
  64. package/dist/image-editor/index.cjs.map +1 -1
  65. package/dist/image-editor/index.d.cts +9 -11
  66. package/dist/image-editor/index.d.ts +9 -11
  67. package/dist/image-editor/index.js +6 -8
  68. package/dist/image-editor/index.js.map +1 -1
  69. package/dist/{opentype-14PDI5D2.d.ts → opentype-01rMIuQR.d.ts} +1 -1
  70. package/dist/{opentype-D80AVmMu.d.cts → opentype-BgqvmGT-.d.cts} +1 -1
  71. package/dist/paint-editor/index.cjs +737 -117
  72. package/dist/paint-editor/index.cjs.map +1 -1
  73. package/dist/paint-editor/index.d.cts +248 -13
  74. package/dist/paint-editor/index.d.ts +248 -13
  75. package/dist/paint-editor/index.js +635 -15
  76. package/dist/paint-editor/index.js.map +1 -1
  77. package/dist/{pathfinder-DjISxkUv.d.ts → pathfinder-D-h0Imus.d.ts} +1 -1
  78. package/dist/{pathfinder-C0UoFypx.d.cts → pathfinder-DgG0Z9Lr.d.cts} +1 -1
  79. package/dist/{player-cGLrngL_.d.ts → player-BK2kKbfd.d.ts} +1 -1
  80. package/dist/{player-CBtEoU2x.d.cts → player-CmbY3218.d.cts} +1 -1
  81. package/dist/pool-C7GtrL34.d.cts +34 -0
  82. package/dist/pool-CTrtciaN.d.ts +34 -0
  83. package/dist/{svg-DJKriJ4A.d.ts → svg-BRLwcibA.d.ts} +2 -3
  84. package/dist/{svg-BkRL-fZJ.d.cts → svg-DLBBPQP9.d.cts} +2 -3
  85. package/dist/{tools-CM8Oe8F3.d.ts → tools-AugT22z3.d.ts} +1 -1
  86. package/dist/{tools-DZCv2kX1.d.cts → tools-BpCmUNxb.d.cts} +1 -1
  87. package/dist/vector/index.cjs +923 -925
  88. package/dist/vector/index.cjs.map +1 -1
  89. package/dist/vector/index.d.cts +10 -12
  90. package/dist/vector/index.d.ts +10 -12
  91. package/dist/vector/index.js +11 -13
  92. package/dist/vector/index.js.map +1 -1
  93. package/dist/video-editor/index.cjs +269 -271
  94. package/dist/video-editor/index.cjs.map +1 -1
  95. package/dist/video-editor/index.d.cts +6 -8
  96. package/dist/video-editor/index.d.ts +6 -8
  97. package/dist/video-editor/index.js +3 -5
  98. package/dist/video-editor/index.js.map +1 -1
  99. package/dist/{warp-CH9MM435.d.cts → warp-C13L_GRn.d.cts} +1 -1
  100. package/dist/{warp-k_PdtXOG.d.ts → warp-q8FK5HHi.d.ts} +1 -1
  101. package/package.json +1 -1
  102. package/skills/pixerate-canvas/SKILL.md +19 -0
  103. package/skills/pixerate-paint-editor/SKILL.md +40 -1
  104. package/dist/behavior-Ymbld6jL.d.cts +0 -60
  105. package/dist/behavior-Ymbld6jL.d.ts +0 -60
  106. package/dist/chunk-GLWZXQ4Q.js.map +0 -1
  107. package/dist/chunk-IOXKXQNW.cjs +0 -178
  108. package/dist/chunk-IOXKXQNW.cjs.map +0 -1
  109. package/dist/chunk-QDJKUBWE.cjs.map +0 -1
  110. package/dist/chunk-TGKT5QAB.js +0 -178
  111. package/dist/chunk-TGKT5QAB.js.map +0 -1
  112. package/dist/chunk-XZWOLXWA.js.map +0 -1
  113. package/dist/evaluate-2S3vSPLy.d.cts +0 -55
  114. package/dist/evaluate-CfmT6xA3.d.ts +0 -55
  115. package/dist/gradient-KDfCvhuj.d.cts +0 -66
  116. package/dist/gradient-KDfCvhuj.d.ts +0 -66
  117. /package/dist/{brushstrokeRender-LRV7GXGD.js.map → brushstrokeRender-7RUITO42.js.map} +0 -0
  118. /package/dist/{chunk-MPQAO33O.js.map → chunk-A6KHMKI4.js.map} +0 -0
  119. /package/dist/{chunk-WUDPFWAN.js.map → chunk-F7Q2NE2Y.js.map} +0 -0
  120. /package/dist/{chunk-G6WXWS4Y.js.map → chunk-FICSDDDF.js.map} +0 -0
  121. /package/dist/{chunk-X6KTSFAE.js.map → chunk-Q4NBEVV5.js.map} +0 -0
  122. /package/dist/{chunk-FPRIUR4T.js.map → chunk-ROZFX4QI.js.map} +0 -0
  123. /package/dist/{chunk-J67OLQUQ.js.map → chunk-UABQTYQF.js.map} +0 -0
  124. /package/dist/{chunk-FG274FYT.js.map → chunk-YGJIER2R.js.map} +0 -0
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4; var _class5; var _class6; var _class7; var _class8; var _class9; var _class10; var _class11;
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4; var _class5; var _class6; var _class7; var _class8; var _class9; var _class10; var _class11; var _class12;
2
2
 
3
3
 
4
4
 
@@ -73,16 +73,18 @@
73
73
  var _chunkW4LNKTHTcjs = require('../chunk-W4LNKTHT.cjs');
74
74
 
75
75
 
76
- var _chunkUXFI3CDZcjs = require('../chunk-UXFI3CDZ.cjs');
76
+ var _chunkSFCPGMCTcjs = require('../chunk-SFCPGMCT.cjs');
77
77
 
78
78
 
79
79
 
80
80
 
81
81
 
82
82
 
83
- var _chunkO5RVCDECcjs = require('../chunk-O5RVCDEC.cjs');
83
+ var _chunkXLUYXUBDcjs = require('../chunk-XLUYXUBD.cjs');
84
84
  require('../chunk-2YQONY6G.cjs');
85
- require('../chunk-W6QTLHZ3.cjs');
85
+
86
+
87
+ var _chunkW6QTLHZ3cjs = require('../chunk-W6QTLHZ3.cjs');
86
88
 
87
89
 
88
90
 
@@ -209,10 +211,15 @@ var _chunkCOAMRKVIcjs = require('../chunk-COAMRKVI.cjs');
209
211
 
210
212
 
211
213
  var _chunkEGFUVXKKcjs = require('../chunk-EGFUVXKK.cjs');
212
- require('../chunk-QQKTOA4U.cjs');
213
- require('../chunk-IOXKXQNW.cjs');
214
- require('../chunk-N3FVUOZD.cjs');
215
- require('../chunk-GUZ47CJM.cjs');
214
+ require('../chunk-ORE334I6.cjs');
215
+ require('../chunk-BJTCSLF6.cjs');
216
+ require('../chunk-IZ4WRXZA.cjs');
217
+
218
+
219
+
220
+
221
+
222
+ var _chunkJODTP4DPcjs = require('../chunk-JODTP4DP.cjs');
216
223
  require('../chunk-RIWPYSKU.cjs');
217
224
  require('../chunk-EMQWJA3G.cjs');
218
225
  require('../chunk-MR3Z4OQI.cjs');
@@ -1483,6 +1490,7 @@ function varyStroke(stroke, m, v) {
1483
1490
  // src/paint-editor/render.ts
1484
1491
  var PAPER_NODE_ID = "__paper";
1485
1492
  var TRACING_NODE_ID = "__tracing";
1493
+ var PAPER_EFFECT_NODE_ID = "__paper_effect";
1486
1494
  function paperKey(p, light) {
1487
1495
  const metal = _nullishCoalesce(p.metallic, () => ( 0));
1488
1496
  return JSON.stringify([p.pattern, p.seed, p.color, p.scale, p.tiling, p.shading, p.dry, metal, metal > 0 && light ? [light.azimuth, light.elevation] : null]);
@@ -1617,11 +1625,11 @@ function header(state, options) {
1617
1625
  return out;
1618
1626
  }
1619
1627
  function serializePaintDocument(state, options = {}) {
1620
- const { layers, assets } = _chunkO5RVCDECcjs.serializeLayers.call(void 0, state.layers);
1628
+ const { layers, assets } = _chunkXLUYXUBDcjs.serializeLayers.call(void 0, state.layers);
1621
1629
  return { ...header(state, options), layers, assets };
1622
1630
  }
1623
1631
  async function serializePaintDocumentExternal(state, store, options = {}) {
1624
- const { layers, assets } = await _chunkO5RVCDECcjs.serializeLayersExternal.call(void 0, state.layers, store);
1632
+ const { layers, assets } = await _chunkXLUYXUBDcjs.serializeLayersExternal.call(void 0, state.layers, store);
1625
1633
  return { ...header(state, options), layers, assets };
1626
1634
  }
1627
1635
  function paintLayersOnly(layers, problems) {
@@ -1658,7 +1666,7 @@ function deserializePaintDocument(raw) {
1658
1666
  const canvas = normalizeCanvas({ width: r.width, height: r.height, dpi: _nullishCoalesce(r.dpi, () => ( void 0)) });
1659
1667
  const paper = _chunkW4LNKTHTcjs.normalizePaper.call(void 0, _nullishCoalesce(r.paper, () => ( {})));
1660
1668
  const assets = r.assets && typeof r.assets === "object" ? r.assets : {};
1661
- const layers = paintLayersOnly(_chunkO5RVCDECcjs.deserializeLayers.call(void 0, r.layers, { assets, problems }), problems);
1669
+ const layers = paintLayersOnly(_chunkXLUYXUBDcjs.deserializeLayers.call(void 0, r.layers, { assets, problems }), problems);
1662
1670
  const wanted = typeof r.activeLayerId === "string" ? r.activeLayerId : null;
1663
1671
  const activeLayerId = wanted && _chunkMZXQTKUMcjs.findLayer.call(void 0, layers, wanted) ? wanted : _nullishCoalesce(_optionalChain([_chunkMZXQTKUMcjs.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));
1664
1672
  const wetEvents = Array.isArray(r.wetEvents) ? r.wetEvents.filter((e) => e && typeof e === "object" && Number.isInteger(e.clock) && typeof e.kind === "string") : [];
@@ -1672,7 +1680,7 @@ async function deserializePaintDocumentAsync(raw, store) {
1672
1680
  if (!raw || typeof raw !== "object") throw new Error("Not a paint document: expected a JSON object.");
1673
1681
  const r = raw;
1674
1682
  const problems = [];
1675
- const assets = await _chunkO5RVCDECcjs.resolveExternalAssets.call(void 0, _nullishCoalesce(r.assets, () => ( {})), store, problems);
1683
+ const assets = await _chunkXLUYXUBDcjs.resolveExternalAssets.call(void 0, _nullishCoalesce(r.assets, () => ( {})), store, problems);
1676
1684
  const loaded = deserializePaintDocument({ ...r, assets });
1677
1685
  return { ...loaded, problems: [...problems, ...loaded.problems] };
1678
1686
  }
@@ -3161,7 +3169,7 @@ function timeLapseVideo(frameCount, width, height, fps, holdMs, name = "Time-lap
3161
3169
  }
3162
3170
  const video = { version: 1, name, width: w, height: h, fps, background: "#000000", assets, tracks: [{ id: "v1", kind: "video", clips }] };
3163
3171
  const durationMs = frameCount ? clips[clips.length - 1].start + clips[clips.length - 1].duration : 0;
3164
- return { video, ffmpeg: _chunkUXFI3CDZcjs.toVideoFfmpeg.call(void 0, video, { output: "timelapse.mp4" }), durationMs };
3172
+ return { video, ffmpeg: _chunkSFCPGMCTcjs.toVideoFfmpeg.call(void 0, video, { output: "timelapse.mp4" }), durationMs };
3165
3173
  }
3166
3174
  async function buildTimeLapse(source, target, options = {}) {
3167
3175
  const maxSide = Math.max(32, Math.min(4096, Math.round(_nullishCoalesce(options.maxSide, () => ( 720)))));
@@ -3216,6 +3224,130 @@ ${tl.ffmpeg.command}
3216
3224
  return _chunkCOAMRKVIcjs.writeZip.call(void 0, entries, { compression: "store" });
3217
3225
  }
3218
3226
 
3227
+ // src/paint-editor/effects.ts
3228
+ var PAINT_EFFECT_PLACES = {
3229
+ /** Effect paper: drawn over the whole sheet. */
3230
+ paper: ["generator"],
3231
+ /** An effect layer: drawn at the canvas size. */
3232
+ layer: ["generator", "overlay", "title"],
3233
+ /** An effect fill: composited onto a layer's pixels. */
3234
+ fill: ["generator", "overlay", "title"],
3235
+ /** Light (or any filter) on a layer's dried paint. */
3236
+ light: ["filter"]
3237
+ };
3238
+ var PLACE_WORDS = {
3239
+ paper: "effect paper takes generator effects",
3240
+ layer: "an effect layer takes generator, overlay or title effects",
3241
+ fill: "an effect fill takes generator, overlay or title effects",
3242
+ light: "light on dried paint takes filter effects"
3243
+ };
3244
+ function checkPaintEffectPlace(d, place) {
3245
+ const allowed = PAINT_EFFECT_PLACES[place];
3246
+ if (d.kind !== "motion" && d.kind !== "vector" && d.uses.some((u) => allowed.includes(u))) return;
3247
+ let instead = "";
3248
+ if (d.uses.includes("filter") && place !== "light") instead = "; run it on a layer's dried paint with apply_effect instead";
3249
+ 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";
3250
+ else if (place === "paper" && d.uses.some((u) => u === "overlay" || u === "title")) instead = "; add it as an effect layer with add_effect_layer instead";
3251
+ throw new (0, _chunkJODTP4DPcjs.EffectUnsupportedError)(`"${d.id}" (${d.name}) is a ${d.uses.join(" / ") || d.kind} effect, and ${PLACE_WORDS[place]}${instead}.`, d.id);
3252
+ }
3253
+ var PAPER_EFFECT_BLENDS = ["multiply", "normal", "overlay", "soft-light", "screen", "color"];
3254
+ var paperVersion = 1;
3255
+ function nextPaperEffectVersion() {
3256
+ return paperVersion++;
3257
+ }
3258
+ function overPixels(base, top, opacity = 1) {
3259
+ const out = new Uint8ClampedArray(base.length);
3260
+ for (let i = 0; i < out.length; i += 4) {
3261
+ const ta = top[i + 3] / 255 * opacity;
3262
+ const ba = base[i + 3] / 255;
3263
+ const a = ta + ba * (1 - ta);
3264
+ out[i + 3] = Math.round(a * 255);
3265
+ if (a > 0) for (let c = 0; c < 3; c++) out[i + c] = (top[i + c] * ta + base[i + c] * ba * (1 - ta)) / a;
3266
+ }
3267
+ return out;
3268
+ }
3269
+ function mixPixels(before, after, amount) {
3270
+ const out = new Uint8ClampedArray(before.length);
3271
+ for (let i = 0; i < out.length; i += 4) {
3272
+ for (let c = 0; c < 3; c++) out[i + c] = before[i + c] + (after[i + c] - before[i + c]) * amount;
3273
+ out[i + 3] = before[i + 3];
3274
+ }
3275
+ return out;
3276
+ }
3277
+ var PaintEffectsRenderer = (_class9 = class {constructor() { _class9.prototype.__init69.call(this);_class9.prototype.__init70.call(this);_class9.prototype.__init71.call(this); }
3278
+ __init69() {this.pool = new (0, _chunkW6QTLHZ3cjs.EffectRendererPool)({ maxRenderers: 3 })}
3279
+ __init70() {this.descriptions = /* @__PURE__ */ new Map()}
3280
+ __init71() {this.provider = null}
3281
+ /** Forgets cached descriptions and renderers when the provider changes. */
3282
+ follow(provider) {
3283
+ if (provider === this.provider) return;
3284
+ this.provider = provider;
3285
+ this.descriptions.clear();
3286
+ this.pool.clear();
3287
+ }
3288
+ describe(provider, id) {
3289
+ this.follow(provider);
3290
+ let d = this.descriptions.get(id);
3291
+ if (!d) {
3292
+ d = Promise.resolve().then(() => provider.describe(id));
3293
+ d.catch(() => this.descriptions.delete(id));
3294
+ this.descriptions.set(id, d);
3295
+ }
3296
+ return d;
3297
+ }
3298
+ async render(provider, id, size, request) {
3299
+ this.follow(provider);
3300
+ const out = await this.pool.render(provider, id, { ...size, depth: 8 }, request);
3301
+ if (out.width !== size.width || out.height !== size.height || out.data.length !== size.width * size.height * 4) {
3302
+ throw new Error(`The effect "${id}" returned ${out.width}\xD7${out.height} pixels for a ${size.width}\xD7${size.height} canvas.`);
3303
+ }
3304
+ return out;
3305
+ }
3306
+ dispose() {
3307
+ this.pool.clear();
3308
+ this.descriptions.clear();
3309
+ }
3310
+ }, _class9);
3311
+ var sourceOut = (s) => ({
3312
+ effect: s.effect,
3313
+ ...s.provider ? { provider: s.provider } : {},
3314
+ ...s.name ? { name: s.name } : {},
3315
+ values: JSON.parse(JSON.stringify(s.values)),
3316
+ ...s.time ? { time: s.time } : {}
3317
+ });
3318
+ function readPaintEffectSource(raw) {
3319
+ if (!raw || typeof raw !== "object") return null;
3320
+ const r = raw;
3321
+ if (typeof r.effect !== "string" || !r.effect || !r.values || typeof r.values !== "object" || Array.isArray(r.values)) return null;
3322
+ return {
3323
+ effect: r.effect,
3324
+ ...typeof r.provider === "string" ? { provider: r.provider } : {},
3325
+ ...typeof r.name === "string" ? { name: r.name } : {},
3326
+ values: r.values,
3327
+ ...typeof r.time === "number" && r.time > 0 ? { time: r.time } : {}
3328
+ };
3329
+ }
3330
+ function paperEffectToJSON(p) {
3331
+ return { ...sourceOut(p), opacity: p.opacity, blend: p.blend, png: _chunkDCLJNVZScjs.pngDataUrl.call(void 0, p.image.width, p.image.height, p.image.data) };
3332
+ }
3333
+ function paperEffectFromJSON(raw, width, height) {
3334
+ const source = readPaintEffectSource(raw);
3335
+ if (!source) throw new Error("it is not an effect (effect id and values)");
3336
+ const r = raw;
3337
+ const parsed = typeof r.png === "string" ? _chunkDCLJNVZScjs.parseDataUrl.call(void 0, r.png) : null;
3338
+ if (!parsed) throw new Error("its pixels are missing");
3339
+ const image = _chunkDCLJNVZScjs.decodePng.call(void 0, parsed.bytes);
3340
+ if (image.width !== width || image.height !== height) throw new Error(`its pixels are ${image.width}\xD7${image.height}, not the canvas size ${width}\xD7${height}`);
3341
+ const opacity = typeof r.opacity === "number" && r.opacity >= 0 && r.opacity <= 1 ? r.opacity : 1;
3342
+ const blend = PAPER_EFFECT_BLENDS.includes(r.blend) ? r.blend : "multiply";
3343
+ return { ...source, opacity, blend, image: { width, height, data: new Uint8ClampedArray(image.data) }, version: nextPaperEffectVersion() };
3344
+ }
3345
+ function effectLayersToJSON(map, keep) {
3346
+ const out = {};
3347
+ for (const [id, s] of Object.entries(map)) if (keep(id)) out[id] = sourceOut(s);
3348
+ return Object.keys(out).length ? out : void 0;
3349
+ }
3350
+
3219
3351
  // src/paint-editor/controller.ts
3220
3352
  var PaintEditorError = class extends Error {
3221
3353
  constructor(message) {
@@ -3243,55 +3375,59 @@ function unionRect(a, b) {
3243
3375
  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 };
3244
3376
  }
3245
3377
  var isPixelLayer = (l) => _optionalChain([l, 'optionalAccess', _158 => _158.type]) === "pixel";
3246
- var PaintEditorController = (_class9 = class _PaintEditorController {
3378
+ var PaintEditorController = (_class10 = class _PaintEditorController {
3247
3379
 
3248
- __init69() {this.extensions = {}}
3249
- __init70() {this.undoStack = []}
3250
- __init71() {this.redoStack = []}
3380
+ __init72() {this.extensions = {}}
3381
+ __init73() {this.undoStack = []}
3382
+ __init74() {this.redoStack = []}
3251
3383
 
3252
3384
 
3253
3385
 
3254
3386
  /** The library list in the state (the same array until the user brushes change, so thumbnails are not redrawn). */
3255
- __init72() {this.library = null}
3387
+ __init75() {this.library = null}
3256
3388
 
3257
- __init73() {this.secondaryColor = "#ffffff"}
3389
+ __init76() {this.secondaryColor = "#ffffff"}
3258
3390
  /** Gradient paint chosen with `setPaint` (`null`: the paint colour). */
3259
- __init74() {this.gradient = null}
3260
- __init75() {this.mixerLoad = _chunk6GFRKLLScjs.EMPTY_MIXER_LOAD}
3261
- __init76() {this.view = { ...DEFAULT_VIEW, pan: { ...DEFAULT_VIEW.pan } }}
3391
+ __init77() {this.gradient = null}
3392
+ __init78() {this.mixerLoad = _chunk6GFRKLLScjs.EMPTY_MIXER_LOAD}
3393
+ __init79() {this.view = { ...DEFAULT_VIEW, pan: { ...DEFAULT_VIEW.pan } }}
3262
3394
 
3263
3395
 
3264
- __init77() {this.listeners = /* @__PURE__ */ new Set()}
3265
- __init78() {this.version = 0}
3266
- __init79() {this.cached = null}
3267
- __init80() {this.session = null}
3268
- __init81() {this.live = null}
3269
- __init82() {this.liveLayers = null}
3270
- __init83() {this.dirty = "all"}
3271
- __init84() {this.seedCounter = 1}
3272
- __init85() {this.strokeCounter = 1}
3396
+ __init80() {this.listeners = /* @__PURE__ */ new Set()}
3397
+ __init81() {this.version = 0}
3398
+ __init82() {this.cached = null}
3399
+ __init83() {this.session = null}
3400
+ __init84() {this.live = null}
3401
+ __init85() {this.liveLayers = null}
3402
+ __init86() {this.dirty = "all"}
3403
+ __init87() {this.seedCounter = 1}
3404
+ __init88() {this.strokeCounter = 1}
3273
3405
 
3274
- __init86() {this.swatches = DEFAULT_SWATCHES.map((s) => ({ ...s }))}
3275
- __init87() {this.pad = new MixingPad()}
3276
- __init88() {this.savedPads = []}
3277
- __init89() {this.nextPadId = 1}
3278
- __init90() {this.tracingVersion = 1}
3279
- __init91() {this.tracingCache = null}
3280
- __init92() {this.imagePixels = /* @__PURE__ */ new Map()}
3281
- __init93() {this.nextReferenceId = 1}
3282
- __init94() {this.viewCompositor = createPaintCompositor()}
3283
- __init95() {this.exportCompositor = createPaintCompositor()}
3406
+ __init89() {this.swatches = DEFAULT_SWATCHES.map((s) => ({ ...s }))}
3407
+ __init90() {this.pad = new MixingPad()}
3408
+ __init91() {this.savedPads = []}
3409
+ __init92() {this.nextPadId = 1}
3410
+ __init93() {this.tracingVersion = 1}
3411
+ __init94() {this.tracingCache = null}
3412
+ __init95() {this.imagePixels = /* @__PURE__ */ new Map()}
3413
+ __init96() {this.nextReferenceId = 1}
3414
+ __init97() {this.viewCompositor = createPaintCompositor()}
3415
+ __init98() {this.exportCompositor = createPaintCompositor()}
3284
3416
  /** Wet media: the simulation, its settings and time. */
3285
3417
 
3286
3418
 
3287
3419
  /** Where the light comes from for thick paint (saved with the document, not undo steps). */
3288
- __init96() {this.lighting = { ...DEFAULT_LIGHTING }}
3289
- __init97() {this.litCaches = /* @__PURE__ */ new Map()}
3420
+ __init99() {this.lighting = { ...DEFAULT_LIGHTING }}
3421
+ __init100() {this.litCaches = /* @__PURE__ */ new Map()}
3290
3422
  /** The live impasto stroke's channels. */
3291
- __init98() {this.liveThick = null}
3423
+ __init101() {this.liveThick = null}
3292
3424
  /** Set while an operation that changes wet paint runs: the simulation before it (for undo). */
3293
- __init99() {this.wetOp = null}
3294
- constructor(options = {}) {;_class9.prototype.__init69.call(this);_class9.prototype.__init70.call(this);_class9.prototype.__init71.call(this);_class9.prototype.__init72.call(this);_class9.prototype.__init73.call(this);_class9.prototype.__init74.call(this);_class9.prototype.__init75.call(this);_class9.prototype.__init76.call(this);_class9.prototype.__init77.call(this);_class9.prototype.__init78.call(this);_class9.prototype.__init79.call(this);_class9.prototype.__init80.call(this);_class9.prototype.__init81.call(this);_class9.prototype.__init82.call(this);_class9.prototype.__init83.call(this);_class9.prototype.__init84.call(this);_class9.prototype.__init85.call(this);_class9.prototype.__init86.call(this);_class9.prototype.__init87.call(this);_class9.prototype.__init88.call(this);_class9.prototype.__init89.call(this);_class9.prototype.__init90.call(this);_class9.prototype.__init91.call(this);_class9.prototype.__init92.call(this);_class9.prototype.__init93.call(this);_class9.prototype.__init94.call(this);_class9.prototype.__init95.call(this);_class9.prototype.__init96.call(this);_class9.prototype.__init97.call(this);_class9.prototype.__init98.call(this);_class9.prototype.__init99.call(this);_class9.prototype.__init100.call(this);_class9.prototype.__init101.call(this);_class9.prototype.__init102.call(this);
3425
+ __init102() {this.wetOp = null}
3426
+ /** The effects provider slot (see `setEffectsProvider`). */
3427
+ __init103() {this.effects = new (0, _chunkJODTP4DPcjs.EffectsSlot)()}
3428
+ __init104() {this.effectsRenderer = new PaintEffectsRenderer()}
3429
+ __init105() {this.paperEffectNodeCache = null}
3430
+ 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);
3295
3431
  this.historyLimit = Math.max(1, _nullishCoalesce(options.historyLimit, () => ( 200)));
3296
3432
  this.doc = createPaintDocument({ width: options.width, height: options.height, dpi: options.dpi, paper: this.resolvePaper(options.paper) });
3297
3433
  this.userBrushes = (_nullishCoalesce(options.brushes, () => ( []))).map((b) => _chunkW4LNKTHTcjs.normalizePaintBrush.call(void 0, { ...b, builtin: false }));
@@ -3404,6 +3540,21 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
3404
3540
  this.trimWetHistory();
3405
3541
  this.emit();
3406
3542
  }
3543
+ /**
3544
+ * Commits `next` as a new undo step, or with `commitToHistory` false folds it into the last step
3545
+ * when that step has the same label (the later values of one slider drag).
3546
+ */
3547
+ commitOrAmend(label, next, commitToHistory) {
3548
+ const last = this.undoStack[this.undoStack.length - 1];
3549
+ if (commitToHistory || !last || last.label !== label || last.wet || this.wetOp) {
3550
+ this.commit(label, next);
3551
+ return;
3552
+ }
3553
+ last.after = next;
3554
+ this.redoStack = [];
3555
+ this.doc = next;
3556
+ this.emit();
3557
+ }
3407
3558
  /** Keeps the wet snapshots in history within the wet undo memory, dropping the oldest. */
3408
3559
  trimWetHistory() {
3409
3560
  const seen = /* @__PURE__ */ new Set();
@@ -3440,7 +3591,7 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
3440
3591
  return wetIds;
3441
3592
  }
3442
3593
  /** Records a wet event (for replays) in the document being built. */
3443
- __init100() {this.pendingWetEvents = []}
3594
+ __init106() {this.pendingWetEvents = []}
3444
3595
  logWet(e) {
3445
3596
  this.pendingWetEvents.push({ clock: _nullishCoalesce(_optionalChain([this, 'access', _171 => _171.wet, 'access', _172 => _172.world, 'optionalAccess', _173 => _173.clock]), () => ( 0)), at: this.doc.strokes.length, ...e });
3446
3597
  }
@@ -3812,6 +3963,257 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
3812
3963
  }
3813
3964
  return new (0, _chunkJ5BA3BQ6cjs.TiledSurface)(4, tiles, 0);
3814
3965
  }
3966
+ // --- Provider effects ------------------------------------------------------------
3967
+ /** The registered effects provider, or `null`. */
3968
+ get effectsProvider() {
3969
+ return this.effects.provider;
3970
+ }
3971
+ /** Registers (or with `null` removes) the effects provider. Not an edit: no undo step. */
3972
+ setEffectsProvider(provider) {
3973
+ this.effects.set(provider);
3974
+ }
3975
+ /** Registers `provider` and returns a function that removes it again (if it is still the one set). */
3976
+ useEffects(provider) {
3977
+ return this.effects.use(provider);
3978
+ }
3979
+ /** The provider's description of an effect, checked for `place` (rejects without a provider or for an unknown id). */
3980
+ async describeEffect(effect, place) {
3981
+ const d = await this.effectsRenderer.describe(this.effects.require(), effect);
3982
+ if (place) checkPaintEffectPlace(d, place);
3983
+ return d;
3984
+ }
3985
+ /** Every effect layer (top first) with its effect. */
3986
+ listEffectLayers() {
3987
+ const map = _nullishCoalesce(this.doc.effectLayers, () => ( {}));
3988
+ return this.listLayers().filter((l) => map[l.id]).map((l) => ({ layerId: l.id, name: l.name, source: map[l.id] }));
3989
+ }
3990
+ /** The effect a layer is drawn from, or `undefined` for other layers. */
3991
+ getEffectLayer(layerId) {
3992
+ return _chunkMZXQTKUMcjs.findLayer.call(void 0, this.doc.layers, layerId) ? _optionalChain([this, 'access', _203 => _203.doc, 'access', _204 => _204.effectLayers, 'optionalAccess', _205 => _205[layerId]]) : void 0;
3993
+ }
3994
+ /** The effect paper (without its pixels), or `null`. */
3995
+ getPaperEffect() {
3996
+ const p = this.doc.paperEffect;
3997
+ if (!p) return null;
3998
+ const { image: _i, version: _v, ...rest } = p;
3999
+ return { ...rest, values: { ...rest.values } };
4000
+ }
4001
+ /** Values over `base` (`null` resets a control to its default), checked against the effect's controls. */
4002
+ effectValues(d, base, changes) {
4003
+ const merged = { ...base };
4004
+ const given = {};
4005
+ for (const [k, v] of Object.entries(_nullishCoalesce(changes, () => ( {})))) {
4006
+ if (!(k in d.controls.properties)) throw new PaintEditorError(`"${k}" is not a control of "${d.id}"; its controls are ${Object.keys(d.controls.properties).join(", ") || "none"} (describe_effect).`);
4007
+ if (v === null) merged[k] = d.defaults[k];
4008
+ else given[k] = v;
4009
+ }
4010
+ return { ...merged, ..._chunkJODTP4DPcjs.resolveEffectValues.call(void 0, { ...d, defaults: merged }, given) };
4011
+ }
4012
+ /** Renders a generator, overlay or title effect at the canvas size. */
4013
+ renderEffectCanvas(d, values, time = 0) {
4014
+ const { width, height } = this.doc.canvas;
4015
+ return this.effectsRenderer.render(this.effects.require(), d.id, { width, height }, { time, values });
4016
+ }
4017
+ sourceOf(d, values, time) {
4018
+ return { effect: d.id, provider: this.effects.require().id, name: d.name, values, ...time ? { time } : {} };
4019
+ }
4020
+ checkTime(time) {
4021
+ if (time !== void 0 && !(Number.isFinite(time) && time >= 0)) throw new PaintEditorError(`time ${time} is not a moment of the effect; use 0 or more milliseconds.`);
4022
+ }
4023
+ checkOpacity(opacity) {
4024
+ if (opacity !== void 0 && !(opacity >= 0 && opacity <= 1)) throw new PaintEditorError(`opacity ${opacity} is out of range; use 0..1.`);
4025
+ }
4026
+ /** A pixel layer that takes effect pixels: unlocked, visible, no sticker layer, no wet paint. */
4027
+ effectTarget(layerId, what) {
4028
+ const l = this.paintTarget(layerId, what);
4029
+ if (_optionalChain([this, 'access', _206 => _206.doc, 'access', _207 => _207.stickers, 'optionalAccess', _208 => _208[l.id], 'optionalAccess', _209 => _209.length])) throw new PaintEditorError(`Layer "${l.name}" is a sticker layer; ${what} another layer (add_layer).`);
4030
+ 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.`);
4031
+ return l;
4032
+ }
4033
+ /** After an effect rendered: the layer must be as it was when the render started. */
4034
+ sameLayerAfterRender(before) {
4035
+ this.requireIdle("applying an effect");
4036
+ const now = this.getLayer(before.id);
4037
+ if (!isPixelLayer(now)) throw new PaintEditorError(`Layer "${before.name}" was removed while the effect rendered.`);
4038
+ if (now.surface !== before.surface || now.offset.x !== before.offset.x || now.offset.y !== before.offset.y) throw new PaintEditorError(`Layer "${before.name}" changed while the effect rendered; apply the effect again.`);
4039
+ return now;
4040
+ }
4041
+ /** The canvas rectangle in a layer's own coordinates. */
4042
+ canvasRectOf(l) {
4043
+ return { x: -l.offset.x, y: -l.offset.y, width: this.doc.canvas.width, height: this.doc.canvas.height };
4044
+ }
4045
+ /**
4046
+ * Sets the effect paper: a provider generator drawn over the paper and under the paint, at the
4047
+ * canvas size (`multiply` by default, so the paper's colour and grain still show). `null` removes
4048
+ * it. One undo step. Returns the effect paper (without pixels), or `null`.
4049
+ */
4050
+ async setPaperEffect(effect, options = {}) {
4051
+ this.requireIdle("changing the paper");
4052
+ if (effect === null) {
4053
+ if (!this.doc.paperEffect) return null;
4054
+ const { paperEffect: _p, ...rest } = this.doc;
4055
+ this.commit("Remove effect paper", rest);
4056
+ return null;
4057
+ }
4058
+ this.checkOpacity(options.opacity);
4059
+ this.checkTime(options.time);
4060
+ if (options.blend !== void 0 && !PAPER_EFFECT_BLENDS.includes(options.blend)) throw new PaintEditorError(`Unknown effect paper blend "${options.blend}"; use ${PAPER_EFFECT_BLENDS.join(", ")}.`);
4061
+ const d = await this.describeEffect(effect, "paper");
4062
+ const values = this.effectValues(d, { ...d.defaults }, options.values);
4063
+ const pixels = await this.renderEffectCanvas(d, values, options.time);
4064
+ this.requireIdle("changing the paper");
4065
+ const was = this.doc.paperEffect;
4066
+ const paperEffect = {
4067
+ ...this.sourceOf(d, values, options.time),
4068
+ opacity: _nullishCoalesce(_nullishCoalesce(options.opacity, () => ( _optionalChain([was, 'optionalAccess', _210 => _210.opacity]))), () => ( 1)),
4069
+ blend: _nullishCoalesce(_nullishCoalesce(options.blend, () => ( _optionalChain([was, 'optionalAccess', _211 => _211.blend]))), () => ( "multiply")),
4070
+ image: { width: pixels.width, height: pixels.height, data: new Uint8ClampedArray(pixels.data) },
4071
+ version: nextPaperEffectVersion()
4072
+ };
4073
+ this.commit("Effect paper", { ...this.doc, paperEffect });
4074
+ return this.getPaperEffect();
4075
+ }
4076
+ /**
4077
+ * Changes the effect paper: new control `values` (merged over its own; `null` resets one) or
4078
+ * `time` draw it again at the canvas size; `opacity` and `blend` only change how it is drawn.
4079
+ * One undo step; with `commitToHistory` false it joins the previous effect paper step (a slider
4080
+ * drag). Returns the effect paper (without pixels).
4081
+ */
4082
+ async updatePaperEffect(changes, commitToHistory = true) {
4083
+ this.requireIdle("changing the paper");
4084
+ const was = this.doc.paperEffect;
4085
+ if (!was) throw new PaintEditorError("There is no effect paper; set one with set_paper_effect.");
4086
+ this.checkOpacity(changes.opacity);
4087
+ this.checkTime(changes.time);
4088
+ if (changes.blend !== void 0 && !PAPER_EFFECT_BLENDS.includes(changes.blend)) throw new PaintEditorError(`Unknown effect paper blend "${changes.blend}"; use ${PAPER_EFFECT_BLENDS.join(", ")}.`);
4089
+ let next = { ...was, ...changes.opacity !== void 0 ? { opacity: changes.opacity } : {}, ...changes.blend !== void 0 ? { blend: changes.blend } : {} };
4090
+ const { width, height } = this.doc.canvas;
4091
+ if (changes.values !== void 0 || changes.time !== void 0 || was.image.width !== width || was.image.height !== height) {
4092
+ const d = await this.describeEffect(was.effect, "paper");
4093
+ const values = this.effectValues(d, was.values, changes.values);
4094
+ const time = _nullishCoalesce(_nullishCoalesce(changes.time, () => ( was.time)), () => ( 0));
4095
+ const pixels = await this.renderEffectCanvas(d, values, time);
4096
+ this.requireIdle("changing the paper");
4097
+ if (this.doc.paperEffect !== was) throw new PaintEditorError("The effect paper changed while it rendered; change it again.");
4098
+ next = { ...next, ...this.sourceOf(d, values, time), image: { width: pixels.width, height: pixels.height, data: new Uint8ClampedArray(pixels.data) }, version: nextPaperEffectVersion() };
4099
+ if (!time) delete next.time;
4100
+ }
4101
+ this.commitOrAmend("Effect paper", { ...this.doc, paperEffect: next }, commitToHistory);
4102
+ return this.getPaperEffect();
4103
+ }
4104
+ /**
4105
+ * Adds an effect layer above the active layer (or `aboveId`): a pixel layer drawn by a provider
4106
+ * generator, overlay or title effect at the canvas size. It keeps its effect, so
4107
+ * `updateEffectLayer` draws it again. One undo step. Returns the layer and its effect.
4108
+ */
4109
+ async addEffectLayer(effect, options = {}) {
4110
+ this.requireIdle("adding a layer");
4111
+ this.checkOpacity(options.opacity);
4112
+ this.checkTime(options.time);
4113
+ if (options.blend !== void 0 && !_chunkJ5BA3BQ6cjs.isBlendMode.call(void 0, options.blend)) throw new PaintEditorError(`Unknown blend mode "${options.blend}". Call get_canvas_info for the blend modes.`);
4114
+ if (options.aboveId !== void 0) this.requireLayer(options.aboveId);
4115
+ const d = await this.describeEffect(effect, "layer");
4116
+ const values = this.effectValues(d, { ...d.defaults }, options.values);
4117
+ const pixels = await this.renderEffectCanvas(d, values, options.time);
4118
+ this.requireIdle("adding a layer");
4119
+ const above = _nullishCoalesce(options.aboveId, () => ( this.doc.activeLayerId));
4120
+ const loc = above ? _chunkMZXQTKUMcjs.findLayer.call(void 0, this.doc.layers, above) : null;
4121
+ if (options.aboveId !== void 0 && !loc) throw new PaintEditorError(`Layer "${options.aboveId}" was removed while the effect rendered.`);
4122
+ const layer = { ...createPaintLayer(_optionalChain([options, 'access', _212 => _212.name, 'optionalAccess', _213 => _213.trim, 'call', _214 => _214()]) || d.name), surface: _chunkJ5BA3BQ6cjs.surfaceFromPixels.call(void 0, pixels, 4), opacity: _nullishCoalesce(options.opacity, () => ( 1)), blend: _nullishCoalesce(options.blend, () => ( "normal")) };
4123
+ const layers = _chunkMZXQTKUMcjs.insertLayer.call(void 0, this.doc.layers, layer, _nullishCoalesce(_optionalChain([loc, 'optionalAccess', _215 => _215.parent, 'optionalAccess', _216 => _216.id]), () => ( null)), loc ? loc.index + 1 : void 0);
4124
+ const source = this.sourceOf(d, values, options.time);
4125
+ this.commit("Add effect layer", { ...this.doc, layers, activeLayerId: layer.id, effectLayers: { ..._nullishCoalesce(this.doc.effectLayers, () => ( {})), [layer.id]: source } });
4126
+ return { layer: this.describeLayer(layer), source };
4127
+ }
4128
+ /**
4129
+ * Draws an effect layer again with new `values` (merged over its own; `null` resets one) or
4130
+ * `time`, at the canvas size, replacing its pixels (paint on it is lost). One undo step; with
4131
+ * `commitToHistory` false it joins the previous effect layer step (a slider drag).
4132
+ */
4133
+ async updateEffectLayer(layerId, changes, commitToHistory = true) {
4134
+ this.requireIdle("changing an effect layer");
4135
+ const was = this.getEffectLayer(layerId);
4136
+ if (!was) throw new PaintEditorError(`"${layerId}" is not an effect layer; add one with add_effect_layer.`);
4137
+ this.checkTime(changes.time);
4138
+ const l = this.effectTarget(layerId, "draw the effect on");
4139
+ const d = await this.describeEffect(was.effect, "layer");
4140
+ const values = this.effectValues(d, was.values, changes.values);
4141
+ const time = _nullishCoalesce(_nullishCoalesce(changes.time, () => ( was.time)), () => ( 0));
4142
+ const pixels = await this.renderEffectCanvas(d, values, time);
4143
+ const now = this.getLayer(l.id);
4144
+ this.requireIdle("changing an effect layer");
4145
+ if (!isPixelLayer(now)) throw new PaintEditorError(`Layer "${l.name}" was removed while the effect rendered.`);
4146
+ const source = this.sourceOf(d, values, time);
4147
+ this.commitOrAmend("Effect layer", { ...this.doc, layers: _chunkMZXQTKUMcjs.mapLayer.call(void 0, this.doc.layers, l.id, () => ({ ...now, surface: _chunkJ5BA3BQ6cjs.surfaceFromPixels.call(void 0, pixels, 4), offset: { x: 0, y: 0 } })), effectLayers: { ..._nullishCoalesce(this.doc.effectLayers, () => ( {})), [l.id]: source } }, commitToHistory);
4148
+ return source;
4149
+ }
4150
+ /** Turns an effect layer into a plain pixel layer, keeping its pixels (one undo step). */
4151
+ rasterizeEffectLayer(layerId) {
4152
+ this.requireIdle("changing an effect layer");
4153
+ if (!this.getEffectLayer(layerId)) throw new PaintEditorError(`"${layerId}" is not an effect layer; list_applied_effects lists them.`);
4154
+ const { [layerId]: _gone, ...rest } = _nullishCoalesce(this.doc.effectLayers, () => ( {}));
4155
+ this.commit("Rasterize effect layer", { ...this.doc, effectLayers: rest });
4156
+ return this.describeLayer(this.requireLayer(layerId));
4157
+ }
4158
+ /**
4159
+ * Fills a layer with a provider generator, overlay or title effect: its pixels, rendered at the
4160
+ * canvas size, are composited onto the layer's paint at `opacity` (only where it is already
4161
+ * painted with `lockTransparency`, or when the layer's transparency is locked). One undo step.
4162
+ */
4163
+ async fillLayerWithEffect(effect, options = {}) {
4164
+ this.requireIdle("filling");
4165
+ this.checkOpacity(options.opacity);
4166
+ this.checkTime(options.time);
4167
+ const l = this.effectTarget(options.layerId, "fill");
4168
+ const d = await this.describeEffect(effect, "fill");
4169
+ const values = this.effectValues(d, { ...d.defaults }, options.values);
4170
+ const pixels = await this.renderEffectCanvas(d, values, options.time);
4171
+ const now = this.sameLayerAfterRender(l);
4172
+ const rect = this.canvasRectOf(now);
4173
+ const before = _chunkJ5BA3BQ6cjs.readRegion.call(void 0, now.surface, rect);
4174
+ let after = overPixels(before, pixels.data, _nullishCoalesce(options.opacity, () => ( 1)));
4175
+ if (options.lockTransparency || _chunkMZXQTKUMcjs.isLayerLocked.call(void 0, now, "transparency")) after = mixPixels(before, after, 1);
4176
+ const surface = _chunkJ5BA3BQ6cjs.writeRegion.call(void 0, now.surface, rect, after);
4177
+ this.commit("Effect fill", { ...this.doc, layers: _chunkMZXQTKUMcjs.mapLayer.call(void 0, this.doc.layers, now.id, () => ({ ...now, surface })) });
4178
+ return { layerId: now.id, source: this.sourceOf(d, values, options.time) };
4179
+ }
4180
+ /**
4181
+ * Runs a filter effect (light, glow, colour grade …) on a layer's dried paint and bakes it in, at
4182
+ * `amount` strength (0..1, default 1). Transparent areas stay transparent; thick paint keeps its
4183
+ * relief, and an effect with a `height` input gets the relief as a height map. Wet paint is
4184
+ * refused (dry it first). One undo step.
4185
+ */
4186
+ async applyLightEffect(layerId, effect, options = {}) {
4187
+ this.requireIdle("applying an effect");
4188
+ const amount = _nullishCoalesce(options.amount, () => ( 1));
4189
+ if (!(amount >= 0 && amount <= 1)) throw new PaintEditorError(`amount ${options.amount} is out of range; use 0..1.`);
4190
+ this.checkTime(options.time);
4191
+ const l = this.effectTarget(layerId, "light");
4192
+ if (!_chunkJ5BA3BQ6cjs.contentBounds.call(void 0, l.surface)) throw new PaintEditorError(`Layer "${l.name}" has no paint to light; paint on it first, or add an effect layer (add_effect_layer).`);
4193
+ const d = await this.describeEffect(effect, "light");
4194
+ const values = this.effectValues(d, { ...d.defaults }, options.values);
4195
+ const rect = this.canvasRectOf(l);
4196
+ const before = _chunkJ5BA3BQ6cjs.readRegion.call(void 0, l.surface, rect);
4197
+ const inputs = { source: { width: rect.width, height: rect.height, data: before } };
4198
+ const heightInput = d.inputs.find((i) => i.kind === "image" && /^(height|depth|relief)$/i.test(i.name));
4199
+ const relief = _optionalChain([this, 'access', _217 => _217.doc, 'access', _218 => _218.thick, 'optionalAccess', _219 => _219[l.id]]);
4200
+ if (heightInput && relief) {
4201
+ const h = _chunkJ5BA3BQ6cjs.readRegion.call(void 0, relief.height, rect);
4202
+ const rgba = new Uint8ClampedArray(rect.width * rect.height * 4);
4203
+ for (let i = 0; i < h.length; i++) rgba.set([h[i], h[i], h[i], 255], i * 4);
4204
+ inputs[heightInput.name] = { width: rect.width, height: rect.height, data: rgba };
4205
+ }
4206
+ const sourceInput = _nullishCoalesce(_optionalChain([d, 'access', _220 => _220.inputs, 'access', _221 => _221.find, 'call', _222 => _222((i) => i.kind === "image" && i.name !== _optionalChain([heightInput, 'optionalAccess', _223 => _223.name])), 'optionalAccess', _224 => _224.name]), () => ( "source"));
4207
+ if (sourceInput !== "source") {
4208
+ inputs[sourceInput] = inputs.source;
4209
+ delete inputs.source;
4210
+ }
4211
+ const out = await this.effectsRenderer.render(this.effects.require(), d.id, { width: rect.width, height: rect.height }, { time: _nullishCoalesce(options.time, () => ( 0)), values, inputs });
4212
+ const now = this.sameLayerAfterRender(l);
4213
+ const surface = _chunkJ5BA3BQ6cjs.writeRegion.call(void 0, now.surface, rect, mixPixels(before, out.data, amount));
4214
+ this.commit("Light effect", { ...this.doc, layers: _chunkMZXQTKUMcjs.mapLayer.call(void 0, this.doc.layers, now.id, () => ({ ...now, surface })) });
4215
+ return { layerId: now.id, source: this.sourceOf(d, values, options.time), amount };
4216
+ }
3815
4217
  // --- Brushes -------------------------------------------------------------------
3816
4218
  findBrush(id) {
3817
4219
  return _nullishCoalesce(_chunkW4LNKTHTcjs.BUILTIN_BRUSHES.find((b) => b.id === id), () => ( this.userBrushes.find((b) => b.id === id)));
@@ -4054,7 +4456,7 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
4054
4456
  return l;
4055
4457
  })();
4056
4458
  const brush = this.strokeBrush(init);
4057
- const stickerLayer = Boolean(_optionalChain([doc, 'access', _203 => _203.stickers, 'optionalAccess', _204 => _204[layer.id], 'optionalAccess', _205 => _205.length]));
4459
+ const stickerLayer = Boolean(_optionalChain([doc, 'access', _225 => _225.stickers, 'optionalAccess', _226 => _226[layer.id], 'optionalAccess', _227 => _227.length]));
4058
4460
  if (brush.engine === "sticker") {
4059
4461
  if (!stickerLayer && _chunkJ5BA3BQ6cjs.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.`);
4060
4462
  } else if (stickerLayer) {
@@ -4104,7 +4506,7 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
4104
4506
  }
4105
4507
  let color = init.color === void 0 ? this.color : parseColor(init.color);
4106
4508
  const tracing = this.guides.tracing;
4107
- if (init.color === void 0 && init.start && _optionalChain([tracing, 'optionalAccess', _206 => _206.visible]) && tracing.sampleColors) color = _nullishCoalesce(this.sampleTracingColor(init.start.x, init.start.y), () => ( color));
4509
+ if (init.color === void 0 && init.start && _optionalChain([tracing, 'optionalAccess', _228 => _228.visible]) && tracing.sampleColors) color = _nullishCoalesce(this.sampleTracingColor(init.start.x, init.start.y), () => ( color));
4108
4510
  const perspective = this.guides.perspective;
4109
4511
  const snapper = init.snapToPerspective && perspective.enabled && perspective.snap ? new PerspectiveSnapper(perspective) : null;
4110
4512
  const useStencils = init.stencils !== false;
@@ -4133,7 +4535,7 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
4133
4535
  mixerLoad: _nullishCoalesce(init.load, () => ( brushLoadForStroke(brush, this.mixerLoad, [rgba[0] / 255, rgba[1] / 255, rgba[2] / 255]))),
4134
4536
  secondary: rgbaOf(this.secondaryColor),
4135
4537
  wet,
4136
- thick: brush.engine === "impasto" ? { channels: _nullishCoalesce(_optionalChain([doc, 'access', _207 => _207.thick, 'optionalAccess', _208 => _208[layer.id]]), () => ( emptyThickChannels())) } : void 0,
4538
+ thick: brush.engine === "impasto" ? { channels: _nullishCoalesce(_optionalChain([doc, 'access', _229 => _229.thick, 'optionalAccess', _230 => _230[layer.id]]), () => ( emptyThickChannels())) } : void 0,
4137
4539
  sticker: brush.engine === "sticker" ? { nextId: this.nextStickerNumber(doc) } : void 0,
4138
4540
  paint: this.strokeGradient(init, brush, color)
4139
4541
  });
@@ -4170,12 +4572,12 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
4170
4572
  const before = this.doc;
4171
4573
  const host = {
4172
4574
  update: (layerId, surface, rects) => {
4173
- if (_optionalChain([this, 'access', _209 => _209.session, 'optionalAccess', _210 => _210.init, 'access', _211 => _211.wet])) {
4575
+ if (_optionalChain([this, 'access', _231 => _231.session, 'optionalAccess', _232 => _232.init, 'access', _233 => _233.wet])) {
4174
4576
  this.wet.syncDisplays();
4175
4577
  return;
4176
4578
  }
4177
4579
  this.live = { layerId, surface };
4178
- const ch = _optionalChain([this, 'access', _212 => _212.session, 'optionalAccess', _213 => _213.thickChannels, 'call', _214 => _214()]);
4580
+ const ch = _optionalChain([this, 'access', _234 => _234.session, 'optionalAccess', _235 => _235.thickChannels, 'call', _236 => _236()]);
4179
4581
  this.liveThick = ch ? { layerId, channels: ch } : null;
4180
4582
  this.emit(rects);
4181
4583
  },
@@ -4187,7 +4589,7 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
4187
4589
  const wetStroke = Boolean(s.init.wet);
4188
4590
  if (wetStroke) this.wet.driver = null;
4189
4591
  const brush = s.init.brush;
4190
- if (!cancelled && _optionalChain([s, 'access', _215 => _215.result, 'optionalAccess', _216 => _216.mixerLoad])) this.keepLoad(brush, s.result.mixerLoad);
4592
+ if (!cancelled && _optionalChain([s, 'access', _237 => _237.result, 'optionalAccess', _238 => _238.mixerLoad])) this.keepLoad(brush, s.result.mixerLoad);
4191
4593
  if (cancelled || !surface) {
4192
4594
  if (this.wetOp) {
4193
4595
  const snap = this.wetOp.before;
@@ -4212,7 +4614,7 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
4212
4614
  const ch = s.thickChannels();
4213
4615
  const thick = ch ? { ..._nullishCoalesce(this.doc.thick, () => ( {})), [l.id]: ch } : this.doc.thick;
4214
4616
  const sprayed = s.stickers();
4215
- const stickers = sprayed ? { ..._nullishCoalesce(this.doc.stickers, () => ( {})), [l.id]: [..._nullishCoalesce(_optionalChain([this, 'access', _217 => _217.doc, 'access', _218 => _218.stickers, 'optionalAccess', _219 => _219[l.id]]), () => ( [])), ...sprayed] } : this.doc.stickers;
4617
+ const stickers = sprayed ? { ..._nullishCoalesce(this.doc.stickers, () => ( {})), [l.id]: [..._nullishCoalesce(_optionalChain([this, 'access', _239 => _239.doc, 'access', _240 => _240.stickers, 'optionalAccess', _241 => _241[l.id]]), () => ( [])), ...sprayed] } : this.doc.stickers;
4216
4618
  this.commit(`${brush.name} stroke`, this.withWetEvents({ ...this.doc, layers: _chunkMZXQTKUMcjs.mapLayer.call(void 0, this.doc.layers, l.id, () => ({ ...l, surface })), strokes: [...this.doc.strokes, stroke], ...thick ? { thick } : {}, ...stickers ? { stickers } : {} }), wetStroke ? before : this.doc);
4217
4619
  }
4218
4620
  };
@@ -4250,7 +4652,7 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
4250
4652
  layers: _chunkMZXQTKUMcjs.mapLayer.call(void 0, out.layers, l.id, () => ({ ...l, surface, offset })),
4251
4653
  strokes: [...out.strokes, stroke],
4252
4654
  ...ch ? { thick: { ..._nullishCoalesce(out.thick, () => ( {})), [l.id]: ch } } : {},
4253
- ...sprayed ? { stickers: { ..._nullishCoalesce(out.stickers, () => ( {})), [l.id]: [..._nullishCoalesce(_optionalChain([out, 'access', _220 => _220.stickers, 'optionalAccess', _221 => _221[l.id]]), () => ( [])), ...sprayed] } } : {}
4655
+ ...sprayed ? { stickers: { ..._nullishCoalesce(out.stickers, () => ( {})), [l.id]: [..._nullishCoalesce(_optionalChain([out, 'access', _242 => _242.stickers, 'optionalAccess', _243 => _243[l.id]]), () => ( [])), ...sprayed] } } : {}
4254
4656
  };
4255
4657
  }
4256
4658
  };
@@ -4308,7 +4710,7 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
4308
4710
  */
4309
4711
  replayStrokes(options) {
4310
4712
  this.requireIdle("replaying");
4311
- if (!_optionalChain([options, 'access', _222 => _222.strokeIds, 'optionalAccess', _223 => _223.length])) throw new PaintEditorError("strokeIds is empty; pass ids from list_strokes.");
4713
+ if (!_optionalChain([options, 'access', _244 => _244.strokeIds, 'optionalAccess', _245 => _245.length])) throw new PaintEditorError("strokeIds is empty; pass ids from list_strokes.");
4312
4714
  const strokes = options.strokeIds.map((id) => {
4313
4715
  const s = this.doc.strokes.find((x) => x.id === id);
4314
4716
  if (!s) throw new PaintEditorError(`Unknown stroke "${id}". Call list_strokes for the ids.`);
@@ -4384,7 +4786,7 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
4384
4786
  const id = _nullishCoalesce(layerId, () => ( this.doc.activeLayerId));
4385
4787
  if (!id) return null;
4386
4788
  this.requireLayer(id);
4387
- const ch = _optionalChain([this, 'access', _224 => _224.doc, 'access', _225 => _225.thick, 'optionalAccess', _226 => _226[id]]);
4789
+ const ch = _optionalChain([this, 'access', _246 => _246.doc, 'access', _247 => _247.thick, 'optionalAccess', _248 => _248[id]]);
4388
4790
  if (!ch) return null;
4389
4791
  const r = reliefInfo(ch);
4390
4792
  return { layerId: id, bounds: r.bounds, maxHeight: r.maxHeight };
@@ -4464,6 +4866,7 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
4464
4866
  /** Stops the wet simulation's worker threads (call when the editor goes away). */
4465
4867
  dispose() {
4466
4868
  this.wet.destroy();
4869
+ this.effectsRenderer.dispose();
4467
4870
  }
4468
4871
  /** Resolves when wet paint is between steps (edits, undo and exports can run). */
4469
4872
  wetIdle() {
@@ -4488,7 +4891,7 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
4488
4891
  wetState() {
4489
4892
  const st = this.getState().wet;
4490
4893
  const backend = this.wet.backend();
4491
- return { ...st, layers: this.wet.wetLayerIds().map((id) => this.wet.info(id)), backend, message: _nullishCoalesce(_optionalChain([backend, 'optionalAccess', _227 => _227.message]), () => ( _chunkFHPVDTI2cjs.wetSupport.call(void 0, ).message)), engine: this.wet.engineInfo() };
4894
+ return { ...st, layers: this.wet.wetLayerIds().map((id) => this.wet.info(id)), backend, message: _nullishCoalesce(_optionalChain([backend, 'optionalAccess', _249 => _249.message]), () => ( _chunkFHPVDTI2cjs.wetSupport.call(void 0, ).message)), engine: this.wet.engineInfo() };
4492
4895
  }
4493
4896
  /**
4494
4897
  * Engine B, the WebGPU accelerator for large wet areas: whether it may run, its state (`off`,
@@ -4573,7 +4976,7 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
4573
4976
  }
4574
4977
  /** Records a settings change as a wet event (not an undo step). */
4575
4978
  recordWetSetting(e) {
4576
- this.doc = { ...this.doc, wetEvents: [..._nullishCoalesce(this.doc.wetEvents, () => ( [])), { clock: _nullishCoalesce(_optionalChain([this, 'access', _228 => _228.wet, 'access', _229 => _229.world, 'optionalAccess', _230 => _230.clock]), () => ( 0)), at: this.doc.strokes.length, ...e }] };
4979
+ this.doc = { ...this.doc, wetEvents: [..._nullishCoalesce(this.doc.wetEvents, () => ( [])), { clock: _nullishCoalesce(_optionalChain([this, 'access', _250 => _250.wet, 'access', _251 => _251.world, 'optionalAccess', _252 => _252.clock]), () => ( 0)), at: this.doc.strokes.length, ...e }] };
4577
4980
  }
4578
4981
  /** Changes a layer's wet settings (viscosity, evaporation, granulation…). Editor settings saved with the document, not an undo step. */
4579
4982
  setWetParams(layerId, update) {
@@ -4640,7 +5043,7 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
4640
5043
  currentLayers() {
4641
5044
  const live = this.live;
4642
5045
  if (!live) return this.doc.layers;
4643
- if (_optionalChain([this, 'access', _231 => _231.liveLayers, 'optionalAccess', _232 => _232.key]) === live.surface) return this.liveLayers.layers;
5046
+ if (_optionalChain([this, 'access', _253 => _253.liveLayers, 'optionalAccess', _254 => _254.key]) === live.surface) return this.liveLayers.layers;
4644
5047
  const layers = _chunkMZXQTKUMcjs.mapLayer.call(void 0, this.doc.layers, live.layerId, (l) => ({ ...l, surface: live.surface }));
4645
5048
  this.liveLayers = { key: live.surface, layers };
4646
5049
  return layers;
@@ -4651,11 +5054,19 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
4651
5054
  if (!t || !t.visible) return [];
4652
5055
  return [this.tracingNode(t)];
4653
5056
  }
5057
+ /** The effect paper as a compositor layer (one object per effect paper, so caches hold). */
5058
+ paperEffectNode(p) {
5059
+ const c = this.paperEffectNodeCache;
5060
+ if (c && c.image === p.image && c.opacity === p.opacity && c.blend === p.blend) return c;
5061
+ const node = { type: "image", id: PAPER_EFFECT_NODE_ID, name: "Effect paper", visible: true, opacity: p.opacity, blend: p.blend, image: p.image, version: p.version };
5062
+ this.paperEffectNodeCache = node;
5063
+ return node;
5064
+ }
4654
5065
  /** The tracing image resampled onto the canvas (cached until it or the canvas changes). */
4655
5066
  tracingNode(t) {
4656
5067
  const { width, height } = this.doc.canvas;
4657
5068
  const key = this.tracingVersion * 100003 + width * 7 + height;
4658
- if (_optionalChain([this, 'access', _233 => _233.tracingCache, 'optionalAccess', _234 => _234.key]) === key && this.tracingCache.node.opacity === t.opacity) return this.tracingCache.node;
5069
+ if (_optionalChain([this, 'access', _255 => _255.tracingCache, 'optionalAccess', _256 => _256.key]) === key && this.tracingCache.node.opacity === t.opacity) return this.tracingCache.node;
4659
5070
  const src = _nullishCoalesce(this.imagePixels.get(t.src), () => ( this.decodeImage(t.src)));
4660
5071
  const image = resampleInto(src, t.rect, width, height);
4661
5072
  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 };
@@ -4682,8 +5093,8 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
4682
5093
  let out = layers;
4683
5094
  const ids = /* @__PURE__ */ new Set([...Object.keys(_nullishCoalesce(thick, () => ( {}))), ...live ? [live.layerId] : []]);
4684
5095
  for (const id of ids) {
4685
- const ch = _optionalChain([live, 'optionalAccess', _235 => _235.layerId]) === id ? live.channels : _optionalChain([thick, 'optionalAccess', _236 => _236[id]]);
4686
- const l = ch && _optionalChain([_chunkMZXQTKUMcjs.findLayer.call(void 0, out, id), 'optionalAccess', _237 => _237.layer]);
5096
+ const ch = _optionalChain([live, 'optionalAccess', _257 => _257.layerId]) === id ? live.channels : _optionalChain([thick, 'optionalAccess', _258 => _258[id]]);
5097
+ const l = ch && _optionalChain([_chunkMZXQTKUMcjs.findLayer.call(void 0, out, id), 'optionalAccess', _259 => _259.layer]);
4687
5098
  if (!ch || !isPixelLayer(l)) continue;
4688
5099
  let cache = this.litCaches.get(id);
4689
5100
  if (!cache) this.litCaches.set(id, cache = new LitCache());
@@ -4696,10 +5107,11 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
4696
5107
  let layers = this.litLayers((_nullishCoalesce(options.wet, () => ( "display"))) === "dried" ? this.driedLayers() : this.currentLayers());
4697
5108
  if (options.layerIds) {
4698
5109
  const picked = [];
4699
- for (const id of options.layerIds) picked.push(_nullishCoalesce(_optionalChain([_chunkMZXQTKUMcjs.findLayer.call(void 0, layers, id), 'optionalAccess', _238 => _238.layer]), () => ( this.requireLayer(id))));
5110
+ for (const id of options.layerIds) picked.push(_nullishCoalesce(_optionalChain([_chunkMZXQTKUMcjs.findLayer.call(void 0, layers, id), 'optionalAccess', _260 => _260.layer]), () => ( this.requireLayer(id))));
4700
5111
  layers = picked.map((l) => ({ ...l, visible: true }));
4701
5112
  }
4702
5113
  const under = options.paper === false ? [] : [paperNode(this.doc.paper, this.lighting)];
5114
+ if (options.paper !== false && this.doc.paperEffect) under.push(this.paperEffectNode(this.doc.paperEffect));
4703
5115
  if (view) under.push(...this.underlayLayers());
4704
5116
  return [...under, ...layers];
4705
5117
  }
@@ -4710,7 +5122,7 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
4710
5122
  */
4711
5123
  compositeTiles(rect, onTile, options = {}) {
4712
5124
  const dirty = options.dirty === "all" ? void 0 : options.dirty;
4713
- this.viewCompositor.compositeTiles(this.renderLayers({}, true), rect, this.sources(), onTile, { dirty, checkpointLayerId: _nullishCoalesce(_optionalChain([this, 'access', _239 => _239.live, 'optionalAccess', _240 => _240.layerId]), () => ( this.doc.activeLayerId)) });
5125
+ this.viewCompositor.compositeTiles(this.renderLayers({}, true), rect, this.sources(), onTile, { dirty, checkpointLayerId: _nullishCoalesce(_optionalChain([this, 'access', _261 => _261.live, 'optionalAccess', _262 => _262.layerId]), () => ( this.doc.activeLayerId)) });
4714
5126
  }
4715
5127
  /** The canvas as canvas-sized RGBA (paper included by default). */
4716
5128
  compositePixels(options = {}) {
@@ -4774,6 +5186,11 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
4774
5186
  for (const [id, list] of Object.entries(_nullishCoalesce(this.doc.stickers, () => ( {})))) if (list.length && _chunkMZXQTKUMcjs.findLayer.call(void 0, this.doc.layers, id)) stickers[id] = list.map((x) => ({ ...x }));
4775
5187
  if (Object.keys(stickers).length) ext.stickers = stickers;
4776
5188
  else delete ext.stickers;
5189
+ const effectLayers = effectLayersToJSON(_nullishCoalesce(this.doc.effectLayers, () => ( {})), (id) => isPixelLayer(_optionalChain([_chunkMZXQTKUMcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _263 => _263.layer])));
5190
+ if (effectLayers) ext.effectLayers = effectLayers;
5191
+ else delete ext.effectLayers;
5192
+ if (this.doc.paperEffect) ext.paperEffect = paperEffectToJSON(this.doc.paperEffect);
5193
+ else delete ext.paperEffect;
4777
5194
  if (this.lighting.azimuth !== DEFAULT_LIGHTING.azimuth || this.lighting.elevation !== DEFAULT_LIGHTING.elevation || this.lighting.relief !== DEFAULT_LIGHTING.relief) ext.lighting = { ...this.lighting };
4778
5195
  else delete ext.lighting;
4779
5196
  return ext;
@@ -4792,6 +5209,23 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
4792
5209
  }
4793
5210
  if (Object.keys(stickers).length) state = { ...state, stickers };
4794
5211
  }
5212
+ if (ext.effectLayers && typeof ext.effectLayers === "object") {
5213
+ const effectLayers = {};
5214
+ for (const [id, v] of Object.entries(ext.effectLayers)) {
5215
+ if (!isPixelLayer(_optionalChain([_chunkMZXQTKUMcjs.findLayer.call(void 0, state.layers, id), 'optionalAccess', _264 => _264.layer]))) continue;
5216
+ const source = readPaintEffectSource(v);
5217
+ if (source) effectLayers[id] = source;
5218
+ else problems.push(`The effect of layer "${id}" could not be read; it loads as a plain layer.`);
5219
+ }
5220
+ if (Object.keys(effectLayers).length) state = { ...state, effectLayers };
5221
+ }
5222
+ if (ext.paperEffect !== void 0) {
5223
+ try {
5224
+ state = { ...state, paperEffect: paperEffectFromJSON(ext.paperEffect, state.canvas.width, state.canvas.height) };
5225
+ } catch (e) {
5226
+ problems.push(`The effect paper could not be read (${e.message}); the plain paper shows.`);
5227
+ }
5228
+ }
4795
5229
  const raw = ext.layerChannels;
4796
5230
  if (!raw || typeof raw !== "object") return state;
4797
5231
  const thick = {};
@@ -4819,7 +5253,7 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
4819
5253
  this.readGuides(loaded.guides, loaded.state, loaded.problems);
4820
5254
  if (Array.isArray(loaded.swatches)) this.swatches = loaded.swatches.map(readSwatch).filter((x) => x !== null);
4821
5255
  for (const s of loaded.state.strokes) {
4822
- const n = Number(_nullishCoalesce(_optionalChain([/^s(\d+)$/, 'access', _241 => _241.exec, 'call', _242 => _242(s.id), 'optionalAccess', _243 => _243[1]]), () => ( 0)));
5256
+ const n = Number(_nullishCoalesce(_optionalChain([/^s(\d+)$/, 'access', _265 => _265.exec, 'call', _266 => _266(s.id), 'optionalAccess', _267 => _267[1]]), () => ( 0)));
4823
5257
  if (n >= this.strokeCounter) this.strokeCounter = n + 1;
4824
5258
  }
4825
5259
  this.undoStack = [];
@@ -4828,6 +5262,8 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
4828
5262
  delete this.extensions.layerChannels;
4829
5263
  delete this.extensions.lighting;
4830
5264
  delete this.extensions.stickers;
5265
+ delete this.extensions.effectLayers;
5266
+ delete this.extensions.paperEffect;
4831
5267
  this.viewCompositor.clear();
4832
5268
  this.emit();
4833
5269
  return loaded.problems;
@@ -4908,10 +5344,10 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
4908
5344
  return next.type === "group" ? { ...next, children: toStandard(next.children) } : next;
4909
5345
  });
4910
5346
  const layers = toStandard(dried);
4911
- const result = _chunkO5RVCDECcjs.exportPsd.call(void 0, { width, height, layers: [paperLayer, ...layers], merged, resolution: dpi });
5347
+ const result = _chunkXLUYXUBDcjs.exportPsd.call(void 0, { width, height, layers: [paperLayer, ...layers], merged, resolution: dpi });
4912
5348
  for (const [mode, names] of changed) {
4913
- const label = _nullishCoalesce(_optionalChain([_chunkJ5BA3BQ6cjs.BLEND_MODES, 'access', _244 => _244.find, 'call', _245 => _245((m) => m.id === mode), 'optionalAccess', _246 => _246.label]), () => ( mode));
4914
- const std = _nullishCoalesce(_optionalChain([_chunkJ5BA3BQ6cjs.BLEND_MODES, 'access', _247 => _247.find, 'call', _248 => _248((m) => m.id === _chunkJ5BA3BQ6cjs.standardBlendMode.call(void 0, mode)), 'optionalAccess', _249 => _249.label]), () => ( _chunkJ5BA3BQ6cjs.standardBlendMode.call(void 0, mode)));
5349
+ const label = _nullishCoalesce(_optionalChain([_chunkJ5BA3BQ6cjs.BLEND_MODES, 'access', _268 => _268.find, 'call', _269 => _269((m) => m.id === mode), 'optionalAccess', _270 => _270.label]), () => ( mode));
5350
+ const std = _nullishCoalesce(_optionalChain([_chunkJ5BA3BQ6cjs.BLEND_MODES, 'access', _271 => _271.find, 'call', _272 => _272((m) => m.id === _chunkJ5BA3BQ6cjs.standardBlendMode.call(void 0, mode)), 'optionalAccess', _273 => _273.label]), () => ( _chunkJ5BA3BQ6cjs.standardBlendMode.call(void 0, mode)));
4915
5351
  const list = names.map((n) => `"${n}"`).join(", ");
4916
5352
  const one = names.length === 1;
4917
5353
  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).`);
@@ -5025,9 +5461,9 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
5025
5461
  /** Adds a floating reference image to look at and pick colours from. */
5026
5462
  addReferenceImage(options) {
5027
5463
  const { src, pixels } = this.importImage(options, "The reference image");
5028
- const ref = {
5464
+ const ref2 = {
5029
5465
  id: `ref${this.nextReferenceId++}`,
5030
- name: _optionalChain([options, 'access', _250 => _250.name, 'optionalAccess', _251 => _251.trim, 'call', _252 => _252()]) || `Reference ${this.guides.references.length + 1}`,
5466
+ name: _optionalChain([options, 'access', _274 => _274.name, 'optionalAccess', _275 => _275.trim, 'call', _276 => _276()]) || `Reference ${this.guides.references.length + 1}`,
5031
5467
  src,
5032
5468
  width: pixels.width,
5033
5469
  height: pixels.height,
@@ -5036,8 +5472,8 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
5036
5472
  displayWidth: _nullishCoalesce(options.displayWidth, () => ( Math.min(240, pixels.width))),
5037
5473
  visible: true
5038
5474
  };
5039
- this.setGuides({ ...this.guides, references: [...this.guides.references, ref] });
5040
- return ref;
5475
+ this.setGuides({ ...this.guides, references: [...this.guides.references, ref2] });
5476
+ return ref2;
5041
5477
  }
5042
5478
  requireReference(id) {
5043
5479
  const r = this.guides.references.find((x) => x.id === id);
@@ -5101,12 +5537,12 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
5101
5537
  }
5102
5538
  }
5103
5539
  if (Array.isArray(r.references)) {
5104
- for (const ref of r.references) {
5105
- if (!ref || typeof ref.src !== "string" || typeof ref.id !== "string") continue;
5540
+ for (const ref2 of r.references) {
5541
+ if (!ref2 || typeof ref2.src !== "string" || typeof ref2.id !== "string") continue;
5106
5542
  try {
5107
- const px = this.decodeImage(ref.src, `Reference "${ref.name}"`);
5108
- guides.references.push({ id: ref.id, name: String(_nullishCoalesce(ref.name, () => ( ref.id))), src: ref.src, width: px.width, height: px.height, x: Number(ref.x) || 0, y: Number(ref.y) || 0, displayWidth: Number(ref.displayWidth) || 240, visible: ref.visible !== false });
5109
- const n = Number(_nullishCoalesce(_optionalChain([/^ref(\d+)$/, 'access', _253 => _253.exec, 'call', _254 => _254(ref.id), 'optionalAccess', _255 => _255[1]]), () => ( 0)));
5543
+ const px = this.decodeImage(ref2.src, `Reference "${ref2.name}"`);
5544
+ 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 });
5545
+ const n = Number(_nullishCoalesce(_optionalChain([/^ref(\d+)$/, 'access', _277 => _277.exec, 'call', _278 => _278(ref2.id), 'optionalAccess', _279 => _279[1]]), () => ( 0)));
5110
5546
  if (n >= this.nextReferenceId) this.nextReferenceId = n + 1;
5111
5547
  } catch (e) {
5112
5548
  problems.push(e.message);
@@ -5117,7 +5553,7 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
5117
5553
  guides.stencils = [];
5118
5554
  r.stencils.forEach((raw2, i) => {
5119
5555
  try {
5120
- const id = typeof _optionalChain([raw2, 'optionalAccess', _256 => _256.id]) === "string" && /^stencil\d+$/.test(raw2.id) ? raw2.id : `stencil${this.nextStencilId}`;
5556
+ const id = typeof _optionalChain([raw2, 'optionalAccess', _280 => _280.id]) === "string" && /^stencil\d+$/.test(raw2.id) ? raw2.id : `stencil${this.nextStencilId}`;
5121
5557
  guides.stencils.push(normalizeStencil(raw2, id));
5122
5558
  const n = Number(id.slice(7));
5123
5559
  if (n >= this.nextStencilId) this.nextStencilId = n + 1;
@@ -5140,12 +5576,12 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
5140
5576
  /** The next free sticker number (ids `st<n>` are unique across the document). */
5141
5577
  nextStickerNumber(doc = this.doc) {
5142
5578
  let n = 0;
5143
- for (const list of Object.values(_nullishCoalesce(doc.stickers, () => ( {})))) for (const st of list) n = Math.max(n, Number(_nullishCoalesce(_optionalChain([/^st(\d+)$/, 'access', _257 => _257.exec, 'call', _258 => _258(st.id), 'optionalAccess', _259 => _259[1]]), () => ( 0))));
5579
+ for (const list of Object.values(_nullishCoalesce(doc.stickers, () => ( {})))) for (const st of list) n = Math.max(n, Number(_nullishCoalesce(_optionalChain([/^st(\d+)$/, 'access', _281 => _281.exec, 'call', _282 => _282(st.id), 'optionalAccess', _283 => _283[1]]), () => ( 0))));
5144
5580
  return n + 1;
5145
5581
  }
5146
5582
  stickerLayer(layerId) {
5147
5583
  const l = this.wetLayer(layerId, "edit the stickers of");
5148
- const stickers = _optionalChain([this, 'access', _260 => _260.doc, 'access', _261 => _261.stickers, 'optionalAccess', _262 => _262[l.id]]);
5584
+ const stickers = _optionalChain([this, 'access', _284 => _284.doc, 'access', _285 => _285.stickers, 'optionalAccess', _286 => _286[l.id]]);
5149
5585
  if (!stickers) throw new PaintEditorError(`Layer "${l.name}" has no stickers; spray some with a sticker brush (list_brushes category sticker).`);
5150
5586
  return { layer: l, stickers };
5151
5587
  }
@@ -5154,7 +5590,7 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
5154
5590
  const id = _nullishCoalesce(layerId, () => ( this.doc.activeLayerId));
5155
5591
  if (!id) return [];
5156
5592
  this.requireLayer(id);
5157
- return (_nullishCoalesce(_optionalChain([this, 'access', _263 => _263.doc, 'access', _264 => _264.stickers, 'optionalAccess', _265 => _265[id]]), () => ( []))).map((s) => ({ ...s }));
5593
+ return (_nullishCoalesce(_optionalChain([this, 'access', _287 => _287.doc, 'access', _288 => _288.stickers, 'optionalAccess', _289 => _289[id]]), () => ( []))).map((s) => ({ ...s }));
5158
5594
  }
5159
5595
  /** Replaces a layer's stickers and redraws its pixels from them (one undo step). */
5160
5596
  commitStickers(label, layer, stickers) {
@@ -5204,13 +5640,13 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
5204
5640
  this.commitStickers("Stickers", l, stickers.map((s) => ({ ...s })));
5205
5641
  }
5206
5642
  // --- Stencils --------------------------------------------------------------------
5207
- __init101() {this.stencilCache = null}
5208
- __init102() {this.nextStencilId = 1}
5643
+ __init107() {this.stencilCache = null}
5644
+ __init108() {this.nextStencilId = 1}
5209
5645
  /** The mask stencils' coverage over the canvas (cached), or `null` when none masks. */
5210
5646
  stencilSelection(stencils = this.guides.stencils) {
5211
5647
  const { width, height } = this.doc.canvas;
5212
5648
  const size = `${width}x${height}`;
5213
- if (_optionalChain([this, 'access', _266 => _266.stencilCache, 'optionalAccess', _267 => _267.key]) === stencils && this.stencilCache.size === size) return this.stencilCache.mask;
5649
+ if (_optionalChain([this, 'access', _290 => _290.stencilCache, 'optionalAccess', _291 => _291.key]) === stencils && this.stencilCache.size === size) return this.stencilCache.mask;
5214
5650
  const mask = stencilMask(stencils, width, height);
5215
5651
  this.stencilCache = { key: stencils, size, mask };
5216
5652
  return mask;
@@ -5272,7 +5708,7 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
5272
5708
  makeSwatch(color, name) {
5273
5709
  const p = typeof color === "string" ? { type: "color", color: parseColor(color) } : this.readStrokePaint(color);
5274
5710
  const out = { color: _chunk6GFRKLLScjs.paintSourceColor.call(void 0, p, { paint: this.color, secondary: this.secondaryColor }) };
5275
- if (_optionalChain([name, 'optionalAccess', _268 => _268.trim, 'call', _269 => _269()])) out.name = name.trim();
5711
+ if (_optionalChain([name, 'optionalAccess', _292 => _292.trim, 'call', _293 => _293()])) out.name = name.trim();
5276
5712
  if (p.type === "gradient") out.paint = p;
5277
5713
  return out;
5278
5714
  }
@@ -5324,7 +5760,7 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
5324
5760
  * mix becomes the paint colour. Returns the mixed colour and the pile's bounds.
5325
5761
  */
5326
5762
  mixOnPad(paints, options = {}) {
5327
- const parsed = (_nullishCoalesce(paints, () => ( []))).map((p, i) => ({ color: parseColor(_optionalChain([p, 'optionalAccess', _270 => _270.color]), `paints[${i}].color`), parts: _optionalChain([p, 'optionalAccess', _271 => _271.parts]) }));
5763
+ const parsed = (_nullishCoalesce(paints, () => ( []))).map((p, i) => ({ color: parseColor(_optionalChain([p, 'optionalAccess', _294 => _294.color]), `paints[${i}].color`), parts: _optionalChain([p, 'optionalAccess', _295 => _295.parts]) }));
5328
5764
  let r;
5329
5765
  try {
5330
5766
  r = this.pad.mix(parsed, options);
@@ -5413,10 +5849,10 @@ var PaintEditorController = (_class9 = class _PaintEditorController {
5413
5849
  }
5414
5850
  /** A layer's tile surface (live while stroking), for thumbnails. */
5415
5851
  layerSurface(id) {
5416
- const l = _optionalChain([_chunkMZXQTKUMcjs.findLayer.call(void 0, this.currentLayers(), id), 'optionalAccess', _272 => _272.layer]);
5852
+ const l = _optionalChain([_chunkMZXQTKUMcjs.findLayer.call(void 0, this.currentLayers(), id), 'optionalAccess', _296 => _296.layer]);
5417
5853
  return isPixelLayer(l) ? l.surface : null;
5418
5854
  }
5419
- }, _class9);
5855
+ }, _class10);
5420
5856
  var MAX_IMAGE_SIDE = 8192;
5421
5857
  function resampleInto(src, rect, width, height) {
5422
5858
  const out = new Uint8ClampedArray(width * height * 4);
@@ -5467,8 +5903,8 @@ function strokeSchedule(points) {
5467
5903
  return total > 0 ? acc.map((d) => d / total) : points.map(() => 1);
5468
5904
  }
5469
5905
  function strokeDuration(points, max = 1800) {
5470
- const t0 = _optionalChain([points, 'access', _273 => _273[0], 'optionalAccess', _274 => _274.t]);
5471
- const t1 = _optionalChain([points, 'access', _275 => _275[points.length - 1], 'optionalAccess', _276 => _276.t]);
5906
+ const t0 = _optionalChain([points, 'access', _297 => _297[0], 'optionalAccess', _298 => _298.t]);
5907
+ const t1 = _optionalChain([points, 'access', _299 => _299[points.length - 1], 'optionalAccess', _300 => _300.t]);
5472
5908
  let ms;
5473
5909
  if (points.every((p) => Number.isFinite(p.t)) && t1 > t0) ms = t1 - t0;
5474
5910
  else {
@@ -5522,7 +5958,7 @@ var PaintDirector = class {
5522
5958
  }
5523
5959
  where(id) {
5524
5960
  const a = this.presence.get(id);
5525
- return { x: _nullishCoalesce(_optionalChain([a, 'optionalAccess', _277 => _277.x]), () => ( 0)), y: _nullishCoalesce(_optionalChain([a, 'optionalAccess', _278 => _278.y]), () => ( 0)) };
5961
+ return { x: _nullishCoalesce(_optionalChain([a, 'optionalAccess', _301 => _301.x]), () => ( 0)), y: _nullishCoalesce(_optionalChain([a, 'optionalAccess', _302 => _302.y]), () => ( 0)) };
5526
5962
  }
5527
5963
  /** Glides to `to`; an actor that just appeared starts there instead of the corner. */
5528
5964
  async glide(id, to, ms = 380) {
@@ -5569,8 +6005,8 @@ var PaintDirector = class {
5569
6005
  }
5570
6006
  case "replay": {
5571
6007
  await this.say(id, command.note, 500);
5572
- const source = c.getStrokes().filter((s) => _optionalChain([command, 'access', _279 => _279.replay, 'access', _280 => _280.strokeIds, 'optionalAccess', _281 => _281.includes, 'call', _282 => _282(s.id)]));
5573
- const first = _optionalChain([source, 'access', _283 => _283[0], 'optionalAccess', _284 => _284.points, 'access', _285 => _285[0]]);
6008
+ const source = c.getStrokes().filter((s) => _optionalChain([command, 'access', _303 => _303.replay, 'access', _304 => _304.strokeIds, 'optionalAccess', _305 => _305.includes, 'call', _306 => _306(s.id)]));
6009
+ const first = _optionalChain([source, 'access', _307 => _307[0], 'optionalAccess', _308 => _308.points, 'access', _309 => _309[0]]);
5574
6010
  if (first) await this.glide(id, first);
5575
6011
  const result = c.replayStrokes(command.replay);
5576
6012
  if (result.bounds) await this.glide(id, centre(result.bounds), 520);
@@ -6983,7 +7419,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
6983
7419
  annotations: { title: "List brushes", ...READ6 },
6984
7420
  handler: () => {
6985
7421
  const s = c.getState();
6986
- return { activeBrushId: s.brush.id, activeEdited: !s.brush.builtin && Boolean(_optionalChain([c, 'access', _286 => _286.getBrush, 'call', _287 => _287(s.brush.id), 'optionalAccess', _288 => _288.builtin])), brushes: s.brushes.map(brushSummary) };
7422
+ return { activeBrushId: s.brush.id, activeEdited: !s.brush.builtin && Boolean(_optionalChain([c, 'access', _310 => _310.getBrush, 'call', _311 => _311(s.brush.id), 'optionalAccess', _312 => _312.builtin])), brushes: s.brushes.map(brushSummary) };
6987
7423
  }
6988
7424
  });
6989
7425
  add({
@@ -7218,7 +7654,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
7218
7654
  color: s.color,
7219
7655
  points: ids ? s.points : s.points.length,
7220
7656
  seed: s.seed,
7221
- copies: _nullishCoalesce(_optionalChain([s, 'access', _289 => _289.copies, 'optionalAccess', _290 => _290.length]), () => ( 0)),
7657
+ copies: _nullishCoalesce(_optionalChain([s, 'access', _313 => _313.copies, 'optionalAccess', _314 => _314.length]), () => ( 0)),
7222
7658
  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) }
7223
7659
  };
7224
7660
  })
@@ -7401,21 +7837,21 @@ var PAINT_TOOLS = [
7401
7837
  { id: "pan", label: "Pan", key: "h" },
7402
7838
  { id: "rotate", label: "Rotate view", key: "r" }
7403
7839
  ];
7404
- var PaintGesture = (_class10 = class {
7405
- constructor(controller, box) {;_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);
7840
+ var PaintGesture = (_class11 = class {
7841
+ constructor(controller, box) {;_class11.prototype.__init109.call(this);_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);
7406
7842
  this.controller = controller;
7407
7843
  this.box = box;
7408
7844
  }
7409
7845
 
7410
7846
 
7411
- __init103() {this.tool = "brush"}
7847
+ __init109() {this.tool = "brush"}
7412
7848
  /** The last refusal (a hidden or locked layer), for the editor to show. */
7413
- __init104() {this.error = null}
7849
+ __init110() {this.error = null}
7414
7850
  /** The predicted tail of the current stroke in document pixels (draw it as a thin preview). */
7415
- __init105() {this.predicted = []}
7416
- __init106() {this.mode = null}
7417
- __init107() {this.penAt = null}
7418
- __init108() {this.penDown = false}
7851
+ __init111() {this.predicted = []}
7852
+ __init112() {this.mode = null}
7853
+ __init113() {this.penAt = null}
7854
+ __init114() {this.penDown = false}
7419
7855
  doc(e) {
7420
7856
  const b = this.box();
7421
7857
  const s = this.controller.getState();
@@ -7496,12 +7932,12 @@ var PaintGesture = (_class10 = class {
7496
7932
  if (!m || m.pointerId !== e.pointerId) return;
7497
7933
  this.mode = null;
7498
7934
  this.predicted = [];
7499
- if (m.kind === "stroke") _optionalChain([this, 'access', _291 => _291.controller, 'access', _292 => _292.activeStroke, 'optionalAccess', _293 => _293.end, 'call', _294 => _294()]);
7935
+ if (m.kind === "stroke") _optionalChain([this, 'access', _315 => _315.controller, 'access', _316 => _316.activeStroke, 'optionalAccess', _317 => _317.end, 'call', _318 => _318()]);
7500
7936
  }
7501
7937
  cancel() {
7502
7938
  this.penDown = false;
7503
7939
  this.predicted = [];
7504
- if (_optionalChain([this, 'access', _295 => _295.mode, 'optionalAccess', _296 => _296.kind]) === "stroke") _optionalChain([this, 'access', _297 => _297.controller, 'access', _298 => _298.activeStroke, 'optionalAccess', _299 => _299.cancel, 'call', _300 => _300()]);
7940
+ if (_optionalChain([this, 'access', _319 => _319.mode, 'optionalAccess', _320 => _320.kind]) === "stroke") _optionalChain([this, 'access', _321 => _321.controller, 'access', _322 => _322.activeStroke, 'optionalAccess', _323 => _323.cancel, 'call', _324 => _324()]);
7505
7941
  this.mode = null;
7506
7942
  }
7507
7943
  get active() {
@@ -7521,7 +7957,7 @@ var PaintGesture = (_class10 = class {
7521
7957
  const py = e.clientY - b.top - b.height / 2;
7522
7958
  this.controller.setView({ zoom, pan: { x: px - (px - s.view.pan.x) * k, y: py - (py - s.view.pan.y) * k } });
7523
7959
  }
7524
- }, _class10);
7960
+ }, _class11);
7525
7961
  function handlePaintShortcut(controller, gesture, e) {
7526
7962
  const mod = e.ctrlKey || e.metaKey;
7527
7963
  const key = e.key.toLowerCase();
@@ -7561,14 +7997,14 @@ function handlePaintShortcut(controller, gesture, e) {
7561
7997
  }
7562
7998
  return false;
7563
7999
  }
7564
- var PaintCanvasPresenter = (_class11 = class {
7565
- constructor(controller) {;_class11.prototype.__init109.call(this);_class11.prototype.__init110.call(this);_class11.prototype.__init111.call(this);
8000
+ var PaintCanvasPresenter = (_class12 = class {
8001
+ constructor(controller) {;_class12.prototype.__init115.call(this);_class12.prototype.__init116.call(this);_class12.prototype.__init117.call(this);
7566
8002
  this.controller = controller;
7567
8003
  }
7568
8004
 
7569
- __init109() {this.uploaded = /* @__PURE__ */ new Map()}
7570
- __init110() {this.scratch = null}
7571
- __init111() {this.size = ""}
8005
+ __init115() {this.uploaded = /* @__PURE__ */ new Map()}
8006
+ __init116() {this.scratch = null}
8007
+ __init117() {this.size = ""}
7572
8008
  /** Draws what changed into `ctx` (a canvas the size of the document); returns the tiles drawn. */
7573
8009
  render(ctx) {
7574
8010
  const { width, height } = this.controller.document.canvas;
@@ -7594,7 +8030,7 @@ var PaintCanvasPresenter = (_class11 = class {
7594
8030
  }, { dirty });
7595
8031
  return drawn;
7596
8032
  }
7597
- }, _class11);
8033
+ }, _class12);
7598
8034
  function guideOverlay(controller) {
7599
8035
  const s = controller.getState();
7600
8036
  const size = s.document.canvas;
@@ -7635,7 +8071,7 @@ var PAPER_SLIDERS = [
7635
8071
  ];
7636
8072
  function readPath(obj, path) {
7637
8073
  let v = obj;
7638
- for (const k of path.split(".")) v = _optionalChain([v, 'optionalAccess', _301 => _301[k]]);
8074
+ for (const k of path.split(".")) v = _optionalChain([v, 'optionalAccess', _325 => _325[k]]);
7639
8075
  return typeof v === "number" ? v : 0;
7640
8076
  }
7641
8077
  function patchPath(obj, path, value) {
@@ -7757,7 +8193,7 @@ function brushEngineControls(brush) {
7757
8193
  impastoTool: true
7758
8194
  };
7759
8195
  case "wet": {
7760
- const tool = _nullishCoalesce(_optionalChain([brush, 'access', _302 => _302.wet, 'optionalAccess', _303 => _303.tool]), () => ( "paint"));
8196
+ const tool = _nullishCoalesce(_optionalChain([brush, 'access', _326 => _326.wet, 'optionalAccess', _327 => _327.tool]), () => ( "paint"));
7761
8197
  const sliders = tool === "paint" ? [
7762
8198
  { path: "wet.water", label: "Water", min: 0, max: 1, step: 0.01 },
7763
8199
  { path: "wet.pigment", label: "Pigment", min: 0, max: 1, step: 0.01 },
@@ -7890,7 +8326,7 @@ function startWetClock(controller, frame, cancel) {
7890
8326
  id = raf(loop);
7891
8327
  return () => {
7892
8328
  stopped = true;
7893
- _optionalChain([caf, 'optionalCall', _304 => _304(id)]);
8329
+ _optionalChain([caf, 'optionalCall', _328 => _328(id)]);
7894
8330
  };
7895
8331
  }
7896
8332
  function drawWaterOverlay(controller, ctx) {
@@ -7939,6 +8375,190 @@ function quickStencil(kind, canvas) {
7939
8375
  }
7940
8376
  }
7941
8377
 
8378
+ // src/paint-editor/effect-tools.ts
8379
+ var PAPER_TARGET = "paper";
8380
+ var ref = (s) => ({ effect: s.effect, ...s.name ? { name: s.name } : {}, ...s.provider ? { provider: s.provider } : {} });
8381
+ function createPaintEffectsToolProvider(controller, options = {}) {
8382
+ const readOnlyReason = () => {
8383
+ const ro = typeof options.readOnly === "function" ? options.readOnly() : options.readOnly;
8384
+ return ro ? typeof ro === "string" ? ro : "The painting is read-only." : null;
8385
+ };
8386
+ const paperInfo = () => {
8387
+ const p = controller.getPaperEffect();
8388
+ 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 } : {} }] : [];
8389
+ };
8390
+ const layerInfo = (layerId) => {
8391
+ const s = controller.getEffectLayer(layerId);
8392
+ return s ? [{ id: "effect", ...ref(s), role: "effect layer", enabled: true, values: s.values, ...s.time ? { time: s.time } : {} }] : [];
8393
+ };
8394
+ const requireLayer = (id) => {
8395
+ const l = controller.getLayer(id);
8396
+ if (!l) {
8397
+ const ids = controller.listLayers().map((x) => `"${x.id}"`);
8398
+ throw new Error(`There is no layer "${id}"; the targets are "${PAPER_TARGET}" and the layers ${ids.join(", ") || "(none)"} (list_layers lists them).`);
8399
+ }
8400
+ return l;
8401
+ };
8402
+ const effectsOf = (target) => target === PAPER_TARGET ? paperInfo() : layerInfo(target);
8403
+ const instanceCheck = (target, instance) => {
8404
+ const want = target === PAPER_TARGET ? PAPER_TARGET : "effect";
8405
+ if (target !== PAPER_TARGET) requireLayer(target);
8406
+ if (instance !== want || !effectsOf(target).length) {
8407
+ const have = effectsOf(target).map((e) => `"${e.id}"`);
8408
+ throw new Error(
8409
+ `${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.`
8410
+ );
8411
+ }
8412
+ };
8413
+ const noStackArgs = (changes) => {
8414
+ if (changes.index !== void 0) throw new Error("index does not apply: the paper and each effect layer have one effect.");
8415
+ if (changes.enabled !== void 0) throw new Error("enabled does not apply here: hide an effect layer with update_layer visible false, or remove the effect paper.");
8416
+ };
8417
+ const values = (v) => v;
8418
+ return _chunkJODTP4DPcjs.createEffectToolProvider.call(void 0, {
8419
+ id: _nullishCoalesce(options.id, () => ( "paint-effects")),
8420
+ namespace: options.namespace,
8421
+ target: { noun: "layer", id: `A pixel layer id from list_layers ("${PAPER_TARGET}" is the effect paper, for list, update and remove).` },
8422
+ applyUses: ["filter"],
8423
+ 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).",
8424
+ provider: () => controller.effectsProvider,
8425
+ readOnlyReason,
8426
+ list: (target) => {
8427
+ if (target === PAPER_TARGET) return [{ target: PAPER_TARGET, name: "Paper", effects: paperInfo() }];
8428
+ if (target) {
8429
+ const l = requireLayer(target);
8430
+ return [{ target, name: l.name, effects: layerInfo(target) }];
8431
+ }
8432
+ const out = [];
8433
+ if (paperInfo().length) out.push({ target: PAPER_TARGET, name: "Paper", effects: paperInfo() });
8434
+ for (const e of controller.listEffectLayers()) out.push({ target: e.layerId, name: e.name, effects: layerInfo(e.layerId) });
8435
+ return out;
8436
+ },
8437
+ apply: async (target, effect, args) => {
8438
+ 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.");
8439
+ noStackArgs(args);
8440
+ requireLayer(target);
8441
+ const r = await controller.applyLightEffect(target, effect, { values: values(args.values), amount: args.opacity });
8442
+ const applied = { id: "light", ...ref(r.source), role: "baked light", enabled: true, opacity: r.amount, values: r.source.values };
8443
+ return { target, effect: applied, effects: layerInfo(target), baked: true };
8444
+ },
8445
+ update: async (target, instance, changes) => {
8446
+ instanceCheck(target, instance);
8447
+ noStackArgs(changes);
8448
+ if (target === PAPER_TARGET) {
8449
+ await controller.updatePaperEffect({ values: changes.values, opacity: changes.opacity });
8450
+ const effects2 = paperInfo();
8451
+ return { target, effect: effects2[0], effects: effects2 };
8452
+ }
8453
+ if (changes.opacity !== void 0) throw new Error("An effect layer's opacity is the layer's: change it with update_layer.");
8454
+ await controller.updateEffectLayer(target, { values: changes.values });
8455
+ const effects = layerInfo(target);
8456
+ return { target, effect: effects[0], effects };
8457
+ },
8458
+ remove: async (target, instance) => {
8459
+ instanceCheck(target, instance);
8460
+ const was = effectsOf(target)[0];
8461
+ if (target === PAPER_TARGET) await controller.setPaperEffect(null);
8462
+ else controller.rasterizeEffectLayer(target);
8463
+ return { target, effect: was, effects: [], ...target === PAPER_TARGET ? {} : { keptPixels: true } };
8464
+ },
8465
+ subscribe: (notify) => {
8466
+ const a = controller.subscribe(() => notify());
8467
+ const b = controller.effects.subscribe(() => notify());
8468
+ return () => {
8469
+ a();
8470
+ b();
8471
+ };
8472
+ },
8473
+ extraTools: (ctx) => [
8474
+ {
8475
+ name: "set_paper_effect",
8476
+ title: "Set the effect paper",
8477
+ description: `Draws a provider generator (search_effects with use generator) over the paper and under the paint, at the canvas size: multiplied by default, so the paper's colour and grain still show. Replaces any effect paper; it is saved and exported with the painting. effect null removes it. One undo step. Returns the effect paper (update_effect / remove_effect with target and effect "paper" change it later).`,
8478
+ inputSchema: {
8479
+ type: "object",
8480
+ properties: {
8481
+ effect: { anyOf: [ctx.effectIdSchema(["generator"]), { type: "null" }], description: "A generator effect id from search_effects, or null to remove the effect paper." },
8482
+ values: ctx.valuesSchema("Control values over the effect's defaults"),
8483
+ opacity: { type: "number", minimum: 0, maximum: 1, description: "Strength 0\u20131 (default 1, or the current effect paper's)." },
8484
+ blend: { type: "string", enum: [...PAPER_EFFECT_BLENDS], description: "How it draws over the paper (default multiply, which keeps the paper's grain; normal covers it)." },
8485
+ time: { type: "number", minimum: 0, description: "Which moment of an animated effect to draw, in ms (default 0)." }
8486
+ },
8487
+ required: ["effect"],
8488
+ additionalProperties: false
8489
+ },
8490
+ annotations: { title: "Set the effect paper", ...ctx.annotations.writeIdempotent },
8491
+ handler: async (args) => {
8492
+ if (args.effect !== null) ctx.requireProvider();
8493
+ return { paperEffect: await controller.setPaperEffect(args.effect, { values: values(args.values), opacity: args.opacity, blend: args.blend, time: args.time }) };
8494
+ }
8495
+ },
8496
+ {
8497
+ name: "add_effect_layer",
8498
+ title: "Add an effect layer",
8499
+ description: 'Adds a pixel layer drawn by a provider generator, overlay or title effect (search_effects with use generator, overlay or title) at the canvas size, above the active layer unless aboveId is given, and makes it active. Paint on it like any layer; update_effect (effect "effect") draws it again with new values, replacing its pixels; remove_effect keeps its pixels as a plain layer. One undo step. Returns the new layer and its effect.',
8500
+ inputSchema: {
8501
+ type: "object",
8502
+ properties: {
8503
+ effect: ctx.effectIdSchema(["generator", "overlay", "title"]),
8504
+ values: ctx.valuesSchema("Control values over the effect's defaults"),
8505
+ name: { type: "string", minLength: 1, description: "The layer name (default: the effect's name)." },
8506
+ aboveId: { type: "string", minLength: 1, description: "Put it directly above this layer (default: above the active layer, else on top)." },
8507
+ opacity: { type: "number", minimum: 0, maximum: 1, description: "Layer opacity 0\u20131 (default 1)." },
8508
+ blend: { type: "string", enum: _chunkJ5BA3BQ6cjs.BLEND_MODES.map((m) => m.id), description: "Layer blend mode (default normal); screen or linear-dodge for light, multiply for textures." },
8509
+ time: { type: "number", minimum: 0, description: "Which moment of an animated effect to draw, in ms (default 0)." }
8510
+ },
8511
+ required: ["effect"],
8512
+ additionalProperties: false
8513
+ },
8514
+ annotations: { title: "Add an effect layer", ...ctx.annotations.write },
8515
+ handler: async (args) => {
8516
+ ctx.requireProvider();
8517
+ const r = await controller.addEffectLayer(args.effect, { values: values(args.values), name: args.name, aboveId: args.aboveId, opacity: args.opacity, blend: args.blend, time: args.time });
8518
+ return { layer: r.layer, effects: layerInfo(r.layer.id) };
8519
+ }
8520
+ },
8521
+ {
8522
+ name: "fill_layer_with_effect",
8523
+ title: "Fill a layer with an effect",
8524
+ description: "Composites a provider generator, overlay or title effect (rendered at the canvas size) onto a layer's pixels at opacity, as a fill: the layer keeps no link to the effect. lockTransparency (or a transparency-locked layer) only colours what is already painted. Wet paint is refused: dry it first (dry_paint). One undo step. Returns the layer id and the effect used.",
8525
+ inputSchema: {
8526
+ type: "object",
8527
+ properties: {
8528
+ effect: ctx.effectIdSchema(["generator", "overlay", "title"]),
8529
+ layerId: { type: "string", minLength: 1, description: "The pixel layer to fill (default: the active layer)." },
8530
+ values: ctx.valuesSchema("Control values over the effect's defaults"),
8531
+ opacity: { type: "number", minimum: 0, maximum: 1, description: "Fill strength 0\u20131 (default 1)." },
8532
+ lockTransparency: { type: "boolean", description: "Only colour pixels that are already painted (default false)." },
8533
+ time: { type: "number", minimum: 0, description: "Which moment of an animated effect to draw, in ms (default 0)." }
8534
+ },
8535
+ required: ["effect"],
8536
+ additionalProperties: false
8537
+ },
8538
+ annotations: { title: "Fill a layer with an effect", ...ctx.annotations.write },
8539
+ handler: async (args) => {
8540
+ ctx.requireProvider();
8541
+ return controller.fillLayerWithEffect(args.effect, { layerId: args.layerId, values: values(args.values), opacity: args.opacity, lockTransparency: args.lockTransparency, time: args.time });
8542
+ }
8543
+ }
8544
+ ]
8545
+ });
8546
+ }
8547
+
8548
+
8549
+
8550
+
8551
+
8552
+
8553
+
8554
+
8555
+
8556
+
8557
+
8558
+
8559
+
8560
+
8561
+
7942
8562
 
7943
8563
 
7944
8564
 
@@ -8225,5 +8845,5 @@ function quickStencil(kind, canvas) {
8225
8845
 
8226
8846
 
8227
8847
 
8228
- exports.BLEND_MENU_GROUPS = BLEND_MENU_GROUPS; exports.BLEND_MODES = _chunkJ5BA3BQ6cjs.BLEND_MODES; exports.BRUSH_ID = _chunkW4LNKTHTcjs.BRUSH_ID; exports.BRUSH_ROTATIONS = _chunkW4LNKTHTcjs.BRUSH_ROTATIONS; exports.BRUSH_SLIDERS = BRUSH_SLIDERS; exports.BUILTIN_BRUSHES = _chunkW4LNKTHTcjs.BUILTIN_BRUSHES; exports.BristleStroke = _chunkW4LNKTHTcjs.BristleStroke; exports.DEFAULT_BEHAVIOR = _chunkW4LNKTHTcjs.DEFAULT_BEHAVIOR; exports.DEFAULT_BRISTLE = _chunkW4LNKTHTcjs.DEFAULT_BRISTLE; exports.DEFAULT_BRUSH_ID = _chunkW4LNKTHTcjs.DEFAULT_BRUSH_ID; exports.DEFAULT_DPI = DEFAULT_DPI; exports.DEFAULT_DYNAMICS = _chunkW4LNKTHTcjs.DEFAULT_DYNAMICS; exports.DEFAULT_FLOW = _chunkFHPVDTI2cjs.DEFAULT_FLOW; exports.DEFAULT_IMPASTO = _chunkW4LNKTHTcjs.DEFAULT_IMPASTO; exports.DEFAULT_LIGHTING = DEFAULT_LIGHTING; exports.DEFAULT_MULTI_COLOR = _chunkW4LNKTHTcjs.DEFAULT_MULTI_COLOR; exports.DEFAULT_PAINT_GRADIENT = _chunk6GFRKLLScjs.DEFAULT_PAINT_GRADIENT; exports.DEFAULT_PAINT_GRADIENT_MAPPING = _chunk6GFRKLLScjs.DEFAULT_PAINT_GRADIENT_MAPPING; exports.DEFAULT_PAPER = _chunkW4LNKTHTcjs.DEFAULT_PAPER; exports.DEFAULT_PARTICLE = _chunkW4LNKTHTcjs.DEFAULT_PARTICLE; exports.DEFAULT_STICKER = _chunkW4LNKTHTcjs.DEFAULT_STICKER; exports.DEFAULT_SWATCHES = DEFAULT_SWATCHES; exports.DEFAULT_VIEW = DEFAULT_VIEW; exports.DEFAULT_WET_BRUSH = _chunkW4LNKTHTcjs.DEFAULT_WET_BRUSH; exports.DEFAULT_WET_PARAMS = _chunkFHPVDTI2cjs.DEFAULT_WET_PARAMS; exports.DryStroke = _chunkW4LNKTHTcjs.DryStroke; exports.GPU_LEAD = GPU_LEAD; exports.GRAIN_PATTERNS = _chunkW4LNKTHTcjs.GRAIN_PATTERNS; exports.GRAIN_TILE = _chunkW4LNKTHTcjs.GRAIN_TILE; exports.HARMONY_KINDS = HARMONY_KINDS; exports.IDENTITY_AFFINE = IDENTITY_AFFINE; exports.IDENTITY_COPY = _chunkW4LNKTHTcjs.IDENTITY_COPY; exports.IMPASTO_TOOLS = _chunkW4LNKTHTcjs.IMPASTO_TOOLS; exports.IMPASTO_TOOL_LABELS = IMPASTO_TOOL_LABELS; exports.LIGHT_SLIDERS = LIGHT_SLIDERS; exports.LitCache = LitCache; exports.MAX_BRUSH_SIZE = _chunk6GFRKLLScjs.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 = _chunkW4LNKTHTcjs.MULTI_COLOR_MODES; exports.MixingPad = MixingPad; exports.PAD_SAMPLE_SIZES = PAD_SAMPLE_SIZES; exports.PAINTERLY_BLEND_MODES = _chunkJ5BA3BQ6cjs.PAINTERLY_BLEND_MODES; exports.PAINT_BRUSH_CATEGORIES = _chunkW4LNKTHTcjs.PAINT_BRUSH_CATEGORIES; exports.PAINT_BRUSH_ENGINES = _chunkW4LNKTHTcjs.PAINT_BRUSH_ENGINES; exports.PAINT_COLOR_JSON_SCHEMA = _chunk6GFRKLLScjs.PAINT_COLOR_JSON_SCHEMA; exports.PAINT_FORMAT = PAINT_FORMAT; exports.PAINT_GRADIENT_FULL_SPEED = _chunk6GFRKLLScjs.PAINT_GRADIENT_FULL_SPEED; exports.PAINT_GRADIENT_JSON_SCHEMA = _chunk6GFRKLLScjs.PAINT_GRADIENT_JSON_SCHEMA; exports.PAINT_GRADIENT_KIT = _chunk6GFRKLLScjs.PAINT_GRADIENT_KIT; exports.PAINT_GRADIENT_MAPPINGS = _chunk6GFRKLLScjs.PAINT_GRADIENT_MAPPINGS; exports.PAINT_GRADIENT_MAPPING_LABELS = _chunk6GFRKLLScjs.PAINT_GRADIENT_MAPPING_LABELS; exports.PAINT_GRADIENT_PRESETS = _chunk6GFRKLLScjs.PAINT_GRADIENT_PRESETS; exports.PAINT_GRADIENT_REPEATS = _chunk6GFRKLLScjs.PAINT_GRADIENT_REPEATS; exports.PAINT_GRADIENT_REPEAT_LABELS = _chunk6GFRKLLScjs.PAINT_GRADIENT_REPEAT_LABELS; exports.PAINT_GRADIENT_SPACES = _chunk6GFRKLLScjs.PAINT_GRADIENT_SPACES; exports.PAINT_GRADIENT_SPACE_LABELS = _chunk6GFRKLLScjs.PAINT_GRADIENT_SPACE_LABELS; exports.PAINT_SCHEMA_VERSION = PAINT_SCHEMA_VERSION; exports.PAINT_SOURCE_JSON_SCHEMA = _chunk6GFRKLLScjs.PAINT_SOURCE_JSON_SCHEMA; exports.PAINT_TOOLS = PAINT_TOOLS; exports.PAPER_FAMILIES = _chunkW4LNKTHTcjs.PAPER_FAMILIES; exports.PAPER_LIBRARY = _chunkW4LNKTHTcjs.PAPER_LIBRARY; exports.PAPER_NODE_ID = PAPER_NODE_ID; exports.PAPER_SLIDERS = PAPER_SLIDERS; exports.PARTICLE_KINDS = _chunkW4LNKTHTcjs.PARTICLE_KINDS; exports.PARTICLE_KIND_LABELS = PARTICLE_KIND_LABELS; exports.PARTICLE_RENDERS = _chunkW4LNKTHTcjs.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.PaintGesture = PaintGesture; exports.PaintGradientSampler = _chunk6GFRKLLScjs.PaintGradientSampler; exports.PaintPresence = PaintPresence; exports.PaintSourceError = _chunk6GFRKLLScjs.PaintSourceError; exports.PaintStrokeSession = PaintStrokeSession; exports.PaintWetLayers = PaintWetLayers; exports.PaperGrain = _chunkW4LNKTHTcjs.PaperGrain; exports.ParticleStroke = _chunkW4LNKTHTcjs.ParticleStroke; exports.PenDabWalker = _chunkW4LNKTHTcjs.PenDabWalker; exports.PenSmoother = _chunkW4LNKTHTcjs.PenSmoother; exports.PerspectiveSnapper = PerspectiveSnapper; exports.SNAP_DECIDE_DISTANCE = SNAP_DECIDE_DISTANCE; exports.STAMP_KINDS = _chunkW4LNKTHTcjs.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 = _chunkW4LNKTHTcjs.StickerSpray; exports.TRACING_NODE_ID = TRACING_NODE_ID; exports.ThickStrokeDriver = ThickStrokeDriver; exports.TileableNoise = _chunkW4LNKTHTcjs.TileableNoise; exports.WET_FLOW_KINDS = _chunkFHPVDTI2cjs.WET_FLOW_KINDS; exports.WET_GPU_MODES = WET_GPU_MODES; exports.WET_GPU_OPTIONS = WET_GPU_OPTIONS; exports.WET_MEDIA = _chunkW4LNKTHTcjs.WET_MEDIA; exports.WET_MEDIUM_LABELS = WET_MEDIUM_LABELS; exports.WET_MEDIUM_PARAMS = WET_MEDIUM_PARAMS; exports.WET_PARAM_KEYS = _chunkFHPVDTI2cjs.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 = _chunkW4LNKTHTcjs.WET_TOOLS; exports.WET_TOOL_LABELS = WET_TOOL_LABELS; exports.WetStrokeDriver = WetStrokeDriver; exports.addPaintGradientStop = _chunk6GFRKLLScjs.addPaintGradientStop; exports.affineCopy = affineCopy; exports.applyAffine = applyAffine; exports.brushEngineControls = brushEngineControls; exports.brushLoadColor = brushLoadColor; exports.brushLoadForStroke = brushLoadForStroke; exports.brushTakesPaint = _chunkW4LNKTHTcjs.brushTakesPaint; exports.brushToJSON = _chunkW4LNKTHTcjs.brushToJSON; exports.buildTimeLapse = buildTimeLapse; exports.clonePaper = _chunkW4LNKTHTcjs.clonePaper; exports.colorHarmony = colorHarmony; exports.composeAffine = composeAffine; exports.contactSheet = contactSheet; exports.createPaintCompositor = createPaintCompositor; exports.createPaintDocument = createPaintDocument; exports.createPaintEditorToolProvider = createPaintEditorToolProvider; 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 = _chunkW4LNKTHTcjs.drawSticker; exports.drawWaterOverlay = drawWaterOverlay; exports.emptiedLayers = emptiedLayers; exports.emptyThickChannels = emptyThickChannels; exports.fitZoom = fitZoom; exports.grainCatch = _chunkW4LNKTHTcjs.grainCatch; exports.grainHeights = _chunkW4LNKTHTcjs.grainHeights; exports.guideOverlay = guideOverlay; exports.handlePaintShortcut = handlePaintShortcut; exports.hash2 = _chunk6GFRKLLScjs.hash2; exports.hexToPaintRgb = _chunk6GFRKLLScjs.hexToPaintRgb; exports.hexToRgb8 = _chunkW4LNKTHTcjs.hexToRgb8; exports.hslToRgb = hslToRgb; exports.hsvToRgb = hsvToRgb; exports.hueToWheel = hueToWheel; exports.invertAffine = invertAffine; exports.isBlendMode = _chunkJ5BA3BQ6cjs.isBlendMode; exports.isGradientPaint = _chunk6GFRKLLScjs.isGradientPaint; exports.isPainterlyBlendMode = _chunkJ5BA3BQ6cjs.isPainterlyBlendMode; exports.isPalmTouch = isPalmTouch; exports.isWetBrush = _chunkW4LNKTHTcjs.isWetBrush; exports.isWetCapable = _chunkW4LNKTHTcjs.isWetCapable; exports.lightTile = lightTile; exports.lightingKey = lightingKey; exports.mapPenPoint = mapPenPoint; exports.mix32 = _chunk6GFRKLLScjs.mix32; exports.mixerLoadForStroke = mixerLoadForStroke; exports.mixerTip = _chunkW4LNKTHTcjs.mixerTip; exports.multiColorForDab = multiColorForDab; exports.multiColorGradient = multiColorGradient; exports.multiColorPalette = multiColorPalette; exports.multiColorSliders = multiColorSliders; exports.multiColorToPaint = _chunkW4LNKTHTcjs.multiColorToPaint; exports.newPaintLayerId = newPaintLayerId; exports.normalizeBehavior = _chunkW4LNKTHTcjs.normalizeBehavior; exports.normalizeBristle = _chunkW4LNKTHTcjs.normalizeBristle; exports.normalizeBrushStroke = normalizeBrushStroke; exports.normalizeCanvas = normalizeCanvas; exports.normalizeDynamics = _chunkW4LNKTHTcjs.normalizeDynamics; exports.normalizeFlow = _chunkFHPVDTI2cjs.normalizeFlow; exports.normalizeHexColor = _chunk6GFRKLLScjs.normalizeHexColor; exports.normalizeImpasto = _chunkW4LNKTHTcjs.normalizeImpasto; exports.normalizeLighting = normalizeLighting; exports.normalizeMultiColor = _chunkW4LNKTHTcjs.normalizeMultiColor; exports.normalizePaintBrush = _chunkW4LNKTHTcjs.normalizePaintBrush; exports.normalizePaper = _chunkW4LNKTHTcjs.normalizePaper; exports.normalizeParticle = _chunkW4LNKTHTcjs.normalizeParticle; exports.normalizePerspective = normalizePerspective; exports.normalizeRotation = normalizeRotation; exports.normalizeStencil = normalizeStencil; exports.normalizeStickerSettings = _chunkW4LNKTHTcjs.normalizeStickerSettings; exports.normalizeStickerUpdate = _chunkW4LNKTHTcjs.normalizeStickerUpdate; exports.normalizeSymmetry = normalizeSymmetry; exports.normalizeView = normalizeView; exports.normalizeWetBrush = _chunkW4LNKTHTcjs.normalizeWetBrush; exports.normalizeWetParams = _chunkFHPVDTI2cjs.normalizeWetParams; exports.padSampleRadius = padSampleRadius; exports.paintGradientMappingFor = _chunk6GFRKLLScjs.paintGradientMappingFor; exports.paintSourceColor = _chunk6GFRKLLScjs.paintSourceColor; exports.paintSourceCss = _chunk6GFRKLLScjs.paintSourceCss; exports.paintToMultiColor = _chunkW4LNKTHTcjs.paintToMultiColor; exports.paperGrain = paperGrain; exports.paperKey = paperKey; exports.paperNode = paperNode; exports.paperPreset = _chunkW4LNKTHTcjs.paperPreset; exports.parseBrushLibrary = _chunkW4LNKTHTcjs.parseBrushLibrary; exports.parseHexColor = parseHexColor; exports.parsePaintSource = _chunk6GFRKLLScjs.parsePaintSource; exports.patchBrushValue = patchBrushValue; exports.patchPath = patchPath; exports.penOrientation = _chunkW4LNKTHTcjs.penOrientation; exports.perspectiveDirections = perspectiveDirections; exports.perspectiveGuideLines = perspectiveGuideLines; exports.pointerToPenPoint = pointerToPenPoint; exports.quickStencil = quickStencil; exports.rand01 = _chunk6GFRKLLScjs.rand01; exports.randSigned = _chunkW4LNKTHTcjs.randSigned; exports.readPaintSource = _chunk6GFRKLLScjs.readPaintSource; exports.readPath = readPath; exports.readSwatch = readSwatch; exports.reliefInfo = reliefInfo; exports.removePaintGradientStop = _chunk6GFRKLLScjs.removePaintGradientStop; exports.renderBrushThumbnail = renderBrushThumbnail; exports.renderColorWheel = renderColorWheel; exports.renderPaper = _chunkW4LNKTHTcjs.renderPaper; exports.renderStickers = _chunkW4LNKTHTcjs.renderStickers; exports.replayFrame = replayFrame; exports.replayItems = replayItems; exports.replayPainting = replayPainting; exports.resolvePaintGradient = _chunk6GFRKLLScjs.resolvePaintGradient; exports.reversePaintGradient = _chunk6GFRKLLScjs.reversePaintGradient; exports.rgbToHexColor = rgbToHexColor; exports.rgbToHsl = rgbToHsl; exports.rgbToHsv = rgbToHsv; exports.samplePressure = samplePressure; exports.scalePaintGradient = _chunk6GFRKLLScjs.scalePaintGradient; exports.scaleStencil = scaleStencil; exports.screenToDocument = screenToDocument; exports.seedFromString = _chunkW4LNKTHTcjs.seedFromString; exports.serializePaintDocument = serializePaintDocument; exports.serializePaintDocumentExternal = serializePaintDocumentExternal; exports.solidPaint = _chunk6GFRKLLScjs.solidPaint; exports.stampCoverage = _chunkW4LNKTHTcjs.stampCoverage; exports.standardBlendMode = _chunkJ5BA3BQ6cjs.standardBlendMode; exports.startWetClock = startWetClock; exports.stencilMask = stencilMask; exports.stencilOutline = stencilOutline; exports.stickerRect = _chunkW4LNKTHTcjs.stickerRect; exports.stickerSurface = _chunkW4LNKTHTcjs.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 = _chunkW4LNKTHTcjs.tiltToOrientation; exports.timeLapseVideo = timeLapseVideo; exports.timeLapseZip = timeLapseZip; exports.toStrokePoint = _chunkW4LNKTHTcjs.toStrokePoint; exports.toggleStamp = toggleStamp; exports.updatePaintGradientStop = _chunk6GFRKLLScjs.updatePaintGradientStop; exports.usesPaintExchange = _chunkW4LNKTHTcjs.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 = _chunkFHPVDTI2cjs.wetSupport; exports.wheelAngle = wheelAngle; exports.wheelPick = wheelPick; exports.wheelPoint = wheelPoint; exports.wheelToHue = wheelToHue;
8848
+ exports.BLEND_MENU_GROUPS = BLEND_MENU_GROUPS; exports.BLEND_MODES = _chunkJ5BA3BQ6cjs.BLEND_MODES; exports.BRUSH_ID = _chunkW4LNKTHTcjs.BRUSH_ID; exports.BRUSH_ROTATIONS = _chunkW4LNKTHTcjs.BRUSH_ROTATIONS; exports.BRUSH_SLIDERS = BRUSH_SLIDERS; exports.BUILTIN_BRUSHES = _chunkW4LNKTHTcjs.BUILTIN_BRUSHES; exports.BristleStroke = _chunkW4LNKTHTcjs.BristleStroke; exports.DEFAULT_BEHAVIOR = _chunkW4LNKTHTcjs.DEFAULT_BEHAVIOR; exports.DEFAULT_BRISTLE = _chunkW4LNKTHTcjs.DEFAULT_BRISTLE; exports.DEFAULT_BRUSH_ID = _chunkW4LNKTHTcjs.DEFAULT_BRUSH_ID; exports.DEFAULT_DPI = DEFAULT_DPI; exports.DEFAULT_DYNAMICS = _chunkW4LNKTHTcjs.DEFAULT_DYNAMICS; exports.DEFAULT_FLOW = _chunkFHPVDTI2cjs.DEFAULT_FLOW; exports.DEFAULT_IMPASTO = _chunkW4LNKTHTcjs.DEFAULT_IMPASTO; exports.DEFAULT_LIGHTING = DEFAULT_LIGHTING; exports.DEFAULT_MULTI_COLOR = _chunkW4LNKTHTcjs.DEFAULT_MULTI_COLOR; exports.DEFAULT_PAINT_GRADIENT = _chunk6GFRKLLScjs.DEFAULT_PAINT_GRADIENT; exports.DEFAULT_PAINT_GRADIENT_MAPPING = _chunk6GFRKLLScjs.DEFAULT_PAINT_GRADIENT_MAPPING; exports.DEFAULT_PAPER = _chunkW4LNKTHTcjs.DEFAULT_PAPER; exports.DEFAULT_PARTICLE = _chunkW4LNKTHTcjs.DEFAULT_PARTICLE; exports.DEFAULT_STICKER = _chunkW4LNKTHTcjs.DEFAULT_STICKER; exports.DEFAULT_SWATCHES = DEFAULT_SWATCHES; exports.DEFAULT_VIEW = DEFAULT_VIEW; exports.DEFAULT_WET_BRUSH = _chunkW4LNKTHTcjs.DEFAULT_WET_BRUSH; exports.DEFAULT_WET_PARAMS = _chunkFHPVDTI2cjs.DEFAULT_WET_PARAMS; exports.DryStroke = _chunkW4LNKTHTcjs.DryStroke; exports.GPU_LEAD = GPU_LEAD; exports.GRAIN_PATTERNS = _chunkW4LNKTHTcjs.GRAIN_PATTERNS; exports.GRAIN_TILE = _chunkW4LNKTHTcjs.GRAIN_TILE; exports.HARMONY_KINDS = HARMONY_KINDS; exports.IDENTITY_AFFINE = IDENTITY_AFFINE; exports.IDENTITY_COPY = _chunkW4LNKTHTcjs.IDENTITY_COPY; exports.IMPASTO_TOOLS = _chunkW4LNKTHTcjs.IMPASTO_TOOLS; exports.IMPASTO_TOOL_LABELS = IMPASTO_TOOL_LABELS; exports.LIGHT_SLIDERS = LIGHT_SLIDERS; exports.LitCache = LitCache; exports.MAX_BRUSH_SIZE = _chunk6GFRKLLScjs.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 = _chunkW4LNKTHTcjs.MULTI_COLOR_MODES; exports.MixingPad = MixingPad; exports.PAD_SAMPLE_SIZES = PAD_SAMPLE_SIZES; exports.PAINTERLY_BLEND_MODES = _chunkJ5BA3BQ6cjs.PAINTERLY_BLEND_MODES; exports.PAINT_BRUSH_CATEGORIES = _chunkW4LNKTHTcjs.PAINT_BRUSH_CATEGORIES; exports.PAINT_BRUSH_ENGINES = _chunkW4LNKTHTcjs.PAINT_BRUSH_ENGINES; exports.PAINT_COLOR_JSON_SCHEMA = _chunk6GFRKLLScjs.PAINT_COLOR_JSON_SCHEMA; exports.PAINT_EFFECT_PLACES = PAINT_EFFECT_PLACES; exports.PAINT_FORMAT = PAINT_FORMAT; exports.PAINT_GRADIENT_FULL_SPEED = _chunk6GFRKLLScjs.PAINT_GRADIENT_FULL_SPEED; exports.PAINT_GRADIENT_JSON_SCHEMA = _chunk6GFRKLLScjs.PAINT_GRADIENT_JSON_SCHEMA; exports.PAINT_GRADIENT_KIT = _chunk6GFRKLLScjs.PAINT_GRADIENT_KIT; exports.PAINT_GRADIENT_MAPPINGS = _chunk6GFRKLLScjs.PAINT_GRADIENT_MAPPINGS; exports.PAINT_GRADIENT_MAPPING_LABELS = _chunk6GFRKLLScjs.PAINT_GRADIENT_MAPPING_LABELS; exports.PAINT_GRADIENT_PRESETS = _chunk6GFRKLLScjs.PAINT_GRADIENT_PRESETS; exports.PAINT_GRADIENT_REPEATS = _chunk6GFRKLLScjs.PAINT_GRADIENT_REPEATS; exports.PAINT_GRADIENT_REPEAT_LABELS = _chunk6GFRKLLScjs.PAINT_GRADIENT_REPEAT_LABELS; exports.PAINT_GRADIENT_SPACES = _chunk6GFRKLLScjs.PAINT_GRADIENT_SPACES; exports.PAINT_GRADIENT_SPACE_LABELS = _chunk6GFRKLLScjs.PAINT_GRADIENT_SPACE_LABELS; exports.PAINT_SCHEMA_VERSION = PAINT_SCHEMA_VERSION; exports.PAINT_SOURCE_JSON_SCHEMA = _chunk6GFRKLLScjs.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 = _chunkW4LNKTHTcjs.PAPER_FAMILIES; exports.PAPER_LIBRARY = _chunkW4LNKTHTcjs.PAPER_LIBRARY; exports.PAPER_NODE_ID = PAPER_NODE_ID; exports.PAPER_SLIDERS = PAPER_SLIDERS; exports.PAPER_TARGET = PAPER_TARGET; exports.PARTICLE_KINDS = _chunkW4LNKTHTcjs.PARTICLE_KINDS; exports.PARTICLE_KIND_LABELS = PARTICLE_KIND_LABELS; exports.PARTICLE_RENDERS = _chunkW4LNKTHTcjs.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 = _chunk6GFRKLLScjs.PaintGradientSampler; exports.PaintPresence = PaintPresence; exports.PaintSourceError = _chunk6GFRKLLScjs.PaintSourceError; exports.PaintStrokeSession = PaintStrokeSession; exports.PaintWetLayers = PaintWetLayers; exports.PaperGrain = _chunkW4LNKTHTcjs.PaperGrain; exports.ParticleStroke = _chunkW4LNKTHTcjs.ParticleStroke; exports.PenDabWalker = _chunkW4LNKTHTcjs.PenDabWalker; exports.PenSmoother = _chunkW4LNKTHTcjs.PenSmoother; exports.PerspectiveSnapper = PerspectiveSnapper; exports.SNAP_DECIDE_DISTANCE = SNAP_DECIDE_DISTANCE; exports.STAMP_KINDS = _chunkW4LNKTHTcjs.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 = _chunkW4LNKTHTcjs.StickerSpray; exports.TRACING_NODE_ID = TRACING_NODE_ID; exports.ThickStrokeDriver = ThickStrokeDriver; exports.TileableNoise = _chunkW4LNKTHTcjs.TileableNoise; exports.WET_FLOW_KINDS = _chunkFHPVDTI2cjs.WET_FLOW_KINDS; exports.WET_GPU_MODES = WET_GPU_MODES; exports.WET_GPU_OPTIONS = WET_GPU_OPTIONS; exports.WET_MEDIA = _chunkW4LNKTHTcjs.WET_MEDIA; exports.WET_MEDIUM_LABELS = WET_MEDIUM_LABELS; exports.WET_MEDIUM_PARAMS = WET_MEDIUM_PARAMS; exports.WET_PARAM_KEYS = _chunkFHPVDTI2cjs.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 = _chunkW4LNKTHTcjs.WET_TOOLS; exports.WET_TOOL_LABELS = WET_TOOL_LABELS; exports.WetStrokeDriver = WetStrokeDriver; exports.addPaintGradientStop = _chunk6GFRKLLScjs.addPaintGradientStop; exports.affineCopy = affineCopy; exports.applyAffine = applyAffine; exports.brushEngineControls = brushEngineControls; exports.brushLoadColor = brushLoadColor; exports.brushLoadForStroke = brushLoadForStroke; exports.brushTakesPaint = _chunkW4LNKTHTcjs.brushTakesPaint; exports.brushToJSON = _chunkW4LNKTHTcjs.brushToJSON; exports.buildTimeLapse = buildTimeLapse; exports.checkPaintEffectPlace = checkPaintEffectPlace; exports.clonePaper = _chunkW4LNKTHTcjs.clonePaper; exports.colorHarmony = colorHarmony; exports.composeAffine = composeAffine; exports.contactSheet = contactSheet; exports.createPaintCompositor = createPaintCompositor; exports.createPaintDocument = createPaintDocument; 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 = _chunkW4LNKTHTcjs.drawSticker; exports.drawWaterOverlay = drawWaterOverlay; exports.effectLayersToJSON = effectLayersToJSON; exports.emptiedLayers = emptiedLayers; exports.emptyThickChannels = emptyThickChannels; exports.fitZoom = fitZoom; exports.grainCatch = _chunkW4LNKTHTcjs.grainCatch; exports.grainHeights = _chunkW4LNKTHTcjs.grainHeights; exports.guideOverlay = guideOverlay; exports.handlePaintShortcut = handlePaintShortcut; exports.hash2 = _chunk6GFRKLLScjs.hash2; exports.hexToPaintRgb = _chunk6GFRKLLScjs.hexToPaintRgb; exports.hexToRgb8 = _chunkW4LNKTHTcjs.hexToRgb8; exports.hslToRgb = hslToRgb; exports.hsvToRgb = hsvToRgb; exports.hueToWheel = hueToWheel; exports.invertAffine = invertAffine; exports.isBlendMode = _chunkJ5BA3BQ6cjs.isBlendMode; exports.isGradientPaint = _chunk6GFRKLLScjs.isGradientPaint; exports.isPainterlyBlendMode = _chunkJ5BA3BQ6cjs.isPainterlyBlendMode; exports.isPalmTouch = isPalmTouch; exports.isWetBrush = _chunkW4LNKTHTcjs.isWetBrush; exports.isWetCapable = _chunkW4LNKTHTcjs.isWetCapable; exports.lightTile = lightTile; exports.lightingKey = lightingKey; exports.mapPenPoint = mapPenPoint; exports.mix32 = _chunk6GFRKLLScjs.mix32; exports.mixPixels = mixPixels; exports.mixerLoadForStroke = mixerLoadForStroke; exports.mixerTip = _chunkW4LNKTHTcjs.mixerTip; exports.multiColorForDab = multiColorForDab; exports.multiColorGradient = multiColorGradient; exports.multiColorPalette = multiColorPalette; exports.multiColorSliders = multiColorSliders; exports.multiColorToPaint = _chunkW4LNKTHTcjs.multiColorToPaint; exports.newPaintLayerId = newPaintLayerId; exports.nextPaperEffectVersion = nextPaperEffectVersion; exports.normalizeBehavior = _chunkW4LNKTHTcjs.normalizeBehavior; exports.normalizeBristle = _chunkW4LNKTHTcjs.normalizeBristle; exports.normalizeBrushStroke = normalizeBrushStroke; exports.normalizeCanvas = normalizeCanvas; exports.normalizeDynamics = _chunkW4LNKTHTcjs.normalizeDynamics; exports.normalizeFlow = _chunkFHPVDTI2cjs.normalizeFlow; exports.normalizeHexColor = _chunk6GFRKLLScjs.normalizeHexColor; exports.normalizeImpasto = _chunkW4LNKTHTcjs.normalizeImpasto; exports.normalizeLighting = normalizeLighting; exports.normalizeMultiColor = _chunkW4LNKTHTcjs.normalizeMultiColor; exports.normalizePaintBrush = _chunkW4LNKTHTcjs.normalizePaintBrush; exports.normalizePaper = _chunkW4LNKTHTcjs.normalizePaper; exports.normalizeParticle = _chunkW4LNKTHTcjs.normalizeParticle; exports.normalizePerspective = normalizePerspective; exports.normalizeRotation = normalizeRotation; exports.normalizeStencil = normalizeStencil; exports.normalizeStickerSettings = _chunkW4LNKTHTcjs.normalizeStickerSettings; exports.normalizeStickerUpdate = _chunkW4LNKTHTcjs.normalizeStickerUpdate; exports.normalizeSymmetry = normalizeSymmetry; exports.normalizeView = normalizeView; exports.normalizeWetBrush = _chunkW4LNKTHTcjs.normalizeWetBrush; exports.normalizeWetParams = _chunkFHPVDTI2cjs.normalizeWetParams; exports.overPixels = overPixels; exports.padSampleRadius = padSampleRadius; exports.paintGradientMappingFor = _chunk6GFRKLLScjs.paintGradientMappingFor; exports.paintSourceColor = _chunk6GFRKLLScjs.paintSourceColor; exports.paintSourceCss = _chunk6GFRKLLScjs.paintSourceCss; exports.paintToMultiColor = _chunkW4LNKTHTcjs.paintToMultiColor; exports.paperEffectFromJSON = paperEffectFromJSON; exports.paperEffectToJSON = paperEffectToJSON; exports.paperGrain = paperGrain; exports.paperKey = paperKey; exports.paperNode = paperNode; exports.paperPreset = _chunkW4LNKTHTcjs.paperPreset; exports.parseBrushLibrary = _chunkW4LNKTHTcjs.parseBrushLibrary; exports.parseHexColor = parseHexColor; exports.parsePaintSource = _chunk6GFRKLLScjs.parsePaintSource; exports.patchBrushValue = patchBrushValue; exports.patchPath = patchPath; exports.penOrientation = _chunkW4LNKTHTcjs.penOrientation; exports.perspectiveDirections = perspectiveDirections; exports.perspectiveGuideLines = perspectiveGuideLines; exports.pointerToPenPoint = pointerToPenPoint; exports.quickStencil = quickStencil; exports.rand01 = _chunk6GFRKLLScjs.rand01; exports.randSigned = _chunkW4LNKTHTcjs.randSigned; exports.readPaintEffectSource = readPaintEffectSource; exports.readPaintSource = _chunk6GFRKLLScjs.readPaintSource; exports.readPath = readPath; exports.readSwatch = readSwatch; exports.reliefInfo = reliefInfo; exports.removePaintGradientStop = _chunk6GFRKLLScjs.removePaintGradientStop; exports.renderBrushThumbnail = renderBrushThumbnail; exports.renderColorWheel = renderColorWheel; exports.renderPaper = _chunkW4LNKTHTcjs.renderPaper; exports.renderStickers = _chunkW4LNKTHTcjs.renderStickers; exports.replayFrame = replayFrame; exports.replayItems = replayItems; exports.replayPainting = replayPainting; exports.resolvePaintGradient = _chunk6GFRKLLScjs.resolvePaintGradient; exports.reversePaintGradient = _chunk6GFRKLLScjs.reversePaintGradient; exports.rgbToHexColor = rgbToHexColor; exports.rgbToHsl = rgbToHsl; exports.rgbToHsv = rgbToHsv; exports.samplePressure = samplePressure; exports.scalePaintGradient = _chunk6GFRKLLScjs.scalePaintGradient; exports.scaleStencil = scaleStencil; exports.screenToDocument = screenToDocument; exports.seedFromString = _chunkW4LNKTHTcjs.seedFromString; exports.serializePaintDocument = serializePaintDocument; exports.serializePaintDocumentExternal = serializePaintDocumentExternal; exports.solidPaint = _chunk6GFRKLLScjs.solidPaint; exports.stampCoverage = _chunkW4LNKTHTcjs.stampCoverage; exports.standardBlendMode = _chunkJ5BA3BQ6cjs.standardBlendMode; exports.startWetClock = startWetClock; exports.stencilMask = stencilMask; exports.stencilOutline = stencilOutline; exports.stickerRect = _chunkW4LNKTHTcjs.stickerRect; exports.stickerSurface = _chunkW4LNKTHTcjs.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 = _chunkW4LNKTHTcjs.tiltToOrientation; exports.timeLapseVideo = timeLapseVideo; exports.timeLapseZip = timeLapseZip; exports.toStrokePoint = _chunkW4LNKTHTcjs.toStrokePoint; exports.toggleStamp = toggleStamp; exports.updatePaintGradientStop = _chunk6GFRKLLScjs.updatePaintGradientStop; exports.usesPaintExchange = _chunkW4LNKTHTcjs.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 = _chunkFHPVDTI2cjs.wetSupport; exports.wheelAngle = wheelAngle; exports.wheelPick = wheelPick; exports.wheelPoint = wheelPoint; exports.wheelToHue = wheelToHue;
8229
8849
  //# sourceMappingURL=index.cjs.map