@pixerate/editor 0.252.0 → 0.254.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 (73) hide show
  1. package/dist/animation-editor/index.cjs +53 -53
  2. package/dist/animation-editor/index.js +2 -2
  3. package/dist/brushes/index.cjs +229 -2014
  4. package/dist/brushes/index.d.cts +5 -1
  5. package/dist/brushes/index.d.ts +5 -1
  6. package/dist/brushes/index.js +236 -2021
  7. package/dist/brushes/patch.d.cts +23 -0
  8. package/dist/brushes/patch.d.ts +23 -0
  9. package/dist/brushes/ui.d.cts +105 -0
  10. package/dist/brushes/ui.d.ts +105 -0
  11. package/dist/canvas/index.cjs +7 -7
  12. package/dist/canvas/index.js +1 -1
  13. package/dist/{chunk-QKXO6JPP.cjs → chunk-2OQGPEHH.cjs} +14 -14
  14. package/dist/chunk-34KLWUH4.cjs +2284 -0
  15. package/dist/{chunk-Z3BRH4JK.cjs → chunk-557BDWKO.cjs} +6 -6
  16. package/dist/{chunk-ZBCT5MEA.cjs → chunk-CBVNCWJM.cjs} +7 -7
  17. package/dist/{chunk-226QDRO3.js → chunk-DHQPRKXF.js} +1 -1
  18. package/dist/{chunk-ABL7IWFZ.js → chunk-GBEF2D4P.js} +1 -1
  19. package/dist/{chunk-ISIO63Q5.cjs → chunk-L2JTLW6B.cjs} +150 -25
  20. package/dist/{chunk-JA57JIT5.js → chunk-MV7CYFMJ.js} +133 -8
  21. package/dist/{chunk-5E2Q7ZHI.js → chunk-MWUZCEFT.js} +1 -1
  22. package/dist/chunk-QPHNVZHO.js +2284 -0
  23. package/dist/effects/conformance.d.cts +1 -0
  24. package/dist/effects/conformance.d.ts +1 -0
  25. package/dist/effects/fake.d.cts +7 -1
  26. package/dist/effects/fake.d.ts +7 -1
  27. package/dist/effects/helpers.d.cts +36 -4
  28. package/dist/effects/helpers.d.ts +36 -4
  29. package/dist/effects/index.cjs +331 -102
  30. package/dist/effects/index.js +238 -9
  31. package/dist/effects/types.d.cts +84 -5
  32. package/dist/effects/types.d.ts +84 -5
  33. package/dist/image-editor/index.cjs +15 -15
  34. package/dist/image-editor/index.js +1 -1
  35. package/dist/paint-editor/brush-controls.d.cts +57 -0
  36. package/dist/paint-editor/brush-controls.d.ts +57 -0
  37. package/dist/paint-editor/brush-library-tools.d.cts +15 -0
  38. package/dist/paint-editor/brush-library-tools.d.ts +15 -0
  39. package/dist/paint-editor/brush-library.d.cts +29 -0
  40. package/dist/paint-editor/brush-library.d.ts +29 -0
  41. package/dist/paint-editor/controller.d.cts +76 -17
  42. package/dist/paint-editor/controller.d.ts +76 -17
  43. package/dist/paint-editor/index.cjs +543 -858
  44. package/dist/paint-editor/index.d.cts +1 -0
  45. package/dist/paint-editor/index.d.ts +1 -0
  46. package/dist/paint-editor/index.js +329 -644
  47. package/dist/paint-editor/serialize.d.cts +7 -4
  48. package/dist/paint-editor/serialize.d.ts +7 -4
  49. package/dist/paint-editor/sticker-tools.d.cts +1 -1
  50. package/dist/paint-editor/sticker-tools.d.ts +1 -1
  51. package/dist/paint-editor/strokes.d.cts +10 -1
  52. package/dist/paint-editor/strokes.d.ts +10 -1
  53. package/dist/paint-editor/tools.d.cts +1 -1
  54. package/dist/paint-editor/tools.d.ts +1 -1
  55. package/dist/paint-editor/ui.d.cts +3 -51
  56. package/dist/paint-editor/ui.d.ts +3 -51
  57. package/dist/paint-editor/wet-tools.d.cts +1 -1
  58. package/dist/paint-editor/wet-tools.d.ts +1 -1
  59. package/dist/vector/index.cjs +6 -6
  60. package/dist/vector/index.js +1 -1
  61. package/dist/video-editor/index.cjs +344 -344
  62. package/dist/video-editor/index.js +4 -4
  63. package/package.json +1 -1
  64. package/skills/pixerate-brushes/SKILL.md +5 -3
  65. package/skills/pixerate-paint-editor/SKILL.md +26 -24
  66. package/skills/pixerate-paint-editor/references/brush-facets.md +30 -0
  67. package/skills/pixerate-paint-editor/references/gradient-paint.md +1 -1
  68. package/skills/pixerate-paint-editor/references/light-paint.md +2 -2
  69. package/skills/pixerate-paint-editor/references/oils.md +1 -1
  70. package/skills/pixerate-paint-editor/references/particle-brushes.md +8 -5
  71. package/skills/pixerate-paint-oil-impasto/SKILL.md +1 -1
  72. package/skills/pixerate-stickers/SKILL.md +1 -1
  73. package/skills/pixerate-video-editor/SKILL.md +1 -1
@@ -6,7 +6,25 @@
6
6
  var _chunkSABJMH6Mcjs = require('../chunk-SABJMH6M.cjs');
7
7
 
8
8
 
9
- var _chunkZBCT5MEAcjs = require('../chunk-ZBCT5MEA.cjs');
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+ var _chunk34KLWUH4cjs = require('../chunk-34KLWUH4.cjs');
25
+
26
+
27
+ var _chunkCBVNCWJMcjs = require('../chunk-CBVNCWJM.cjs');
10
28
 
11
29
 
12
30
 
@@ -139,7 +157,7 @@ var _chunkPY4GWSE2cjs = require('../chunk-PY4GWSE2.cjs');
139
157
 
140
158
 
141
159
 
142
- var _chunkISIO63Q5cjs = require('../chunk-ISIO63Q5.cjs');
160
+ var _chunkL2JTLW6Bcjs = require('../chunk-L2JTLW6B.cjs');
143
161
  require('../chunk-WOFXZ3XU.cjs');
144
162
 
145
163
 
@@ -194,7 +212,6 @@ var _chunkPXDIAYB6cjs = require('../chunk-PXDIAYB6.cjs');
194
212
 
195
213
 
196
214
 
197
-
198
215
 
199
216
 
200
217
  var _chunkFQPUF2W2cjs = require('../chunk-FQPUF2W2.cjs');
@@ -3326,6 +3343,19 @@ function readLoad(raw) {
3326
3343
  if (!reservoir && !pickup) return null;
3327
3344
  return { reservoir, amount: reservoir && finite2(r.amount) ? Math.min(1, Math.max(0, r.amount)) : 0, pickup };
3328
3345
  }
3346
+ function readStrokeBrush(raw) {
3347
+ if (raw && typeof raw === "object" && "kind" in raw && !("engine" in raw)) {
3348
+ try {
3349
+ return _chunk34KLWUH4cjs.resolveBrush.call(void 0, _chunk34KLWUH4cjs.normalizeBrushSpec.call(void 0, raw));
3350
+ } catch (e4) {
3351
+ }
3352
+ }
3353
+ return _chunkHS6QDWDFcjs.normalizePaintBrush.call(void 0, _nullishCoalesce(raw, () => ( {})));
3354
+ }
3355
+ function strokeToJSON(stroke) {
3356
+ const { brush, ...rest } = stroke;
3357
+ return { ...JSON.parse(JSON.stringify(rest)), brush: _chunk34KLWUH4cjs.migrateBrushV1.call(void 0, brush) };
3358
+ }
3329
3359
  function normalizeBrushStroke(raw) {
3330
3360
  if (!raw || typeof raw !== "object") return null;
3331
3361
  const r = raw;
@@ -3335,7 +3365,7 @@ function normalizeBrushStroke(raw) {
3335
3365
  const out = {
3336
3366
  id: r.id,
3337
3367
  layerId: r.layerId,
3338
- brush: _chunkHS6QDWDFcjs.normalizePaintBrush.call(void 0, _nullishCoalesce(r.brush, () => ( {}))),
3368
+ brush: readStrokeBrush(r.brush),
3339
3369
  color: typeof r.color === "string" && /^#[0-9a-f]{6}$/i.test(r.color) ? r.color.toLowerCase() : "#000000",
3340
3370
  points,
3341
3371
  seed: finite2(r.seed) ? r.seed | 0 : 0
@@ -3349,7 +3379,7 @@ function normalizeBrushStroke(raw) {
3349
3379
  for (const raw2 of r.stencils) {
3350
3380
  try {
3351
3381
  st.push(normalizeStencil(raw2, typeof _optionalChain([raw2, 'optionalAccess', _107 => _107.id]) === "string" ? raw2.id : "stencil"));
3352
- } catch (e4) {
3382
+ } catch (e5) {
3353
3383
  }
3354
3384
  }
3355
3385
  if (st.length) out.stencils = st;
@@ -3515,7 +3545,7 @@ function downsampleRgba(data, width, height, tw, th) {
3515
3545
 
3516
3546
  // src/paint-editor/serialize.ts
3517
3547
  var PAINT_FORMAT = "pixerate-paint";
3518
- var PAINT_SCHEMA_VERSION = 1;
3548
+ var PAINT_SCHEMA_VERSION = 2;
3519
3549
  var KNOWN = /* @__PURE__ */ new Set(["format", "version", "width", "height", "dpi", "paper", "layers", "assets", "activeLayerId", "strokes", "guides", "swatches", "mixingPad", "wet", "wetEvents", "paintEvents", "origin"]);
3520
3550
  function documentExtensions(raw) {
3521
3551
  const out = {};
@@ -3533,7 +3563,7 @@ function header(state, options) {
3533
3563
  paper: { ...state.paper, dry: { ...state.paper.dry }, wet: { ...state.paper.wet } },
3534
3564
  activeLayerId: state.activeLayerId
3535
3565
  };
3536
- if (options.strokes !== false && state.strokes.length) out.strokes = JSON.parse(JSON.stringify(state.strokes));
3566
+ if (options.strokes !== false && state.strokes.length) out.strokes = state.strokes.map(strokeToJSON);
3537
3567
  if (options.guides !== void 0) out.guides = JSON.parse(JSON.stringify(options.guides));
3538
3568
  if (options.swatches !== void 0) out.swatches = JSON.parse(JSON.stringify(options.swatches));
3539
3569
  if (options.mixingPad !== void 0) out.mixingPad = JSON.parse(JSON.stringify(options.mixingPad));
@@ -4921,10 +4951,10 @@ var MixingPad = (_class16 = class {constructor() { _class16.prototype.__init106.
4921
4951
  * mixed colour's scattering is re-estimated from its luminance, so repeated small mixes favour
4922
4952
  * the lighter paint (see GOTCHAS).
4923
4953
  */
4924
- mix(paints, options = {}) {
4925
- if (!paints.length || paints.length > 8) throw new Error(`Give 1 to 8 paints to mix; got ${paints.length}.`);
4926
- const total = paints.reduce((n, p) => n + p.parts, 0);
4927
- paints.forEach((p, i) => {
4954
+ mix(paints2, options = {}) {
4955
+ if (!paints2.length || paints2.length > 8) throw new Error(`Give 1 to 8 paints to mix; got ${paints2.length}.`);
4956
+ const total = paints2.reduce((n, p) => n + p.parts, 0);
4957
+ paints2.forEach((p, i) => {
4928
4958
  if (!(Number.isFinite(p.parts) && p.parts >= 0)) throw new Error(`paints[${i}].parts is ${p.parts}; use a number \u2265 0.`);
4929
4959
  });
4930
4960
  if (!(total > 0)) throw new Error("Every paint has 0 parts; give at least one paint parts above 0.");
@@ -4939,7 +4969,7 @@ var MixingPad = (_class16 = class {constructor() { _class16.prototype.__init106.
4939
4969
  }
4940
4970
  const bounds = { x: Math.floor(cx - R), y: Math.floor(cy - R), width: Math.ceil(2 * R), height: Math.ceil(2 * R) };
4941
4971
  if (options.clear !== false) this.surface = _chunk474IQG74cjs.writeRegion.call(void 0, this.surface, bounds, new Uint8ClampedArray(bounds.width * bounds.height * 4));
4942
- const used = paints.filter((p) => p.parts > 0);
4972
+ const used = paints2.filter((p) => p.parts > 0);
4943
4973
  const area = Math.PI * (0.7 * R) ** 2;
4944
4974
  used.forEach((p, i) => {
4945
4975
  const r = Math.sqrt(area * (p.parts / total) / Math.PI);
@@ -4962,8 +4992,8 @@ var MixingPad = (_class16 = class {constructor() { _class16.prototype.__init106.
4962
4992
  this.run(knife, stir, "#000000");
4963
4993
  }
4964
4994
  const mixed = _chunk2VX55NFMcjs.mixPigments.call(void 0,
4965
- paints.map((p) => hexToRgb8(p.color).map((v) => v / 255)),
4966
- paints.map((p) => p.parts)
4995
+ paints2.map((p) => hexToRgb8(p.color).map((v) => v / 255)),
4996
+ paints2.map((p) => p.parts)
4967
4997
  );
4968
4998
  const core = _chunkHS6QDWDFcjs.normalizePaintBrush.call(void 0, { tip: { ...PAD_BLOB.tip, size: R * 1.1, hardness: 0.55 } }, PAD_BLOB);
4969
4999
  const hex = "#" + mixed.map((v) => Math.round(v * 255).toString(16).padStart(2, "0")).join("");
@@ -5001,6 +5031,79 @@ var MixingPad = (_class16 = class {constructor() { _class16.prototype.__init106.
5001
5031
  }
5002
5032
  }, _class16);
5003
5033
 
5034
+ // src/paint-editor/brush-library.ts
5035
+ var copyJSON = (v) => JSON.parse(JSON.stringify(v));
5036
+ var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
5037
+ function libraryBrush(spec, builtin, resolved) {
5038
+ const brush = resolved ? _chunkHS6QDWDFcjs.normalizePaintBrush.call(void 0, resolved, resolved) : _chunk34KLWUH4cjs.resolveBrush.call(void 0, spec);
5039
+ if (builtin) brush.builtin = true;
5040
+ else delete brush.builtin;
5041
+ return { spec, brush, builtin };
5042
+ }
5043
+ var builtins = null;
5044
+ function builtinLibraryBrushes() {
5045
+ return builtins ??= _chunk34KLWUH4cjs.BRUSH_PRESETS.map((spec) => {
5046
+ const resolved = _chunkHS6QDWDFcjs.BUILTIN_BRUSHES.find((b) => b.id === spec.id);
5047
+ return libraryBrush(spec, true, resolved);
5048
+ });
5049
+ }
5050
+ function seededStorage(brushes) {
5051
+ if (!brushes.length) return void 0;
5052
+ let stored = JSON.stringify({ format: "pixerate-brushes", version: 1, brushes: brushes.map(_chunkHS6QDWDFcjs.brushToJSON) });
5053
+ return {
5054
+ get: async () => stored,
5055
+ set: async (_key, value) => {
5056
+ stored = value;
5057
+ }
5058
+ };
5059
+ }
5060
+ var paints = (b) => {
5061
+ const { category: _c, builtin: _b, ...rest } = b;
5062
+ return JSON.stringify(rest);
5063
+ };
5064
+ function brushSpecOf(next, from) {
5065
+ const plain = _chunk34KLWUH4cjs.migrateBrushV1.call(void 0, next);
5066
+ const out = copyJSON(plain);
5067
+ if (from.description) out.description = from.description;
5068
+ if (_optionalChain([from, 'access', _209 => _209.tags, 'optionalAccess', _210 => _210.length])) out.tags = [...from.tags];
5069
+ if (out.kind === "mark" && from.kind === "mark") {
5070
+ if (from.medium) out.medium = from.medium;
5071
+ if (from.variety) out.variety = from.variety;
5072
+ }
5073
+ const colour = { ..._nullishCoalesce(from.colour, () => ( {})) };
5074
+ if (_optionalChain([plain, 'access', _211 => _211.colour, 'optionalAccess', _212 => _212.default]) !== void 0) colour.default = plain.colour.default;
5075
+ else if (isObject(colour.default) && colour.default.type === "gradient") delete colour.default;
5076
+ if (Object.keys(colour).length) out.colour = copyJSON(colour);
5077
+ else delete out.colour;
5078
+ if ((_nullishCoalesce(_optionalChain([out, 'access', _213 => _213.light, 'optionalAccess', _214 => _214.amount]), () => ( 0))) > 0 && (_optionalChain([from, 'access', _215 => _215.light, 'optionalAccess', _216 => _216.spill]) || _optionalChain([from, 'access', _217 => _217.light, 'optionalAccess', _218 => _218.glow]) !== void 0)) {
5079
+ out.light = { ...out.light, ...from.light.spill ? { spill: { ...from.light.spill } } : {}, ...from.light.glow !== void 0 ? { glow: from.light.glow } : {} };
5080
+ }
5081
+ if (_optionalChain([from, 'access', _219 => _219.motion, 'optionalAccess', _220 => _220.live]) !== void 0 || _optionalChain([from, 'access', _221 => _221.motion, 'optionalAccess', _222 => _222.fps]) !== void 0) {
5082
+ out.motion = { ..._nullishCoalesce(out.motion, () => ( {})), ...from.motion.live !== void 0 ? { live: from.motion.live } : {}, ...from.motion.fps !== void 0 ? { fps: from.motion.fps } : {} };
5083
+ }
5084
+ try {
5085
+ const hinted = _chunk34KLWUH4cjs.normalizeBrushSpec.call(void 0, out, []);
5086
+ if (paints(_chunk34KLWUH4cjs.resolveBrush.call(void 0, hinted)) === paints(_chunk34KLWUH4cjs.resolveBrush.call(void 0, plain))) return hinted;
5087
+ } catch (e6) {
5088
+ }
5089
+ return plain;
5090
+ }
5091
+ function engineChanges(base, next) {
5092
+ const diff = (a, b) => {
5093
+ if (isObject(a) && isObject(b)) {
5094
+ const out = {};
5095
+ for (const k of Object.keys(b)) {
5096
+ const d = diff(a[k], b[k]);
5097
+ if (d !== void 0) out[k] = d;
5098
+ }
5099
+ return Object.keys(out).length ? out : void 0;
5100
+ }
5101
+ return JSON.stringify(a) === JSON.stringify(b) ? void 0 : copyJSON(b);
5102
+ };
5103
+ const { id: _i, builtin: _b, ...rest } = _nullishCoalesce(diff(base, next), () => ( {}));
5104
+ return rest;
5105
+ }
5106
+
5004
5107
  // src/paint-editor/live-strokes.ts
5005
5108
  var LIVE_STROKE_ENGINES = ["dab", "particle", "bristle", "mixer"];
5006
5109
  function liveStrokeRefusal(brush) {
@@ -5098,8 +5201,8 @@ var BacklightCache = (_class17 = class {constructor() { _class17.prototype.__ini
5098
5201
  refs.length = 0;
5099
5202
  for (const l of layers) {
5100
5203
  tilesUnder(l.surface, rect, l.offset, refs);
5101
- tilesUnder(_optionalChain([l, 'access', _209 => _209.thick, 'optionalAccess', _210 => _210.height]), rect, l.offset, refs);
5102
- tilesUnder(_optionalChain([l, 'access', _211 => _211.thick, 'optionalAccess', _212 => _212.material]), rect, l.offset, refs);
5204
+ tilesUnder(_optionalChain([l, 'access', _223 => _223.thick, 'optionalAccess', _224 => _224.height]), rect, l.offset, refs);
5205
+ tilesUnder(_optionalChain([l, 'access', _225 => _225.thick, 'optionalAccess', _226 => _226.material]), rect, l.offset, refs);
5103
5206
  }
5104
5207
  const k = _chunk474IQG74cjs.tileKey.call(void 0, tx, ty);
5105
5208
  let r = this.tiles.get(k);
@@ -5193,8 +5296,8 @@ function computeTile(paper, grain, amount, rect, layers) {
5193
5296
  const lr = { x: rect.x - l.offset.x, y: rect.y - l.offset.y, width: rect.width, height: rect.height };
5194
5297
  if (!l.surface.tiles.size) continue;
5195
5298
  const px = _chunk474IQG74cjs.readRegion.call(void 0, l.surface, lr);
5196
- const h = _optionalChain([l, 'access', _213 => _213.thick, 'optionalAccess', _214 => _214.height, 'access', _215 => _215.tiles, 'access', _216 => _216.size]) ? _chunk474IQG74cjs.readRegion.call(void 0, l.thick.height, lr) : null;
5197
- const m = h && _optionalChain([l, 'access', _217 => _217.thick, 'optionalAccess', _218 => _218.material, 'access', _219 => _219.tiles, 'access', _220 => _220.size]) ? _chunk474IQG74cjs.readRegion.call(void 0, l.thick.material, lr) : null;
5299
+ const h = _optionalChain([l, 'access', _227 => _227.thick, 'optionalAccess', _228 => _228.height, 'access', _229 => _229.tiles, 'access', _230 => _230.size]) ? _chunk474IQG74cjs.readRegion.call(void 0, l.thick.height, lr) : null;
5300
+ const m = h && _optionalChain([l, 'access', _231 => _231.thick, 'optionalAccess', _232 => _232.material, 'access', _233 => _233.tiles, 'access', _234 => _234.size]) ? _chunk474IQG74cjs.readRegion.call(void 0, l.thick.material, lr) : null;
5198
5301
  const op = l.opacity;
5199
5302
  for (let i = 0; i < n; i++) {
5200
5303
  const a8 = px[i * 4 + 3];
@@ -5269,7 +5372,7 @@ async function replayPainting(source, target, options = {}) {
5269
5372
  const maxStrokes = _nullishCoalesce(options.strokes, () => ( source.strokes.length));
5270
5373
  const chunk = Math.max(1, _nullishCoalesce(options.wetChunk, () => ( 0))) || Infinity;
5271
5374
  let strokes = 0;
5272
- await target.prepareEffectPaints(source.strokes.slice(0, maxStrokes).flatMap((st) => _optionalChain([st, 'access', _221 => _221.paint, 'optionalAccess', _222 => _222.type]) === "effect" ? [st.paint] : []));
5375
+ await target.prepareEffectPaints(source.strokes.slice(0, maxStrokes).flatMap((st) => _optionalChain([st, 'access', _235 => _235.paint, 'optionalAccess', _236 => _236.type]) === "effect" ? [st.paint] : []));
5273
5376
  const advanceTo = async (clock) => {
5274
5377
  const now = target.getState().wet.clock;
5275
5378
  let left = clock - now;
@@ -5277,7 +5380,7 @@ async function replayPainting(source, target, options = {}) {
5277
5380
  const n = Math.min(left, chunk);
5278
5381
  await target.advanceWet({ steps: n });
5279
5382
  left -= n;
5280
- if (Number.isFinite(chunk)) await _optionalChain([options, 'access', _223 => _223.onWetSteps, 'optionalCall', _224 => _224(target.getState().wet.clock)]);
5383
+ if (Number.isFinite(chunk)) await _optionalChain([options, 'access', _237 => _237.onWetSteps, 'optionalCall', _238 => _238(target.getState().wet.clock)]);
5281
5384
  }
5282
5385
  };
5283
5386
  const sr = (r) => ({ x: r.x * s, y: r.y * s, width: r.width * s, height: r.height * s });
@@ -5290,14 +5393,14 @@ async function replayPainting(source, target, options = {}) {
5290
5393
  else if (e.kind === "clear") target.clearLayer(e.layerId);
5291
5394
  else if (e.kind === "live-strokes") {
5292
5395
  const d = e.data;
5293
- if (_optionalChain([d, 'optionalAccess', _225 => _225.rasterized])) target.replaceLiveStrokes(e.layerId, null);
5396
+ if (_optionalChain([d, 'optionalAccess', _239 => _239.rasterized])) target.replaceLiveStrokes(e.layerId, null);
5294
5397
  else {
5295
- const list = (_nullishCoalesce(_optionalChain([d, 'optionalAccess', _226 => _226.strokes]), () => ( []))).map((st2) => s === 1 ? st2 : { ...varyStroke(st2, scaleM, { scale: s }), ...st2.stencils ? { stencils: st2.stencils.map((x) => scaleStencil(x, s)) } : {} });
5296
- await target.prepareEffectPaints(list.flatMap((st2) => _optionalChain([st2, 'access', _227 => _227.paint, 'optionalAccess', _228 => _228.type]) === "effect" ? [st2.paint] : []));
5398
+ const list = (_nullishCoalesce(_optionalChain([d, 'optionalAccess', _240 => _240.strokes]), () => ( []))).map((st2) => s === 1 ? st2 : { ...varyStroke(st2, scaleM, { scale: s }), ...st2.stencils ? { stencils: st2.stencils.map((x) => scaleStencil(x, s)) } : {} });
5399
+ await target.prepareEffectPaints(list.flatMap((st2) => _optionalChain([st2, 'access', _241 => _241.paint, 'optionalAccess', _242 => _242.type]) === "effect" ? [st2.paint] : []));
5297
5400
  target.replaceLiveStrokes(e.layerId, list);
5298
5401
  }
5299
5402
  } else if (e.kind === "stickers") {
5300
- const list = (_nullishCoalesce(_optionalChain([e, 'access', _229 => _229.data, 'optionalAccess', _230 => _230.stickers]), () => ( []))).map((x) => s === 1 ? x : { ...x, x: x.x * s, y: x.y * s, size: x.size * s });
5403
+ const list = (_nullishCoalesce(_optionalChain([e, 'access', _243 => _243.data, 'optionalAccess', _244 => _244.stickers]), () => ( []))).map((x) => s === 1 ? x : { ...x, x: x.x * s, y: x.y * s, size: x.size * s });
5301
5404
  target.replaceStickers(e.layerId, list);
5302
5405
  } else target.flattenRelief(e.layerId);
5303
5406
  continue;
@@ -5310,8 +5413,8 @@ async function replayPainting(source, target, options = {}) {
5310
5413
  switch (e.kind) {
5311
5414
  case "dry": {
5312
5415
  const rect = e.data;
5313
- const ids = _optionalChain([e, 'access', _231 => _231.layerId, 'optionalAccess', _232 => _232.split, 'call', _233 => _233(","), 'access', _234 => _234.filter, 'call', _235 => _235(Boolean)]);
5314
- if (_optionalChain([ids, 'optionalAccess', _236 => _236.length])) for (const id of ids) target.dryPaint({ layerId: id, rect: rect ? sr(rect) : void 0 });
5416
+ const ids = _optionalChain([e, 'access', _245 => _245.layerId, 'optionalAccess', _246 => _246.split, 'call', _247 => _247(","), 'access', _248 => _248.filter, 'call', _249 => _249(Boolean)]);
5417
+ if (_optionalChain([ids, 'optionalAccess', _250 => _250.length])) for (const id of ids) target.dryPaint({ layerId: id, rect: rect ? sr(rect) : void 0 });
5315
5418
  else target.dryPaint({ rect: rect ? sr(rect) : void 0 });
5316
5419
  break;
5317
5420
  }
@@ -5334,7 +5437,7 @@ async function replayPainting(source, target, options = {}) {
5334
5437
  break;
5335
5438
  }
5336
5439
  }
5337
- } catch (e5) {
5440
+ } catch (e7) {
5338
5441
  }
5339
5442
  continue;
5340
5443
  }
@@ -5342,7 +5445,7 @@ async function replayPainting(source, target, options = {}) {
5342
5445
  strokes++;
5343
5446
  if (!target.getLayer(st.layerId)) continue;
5344
5447
  const init = { layerId: st.layerId, color: st.color, brush: st.brush, seed: st.seed, copies: _nullishCoalesce(st.copies, () => ( [])), ...st.load ? { load: st.load } : {}, ...st.paint ? { paint: st.paint } : {}, snapToPerspective: false, stencils: false, maskStencils: (_nullishCoalesce(st.stencils, () => ( []))).map((x) => s === 1 ? x : scaleStencil(x, s)) };
5345
- if (st.brush.engine === "wet" && _optionalChain([st, 'access', _237 => _237.steps, 'optionalAccess', _238 => _238.length]) === st.points.length) {
5448
+ if (st.brush.engine === "wet" && _optionalChain([st, 'access', _251 => _251.steps, 'optionalAccess', _252 => _252.length]) === st.points.length) {
5346
5449
  await target.wetIdle();
5347
5450
  await advanceTo(st.steps[0]);
5348
5451
  const session = target.beginStroke({ ...init, start: st.points[0] });
@@ -5362,7 +5465,7 @@ async function replayPainting(source, target, options = {}) {
5362
5465
  await target.wetIdle();
5363
5466
  target.paintStroke({ ...init, points: st.points });
5364
5467
  }
5365
- await _optionalChain([options, 'access', _239 => _239.onStroke, 'optionalCall', _240 => _240(strokes)]);
5468
+ await _optionalChain([options, 'access', _253 => _253.onStroke, 'optionalCall', _254 => _254(strokes)]);
5366
5469
  }
5367
5470
  void IDENTITY_AFFINE;
5368
5471
  }
@@ -5385,7 +5488,7 @@ function timeLapseVideo(frameCount, width, height, fps, holdMs, name = "Time-lap
5385
5488
  }
5386
5489
  const video = { version: 1, name, width: w, height: h, fps, background: "#000000", assets, tracks: [{ id: "v1", kind: "video", clips }] };
5387
5490
  const durationMs = frameCount ? clips[clips.length - 1].start + clips[clips.length - 1].duration : 0;
5388
- return { video, ffmpeg: _chunkZBCT5MEAcjs.toVideoFfmpeg.call(void 0, video, { output: "timelapse.mp4" }), durationMs };
5491
+ return { video, ffmpeg: _chunkCBVNCWJMcjs.toVideoFfmpeg.call(void 0, video, { output: "timelapse.mp4" }), durationMs };
5389
5492
  }
5390
5493
  async function buildTimeLapse(source, target, options = {}) {
5391
5494
  const maxSide = Math.max(32, Math.min(4096, Math.round(_nullishCoalesce(options.maxSide, () => ( 720)))));
@@ -5407,7 +5510,7 @@ async function buildTimeLapse(source, target, options = {}) {
5407
5510
  wetChunk: wetEvery > 0 ? wetEvery : 0,
5408
5511
  onStroke: (i) => {
5409
5512
  if (i % perFrame === 0 || i === total) shoot(i);
5410
- _optionalChain([options, 'access', _241 => _241.onProgress, 'optionalCall', _242 => _242(total ? i / total : 1)]);
5513
+ _optionalChain([options, 'access', _255 => _255.onProgress, 'optionalCall', _256 => _256(total ? i / total : 1)]);
5411
5514
  },
5412
5515
  onWetSteps: wetEvery > 0 ? () => shoot(-1) : void 0
5413
5516
  });
@@ -5468,7 +5571,7 @@ function checkPaintEffectPlace(d, place) {
5468
5571
  else if (d.uses.includes("filter") && place !== "light") instead = "; run it on a layer's dried paint with apply_effect instead";
5469
5572
  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";
5470
5573
  else if (place === "paper" && d.uses.some((u) => u === "overlay" || u === "title")) instead = "; add it as an effect layer with add_effect_layer instead";
5471
- throw new (0, _chunkISIO63Q5cjs.EffectUnsupportedError)(`"${d.id}" (${d.name}) is a ${d.uses.join(" / ") || d.kind} effect, and ${PLACE_WORDS[place]}${instead}.`, d.id);
5574
+ throw new (0, _chunkL2JTLW6Bcjs.EffectUnsupportedError)(`"${d.id}" (${d.name}) is a ${d.uses.join(" / ") || d.kind} effect, and ${PLACE_WORDS[place]}${instead}.`, d.id);
5472
5575
  }
5473
5576
  var PAPER_EFFECT_BLENDS = ["multiply", "normal", "overlay", "soft-light", "screen", "color"];
5474
5577
  var paperVersion = 1;
@@ -5583,6 +5686,13 @@ var PaintEditorError = class extends Error {
5583
5686
  this.name = "PaintEditorError";
5584
5687
  }
5585
5688
  };
5689
+ async function libraryCall(call) {
5690
+ try {
5691
+ return await call();
5692
+ } catch (e) {
5693
+ throw e instanceof _chunk34KLWUH4cjs.BrushLibraryError ? new PaintEditorError(e.message) : e;
5694
+ }
5695
+ }
5586
5696
  var HEX3 = /^#[0-9a-f]{6}$/i;
5587
5697
  var MAX_ADD_STICKERS = 500;
5588
5698
  function parseColor(value, what = "color") {
@@ -5603,99 +5713,116 @@ function unionRect(a, b) {
5603
5713
  const y = Math.min(a.y, b.y);
5604
5714
  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 };
5605
5715
  }
5606
- var isPixelLayer = (l) => _optionalChain([l, 'optionalAccess', _243 => _243.type]) === "pixel";
5716
+ var isPixelLayer = (l) => _optionalChain([l, 'optionalAccess', _257 => _257.type]) === "pixel";
5607
5717
  var PaintEditorController = (_class19 = class _PaintEditorController {
5608
5718
 
5609
5719
  __init117() {this.extensions = {}}
5610
5720
  __init118() {this.undoStack = []}
5611
5721
  __init119() {this.redoStack = []}
5612
5722
 
5723
+ /** The brush library this editor lists, saves into and paints from (shared with other editors when the host passes one). */
5724
+
5613
5725
 
5726
+ /** The active brush as facets (what `getBrushSpec` and saving use). */
5727
+
5728
+ /** The library's brushes as last read, each as stored (facets) and as the engine paints it. */
5729
+
5730
+ /** The brush id asked for at construction, while the library had not listed it yet. */
5731
+ __init120() {this.pendingBrushId = null}
5732
+ __init121() {this.brushesLoaded = Promise.resolve()}
5614
5733
 
5615
5734
  /** The library list in the state (the same array until the user brushes change, so thumbnails are not redrawn). */
5616
- __init120() {this.library = null}
5735
+ __init122() {this.library = null}
5617
5736
 
5618
- __init121() {this.secondaryColor = "#ffffff"}
5737
+ __init123() {this.secondaryColor = "#ffffff"}
5619
5738
  /** Gradient paint chosen with `setPaint` (`null`: the paint colour). */
5620
- __init122() {this.gradient = null}
5739
+ __init124() {this.gradient = null}
5621
5740
  /** Effect paint chosen with `setEffectPaint` (rendered), and one still rendering. */
5622
- __init123() {this.effectPaint = null}
5623
- __init124() {this.effectPaintPending = null}
5741
+ __init125() {this.effectPaint = null}
5742
+ __init126() {this.effectPaintPending = null}
5624
5743
  /** Changes whenever the paint is chosen, so an effect paint that finishes rendering late does not take over. */
5625
- __init125() {this.paintEpoch = 0}
5744
+ __init127() {this.paintEpoch = 0}
5626
5745
  /** Rendered effect paints by `effectPaintKey` (most recently used last). */
5627
- __init126() {this.effectPaintPixels = /* @__PURE__ */ new Map()}
5628
- __init127() {this.mixerLoad = _chunkFQPUF2W2cjs.EMPTY_MIXER_LOAD}
5629
- __init128() {this.view = { ...DEFAULT_VIEW, pan: { ...DEFAULT_VIEW.pan } }}
5746
+ __init128() {this.effectPaintPixels = /* @__PURE__ */ new Map()}
5747
+ __init129() {this.mixerLoad = _chunkFQPUF2W2cjs.EMPTY_MIXER_LOAD}
5748
+ __init130() {this.view = { ...DEFAULT_VIEW, pan: { ...DEFAULT_VIEW.pan } }}
5630
5749
 
5631
- __init129() {this.selectedStroke = null}
5632
- __init130() {this.selectedSticker = null}
5750
+ __init131() {this.selectedStroke = null}
5751
+ __init132() {this.selectedSticker = null}
5633
5752
  /** A sticker drag in progress (`previewSticker`): the document before it, so the drop undoes in one step, and the one it showed last. */
5634
- __init131() {this.stickerPreview = null}
5753
+ __init133() {this.stickerPreview = null}
5635
5754
 
5636
- __init132() {this.listeners = /* @__PURE__ */ new Set()}
5637
- __init133() {this.version = 0}
5638
- __init134() {this.cached = null}
5639
- __init135() {this.session = null}
5640
- __init136() {this.live = null}
5641
- __init137() {this.liveLayers = null}
5642
- __init138() {this.dirty = "all"}
5643
- __init139() {this.seedCounter = 1}
5644
- __init140() {this.strokeCounter = 1}
5755
+ __init134() {this.listeners = /* @__PURE__ */ new Set()}
5756
+ __init135() {this.version = 0}
5757
+ __init136() {this.cached = null}
5758
+ __init137() {this.session = null}
5759
+ __init138() {this.live = null}
5760
+ __init139() {this.liveLayers = null}
5761
+ __init140() {this.dirty = "all"}
5762
+ __init141() {this.seedCounter = 1}
5763
+ __init142() {this.strokeCounter = 1}
5645
5764
  /** Light paint: each layer's spill settings (saved with the document, not undo steps; missing = the defaults). */
5646
- __init141() {this.lightSpills = {}}
5647
- __init142() {this.lightCaches = /* @__PURE__ */ new Map()}
5765
+ __init143() {this.lightSpills = {}}
5766
+ __init144() {this.lightCaches = /* @__PURE__ */ new Map()}
5648
5767
  /** Backlit paper: the light through the paint as drawn (live strokes too), and as committed (its spill). */
5649
- __init143() {this.backlightView = new BacklightCache()}
5650
- __init144() {this.backlightCommitted = new BacklightCache()}
5768
+ __init145() {this.backlightView = new BacklightCache()}
5769
+ __init146() {this.backlightCommitted = new BacklightCache()}
5651
5770
  /** Live effect paint: playing and the frame rate cap (editor state), and the time the view shows. */
5652
- __init145() {this.effectPlaybackState = { playing: true, fps: 30 }}
5653
- __init146() {this.effectTime = 0}
5771
+ __init147() {this.effectPlaybackState = { playing: true, fps: 30 }}
5772
+ __init148() {this.effectTime = 0}
5654
5773
  /** While a frame is drawn: the time live effect strokes are drawn at (else their own time). */
5655
- __init147() {this.liveEffectAt = null}
5774
+ __init149() {this.liveEffectAt = null}
5656
5775
  /** The view's stroke layers at `effectTime`, each with the document surface it was drawn from (stale once that changes). */
5657
- __init148() {this.animatedLayers = /* @__PURE__ */ new Map()}
5776
+ __init150() {this.animatedLayers = /* @__PURE__ */ new Map()}
5658
5777
  /** `renderAnimationFrame` / `withEffectTime`: layer surfaces at another time, for one render. */
5659
- __init149() {this.frameOverride = null}
5778
+ __init151() {this.frameOverride = null}
5660
5779
  /** The area each stroke painted (document pixels; `null`: nothing), learnt as it is painted or drawn, so a stroke layer edit redraws only where it changes (see `drawLiveStrokes`). */
5661
- __init150() {this.paintedBounds = /* @__PURE__ */ new WeakMap()}
5780
+ __init152() {this.paintedBounds = /* @__PURE__ */ new WeakMap()}
5662
5781
 
5663
- __init151() {this.swatches = DEFAULT_SWATCHES.map((s) => ({ ...s }))}
5664
- __init152() {this.pad = new MixingPad()}
5665
- __init153() {this.savedPads = []}
5666
- __init154() {this.nextPadId = 1}
5667
- __init155() {this.tracingVersion = 1}
5668
- __init156() {this.tracingCache = null}
5669
- __init157() {this.imagePixels = /* @__PURE__ */ new Map()}
5670
- __init158() {this.nextReferenceId = 1}
5671
- __init159() {this.viewCompositor = createPaintCompositor()}
5672
- __init160() {this.exportCompositor = createPaintCompositor()}
5782
+ __init153() {this.swatches = DEFAULT_SWATCHES.map((s) => ({ ...s }))}
5783
+ __init154() {this.pad = new MixingPad()}
5784
+ __init155() {this.savedPads = []}
5785
+ __init156() {this.nextPadId = 1}
5786
+ __init157() {this.tracingVersion = 1}
5787
+ __init158() {this.tracingCache = null}
5788
+ __init159() {this.imagePixels = /* @__PURE__ */ new Map()}
5789
+ __init160() {this.nextReferenceId = 1}
5790
+ __init161() {this.viewCompositor = createPaintCompositor()}
5791
+ __init162() {this.exportCompositor = createPaintCompositor()}
5673
5792
  /** Wet media: the simulation, its settings and time. */
5674
5793
 
5675
5794
 
5676
5795
  /** Where the light comes from for thick paint (saved with the document, not undo steps). */
5677
- __init161() {this.lighting = { ...DEFAULT_LIGHTING }}
5678
- __init162() {this.litCaches = /* @__PURE__ */ new Map()}
5796
+ __init163() {this.lighting = { ...DEFAULT_LIGHTING }}
5797
+ __init164() {this.litCaches = /* @__PURE__ */ new Map()}
5679
5798
  /** The live impasto stroke's channels. */
5680
- __init163() {this.liveThick = null}
5799
+ __init165() {this.liveThick = null}
5681
5800
  /** Set while an operation that changes wet paint runs: the simulation before it (for undo). */
5682
- __init164() {this.wetOp = null}
5801
+ __init166() {this.wetOp = null}
5683
5802
  /** The effects provider slot (see `setEffectsProvider`). */
5684
- __init165() {this.effects = new (0, _chunkISIO63Q5cjs.EffectsSlot)()}
5803
+ __init167() {this.effects = new (0, _chunkL2JTLW6Bcjs.EffectsSlot)()}
5685
5804
  /** The sticker library slot (see `setStickersProvider`). */
5686
- __init166() {this.stickers = new (0, _chunkJSDND7DFcjs.StickersSlot)(_chunkSABJMH6Mcjs.editorStickers.call(void 0, ))}
5687
- __init167() {this.stickerArt = new StickerArtCache()}
5805
+ __init168() {this.stickers = new (0, _chunkJSDND7DFcjs.StickersSlot)(_chunkSABJMH6Mcjs.editorStickers.call(void 0, ))}
5806
+ __init169() {this.stickerArt = new StickerArtCache()}
5688
5807
 
5689
- __init168() {this.effectsRenderer = new PaintEffectsRenderer()}
5690
- __init169() {this.paperEffectNodeCache = null}
5691
- constructor(options = {}) {;_class19.prototype.__init117.call(this);_class19.prototype.__init118.call(this);_class19.prototype.__init119.call(this);_class19.prototype.__init120.call(this);_class19.prototype.__init121.call(this);_class19.prototype.__init122.call(this);_class19.prototype.__init123.call(this);_class19.prototype.__init124.call(this);_class19.prototype.__init125.call(this);_class19.prototype.__init126.call(this);_class19.prototype.__init127.call(this);_class19.prototype.__init128.call(this);_class19.prototype.__init129.call(this);_class19.prototype.__init130.call(this);_class19.prototype.__init131.call(this);_class19.prototype.__init132.call(this);_class19.prototype.__init133.call(this);_class19.prototype.__init134.call(this);_class19.prototype.__init135.call(this);_class19.prototype.__init136.call(this);_class19.prototype.__init137.call(this);_class19.prototype.__init138.call(this);_class19.prototype.__init139.call(this);_class19.prototype.__init140.call(this);_class19.prototype.__init141.call(this);_class19.prototype.__init142.call(this);_class19.prototype.__init143.call(this);_class19.prototype.__init144.call(this);_class19.prototype.__init145.call(this);_class19.prototype.__init146.call(this);_class19.prototype.__init147.call(this);_class19.prototype.__init148.call(this);_class19.prototype.__init149.call(this);_class19.prototype.__init150.call(this);_class19.prototype.__init151.call(this);_class19.prototype.__init152.call(this);_class19.prototype.__init153.call(this);_class19.prototype.__init154.call(this);_class19.prototype.__init155.call(this);_class19.prototype.__init156.call(this);_class19.prototype.__init157.call(this);_class19.prototype.__init158.call(this);_class19.prototype.__init159.call(this);_class19.prototype.__init160.call(this);_class19.prototype.__init161.call(this);_class19.prototype.__init162.call(this);_class19.prototype.__init163.call(this);_class19.prototype.__init164.call(this);_class19.prototype.__init165.call(this);_class19.prototype.__init166.call(this);_class19.prototype.__init167.call(this);_class19.prototype.__init168.call(this);_class19.prototype.__init169.call(this);_class19.prototype.__init170.call(this);_class19.prototype.__init171.call(this);_class19.prototype.__init172.call(this);_class19.prototype.__init173.call(this);
5808
+ __init170() {this.effectsRenderer = new PaintEffectsRenderer()}
5809
+ __init171() {this.paperEffectNodeCache = null}
5810
+ constructor(options = {}) {;_class19.prototype.__init117.call(this);_class19.prototype.__init118.call(this);_class19.prototype.__init119.call(this);_class19.prototype.__init120.call(this);_class19.prototype.__init121.call(this);_class19.prototype.__init122.call(this);_class19.prototype.__init123.call(this);_class19.prototype.__init124.call(this);_class19.prototype.__init125.call(this);_class19.prototype.__init126.call(this);_class19.prototype.__init127.call(this);_class19.prototype.__init128.call(this);_class19.prototype.__init129.call(this);_class19.prototype.__init130.call(this);_class19.prototype.__init131.call(this);_class19.prototype.__init132.call(this);_class19.prototype.__init133.call(this);_class19.prototype.__init134.call(this);_class19.prototype.__init135.call(this);_class19.prototype.__init136.call(this);_class19.prototype.__init137.call(this);_class19.prototype.__init138.call(this);_class19.prototype.__init139.call(this);_class19.prototype.__init140.call(this);_class19.prototype.__init141.call(this);_class19.prototype.__init142.call(this);_class19.prototype.__init143.call(this);_class19.prototype.__init144.call(this);_class19.prototype.__init145.call(this);_class19.prototype.__init146.call(this);_class19.prototype.__init147.call(this);_class19.prototype.__init148.call(this);_class19.prototype.__init149.call(this);_class19.prototype.__init150.call(this);_class19.prototype.__init151.call(this);_class19.prototype.__init152.call(this);_class19.prototype.__init153.call(this);_class19.prototype.__init154.call(this);_class19.prototype.__init155.call(this);_class19.prototype.__init156.call(this);_class19.prototype.__init157.call(this);_class19.prototype.__init158.call(this);_class19.prototype.__init159.call(this);_class19.prototype.__init160.call(this);_class19.prototype.__init161.call(this);_class19.prototype.__init162.call(this);_class19.prototype.__init163.call(this);_class19.prototype.__init164.call(this);_class19.prototype.__init165.call(this);_class19.prototype.__init166.call(this);_class19.prototype.__init167.call(this);_class19.prototype.__init168.call(this);_class19.prototype.__init169.call(this);_class19.prototype.__init170.call(this);_class19.prototype.__init171.call(this);_class19.prototype.__init172.call(this);_class19.prototype.__init173.call(this);_class19.prototype.__init174.call(this);_class19.prototype.__init175.call(this);
5692
5811
  this.historyLimit = Math.max(1, _nullishCoalesce(options.historyLimit, () => ( 200)));
5693
5812
  this.rasterizeSticker = _nullishCoalesce(options.rasterizeSticker, () => ( defaultStickerRasterizer));
5694
5813
  if (options.stickers) this.stickers.set(options.stickers);
5695
5814
  this.doc = createPaintDocument({ width: options.width, height: options.height, dpi: options.dpi, paper: this.resolvePaper(options.paper) });
5696
- this.userBrushes = (_nullishCoalesce(options.brushes, () => ( []))).map((b) => _chunkHS6QDWDFcjs.normalizePaintBrush.call(void 0, { ...b, builtin: false }));
5697
- const start = _nullishCoalesce(this.findBrush(_nullishCoalesce(options.brushId, () => ( _chunkHS6QDWDFcjs.DEFAULT_BRUSH_ID))), () => ( this.findBrush(_chunkHS6QDWDFcjs.DEFAULT_BRUSH_ID)));
5698
- this.brush = _chunkHS6QDWDFcjs.normalizePaintBrush.call(void 0, start);
5815
+ const seed = (_nullishCoalesce(options.brushes, () => ( []))).map((b) => _chunkHS6QDWDFcjs.normalizePaintBrush.call(void 0, { ...b, builtin: false }));
5816
+ this.brushLibrary = _nullishCoalesce(options.brushLibrary, () => ( _chunk34KLWUH4cjs.createBrushLibrary.call(void 0, { storage: seededStorage(seed) })));
5817
+ this.brushEntries = [...builtinLibraryBrushes(), ...seed.map((b) => libraryBrush(_chunk34KLWUH4cjs.migrateBrushV1.call(void 0, b), false, b))];
5818
+ const wanted = _nullishCoalesce(options.brushId, () => ( _chunkHS6QDWDFcjs.DEFAULT_BRUSH_ID));
5819
+ const start = _nullishCoalesce(this.findEntry(wanted), () => ( this.findEntry(_chunkHS6QDWDFcjs.DEFAULT_BRUSH_ID)));
5820
+ this.brush = _chunkHS6QDWDFcjs.normalizePaintBrush.call(void 0, start.brush);
5821
+ this.brushSpec = copyJSON(start.spec);
5822
+ this.unsubscribeLibrary = this.brushLibrary.subscribe(() => void this.refreshBrushes().catch(() => void 0));
5823
+ if (options.brushLibrary && seed.length) void this.brushLibrary.importFile(seed.map(_chunkHS6QDWDFcjs.brushToJSON)).catch(() => void 0);
5824
+ void this.refreshBrushes().catch(() => void 0);
5825
+ this.pendingBrushId = start.brush.id === wanted ? null : wanted;
5699
5826
  this.color = options.color ? parseColor(options.color) : "#1f2937";
5700
5827
  this.hand = options.hand === "left" ? "left" : "right";
5701
5828
  this.encodeImage = options.encodeImage;
@@ -5706,7 +5833,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
5706
5833
  canvas: () => this.doc.canvas,
5707
5834
  paper: () => this.doc.paper,
5708
5835
  layerSurface: (id) => {
5709
- const l = _optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _244 => _244.layer]);
5836
+ const l = _optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _258 => _258.layer]);
5710
5837
  return isPixelLayer(l) ? l.surface : null;
5711
5838
  },
5712
5839
  updateSurfaces: (surfaces, rects) => {
@@ -5715,7 +5842,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
5715
5842
  this.doc = { ...this.doc, layers };
5716
5843
  this.emit(rects.length ? rects : "all");
5717
5844
  },
5718
- layerLight: (id) => _nullishCoalesce(_optionalChain([this, 'access', _245 => _245.doc, 'access', _246 => _246.light, 'optionalAccess', _247 => _247[id]]), () => ( null)),
5845
+ layerLight: (id) => _nullishCoalesce(_optionalChain([this, 'access', _259 => _259.doc, 'access', _260 => _260.light, 'optionalAccess', _261 => _261[id]]), () => ( null)),
5719
5846
  updateLights: (lights) => {
5720
5847
  let light = this.doc.light;
5721
5848
  for (const [id, surface] of lights) if (_chunkDPYAO5U6cjs.findLayer.call(void 0, this.doc.layers, id)) light = withLayerLight(light, id, surface);
@@ -5726,7 +5853,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
5726
5853
  },
5727
5854
  options.wet
5728
5855
  );
5729
- this.wet.onDriverDone = () => _optionalChain([this, 'access', _248 => _248.session, 'optionalAccess', _249 => _249.completeWetEnd, 'call', _250 => _250()]);
5856
+ this.wet.onDriverDone = () => _optionalChain([this, 'access', _262 => _262.session, 'optionalAccess', _263 => _263.completeWetEnd, 'call', _264 => _264()]);
5730
5857
  }
5731
5858
  // --- State and events ----------------------------------------------------------
5732
5859
  subscribe(listener) {
@@ -5748,7 +5875,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
5748
5875
  this.cached = {
5749
5876
  document: this.doc,
5750
5877
  brush: this.brush,
5751
- brushes: this.library ??= [..._chunkHS6QDWDFcjs.BUILTIN_BRUSHES, ...this.userBrushes],
5878
+ brushes: this.library ??= this.brushEntries.map((e) => e.brush),
5752
5879
  color: this.color,
5753
5880
  secondaryColor: this.secondaryColor,
5754
5881
  paint: _nullishCoalesce(this.gradient, () => ( { type: "color", color: this.color })),
@@ -5762,8 +5889,8 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
5762
5889
  selectedSticker: this.selectedSticker,
5763
5890
  canUndo: this.undoStack.length > 0 && !this.session,
5764
5891
  canRedo: this.redoStack.length > 0 && !this.session,
5765
- undoLabel: _nullishCoalesce(_optionalChain([last, 'optionalAccess', _251 => _251.label]), () => ( null)),
5766
- redoLabel: _nullishCoalesce(_optionalChain([next, 'optionalAccess', _252 => _252.label]), () => ( null)),
5892
+ undoLabel: _nullishCoalesce(_optionalChain([last, 'optionalAccess', _265 => _265.label]), () => ( null)),
5893
+ redoLabel: _nullishCoalesce(_optionalChain([next, 'optionalAccess', _266 => _266.label]), () => ( null)),
5767
5894
  guides: this.guides,
5768
5895
  swatches: this.swatches,
5769
5896
  mixingPadVersion: this.pad.version,
@@ -5776,10 +5903,10 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
5776
5903
  overlay: this.wet.overlay,
5777
5904
  instantDry: this.wet.instantDry,
5778
5905
  speed: this.wet.speed,
5779
- clock: _nullishCoalesce(_optionalChain([this, 'access', _253 => _253.wet, 'access', _254 => _254.world, 'optionalAccess', _255 => _255.clock]), () => ( 0)),
5906
+ clock: _nullishCoalesce(_optionalChain([this, 'access', _267 => _267.wet, 'access', _268 => _268.world, 'optionalAccess', _269 => _269.clock]), () => ( 0)),
5780
5907
  tilt: { ...this.wet.tilt },
5781
5908
  gpu: this.wet.gpuMode,
5782
- gpuActive: Boolean(_optionalChain([this, 'access', _256 => _256.wet, 'access', _257 => _257.world, 'optionalAccess', _258 => _258.gpuActive]))
5909
+ gpuActive: Boolean(_optionalChain([this, 'access', _270 => _270.wet, 'access', _271 => _271.world, 'optionalAccess', _272 => _272.gpuActive]))
5783
5910
  },
5784
5911
  version: this.version
5785
5912
  };
@@ -5798,7 +5925,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
5798
5925
  return d;
5799
5926
  }
5800
5927
  // --- History -------------------------------------------------------------------
5801
- __init170() {this.docRevision = 0}
5928
+ __init172() {this.docRevision = 0}
5802
5929
  /**
5803
5930
  * Bumped on every change to the painting (a committed or amended step, undo, redo, opening a
5804
5931
  * document), not on wet-paint frames or view changes. `createPaintEditorDocument` uses it.
@@ -5881,9 +6008,9 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
5881
6008
  return wetIds;
5882
6009
  }
5883
6010
  /** Records a wet event (for replays) in the document being built. */
5884
- __init171() {this.pendingWetEvents = []}
6011
+ __init173() {this.pendingWetEvents = []}
5885
6012
  logWet(e) {
5886
- this.pendingWetEvents.push({ clock: _nullishCoalesce(_optionalChain([this, 'access', _259 => _259.wet, 'access', _260 => _260.world, 'optionalAccess', _261 => _261.clock]), () => ( 0)), at: this.doc.strokes.length, ...e });
6013
+ this.pendingWetEvents.push({ clock: _nullishCoalesce(_optionalChain([this, 'access', _273 => _273.wet, 'access', _274 => _274.world, 'optionalAccess', _275 => _275.clock]), () => ( 0)), at: this.doc.strokes.length, ...e });
5887
6014
  }
5888
6015
  /** The document with a paint event appended (for replays). */
5889
6016
  withPaintEvent(doc, e) {
@@ -6027,7 +6154,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
6027
6154
  }
6028
6155
  let next = { ...shiftDocument(this.withWetEvents(this.doc), left, top), canvas: { ...was, width, height } };
6029
6156
  for (const id of keptWet) {
6030
- const l = _optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, next.layers, id), 'optionalAccess', _262 => _262.layer]);
6157
+ const l = _optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, next.layers, id), 'optionalAccess', _276 => _276.layer]);
6031
6158
  if (isPixelLayer(l)) next = { ...next, layers: _chunkDPYAO5U6cjs.mapLayer.call(void 0, next.layers, id, () => ({ ...l, surface: _chunk474IQG74cjs.translateSurface.call(void 0, l.surface, l.offset.x, l.offset.y), offset: { x: 0, y: 0 } })) };
6032
6159
  }
6033
6160
  if (this.wet.world) {
@@ -6071,7 +6198,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
6071
6198
  }
6072
6199
  // --- Layers --------------------------------------------------------------------
6073
6200
  getLayer(id) {
6074
- return _optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _263 => _263.layer]);
6201
+ return _optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _277 => _277.layer]);
6075
6202
  }
6076
6203
  /** The active pixel layer (or `undefined`). */
6077
6204
  getActiveLayer() {
@@ -6090,7 +6217,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
6090
6217
  walk(this.doc.layers, null, 0);
6091
6218
  return out;
6092
6219
  }
6093
- describeLayer(l, parentId = _nullishCoalesce(_optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, this.doc.layers, l.id), 'optionalAccess', _264 => _264.parent, 'optionalAccess', _265 => _265.id]), () => ( null)), depth = _nullishCoalesce(_optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, this.doc.layers, l.id), 'optionalAccess', _266 => _266.path, 'access', _267 => _267.length]), () => ( 0))) {
6220
+ describeLayer(l, parentId = _nullishCoalesce(_optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, this.doc.layers, l.id), 'optionalAccess', _278 => _278.parent, 'optionalAccess', _279 => _279.id]), () => ( null)), depth = _nullishCoalesce(_optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, this.doc.layers, l.id), 'optionalAccess', _280 => _280.path, 'access', _281 => _281.length]), () => ( 0))) {
6094
6221
  let bounds = null;
6095
6222
  if (l.type === "pixel") {
6096
6223
  const b = _chunk474IQG74cjs.contentBounds.call(void 0, l.surface);
@@ -6107,8 +6234,8 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
6107
6234
  locks: { ..._nullishCoalesce(l.locks, () => ( {})) },
6108
6235
  active: l.id === this.doc.activeLayerId,
6109
6236
  bounds,
6110
- ..._optionalChain([this, 'access', _268 => _268.doc, 'access', _269 => _269.liveStrokes, 'optionalAccess', _270 => _270[l.id]]) ? { liveStrokes: this.doc.liveStrokes[l.id].length } : {},
6111
- ..._optionalChain([l, 'access', _271 => _271.effects, 'optionalAccess', _272 => _272.items, 'access', _273 => _273.length]) ? { effects: l.effects.items.length } : {},
6237
+ ..._optionalChain([this, 'access', _282 => _282.doc, 'access', _283 => _283.liveStrokes, 'optionalAccess', _284 => _284[l.id]]) ? { liveStrokes: this.doc.liveStrokes[l.id].length } : {},
6238
+ ..._optionalChain([l, 'access', _285 => _285.effects, 'optionalAccess', _286 => _286.items, 'access', _287 => _287.length]) ? { effects: l.effects.items.length } : {},
6112
6239
  parentId,
6113
6240
  depth
6114
6241
  };
@@ -6140,7 +6267,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
6140
6267
  this.requireIdle("adding a layer");
6141
6268
  const count = _chunkDPYAO5U6cjs.flattenLayers.call(void 0, this.doc.layers).length;
6142
6269
  const type = _nullishCoalesce(options.type, () => ( "pixel"));
6143
- const name = _optionalChain([options, 'access', _274 => _274.name, 'optionalAccess', _275 => _275.trim, 'call', _276 => _276()]) || (type === "group" ? `Group ${count + 1}` : type === "strokes" ? `Strokes ${count + 1}` : `Layer ${count + 1}`);
6270
+ const name = _optionalChain([options, 'access', _288 => _288.name, 'optionalAccess', _289 => _289.trim, 'call', _290 => _290()]) || (type === "group" ? `Group ${count + 1}` : type === "strokes" ? `Strokes ${count + 1}` : `Layer ${count + 1}`);
6144
6271
  const layer = type === "group" ? { type: "group", id: newPaintLayerId(), name, visible: true, opacity: 1, blend: "pass-through", children: [] } : createPaintLayer(name);
6145
6272
  let parentId = null;
6146
6273
  let index;
@@ -6152,7 +6279,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
6152
6279
  } else if (above) {
6153
6280
  const loc = _chunkDPYAO5U6cjs.findLayer.call(void 0, this.doc.layers, above);
6154
6281
  if (!loc) throw new PaintEditorError(`Unknown layer "${above}". Call list_layers for the ids.`);
6155
- parentId = _nullishCoalesce(_optionalChain([loc, 'access', _277 => _277.parent, 'optionalAccess', _278 => _278.id]), () => ( null));
6282
+ parentId = _nullishCoalesce(_optionalChain([loc, 'access', _291 => _291.parent, 'optionalAccess', _292 => _292.id]), () => ( null));
6156
6283
  index = loc.index + 1;
6157
6284
  }
6158
6285
  const layers = _chunkDPYAO5U6cjs.insertLayer.call(void 0, this.doc.layers, layer, parentId, index);
@@ -6258,7 +6385,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
6258
6385
  }
6259
6386
  requireEffect(id, effectId) {
6260
6387
  const l = this.requireLayer(id);
6261
- const items = _nullishCoalesce(_optionalChain([l, 'access', _279 => _279.effects, 'optionalAccess', _280 => _280.items]), () => ( []));
6388
+ const items = _nullishCoalesce(_optionalChain([l, 'access', _293 => _293.effects, 'optionalAccess', _294 => _294.items]), () => ( []));
6262
6389
  const i = items.findIndex((e) => e.id === effectId);
6263
6390
  if (i === -1) throw new PaintEditorError(`Layer "${l.name}" has no effect "${effectId}". Effects: ${items.map((e) => `${e.id} (${e.kind})`).join(", ") || "none"}; call list_layer_effects.`);
6264
6391
  return i;
@@ -6281,7 +6408,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
6281
6408
  }
6282
6409
  const layers = _chunkDPYAO5U6cjs.mapLayer.call(void 0, this.doc.layers, id, () => null);
6283
6410
  let active = this.doc.activeLayerId;
6284
- if (active && !_chunkDPYAO5U6cjs.findLayer.call(void 0, layers, active)) active = _nullishCoalesce(_optionalChain([_chunkDPYAO5U6cjs.flattenLayers.call(void 0, layers), 'access', _281 => _281.filter, 'call', _282 => _282((x) => x.type === "pixel"), 'access', _283 => _283.pop, 'call', _284 => _284(), 'optionalAccess', _285 => _285.id]), () => ( null));
6411
+ if (active && !_chunkDPYAO5U6cjs.findLayer.call(void 0, layers, active)) active = _nullishCoalesce(_optionalChain([_chunkDPYAO5U6cjs.flattenLayers.call(void 0, layers), 'access', _295 => _295.filter, 'call', _296 => _296((x) => x.type === "pixel"), 'access', _297 => _297.pop, 'call', _298 => _298(), 'optionalAccess', _299 => _299.id]), () => ( null));
6285
6412
  this.commit("Remove layer", { ...this.doc, layers, activeLayerId: active, ...this.thickWithout(_chunkDPYAO5U6cjs.flattenLayers.call(void 0, [l]).map((x) => x.id)), ...this.stickersWithout(_chunkDPYAO5U6cjs.flattenLayers.call(void 0, [l]).map((x) => x.id)), ...this.liveStrokesWithout(_chunkDPYAO5U6cjs.flattenLayers.call(void 0, [l]).map((x) => x.id)), ...this.lightWithout(_chunkDPYAO5U6cjs.flattenLayers.call(void 0, [l]).map((x) => x.id)) });
6286
6413
  return { removed: id, activeLayerId: active };
6287
6414
  }
@@ -6307,7 +6434,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
6307
6434
  return l.type === "group" ? { ...l, id: id2, children: l.children.map(copy) } : { ...l, id: id2 };
6308
6435
  };
6309
6436
  const dup = { ...copy(loc.layer), name: `${loc.layer.name} copy` };
6310
- const layers = _chunkDPYAO5U6cjs.insertLayer.call(void 0, this.doc.layers, dup, _nullishCoalesce(_optionalChain([loc, 'access', _286 => _286.parent, 'optionalAccess', _287 => _287.id]), () => ( null)), loc.index + 1);
6437
+ const layers = _chunkDPYAO5U6cjs.insertLayer.call(void 0, this.doc.layers, dup, _nullishCoalesce(_optionalChain([loc, 'access', _300 => _300.parent, 'optionalAccess', _301 => _301.id]), () => ( null)), loc.index + 1);
6311
6438
  this.commit("Duplicate layer", this.withWetEvents({ ...this.doc, layers, activeLayerId: dup.id, ...this.doc.thick ? { thick } : {}, ...this.doc.stickers ? { stickers } : {}, ...this.doc.liveStrokes ? { liveStrokes } : {}, ...this.doc.light ? { light } : {} }));
6312
6439
  return this.describeLayer(dup);
6313
6440
  }
@@ -6316,7 +6443,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
6316
6443
  this.requireIdle("moving a layer");
6317
6444
  const loc = _chunkDPYAO5U6cjs.findLayer.call(void 0, this.doc.layers, id);
6318
6445
  if (!loc) throw new PaintEditorError(`Unknown layer "${id}". Call list_layers for the ids.`);
6319
- const target = parentId === void 0 ? _nullishCoalesce(_optionalChain([loc, 'access', _288 => _288.parent, 'optionalAccess', _289 => _289.id]), () => ( null)) : parentId;
6446
+ const target = parentId === void 0 ? _nullishCoalesce(_optionalChain([loc, 'access', _302 => _302.parent, 'optionalAccess', _303 => _303.id]), () => ( null)) : parentId;
6320
6447
  if (target) {
6321
6448
  const g = this.requireLayer(target);
6322
6449
  if (g.type !== "group") throw new PaintEditorError(`Layer "${g.name}" is not a group; pass a group id as parentId.`);
@@ -6335,7 +6462,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
6335
6462
  const pre = _chunkDPYAO5U6cjs.findLayer.call(void 0, this.doc.layers, id);
6336
6463
  if (pre) {
6337
6464
  const sib = pre.parent ? pre.parent.children : this.doc.layers;
6338
- this.dryLayersFirst([id, _optionalChain([sib, 'access', _290 => _290[pre.index - 1], 'optionalAccess', _291 => _291.id])].filter((x) => Boolean(x)));
6465
+ this.dryLayersFirst([id, _optionalChain([sib, 'access', _304 => _304[pre.index - 1], 'optionalAccess', _305 => _305.id])].filter((x) => Boolean(x)));
6339
6466
  }
6340
6467
  const loc = _chunkDPYAO5U6cjs.findLayer.call(void 0, this.doc.layers, id);
6341
6468
  if (!loc) throw new PaintEditorError(`Unknown layer "${id}". Call list_layers for the ids.`);
@@ -6355,7 +6482,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
6355
6482
  const merged = { ...below, surface, offset: { x: 0, y: 0 } };
6356
6483
  const layers = _chunkDPYAO5U6cjs.mapLayer.call(void 0, _chunkDPYAO5U6cjs.mapLayer.call(void 0, this.doc.layers, upper.id, () => null), below.id, () => merged);
6357
6484
  const toDoc = (t, l) => t ? _chunk474IQG74cjs.translateSurface.call(void 0, t, l.offset.x, l.offset.y) : void 0;
6358
- const mergedLight = _optionalChain([this, 'access', _292 => _292.doc, 'access', _293 => _293.light, 'optionalAccess', _294 => _294[upper.id]]) || _optionalChain([this, 'access', _295 => _295.doc, 'access', _296 => _296.light, 'optionalAccess', _297 => _297[below.id]]) ? mergeLight(toDoc(_optionalChain([this, 'access', _298 => _298.doc, 'access', _299 => _299.light, 'optionalAccess', _300 => _300[below.id]]), below), upper.visible ? toDoc(_optionalChain([this, 'access', _301 => _301.doc, 'access', _302 => _302.light, 'optionalAccess', _303 => _303[upper.id]]), upper) : void 0, _chunk474IQG74cjs.translateSurface.call(void 0, upper.surface, upper.offset.x, upper.offset.y)) : void 0;
6485
+ const mergedLight = _optionalChain([this, 'access', _306 => _306.doc, 'access', _307 => _307.light, 'optionalAccess', _308 => _308[upper.id]]) || _optionalChain([this, 'access', _309 => _309.doc, 'access', _310 => _310.light, 'optionalAccess', _311 => _311[below.id]]) ? mergeLight(toDoc(_optionalChain([this, 'access', _312 => _312.doc, 'access', _313 => _313.light, 'optionalAccess', _314 => _314[below.id]]), below), upper.visible ? toDoc(_optionalChain([this, 'access', _315 => _315.doc, 'access', _316 => _316.light, 'optionalAccess', _317 => _317[upper.id]]), upper) : void 0, _chunk474IQG74cjs.translateSurface.call(void 0, upper.surface, upper.offset.x, upper.offset.y)) : void 0;
6359
6486
  const lightAfter = _nullishCoalesce(this.lightWithout([upper.id, below.id]).light, () => ( (this.doc.light ? { ...this.doc.light } : void 0)));
6360
6487
  const light = mergedLight ? { ..._nullishCoalesce(lightAfter, () => ( {})), [below.id]: mergedLight } : lightAfter;
6361
6488
  this.commit("Merge down", this.withWetEvents({ ...this.doc, layers, activeLayerId: below.id, ...this.thickWithout([upper.id]), ...this.stickersWithout([upper.id, below.id]), ...this.liveStrokesWithout([upper.id, below.id]), ...light ? { light } : {} }));
@@ -6370,7 +6497,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
6370
6497
  this.wet.world.removeLane(l.id);
6371
6498
  }
6372
6499
  const bounds = this.describeLayer(l).bounds;
6373
- this.commit("Clear layer", this.withPaintEvent({ ...this.doc, layers: _chunkDPYAO5U6cjs.mapLayer.call(void 0, this.doc.layers, l.id, () => ({ ...l, surface: _chunk474IQG74cjs.emptySurface.call(void 0, 4) })), ...this.thickWithout([l.id]), ...this.stickersWithout([l.id]), ..._optionalChain([this, 'access', _304 => _304.doc, 'access', _305 => _305.liveStrokes, 'optionalAccess', _306 => _306[l.id]]) ? { liveStrokes: { ...this.doc.liveStrokes, [l.id]: [] } } : {}, ...this.lightWithout([l.id]) }, { kind: "clear", layerId: l.id }));
6500
+ this.commit("Clear layer", this.withPaintEvent({ ...this.doc, layers: _chunkDPYAO5U6cjs.mapLayer.call(void 0, this.doc.layers, l.id, () => ({ ...l, surface: _chunk474IQG74cjs.emptySurface.call(void 0, 4) })), ...this.thickWithout([l.id]), ...this.stickersWithout([l.id]), ..._optionalChain([this, 'access', _318 => _318.doc, 'access', _319 => _319.liveStrokes, 'optionalAccess', _320 => _320[l.id]]) ? { liveStrokes: { ...this.doc.liveStrokes, [l.id]: [] } } : {}, ...this.lightWithout([l.id]) }, { kind: "clear", layerId: l.id }));
6374
6501
  return { layerId: l.id, bounds };
6375
6502
  }
6376
6503
  /**
@@ -6380,8 +6507,8 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
6380
6507
  fillLayer(options = {}) {
6381
6508
  this.requireIdle("filling");
6382
6509
  const fillTarget = this.paintTarget(options.layerId, "fill");
6383
- if (_optionalChain([this, 'access', _307 => _307.doc, 'access', _308 => _308.stickers, 'optionalAccess', _309 => _309[fillTarget.id], 'optionalAccess', _310 => _310.length])) throw new PaintEditorError(`Layer "${fillTarget.name}" is a sticker layer; fill another layer (add_layer).`);
6384
- if (_optionalChain([this, 'access', _311 => _311.doc, 'access', _312 => _312.liveStrokes, 'optionalAccess', _313 => _313[fillTarget.id]])) throw new PaintEditorError(`Layer "${fillTarget.name}" is a stroke layer (its pixels are drawn from its strokes); fill another layer (add_layer), or rasterize it first (rasterize_stroke_layer).`);
6510
+ if (_optionalChain([this, 'access', _321 => _321.doc, 'access', _322 => _322.stickers, 'optionalAccess', _323 => _323[fillTarget.id], 'optionalAccess', _324 => _324.length])) throw new PaintEditorError(`Layer "${fillTarget.name}" is a sticker layer; fill another layer (add_layer).`);
6511
+ if (_optionalChain([this, 'access', _325 => _325.doc, 'access', _326 => _326.liveStrokes, 'optionalAccess', _327 => _327[fillTarget.id]])) throw new PaintEditorError(`Layer "${fillTarget.name}" is a stroke layer (its pixels are drawn from its strokes); fill another layer (add_layer), or rasterize it first (rasterize_stroke_layer).`);
6385
6512
  this.dryLayersFirst([_nullishCoalesce(_nullishCoalesce(options.layerId, () => ( this.doc.activeLayerId)), () => ( ""))]);
6386
6513
  const l = this.paintTarget(options.layerId, "fill");
6387
6514
  const color = options.color === void 0 ? this.color : parseColor(options.color);
@@ -6414,7 +6541,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
6414
6541
  offset: l.offset
6415
6542
  };
6416
6543
  const surface = this.applyCoverage(l, coverage, rect, apply);
6417
- const lit = _optionalChain([this, 'access', _314 => _314.doc, 'access', _315 => _315.light, 'optionalAccess', _316 => _316[l.id]]);
6544
+ const lit = _optionalChain([this, 'access', _328 => _328.doc, 'access', _329 => _329.light, 'optionalAccess', _330 => _330[l.id]]);
6418
6545
  const light = lit ? withLayerLight(this.doc.light, l.id, scaleLight(lit, 1 - opacity)) : void 0;
6419
6546
  this.commit("Fill layer", this.withPaintEvent(this.withWetEvents({ ...this.doc, layers: _chunkDPYAO5U6cjs.mapLayer.call(void 0, this.doc.layers, l.id, () => ({ ...l, surface })), ...light ? { light } : {} }), { kind: "fill", layerId: l.id, data: { color, opacity, grain: grainAmount, pressure, blend } }));
6420
6547
  return { layerId: l.id, bounds: rect };
@@ -6424,7 +6551,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
6424
6551
  const tiles = new Map(base.tiles);
6425
6552
  for (const { tx, ty } of _chunk474IQG74cjs.tilesInRect.call(void 0, { x: rect.x - l.offset.x, y: rect.y - l.offset.y, width: rect.width, height: rect.height })) {
6426
6553
  const key = _chunk474IQG74cjs.tileKey.call(void 0, tx, ty);
6427
- const src = _nullishCoalesce(_optionalChain([base, 'access', _317 => _317.tiles, 'access', _318 => _318.get, 'call', _319 => _319(key), 'optionalAccess', _320 => _320.data]), () => ( new Uint8ClampedArray(_chunk474IQG74cjs.TILE * _chunk474IQG74cjs.TILE * 4)));
6554
+ const src = _nullishCoalesce(_optionalChain([base, 'access', _331 => _331.tiles, 'access', _332 => _332.get, 'call', _333 => _333(key), 'optionalAccess', _334 => _334.data]), () => ( new Uint8ClampedArray(_chunk474IQG74cjs.TILE * _chunk474IQG74cjs.TILE * 4)));
6428
6555
  const tile = _chunk474IQG74cjs.finishTile.call(void 0, _chunkFQPUF2W2cjs.applyStrokeToTile.call(void 0, coverage, src, 4, tx, ty, apply), 4, 0);
6429
6556
  if (tile) tiles.set(key, tile);
6430
6557
  else tiles.delete(key);
@@ -6457,7 +6584,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
6457
6584
  }
6458
6585
  /** The effect a layer is drawn from, or `undefined` for other layers. */
6459
6586
  getEffectLayer(layerId) {
6460
- return _chunkDPYAO5U6cjs.findLayer.call(void 0, this.doc.layers, layerId) ? _optionalChain([this, 'access', _321 => _321.doc, 'access', _322 => _322.effectLayers, 'optionalAccess', _323 => _323[layerId]]) : void 0;
6587
+ return _chunkDPYAO5U6cjs.findLayer.call(void 0, this.doc.layers, layerId) ? _optionalChain([this, 'access', _335 => _335.doc, 'access', _336 => _336.effectLayers, 'optionalAccess', _337 => _337[layerId]]) : void 0;
6461
6588
  }
6462
6589
  /** The effect paper (without its pixels), or `null`. */
6463
6590
  getPaperEffect() {
@@ -6475,7 +6602,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
6475
6602
  if (v === null) merged[k] = d.defaults[k];
6476
6603
  else given[k] = v;
6477
6604
  }
6478
- return { ...merged, ..._chunkISIO63Q5cjs.resolveEffectValues.call(void 0, { ...d, defaults: merged }, given) };
6605
+ return { ...merged, ..._chunkL2JTLW6Bcjs.resolveEffectValues.call(void 0, { ...d, defaults: merged }, given) };
6479
6606
  }
6480
6607
  /** Renders a generator, overlay or title effect at the canvas size. */
6481
6608
  renderEffectCanvas(d, values, time = 0) {
@@ -6494,8 +6621,8 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
6494
6621
  /** A pixel layer that takes effect pixels: unlocked, visible, no sticker layer, no wet paint. */
6495
6622
  effectTarget(layerId, what) {
6496
6623
  const l = this.paintTarget(layerId, what);
6497
- if (_optionalChain([this, 'access', _324 => _324.doc, 'access', _325 => _325.stickers, 'optionalAccess', _326 => _326[l.id], 'optionalAccess', _327 => _327.length])) throw new PaintEditorError(`Layer "${l.name}" is a sticker layer; ${what} another layer (add_layer).`);
6498
- if (_optionalChain([this, 'access', _328 => _328.doc, 'access', _329 => _329.liveStrokes, 'optionalAccess', _330 => _330[l.id]])) throw new PaintEditorError(`Layer "${l.name}" is a stroke layer (its pixels are drawn from its strokes); ${what} another layer (add_layer), or rasterize it first (rasterize_stroke_layer).`);
6624
+ if (_optionalChain([this, 'access', _338 => _338.doc, 'access', _339 => _339.stickers, 'optionalAccess', _340 => _340[l.id], 'optionalAccess', _341 => _341.length])) throw new PaintEditorError(`Layer "${l.name}" is a sticker layer; ${what} another layer (add_layer).`);
6625
+ if (_optionalChain([this, 'access', _342 => _342.doc, 'access', _343 => _343.liveStrokes, 'optionalAccess', _344 => _344[l.id]])) throw new PaintEditorError(`Layer "${l.name}" is a stroke layer (its pixels are drawn from its strokes); ${what} another layer (add_layer), or rasterize it first (rasterize_stroke_layer).`);
6499
6626
  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.`);
6500
6627
  return l;
6501
6628
  }
@@ -6534,8 +6661,8 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
6534
6661
  const was = this.doc.paperEffect;
6535
6662
  const paperEffect = {
6536
6663
  ...this.sourceOf(d, values, options.time),
6537
- opacity: _nullishCoalesce(_nullishCoalesce(options.opacity, () => ( _optionalChain([was, 'optionalAccess', _331 => _331.opacity]))), () => ( 1)),
6538
- blend: _nullishCoalesce(_nullishCoalesce(options.blend, () => ( _optionalChain([was, 'optionalAccess', _332 => _332.blend]))), () => ( "multiply")),
6664
+ opacity: _nullishCoalesce(_nullishCoalesce(options.opacity, () => ( _optionalChain([was, 'optionalAccess', _345 => _345.opacity]))), () => ( 1)),
6665
+ blend: _nullishCoalesce(_nullishCoalesce(options.blend, () => ( _optionalChain([was, 'optionalAccess', _346 => _346.blend]))), () => ( "multiply")),
6539
6666
  image: { width: pixels.width, height: pixels.height, data: new Uint8ClampedArray(pixels.data) },
6540
6667
  version: nextPaperEffectVersion()
6541
6668
  };
@@ -6588,8 +6715,8 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
6588
6715
  const above = _nullishCoalesce(options.aboveId, () => ( this.doc.activeLayerId));
6589
6716
  const loc = above ? _chunkDPYAO5U6cjs.findLayer.call(void 0, this.doc.layers, above) : null;
6590
6717
  if (options.aboveId !== void 0 && !loc) throw new PaintEditorError(`Layer "${options.aboveId}" was removed while the effect rendered.`);
6591
- const layer = { ...createPaintLayer(_optionalChain([options, 'access', _333 => _333.name, 'optionalAccess', _334 => _334.trim, 'call', _335 => _335()]) || d.name), surface: _chunk474IQG74cjs.surfaceFromPixels.call(void 0, pixels, 4), opacity: _nullishCoalesce(options.opacity, () => ( 1)), blend: _nullishCoalesce(options.blend, () => ( "normal")) };
6592
- const layers = _chunkDPYAO5U6cjs.insertLayer.call(void 0, this.doc.layers, layer, _nullishCoalesce(_optionalChain([loc, 'optionalAccess', _336 => _336.parent, 'optionalAccess', _337 => _337.id]), () => ( null)), loc ? loc.index + 1 : void 0);
6718
+ const layer = { ...createPaintLayer(_optionalChain([options, 'access', _347 => _347.name, 'optionalAccess', _348 => _348.trim, 'call', _349 => _349()]) || d.name), surface: _chunk474IQG74cjs.surfaceFromPixels.call(void 0, pixels, 4), opacity: _nullishCoalesce(options.opacity, () => ( 1)), blend: _nullishCoalesce(options.blend, () => ( "normal")) };
6719
+ const layers = _chunkDPYAO5U6cjs.insertLayer.call(void 0, this.doc.layers, layer, _nullishCoalesce(_optionalChain([loc, 'optionalAccess', _350 => _350.parent, 'optionalAccess', _351 => _351.id]), () => ( null)), loc ? loc.index + 1 : void 0);
6593
6720
  const source = this.sourceOf(d, values, options.time);
6594
6721
  this.commit("Add effect layer", { ...this.doc, layers, activeLayerId: layer.id, effectLayers: { ..._nullishCoalesce(this.doc.effectLayers, () => ( {})), [layer.id]: source } });
6595
6722
  return { layer: this.describeLayer(layer), source };
@@ -6730,9 +6857,9 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
6730
6857
  * Renders effect paints that are not rendered yet (strokes and replays need them rendered
6731
6858
  * first, since strokes are synchronous). Throws naming the effect and provider when one cannot be.
6732
6859
  */
6733
- async prepareEffectPaints(paints) {
6860
+ async prepareEffectPaints(paints2) {
6734
6861
  const seen = /* @__PURE__ */ new Set();
6735
- for (const p of paints) {
6862
+ for (const p of paints2) {
6736
6863
  const key = effectPaintKey(p);
6737
6864
  if (seen.has(key)) continue;
6738
6865
  seen.add(key);
@@ -6742,8 +6869,8 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
6742
6869
  /** Renders the effect paints of recorded strokes (default all of them) before a replay. */
6743
6870
  async prepareStrokeEffects(strokeIds) {
6744
6871
  const ids = strokeIds ? new Set(strokeIds) : null;
6745
- const paints = this.doc.strokes.filter((s) => (!ids || ids.has(s.id)) && _optionalChain([s, 'access', _338 => _338.paint, 'optionalAccess', _339 => _339.type]) === "effect").map((s) => s.paint);
6746
- await this.prepareEffectPaints(paints);
6872
+ const paints2 = this.doc.strokes.filter((s) => (!ids || ids.has(s.id)) && _optionalChain([s, 'access', _352 => _352.paint, 'optionalAccess', _353 => _353.type]) === "effect").map((s) => s.paint);
6873
+ await this.prepareEffectPaints(paints2);
6747
6874
  }
6748
6875
  /** A small preview of the effect paint (a PNG data URL `size` px wide), or `null` without a rendered one. */
6749
6876
  effectPaintThumbnail(size = 48) {
@@ -6805,14 +6932,14 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
6805
6932
  const before = _chunk474IQG74cjs.readRegion.call(void 0, l.surface, rect);
6806
6933
  const inputs = { source: { width: rect.width, height: rect.height, data: before } };
6807
6934
  const heightInput = d.inputs.find((i) => i.kind === "image" && /^(height|depth|relief)$/i.test(i.name));
6808
- const relief = _optionalChain([this, 'access', _340 => _340.doc, 'access', _341 => _341.thick, 'optionalAccess', _342 => _342[l.id]]);
6935
+ const relief = _optionalChain([this, 'access', _354 => _354.doc, 'access', _355 => _355.thick, 'optionalAccess', _356 => _356[l.id]]);
6809
6936
  if (heightInput && relief) {
6810
6937
  const h = _chunk474IQG74cjs.readRegion.call(void 0, relief.height, rect);
6811
6938
  const rgba = new Uint8ClampedArray(rect.width * rect.height * 4);
6812
6939
  for (let i = 0; i < h.length; i++) rgba.set([h[i], h[i], h[i], 255], i * 4);
6813
6940
  inputs[heightInput.name] = { width: rect.width, height: rect.height, data: rgba };
6814
6941
  }
6815
- const sourceInput = _nullishCoalesce(_optionalChain([d, 'access', _343 => _343.inputs, 'access', _344 => _344.find, 'call', _345 => _345((i) => i.kind === "image" && i.name !== _optionalChain([heightInput, 'optionalAccess', _346 => _346.name])), 'optionalAccess', _347 => _347.name]), () => ( "source"));
6942
+ const sourceInput = _nullishCoalesce(_optionalChain([d, 'access', _357 => _357.inputs, 'access', _358 => _358.find, 'call', _359 => _359((i) => i.kind === "image" && i.name !== _optionalChain([heightInput, 'optionalAccess', _360 => _360.name])), 'optionalAccess', _361 => _361.name]), () => ( "source"));
6816
6943
  if (sourceInput !== "source") {
6817
6944
  inputs[sourceInput] = inputs.source;
6818
6945
  delete inputs.source;
@@ -6824,100 +6951,162 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
6824
6951
  return { layerId: now.id, source: this.sourceOf(d, values, options.time), amount };
6825
6952
  }
6826
6953
  // --- Brushes -------------------------------------------------------------------
6954
+ findEntry(id) {
6955
+ return this.brushEntries.find((e) => e.brush.id === id);
6956
+ }
6827
6957
  findBrush(id) {
6828
- return _nullishCoalesce(_chunkHS6QDWDFcjs.BUILTIN_BRUSHES.find((b) => b.id === id), () => ( this.userBrushes.find((b) => b.id === id)));
6958
+ return _optionalChain([this, 'access', _362 => _362.findEntry, 'call', _363 => _363(id), 'optionalAccess', _364 => _364.brush]);
6959
+ }
6960
+ requireEntry(id) {
6961
+ const e = this.findEntry(id);
6962
+ if (!e) throw new PaintEditorError(`Unknown brush "${id}". ${_chunk34KLWUH4cjs.closest.call(void 0, id, this.brushEntries.map((x) => x.brush.id))}Call list_brush_presets for the ids.`);
6963
+ return e;
6829
6964
  }
6830
- /** A library brush by id (`undefined` when unknown). */
6965
+ requireBrush(id) {
6966
+ return this.requireEntry(id).brush;
6967
+ }
6968
+ /** Reads the library again (after a change anywhere it is shared). */
6969
+ refreshBrushes() {
6970
+ const run = this.brushLibrary.list().then((entries) => {
6971
+ this.brushEntries = entries.map((e) => libraryBrush(e.brush, e.builtin));
6972
+ this.library = null;
6973
+ const pending = this.pendingBrushId;
6974
+ this.pendingBrushId = null;
6975
+ if (pending && this.findEntry(pending)) this.setBrush({ id: pending });
6976
+ else this.emit([]);
6977
+ });
6978
+ this.brushesLoaded = run.catch(() => void 0);
6979
+ return run;
6980
+ }
6981
+ /** Resolves once the brush library has been read (user brushes kept in storage are listed from then on). */
6982
+ whenBrushesLoaded() {
6983
+ return this.brushesLoaded;
6984
+ }
6985
+ /** A library brush by id, as the engine paints it (`undefined` when unknown). */
6831
6986
  getBrush(id) {
6832
6987
  const b = this.findBrush(id);
6833
6988
  return b ? _chunkHS6QDWDFcjs.normalizePaintBrush.call(void 0, b, b) : void 0;
6834
6989
  }
6835
- requireBrush(id) {
6836
- const b = this.findBrush(id);
6837
- if (!b) throw new PaintEditorError(`Unknown brush "${id}". Call list_brushes for the ids.`);
6838
- return b;
6990
+ /** A library brush by id as stored (its facets), or without an id the active brush as edited. */
6991
+ getBrushSpec(id) {
6992
+ const spec = id === void 0 ? this.brushSpec : _optionalChain([this, 'access', _365 => _365.findEntry, 'call', _366 => _366(id), 'optionalAccess', _367 => _367.spec]);
6993
+ return spec ? copyJSON(spec) : void 0;
6839
6994
  }
6840
6995
  /**
6841
- * Chooses the active brush (`id`: a library brush) and / or changes its settings. Editor state,
6842
- * not an undo step. Returns the active brush.
6996
+ * Chooses the active brush (`id`: a library brush) and / or changes its engine settings. Editor
6997
+ * state, not an undo step. Returns the active brush. `setBrushFacets` changes it by facets.
6843
6998
  */
6844
6999
  setBrush(update = {}) {
6845
7000
  const { id, ...changes } = update;
6846
- const base = id !== void 0 ? this.requireBrush(id) : this.brush;
7001
+ const entry = id !== void 0 ? this.requireEntry(id) : null;
7002
+ const base = entry ? entry.brush : this.brush;
7003
+ const baseSpec = entry ? entry.spec : this.brushSpec;
6847
7004
  if (changes.paint !== void 0 && changes.paint !== null) this.readStrokePaint(changes.paint);
7005
+ const unchanged = !Object.keys(changes).length;
6848
7006
  const next = _chunkHS6QDWDFcjs.normalizePaintBrush.call(void 0, { ...changes, id: base.id }, base);
6849
- if (base.builtin && !Object.keys(changes).length) next.builtin = true;
7007
+ this.useBrush(next, unchanged ? baseSpec : brushSpecOf(next, baseSpec), unchanged && base.builtin === true);
7008
+ return this.brush;
7009
+ }
7010
+ /**
7011
+ * Chooses the active brush (`id`: a library brush) and / or lays a facet patch over it (objects
7012
+ * merge, lists and values replace, as the library's `update_brush` does). Editor state, not an
7013
+ * undo step. `unset` removes whole facets first. Returns the active brush as the engine paints
7014
+ * it, its facets, and what was clamped or dropped.
7015
+ */
7016
+ setBrushFacets(patch = {}, id, unset = []) {
7017
+ const entry = id !== void 0 ? this.requireEntry(id) : null;
7018
+ const unchanged = !Object.keys(patch).length && !unset.length;
7019
+ const problems = [];
7020
+ const base = copyJSON(entry ? entry.spec : this.brushSpec);
7021
+ for (const k of unset) delete base[k];
7022
+ const spec = this.readBrushPatch(base, patch, problems);
7023
+ this.useBrush(unchanged && entry ? entry.brush : _chunk34KLWUH4cjs.resolveBrush.call(void 0, spec), spec, unchanged && _optionalChain([entry, 'optionalAccess', _368 => _368.builtin]) === true);
7024
+ return { brush: this.brush, spec: copyJSON(this.brushSpec), problems };
7025
+ }
7026
+ /**
7027
+ * Makes `spec` (a whole facet brush, as the brush editor edits it) the active brush, keeping the
7028
+ * active brush's id. Editor state, not an undo step. Returns it as the engine paints it, its
7029
+ * facets, and what was clamped or dropped.
7030
+ */
7031
+ setBrushSpec(spec) {
7032
+ const problems = [];
7033
+ const paint = _optionalChain([spec, 'access', _369 => _369.colour, 'optionalAccess', _370 => _370.default]);
7034
+ if (paint && typeof paint === "object" && "type" in paint && paint.type === "gradient") this.readStrokePaint(paint);
7035
+ let next;
7036
+ try {
7037
+ next = _chunk34KLWUH4cjs.normalizeBrushSpec.call(void 0, { ...spec, id: this.brush.id }, problems);
7038
+ } catch (e) {
7039
+ throw new PaintEditorError(e.message);
7040
+ }
7041
+ this.useBrush(_chunk34KLWUH4cjs.resolveBrush.call(void 0, next), next, false);
7042
+ return { brush: this.brush, spec: copyJSON(this.brushSpec), problems };
7043
+ }
7044
+ /**
7045
+ * The engine settings a facet patch changes on a brush (`from`: a library brush id or a brush as
7046
+ * painted; default the active brush), as `paintStroke`'s and `updateStroke`'s `brush` take them.
7047
+ */
7048
+ brushChanges(patch, from) {
7049
+ const entry = typeof from === "string" ? this.requireEntry(from) : null;
7050
+ const base = entry ? entry.brush : typeof from === "object" ? _chunkHS6QDWDFcjs.normalizePaintBrush.call(void 0, from, from) : this.brush;
7051
+ const spec = entry ? entry.spec : typeof from === "object" ? _chunk34KLWUH4cjs.migrateBrushV1.call(void 0, base) : this.brushSpec;
7052
+ return engineChanges(base, _chunk34KLWUH4cjs.resolveBrush.call(void 0, this.readBrushPatch(spec, patch, [])));
7053
+ }
7054
+ readBrushPatch(base, patch, problems) {
7055
+ const { id: _id, name, ...rest } = patch;
7056
+ const paint = _optionalChain([rest, 'access', _371 => _371.colour, 'optionalAccess', _372 => _372.default]);
7057
+ if (paint && typeof paint === "object" && "type" in paint && paint.type === "gradient") this.readStrokePaint(paint);
7058
+ try {
7059
+ return _chunk34KLWUH4cjs.normalizeBrushSpec.call(void 0, _chunk34KLWUH4cjs.mergeBrushPatch.call(void 0, base, { ...rest, ...name !== void 0 ? { name } : {} }), problems);
7060
+ } catch (e) {
7061
+ throw new PaintEditorError(e.message);
7062
+ }
7063
+ }
7064
+ useBrush(next, spec, builtin) {
7065
+ next = _chunkHS6QDWDFcjs.normalizePaintBrush.call(void 0, next, next);
7066
+ if (builtin) next.builtin = true;
6850
7067
  else delete next.builtin;
6851
7068
  this.brush = next;
7069
+ this.brushSpec = { ...copyJSON(spec), id: next.id, name: next.name };
7070
+ this.pendingBrushId = null;
6852
7071
  this.emit([]);
6853
7072
  if (next.engine === "sticker" && next.sticker.stamps.some((r) => !_chunkJSDND7DFcjs.editorStampOf.call(void 0, r))) void this.prepareStickers(next.sticker.stamps).catch(() => this.emit([]));
6854
- return this.brush;
6855
7073
  }
6856
- /** Saves the active brush (or `brush`) into the user library under `id` / `name`. */
6857
- saveBrush(options) {
7074
+ /**
7075
+ * Saves the active brush (or `brush`, engine settings on top of it) into the brush library under
7076
+ * `id` / `name`, replacing a user brush with that id. Built-in ids are refused. Resolves with the
7077
+ * saved brush.
7078
+ */
7079
+ async saveBrush(options) {
6858
7080
  if (!_chunkHS6QDWDFcjs.BRUSH_ID.test(options.id)) throw new PaintEditorError(`Brush id "${options.id}" is invalid; use lowercase letters, digits and dashes (e.g. "my-pencil").`);
6859
- if (_chunkHS6QDWDFcjs.BUILTIN_BRUSHES.some((b) => b.id === options.id)) throw new PaintEditorError(`"${options.id}" is a built-in brush; save under another id.`);
6860
- const source = options.brush ? _chunkHS6QDWDFcjs.normalizePaintBrush.call(void 0, options.brush, this.brush) : this.brush;
6861
- const saved = _chunkHS6QDWDFcjs.normalizePaintBrush.call(void 0, { ...source, id: options.id, name: _nullishCoalesce(options.name, () => ( source.name)) });
6862
- delete saved.builtin;
6863
- const i = this.userBrushes.findIndex((b) => b.id === options.id);
6864
- if (i >= 0) this.userBrushes[i] = saved;
6865
- else this.userBrushes.push(saved);
6866
- this.library = null;
6867
- this.emit([]);
6868
- return saved;
6869
- }
6870
- removeBrush(id) {
6871
- if (_chunkHS6QDWDFcjs.BUILTIN_BRUSHES.some((b) => b.id === id)) throw new PaintEditorError(`"${id}" is a built-in brush and cannot be removed.`);
6872
- const i = this.userBrushes.findIndex((b) => b.id === id);
6873
- if (i < 0) throw new PaintEditorError(`Unknown brush "${id}". Call list_brushes for the ids.`);
6874
- this.userBrushes.splice(i, 1);
6875
- this.library = null;
6876
- this.emit([]);
6877
- }
6878
- /** The user's saved brushes. */
7081
+ if (this.brushLibrary.isBuiltin(options.id)) throw new PaintEditorError(`"${options.id}" is a built-in brush; save under another id.`);
7082
+ const spec = options.brush ? brushSpecOf(_chunkHS6QDWDFcjs.normalizePaintBrush.call(void 0, options.brush, this.brush), this.brushSpec) : this.brushSpec;
7083
+ const { brush } = await libraryCall(() => this.brushLibrary.save({ ...spec, id: options.id, name: _nullishCoalesce(options.name, () => ( spec.name)) }, { overwrite: true }));
7084
+ await this.refreshBrushes();
7085
+ return this.requireBrush(brush.id);
7086
+ }
7087
+ /** Removes a user brush from the brush library (built-in brushes can't be removed). */
7088
+ async removeBrush(id) {
7089
+ if (this.brushLibrary.isBuiltin(id)) throw new PaintEditorError(`"${id}" is a built-in brush and cannot be removed.`);
7090
+ if (!await libraryCall(() => this.brushLibrary.remove(id))) throw new PaintEditorError(`Unknown brush "${id}". Call list_brush_presets for the ids.`);
7091
+ await this.refreshBrushes();
7092
+ }
7093
+ /** The user's saved brushes, as the engine paints them. */
6879
7094
  getUserBrushes() {
6880
- return this.userBrushes.map((b) => _chunkHS6QDWDFcjs.normalizePaintBrush.call(void 0, b, b));
7095
+ return this.brushEntries.filter((e) => !e.builtin).map((e) => _chunkHS6QDWDFcjs.normalizePaintBrush.call(void 0, e.brush, e.brush));
6881
7096
  }
6882
- /** A brush library file of the given brushes (default: the user's brushes). */
7097
+ /** A brush library file (version 2) of the given brushes (default: the user's brushes). */
6883
7098
  exportBrushes(ids) {
6884
- const list = ids ? ids.map((id) => this.requireBrush(id)) : this.userBrushes;
6885
- return { format: "pixerate-brushes", version: 1, brushes: list.map(_chunkHS6QDWDFcjs.brushToJSON) };
7099
+ return libraryCall(() => this.brushLibrary.exportFile(ids));
6886
7100
  }
6887
7101
  /**
6888
- * Adds the brushes of a library file to the user library. A brush whose id is taken is skipped
6889
- * unless `replace` (built-in ids are always skipped). Returns the ids added and the problems.
7102
+ * Adds the brushes of a library file (version 1 or 2) to the brush library. A brush whose id is
7103
+ * taken is skipped unless `replace` (built-in ids are always skipped). Resolves with the ids
7104
+ * added or replaced, the ids skipped and the problems.
6890
7105
  */
6891
- importBrushes(file, options = {}) {
6892
- const problems = [];
6893
- let list;
6894
- try {
6895
- list = _chunkHS6QDWDFcjs.parseBrushLibrary.call(void 0, file, problems);
6896
- } catch (e) {
6897
- throw new PaintEditorError(e.message);
6898
- }
6899
- const added = [];
6900
- const skipped = [];
6901
- for (const b of list) {
6902
- if (_chunkHS6QDWDFcjs.BUILTIN_BRUSHES.some((x) => x.id === b.id)) {
6903
- skipped.push(b.id);
6904
- problems.push(`"${b.id}" is a built-in brush id; rename it to import it.`);
6905
- continue;
6906
- }
6907
- const i = this.userBrushes.findIndex((x) => x.id === b.id);
6908
- if (i >= 0 && !options.replace) {
6909
- skipped.push(b.id);
6910
- continue;
6911
- }
6912
- if (i >= 0) this.userBrushes[i] = b;
6913
- else this.userBrushes.push(b);
6914
- added.push(b.id);
6915
- }
6916
- if (added.length) {
6917
- this.library = null;
6918
- this.emit([]);
6919
- }
6920
- return { added, skipped, problems };
7106
+ async importBrushes(file, options = {}) {
7107
+ const r = await libraryCall(() => this.brushLibrary.importFile(file, { overwrite: !!options.replace }));
7108
+ await this.refreshBrushes();
7109
+ return { added: [...r.added, ...r.replaced], skipped: r.skipped, problems: r.problems };
6921
7110
  }
6922
7111
  /** A thumbnail of a brush: a test stroke on the current paper. */
6923
7112
  brushThumbnail(id, options = {}) {
@@ -7076,20 +7265,20 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7076
7265
  const brush = this.strokeBrush(init);
7077
7266
  const effect = this.strokeEffect(init, brush);
7078
7267
  if (brush.light.amount > 0) {
7079
- if (brush.engine === "sticker") throw new PaintEditorError(`The ${brush.name} brush sprays stickers, which don't take light yet; paint light with a dab or particle light brush (list_brushes category light), or set light.amount to 0 (set_brush).`);
7268
+ if (brush.engine === "sticker") throw new PaintEditorError(`The ${brush.name} brush sprays stickers, which don't take light yet; paint light with a dab or particle light brush (glow-gel, neon-marker; list_brush_presets lists them), or set light.amount to 0 (set_brush).`);
7080
7269
  }
7081
- if (_optionalChain([doc, 'access', _348 => _348.liveStrokes, 'optionalAccess', _349 => _349[layer.id]])) {
7270
+ if (_optionalChain([doc, 'access', _373 => _373.liveStrokes, 'optionalAccess', _374 => _374[layer.id]])) {
7082
7271
  const why = liveStrokeRefusal(brush);
7083
7272
  if (why) throw new PaintEditorError(`Layer "${layer.name}" is a stroke layer. ${why}`);
7084
7273
  }
7085
- if (_optionalChain([doc, 'access', _350 => _350.liveStrokes, 'optionalAccess', _351 => _351[layer.id]]) && _optionalChain([effect, 'optionalAccess', _352 => _352.source, 'access', _353 => _353.live])) {
7274
+ if (_optionalChain([doc, 'access', _375 => _375.liveStrokes, 'optionalAccess', _376 => _376[layer.id]]) && _optionalChain([effect, 'optionalAccess', _377 => _377.source, 'access', _378 => _378.live])) {
7086
7275
  const key = effectPaintKey(effect.source);
7087
7276
  const { sources } = this.liveEffects(doc);
7088
7277
  if (!sources.some((p) => effectPaintKey(p) === key) && sources.length >= MAX_LIVE_EFFECT_SOURCES) {
7089
7278
  throw new PaintEditorError(`The painting already plays ${MAX_LIVE_EFFECT_SOURCES} live effects, the most it can; paint with one of them, or set_effect_paint with live false to bake this one.`);
7090
7279
  }
7091
7280
  }
7092
- const stickerLayer = Boolean(_optionalChain([doc, 'access', _354 => _354.stickers, 'optionalAccess', _355 => _355[layer.id], 'optionalAccess', _356 => _356.length]));
7281
+ const stickerLayer = Boolean(_optionalChain([doc, 'access', _379 => _379.stickers, 'optionalAccess', _380 => _380[layer.id], 'optionalAccess', _381 => _381.length]));
7093
7282
  if (brush.engine === "sticker") {
7094
7283
  if (!stickerLayer && _chunk474IQG74cjs.contentBounds.call(void 0, layer.surface)) throw new PaintEditorError(`Layer "${layer.name}" already has paint; spray stickers onto an empty layer (add_layer) so they stay editable.`);
7095
7284
  } else if (stickerLayer) {
@@ -7129,7 +7318,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7129
7318
  copies: [IDENTITY_AFFINE, ...copiesW].map(affineCopy),
7130
7319
  mask: init.maskStencils ? this.stencilSelection(init.maskStencils) : init.stencils !== false ? this.stencilSelection() : null,
7131
7320
  paint: effect ? null : wetGradient,
7132
- effect: _nullishCoalesce(_optionalChain([effect, 'optionalAccess', _357 => _357.pixels]), () => ( null))
7321
+ effect: _nullishCoalesce(_optionalChain([effect, 'optionalAccess', _382 => _382.pixels]), () => ( null))
7133
7322
  });
7134
7323
  init = { ...init, seed: seedW, load };
7135
7324
  wet = { driver, surface: () => world.display(id).surface };
@@ -7140,7 +7329,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7140
7329
  }
7141
7330
  let color = init.color === void 0 ? this.color : parseColor(init.color);
7142
7331
  const tracing = this.guides.tracing;
7143
- if (init.color === void 0 && init.start && _optionalChain([tracing, 'optionalAccess', _358 => _358.visible]) && tracing.sampleColors) color = _nullishCoalesce(this.sampleTracingColor(init.start.x, init.start.y), () => ( color));
7332
+ if (init.color === void 0 && init.start && _optionalChain([tracing, 'optionalAccess', _383 => _383.visible]) && tracing.sampleColors) color = _nullishCoalesce(this.sampleTracingColor(init.start.x, init.start.y), () => ( color));
7144
7333
  const perspective = this.guides.perspective;
7145
7334
  const snapper = init.snapToPerspective && perspective.enabled && perspective.snap ? new PerspectiveSnapper(perspective) : null;
7146
7335
  const useStencils = init.stencils !== false;
@@ -7173,9 +7362,9 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7173
7362
  mixerLoad: _nullishCoalesce(init.load, () => ( brushLoadForStroke(brush, this.mixerLoad, [rgba[0] / 255, rgba[1] / 255, rgba[2] / 255]))),
7174
7363
  secondary: rgbaOf(this.secondaryColor),
7175
7364
  wet,
7176
- thick: brush.engine === "impasto" ? { channels: _nullishCoalesce(_optionalChain([doc, 'access', _359 => _359.thick, 'optionalAccess', _360 => _360[layer.id]]), () => ( emptyThickChannels())) } : void 0,
7365
+ thick: brush.engine === "impasto" ? { channels: _nullishCoalesce(_optionalChain([doc, 'access', _384 => _384.thick, 'optionalAccess', _385 => _385[layer.id]]), () => ( emptyThickChannels())) } : void 0,
7177
7366
  // Light paint: a twin of the stroke paints the light channel (laying, dimming, moving light).
7178
- light: !wet && brush.engine !== "sticker" && (brush.light.amount > 0 || _optionalChain([doc, 'access', _361 => _361.light, 'optionalAccess', _362 => _362[layer.id]])) ? { surface: _nullishCoalesce(_optionalChain([doc, 'access', _363 => _363.light, 'optionalAccess', _364 => _364[layer.id]]), () => ( emptyLight())) } : null,
7367
+ light: !wet && brush.engine !== "sticker" && (brush.light.amount > 0 || _optionalChain([doc, 'access', _386 => _386.light, 'optionalAccess', _387 => _387[layer.id]])) ? { surface: _nullishCoalesce(_optionalChain([doc, 'access', _388 => _388.light, 'optionalAccess', _389 => _389[layer.id]]), () => ( emptyLight())) } : null,
7179
7368
  sticker: brush.engine === "sticker" ? { nextId: this.nextStickerNumber(doc), art: this.stickerArt.get } : void 0,
7180
7369
  paint: effect ? null : this.strokeGradient(init, brush, color),
7181
7370
  effect
@@ -7214,12 +7403,12 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7214
7403
  const before = this.doc;
7215
7404
  const host = {
7216
7405
  update: (layerId, surface, rects) => {
7217
- if (_optionalChain([this, 'access', _365 => _365.session, 'optionalAccess', _366 => _366.init, 'access', _367 => _367.wet])) {
7406
+ if (_optionalChain([this, 'access', _390 => _390.session, 'optionalAccess', _391 => _391.init, 'access', _392 => _392.wet])) {
7218
7407
  this.wet.syncDisplays();
7219
7408
  return;
7220
7409
  }
7221
7410
  this.live = { layerId, surface };
7222
- const ch = _optionalChain([this, 'access', _368 => _368.session, 'optionalAccess', _369 => _369.thickChannels, 'call', _370 => _370()]);
7411
+ const ch = _optionalChain([this, 'access', _393 => _393.session, 'optionalAccess', _394 => _394.thickChannels, 'call', _395 => _395()]);
7223
7412
  this.liveThick = ch ? { layerId, channels: ch } : null;
7224
7413
  this.emit(rects);
7225
7414
  },
@@ -7231,7 +7420,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7231
7420
  const wetStroke = Boolean(s.init.wet);
7232
7421
  if (wetStroke) this.wet.driver = null;
7233
7422
  const brush = s.init.brush;
7234
- if (!cancelled && _optionalChain([s, 'access', _371 => _371.result, 'optionalAccess', _372 => _372.mixerLoad])) this.keepLoad(brush, s.result.mixerLoad);
7423
+ if (!cancelled && _optionalChain([s, 'access', _396 => _396.result, 'optionalAccess', _397 => _397.mixerLoad])) this.keepLoad(brush, s.result.mixerLoad);
7235
7424
  if (cancelled || !surface) {
7236
7425
  if (this.wetOp) {
7237
7426
  const snap = this.wetOp.before;
@@ -7246,7 +7435,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7246
7435
  }
7247
7436
  const stroke = this.record(s);
7248
7437
  s.result.strokeId = stroke.id;
7249
- this.paintedBounds.set(stroke, _nullishCoalesce(_optionalChain([s, 'access', _373 => _373.result, 'optionalAccess', _374 => _374.bounds]), () => ( null)));
7438
+ this.paintedBounds.set(stroke, _nullishCoalesce(_optionalChain([s, 'access', _398 => _398.result, 'optionalAccess', _399 => _399.bounds]), () => ( null)));
7250
7439
  if (wetStroke && this.wet.instantDry) {
7251
7440
  this.wet.dry(s.layerId);
7252
7441
  this.logWet({ kind: "dry", layerId: s.layerId, at: this.doc.strokes.length + 1 });
@@ -7257,8 +7446,8 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7257
7446
  const ch = s.thickChannels();
7258
7447
  const thick = ch ? { ..._nullishCoalesce(this.doc.thick, () => ( {})), [l.id]: ch } : this.doc.thick;
7259
7448
  const sprayed = s.stickers();
7260
- const stickers = sprayed ? { ..._nullishCoalesce(this.doc.stickers, () => ( {})), [l.id]: [..._nullishCoalesce(_optionalChain([this, 'access', _375 => _375.doc, 'access', _376 => _376.stickers, 'optionalAccess', _377 => _377[l.id]]), () => ( [])), ...sprayed] } : this.doc.stickers;
7261
- const wetLight = wetStroke && _optionalChain([this, 'access', _378 => _378.wet, 'access', _379 => _379.world, 'optionalAccess', _380 => _380.hasLane, 'call', _381 => _381(l.id)]) ? this.wet.world.lightDisplay(l.id) : null;
7449
+ const stickers = sprayed ? { ..._nullishCoalesce(this.doc.stickers, () => ( {})), [l.id]: [..._nullishCoalesce(_optionalChain([this, 'access', _400 => _400.doc, 'access', _401 => _401.stickers, 'optionalAccess', _402 => _402[l.id]]), () => ( [])), ...sprayed] } : this.doc.stickers;
7450
+ const wetLight = wetStroke && _optionalChain([this, 'access', _403 => _403.wet, 'access', _404 => _404.world, 'optionalAccess', _405 => _405.hasLane, 'call', _406 => _406(l.id)]) ? this.wet.world.lightDisplay(l.id) : null;
7262
7451
  const light = withLayerLight(this.doc.light, l.id, _nullishCoalesce(s.lightChannel(), () => ( wetLight)));
7263
7452
  this.commit(`${brush.name} stroke`, this.withWetEvents(withLiveStroke({ ...this.doc, layers: _chunkDPYAO5U6cjs.mapLayer.call(void 0, this.doc.layers, l.id, () => ({ ...l, surface })), strokes: [...this.doc.strokes, stroke], ...thick ? { thick } : {}, ...stickers ? { stickers } : {}, ...light ? { light } : {} }, stroke)), wetStroke ? before : this.doc);
7264
7453
  }
@@ -7288,18 +7477,18 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7288
7477
  if (cancelled || !surface) return;
7289
7478
  const stroke = this.record(s);
7290
7479
  s.result.strokeId = stroke.id;
7291
- this.paintedBounds.set(stroke, _nullishCoalesce(_optionalChain([s, 'access', _382 => _382.result, 'optionalAccess', _383 => _383.bounds]), () => ( null)));
7480
+ this.paintedBounds.set(stroke, _nullishCoalesce(_optionalChain([s, 'access', _407 => _407.result, 'optionalAccess', _408 => _408.bounds]), () => ( null)));
7292
7481
  const l = _chunkDPYAO5U6cjs.findLayer.call(void 0, out.layers, s.layerId).layer;
7293
7482
  const offset = s.init.wet ? { x: 0, y: 0 } : l.offset;
7294
7483
  const ch = s.thickChannels();
7295
7484
  const sprayed = s.stickers();
7296
- const lit = _nullishCoalesce(s.lightChannel(), () => ( (s.init.wet && _optionalChain([this, 'access', _384 => _384.wet, 'access', _385 => _385.world, 'optionalAccess', _386 => _386.hasLane, 'call', _387 => _387(l.id)]) ? this.wet.world.lightDisplay(l.id) : null)));
7485
+ const lit = _nullishCoalesce(s.lightChannel(), () => ( (s.init.wet && _optionalChain([this, 'access', _409 => _409.wet, 'access', _410 => _410.world, 'optionalAccess', _411 => _411.hasLane, 'call', _412 => _412(l.id)]) ? this.wet.world.lightDisplay(l.id) : null)));
7297
7486
  out = withLiveStroke({
7298
7487
  ...out,
7299
7488
  layers: _chunkDPYAO5U6cjs.mapLayer.call(void 0, out.layers, l.id, () => ({ ...l, surface, offset })),
7300
7489
  strokes: [...out.strokes, stroke],
7301
7490
  ...ch ? { thick: { ..._nullishCoalesce(out.thick, () => ( {})), [l.id]: ch } } : {},
7302
- ...sprayed ? { stickers: { ..._nullishCoalesce(out.stickers, () => ( {})), [l.id]: [..._nullishCoalesce(_optionalChain([out, 'access', _388 => _388.stickers, 'optionalAccess', _389 => _389[l.id]]), () => ( [])), ...sprayed] } } : {},
7491
+ ...sprayed ? { stickers: { ..._nullishCoalesce(out.stickers, () => ( {})), [l.id]: [..._nullishCoalesce(_optionalChain([out, 'access', _413 => _413.stickers, 'optionalAccess', _414 => _414[l.id]]), () => ( [])), ...sprayed] } } : {},
7303
7492
  ...lit ? { light: withLayerLight(out.light, l.id, lit) } : {}
7304
7493
  }, stroke);
7305
7494
  }
@@ -7358,7 +7547,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7358
7547
  */
7359
7548
  replayStrokes(options) {
7360
7549
  this.requireIdle("replaying");
7361
- if (!_optionalChain([options, 'access', _390 => _390.strokeIds, 'optionalAccess', _391 => _391.length])) throw new PaintEditorError("strokeIds is empty; pass ids from list_strokes.");
7550
+ if (!_optionalChain([options, 'access', _415 => _415.strokeIds, 'optionalAccess', _416 => _416.length])) throw new PaintEditorError("strokeIds is empty; pass ids from list_strokes.");
7362
7551
  const strokes = options.strokeIds.map((id) => {
7363
7552
  const s = this.doc.strokes.find((x) => x.id === id);
7364
7553
  if (!s) throw new PaintEditorError(`Unknown stroke "${id}". Call list_strokes for the ids.`);
@@ -7372,7 +7561,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7372
7561
  if (options.layerId !== void 0) this.paintTarget(options.layerId, "replay onto");
7373
7562
  if (options.color === void 0) {
7374
7563
  for (const s of strokes) {
7375
- if (_optionalChain([s, 'access', _392 => _392.paint, 'optionalAccess', _393 => _393.type]) === "effect" && !this.effectPaintImage(s.paint)) {
7564
+ if (_optionalChain([s, 'access', _417 => _417.paint, 'optionalAccess', _418 => _418.type]) === "effect" && !this.effectPaintImage(s.paint)) {
7376
7565
  throw new PaintEditorError(`Stroke "${s.id}" paints with the effect "${s.paint.effect}"${s.paint.provider ? ` from provider "${s.paint.provider}"` : ""}, which is not rendered in this editor; render it first (prepareStrokeEffects; the replay_strokes tool does this) or recolour the replay with color.`);
7377
7566
  }
7378
7567
  }
@@ -7430,7 +7619,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7430
7619
  /** A layer's light paint: whether it has any, where (document pixels), its brightest value 0..255, and its spill. */
7431
7620
  lightOf(layerId) {
7432
7621
  const l = this.wetLayer(layerId, "read the light of");
7433
- const info = lightInfo(_optionalChain([this, 'access', _394 => _394.doc, 'access', _395 => _395.light, 'optionalAccess', _396 => _396[l.id]]));
7622
+ const info = lightInfo(_optionalChain([this, 'access', _419 => _419.doc, 'access', _420 => _420.light, 'optionalAccess', _421 => _421[l.id]]));
7434
7623
  const bounds = info.bounds ? { ...info.bounds, x: info.bounds.x + l.offset.x, y: info.bounds.y + l.offset.y } : null;
7435
7624
  return { layerId: l.id, hasLight: info.peak > 0, bounds, peak: info.peak, spill: { ...this.lightSpillOf(l.id) } };
7436
7625
  }
@@ -7481,7 +7670,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7481
7670
  const id = _nullishCoalesce(layerId, () => ( this.doc.activeLayerId));
7482
7671
  if (!id) return null;
7483
7672
  this.requireLayer(id);
7484
- const ch = _optionalChain([this, 'access', _397 => _397.doc, 'access', _398 => _398.thick, 'optionalAccess', _399 => _399[id]]);
7673
+ const ch = _optionalChain([this, 'access', _422 => _422.doc, 'access', _423 => _423.thick, 'optionalAccess', _424 => _424[id]]);
7485
7674
  if (!ch) return null;
7486
7675
  const r = reliefInfo(ch);
7487
7676
  return { layerId: id, bounds: r.bounds, maxHeight: r.maxHeight };
@@ -7507,7 +7696,8 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7507
7696
  const w = Math.round(width * scale);
7508
7697
  const h = Math.round(height * scale);
7509
7698
  if (w > 16384 || h > 16384) throw new PaintEditorError(`At scale ${scale} the canvas would be ${w}\xD7${h}; the limit is 16384 px per side. Use a smaller scale.`);
7510
- const target = new _PaintEditorController({ width: w, height: h, dpi: dpi * scale, brushes: this.userBrushes, wet: this.wetOptions });
7699
+ const target = new _PaintEditorController({ width: w, height: h, dpi: dpi * scale, brushLibrary: this.brushLibrary, wet: this.wetOptions });
7700
+ target.brushEntries = this.brushEntries;
7511
7701
  const paper = { ...this.doc.paper, scale: Math.min(8, this.doc.paper.scale * scale) };
7512
7702
  target.adopt({ state: { canvas: target.doc.canvas, paper, layers: emptiedLayers(this.doc.layers), activeLayerId: this.doc.activeLayerId, strokes: [] }, extensions: {}, problems: [] });
7513
7703
  target.lighting = { ...this.lighting };
@@ -7562,6 +7752,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7562
7752
  }
7563
7753
  /** Stops the wet simulation's worker threads (call when the editor goes away). */
7564
7754
  dispose() {
7755
+ this.unsubscribeLibrary();
7565
7756
  this.wet.destroy();
7566
7757
  this.effectsRenderer.dispose();
7567
7758
  this.effectPaintPixels.clear();
@@ -7589,7 +7780,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7589
7780
  wetState() {
7590
7781
  const st = this.getState().wet;
7591
7782
  const backend = this.wet.backend();
7592
- return { ...st, layers: this.wet.wetLayerIds().map((id) => this.wet.info(id)), backend, message: _nullishCoalesce(_optionalChain([backend, 'optionalAccess', _400 => _400.message]), () => ( _chunkKBYB7OWBcjs.wetSupport.call(void 0, ).message)), engine: this.wet.engineInfo() };
7783
+ return { ...st, layers: this.wet.wetLayerIds().map((id) => this.wet.info(id)), backend, message: _nullishCoalesce(_optionalChain([backend, 'optionalAccess', _425 => _425.message]), () => ( _chunkKBYB7OWBcjs.wetSupport.call(void 0, ).message)), engine: this.wet.engineInfo() };
7593
7784
  }
7594
7785
  /**
7595
7786
  * Engine B, the WebGPU accelerator for large wet areas: whether it may run, its state (`off`,
@@ -7674,7 +7865,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7674
7865
  }
7675
7866
  /** Records a settings change as a wet event (not an undo step). */
7676
7867
  recordWetSetting(e) {
7677
- this.doc = { ...this.doc, wetEvents: [..._nullishCoalesce(this.doc.wetEvents, () => ( [])), { clock: _nullishCoalesce(_optionalChain([this, 'access', _401 => _401.wet, 'access', _402 => _402.world, 'optionalAccess', _403 => _403.clock]), () => ( 0)), at: this.doc.strokes.length, ...e }] };
7868
+ this.doc = { ...this.doc, wetEvents: [..._nullishCoalesce(this.doc.wetEvents, () => ( [])), { clock: _nullishCoalesce(_optionalChain([this, 'access', _426 => _426.wet, 'access', _427 => _427.world, 'optionalAccess', _428 => _428.clock]), () => ( 0)), at: this.doc.strokes.length, ...e }] };
7678
7869
  }
7679
7870
  /** Changes a layer's wet settings (viscosity, evaporation, granulation…). Editor settings saved with the document, not an undo step. */
7680
7871
  setWetParams(layerId, update) {
@@ -7743,7 +7934,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7743
7934
  if (override) return Array.from(override).reduce((ls, [id, surface]) => _chunkDPYAO5U6cjs.mapLayer.call(void 0, ls, id, (l) => ({ ...l, surface })), this.doc.layers);
7744
7935
  const live = this.live;
7745
7936
  if (!live) return this.animatedView();
7746
- if (_optionalChain([this, 'access', _404 => _404.liveLayers, 'optionalAccess', _405 => _405.key]) === live.surface) return this.liveLayers.layers;
7937
+ if (_optionalChain([this, 'access', _429 => _429.liveLayers, 'optionalAccess', _430 => _430.key]) === live.surface) return this.liveLayers.layers;
7747
7938
  const layers = _chunkDPYAO5U6cjs.mapLayer.call(void 0, this.doc.layers, live.layerId, (l) => ({ ...l, surface: live.surface }));
7748
7939
  this.liveLayers = { key: live.surface, layers };
7749
7940
  return layers;
@@ -7766,7 +7957,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7766
7957
  tracingNode(t) {
7767
7958
  const { width, height } = this.doc.canvas;
7768
7959
  const key = this.tracingVersion * 100003 + width * 7 + height;
7769
- if (_optionalChain([this, 'access', _406 => _406.tracingCache, 'optionalAccess', _407 => _407.key]) === key && this.tracingCache.node.opacity === t.opacity) return this.tracingCache.node;
7960
+ if (_optionalChain([this, 'access', _431 => _431.tracingCache, 'optionalAccess', _432 => _432.key]) === key && this.tracingCache.node.opacity === t.opacity) return this.tracingCache.node;
7770
7961
  const src = _nullishCoalesce(this.imagePixels.get(t.src), () => ( this.decodeImage(t.src)));
7771
7962
  const image = resampleInto(src, t.rect, width, height);
7772
7963
  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 };
@@ -7793,8 +7984,8 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7793
7984
  let out = layers;
7794
7985
  const ids = /* @__PURE__ */ new Set([...Object.keys(_nullishCoalesce(thick, () => ( {}))), ...live ? [live.layerId] : []]);
7795
7986
  for (const id of ids) {
7796
- const ch = _optionalChain([live, 'optionalAccess', _408 => _408.layerId]) === id ? live.channels : _optionalChain([thick, 'optionalAccess', _409 => _409[id]]);
7797
- const l = ch && _optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, out, id), 'optionalAccess', _410 => _410.layer]);
7987
+ const ch = _optionalChain([live, 'optionalAccess', _433 => _433.layerId]) === id ? live.channels : _optionalChain([thick, 'optionalAccess', _434 => _434[id]]);
7988
+ const l = ch && _optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, out, id), 'optionalAccess', _435 => _435.layer]);
7798
7989
  if (!ch || !isPixelLayer(l)) continue;
7799
7990
  let cache = this.litCaches.get(id);
7800
7991
  if (!cache) this.litCaches.set(id, cache = new LitCache());
@@ -7814,13 +8005,13 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7814
8005
  if (!ids.size) return layers;
7815
8006
  let out = layers;
7816
8007
  for (const id of ids) {
7817
- const l = _optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, out, id), 'optionalAccess', _411 => _411.layer]);
8008
+ const l = _optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, out, id), 'optionalAccess', _436 => _436.layer]);
7818
8009
  if (!isPixelLayer(l)) continue;
7819
8010
  let cache = this.lightCaches.get(id);
7820
8011
  if (!cache) this.lightCaches.set(id, cache = new LightCache());
7821
- const glowed = cache.glow(l.surface, light[id], _optionalChain([this, 'access', _412 => _412.liveThick, 'optionalAccess', _413 => _413.layerId]) === id ? this.liveThick.channels : _optionalChain([this, 'access', _414 => _414.doc, 'access', _415 => _415.thick, 'optionalAccess', _416 => _416[id]]));
8012
+ const glowed = cache.glow(l.surface, light[id], _optionalChain([this, 'access', _437 => _437.liveThick, 'optionalAccess', _438 => _438.layerId]) === id ? this.liveThick.channels : _optionalChain([this, 'access', _439 => _439.doc, 'access', _440 => _440.thick, 'optionalAccess', _441 => _441[id]]));
7822
8013
  if (glowed !== l.surface) out = _chunkDPYAO5U6cjs.mapLayer.call(void 0, out, id, () => ({ ...l, surface: glowed }));
7823
- const committed = _optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _417 => _417.layer]);
8014
+ const committed = _optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _442 => _442.layer]);
7824
8015
  const spill = light[id] && isPixelLayer(committed) ? cache.spill(committed.surface, light[id], this.lightSpillOf(id)) : null;
7825
8016
  if (spill) out = insertAfter(out, id, { type: "pixel", id: `${id}${SPILL_SUFFIX}`, name: `${l.name} light`, visible: l.visible, opacity: l.opacity, blend: "linear-dodge", surface: spill, offset: { ...l.offset } });
7826
8017
  }
@@ -7832,7 +8023,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7832
8023
  if (!l.visible) continue;
7833
8024
  if (l.type === "group") this.backlitLayers(l.children, committed, opacity * l.opacity, out);
7834
8025
  else if (isPixelLayer(l)) {
7835
- const thick = !committed && _optionalChain([this, 'access', _418 => _418.liveThick, 'optionalAccess', _419 => _419.layerId]) === l.id ? this.liveThick.channels : _optionalChain([this, 'access', _420 => _420.doc, 'access', _421 => _421.thick, 'optionalAccess', _422 => _422[l.id]]);
8026
+ const thick = !committed && _optionalChain([this, 'access', _443 => _443.liveThick, 'optionalAccess', _444 => _444.layerId]) === l.id ? this.liveThick.channels : _optionalChain([this, 'access', _445 => _445.doc, 'access', _446 => _446.thick, 'optionalAccess', _447 => _447[l.id]]);
7836
8027
  out.push({ surface: l.surface, offset: l.offset, opacity: opacity * l.opacity, ...thick ? { thick } : {} });
7837
8028
  }
7838
8029
  }
@@ -7861,7 +8052,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7861
8052
  if (backlight) layers = [...layers, backlight];
7862
8053
  if (options.layerIds) {
7863
8054
  const picked = [];
7864
- for (const id of options.layerIds) picked.push(_nullishCoalesce(_optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, layers, id), 'optionalAccess', _423 => _423.layer]), () => ( this.requireLayer(id))));
8055
+ for (const id of options.layerIds) picked.push(_nullishCoalesce(_optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, layers, id), 'optionalAccess', _448 => _448.layer]), () => ( this.requireLayer(id))));
7865
8056
  layers = picked.map((l) => ({ ...l, visible: true }));
7866
8057
  }
7867
8058
  const under = options.paper === false ? [] : [paperNode(this.doc.paper, this.lighting)];
@@ -7877,7 +8068,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7877
8068
  */
7878
8069
  compositeTiles(rect, onTile, options = {}) {
7879
8070
  const dirty = options.dirty === "all" ? void 0 : options.dirty;
7880
- this.viewCompositor.compositeTiles(this.renderLayers({ paper: options.paper }, true), rect, this.sources(), onTile, { dirty, checkpointLayerId: _nullishCoalesce(_optionalChain([this, 'access', _424 => _424.live, 'optionalAccess', _425 => _425.layerId]), () => ( this.doc.activeLayerId)) });
8071
+ this.viewCompositor.compositeTiles(this.renderLayers({ paper: options.paper }, true), rect, this.sources(), onTile, { dirty, checkpointLayerId: _nullishCoalesce(_optionalChain([this, 'access', _449 => _449.live, 'optionalAccess', _450 => _450.layerId]), () => ( this.doc.activeLayerId)) });
7881
8072
  }
7882
8073
  /** The canvas as canvas-sized RGBA (paper included by default). */
7883
8074
  compositePixels(options = {}) {
@@ -7942,7 +8133,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7942
8133
  if (Object.keys(stickers).length) ext.stickers = stickers;
7943
8134
  else delete ext.stickers;
7944
8135
  const liveStrokes = {};
7945
- for (const [id, list] of Object.entries(_nullishCoalesce(this.doc.liveStrokes, () => ( {})))) if (_chunkDPYAO5U6cjs.findLayer.call(void 0, this.doc.layers, id)) liveStrokes[id] = list.map((x) => JSON.parse(JSON.stringify(x)));
8136
+ for (const [id, list] of Object.entries(_nullishCoalesce(this.doc.liveStrokes, () => ( {})))) if (_chunkDPYAO5U6cjs.findLayer.call(void 0, this.doc.layers, id)) liveStrokes[id] = list.map(strokeToJSON);
7946
8137
  if (Object.keys(liveStrokes).length) ext.liveStrokes = liveStrokes;
7947
8138
  else delete ext.liveStrokes;
7948
8139
  const light = {};
@@ -7956,7 +8147,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7956
8147
  const spills = Object.fromEntries(Object.entries(this.lightSpills).filter(([id]) => _chunkDPYAO5U6cjs.findLayer.call(void 0, this.doc.layers, id)));
7957
8148
  if (Object.keys(spills).length) ext.lightSpill = spills;
7958
8149
  else delete ext.lightSpill;
7959
- const effectLayers = effectLayersToJSON(_nullishCoalesce(this.doc.effectLayers, () => ( {})), (id) => isPixelLayer(_optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _426 => _426.layer])));
8150
+ const effectLayers = effectLayersToJSON(_nullishCoalesce(this.doc.effectLayers, () => ( {})), (id) => isPixelLayer(_optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _451 => _451.layer])));
7960
8151
  if (effectLayers) ext.effectLayers = effectLayers;
7961
8152
  else delete ext.effectLayers;
7962
8153
  if (this.doc.paperEffect) ext.paperEffect = paperEffectToJSON(this.doc.paperEffect);
@@ -7980,7 +8171,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7980
8171
  const stamp = _chunkJSDND7DFcjs.editorStampOf.call(void 0, ref2);
7981
8172
  const { stamp: _old, ...rest } = x;
7982
8173
  return [{ ...rest, ref: ref2, ...stamp ? { stamp } : {} }];
7983
- } catch (e6) {
8174
+ } catch (e8) {
7984
8175
  return [];
7985
8176
  }
7986
8177
  });
@@ -7992,7 +8183,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
7992
8183
  if (ext.liveStrokes && typeof ext.liveStrokes === "object") {
7993
8184
  const liveStrokes = {};
7994
8185
  for (const [id, list] of Object.entries(ext.liveStrokes)) {
7995
- if (!isPixelLayer(_optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, state.layers, id), 'optionalAccess', _427 => _427.layer])) || !Array.isArray(list)) continue;
8186
+ if (!isPixelLayer(_optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, state.layers, id), 'optionalAccess', _452 => _452.layer])) || !Array.isArray(list)) continue;
7996
8187
  const ok = list.map(normalizeBrushStroke).filter((x) => x !== null).map((x) => ({ ...x, layerId: id }));
7997
8188
  if (ok.length !== list.length) problems.push(`Some strokes of stroke layer "${id}" could not be read; they were dropped (the layer's pixels are kept until a stroke is edited).`);
7998
8189
  liveStrokes[id] = ok;
@@ -8002,7 +8193,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
8002
8193
  if (ext.effectLayers && typeof ext.effectLayers === "object") {
8003
8194
  const effectLayers = {};
8004
8195
  for (const [id, v] of Object.entries(ext.effectLayers)) {
8005
- if (!isPixelLayer(_optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, state.layers, id), 'optionalAccess', _428 => _428.layer]))) continue;
8196
+ if (!isPixelLayer(_optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, state.layers, id), 'optionalAccess', _453 => _453.layer]))) continue;
8006
8197
  const source = readPaintEffectSource(v);
8007
8198
  if (source) effectLayers[id] = source;
8008
8199
  else problems.push(`The effect of layer "${id}" could not be read; it loads as a plain layer.`);
@@ -8022,7 +8213,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
8022
8213
  for (const [id, v] of Object.entries(ext.lightSpill)) {
8023
8214
  try {
8024
8215
  if (_chunkDPYAO5U6cjs.findLayer.call(void 0, state.layers, id)) this.lightSpills[id] = normalizeLightSpill(_nullishCoalesce(v, () => ( {})));
8025
- } catch (e7) {
8216
+ } catch (e9) {
8026
8217
  problems.push(`The light spill of layer "${id}" could not be read; it takes the defaults.`);
8027
8218
  }
8028
8219
  }
@@ -8030,7 +8221,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
8030
8221
  if (ext.light && typeof ext.light === "object") {
8031
8222
  const light = {};
8032
8223
  for (const [id, v] of Object.entries(ext.light)) {
8033
- if (!isPixelLayer(_optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, state.layers, id), 'optionalAccess', _429 => _429.layer]))) continue;
8224
+ if (!isPixelLayer(_optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, state.layers, id), 'optionalAccess', _454 => _454.layer]))) continue;
8034
8225
  try {
8035
8226
  light[id] = lightFromJSON(v);
8036
8227
  } catch (e) {
@@ -8066,7 +8257,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
8066
8257
  this.readGuides(loaded.guides, loaded.state, loaded.problems);
8067
8258
  if (Array.isArray(loaded.swatches)) this.swatches = loaded.swatches.map(readSwatch).filter((x) => x !== null);
8068
8259
  for (const s of loaded.state.strokes) {
8069
- const n = Number(_nullishCoalesce(_optionalChain([/^s(\d+)$/, 'access', _430 => _430.exec, 'call', _431 => _431(s.id), 'optionalAccess', _432 => _432[1]]), () => ( 0)));
8260
+ const n = Number(_nullishCoalesce(_optionalChain([/^s(\d+)$/, 'access', _455 => _455.exec, 'call', _456 => _456(s.id), 'optionalAccess', _457 => _457[1]]), () => ( 0)));
8070
8261
  if (n >= this.strokeCounter) this.strokeCounter = n + 1;
8071
8262
  }
8072
8263
  this.undoStack = [];
@@ -8074,7 +8265,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
8074
8265
  this.doc = this.readThick(loaded.state, loaded.extensions, loaded.problems);
8075
8266
  for (const list of Object.values(_nullishCoalesce(this.doc.liveStrokes, () => ( {})))) {
8076
8267
  for (const s of list) {
8077
- const n = Number(_nullishCoalesce(_optionalChain([/^s(\d+)$/, 'access', _433 => _433.exec, 'call', _434 => _434(s.id), 'optionalAccess', _435 => _435[1]]), () => ( 0)));
8268
+ const n = Number(_nullishCoalesce(_optionalChain([/^s(\d+)$/, 'access', _458 => _458.exec, 'call', _459 => _459(s.id), 'optionalAccess', _460 => _460[1]]), () => ( 0)));
8078
8269
  if (n >= this.strokeCounter) this.strokeCounter = n + 1;
8079
8270
  }
8080
8271
  }
@@ -8173,8 +8364,8 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
8173
8364
  const layers = toStandard(dried);
8174
8365
  const result = _chunkJFHBXNR2cjs.exportPsd.call(void 0, { width, height, layers: [paperLayer, ...layers], merged, resolution: dpi });
8175
8366
  for (const [mode, names] of changed) {
8176
- const label = _nullishCoalesce(_optionalChain([_chunk2VX55NFMcjs.BLEND_MODES, 'access', _436 => _436.find, 'call', _437 => _437((m) => m.id === mode), 'optionalAccess', _438 => _438.label]), () => ( mode));
8177
- const std = _nullishCoalesce(_optionalChain([_chunk2VX55NFMcjs.BLEND_MODES, 'access', _439 => _439.find, 'call', _440 => _440((m) => m.id === _chunk2VX55NFMcjs.standardBlendMode.call(void 0, mode)), 'optionalAccess', _441 => _441.label]), () => ( _chunk2VX55NFMcjs.standardBlendMode.call(void 0, mode)));
8367
+ const label = _nullishCoalesce(_optionalChain([_chunk2VX55NFMcjs.BLEND_MODES, 'access', _461 => _461.find, 'call', _462 => _462((m) => m.id === mode), 'optionalAccess', _463 => _463.label]), () => ( mode));
8368
+ const std = _nullishCoalesce(_optionalChain([_chunk2VX55NFMcjs.BLEND_MODES, 'access', _464 => _464.find, 'call', _465 => _465((m) => m.id === _chunk2VX55NFMcjs.standardBlendMode.call(void 0, mode)), 'optionalAccess', _466 => _466.label]), () => ( _chunk2VX55NFMcjs.standardBlendMode.call(void 0, mode)));
8178
8369
  const list = names.map((n) => `"${n}"`).join(", ");
8179
8370
  const one = names.length === 1;
8180
8371
  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).`);
@@ -8296,7 +8487,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
8296
8487
  const { src, pixels } = this.importImage(options, "The reference image");
8297
8488
  const ref2 = {
8298
8489
  id: `ref${this.nextReferenceId++}`,
8299
- name: _optionalChain([options, 'access', _442 => _442.name, 'optionalAccess', _443 => _443.trim, 'call', _444 => _444()]) || `Reference ${this.guides.references.length + 1}`,
8490
+ name: _optionalChain([options, 'access', _467 => _467.name, 'optionalAccess', _468 => _468.trim, 'call', _469 => _469()]) || `Reference ${this.guides.references.length + 1}`,
8300
8491
  src,
8301
8492
  width: pixels.width,
8302
8493
  height: pixels.height,
@@ -8375,7 +8566,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
8375
8566
  try {
8376
8567
  const px = this.decodeImage(ref2.src, `Reference "${ref2.name}"`);
8377
8568
  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 });
8378
- const n = Number(_nullishCoalesce(_optionalChain([/^ref(\d+)$/, 'access', _445 => _445.exec, 'call', _446 => _446(ref2.id), 'optionalAccess', _447 => _447[1]]), () => ( 0)));
8569
+ const n = Number(_nullishCoalesce(_optionalChain([/^ref(\d+)$/, 'access', _470 => _470.exec, 'call', _471 => _471(ref2.id), 'optionalAccess', _472 => _472[1]]), () => ( 0)));
8379
8570
  if (n >= this.nextReferenceId) this.nextReferenceId = n + 1;
8380
8571
  } catch (e) {
8381
8572
  problems.push(e.message);
@@ -8386,7 +8577,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
8386
8577
  guides.stencils = [];
8387
8578
  r.stencils.forEach((raw2, i) => {
8388
8579
  try {
8389
- const id = typeof _optionalChain([raw2, 'optionalAccess', _448 => _448.id]) === "string" && /^stencil\d+$/.test(raw2.id) ? raw2.id : `stencil${this.nextStencilId}`;
8580
+ const id = typeof _optionalChain([raw2, 'optionalAccess', _473 => _473.id]) === "string" && /^stencil\d+$/.test(raw2.id) ? raw2.id : `stencil${this.nextStencilId}`;
8390
8581
  guides.stencils.push(normalizeStencil(raw2, id));
8391
8582
  const n = Number(id.slice(7));
8392
8583
  if (n >= this.nextStencilId) this.nextStencilId = n + 1;
@@ -8409,13 +8600,13 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
8409
8600
  /** The next free sticker number (ids `st<n>` are unique across the document). */
8410
8601
  nextStickerNumber(doc = this.doc) {
8411
8602
  let n = 0;
8412
- for (const list of Object.values(_nullishCoalesce(doc.stickers, () => ( {})))) for (const st of list) n = Math.max(n, Number(_nullishCoalesce(_optionalChain([/^st(\d+)$/, 'access', _449 => _449.exec, 'call', _450 => _450(st.id), 'optionalAccess', _451 => _451[1]]), () => ( 0))));
8603
+ for (const list of Object.values(_nullishCoalesce(doc.stickers, () => ( {})))) for (const st of list) n = Math.max(n, Number(_nullishCoalesce(_optionalChain([/^st(\d+)$/, 'access', _474 => _474.exec, 'call', _475 => _475(st.id), 'optionalAccess', _476 => _476[1]]), () => ( 0))));
8413
8604
  return n + 1;
8414
8605
  }
8415
8606
  stickerLayer(layerId) {
8416
8607
  const l = this.wetLayer(layerId, "edit the stickers of");
8417
- const stickers = _optionalChain([this, 'access', _452 => _452.doc, 'access', _453 => _453.stickers, 'optionalAccess', _454 => _454[l.id]]);
8418
- if (!stickers) throw new PaintEditorError(`Layer "${l.name}" has no stickers; spray some with a sticker brush (list_brushes category sticker).`);
8608
+ const stickers = _optionalChain([this, 'access', _477 => _477.doc, 'access', _478 => _478.stickers, 'optionalAccess', _479 => _479[l.id]]);
8609
+ if (!stickers) throw new PaintEditorError(`Layer "${l.name}" has no stickers; spray some with a sticker brush (sticker-stars; list_brush_presets lists them).`);
8419
8610
  return { layer: l, stickers };
8420
8611
  }
8421
8612
  // --- The sticker library ---------------------------------------------------------
@@ -8473,7 +8664,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
8473
8664
  const id = _nullishCoalesce(layerId, () => ( this.doc.activeLayerId));
8474
8665
  if (!id) return [];
8475
8666
  this.requireLayer(id);
8476
- return (_nullishCoalesce(_optionalChain([this, 'access', _455 => _455.doc, 'access', _456 => _456.stickers, 'optionalAccess', _457 => _457[id]]), () => ( []))).map((s) => ({ ...s }));
8667
+ return (_nullishCoalesce(_optionalChain([this, 'access', _480 => _480.doc, 'access', _481 => _481.stickers, 'optionalAccess', _482 => _482[id]]), () => ( []))).map((s) => ({ ...s }));
8477
8668
  }
8478
8669
  /**
8479
8670
  * Replaces a layer's stickers and redraws its pixels from them (one undo step). With `dirty`,
@@ -8494,7 +8685,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
8494
8685
  }
8495
8686
  /** The document from before the sticker preview on screen, or `null` when none is (anything else changed the document since). */
8496
8687
  previewBase() {
8497
- return _optionalChain([this, 'access', _458 => _458.stickerPreview, 'optionalAccess', _459 => _459.shown]) === this.doc ? this.stickerPreview.base : null;
8688
+ return _optionalChain([this, 'access', _483 => _483.stickerPreview, 'optionalAccess', _484 => _484.shown]) === this.doc ? this.stickerPreview.base : null;
8498
8689
  }
8499
8690
  readStickerUpdate(update) {
8500
8691
  try {
@@ -8509,7 +8700,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
8509
8700
  const id = _nullishCoalesce(layerId, () => ( this.doc.activeLayerId));
8510
8701
  if (!id) return null;
8511
8702
  this.requireLayer(id);
8512
- const hit = stickerAt(_nullishCoalesce(_optionalChain([this, 'access', _460 => _460.doc, 'access', _461 => _461.stickers, 'optionalAccess', _462 => _462[id]]), () => ( [])), x, y, this.stickerArt.get);
8703
+ const hit = stickerAt(_nullishCoalesce(_optionalChain([this, 'access', _485 => _485.doc, 'access', _486 => _486.stickers, 'optionalAccess', _487 => _487[id]]), () => ( [])), x, y, this.stickerArt.get);
8513
8704
  return hit ? { ...hit } : null;
8514
8705
  }
8515
8706
  /** Picks a sticker for the panel and canvas (`null` for none). Editor state, not an undo step. */
@@ -8565,8 +8756,8 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
8565
8756
  const layer = this.wetLayer(layerId, "add stickers to");
8566
8757
  if (!input.length) throw new PaintEditorError("Pass at least one sticker (ref, x, y).");
8567
8758
  if (input.length > MAX_ADD_STICKERS) throw new PaintEditorError(`At most ${MAX_ADD_STICKERS} stickers per call; split them over several calls.`);
8568
- const existing = _optionalChain([this, 'access', _463 => _463.doc, 'access', _464 => _464.stickers, 'optionalAccess', _465 => _465[layer.id]]);
8569
- if (!_optionalChain([existing, 'optionalAccess', _466 => _466.length])) {
8759
+ const existing = _optionalChain([this, 'access', _488 => _488.doc, 'access', _489 => _489.stickers, 'optionalAccess', _490 => _490[layer.id]]);
8760
+ if (!_optionalChain([existing, 'optionalAccess', _491 => _491.length])) {
8570
8761
  if (this.wet.wetLayerIds().includes(layer.id) || _chunk474IQG74cjs.contentBounds.call(void 0, layer.surface)) throw new PaintEditorError(`Layer "${layer.name}" already has paint; add stickers to an empty layer (add_layer) or a sticker layer so they stay editable.`);
8571
8762
  }
8572
8763
  let n = this.nextStickerNumber();
@@ -8583,7 +8774,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
8583
8774
  const id = n++;
8584
8775
  return { id: `st${id}`, size: 48, rotation: 0, color: this.color, opacity: 1, seed: _nullishCoalesce(raw.seed, () => ( _chunk3K6HWEXZcjs.mix32.call(void 0, id * 2654435761 >>> 0) & 2147483647)), ...u };
8585
8776
  });
8586
- this.commitStickers("Add stickers", layer, [..._nullishCoalesce(existing, () => ( [])), ...added], _optionalChain([existing, 'optionalAccess', _467 => _467.length]) ? added.map(stickerRect) : void 0);
8777
+ this.commitStickers("Add stickers", layer, [..._nullishCoalesce(existing, () => ( [])), ...added], _optionalChain([existing, 'optionalAccess', _492 => _492.length]) ? added.map(stickerRect) : void 0);
8587
8778
  return added.map((s) => ({ ...s }));
8588
8779
  }
8589
8780
  /** Brings stickers to the top (`front`) or bottom of their layer (one undo step). */
@@ -8622,20 +8813,20 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
8622
8813
  }
8623
8814
  liveStrokeLayer(layerId, what) {
8624
8815
  const l = this.wetLayer(layerId, what);
8625
- const strokes = _optionalChain([this, 'access', _468 => _468.doc, 'access', _469 => _469.liveStrokes, 'optionalAccess', _470 => _470[l.id]]);
8816
+ const strokes = _optionalChain([this, 'access', _493 => _493.doc, 'access', _494 => _494.liveStrokes, 'optionalAccess', _495 => _495[l.id]]);
8626
8817
  if (!strokes) throw new PaintEditorError(`Layer "${l.name}" is not a stroke layer; add one with add_layer {type: "strokes"} (or convert_to_stroke_layer on an empty layer), then paint on it.`);
8627
8818
  return { layer: l, strokes };
8628
8819
  }
8629
8820
  /** Whether a layer is a live stroke layer. */
8630
8821
  isLiveStrokeLayer(layerId) {
8631
- return Boolean(_optionalChain([this, 'access', _471 => _471.doc, 'access', _472 => _472.liveStrokes, 'optionalAccess', _473 => _473[layerId]]));
8822
+ return Boolean(_optionalChain([this, 'access', _496 => _496.doc, 'access', _497 => _497.liveStrokes, 'optionalAccess', _498 => _498[layerId]]));
8632
8823
  }
8633
8824
  /** Makes an empty pixel layer a live stroke layer (one undo step). */
8634
8825
  convertToLiveStrokes(layerId) {
8635
8826
  this.requireIdle("converting a layer");
8636
8827
  const l = this.paintTarget(layerId, "convert");
8637
- if (_optionalChain([this, 'access', _474 => _474.doc, 'access', _475 => _475.liveStrokes, 'optionalAccess', _476 => _476[l.id]])) return this.describeLayer(l);
8638
- if (_optionalChain([this, 'access', _477 => _477.doc, 'access', _478 => _478.stickers, 'optionalAccess', _479 => _479[l.id], 'optionalAccess', _480 => _480.length])) throw new PaintEditorError(`Layer "${l.name}" is a sticker layer; add a stroke layer instead (add_layer {type: "strokes"}).`);
8828
+ if (_optionalChain([this, 'access', _499 => _499.doc, 'access', _500 => _500.liveStrokes, 'optionalAccess', _501 => _501[l.id]])) return this.describeLayer(l);
8829
+ if (_optionalChain([this, 'access', _502 => _502.doc, 'access', _503 => _503.stickers, 'optionalAccess', _504 => _504[l.id], 'optionalAccess', _505 => _505.length])) throw new PaintEditorError(`Layer "${l.name}" is a sticker layer; add a stroke layer instead (add_layer {type: "strokes"}).`);
8639
8830
  if (_chunk474IQG74cjs.contentBounds.call(void 0, l.surface) || this.wet.wetLayerIds().includes(l.id)) throw new PaintEditorError(`Layer "${l.name}" already has paint, which isn't kept as strokes; convert an empty layer or add a stroke layer (add_layer {type: "strokes"}).`);
8640
8831
  this.commit("Convert to stroke layer", { ...this.doc, liveStrokes: { ..._nullishCoalesce(this.doc.liveStrokes, () => ( {})), [l.id]: [] } });
8641
8832
  return this.describeLayer(this.getLayer(l.id));
@@ -8648,7 +8839,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
8648
8839
  findLiveStroke(id) {
8649
8840
  for (const [layerId, strokes] of Object.entries(_nullishCoalesce(this.doc.liveStrokes, () => ( {})))) {
8650
8841
  const index = strokes.findIndex((x) => x.id === id);
8651
- const layer = _optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, this.doc.layers, layerId), 'optionalAccess', _481 => _481.layer]);
8842
+ const layer = _optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, this.doc.layers, layerId), 'optionalAccess', _506 => _506.layer]);
8652
8843
  if (index >= 0 && isPixelLayer(layer)) return { layer, strokes, index };
8653
8844
  }
8654
8845
  const baked = this.doc.strokes.some((x) => x.id === id);
@@ -8743,9 +8934,9 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
8743
8934
  const layers = /* @__PURE__ */ new Map();
8744
8935
  for (const f of found) layers.set(f.layer.id, f.layer);
8745
8936
  for (const [layerId, layer] of layers) {
8746
- const gone = (_nullishCoalesce(_optionalChain([doc, 'access', _482 => _482.liveStrokes, 'optionalAccess', _483 => _483[layerId]]), () => ( []))).filter((x) => ids.includes(x.id));
8937
+ const gone = (_nullishCoalesce(_optionalChain([doc, 'access', _507 => _507.liveStrokes, 'optionalAccess', _508 => _508[layerId]]), () => ( []))).filter((x) => ids.includes(x.id));
8747
8938
  for (const x of gone) bounds = unionRect(bounds, this.strokeArea(x));
8748
- doc = this.withLiveStrokes(doc, layer, (_nullishCoalesce(_optionalChain([doc, 'access', _484 => _484.liveStrokes, 'optionalAccess', _485 => _485[layerId]]), () => ( []))).filter((x) => !ids.includes(x.id)), this.strokeAreas(gone));
8939
+ doc = this.withLiveStrokes(doc, layer, (_nullishCoalesce(_optionalChain([doc, 'access', _509 => _509.liveStrokes, 'optionalAccess', _510 => _510[layerId]]), () => ( []))).filter((x) => !ids.includes(x.id)), this.strokeAreas(gone));
8749
8940
  }
8750
8941
  this.commit(ids.length === 1 ? "Remove stroke" : "Remove strokes", doc);
8751
8942
  return { removed: [...ids], bounds };
@@ -8813,7 +9004,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
8813
9004
  }
8814
9005
  withLiveStrokes(doc, layer, list, dirty) {
8815
9006
  if (_chunkDPYAO5U6cjs.isLayerLocked.call(void 0, layer, "pixels")) throw new PaintEditorError(`Layer "${layer.name}" has its pixels locked; unlock it (update_layer locks) first.`);
8816
- const current = _optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, doc.layers, layer.id), 'optionalAccess', _486 => _486.layer]);
9007
+ const current = _optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, doc.layers, layer.id), 'optionalAccess', _511 => _511.layer]);
8817
9008
  const surface = this.drawLiveStrokes(_nullishCoalesce(current, () => ( layer)), list, dirty);
8818
9009
  const next = { ...doc, layers: _chunkDPYAO5U6cjs.mapLayer.call(void 0, doc.layers, layer.id, (l) => ({ ...l, surface, offset: { x: 0, y: 0 } })), liveStrokes: { ..._nullishCoalesce(doc.liveStrokes, () => ( {})), [layer.id]: [...list] } };
8819
9010
  return this.withPaintEvent(next, { kind: "live-strokes", layerId: layer.id, data: { strokes: list.map((x) => JSON.parse(JSON.stringify(x))) } });
@@ -8891,7 +9082,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
8891
9082
  if (!this.animatedLayers.size) return this.doc.layers;
8892
9083
  let layers = this.doc.layers;
8893
9084
  for (const [id, a] of this.animatedLayers) {
8894
- const l = _optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, layers, id), 'optionalAccess', _487 => _487.layer]);
9085
+ const l = _optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, layers, id), 'optionalAccess', _512 => _512.layer]);
8895
9086
  if (isPixelLayer(l) && l.surface === a.base) layers = _chunkDPYAO5U6cjs.mapLayer.call(void 0, layers, id, () => ({ ...l, surface: a.surface }));
8896
9087
  }
8897
9088
  return layers;
@@ -8901,7 +9092,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
8901
9092
  const layers = [];
8902
9093
  const sources = /* @__PURE__ */ new Map();
8903
9094
  for (const [id, strokes] of Object.entries(_nullishCoalesce(doc.liveStrokes, () => ( {})))) {
8904
- const layer = _optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, doc.layers, id), 'optionalAccess', _488 => _488.layer]);
9095
+ const layer = _optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, doc.layers, id), 'optionalAccess', _513 => _513.layer]);
8905
9096
  const live = strokes.filter(isLiveEffect);
8906
9097
  if (!isPixelLayer(layer) || !live.length) continue;
8907
9098
  layers.push({ layer, strokes });
@@ -9026,13 +9217,13 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
9026
9217
  return this.withEffectTime(time, () => this.compositePixels(options));
9027
9218
  }
9028
9219
  // --- Stencils --------------------------------------------------------------------
9029
- __init172() {this.stencilCache = null}
9030
- __init173() {this.nextStencilId = 1}
9220
+ __init174() {this.stencilCache = null}
9221
+ __init175() {this.nextStencilId = 1}
9031
9222
  /** The mask stencils' coverage over the canvas (cached), or `null` when none masks. */
9032
9223
  stencilSelection(stencils = this.guides.stencils) {
9033
9224
  const { width, height } = this.doc.canvas;
9034
9225
  const size = `${width}x${height}`;
9035
- if (_optionalChain([this, 'access', _489 => _489.stencilCache, 'optionalAccess', _490 => _490.key]) === stencils && this.stencilCache.size === size) return this.stencilCache.mask;
9226
+ if (_optionalChain([this, 'access', _514 => _514.stencilCache, 'optionalAccess', _515 => _515.key]) === stencils && this.stencilCache.size === size) return this.stencilCache.mask;
9036
9227
  const mask = stencilMask(stencils, width, height);
9037
9228
  this.stencilCache = { key: stencils, size, mask };
9038
9229
  return mask;
@@ -9094,7 +9285,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
9094
9285
  makeSwatch(color, name) {
9095
9286
  const p = typeof color === "string" ? { type: "color", color: parseColor(color) } : this.readStrokePaint(color);
9096
9287
  const out = { color: _chunkFQPUF2W2cjs.paintSourceColor.call(void 0, p, { paint: this.color, secondary: this.secondaryColor }) };
9097
- if (_optionalChain([name, 'optionalAccess', _491 => _491.trim, 'call', _492 => _492()])) out.name = name.trim();
9288
+ if (_optionalChain([name, 'optionalAccess', _516 => _516.trim, 'call', _517 => _517()])) out.name = name.trim();
9098
9289
  if (p.type === "gradient") out.paint = p;
9099
9290
  return out;
9100
9291
  }
@@ -9145,8 +9336,8 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
9145
9336
  * and a fully mixed core of the Kubelka-Munk mix (see `MixingPad.mix`). With `setColor` the
9146
9337
  * mix becomes the paint colour. Returns the mixed colour and the pile's bounds.
9147
9338
  */
9148
- mixOnPad(paints, options = {}) {
9149
- const parsed = (_nullishCoalesce(paints, () => ( []))).map((p, i) => ({ color: parseColor(_optionalChain([p, 'optionalAccess', _493 => _493.color]), `paints[${i}].color`), parts: _optionalChain([p, 'optionalAccess', _494 => _494.parts]) }));
9339
+ mixOnPad(paints2, options = {}) {
9340
+ const parsed = (_nullishCoalesce(paints2, () => ( []))).map((p, i) => ({ color: parseColor(_optionalChain([p, 'optionalAccess', _518 => _518.color]), `paints[${i}].color`), parts: _optionalChain([p, 'optionalAccess', _519 => _519.parts]) }));
9150
9341
  let r;
9151
9342
  try {
9152
9343
  r = this.pad.mix(parsed, options);
@@ -9235,7 +9426,7 @@ var PaintEditorController = (_class19 = class _PaintEditorController {
9235
9426
  }
9236
9427
  /** A layer's tile surface (live while stroking), for thumbnails. */
9237
9428
  layerSurface(id) {
9238
- const l = _optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, this.currentLayers(), id), 'optionalAccess', _495 => _495.layer]);
9429
+ const l = _optionalChain([_chunkDPYAO5U6cjs.findLayer.call(void 0, this.currentLayers(), id), 'optionalAccess', _520 => _520.layer]);
9239
9430
  return isPixelLayer(l) ? l.surface : null;
9240
9431
  }
9241
9432
  }, _class19.__initStatic(), _class19);
@@ -9257,7 +9448,7 @@ function insertAfter(layers, id, node) {
9257
9448
  return layers.map((l) => l.type === "group" ? { ...l, children: insertAfter(l.children, id, node) } : l);
9258
9449
  }
9259
9450
  function isLiveEffect(s) {
9260
- return _optionalChain([s, 'access', _496 => _496.paint, 'optionalAccess', _497 => _497.type]) === "effect" && s.paint.live === true;
9451
+ return _optionalChain([s, 'access', _521 => _521.paint, 'optionalAccess', _522 => _522.type]) === "effect" && s.paint.live === true;
9261
9452
  }
9262
9453
  function framePaint(p, t) {
9263
9454
  return { ...p, time: p.time + t };
@@ -9282,7 +9473,7 @@ function clipRect(r, width, height) {
9282
9473
  return x1 > x0 && y1 > y0 ? { x: x0, y: y0, width: x1 - x0, height: y1 - y0 } : null;
9283
9474
  }
9284
9475
  function withLiveStroke(doc, stroke) {
9285
- const list = _optionalChain([doc, 'access', _498 => _498.liveStrokes, 'optionalAccess', _499 => _499[stroke.layerId]]);
9476
+ const list = _optionalChain([doc, 'access', _523 => _523.liveStrokes, 'optionalAccess', _524 => _524[stroke.layerId]]);
9286
9477
  return list ? { ...doc, liveStrokes: { ...doc.liveStrokes, [stroke.layerId]: [...list, stroke] } } : doc;
9287
9478
  }
9288
9479
  function shiftDocument(doc, dx, dy) {
@@ -9309,9 +9500,9 @@ function shiftDocument(doc, dx, dy) {
9309
9500
  if (doc.liveStrokes) out.liveStrokes = Object.fromEntries(Object.entries(doc.liveStrokes).map(([id, list]) => [id, list.map(moveStroke)]));
9310
9501
  if (doc.paintEvents) {
9311
9502
  out.paintEvents = doc.paintEvents.map((e) => {
9312
- const list = e.kind === "stickers" ? _optionalChain([e, 'access', _500 => _500.data, 'optionalAccess', _501 => _501.stickers]) : void 0;
9503
+ const list = e.kind === "stickers" ? _optionalChain([e, 'access', _525 => _525.data, 'optionalAccess', _526 => _526.stickers]) : void 0;
9313
9504
  if (list) return { ...e, data: { ...e.data, stickers: moveStickers(list) } };
9314
- const strokes = e.kind === "live-strokes" ? _optionalChain([e, 'access', _502 => _502.data, 'optionalAccess', _503 => _503.strokes]) : void 0;
9505
+ const strokes = e.kind === "live-strokes" ? _optionalChain([e, 'access', _527 => _527.data, 'optionalAccess', _528 => _528.strokes]) : void 0;
9315
9506
  return strokes ? { ...e, data: { ...e.data, strokes: strokes.map(moveStroke) } } : e;
9316
9507
  });
9317
9508
  }
@@ -9393,8 +9584,8 @@ function strokeSchedule(points) {
9393
9584
  return total > 0 ? acc.map((d) => d / total) : points.map(() => 1);
9394
9585
  }
9395
9586
  function strokeDuration(points, max = 1800) {
9396
- const t0 = _optionalChain([points, 'access', _504 => _504[0], 'optionalAccess', _505 => _505.t]);
9397
- const t1 = _optionalChain([points, 'access', _506 => _506[points.length - 1], 'optionalAccess', _507 => _507.t]);
9587
+ const t0 = _optionalChain([points, 'access', _529 => _529[0], 'optionalAccess', _530 => _530.t]);
9588
+ const t1 = _optionalChain([points, 'access', _531 => _531[points.length - 1], 'optionalAccess', _532 => _532.t]);
9398
9589
  let ms;
9399
9590
  if (points.every((p) => Number.isFinite(p.t)) && t1 > t0) ms = t1 - t0;
9400
9591
  else {
@@ -9448,7 +9639,7 @@ var PaintDirector = class {
9448
9639
  }
9449
9640
  where(id) {
9450
9641
  const a = this.presence.get(id);
9451
- return { x: _nullishCoalesce(_optionalChain([a, 'optionalAccess', _508 => _508.x]), () => ( 0)), y: _nullishCoalesce(_optionalChain([a, 'optionalAccess', _509 => _509.y]), () => ( 0)) };
9642
+ return { x: _nullishCoalesce(_optionalChain([a, 'optionalAccess', _533 => _533.x]), () => ( 0)), y: _nullishCoalesce(_optionalChain([a, 'optionalAccess', _534 => _534.y]), () => ( 0)) };
9452
9643
  }
9453
9644
  /** Glides to `to`; an actor that just appeared starts there instead of the corner. */
9454
9645
  async glide(id, to, ms = 380) {
@@ -9495,8 +9686,8 @@ var PaintDirector = class {
9495
9686
  }
9496
9687
  case "replay": {
9497
9688
  await this.say(id, command.note, 500);
9498
- const source = c.getStrokes().filter((s) => _optionalChain([command, 'access', _510 => _510.replay, 'access', _511 => _511.strokeIds, 'optionalAccess', _512 => _512.includes, 'call', _513 => _513(s.id)]));
9499
- const first = _optionalChain([source, 'access', _514 => _514[0], 'optionalAccess', _515 => _515.points, 'access', _516 => _516[0]]);
9689
+ const source = c.getStrokes().filter((s) => _optionalChain([command, 'access', _535 => _535.replay, 'access', _536 => _536.strokeIds, 'optionalAccess', _537 => _537.includes, 'call', _538 => _538(s.id)]));
9690
+ const first = _optionalChain([source, 'access', _539 => _539[0], 'optionalAccess', _540 => _540.points, 'access', _541 => _541[0]]);
9500
9691
  if (first) await this.glide(id, first);
9501
9692
  const result = c.replayStrokes(command.replay);
9502
9693
  if (result.bounds) await this.glide(id, centre(result.bounds), 520);
@@ -10140,7 +10331,7 @@ function createPaintGuideTools(c) {
10140
10331
  additionalProperties: false
10141
10332
  },
10142
10333
  annotations: { title: "Mix paints on the pad", ...WRITE2 },
10143
- handler: ({ paints, x, y, radius, passes, clear, setColor }) => c.mixOnPad(paints, { x, y, radius, passes, clear, setColor })
10334
+ handler: ({ paints: paints2, x, y, radius, passes, clear, setColor }) => c.mixOnPad(paints2, { x, y, radius, passes, clear, setColor })
10144
10335
  },
10145
10336
  {
10146
10337
  name: "save_mixing_pad",
@@ -10571,254 +10762,6 @@ var DESTRUCTIVE3 = { readOnlyHint: false, destructiveHint: true, idempotentHint:
10571
10762
  var EMPTY3 = { type: "object", properties: {}, additionalProperties: false };
10572
10763
  var COLOR3 = { type: "string", pattern: "^#[0-9a-fA-F]{6}$", description: 'Colour #rrggbb, e.g. "#2a4b8d".' };
10573
10764
  var LAYER_ID4 = { type: "string", description: "Layer id from list_layers (default the active layer)." };
10574
- var TIP = {
10575
- type: "object",
10576
- description: "The tip (the shared brush engine). Missing fields keep their current values.",
10577
- properties: {
10578
- size: { type: "number", minimum: 1, maximum: _chunkFQPUF2W2cjs.MAX_BRUSH_SIZE, description: "Diameter in pixels." },
10579
- hardness: { type: "number", minimum: 0, maximum: 1, description: "Edge hardness, 0 (soft) .. 1 (hard)." },
10580
- spacing: { type: "number", minimum: 0.01, maximum: 10, description: "Dab spacing as a fraction of the diameter (0.05 is smooth, 1 is dotted)." },
10581
- angle: { type: "number", minimum: -360, maximum: 360, description: "Tip angle in degrees, counter-clockwise; with rotation stroke or barrel it is added to the stroke direction or pen rotation." },
10582
- roundness: { type: "number", minimum: 0.01, maximum: 1, description: "Tip roundness: 1 round, lower is a flat ellipse (a pastel or chisel tip)." },
10583
- opacity: { type: "number", minimum: 0, maximum: 1, description: "Stroke opacity ceiling: overlapping dabs never exceed it." },
10584
- flow: { type: "number", minimum: 0, maximum: 1, description: "Build-up per dab towards the opacity (low flow builds up softly, like an airbrush)." },
10585
- smoothing: { type: "number", minimum: 0, maximum: 0.95, description: "Position smoothing of the input, 0..0.95." },
10586
- pressureSize: { type: "boolean", description: "Pressure scales the size (down to dynamics.minSize)." },
10587
- pressureOpacity: { type: "boolean", description: "Pressure scales the opacity." },
10588
- blend: {
10589
- type: "string",
10590
- enum: _chunk2VX55NFMcjs.BLEND_MODES.map((m) => m.id),
10591
- description: "How paint combines with the layer. pigment mixes it in like real paint (blue into yellow gives green); multiply darkens like marker ink; watercolor glazes like a transparent wash; tint, highlight and shadow recolour, light and shade (see list_blend_modes)."
10592
- }
10593
- },
10594
- additionalProperties: false
10595
- };
10596
- var DYNAMICS = {
10597
- type: "object",
10598
- description: "Pen dynamics and jitter. Missing fields keep their current values.",
10599
- properties: {
10600
- minSize: { type: "number", minimum: 0, maximum: 1, description: "Size at zero pressure as a fraction of the full size (when pressureSize)." },
10601
- pressureFlow: { type: "number", minimum: 0, maximum: 1, description: "How much pressure scales flow." },
10602
- tiltSize: { type: "number", minimum: 0, maximum: 1, description: "Laying the pen down widens the tip (up to 2.5\xD7)." },
10603
- tiltRoundness: { type: "number", minimum: 0, maximum: 1, description: "Laying the pen down flattens the tip along the tilt (side-of-the-pencil shading)." },
10604
- tiltOpacity: { type: "number", minimum: 0, maximum: 1, description: "Laying the pen down lightens the mark." },
10605
- velocitySize: { type: "number", minimum: -1, maximum: 1, description: "Positive grows the tip on fast strokes, negative thins it (needs point times t)." },
10606
- velocityOpacity: { type: "number", minimum: -1, maximum: 1, description: "Positive darkens fast marks, negative lightens them (needs point times t)." },
10607
- sizeJitter: { type: "number", minimum: 0, maximum: 1, description: "Random size change per dab." },
10608
- angleJitter: { type: "number", minimum: 0, maximum: 1, description: "Random angle per dab, as a fraction of \xB1180\xB0." },
10609
- opacityJitter: { type: "number", minimum: 0, maximum: 1, description: "Random opacity drop per dab." },
10610
- scatter: { type: "number", minimum: 0, maximum: 4, description: "Random offset across the stroke, in diameters." }
10611
- },
10612
- additionalProperties: false
10613
- };
10614
- var MIXER = {
10615
- type: "object",
10616
- description: "Mixer engine settings (the Mixer Brush). Missing fields keep their current values.",
10617
- properties: {
10618
- wet: { type: "number", minimum: 0, maximum: 1, description: "Pick-up ratio: how much canvas colour each dab picks up, 0 (dry) .. 1." },
10619
- load: { type: "number", minimum: 0, maximum: 1, description: "How much paint the reservoir holds; below 1 it drains per dab, so long strokes run dry." },
10620
- mix: { type: "number", minimum: 0, maximum: 1, description: "Mix ratio: how far each dab's paint moves from the reservoir towards the picked-up colour." },
10621
- loadEachStroke: { type: "boolean", description: "Refill the reservoir with the colour before each stroke." },
10622
- cleanEachStroke: { type: "boolean", description: "Empty the pickup well after each stroke." },
10623
- mixing: { type: "string", enum: [..._chunkFQPUF2W2cjs.MIXING_MODELS], description: "rgb: RGB averages. pigment: mixes like paint (Kubelka-Munk)." }
10624
- },
10625
- additionalProperties: false
10626
- };
10627
- var MIXING = { type: "string", enum: [..._chunkFQPUF2W2cjs.MIXING_MODELS], description: "pigment: mixes like paint (Kubelka-Munk, blue and yellow make green); rgb: straight RGB averages." };
10628
- var BEHAVIOR = {
10629
- type: "object",
10630
- description: "How the brush handles paint on the canvas (dab and mixer engines; on a mixer brush pickup, mix, dirty and mixing are its mixer wet, mix, !cleanEachStroke and mixing). Missing fields keep their current values.",
10631
- properties: {
10632
- pickup: { type: "number", minimum: 0, maximum: 1, description: "Pick-up ratio 0..1: how much of the paint under each dab the brush lifts and carries along (0: none, a dry brush)." },
10633
- mix: { type: "number", minimum: 0, maximum: 1, description: "Mix ratio 0..1: how much of the carried paint goes into what the brush lays down, against the brush's own colour (scaled by pickup)." },
10634
- dirty: { type: "boolean", description: "Dirty brush: keep the carried paint after the stroke, so the next stroke starts with the last colour it touched (needs pickup above 0). clean_mixer_brush wipes it." },
10635
- mixing: MIXING,
10636
- multicolor: {
10637
- type: "object",
10638
- description: "Multi-coloured brush (the older form of paint, the brush's own gradient: tip is across-tip, dab is distance in dabs or random). Read back from paint when it has a multi-colour equivalent. Missing fields keep their current values.",
10639
- properties: {
10640
- mode: { type: "string", enum: [..._chunkHS6QDWDFcjs.MULTI_COLOR_MODES], description: "off; tip: the colours lie side by side across the tip (stripes along the stroke, like a brush loaded with several paints); dab: the colour changes along the stroke." },
10641
- colors: { type: "array", maxItems: 8, items: { ...COLOR3 }, description: "2..8 colours #rrggbb; fewer than 2 uses the paint colour and the secondary colour." },
10642
- order: { type: "string", enum: ["sequence", "random"], description: "dab mode: sequence runs through the colours in order, blending between them; random picks one per run of dabs (seeded)." },
10643
- length: { type: "integer", minimum: 1, maximum: 500, description: "dab mode: dabs per colour (default 12)." },
10644
- softness: { type: "number", minimum: 0, maximum: 1, description: "How softly neighbouring colours blend: 0 hard stripes or steps, 1 a smooth gradient." }
10645
- },
10646
- additionalProperties: false
10647
- }
10648
- },
10649
- additionalProperties: false
10650
- };
10651
- var BRUSH_PAINT = {
10652
- description: `The brush's own gradient paint, used instead of the editor's paint (null: the editor's paint). It is what the multi-colour settings became; stops may be "paint" / "secondary" for the editor's two colours.`,
10653
- anyOf: [_chunkFQPUF2W2cjs.PAINT_GRADIENT_JSON_SCHEMA, { type: "null", description: "No gradient of its own: the editor's paint." }]
10654
- };
10655
- var BLENDER = {
10656
- type: "object",
10657
- description: "Blender engine settings. Missing fields keep their current values.",
10658
- properties: {
10659
- strength: { type: "number", minimum: 0, maximum: 1, description: "How far each pixel under the tip moves towards the mix of the paint near it, per dab." },
10660
- distance: { type: "number", minimum: 0, maximum: 1, description: "Blend distance: how far away colours are mixed in, as a fraction of the tip diameter (0.35 default; higher blends wider and softer)." },
10661
- mixing: MIXING
10662
- },
10663
- additionalProperties: false
10664
- };
10665
- var SMUDGE = {
10666
- type: "object",
10667
- description: "Smudge engine settings. Missing fields keep their current values.",
10668
- properties: {
10669
- strength: { type: "number", minimum: 0, maximum: 1, description: "How strongly the dragged paint covers what is under the tip, per dab." },
10670
- length: { type: "number", minimum: 0, maximum: 1, description: "How far paint is dragged: the share of the carried paint kept from dab to dab (0.85 default; 1 drags it the whole stroke)." },
10671
- mixing: { ...MIXING, description: "rgb (default): smeared colours average; pigment: they mix like paint." }
10672
- },
10673
- additionalProperties: false
10674
- };
10675
- var WET_BRUSH = {
10676
- type: "object",
10677
- description: "Wet engine settings (watercolour, gouache and the wet tools). Missing fields keep their current values.",
10678
- properties: {
10679
- tool: {
10680
- type: "string",
10681
- enum: [..._chunkHS6QDWDFcjs.WET_TOOLS],
10682
- description: "paint: water and pigment (picks up and mixes wet paint by behavior.pickup / mix); water: clear water (with rewet it lifts dried paint); dry: a hair dryer, takes water; blow: pushes the water along the stroke; blend: evens out wet pigment; smudge: drags wet paint; blot: a tissue, takes wet paint up (erase wet)."
10683
- },
10684
- medium: { type: "string", enum: [..._chunkHS6QDWDFcjs.WET_MEDIA], description: "The medium: watercolor, gouache or oil. A layer takes the medium's wet settings the first time it holds wet paint (oil: thick, barely flows, stays wet long and blends into the wet paint it meets)." },
10685
- load: { type: "number", minimum: 0, maximum: 1, description: "Paint loading: 1 never runs out; lower, the brush runs dry along a long stroke (each stroke reloads)." },
10686
- thinner: { type: "number", minimum: 0, maximum: 1, description: "Thinner (water or solvent): more transparent, runnier paint." },
10687
- water: { type: "number", minimum: 0, maximum: 1, description: "Wetness: water laid per stroke, 0.2 a damp brush .. 1 a dripping one." },
10688
- pigment: { type: "number", minimum: 0, maximum: 1, description: "Pigment concentration: 0 clear water .. 1 straight from the tube." },
10689
- body: { type: "number", minimum: 0, maximum: 1, description: "Body: 0 a transparent watercolour (glazes) .. 1 opaque gouache (hides what is under it)." },
10690
- strength: { type: "number", minimum: 0, maximum: 1, description: "Strength of dry, blow, blend, smudge and blot." },
10691
- rewet: { type: "number", minimum: 0, maximum: 1, description: "How much dried paint the water lifts again: 0 none (staining) .. 1." }
10692
- },
10693
- additionalProperties: false
10694
- };
10695
- var IMPASTO_BRUSH = {
10696
- type: "object",
10697
- description: "Impasto engine settings (thick paint with relief, lit by set_lighting). Missing fields keep their current values.",
10698
- properties: {
10699
- tool: {
10700
- type: "string",
10701
- enum: [..._chunkHS6QDWDFcjs.IMPASTO_TOOLS],
10702
- description: "brush: thick paint with bristle ridges along the stroke; tube: blobs squeezed from the tube; knife: a palette knife that scrapes the relief flat and smears the paint; roller: a flat stippled band; gloop: a thick, glossy, rounded bead."
10703
- },
10704
- thickness: { type: "number", minimum: 0, maximum: 1, description: "How far the paint stands up." },
10705
- gloss: { type: "number", minimum: 0, maximum: 1, description: "Shine: 0 matte .. 1 wet-looking gloss." },
10706
- metallic: { type: "number", minimum: 0, maximum: 1, description: "Metallic paint: highlights take the paint colour (gold, copper, silver)." },
10707
- load: { type: "number", minimum: 0, maximum: 1, description: "Paint loading: 1 never runs out; lower, the stroke thins and fades as the brush empties." },
10708
- thinner: { type: "number", minimum: 0, maximum: 1, description: "Thinner: flatter, more transparent paint." },
10709
- drag: { type: "number", minimum: 0, maximum: 1, description: "Knife and brush: how much of the paint under the tool is dragged along." },
10710
- rim: { type: "number", minimum: 0, maximum: 1, description: "Light paint (with light.amount): the bead's light is stronger where its surface turns away, as on backlit glass (default 0)." },
10711
- clarity: { type: "number", minimum: 0, maximum: 1, description: "Glassy paint: the middle of a bead lets the layers below show through while its edges stay solid (default 0). flatten_relief clears it." }
10712
- },
10713
- additionalProperties: false
10714
- };
10715
- var LIGHT_BRUSH = {
10716
- type: "object",
10717
- description: "Light paint: the light the brush lays with its colour, glowing in the paint's own colour and spilling onto its surroundings (set_light_spill). Dab, particle, bristle, Mixer Brush, impasto and wet paint brushes take it (wet light flows, pools, granulates and blooms with the pigment until the paint dries, then is ordinary light paint); wet tools other than paint lay none, and sticker brushes refuse light above 0. Missing fields keep their current values.",
10718
- properties: {
10719
- amount: { type: "number", minimum: 0, maximum: 1, description: "Light each dab lays, scaled by its coverage and flow (0 none, default; 1 full)." },
10720
- pressure: { type: "boolean", description: "Pressure scales the light (default false)." }
10721
- },
10722
- additionalProperties: false
10723
- };
10724
- var PARTICLE_BRUSH = {
10725
- type: "object",
10726
- description: "Particle engine settings (procedural brushes). Missing fields keep their current values.",
10727
- properties: {
10728
- kind: {
10729
- type: "string",
10730
- enum: [..._chunkHS6QDWDFcjs.PARTICLE_KINDS],
10731
- description: "string: strands of masses on springs dragged behind the pen (hair, fur, wet string); spring: particles on springs to the pen, overshooting and wobbling; orbit: particles circling the pen (curls); flow: particles thrown off the pen into a swirling flow until they fade; elastic: strands whose links keep a rest length, stretching when the pen is fast and snapping back; fuzzy: winding strings, each strand waving out of step with the others (always waves by at least 0.12 of the tip size)."
10732
- },
10733
- render: {
10734
- type: "string",
10735
- enum: [..._chunkHS6QDWDFcjs.PARTICLE_RENDERS],
10736
- description: "dot: a mark at each step (round, or dotTextures); line: each particle draws a continuous line; sequence: beads spaced along each path (round, or dotTextures); ribbon: the band between neighbouring particles' paths filled (ribbonFill), with the paths drawn as its edges at the mark size (flame, silk, smoke)."
10737
- },
10738
- count: { type: "integer", minimum: 1, maximum: 64, description: "Particles (flow: how many are thrown per tip of travel)." },
10739
- size: { type: "number", minimum: 0, maximum: 1, description: "Mark size as a fraction of the tip size (ribbon: the width of its edges)." },
10740
- spread: { type: "number", minimum: 0, maximum: 1, description: "How far apart the particles start, as a fraction of the tip size (ribbon: how wide it is)." },
10741
- stiffness: { type: "number", minimum: 0, maximum: 1, description: "Spring, string and elastic stiffness: stiff follows closely (elastic: snaps back faster), soft swings wide." },
10742
- damping: { type: "number", minimum: 0, maximum: 1, description: "How quickly motion dies down." },
10743
- speed: { type: "number", minimum: 0, maximum: 1, description: "Orbit and flow speed." },
10744
- gravity: { type: "number", minimum: -1, maximum: 1, description: "Pull downwards (negative: upwards)." },
10745
- life: { type: "number", minimum: 0, maximum: 1, description: "Flow particles: how long they live." },
10746
- interval: { type: "number", minimum: 0, maximum: 1, description: "Sequence: spacing of the beads." },
10747
- ribbonFill: { type: "number", minimum: 0, maximum: 1, description: "Ribbon: opacity of the fill between the paths, relative to their edges (default 0.5; 0 draws only the edges)." },
10748
- ribbonPairs: { type: "string", enum: [..._chunkHS6QDWDFcjs.RIBBON_PAIRS], description: "Ribbon: adjacent (default) joins each particle to its neighbour around the pen; first-last makes one band between the outermost two." },
10749
- waveAmplitude: { type: "number", minimum: 0, maximum: 1, description: "Wave: how far each particle's drawn place swings sideways to the stroke, as a fraction of the tip size (default 0: no wave). Works with every kind and render." },
10750
- waveLength: { type: "number", minimum: 4, maximum: 2e3, description: "Wave: wavelength in px of pen travel (default 60)." },
10751
- waveSpeed: { type: "number", minimum: 0, maximum: 1, description: "Wave: how fast the waves run, by stroke time (0 default: they stand still on the path; 1: about four a second, so slow strokes wave more). Strokes without times run at a nominal 0.5 px/ms." },
10752
- wavePhaseJitter: { type: "number", minimum: 0, maximum: 1, description: "Wave: how far out of step the particles' waves are (default 0: all in step, a wavy band; 1: random phases, tangled strands)." },
10753
- dotTextures: {
10754
- type: "array",
10755
- maxItems: _chunkHS6QDWDFcjs.MAX_DOT_TEXTURES,
10756
- items: { type: "string", enum: [..._chunkJSDND7DFcjs.STAMP_KINDS], description: "A stamp." },
10757
- description: `Dot and sequence renders: up to ${_chunkHS6QDWDFcjs.MAX_DOT_TEXTURES} sticker stamps (list_stickers) drawn instead of round marks; repeats are allowed (they weight the order). Empty (default): round marks.`
10758
- },
10759
- dotTextureOrder: { type: "string", enum: [..._chunkHS6QDWDFcjs.DOT_TEXTURE_ORDERS], description: "Textured dots: sequence (default) uses the stamps in turn; random picks one per dot (seeded, so replays are exact)." },
10760
- dotRotation: { type: "string", enum: [..._chunkHS6QDWDFcjs.DOT_ROTATIONS], description: "Textured dots: follow turns each with its particle's motion; random (default) turns each at random; fixed uses the tip angle." }
10761
- },
10762
- additionalProperties: false
10763
- };
10764
- var BRISTLE_BRUSH = {
10765
- type: "object",
10766
- description: "Bristle engine settings: a tuft of bristles, each its own line. Missing fields keep their current values.",
10767
- properties: {
10768
- count: { type: "integer", minimum: 3, maximum: 128, description: "Bristles in the tuft." },
10769
- stiffness: { type: "number", minimum: 0, maximum: 1, description: "Stiff bristles follow the tip; soft ones lag and bend into curves at turns." },
10770
- splay: { type: "number", minimum: 0, maximum: 1, description: "How far pressure spreads the tuft." },
10771
- thickness: { type: "number", minimum: 0, maximum: 1, description: "Each bristle's line width as a fraction of the tip size." },
10772
- load: { type: "number", minimum: 0, maximum: 1, description: "Paint per bristle: 1 never runs dry; lower, bristles run out along the stroke (dry brush)." },
10773
- jitter: { type: "number", minimum: 0, maximum: 1, description: "Random variation between bristles." }
10774
- },
10775
- additionalProperties: false
10776
- };
10777
- var STICKER_BRUSH = {
10778
- type: "object",
10779
- description: "Sticker engine settings: stamps sprayed along the stroke as editable stickers. Missing fields keep their current values.",
10780
- properties: {
10781
- stamps: {
10782
- type: "array",
10783
- minItems: 1,
10784
- maxItems: _chunkHS6QDWDFcjs.MAX_STICKER_STAMPS,
10785
- items: { type: "string", minLength: 1, description: "A sticker ref provider:id from find_stickers (e.g. editor:star); a bare editor stamp (star) means editor:star." },
10786
- description: `The stickers to spray, one picked at random per sticker: refs from find_stickers (the editor's own: ${_chunkJSDND7DFcjs.STAMP_KINDS.map((k) => `editor:${k}`).join(", ")}). Each is checked against the sticker library and an unknown ref is refused with the closest ones. A provider's sticker is drawn from its art (tinted to the paint colour when tintable), loaded before the stroke.`
10787
- },
10788
- density: { type: "number", minimum: 0, maximum: 1, description: "How closely stickers follow each other: about density \xD7 4 stickers per tip diameter of travel (0.25 \u2248 one per diameter, 1 \u2248 four). Default 0.4." },
10789
- sizeJitter: { type: "number", minimum: 0, maximum: 1, description: "Random size change." },
10790
- rotationJitter: { type: "number", minimum: 0, maximum: 1, description: "Random turn as a fraction of \xB1180\xB0." },
10791
- scatter: { type: "number", minimum: 0, maximum: 2, description: "How far from the path stickers land, in tip diameters." },
10792
- colorJitter: { type: "number", minimum: 0, maximum: 1, description: "Random colour change around the paint colour: at 1, up to \xB140\xB0 of hue and \xB10.15 OKLab lightness, kept in gamut. Default 0.2." }
10793
- },
10794
- additionalProperties: false
10795
- };
10796
- var BRUSH_FIELDS = {
10797
- name: { type: "string", minLength: 1, maxLength: 80, description: "Display name." },
10798
- category: { type: "string", enum: [..._chunkHS6QDWDFcjs.PAINT_BRUSH_CATEGORIES], description: "Library category." },
10799
- engine: {
10800
- type: "string",
10801
- enum: [..._chunkHS6QDWDFcjs.PAINT_BRUSH_ENGINES],
10802
- description: "dab: paints dabs (with behavior.pickup or gradient paint it paints dab by dab, lifting and mixing paint); eraser: removes paint; mixer: the Mixer Brush (a reservoir plus picked-up paint); blender: mixes the colours under and near the tip; smudge: drags paint along the stroke; wet: watercolour, gouache, oil and the wet tools on a simulated wet layer (see wet); impasto: thick paint with relief (see impasto); particle: procedural particle brushes (see particle); bristle: a tuft of bristles that bend and splay (see bristle); sticker: sprays editable sticker stamps (see sticker)."
10803
- },
10804
- tip: TIP,
10805
- grain: { type: "number", minimum: 0, maximum: 1, description: "Paper grain response: 0 ignores the grain, 1 catches only its peaks at light pressure (pencil, pastel, charcoal). Multiplied by the paper depth." },
10806
- pressureSmoothing: { type: "number", minimum: 0, maximum: 0.95, description: "Pressure smoothing, separate from the tip position smoothing." },
10807
- rotation: { type: "string", enum: [..._chunkHS6QDWDFcjs.BRUSH_ROTATIONS], description: "What turns the tip: fixed (tip.angle), stroke (follows the direction of travel) or barrel (the pen barrel rotation, twist)." },
10808
- dynamics: DYNAMICS,
10809
- mixer: MIXER,
10810
- loadsColor: { type: "boolean", description: "Mixer engine: load the colour each stroke (false for a mixer that only moves paint)." },
10811
- behavior: BEHAVIOR,
10812
- blender: BLENDER,
10813
- smudge: SMUDGE,
10814
- wet: WET_BRUSH,
10815
- impasto: IMPASTO_BRUSH,
10816
- particle: PARTICLE_BRUSH,
10817
- bristle: BRISTLE_BRUSH,
10818
- sticker: STICKER_BRUSH,
10819
- light: LIGHT_BRUSH,
10820
- paint: BRUSH_PAINT
10821
- };
10822
10765
  var TIME = { type: "number", minimum: 0, description: "Draw live effect paint (strokes on stroke layers painted with live effect paint) this many ms into its animation (default: as painted, its own time)." };
10823
10766
  var POINTS = {
10824
10767
  type: "array",
@@ -10846,26 +10789,6 @@ function loadResult(load) {
10846
10789
  const hex = (c) => c ? "#" + c.map((v) => Math.round(Math.min(1, Math.max(0, v)) * 255).toString(16).padStart(2, "0")).join("") : null;
10847
10790
  return { reservoir: hex(load.reservoir), amount: Math.round(load.amount * 1e3) / 1e3, pickup: hex(load.pickup) };
10848
10791
  }
10849
- function brushSummary(b) {
10850
- return {
10851
- gradient: b.paint !== null,
10852
- id: b.id,
10853
- name: b.name,
10854
- category: b.category,
10855
- engine: b.engine,
10856
- size: b.tip.size,
10857
- grain: b.grain,
10858
- rotation: b.rotation,
10859
- wetCapable: _chunkHS6QDWDFcjs.isWetCapable.call(void 0, b),
10860
- pickup: b.behavior.pickup,
10861
- dirty: b.behavior.dirty,
10862
- multicolor: b.behavior.multicolor.mode,
10863
- ...b.engine === "wet" ? { wetTool: b.wet.tool, medium: b.wet.medium } : {},
10864
- ...b.engine === "impasto" ? { impastoTool: b.impasto.tool } : {},
10865
- ...b.light.amount > 0 ? { light: b.light.amount } : {},
10866
- builtin: Boolean(b.builtin)
10867
- };
10868
- }
10869
10792
  function createPaintEditorToolProvider(controller, options = {}) {
10870
10793
  const c = typeof controller === "function" ? lazyController(controller) : controller;
10871
10794
  const tools = [];
@@ -11180,121 +11103,31 @@ function createPaintEditorToolProvider(controller, options = {}) {
11180
11103
  coordinates: { out: ["bounds"] },
11181
11104
  handler: ({ layerId }) => c.clearLayer(layerId)
11182
11105
  });
11183
- add({
11184
- name: "list_brushes",
11185
- title: "List brushes",
11186
- description: "Lists the brush library: built-in dry media (pencils, pastels, charcoal, airbrush, marker, ink, erasers), paint brushes (dirty round, multi-colour flat, palette dabber), blending tools (blender, smudge, pigment smudge, Mixer Brush), light paint (category light: glow gel, neon marker, light airbrush, spark trail, light ribbon, flame ribbon, neon strand, smoke ribbon, bokeh dots, twinkle sparks, glow wash, highlighter; light is the amount they lay) and saved user brushes, with id, name, category, engine, size, grain response, rotation mode, whether it can pick up paint (wetCapable), its pick-up ratio, dirty and multi-colour mode, plus the active brush id.",
11187
- inputSchema: EMPTY3,
11188
- annotations: { title: "List brushes", ...READ6 },
11189
- handler: () => {
11190
- const s = c.getState();
11191
- return { activeBrushId: s.brush.id, activeEdited: !s.brush.builtin && Boolean(_optionalChain([c, 'access', _517 => _517.getBrush, 'call', _518 => _518(s.brush.id), 'optionalAccess', _519 => _519.builtin])), brushes: s.brushes.map(brushSummary) };
11192
- }
11193
- });
11194
11106
  add({
11195
11107
  name: "get_brush",
11196
11108
  title: "Get a brush",
11197
- description: "Reads every setting of a brush (tip, grain, pressure smoothing, rotation, dynamics, mixer, behavior: pick-up / mix / dirty, blender, smudge, its own gradient paint as paint, null when it paints the editor's paint). Without id, the active brush as edited. Also returns strokePaint: what a stroke with it would paint now (its gradient, else the editor's paint from set_paint).",
11198
- inputSchema: { type: "object", properties: { id: { type: "string", description: "Brush id from list_brushes (default the active brush)." } }, additionalProperties: false },
11109
+ description: "Reads a brush as facets (kind, medium, variety or tool, tip, marks, dynamics, behaviour, light, motion, colour: the brush library's form, as describe_brush returns it), with the engine it paints with and whether it is an unchanged built-in preset. Without id, the active brush as edited. Also returns strokePaint: what a stroke with it would paint now (its gradient colour, else the editor's paint from set_paint). Changes nothing.",
11110
+ inputSchema: { type: "object", properties: { id: { type: "string", description: "Brush id from list_brush_presets (default the active brush)." } }, additionalProperties: false },
11199
11111
  annotations: { title: "Get a brush", ...READ6 },
11200
11112
  handler: ({ id }) => {
11201
11113
  const st = c.getState();
11202
- if (id === void 0) return { ..._chunkHS6QDWDFcjs.brushToJSON.call(void 0, st.brush), strokePaint: _nullishCoalesce(st.brush.paint, () => ( st.paint)) };
11203
- const b = c.getBrush(id);
11204
- if (!b) throw new Error(`Unknown brush "${id}". Call list_brushes for the ids.`);
11205
- return { ..._chunkHS6QDWDFcjs.brushToJSON.call(void 0, b), builtin: Boolean(b.builtin), strokePaint: _nullishCoalesce(b.paint, () => ( st.paint)) };
11114
+ const b = id === void 0 ? st.brush : c.getBrush(id);
11115
+ if (!b) c.setBrushFacets({}, id);
11116
+ const brush = b;
11117
+ return { brush: c.getBrushSpec(id), engine: brush.engine, category: brush.category, builtin: Boolean(brush.builtin), strokePaint: _nullishCoalesce(brush.paint, () => ( st.paint)) };
11206
11118
  }
11207
11119
  });
11208
11120
  add({
11209
11121
  name: "set_brush",
11210
11122
  title: "Set the brush",
11211
- description: "Chooses the active brush (id) and / or changes its settings; strokes without a brush use it. Editor state, not an undo step. Changes stay on the active brush until save_brush stores them. Returns the active brush.",
11212
- inputSchema: { type: "object", properties: { id: { type: "string", description: "Brush id from list_brushes to start from." }, ...BRUSH_FIELDS }, additionalProperties: false },
11123
+ description: "Chooses the active brush (id, from list_brush_presets) and / or changes it with facets laid over it (objects merge, lists and values replace, marks of another kind replace the marks; the brush library's create_brush fields); unset removes whole facets first (unset colour drops a brush's own gradient). Strokes without a brush use it. Editor state, not an undo step: the changes stay on the active brush until the library's create_brush or update_brush stores a brush. Returns the active brush as facets, the engine it paints with, and problems (values clamped or dropped).",
11124
+ inputSchema: { type: "object", properties: { id: { type: "string", description: "Brush id from list_brush_presets to start from (default the active brush)." }, name: { type: "string", minLength: 1, maxLength: 80, description: "Display name." }, ..._chunk34KLWUH4cjs.BRUSH_PATCH_PROPERTIES, unset: _chunk34KLWUH4cjs.BRUSH_UNSET_PROPERTY }, additionalProperties: false },
11213
11125
  annotations: { title: "Set the brush", ...SET4 },
11214
- handler: async (a) => {
11215
- const stamps = _optionalChain([a, 'access', _520 => _520.sticker, 'optionalAccess', _521 => _521.stamps]);
11126
+ handler: async ({ id, unset, ...patch }) => {
11127
+ const stamps = _optionalChain([patch, 'access', _542 => _542.tip, 'optionalAccess', _543 => _543.stamps]);
11216
11128
  if (stamps) await c.prepareStickers(stamps);
11217
- return _chunkHS6QDWDFcjs.brushToJSON.call(void 0, c.setBrush(a));
11218
- }
11219
- });
11220
- add({
11221
- name: "save_brush",
11222
- title: "Save a brush",
11223
- description: "Saves the active brush (with its changes) into the user library under a new or existing user id. Built-in ids are refused. Library state, not an undo step. Returns the saved brush.",
11224
- inputSchema: {
11225
- type: "object",
11226
- properties: {
11227
- id: { type: "string", pattern: "^[a-z0-9][a-z0-9-]{0,63}$", description: "Library id: lowercase letters, digits and dashes." },
11228
- name: { type: "string", minLength: 1, maxLength: 80, description: "Display name (default the brush name)." }
11229
- },
11230
- required: ["id"],
11231
- additionalProperties: false
11232
- },
11233
- annotations: { title: "Save a brush", ...SET4 },
11234
- handler: ({ id, name }) => _chunkHS6QDWDFcjs.brushToJSON.call(void 0, c.saveBrush({ id, name }))
11235
- });
11236
- add({
11237
- name: "remove_brush",
11238
- title: "Remove a saved brush",
11239
- description: "Removes a user brush from the library (built-in brushes cannot be removed). Library state, not an undo step. Returns the removed id.",
11240
- inputSchema: { type: "object", properties: { id: { type: "string", description: "User brush id from list_brushes." } }, required: ["id"], additionalProperties: false },
11241
- annotations: { title: "Remove a saved brush", ...DESTRUCTIVE3 },
11242
- handler: ({ id }) => {
11243
- c.removeBrush(id);
11244
- return { removed: id };
11245
- }
11246
- });
11247
- add({
11248
- name: "export_brushes",
11249
- title: "Export brushes",
11250
- description: "Returns a brush library file (JSON: format pixerate-brushes, version 1, brushes) of the given brushes, or of every user brush. Changes nothing.",
11251
- inputSchema: {
11252
- type: "object",
11253
- properties: { ids: { type: "array", items: { type: "string", description: "Brush id." }, description: "Brush ids from list_brushes (default every user brush)." } },
11254
- additionalProperties: false
11255
- },
11256
- annotations: { title: "Export brushes", ...READ6 },
11257
- handler: ({ ids }) => c.exportBrushes(ids)
11258
- });
11259
- add({
11260
- name: "import_brushes",
11261
- title: "Import brushes",
11262
- description: "Adds the brushes of a brush library file (as export_brushes returns) to the user library. Taken ids are skipped unless replace is true; built-in ids are always skipped. Library state, not an undo step. Returns the ids added and skipped and any problems.",
11263
- inputSchema: {
11264
- type: "object",
11265
- properties: {
11266
- library: { type: "object", description: 'The library file: {format: "pixerate-brushes", version: 1, brushes: [...]}.' },
11267
- replace: { type: "boolean", description: "Replace user brushes with the same id (default false)." }
11268
- },
11269
- required: ["library"],
11270
- additionalProperties: false
11271
- },
11272
- annotations: { title: "Import brushes", ...WRITE5 },
11273
- handler: ({ library, replace }) => c.importBrushes(library, { replace })
11274
- });
11275
- add({
11276
- name: "render_brush_thumbnail",
11277
- title: "Render a brush thumbnail",
11278
- description: "Renders a brush as a PNG: a test stroke (an S-curve swelling and fading in pressure) on the current paper, so you can see what it does before painting. Changes nothing.",
11279
- inputSchema: {
11280
- type: "object",
11281
- properties: {
11282
- id: { type: "string", description: "Brush id from list_brushes (default the active brush)." },
11283
- width: { type: "integer", minimum: 16, maximum: 512, description: "Width in pixels (default 160)." },
11284
- height: { type: "integer", minimum: 16, maximum: 512, description: "Height in pixels (default 48)." },
11285
- color: { ...COLOR3, description: "Stroke colour (default the paint colour)." }
11286
- },
11287
- additionalProperties: false
11288
- },
11289
- annotations: { title: "Render a brush thumbnail", ...READ6 },
11290
- handler: ({ id, width, height, color }) => {
11291
- const t = c.brushThumbnail(_nullishCoalesce(id, () => ( c.getState().brush.id)), { width, height, color });
11292
- return {
11293
- content: [
11294
- { type: "image", data: _chunkW5M3J7PVcjs.bytesToBase64.call(void 0, _chunkW5M3J7PVcjs.encodePng.call(void 0, t.width, t.height, t.data)), mimeType: "image/png" },
11295
- { type: "text", text: `Brush ${_nullishCoalesce(id, () => ( c.getState().brush.id))} ${t.width}\xD7${t.height}` }
11296
- ]
11297
- };
11129
+ const r = c.setBrushFacets(patch, id, unset);
11130
+ return { brush: r.spec, engine: r.brush.engine, problems: r.problems };
11298
11131
  }
11299
11132
  });
11300
11133
  add({
@@ -11371,14 +11204,14 @@ function createPaintEditorToolProvider(controller, options = {}) {
11371
11204
  add({
11372
11205
  name: "paint_stroke",
11373
11206
  title: "Paint a brush stroke",
11374
- description: "Paints one stroke through points (document pixels, with optional pressure, time, tilt and barrel rotation) on a pixel layer with a library brush or the active one, optionally changed for this stroke. Grain-responsive brushes follow the paper; the mixer engine (mixer-brush) picks up and mixes paint already on the layer, the blender mixes nearby colours, the smudge drags paint, and dab brushes with behavior.pickup lift and carry paint, and wet brushes (engine wet: watercolour, gouache, add water, dry, blow, wet blend, wet smudge, blot) paint on the layer\u2019s wet layer, where the paint keeps moving until it dries (the result says wet: true while it is; see advance_wet_paint and dry_paint; a dry brush on wet paint dries it first; wet oil brushes blend into the wet oil they meet; with light.amount, as glow-wash has, their light flows with the paint), impasto brushes (engine impasto: impasto brush, paint tube, palette knife, roller, gloop pen, metallic paint) lay thick paint whose relief is lit by set_lighting, particle and bristle brushes draw procedural marks, and sticker brushes spray editable stickers onto an empty or sticker layer (list_stickers). Guide stencils make strokes that start near them follow them; mask stencils keep paint inside them. The symmetry guide adds its mirror copies; with a tracing image that samples colours, a stroke without color takes the image colour at its first point. With an agent cursor (a director), the stroke is painted live along the points at the pace of their times. One undo step. Returns the layer id, changed bounds, dab count, the recorded strokeId (for replay_strokes), for wet brushes wet (paint still wet) and, for brushes that pick up paint, mixerLoad: what the brush carries after the stroke.",
11207
+ description: "Paints one stroke through points (document pixels, with optional pressure, time, tilt and barrel rotation) on a pixel layer of the canvas with a library brush or the active one, optionally changed (by facets) for this stroke. Grain-responsive brushes follow the paper; the mixer engine (mixer-brush) picks up and mixes paint already on the layer, the blender mixes nearby colours, the smudge drags paint, and dab brushes with behavior.pickup lift and carry paint, and wet brushes (engine wet: watercolour, gouache, add water, dry, blow, wet blend, wet smudge, blot) paint on the layer\u2019s wet layer, where the paint keeps moving until it dries (the result says wet: true while it is; see advance_wet_paint and dry_paint; a dry brush on wet paint dries it first; wet oil brushes blend into the wet oil they meet; with light.amount, as glow-wash has, their light flows with the paint), impasto brushes (engine impasto: impasto brush, paint tube, palette knife, roller, gloop pen, metallic paint) lay thick paint whose relief is lit by set_lighting, particle and bristle brushes draw procedural marks, and sticker brushes spray editable stickers onto an empty or sticker layer (list_stickers). Guide stencils make strokes that start near them follow them; mask stencils keep paint inside them. The symmetry guide adds its mirror copies; with a tracing image that samples colours, a stroke without color takes the image colour at its first point. With an agent cursor (a director), the stroke is painted live along the points at the pace of their times. One undo step. Returns the layer id, changed bounds, dab count, the recorded strokeId (for replay_strokes), for wet brushes wet (paint still wet) and, for brushes that pick up paint, mixerLoad: what the brush carries after the stroke.",
11375
11208
  inputSchema: {
11376
11209
  type: "object",
11377
11210
  properties: {
11378
11211
  points: POINTS,
11379
11212
  layerId: LAYER_ID4,
11380
- brushId: { type: "string", description: "Brush id from list_brushes (default the active brush)." },
11381
- brush: { type: "object", description: "Brush changes for this stroke only.", properties: BRUSH_FIELDS, additionalProperties: false },
11213
+ brushId: { type: "string", description: "Brush id from list_brush_presets (default the active brush)." },
11214
+ brush: { type: "object", description: "Facets to change for this stroke only, laid over brushId or the active brush (as set_brush takes them).", properties: _chunk34KLWUH4cjs.BRUSH_PATCH_PROPERTIES, additionalProperties: false },
11382
11215
  color: { ...COLOR3, description: "Paint colour #rrggbb (default the paint colour)." },
11383
11216
  paint: { ..._chunkFQPUF2W2cjs.PAINT_SOURCE_JSON_SCHEMA, description: "What this stroke paints with instead of the editor's paint: a colour, or gradient paint that changes colour as the stroke goes (by distance, pressure, tilt, speed, direction, time, across the tip or at random). Wins over the brush's own gradient." },
11384
11217
  seed: { type: "integer", minimum: 0, description: "Jitter seed (default a new one); the same seed and points give the same marks." },
@@ -11392,9 +11225,9 @@ function createPaintEditorToolProvider(controller, options = {}) {
11392
11225
  handler: async (a) => {
11393
11226
  await c.wetIdle();
11394
11227
  const base = a.brushId ? c.getBrush(a.brushId) : c.getState().brush;
11395
- const over = a.brush;
11396
- if ((_nullishCoalesce(_optionalChain([over, 'optionalAccess', _522 => _522.engine]), () => ( _optionalChain([base, 'optionalAccess', _523 => _523.engine])))) === "sticker") await c.prepareStickers(_nullishCoalesce(_nullishCoalesce(_optionalChain([over, 'optionalAccess', _524 => _524.sticker, 'optionalAccess', _525 => _525.stamps]), () => ( _optionalChain([base, 'optionalAccess', _526 => _526.sticker, 'access', _527 => _527.stamps]))), () => ( [])));
11397
- const stroke = { points: a.points, layerId: a.layerId, brushId: a.brushId, brush: a.brush, color: a.color, paint: a.paint, seed: a.seed, snapToPerspective: a.snapToPerspective };
11228
+ const brush = a.brush ? c.brushChanges(a.brush, a.brushId) : void 0;
11229
+ if ((_nullishCoalesce(_optionalChain([brush, 'optionalAccess', _544 => _544.engine]), () => ( _optionalChain([base, 'optionalAccess', _545 => _545.engine])))) === "sticker") await c.prepareStickers(_nullishCoalesce(_nullishCoalesce(_optionalChain([brush, 'optionalAccess', _546 => _546.sticker, 'optionalAccess', _547 => _547.stamps]), () => ( _optionalChain([base, 'optionalAccess', _548 => _548.sticker, 'access', _549 => _549.stamps]))), () => ( [])));
11230
+ const stroke = { points: a.points, layerId: a.layerId, brushId: a.brushId, brush, color: a.color, paint: a.paint, seed: a.seed, snapToPerspective: a.snapToPerspective };
11398
11231
  const r = await act({ kind: "stroke", stroke }, () => c.paintStroke(stroke));
11399
11232
  return r.mixerLoad ? { ...r, mixerLoad: loadResult(r.mixerLoad) } : r;
11400
11233
  }
@@ -11425,7 +11258,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
11425
11258
  if (ids) {
11426
11259
  for (const id of ids) if (!all.some((s) => s.id === id)) throw new Error(`Unknown stroke "${id}". Call list_strokes without ids for the ids.`);
11427
11260
  }
11428
- return { total: all.length, strokes: picked.map((s) => strokeSummary(s, Boolean(ids), live ? true : liveIds.has(s.id) && _optionalChain([c, 'access', _528 => _528.document, 'access', _529 => _529.liveStrokes, 'optionalAccess', _530 => _530[s.layerId], 'optionalAccess', _531 => _531.includes, 'call', _532 => _532(s)]) === true)) };
11261
+ return { total: all.length, strokes: picked.map((s) => strokeSummary(s, Boolean(ids), live ? true : liveIds.has(s.id) && _optionalChain([c, 'access', _550 => _550.document, 'access', _551 => _551.liveStrokes, 'optionalAccess', _552 => _552[s.layerId], 'optionalAccess', _553 => _553.includes, 'call', _554 => _554(s)]) === true)) };
11429
11262
  }
11430
11263
  });
11431
11264
  add({
@@ -11457,8 +11290,8 @@ function createPaintEditorToolProvider(controller, options = {}) {
11457
11290
  type: "object",
11458
11291
  properties: {
11459
11292
  id: { type: "string", description: "Stroke id from list_strokes {live: true}." },
11460
- brushId: { type: "string", description: "Brush preset id from list_brushes; the stroke keeps its size." },
11461
- brush: { type: "object", properties: BRUSH_FIELDS, additionalProperties: false, description: "Brush settings to change on top of brushId or the stroke\u2019s brush; missing fields keep their values." },
11293
+ brushId: { type: "string", description: "Brush id from list_brush_presets; the stroke keeps its size." },
11294
+ brush: { type: "object", properties: _chunk34KLWUH4cjs.BRUSH_PATCH_PROPERTIES, additionalProperties: false, description: "Facets to change on top of brushId or the stroke\u2019s brush (as set_brush takes them); missing fields keep their values." },
11462
11295
  color: { type: "string", pattern: "^#[0-9a-fA-F]{6}$", description: "New colour #rrggbb (replaces gradient paint)." },
11463
11296
  paint: { anyOf: [_chunkFQPUF2W2cjs.PAINT_SOURCE_JSON_SCHEMA, { type: "null", description: "Back to the stroke\u2019s plain colour." }], description: "A colour or gradient paint for the stroke; null drops its gradient." },
11464
11297
  seed: { type: "integer", minimum: 0, description: "Another jitter seed: particles, scatter and texture fall differently." }
@@ -11470,6 +11303,11 @@ function createPaintEditorToolProvider(controller, options = {}) {
11470
11303
  coordinates: { out: ["bounds", "stroke.bounds"] },
11471
11304
  handler: ({ id, ...update }) => {
11472
11305
  if (!Object.keys(update).length) throw new Error("Pass at least one change: brushId, brush, color, paint or seed.");
11306
+ if (update.brush) {
11307
+ const stroke = Object.values(_nullishCoalesce(c.document.liveStrokes, () => ( {}))).flat().find((s) => s.id === id);
11308
+ if (!stroke) throw new Error(`Unknown stroke "${id}" on a stroke layer. Call list_strokes {live: true} for the ids.`);
11309
+ update.brush = c.brushChanges(update.brush, _nullishCoalesce(update.brushId, () => ( stroke.brush)));
11310
+ }
11473
11311
  const r = c.updateStroke(id, update);
11474
11312
  return { stroke: strokeSummary(r.stroke, false, true), bounds: r.bounds };
11475
11313
  }
@@ -11574,7 +11412,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
11574
11412
  },
11575
11413
  pressureScale: { type: "number", minimum: 0, maximum: 4, description: "Multiply every pressure (default 1)." },
11576
11414
  color: { ...COLOR3, description: "Recolour (default each stroke\u2019s colour)." },
11577
- brushId: { type: "string", description: "Replay with this brush from list_brushes (default each stroke\u2019s brush)." },
11415
+ brushId: { type: "string", description: "Replay with this brush from list_brush_presets (default each stroke\u2019s brush)." },
11578
11416
  layerId: { type: "string", description: "Paint on this layer (default each stroke\u2019s layer)." },
11579
11417
  repeat: { type: "integer", minimum: 1, maximum: 100, description: "How many copies (default 1)." }
11580
11418
  },
@@ -11729,16 +11567,16 @@ function createPaintEditorToolProvider(controller, options = {}) {
11729
11567
  }
11730
11568
  function hostTool({ coordinates, ...tool }, { origin, onChange }) {
11731
11569
  if (!origin && !onChange) return tool;
11732
- const write = !_optionalChain([tool, 'access', _533 => _533.annotations, 'optionalAccess', _534 => _534.readOnlyHint]);
11570
+ const write = !_optionalChain([tool, 'access', _555 => _555.annotations, 'optionalAccess', _556 => _556.readOnlyHint]);
11733
11571
  const done = (result) => {
11734
- if (write) _optionalChain([onChange, 'optionalCall', _535 => _535({ tool: tool.name })]);
11735
- return origin && _optionalChain([coordinates, 'optionalAccess', _536 => _536.out]) ? fromDocument(result, coordinates.out, origin) : result;
11572
+ if (write) _optionalChain([onChange, 'optionalCall', _557 => _557({ tool: tool.name })]);
11573
+ return origin && _optionalChain([coordinates, 'optionalAccess', _558 => _558.out]) ? fromDocument(result, coordinates.out, origin) : result;
11736
11574
  };
11737
11575
  return {
11738
11576
  ...tool,
11739
11577
  ...origin ? { description: hostedText(_nullishCoalesce(tool.description, () => ( ""))), inputSchema: hostedSchema(tool.inputSchema) } : {},
11740
11578
  handler: (args, context) => {
11741
- const r = tool.handler(origin && _optionalChain([coordinates, 'optionalAccess', _537 => _537.in]) ? toDocument(args, coordinates.in, origin) : args, context);
11579
+ const r = tool.handler(origin && _optionalChain([coordinates, 'optionalAccess', _559 => _559.in]) ? toDocument(args, coordinates.in, origin) : args, context);
11742
11580
  return r instanceof Promise ? r.then(done) : done(r);
11743
11581
  }
11744
11582
  };
@@ -11755,12 +11593,24 @@ function strokeSummary(s, withPoints, live) {
11755
11593
  color: s.color,
11756
11594
  points: withPoints ? s.points : s.points.length,
11757
11595
  seed: s.seed,
11758
- copies: _nullishCoalesce(_optionalChain([s, 'access', _538 => _538.copies, 'optionalAccess', _539 => _539.length]), () => ( 0)),
11596
+ copies: _nullishCoalesce(_optionalChain([s, 'access', _560 => _560.copies, 'optionalAccess', _561 => _561.length]), () => ( 0)),
11759
11597
  live,
11760
11598
  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) }
11761
11599
  };
11762
11600
  }
11763
11601
 
11602
+ // src/paint-editor/brush-library-tools.ts
11603
+ function createPaintBrushLibraryToolProvider(controller, options = {}) {
11604
+ return _chunk34KLWUH4cjs.createBrushLibraryToolProvider.call(void 0, controller.brushLibrary, {
11605
+ profile: _chunk34KLWUH4cjs.PAINT_PROFILE,
11606
+ ...options,
11607
+ renderPreview: (brush, { width, height, color }) => {
11608
+ const t = renderBrushThumbnail(_chunk34KLWUH4cjs.resolveBrush.call(void 0, brush), { paper: controller.getState().document.paper, width, height, color: color.toLowerCase() });
11609
+ return { data: _chunkW5M3J7PVcjs.bytesToBase64.call(void 0, _chunkW5M3J7PVcjs.encodePng.call(void 0, t.width, t.height, t.data)), mimeType: "image/png" };
11610
+ }
11611
+ });
11612
+ }
11613
+
11764
11614
  // src/paint-editor/ui.ts
11765
11615
  var PAINT_TOOLS = [
11766
11616
  { id: "brush", label: "Brush", key: "b" },
@@ -11771,20 +11621,20 @@ var PAINT_TOOLS = [
11771
11621
  { id: "rotate", label: "Rotate view", key: "r" }
11772
11622
  ];
11773
11623
  var PaintGesture = (_class20 = class {
11774
- constructor(controller, box) {;_class20.prototype.__init174.call(this);_class20.prototype.__init175.call(this);_class20.prototype.__init176.call(this);_class20.prototype.__init177.call(this);_class20.prototype.__init178.call(this);_class20.prototype.__init179.call(this);
11624
+ constructor(controller, box) {;_class20.prototype.__init176.call(this);_class20.prototype.__init177.call(this);_class20.prototype.__init178.call(this);_class20.prototype.__init179.call(this);_class20.prototype.__init180.call(this);_class20.prototype.__init181.call(this);
11775
11625
  this.controller = controller;
11776
11626
  this.box = box;
11777
11627
  }
11778
11628
 
11779
11629
 
11780
- __init174() {this.tool = "brush"}
11630
+ __init176() {this.tool = "brush"}
11781
11631
  /** The last refusal (a hidden or locked layer), for the editor to show. */
11782
- __init175() {this.error = null}
11632
+ __init177() {this.error = null}
11783
11633
  /** The predicted tail of the current stroke in document pixels (draw it as a thin preview). */
11784
- __init176() {this.predicted = []}
11785
- __init177() {this.mode = null}
11786
- __init178() {this.penAt = null}
11787
- __init179() {this.penDown = false}
11634
+ __init178() {this.predicted = []}
11635
+ __init179() {this.mode = null}
11636
+ __init180() {this.penAt = null}
11637
+ __init181() {this.penDown = false}
11788
11638
  doc(e) {
11789
11639
  const b = this.box();
11790
11640
  const s = this.controller.getState();
@@ -11840,13 +11690,13 @@ var PaintGesture = (_class20 = class {
11840
11690
  const p = this.doc(e);
11841
11691
  const s = this.controller.getState();
11842
11692
  const layerId = s.document.activeLayerId;
11843
- if (!layerId || !_optionalChain([s, 'access', _540 => _540.document, 'access', _541 => _541.liveStrokes, 'optionalAccess', _542 => _542[layerId]])) {
11693
+ if (!layerId || !_optionalChain([s, 'access', _562 => _562.document, 'access', _563 => _563.liveStrokes, 'optionalAccess', _564 => _564[layerId]])) {
11844
11694
  this.error = "Pick a stroke layer in the Layers panel (or add one) to select its strokes.";
11845
11695
  return false;
11846
11696
  }
11847
11697
  try {
11848
11698
  const hit = this.controller.liveStrokeAt(layerId, p.x, p.y);
11849
- this.controller.selectStroke(_nullishCoalesce(_optionalChain([hit, 'optionalAccess', _543 => _543.id]), () => ( null)));
11699
+ this.controller.selectStroke(_nullishCoalesce(_optionalChain([hit, 'optionalAccess', _565 => _565.id]), () => ( null)));
11850
11700
  if (!hit) return false;
11851
11701
  this.mode = { kind: "move-stroke", pointerId: e.pointerId, id: hit.id, from: p, to: p };
11852
11702
  return true;
@@ -11858,7 +11708,7 @@ var PaintGesture = (_class20 = class {
11858
11708
  /** While a stroke is dragged: how far it has moved (document pixels), to draw its outline there. */
11859
11709
  get strokeDrag() {
11860
11710
  const m = this.mode;
11861
- return _optionalChain([m, 'optionalAccess', _544 => _544.kind]) === "move-stroke" ? { id: m.id, dx: m.to.x - m.from.x, dy: m.to.y - m.from.y } : null;
11711
+ return _optionalChain([m, 'optionalAccess', _566 => _566.kind]) === "move-stroke" ? { id: m.id, dx: m.to.x - m.from.x, dy: m.to.y - m.from.y } : null;
11862
11712
  }
11863
11713
  /**
11864
11714
  * The Stickers tool: pressing a sticker picks it and dragging moves it (one undo step at the
@@ -11932,7 +11782,7 @@ var PaintGesture = (_class20 = class {
11932
11782
  if (!m || m.pointerId !== e.pointerId) return;
11933
11783
  this.mode = null;
11934
11784
  this.predicted = [];
11935
- if (m.kind === "stroke") _optionalChain([this, 'access', _545 => _545.controller, 'access', _546 => _546.activeStroke, 'optionalAccess', _547 => _547.end, 'call', _548 => _548()]);
11785
+ if (m.kind === "stroke") _optionalChain([this, 'access', _567 => _567.controller, 'access', _568 => _568.activeStroke, 'optionalAccess', _569 => _569.end, 'call', _570 => _570()]);
11936
11786
  if (m.kind === "move-stroke") {
11937
11787
  const dx = Math.round((this.doc(e).x - m.from.x) * 100) / 100;
11938
11788
  const dy = Math.round((this.doc(e).y - m.from.y) * 100) / 100;
@@ -11956,8 +11806,8 @@ var PaintGesture = (_class20 = class {
11956
11806
  cancel() {
11957
11807
  this.penDown = false;
11958
11808
  this.predicted = [];
11959
- if (_optionalChain([this, 'access', _549 => _549.mode, 'optionalAccess', _550 => _550.kind]) === "stroke") _optionalChain([this, 'access', _551 => _551.controller, 'access', _552 => _552.activeStroke, 'optionalAccess', _553 => _553.cancel, 'call', _554 => _554()]);
11960
- if (_optionalChain([this, 'access', _555 => _555.mode, 'optionalAccess', _556 => _556.kind]) === "sticker") this.controller.cancelStickerPreview();
11809
+ if (_optionalChain([this, 'access', _571 => _571.mode, 'optionalAccess', _572 => _572.kind]) === "stroke") _optionalChain([this, 'access', _573 => _573.controller, 'access', _574 => _574.activeStroke, 'optionalAccess', _575 => _575.cancel, 'call', _576 => _576()]);
11810
+ if (_optionalChain([this, 'access', _577 => _577.mode, 'optionalAccess', _578 => _578.kind]) === "sticker") this.controller.cancelStickerPreview();
11961
11811
  this.mode = null;
11962
11812
  }
11963
11813
  get active() {
@@ -12019,13 +11869,13 @@ function handlePaintShortcut(controller, gesture, e) {
12019
11869
  return false;
12020
11870
  }
12021
11871
  var PaintCanvasPresenter = (_class21 = class {
12022
- constructor(controller) {;_class21.prototype.__init180.call(this);_class21.prototype.__init181.call(this);_class21.prototype.__init182.call(this);
11872
+ constructor(controller) {;_class21.prototype.__init182.call(this);_class21.prototype.__init183.call(this);_class21.prototype.__init184.call(this);
12023
11873
  this.controller = controller;
12024
11874
  }
12025
11875
 
12026
- __init180() {this.uploaded = /* @__PURE__ */ new Map()}
12027
- __init181() {this.scratch = null}
12028
- __init182() {this.size = ""}
11876
+ __init182() {this.uploaded = /* @__PURE__ */ new Map()}
11877
+ __init183() {this.scratch = null}
11878
+ __init184() {this.size = ""}
12029
11879
  /** Draws what changed into `ctx` (a canvas the size of the document); returns the tiles drawn. */
12030
11880
  render(ctx) {
12031
11881
  const { width, height } = this.controller.document.canvas;
@@ -12057,7 +11907,7 @@ function guideOverlay(controller, drag) {
12057
11907
  const size = s.document.canvas;
12058
11908
  const out = [];
12059
11909
  const layerId = s.document.activeLayerId;
12060
- const strokePicked = layerId && s.selectedStroke ? _optionalChain([s, 'access', _557 => _557.document, 'access', _558 => _558.liveStrokes, 'optionalAccess', _559 => _559[layerId], 'optionalAccess', _560 => _560.some, 'call', _561 => _561((x) => x.id === s.selectedStroke)]) : false;
11910
+ const strokePicked = layerId && s.selectedStroke ? _optionalChain([s, 'access', _579 => _579.document, 'access', _580 => _580.liveStrokes, 'optionalAccess', _581 => _581[layerId], 'optionalAccess', _582 => _582.some, 'call', _583 => _583((x) => x.id === s.selectedStroke)]) : false;
12061
11911
  const area = strokePicked ? controller.liveStrokeArea(s.selectedStroke) : null;
12062
11912
  if (area) {
12063
11913
  const dx = drag && drag.id === s.selectedStroke ? drag.dx : 0;
@@ -12070,7 +11920,7 @@ function guideOverlay(controller, drag) {
12070
11920
  ];
12071
11921
  for (let i = 0; i < 4; i++) out.push({ from: box[i], to: box[(i + 1) % 4], kind: "stroke" });
12072
11922
  }
12073
- const picked = layerId && s.selectedSticker ? _optionalChain([s, 'access', _562 => _562.document, 'access', _563 => _563.stickers, 'optionalAccess', _564 => _564[layerId], 'optionalAccess', _565 => _565.find, 'call', _566 => _566((x) => x.id === s.selectedSticker)]) : void 0;
11923
+ const picked = layerId && s.selectedSticker ? _optionalChain([s, 'access', _584 => _584.document, 'access', _585 => _585.stickers, 'optionalAccess', _586 => _586[layerId], 'optionalAccess', _587 => _587.find, 'call', _588 => _588((x) => x.id === s.selectedSticker)]) : void 0;
12074
11924
  if (picked) {
12075
11925
  const r = picked.size / 2 + 2;
12076
11926
  const a = picked.rotation * Math.PI / 180;
@@ -12087,21 +11937,6 @@ function guideOverlay(controller, drag) {
12087
11937
  if (s.guides.perspective.enabled) for (const [from, to] of perspectiveGuideLines(s.guides.perspective, size, 16)) out.push({ from, to, kind: "perspective" });
12088
11938
  return out;
12089
11939
  }
12090
- var BRUSH_SLIDERS = [
12091
- { path: "tip.size", label: "Size", min: 1, max: 400, step: 1 },
12092
- { path: "tip.opacity", label: "Opacity", min: 0, max: 1, step: 0.01 },
12093
- { path: "tip.flow", label: "Flow", min: 0, max: 1, step: 0.01 },
12094
- { path: "tip.hardness", label: "Hardness", min: 0, max: 1, step: 0.01 },
12095
- { path: "tip.spacing", label: "Spacing", min: 0.01, max: 1, step: 0.01 },
12096
- { path: "tip.roundness", label: "Roundness", min: 0.05, max: 1, step: 0.01 },
12097
- { path: "tip.angle", label: "Angle", min: -180, max: 180, step: 1 },
12098
- { path: "grain", label: "Grain", min: 0, max: 1, step: 0.01 },
12099
- { path: "tip.smoothing", label: "Smoothing", min: 0, max: 0.95, step: 0.01 },
12100
- { path: "pressureSmoothing", label: "Pressure smoothing", min: 0, max: 0.95, step: 0.01 },
12101
- { path: "dynamics.minSize", label: "Min size", min: 0, max: 1, step: 0.01 },
12102
- { path: "dynamics.tiltSize", label: "Tilt size", min: 0, max: 1, step: 0.01 },
12103
- { path: "dynamics.velocitySize", label: "Speed size", min: -1, max: 1, step: 0.01 }
12104
- ];
12105
11940
  var PAPER_SLIDERS = [
12106
11941
  { path: "depth", label: "Grain depth", min: 0, max: 1, step: 0.01 },
12107
11942
  { path: "scale", label: "Grain scale", min: 0.25, max: 8, step: 0.05 },
@@ -12115,7 +11950,7 @@ var PAPER_SLIDERS = [
12115
11950
  ];
12116
11951
  function readPath(obj, path) {
12117
11952
  let v = obj;
12118
- for (const k of path.split(".")) v = _optionalChain([v, 'optionalAccess', _567 => _567[k]]);
11953
+ for (const k of path.split(".")) v = _optionalChain([v, 'optionalAccess', _589 => _589[k]]);
12119
11954
  return typeof v === "number" ? v : 0;
12120
11955
  }
12121
11956
  function patchPath(obj, path, value) {
@@ -12160,158 +11995,6 @@ var BLEND_MENU_GROUPS = [
12160
11995
  { label: "Standard", modes: _chunk2VX55NFMcjs.BLEND_MODES.filter((m) => !m.painterly && m.id !== "pigment") },
12161
11996
  { label: "Paint", modes: _chunk2VX55NFMcjs.BLEND_MODES.filter((m) => m.painterly || m.id === "pigment") }
12162
11997
  ];
12163
- var LIGHT_SLIDER = { path: "light.amount", label: "Light", min: 0, max: 1, step: 0.01 };
12164
- var PICKUP_SLIDERS = [
12165
- { path: "behavior.pickup", label: "Pick-up", min: 0, max: 1, step: 0.01 },
12166
- { path: "behavior.mix", label: "Mix", min: 0, max: 1, step: 0.01 }
12167
- ];
12168
- function brushEngineControls(brush) {
12169
- const c = engineControls(brush);
12170
- const wetPaint = brush.engine === "wet" && _optionalChain([brush, 'access', _568 => _568.wet, 'optionalAccess', _569 => _569.tool]) === "paint";
12171
- if (!c || !(wetPaint || ["dab", "mixer", "particle", "bristle", "impasto"].includes(brush.engine))) return c;
12172
- const extra = brush.engine === "impasto" ? [{ path: "impasto.rim", label: "Rim", min: 0, max: 1, step: 0.01 }, { path: "impasto.clarity", label: "Clarity", min: 0, max: 1, step: 0.01 }] : [];
12173
- return { ...c, sliders: [...c.sliders, LIGHT_SLIDER, ...extra], light: true };
12174
- }
12175
- function engineControls(brush) {
12176
- switch (brush.engine) {
12177
- case "particle":
12178
- return {
12179
- title: "Particles",
12180
- sliders: [
12181
- { path: "particle.count", label: "Particles", min: 1, max: 64, step: 1 },
12182
- { path: "particle.size", label: "Mark size", min: 0, max: 1, step: 0.01 },
12183
- { path: "particle.spread", label: "Spread", min: 0, max: 1, step: 0.01 },
12184
- { path: "particle.stiffness", label: "Stiffness", min: 0, max: 1, step: 0.01 },
12185
- { path: "particle.damping", label: "Damping", min: 0, max: 1, step: 0.01 },
12186
- { path: "particle.speed", label: "Speed", min: 0, max: 1, step: 0.01 },
12187
- { path: "particle.gravity", label: "Gravity", min: -1, max: 1, step: 0.01 },
12188
- { path: "particle.life", label: "Life", min: 0, max: 1, step: 0.01 },
12189
- { path: "particle.interval", label: "Bead spacing", min: 0, max: 1, step: 0.01 },
12190
- { path: "particle.ribbonFill", label: "Ribbon fill", min: 0, max: 1, step: 0.01 },
12191
- { path: "particle.waveAmplitude", label: "Wave", min: 0, max: 1, step: 0.01 },
12192
- { path: "particle.waveLength", label: "Wavelength", min: 4, max: 400, step: 1 },
12193
- { path: "particle.waveSpeed", label: "Wave speed", min: 0, max: 1, step: 0.01 },
12194
- { path: "particle.wavePhaseJitter", label: "Wave scatter", min: 0, max: 1, step: 0.01 }
12195
- ],
12196
- mixingPath: null,
12197
- dirty: false,
12198
- multicolor: false,
12199
- load: false,
12200
- particleMenus: true
12201
- };
12202
- case "bristle":
12203
- return {
12204
- title: "Bristles",
12205
- sliders: [
12206
- { path: "bristle.count", label: "Bristles", min: 3, max: 128, step: 1 },
12207
- { path: "bristle.stiffness", label: "Stiffness", min: 0, max: 1, step: 0.01 },
12208
- { path: "bristle.splay", label: "Splay", min: 0, max: 1, step: 0.01 },
12209
- { path: "bristle.thickness", label: "Bristle width", min: 0, max: 1, step: 0.01 },
12210
- { path: "bristle.load", label: "Load", min: 0, max: 1, step: 0.01 },
12211
- { path: "bristle.jitter", label: "Variation", min: 0, max: 1, step: 0.01 }
12212
- ],
12213
- mixingPath: null,
12214
- dirty: false,
12215
- multicolor: false,
12216
- load: false
12217
- };
12218
- case "sticker":
12219
- return {
12220
- title: "Stickers",
12221
- sliders: [
12222
- { path: "sticker.density", label: "Density", min: 0, max: 1, step: 0.01 },
12223
- { path: "sticker.sizeJitter", label: "Size jitter", min: 0, max: 1, step: 0.01 },
12224
- { path: "sticker.rotationJitter", label: "Turn jitter", min: 0, max: 1, step: 0.01 },
12225
- { path: "sticker.scatter", label: "Scatter", min: 0, max: 2, step: 0.01 },
12226
- { path: "sticker.colorJitter", label: "Colour jitter", min: 0, max: 1, step: 0.01 }
12227
- ],
12228
- mixingPath: null,
12229
- dirty: false,
12230
- multicolor: false,
12231
- load: false,
12232
- stickerStamps: true
12233
- };
12234
- case "impasto":
12235
- return {
12236
- title: "Thick paint",
12237
- sliders: [
12238
- { path: "impasto.thickness", label: "Thickness", min: 0, max: 1, step: 0.01 },
12239
- { path: "impasto.gloss", label: "Gloss", min: 0, max: 1, step: 0.01 },
12240
- { path: "impasto.metallic", label: "Metallic", min: 0, max: 1, step: 0.01 },
12241
- { path: "impasto.load", label: "Load", min: 0, max: 1, step: 0.01 },
12242
- { path: "impasto.thinner", label: "Thinner", min: 0, max: 1, step: 0.01 },
12243
- { path: "impasto.drag", label: "Drag", min: 0, max: 1, step: 0.01 },
12244
- ...PICKUP_SLIDERS
12245
- ],
12246
- mixingPath: "behavior.mixing",
12247
- dirty: true,
12248
- multicolor: false,
12249
- load: true,
12250
- impastoTool: true
12251
- };
12252
- case "wet": {
12253
- const tool = _nullishCoalesce(_optionalChain([brush, 'access', _570 => _570.wet, 'optionalAccess', _571 => _571.tool]), () => ( "paint"));
12254
- const sliders = tool === "paint" ? [
12255
- { path: "wet.water", label: "Water", min: 0, max: 1, step: 0.01 },
12256
- { path: "wet.pigment", label: "Pigment", min: 0, max: 1, step: 0.01 },
12257
- { path: "wet.body", label: "Body (opacity)", min: 0, max: 1, step: 0.01 },
12258
- { path: "wet.rewet", label: "Re-wet", min: 0, max: 1, step: 0.01 },
12259
- { path: "wet.load", label: "Load", min: 0, max: 1, step: 0.01 },
12260
- { path: "wet.thinner", label: "Thinner", min: 0, max: 1, step: 0.01 },
12261
- ...PICKUP_SLIDERS
12262
- ] : tool === "water" ? [
12263
- { path: "wet.water", label: "Water", min: 0, max: 1, step: 0.01 },
12264
- { path: "wet.rewet", label: "Re-wet", min: 0, max: 1, step: 0.01 }
12265
- ] : [{ path: "wet.strength", label: "Strength", min: 0, max: 1, step: 0.01 }];
12266
- return { title: "Wet brush", sliders, mixingPath: tool === "paint" ? "behavior.mixing" : null, dirty: tool === "paint", multicolor: false, load: tool === "paint", wetTool: true };
12267
- }
12268
- case "blender":
12269
- return {
12270
- title: "Blender",
12271
- sliders: [
12272
- { path: "blender.strength", label: "Strength", min: 0, max: 1, step: 0.01 },
12273
- { path: "blender.distance", label: "Blend distance", min: 0, max: 1, step: 0.01 }
12274
- ],
12275
- mixingPath: "blender.mixing",
12276
- dirty: false,
12277
- multicolor: false,
12278
- load: false
12279
- };
12280
- case "smudge":
12281
- return {
12282
- title: "Smudge",
12283
- sliders: [
12284
- { path: "smudge.strength", label: "Strength", min: 0, max: 1, step: 0.01 },
12285
- { path: "smudge.length", label: "Length", min: 0, max: 1, step: 0.01 }
12286
- ],
12287
- mixingPath: "smudge.mixing",
12288
- dirty: false,
12289
- multicolor: false,
12290
- load: false
12291
- };
12292
- case "mixer":
12293
- return { title: "Mixer Brush", sliders: [...PICKUP_SLIDERS, { path: "mixer.load", label: "Load", min: 0, max: 1, step: 0.01 }], mixingPath: "behavior.mixing", dirty: true, multicolor: true, load: true };
12294
- case "dab":
12295
- return { title: "Paint behaviour", sliders: PICKUP_SLIDERS, mixingPath: "behavior.mixing", dirty: true, multicolor: true, load: true };
12296
- default:
12297
- return null;
12298
- }
12299
- }
12300
- function multiColorSliders(mode) {
12301
- if (mode === "off") return [];
12302
- const soft = { path: "behavior.multicolor.softness", label: "Colour softness", min: 0, max: 1, step: 0.01 };
12303
- return mode === "dab" ? [soft, { path: "behavior.multicolor.length", label: "Dabs per colour", min: 1, max: 100, step: 1 }] : [soft];
12304
- }
12305
- function patchBrushValue(brush, path, value) {
12306
- const set = (obj, keys) => {
12307
- const [head2, ...rest2] = keys;
12308
- if (!rest2.length) return { ...obj, [head2]: value };
12309
- return { ...obj, [head2]: set(_nullishCoalesce(obj[head2], () => ( {})), rest2) };
12310
- };
12311
- const [head, ...rest] = path.split(".");
12312
- if (!rest.length) return { [head]: value };
12313
- return { [head]: set({ ..._nullishCoalesce(brush[head], () => ( {})) }, rest) };
12314
- }
12315
11998
  function brushLoadColor(load) {
12316
11999
  const c = _nullishCoalesce(load.pickup, () => ( load.reservoir));
12317
12000
  return c ? rgbToHexColor(Math.round(c[0] * 255), Math.round(c[1] * 255), Math.round(c[2] * 255)) : null;
@@ -12383,7 +12066,7 @@ function startWetClock(controller, frame, cancel) {
12383
12066
  id = raf(loop);
12384
12067
  return () => {
12385
12068
  stopped = true;
12386
- _optionalChain([caf, 'optionalCall', _572 => _572(id)]);
12069
+ _optionalChain([caf, 'optionalCall', _590 => _590(id)]);
12387
12070
  };
12388
12071
  }
12389
12072
  function drawWaterOverlay(controller, ctx) {
@@ -12498,7 +12181,7 @@ function createPaintEffectsToolProvider(controller, options = {}) {
12498
12181
  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.");
12499
12182
  };
12500
12183
  const values = (v) => v;
12501
- return withPaintPlayback(_chunkISIO63Q5cjs.createEffectToolProvider.call(void 0, {
12184
+ return withPaintPlayback(_chunkL2JTLW6Bcjs.createEffectToolProvider.call(void 0, {
12502
12185
  id: _nullishCoalesce(options.id, () => ( "paint-effects")),
12503
12186
  namespace: options.namespace,
12504
12187
  title: "Paint effects",
@@ -13068,4 +12751,6 @@ function createPaintEditorDocument(controller, options = {}) {
13068
12751
 
13069
12752
 
13070
12753
 
13071
- exports.BACKLIGHT_SPILL = BACKLIGHT_SPILL; exports.BLEND_MENU_GROUPS = BLEND_MENU_GROUPS; exports.BLEND_MODES = _chunk2VX55NFMcjs.BLEND_MODES; exports.BRUSH_ID = _chunkHS6QDWDFcjs.BRUSH_ID; exports.BRUSH_ROTATIONS = _chunkHS6QDWDFcjs.BRUSH_ROTATIONS; exports.BRUSH_SLIDERS = BRUSH_SLIDERS; exports.BUILTIN_BRUSHES = _chunkHS6QDWDFcjs.BUILTIN_BRUSHES; exports.BristleStroke = BristleStroke; exports.DEFAULT_BACKLIGHT_COLOR = DEFAULT_BACKLIGHT_COLOR; exports.DEFAULT_BEHAVIOR = _chunkHS6QDWDFcjs.DEFAULT_BEHAVIOR; exports.DEFAULT_BRISTLE = _chunkHS6QDWDFcjs.DEFAULT_BRISTLE; exports.DEFAULT_BRUSH_ID = _chunkHS6QDWDFcjs.DEFAULT_BRUSH_ID; exports.DEFAULT_DPI = DEFAULT_DPI; exports.DEFAULT_DYNAMICS = _chunkHS6QDWDFcjs.DEFAULT_DYNAMICS; exports.DEFAULT_FLOW = _chunkKBYB7OWBcjs.DEFAULT_FLOW; exports.DEFAULT_IMPASTO = _chunkHS6QDWDFcjs.DEFAULT_IMPASTO; exports.DEFAULT_LIGHT = _chunkHS6QDWDFcjs.DEFAULT_LIGHT; exports.DEFAULT_LIGHTING = DEFAULT_LIGHTING; exports.DEFAULT_MULTI_COLOR = _chunkHS6QDWDFcjs.DEFAULT_MULTI_COLOR; exports.DEFAULT_PAINT_GRADIENT = _chunkFQPUF2W2cjs.DEFAULT_PAINT_GRADIENT; exports.DEFAULT_PAINT_GRADIENT_MAPPING = _chunkFQPUF2W2cjs.DEFAULT_PAINT_GRADIENT_MAPPING; exports.DEFAULT_PAPER = DEFAULT_PAPER; exports.DEFAULT_PARTICLE = _chunkHS6QDWDFcjs.DEFAULT_PARTICLE; exports.DEFAULT_STICKER = _chunkHS6QDWDFcjs.DEFAULT_STICKER; exports.DEFAULT_SWATCHES = DEFAULT_SWATCHES; exports.DEFAULT_VIEW = DEFAULT_VIEW; exports.DEFAULT_WET_BRUSH = _chunkHS6QDWDFcjs.DEFAULT_WET_BRUSH; exports.DEFAULT_WET_PARAMS = _chunkKBYB7OWBcjs.DEFAULT_WET_PARAMS; exports.DOT_ROTATIONS = _chunkHS6QDWDFcjs.DOT_ROTATIONS; exports.DOT_ROTATION_LABELS = DOT_ROTATION_LABELS; exports.DOT_TEXTURE_ORDERS = _chunkHS6QDWDFcjs.DOT_TEXTURE_ORDERS; exports.DOT_TEXTURE_ORDER_LABELS = DOT_TEXTURE_ORDER_LABELS; exports.DryStroke = DryStroke; exports.EFFECT_MAP_REPEATS = EFFECT_MAP_REPEATS; exports.EFFECT_STRIP_HEIGHT = EFFECT_STRIP_HEIGHT; exports.GPU_LEAD = GPU_LEAD; exports.GRAIN_PATTERNS = _chunkPXDIAYB6cjs.GRAIN_PATTERNS; exports.GRAIN_TILE = _chunkPXDIAYB6cjs.GRAIN_TILE; exports.HARMONY_KINDS = _chunkEUIDTZNQcjs.HARMONY_KINDS; exports.IDENTITY_AFFINE = IDENTITY_AFFINE; exports.IDENTITY_COPY = IDENTITY_COPY; exports.IMPASTO_TOOLS = _chunkHS6QDWDFcjs.IMPASTO_TOOLS; exports.IMPASTO_TOOL_LABELS = IMPASTO_TOOL_LABELS; exports.LIGHT_SLIDERS = LIGHT_SLIDERS; exports.LIVE_STROKE_ENGINES = LIVE_STROKE_ENGINES; exports.LitCache = LitCache; exports.MAX_BRUSH_SIZE = _chunkFQPUF2W2cjs.MAX_BRUSH_SIZE; exports.MAX_CANVAS_SIDE = MAX_CANVAS_SIDE; exports.MAX_COORDINATE = MAX_COORDINATE; exports.MAX_DOT_TEXTURES = _chunkHS6QDWDFcjs.MAX_DOT_TEXTURES; exports.MAX_IMAGE_SIDE = MAX_IMAGE_SIDE; exports.MAX_LIVE_EFFECT_SOURCES = MAX_LIVE_EFFECT_SOURCES; exports.MAX_STICKER_STAMPS = _chunkHS6QDWDFcjs.MAX_STICKER_STAMPS; exports.MAX_ZOOM = MAX_ZOOM; exports.MIN_CANVAS_SIDE = MIN_CANVAS_SIDE; exports.MIN_ZOOM = MIN_ZOOM; exports.MIXING_PAD_HEIGHT = MIXING_PAD_HEIGHT; exports.MIXING_PAD_WIDTH = MIXING_PAD_WIDTH; exports.MULTI_COLOR_MODES = _chunkHS6QDWDFcjs.MULTI_COLOR_MODES; exports.MixingPad = MixingPad; exports.PAD_SAMPLE_SIZES = PAD_SAMPLE_SIZES; exports.PAINTERLY_BLEND_MODES = _chunk2VX55NFMcjs.PAINTERLY_BLEND_MODES; exports.PAINT_BRUSH_CATEGORIES = _chunkHS6QDWDFcjs.PAINT_BRUSH_CATEGORIES; exports.PAINT_BRUSH_ENGINES = _chunkHS6QDWDFcjs.PAINT_BRUSH_ENGINES; exports.PAINT_COLOR_JSON_SCHEMA = _chunkFQPUF2W2cjs.PAINT_COLOR_JSON_SCHEMA; exports.PAINT_EFFECT_PLACES = PAINT_EFFECT_PLACES; exports.PAINT_FORMAT = PAINT_FORMAT; exports.PAINT_GRADIENT_FULL_SPEED = _chunkFQPUF2W2cjs.PAINT_GRADIENT_FULL_SPEED; exports.PAINT_GRADIENT_JSON_SCHEMA = _chunkFQPUF2W2cjs.PAINT_GRADIENT_JSON_SCHEMA; exports.PAINT_GRADIENT_KIT = _chunkFQPUF2W2cjs.PAINT_GRADIENT_KIT; exports.PAINT_GRADIENT_MAPPINGS = _chunkFQPUF2W2cjs.PAINT_GRADIENT_MAPPINGS; exports.PAINT_GRADIENT_MAPPING_LABELS = _chunkFQPUF2W2cjs.PAINT_GRADIENT_MAPPING_LABELS; exports.PAINT_GRADIENT_PRESETS = _chunkFQPUF2W2cjs.PAINT_GRADIENT_PRESETS; exports.PAINT_GRADIENT_REPEATS = _chunkFQPUF2W2cjs.PAINT_GRADIENT_REPEATS; exports.PAINT_GRADIENT_REPEAT_LABELS = _chunkFQPUF2W2cjs.PAINT_GRADIENT_REPEAT_LABELS; exports.PAINT_GRADIENT_SPACES = _chunkFQPUF2W2cjs.PAINT_GRADIENT_SPACES; exports.PAINT_GRADIENT_SPACE_LABELS = _chunkFQPUF2W2cjs.PAINT_GRADIENT_SPACE_LABELS; exports.PAINT_SCHEMA_VERSION = PAINT_SCHEMA_VERSION; exports.PAINT_SOURCE_JSON_SCHEMA = _chunkFQPUF2W2cjs.PAINT_SOURCE_JSON_SCHEMA; exports.PAINT_TARGET = PAINT_TARGET; exports.PAINT_TOOLS = PAINT_TOOLS; exports.PAPER_EFFECT_BLENDS = PAPER_EFFECT_BLENDS; exports.PAPER_EFFECT_NODE_ID = PAPER_EFFECT_NODE_ID; exports.PAPER_FAMILIES = PAPER_FAMILIES; exports.PAPER_LIBRARY = PAPER_LIBRARY; exports.PAPER_NODE_ID = PAPER_NODE_ID; exports.PAPER_SLIDERS = PAPER_SLIDERS; exports.PAPER_TARGET = PAPER_TARGET; exports.PARTICLE_KINDS = _chunkHS6QDWDFcjs.PARTICLE_KINDS; exports.PARTICLE_KIND_LABELS = PARTICLE_KIND_LABELS; exports.PARTICLE_RENDERS = _chunkHS6QDWDFcjs.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 = _chunkFQPUF2W2cjs.PaintGradientSampler; exports.PaintPresence = PaintPresence; exports.PaintSourceError = _chunkFQPUF2W2cjs.PaintSourceError; exports.PaintStrokeSession = PaintStrokeSession; exports.PaintWetLayers = PaintWetLayers; exports.PaperGrain = _chunkPXDIAYB6cjs.PaperGrain; exports.ParticleStroke = ParticleStroke; exports.PenDabWalker = PenDabWalker; exports.PenSmoother = PenSmoother; exports.PerspectiveSnapper = PerspectiveSnapper; exports.RIBBON_PAIRS = _chunkHS6QDWDFcjs.RIBBON_PAIRS; exports.RIBBON_PAIR_LABELS = RIBBON_PAIR_LABELS; exports.SNAP_DECIDE_DISTANCE = SNAP_DECIDE_DISTANCE; exports.STAMP_KINDS = _chunkJSDND7DFcjs.STAMP_KINDS; exports.STAMP_LABELS = STAMP_LABELS; exports.STENCIL_KINDS = STENCIL_KINDS; exports.STENCIL_SHAPES = STENCIL_SHAPES; exports.STICKER_ART_SIZE = STICKER_ART_SIZE; exports.STICKER_SLIDERS = STICKER_SLIDERS; exports.STROKE_SLIDERS = STROKE_SLIDERS; exports.SYMMETRY_MODES = SYMMETRY_MODES; exports.StencilSnapper = StencilSnapper; exports.StickerArtCache = StickerArtCache; exports.StickerBrowser = _chunkSABJMH6Mcjs.StickerBrowser; exports.StickerSpray = StickerSpray; exports.TRACING_NODE_ID = TRACING_NODE_ID; exports.ThickStrokeDriver = ThickStrokeDriver; exports.TileableNoise = _chunk3K6HWEXZcjs.TileableNoise; exports.WET_FLOW_KINDS = _chunkKBYB7OWBcjs.WET_FLOW_KINDS; exports.WET_GPU_MODES = WET_GPU_MODES; exports.WET_GPU_OPTIONS = WET_GPU_OPTIONS; exports.WET_MEDIA = _chunkHS6QDWDFcjs.WET_MEDIA; exports.WET_MEDIUM_LABELS = WET_MEDIUM_LABELS; exports.WET_MEDIUM_PARAMS = WET_MEDIUM_PARAMS; exports.WET_PARAM_KEYS = _chunkKBYB7OWBcjs.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 = _chunkHS6QDWDFcjs.WET_TOOLS; exports.WET_TOOL_LABELS = WET_TOOL_LABELS; exports.WetStrokeDriver = WetStrokeDriver; exports.addPaintGradientStop = _chunkFQPUF2W2cjs.addPaintGradientStop; exports.addPolygonArea = addPolygonArea; exports.affineCopy = affineCopy; exports.applyAffine = applyAffine; exports.backlightOf = backlightOf; exports.brushEngineControls = brushEngineControls; exports.brushLoadColor = brushLoadColor; exports.brushLoadForStroke = brushLoadForStroke; exports.brushTakesPaint = _chunkHS6QDWDFcjs.brushTakesPaint; exports.brushToJSON = _chunkHS6QDWDFcjs.brushToJSON; exports.buildTimeLapse = buildTimeLapse; exports.checkPaintEffectPlace = checkPaintEffectPlace; exports.clonePaper = clonePaper; exports.colorHarmony = colorHarmony2; exports.composeAffine = composeAffine; exports.contactSheet = contactSheet; exports.createPaintCompositor = createPaintCompositor; exports.createPaintDocument = createPaintDocument; exports.createPaintEditorDocument = createPaintEditorDocument; exports.createPaintEditorToolProvider = createPaintEditorToolProvider; exports.createPaintEffectsToolProvider = createPaintEffectsToolProvider; exports.createPaintLayer = createPaintLayer; exports.createPaintReplayTools = createPaintReplayTools; exports.createPaintStickerTools = createPaintStickerTools; exports.createPaintThickTools = createPaintThickTools; exports.createPaintWetTools = createPaintWetTools; exports.decodeImageBlob = decodeImageBlob; exports.defaultGuides = defaultGuides; exports.defaultImageEncoder = defaultImageEncoder; exports.defaultStickerRasterizer = defaultStickerRasterizer; exports.deserializePaintDocument = deserializePaintDocument; exports.deserializePaintDocumentAsync = deserializePaintDocumentAsync; exports.documentExtensions = documentExtensions; exports.documentToScreen = documentToScreen; exports.downloadBytes = downloadBytes; exports.downsampleRgba = downsampleRgba; exports.drawSticker = drawSticker; exports.drawWaterOverlay = drawWaterOverlay; exports.effectDabField = effectDabField; exports.effectLayersToJSON = effectLayersToJSON; exports.effectPaintKey = effectPaintKey; exports.effectPaintSize = effectPaintSize; exports.emptiedLayers = emptiedLayers; exports.emptyThickChannels = emptyThickChannels; exports.fitZoom = fitZoom; exports.grainCatch = _chunkPXDIAYB6cjs.grainCatch; exports.grainHeights = _chunkPXDIAYB6cjs.grainHeights; exports.guideOverlay = guideOverlay; exports.handlePaintShortcut = handlePaintShortcut; exports.hash2 = _chunk3K6HWEXZcjs.hash2; exports.hexToPaintRgb = _chunkFQPUF2W2cjs.hexToPaintRgb; exports.hexToRgb8 = hexToRgb8; exports.hslToRgb = hslToRgb; exports.hsvToRgb = hsvToRgb; exports.hueToWheel = _chunkEUIDTZNQcjs.hueToWheel; exports.invertAffine = invertAffine; exports.isBlendMode = _chunk2VX55NFMcjs.isBlendMode; exports.isGradientPaint = _chunkFQPUF2W2cjs.isGradientPaint; exports.isPaintEffectPaint = isPaintEffectPaint; exports.isPainterlyBlendMode = _chunk2VX55NFMcjs.isPainterlyBlendMode; exports.isPalmTouch = isPalmTouch; exports.isWetBrush = _chunkHS6QDWDFcjs.isWetBrush; exports.isWetCapable = _chunkHS6QDWDFcjs.isWetCapable; exports.lightTile = lightTile; exports.lightingKey = lightingKey; exports.liveStrokeBounds = liveStrokeBounds; exports.liveStrokeRefusal = liveStrokeRefusal; exports.mapPenPoint = mapPenPoint; exports.mix32 = _chunk3K6HWEXZcjs.mix32; exports.mixPixels = mixPixels; exports.mixerLoadForStroke = mixerLoadForStroke; exports.mixerTip = mixerTip; exports.multiColorForDab = multiColorForDab; exports.multiColorGradient = multiColorGradient; exports.multiColorPalette = multiColorPalette; exports.multiColorSliders = multiColorSliders; exports.multiColorToPaint = _chunkHS6QDWDFcjs.multiColorToPaint; exports.newPaintLayerId = newPaintLayerId; exports.nextPaperEffectVersion = nextPaperEffectVersion; exports.normalizeBehavior = _chunkHS6QDWDFcjs.normalizeBehavior; exports.normalizeBristle = _chunkHS6QDWDFcjs.normalizeBristle; exports.normalizeBrushStroke = normalizeBrushStroke; exports.normalizeCanvas = normalizeCanvas; exports.normalizeDynamics = _chunkHS6QDWDFcjs.normalizeDynamics; exports.normalizeFlow = _chunkKBYB7OWBcjs.normalizeFlow; exports.normalizeHexColor = _chunkFQPUF2W2cjs.normalizeHexColor; exports.normalizeImpasto = _chunkHS6QDWDFcjs.normalizeImpasto; exports.normalizeLight = _chunkHS6QDWDFcjs.normalizeLight; exports.normalizeLighting = normalizeLighting; exports.normalizeMultiColor = _chunkHS6QDWDFcjs.normalizeMultiColor; exports.normalizePaintBrush = _chunkHS6QDWDFcjs.normalizePaintBrush; exports.normalizePaper = normalizePaper; exports.normalizeParticle = _chunkHS6QDWDFcjs.normalizeParticle; exports.normalizePerspective = normalizePerspective; exports.normalizeRotation = normalizeRotation; exports.normalizeStencil = normalizeStencil; exports.normalizeStickerSettings = _chunkHS6QDWDFcjs.normalizeStickerSettings; exports.normalizeStickerUpdate = normalizeStickerUpdate; exports.normalizeSymmetry = normalizeSymmetry; exports.normalizeView = normalizeView; exports.normalizeWetBrush = _chunkHS6QDWDFcjs.normalizeWetBrush; exports.normalizeWetParams = _chunkKBYB7OWBcjs.normalizeWetParams; exports.overPixels = overPixels; exports.padSampleRadius = padSampleRadius; exports.paintGradientMappingFor = _chunkFQPUF2W2cjs.paintGradientMappingFor; exports.paintPlaybackPanel = paintPlaybackPanel; exports.paintSourceColor = _chunkFQPUF2W2cjs.paintSourceColor; exports.paintSourceCss = _chunkFQPUF2W2cjs.paintSourceCss; exports.paintToMultiColor = _chunkHS6QDWDFcjs.paintToMultiColor; exports.paperEffectFromJSON = paperEffectFromJSON; exports.paperEffectToJSON = paperEffectToJSON; exports.paperGrain = paperGrain; exports.paperKey = paperKey; exports.paperNode = paperNode; exports.paperPreset = paperPreset; exports.parseBrushLibrary = _chunkHS6QDWDFcjs.parseBrushLibrary; exports.parseHexColor = parseHexColor; exports.parsePaintSource = _chunkFQPUF2W2cjs.parsePaintSource; exports.patchBrushValue = patchBrushValue; exports.patchPath = patchPath; exports.penOrientation = penOrientation; exports.perspectiveDirections = perspectiveDirections; exports.perspectiveGuideLines = perspectiveGuideLines; exports.planPaintToolPlayback = planPaintToolPlayback; exports.pointerToPenPoint = pointerToPenPoint; exports.quickStencil = quickStencil; exports.rand01 = _chunk3K6HWEXZcjs.rand01; exports.randSigned = _chunk3K6HWEXZcjs.randSigned; exports.readEffectStrokeMap = readEffectStrokeMap; exports.readPaintEffectPaint = readPaintEffectPaint; exports.readPaintEffectSource = readPaintEffectSource; exports.readPaintSource = _chunkFQPUF2W2cjs.readPaintSource; exports.readPath = readPath; exports.readSwatch = readSwatch; exports.reliefInfo = reliefInfo; exports.removePaintGradientStop = _chunkFQPUF2W2cjs.removePaintGradientStop; exports.renderBrushThumbnail = renderBrushThumbnail; exports.renderColorWheel = renderColorWheel; exports.renderPaper = renderPaper; exports.renderStickers = renderStickers; exports.replayFrame = replayFrame; exports.replayItems = replayItems; exports.replayPainting = replayPainting; exports.resolvePaintGradient = _chunkFQPUF2W2cjs.resolvePaintGradient; exports.reversePaintGradient = _chunkFQPUF2W2cjs.reversePaintGradient; exports.rgbToHexColor = rgbToHexColor; exports.rgbToHsl = rgbToHsl; exports.rgbToHsv = rgbToHsv; exports.sampleArt = sampleArt; exports.sampleEffectAt = sampleEffectAt; exports.sampleEffectField = sampleEffectField; exports.samplePressure = samplePressure; exports.scalePaintGradient = _chunkFQPUF2W2cjs.scalePaintGradient; exports.scaleStencil = scaleStencil; exports.screenToDocument = screenToDocument; exports.seedFromString = _chunk3K6HWEXZcjs.seedFromString; exports.serializePaintDocument = serializePaintDocument; exports.serializePaintDocumentExternal = serializePaintDocumentExternal; exports.solidPaint = _chunkFQPUF2W2cjs.solidPaint; exports.stampCoverage = _chunkJSDND7DFcjs.stampCoverage; exports.standardBlendMode = _chunk2VX55NFMcjs.standardBlendMode; exports.startWetClock = startWetClock; exports.stencilMask = stencilMask; exports.stencilOutline = stencilOutline; exports.stickerAt = stickerAt; exports.stickerRect = stickerRect; exports.stickerRefLabel = stickerRefLabel; exports.stickerStamp = stickerStamp; exports.stickerSurface = stickerSurface; exports.strokeBounds = strokeBounds; exports.strokeDuration = strokeDuration; exports.strokeSchedule = strokeSchedule; exports.sweepPath = sweepPath; exports.symmetryAxisAngles = symmetryAxisAngles; exports.symmetryAxisSegments = symmetryAxisSegments; exports.symmetryCopies = symmetryCopies; exports.thickFromJSON = thickFromJSON; exports.thickToJSON = thickToJSON; exports.thumbnailStroke = thumbnailStroke; exports.tiltToOrientation = tiltToOrientation; exports.timeLapseVideo = timeLapseVideo; exports.timeLapseZip = timeLapseZip; exports.toStrokePoint = toStrokePoint; exports.toggleDotTexture = toggleDotTexture; exports.toggleStamp = toggleStamp; exports.toggleStickerRef = toggleStickerRef; exports.translateStencil = translateStencil; exports.updatePaintGradientStop = _chunkFQPUF2W2cjs.updatePaintGradientStop; exports.usesPaintExchange = _chunkHS6QDWDFcjs.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 = _chunkKBYB7OWBcjs.wetSupport; exports.wheelAngle = wheelAngle; exports.wheelPick = wheelPick; exports.wheelPoint = wheelPoint; exports.wheelToHue = _chunkEUIDTZNQcjs.wheelToHue; exports.withPaintPlayback = withPaintPlayback;
12754
+
12755
+
12756
+ exports.BACKLIGHT_SPILL = BACKLIGHT_SPILL; exports.BLEND_MENU_GROUPS = BLEND_MENU_GROUPS; exports.BLEND_MODES = _chunk2VX55NFMcjs.BLEND_MODES; exports.BRUSH_ID = _chunkHS6QDWDFcjs.BRUSH_ID; exports.BRUSH_ROTATIONS = _chunkHS6QDWDFcjs.BRUSH_ROTATIONS; exports.BRUSH_SLIDERS = _chunk34KLWUH4cjs.BRUSH_SLIDERS; exports.BUILTIN_BRUSHES = _chunkHS6QDWDFcjs.BUILTIN_BRUSHES; exports.BristleStroke = BristleStroke; exports.DEFAULT_BACKLIGHT_COLOR = DEFAULT_BACKLIGHT_COLOR; exports.DEFAULT_BEHAVIOR = _chunkHS6QDWDFcjs.DEFAULT_BEHAVIOR; exports.DEFAULT_BRISTLE = _chunkHS6QDWDFcjs.DEFAULT_BRISTLE; exports.DEFAULT_BRUSH_ID = _chunkHS6QDWDFcjs.DEFAULT_BRUSH_ID; exports.DEFAULT_DPI = DEFAULT_DPI; exports.DEFAULT_DYNAMICS = _chunkHS6QDWDFcjs.DEFAULT_DYNAMICS; exports.DEFAULT_FLOW = _chunkKBYB7OWBcjs.DEFAULT_FLOW; exports.DEFAULT_IMPASTO = _chunkHS6QDWDFcjs.DEFAULT_IMPASTO; exports.DEFAULT_LIGHT = _chunkHS6QDWDFcjs.DEFAULT_LIGHT; exports.DEFAULT_LIGHTING = DEFAULT_LIGHTING; exports.DEFAULT_MULTI_COLOR = _chunkHS6QDWDFcjs.DEFAULT_MULTI_COLOR; exports.DEFAULT_PAINT_GRADIENT = _chunkFQPUF2W2cjs.DEFAULT_PAINT_GRADIENT; exports.DEFAULT_PAINT_GRADIENT_MAPPING = _chunkFQPUF2W2cjs.DEFAULT_PAINT_GRADIENT_MAPPING; exports.DEFAULT_PAPER = DEFAULT_PAPER; exports.DEFAULT_PARTICLE = _chunkHS6QDWDFcjs.DEFAULT_PARTICLE; exports.DEFAULT_STICKER = _chunkHS6QDWDFcjs.DEFAULT_STICKER; exports.DEFAULT_SWATCHES = DEFAULT_SWATCHES; exports.DEFAULT_VIEW = DEFAULT_VIEW; exports.DEFAULT_WET_BRUSH = _chunkHS6QDWDFcjs.DEFAULT_WET_BRUSH; exports.DEFAULT_WET_PARAMS = _chunkKBYB7OWBcjs.DEFAULT_WET_PARAMS; exports.DOT_ROTATIONS = _chunkHS6QDWDFcjs.DOT_ROTATIONS; exports.DOT_ROTATION_LABELS = DOT_ROTATION_LABELS; exports.DOT_TEXTURE_ORDERS = _chunkHS6QDWDFcjs.DOT_TEXTURE_ORDERS; exports.DOT_TEXTURE_ORDER_LABELS = DOT_TEXTURE_ORDER_LABELS; exports.DryStroke = DryStroke; exports.EFFECT_MAP_REPEATS = EFFECT_MAP_REPEATS; exports.EFFECT_STRIP_HEIGHT = EFFECT_STRIP_HEIGHT; exports.GPU_LEAD = GPU_LEAD; exports.GRAIN_PATTERNS = _chunkPXDIAYB6cjs.GRAIN_PATTERNS; exports.GRAIN_TILE = _chunkPXDIAYB6cjs.GRAIN_TILE; exports.HARMONY_KINDS = _chunkEUIDTZNQcjs.HARMONY_KINDS; exports.IDENTITY_AFFINE = IDENTITY_AFFINE; exports.IDENTITY_COPY = IDENTITY_COPY; exports.IMPASTO_TOOLS = _chunkHS6QDWDFcjs.IMPASTO_TOOLS; exports.IMPASTO_TOOL_LABELS = IMPASTO_TOOL_LABELS; exports.LIGHT_SLIDERS = LIGHT_SLIDERS; exports.LIVE_STROKE_ENGINES = LIVE_STROKE_ENGINES; exports.LitCache = LitCache; exports.MAX_BRUSH_SIZE = _chunkFQPUF2W2cjs.MAX_BRUSH_SIZE; exports.MAX_CANVAS_SIDE = MAX_CANVAS_SIDE; exports.MAX_COORDINATE = MAX_COORDINATE; exports.MAX_DOT_TEXTURES = _chunkHS6QDWDFcjs.MAX_DOT_TEXTURES; exports.MAX_IMAGE_SIDE = MAX_IMAGE_SIDE; exports.MAX_LIVE_EFFECT_SOURCES = MAX_LIVE_EFFECT_SOURCES; exports.MAX_STICKER_STAMPS = _chunkHS6QDWDFcjs.MAX_STICKER_STAMPS; exports.MAX_ZOOM = MAX_ZOOM; exports.MIN_CANVAS_SIDE = MIN_CANVAS_SIDE; exports.MIN_ZOOM = MIN_ZOOM; exports.MIXING_PAD_HEIGHT = MIXING_PAD_HEIGHT; exports.MIXING_PAD_WIDTH = MIXING_PAD_WIDTH; exports.MULTI_COLOR_MODES = _chunkHS6QDWDFcjs.MULTI_COLOR_MODES; exports.MixingPad = MixingPad; exports.PAD_SAMPLE_SIZES = PAD_SAMPLE_SIZES; exports.PAINTERLY_BLEND_MODES = _chunk2VX55NFMcjs.PAINTERLY_BLEND_MODES; exports.PAINT_BRUSH_CATEGORIES = _chunkHS6QDWDFcjs.PAINT_BRUSH_CATEGORIES; exports.PAINT_BRUSH_ENGINES = _chunkHS6QDWDFcjs.PAINT_BRUSH_ENGINES; exports.PAINT_COLOR_JSON_SCHEMA = _chunkFQPUF2W2cjs.PAINT_COLOR_JSON_SCHEMA; exports.PAINT_EFFECT_PLACES = PAINT_EFFECT_PLACES; exports.PAINT_FORMAT = PAINT_FORMAT; exports.PAINT_GRADIENT_FULL_SPEED = _chunkFQPUF2W2cjs.PAINT_GRADIENT_FULL_SPEED; exports.PAINT_GRADIENT_JSON_SCHEMA = _chunkFQPUF2W2cjs.PAINT_GRADIENT_JSON_SCHEMA; exports.PAINT_GRADIENT_KIT = _chunkFQPUF2W2cjs.PAINT_GRADIENT_KIT; exports.PAINT_GRADIENT_MAPPINGS = _chunkFQPUF2W2cjs.PAINT_GRADIENT_MAPPINGS; exports.PAINT_GRADIENT_MAPPING_LABELS = _chunkFQPUF2W2cjs.PAINT_GRADIENT_MAPPING_LABELS; exports.PAINT_GRADIENT_PRESETS = _chunkFQPUF2W2cjs.PAINT_GRADIENT_PRESETS; exports.PAINT_GRADIENT_REPEATS = _chunkFQPUF2W2cjs.PAINT_GRADIENT_REPEATS; exports.PAINT_GRADIENT_REPEAT_LABELS = _chunkFQPUF2W2cjs.PAINT_GRADIENT_REPEAT_LABELS; exports.PAINT_GRADIENT_SPACES = _chunkFQPUF2W2cjs.PAINT_GRADIENT_SPACES; exports.PAINT_GRADIENT_SPACE_LABELS = _chunkFQPUF2W2cjs.PAINT_GRADIENT_SPACE_LABELS; exports.PAINT_SCHEMA_VERSION = PAINT_SCHEMA_VERSION; exports.PAINT_SOURCE_JSON_SCHEMA = _chunkFQPUF2W2cjs.PAINT_SOURCE_JSON_SCHEMA; exports.PAINT_TARGET = PAINT_TARGET; exports.PAINT_TOOLS = PAINT_TOOLS; exports.PAPER_EFFECT_BLENDS = PAPER_EFFECT_BLENDS; exports.PAPER_EFFECT_NODE_ID = PAPER_EFFECT_NODE_ID; exports.PAPER_FAMILIES = PAPER_FAMILIES; exports.PAPER_LIBRARY = PAPER_LIBRARY; exports.PAPER_NODE_ID = PAPER_NODE_ID; exports.PAPER_SLIDERS = PAPER_SLIDERS; exports.PAPER_TARGET = PAPER_TARGET; exports.PARTICLE_KINDS = _chunkHS6QDWDFcjs.PARTICLE_KINDS; exports.PARTICLE_KIND_LABELS = PARTICLE_KIND_LABELS; exports.PARTICLE_RENDERS = _chunkHS6QDWDFcjs.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 = _chunkFQPUF2W2cjs.PaintGradientSampler; exports.PaintPresence = PaintPresence; exports.PaintSourceError = _chunkFQPUF2W2cjs.PaintSourceError; exports.PaintStrokeSession = PaintStrokeSession; exports.PaintWetLayers = PaintWetLayers; exports.PaperGrain = _chunkPXDIAYB6cjs.PaperGrain; exports.ParticleStroke = ParticleStroke; exports.PenDabWalker = PenDabWalker; exports.PenSmoother = PenSmoother; exports.PerspectiveSnapper = PerspectiveSnapper; exports.RIBBON_PAIRS = _chunkHS6QDWDFcjs.RIBBON_PAIRS; exports.RIBBON_PAIR_LABELS = RIBBON_PAIR_LABELS; exports.SNAP_DECIDE_DISTANCE = SNAP_DECIDE_DISTANCE; exports.STAMP_KINDS = _chunkJSDND7DFcjs.STAMP_KINDS; exports.STAMP_LABELS = STAMP_LABELS; exports.STENCIL_KINDS = STENCIL_KINDS; exports.STENCIL_SHAPES = STENCIL_SHAPES; exports.STICKER_ART_SIZE = STICKER_ART_SIZE; exports.STICKER_SLIDERS = STICKER_SLIDERS; exports.STROKE_SLIDERS = STROKE_SLIDERS; exports.SYMMETRY_MODES = SYMMETRY_MODES; exports.StencilSnapper = StencilSnapper; exports.StickerArtCache = StickerArtCache; exports.StickerBrowser = _chunkSABJMH6Mcjs.StickerBrowser; exports.StickerSpray = StickerSpray; exports.TRACING_NODE_ID = TRACING_NODE_ID; exports.ThickStrokeDriver = ThickStrokeDriver; exports.TileableNoise = _chunk3K6HWEXZcjs.TileableNoise; exports.WET_FLOW_KINDS = _chunkKBYB7OWBcjs.WET_FLOW_KINDS; exports.WET_GPU_MODES = WET_GPU_MODES; exports.WET_GPU_OPTIONS = WET_GPU_OPTIONS; exports.WET_MEDIA = _chunkHS6QDWDFcjs.WET_MEDIA; exports.WET_MEDIUM_LABELS = WET_MEDIUM_LABELS; exports.WET_MEDIUM_PARAMS = WET_MEDIUM_PARAMS; exports.WET_PARAM_KEYS = _chunkKBYB7OWBcjs.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 = _chunkHS6QDWDFcjs.WET_TOOLS; exports.WET_TOOL_LABELS = WET_TOOL_LABELS; exports.WetStrokeDriver = WetStrokeDriver; exports.addPaintGradientStop = _chunkFQPUF2W2cjs.addPaintGradientStop; exports.addPolygonArea = addPolygonArea; exports.affineCopy = affineCopy; exports.applyAffine = applyAffine; exports.backlightOf = backlightOf; exports.brushEngineControls = _chunk34KLWUH4cjs.brushEngineControls; exports.brushLoadColor = brushLoadColor; exports.brushLoadForStroke = brushLoadForStroke; exports.brushTakesPaint = _chunkHS6QDWDFcjs.brushTakesPaint; exports.brushToJSON = _chunkHS6QDWDFcjs.brushToJSON; exports.buildTimeLapse = buildTimeLapse; exports.checkPaintEffectPlace = checkPaintEffectPlace; exports.clonePaper = clonePaper; exports.colorHarmony = colorHarmony2; exports.composeAffine = composeAffine; exports.contactSheet = contactSheet; exports.createPaintBrushLibraryToolProvider = createPaintBrushLibraryToolProvider; exports.createPaintCompositor = createPaintCompositor; exports.createPaintDocument = createPaintDocument; exports.createPaintEditorDocument = createPaintEditorDocument; exports.createPaintEditorToolProvider = createPaintEditorToolProvider; exports.createPaintEffectsToolProvider = createPaintEffectsToolProvider; exports.createPaintLayer = createPaintLayer; exports.createPaintReplayTools = createPaintReplayTools; exports.createPaintStickerTools = createPaintStickerTools; exports.createPaintThickTools = createPaintThickTools; exports.createPaintWetTools = createPaintWetTools; exports.decodeImageBlob = decodeImageBlob; exports.defaultGuides = defaultGuides; exports.defaultImageEncoder = defaultImageEncoder; exports.defaultStickerRasterizer = defaultStickerRasterizer; exports.deserializePaintDocument = deserializePaintDocument; exports.deserializePaintDocumentAsync = deserializePaintDocumentAsync; exports.documentExtensions = documentExtensions; exports.documentToScreen = documentToScreen; exports.downloadBytes = downloadBytes; exports.downsampleRgba = downsampleRgba; exports.drawSticker = drawSticker; exports.drawWaterOverlay = drawWaterOverlay; exports.effectDabField = effectDabField; exports.effectLayersToJSON = effectLayersToJSON; exports.effectPaintKey = effectPaintKey; exports.effectPaintSize = effectPaintSize; exports.emptiedLayers = emptiedLayers; exports.emptyThickChannels = emptyThickChannels; exports.fitZoom = fitZoom; exports.grainCatch = _chunkPXDIAYB6cjs.grainCatch; exports.grainHeights = _chunkPXDIAYB6cjs.grainHeights; exports.guideOverlay = guideOverlay; exports.handlePaintShortcut = handlePaintShortcut; exports.hash2 = _chunk3K6HWEXZcjs.hash2; exports.hexToPaintRgb = _chunkFQPUF2W2cjs.hexToPaintRgb; exports.hexToRgb8 = hexToRgb8; exports.hslToRgb = hslToRgb; exports.hsvToRgb = hsvToRgb; exports.hueToWheel = _chunkEUIDTZNQcjs.hueToWheel; exports.invertAffine = invertAffine; exports.isBlendMode = _chunk2VX55NFMcjs.isBlendMode; exports.isGradientPaint = _chunkFQPUF2W2cjs.isGradientPaint; exports.isPaintEffectPaint = isPaintEffectPaint; exports.isPainterlyBlendMode = _chunk2VX55NFMcjs.isPainterlyBlendMode; exports.isPalmTouch = isPalmTouch; exports.isWetBrush = _chunkHS6QDWDFcjs.isWetBrush; exports.isWetCapable = _chunkHS6QDWDFcjs.isWetCapable; exports.lightTile = lightTile; exports.lightingKey = lightingKey; exports.liveStrokeBounds = liveStrokeBounds; exports.liveStrokeRefusal = liveStrokeRefusal; exports.mapPenPoint = mapPenPoint; exports.mix32 = _chunk3K6HWEXZcjs.mix32; exports.mixPixels = mixPixels; exports.mixerLoadForStroke = mixerLoadForStroke; exports.mixerTip = mixerTip; exports.multiColorForDab = multiColorForDab; exports.multiColorGradient = multiColorGradient; exports.multiColorPalette = multiColorPalette; exports.multiColorSliders = _chunk34KLWUH4cjs.multiColorSliders; exports.multiColorToPaint = _chunkHS6QDWDFcjs.multiColorToPaint; exports.newPaintLayerId = newPaintLayerId; exports.nextPaperEffectVersion = nextPaperEffectVersion; exports.normalizeBehavior = _chunkHS6QDWDFcjs.normalizeBehavior; exports.normalizeBristle = _chunkHS6QDWDFcjs.normalizeBristle; exports.normalizeBrushStroke = normalizeBrushStroke; exports.normalizeCanvas = normalizeCanvas; exports.normalizeDynamics = _chunkHS6QDWDFcjs.normalizeDynamics; exports.normalizeFlow = _chunkKBYB7OWBcjs.normalizeFlow; exports.normalizeHexColor = _chunkFQPUF2W2cjs.normalizeHexColor; exports.normalizeImpasto = _chunkHS6QDWDFcjs.normalizeImpasto; exports.normalizeLight = _chunkHS6QDWDFcjs.normalizeLight; exports.normalizeLighting = normalizeLighting; exports.normalizeMultiColor = _chunkHS6QDWDFcjs.normalizeMultiColor; exports.normalizePaintBrush = _chunkHS6QDWDFcjs.normalizePaintBrush; exports.normalizePaper = normalizePaper; exports.normalizeParticle = _chunkHS6QDWDFcjs.normalizeParticle; exports.normalizePerspective = normalizePerspective; exports.normalizeRotation = normalizeRotation; exports.normalizeStencil = normalizeStencil; exports.normalizeStickerSettings = _chunkHS6QDWDFcjs.normalizeStickerSettings; exports.normalizeStickerUpdate = normalizeStickerUpdate; exports.normalizeSymmetry = normalizeSymmetry; exports.normalizeView = normalizeView; exports.normalizeWetBrush = _chunkHS6QDWDFcjs.normalizeWetBrush; exports.normalizeWetParams = _chunkKBYB7OWBcjs.normalizeWetParams; exports.overPixels = overPixels; exports.padSampleRadius = padSampleRadius; exports.paintGradientMappingFor = _chunkFQPUF2W2cjs.paintGradientMappingFor; exports.paintPlaybackPanel = paintPlaybackPanel; exports.paintSourceColor = _chunkFQPUF2W2cjs.paintSourceColor; exports.paintSourceCss = _chunkFQPUF2W2cjs.paintSourceCss; exports.paintToMultiColor = _chunkHS6QDWDFcjs.paintToMultiColor; exports.paperEffectFromJSON = paperEffectFromJSON; exports.paperEffectToJSON = paperEffectToJSON; exports.paperGrain = paperGrain; exports.paperKey = paperKey; exports.paperNode = paperNode; exports.paperPreset = paperPreset; exports.parseBrushLibrary = _chunkHS6QDWDFcjs.parseBrushLibrary; exports.parseHexColor = parseHexColor; exports.parsePaintSource = _chunkFQPUF2W2cjs.parsePaintSource; exports.patchBrushValue = _chunk34KLWUH4cjs.patchBrushValue; exports.patchPath = patchPath; exports.penOrientation = penOrientation; exports.perspectiveDirections = perspectiveDirections; exports.perspectiveGuideLines = perspectiveGuideLines; exports.planPaintToolPlayback = planPaintToolPlayback; exports.pointerToPenPoint = pointerToPenPoint; exports.quickStencil = quickStencil; exports.rand01 = _chunk3K6HWEXZcjs.rand01; exports.randSigned = _chunk3K6HWEXZcjs.randSigned; exports.readEffectStrokeMap = readEffectStrokeMap; exports.readPaintEffectPaint = readPaintEffectPaint; exports.readPaintEffectSource = readPaintEffectSource; exports.readPaintSource = _chunkFQPUF2W2cjs.readPaintSource; exports.readPath = readPath; exports.readSwatch = readSwatch; exports.reliefInfo = reliefInfo; exports.removePaintGradientStop = _chunkFQPUF2W2cjs.removePaintGradientStop; exports.renderBrushThumbnail = renderBrushThumbnail; exports.renderColorWheel = renderColorWheel; exports.renderPaper = renderPaper; exports.renderStickers = renderStickers; exports.replayFrame = replayFrame; exports.replayItems = replayItems; exports.replayPainting = replayPainting; exports.resolvePaintGradient = _chunkFQPUF2W2cjs.resolvePaintGradient; exports.reversePaintGradient = _chunkFQPUF2W2cjs.reversePaintGradient; exports.rgbToHexColor = rgbToHexColor; exports.rgbToHsl = rgbToHsl; exports.rgbToHsv = rgbToHsv; exports.sampleArt = sampleArt; exports.sampleEffectAt = sampleEffectAt; exports.sampleEffectField = sampleEffectField; exports.samplePressure = samplePressure; exports.scalePaintGradient = _chunkFQPUF2W2cjs.scalePaintGradient; exports.scaleStencil = scaleStencil; exports.screenToDocument = screenToDocument; exports.seedFromString = _chunk3K6HWEXZcjs.seedFromString; exports.serializePaintDocument = serializePaintDocument; exports.serializePaintDocumentExternal = serializePaintDocumentExternal; exports.solidPaint = _chunkFQPUF2W2cjs.solidPaint; exports.stampCoverage = _chunkJSDND7DFcjs.stampCoverage; exports.standardBlendMode = _chunk2VX55NFMcjs.standardBlendMode; exports.startWetClock = startWetClock; exports.stencilMask = stencilMask; exports.stencilOutline = stencilOutline; exports.stickerAt = stickerAt; exports.stickerRect = stickerRect; exports.stickerRefLabel = stickerRefLabel; exports.stickerStamp = stickerStamp; exports.stickerSurface = stickerSurface; exports.strokeBounds = strokeBounds; exports.strokeDuration = strokeDuration; exports.strokeSchedule = strokeSchedule; exports.strokeToJSON = strokeToJSON; exports.sweepPath = sweepPath; exports.symmetryAxisAngles = symmetryAxisAngles; exports.symmetryAxisSegments = symmetryAxisSegments; exports.symmetryCopies = symmetryCopies; exports.thickFromJSON = thickFromJSON; exports.thickToJSON = thickToJSON; exports.thumbnailStroke = thumbnailStroke; exports.tiltToOrientation = tiltToOrientation; exports.timeLapseVideo = timeLapseVideo; exports.timeLapseZip = timeLapseZip; exports.toStrokePoint = toStrokePoint; exports.toggleDotTexture = toggleDotTexture; exports.toggleStamp = toggleStamp; exports.toggleStickerRef = toggleStickerRef; exports.translateStencil = translateStencil; exports.updatePaintGradientStop = _chunkFQPUF2W2cjs.updatePaintGradientStop; exports.usesPaintExchange = _chunkHS6QDWDFcjs.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 = _chunkKBYB7OWBcjs.wetSupport; exports.wheelAngle = wheelAngle; exports.wheelPick = wheelPick; exports.wheelPoint = wheelPoint; exports.wheelToHue = _chunkEUIDTZNQcjs.wheelToHue; exports.withPaintPlayback = withPaintPlayback;