@pixerate/editor 0.106.0 → 0.108.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 (70) hide show
  1. package/THIRD_PARTY_NOTICES.md +4 -0
  2. package/dist/animation-editor/index.cjs +39 -39
  3. package/dist/animation-editor/index.d.cts +1 -1
  4. package/dist/animation-editor/index.d.ts +1 -1
  5. package/dist/animation-editor/index.js +1 -1
  6. package/dist/{chunk-DS7KDKPX.js → chunk-3PHA3UKI.js} +2 -2
  7. package/dist/{chunk-ZID226ZG.cjs → chunk-FRD3FUXI.cjs} +172 -172
  8. package/dist/{chunk-ZID226ZG.cjs.map → chunk-FRD3FUXI.cjs.map} +1 -1
  9. package/dist/{chunk-67FRIOPZ.js → chunk-G4BIYE6R.js} +2 -2
  10. package/dist/{chunk-PV42JITT.cjs → chunk-HUFQD4CB.cjs} +44 -44
  11. package/dist/{chunk-PV42JITT.cjs.map → chunk-HUFQD4CB.cjs.map} +1 -1
  12. package/dist/{chunk-63EFQCT5.js → chunk-HUQ7EHVI.js} +1140 -371
  13. package/dist/chunk-HUQ7EHVI.js.map +1 -0
  14. package/dist/{chunk-4X5MIVCE.js → chunk-SOROZ2BF.js} +3 -3
  15. package/dist/{chunk-CRMAXIUV.cjs → chunk-SZ6KMZNM.cjs} +157 -8
  16. package/dist/chunk-SZ6KMZNM.cjs.map +1 -0
  17. package/dist/{chunk-WSTEXEKD.cjs → chunk-T3QZ6S47.cjs} +92 -92
  18. package/dist/{chunk-WSTEXEKD.cjs.map → chunk-T3QZ6S47.cjs.map} +1 -1
  19. package/dist/{chunk-KANRAHTL.cjs → chunk-UTEVPQTS.cjs} +1353 -584
  20. package/dist/chunk-UTEVPQTS.cjs.map +1 -0
  21. package/dist/{chunk-HEW6KDNI.js → chunk-WMBIJCHA.js} +155 -6
  22. package/dist/chunk-WMBIJCHA.js.map +1 -0
  23. package/dist/{compositor-Bc3PNP3C.d.cts → compositor-D92URMlm.d.cts} +1 -1
  24. package/dist/{compositor-BsYYllvR.d.ts → compositor-Kt_M4ruo.d.ts} +1 -1
  25. package/dist/{export-_m3Es4ru.d.cts → export-JGWQEPJn.d.cts} +3 -3
  26. package/dist/{export-iMrop3Jm.d.ts → export-a9bnF7Cl.d.ts} +3 -3
  27. package/dist/image-editor/index.cjs +627 -619
  28. package/dist/image-editor/index.cjs.map +1 -1
  29. package/dist/image-editor/index.d.cts +8 -8
  30. package/dist/image-editor/index.d.ts +8 -8
  31. package/dist/image-editor/index.js +12 -4
  32. package/dist/image-editor/index.js.map +1 -1
  33. package/dist/{mixer-C1M1Nua_.d.cts → mixer-5ziHU8OS.d.cts} +1 -1
  34. package/dist/{mixer-Cu5a9Bzd.d.ts → mixer-DNqiYXYQ.d.ts} +1 -1
  35. package/dist/paint/index.cjs +3 -3
  36. package/dist/paint/index.d.cts +2 -2
  37. package/dist/paint/index.d.ts +2 -2
  38. package/dist/paint/index.js +2 -2
  39. package/dist/paint-editor/index.cjs +365 -132
  40. package/dist/paint-editor/index.cjs.map +1 -1
  41. package/dist/paint-editor/index.d.cts +113 -8
  42. package/dist/paint-editor/index.d.ts +113 -8
  43. package/dist/paint-editor/index.js +249 -16
  44. package/dist/paint-editor/index.js.map +1 -1
  45. package/dist/raster/index.cjs +11 -3
  46. package/dist/raster/index.cjs.map +1 -1
  47. package/dist/raster/index.d.cts +4 -4
  48. package/dist/raster/index.d.ts +4 -4
  49. package/dist/raster/index.js +10 -2
  50. package/dist/{surface-BBJN9wxg.d.ts → surface-CkKOHGPm.d.cts} +20 -2
  51. package/dist/{surface-BBJN9wxg.d.cts → surface-CkKOHGPm.d.ts} +20 -2
  52. package/dist/{svg-Bj1MQFh6.d.cts → svg-ClVIG4T7.d.cts} +26 -2
  53. package/dist/{svg-vme0PLNo.d.ts → svg-SseJTIrA.d.ts} +26 -2
  54. package/dist/vector/index.cjs +977 -948
  55. package/dist/vector/index.cjs.map +1 -1
  56. package/dist/vector/index.d.cts +266 -7
  57. package/dist/vector/index.d.ts +266 -7
  58. package/dist/vector/index.js +427 -398
  59. package/dist/vector/index.js.map +1 -1
  60. package/package.json +1 -1
  61. package/skills/pixerate-image-editor/SKILL.md +50 -7
  62. package/skills/pixerate-paint-editor/SKILL.md +21 -1
  63. package/skills/pixerate-vector/SKILL.md +35 -5
  64. package/dist/chunk-63EFQCT5.js.map +0 -1
  65. package/dist/chunk-CRMAXIUV.cjs.map +0 -1
  66. package/dist/chunk-HEW6KDNI.js.map +0 -1
  67. package/dist/chunk-KANRAHTL.cjs.map +0 -1
  68. /package/dist/{chunk-DS7KDKPX.js.map → chunk-3PHA3UKI.js.map} +0 -0
  69. /package/dist/{chunk-67FRIOPZ.js.map → chunk-G4BIYE6R.js.map} +0 -0
  70. /package/dist/{chunk-4X5MIVCE.js.map → chunk-SOROZ2BF.js.map} +0 -0
@@ -4,7 +4,7 @@
4
4
 
5
5
 
6
6
 
7
- var _chunkZID226ZGcjs = require('../chunk-ZID226ZG.cjs');
7
+ var _chunkFRD3FUXIcjs = require('../chunk-FRD3FUXI.cjs');
8
8
 
9
9
 
10
10
 
@@ -17,7 +17,7 @@ var _chunkZID226ZGcjs = require('../chunk-ZID226ZG.cjs');
17
17
 
18
18
 
19
19
 
20
- var _chunkWSTEXEKDcjs = require('../chunk-WSTEXEKD.cjs');
20
+ var _chunkT3QZ6S47cjs = require('../chunk-T3QZ6S47.cjs');
21
21
  require('../chunk-MUUXNRU4.cjs');
22
22
 
23
23
 
@@ -35,7 +35,7 @@ require('../chunk-MUUXNRU4.cjs');
35
35
 
36
36
 
37
37
 
38
- var _chunkPV42JITTcjs = require('../chunk-PV42JITT.cjs');
38
+ var _chunkHUFQD4CBcjs = require('../chunk-HUFQD4CB.cjs');
39
39
 
40
40
 
41
41
 
@@ -50,7 +50,16 @@ var _chunkPV42JITTcjs = require('../chunk-PV42JITT.cjs');
50
50
 
51
51
 
52
52
 
53
- var _chunkCRMAXIUVcjs = require('../chunk-CRMAXIUV.cjs');
53
+
54
+
55
+
56
+ var _chunkSZ6KMZNMcjs = require('../chunk-SZ6KMZNM.cjs');
57
+
58
+
59
+
60
+
61
+
62
+ var _chunkEGFUVXKKcjs = require('../chunk-EGFUVXKK.cjs');
54
63
  require('../chunk-DWGZUSES.cjs');
55
64
 
56
65
  // src/paint-editor/noise.ts
@@ -400,7 +409,7 @@ function newPaintLayerId() {
400
409
  return `pl${Date.now().toString(36)}${(nextId++).toString(36)}`;
401
410
  }
402
411
  function createPaintLayer(name, id = newPaintLayerId()) {
403
- return { type: "pixel", id, name, visible: true, opacity: 1, blend: "normal", surface: _chunkCRMAXIUVcjs.emptySurface.call(void 0, 4), offset: { x: 0, y: 0 } };
412
+ return { type: "pixel", id, name, visible: true, opacity: 1, blend: "normal", surface: _chunkSZ6KMZNMcjs.emptySurface.call(void 0, 4), offset: { x: 0, y: 0 } };
404
413
  }
405
414
  var PaintDocumentError = class extends Error {
406
415
  constructor(message) {
@@ -468,12 +477,12 @@ function normalizePaintBrush(raw = {}, base) {
468
477
  name: typeof raw.name === "string" && raw.name.trim() ? raw.name.trim().slice(0, 80) : b.name,
469
478
  category: PAINT_BRUSH_CATEGORIES.includes(raw.category) ? raw.category : b.category,
470
479
  engine: PAINT_BRUSH_ENGINES.includes(raw.engine) ? raw.engine : b.engine,
471
- tip: _chunkPV42JITTcjs.normalizeBrush.call(void 0, { ...b.tip, ..._nullishCoalesce(raw.tip, () => ( {})) }),
480
+ tip: _chunkHUFQD4CBcjs.normalizeBrush.call(void 0, { ...b.tip, ..._nullishCoalesce(raw.tip, () => ( {})) }),
472
481
  grain: unit2(raw.grain, b.grain),
473
482
  pressureSmoothing: range(raw.pressureSmoothing, 0, 0.95, b.pressureSmoothing),
474
483
  rotation: BRUSH_ROTATIONS.includes(raw.rotation) ? raw.rotation : b.rotation,
475
484
  dynamics: normalizeDynamics(_nullishCoalesce(raw.dynamics, () => ( {})), b.dynamics),
476
- mixer: _chunkPV42JITTcjs.normalizeMixer.call(void 0, { ...b.mixer, ..._nullishCoalesce(raw.mixer, () => ( {})) }),
485
+ mixer: _chunkHUFQD4CBcjs.normalizeMixer.call(void 0, { ...b.mixer, ..._nullishCoalesce(raw.mixer, () => ( {})) }),
477
486
  loadsColor: typeof raw.loadsColor === "boolean" ? raw.loadsColor : b.loadsColor,
478
487
  ...raw.builtin ? { builtin: true } : {}
479
488
  };
@@ -483,12 +492,12 @@ var BASE_BRUSH = {
483
492
  name: "Round",
484
493
  category: "custom",
485
494
  engine: "dab",
486
- tip: { ..._chunkPV42JITTcjs.DEFAULT_BRUSH },
495
+ tip: { ..._chunkHUFQD4CBcjs.DEFAULT_BRUSH },
487
496
  grain: 0,
488
497
  pressureSmoothing: 0,
489
498
  rotation: "fixed",
490
499
  dynamics: { ...DEFAULT_DYNAMICS },
491
- mixer: { ..._chunkPV42JITTcjs.DEFAULT_MIXER },
500
+ mixer: { ..._chunkHUFQD4CBcjs.DEFAULT_MIXER },
492
501
  loadsColor: true
493
502
  };
494
503
  var builtin = (init) => ({ ...normalizePaintBrush(init), builtin: true });
@@ -865,7 +874,7 @@ var DryStroke = (_class5 = class {
865
874
  }
866
875
 
867
876
 
868
- __init12() {this.coverage = new (0, _chunkPV42JITTcjs.CoverageMap)()}
877
+ __init12() {this.coverage = new (0, _chunkHUFQD4CBcjs.CoverageMap)()}
869
878
  __init13() {this.dabCount = 0}
870
879
 
871
880
 
@@ -899,11 +908,11 @@ var DryStroke = (_class5 = class {
899
908
  const hardness = this.brush.tip.hardness;
900
909
  const grain = this.options.grain;
901
910
  for (const d of dabs) {
902
- const rect = _chunkPV42JITTcjs.dabRect.call(void 0, d, hardness);
911
+ const rect = _chunkHUFQD4CBcjs.dabRect.call(void 0, d, hardness);
903
912
  const n = rect.width * rect.height;
904
913
  if (this.buf.length < n) this.buf = new Float32Array(n);
905
914
  const vals = this.buf.subarray(0, n);
906
- _chunkPV42JITTcjs.rasterizeDab.call(void 0, d, hardness, rect, vals);
915
+ _chunkHUFQD4CBcjs.rasterizeDab.call(void 0, d, hardness, rect, vals);
907
916
  if (this.depth > 0 && grain) {
908
917
  for (let yy = 0, k = 0; yy < rect.height; yy++) {
909
918
  const y = rect.y + yy + 0.5;
@@ -928,7 +937,7 @@ function toStrokePoint(p) {
928
937
 
929
938
  // src/paint-editor/stroke.ts
930
939
  function defaultTile(surface) {
931
- const data = new Uint8ClampedArray(_chunkCRMAXIUVcjs.TILE * _chunkCRMAXIUVcjs.TILE * surface.channels);
940
+ const data = new Uint8ClampedArray(_chunkSZ6KMZNMcjs.TILE * _chunkSZ6KMZNMcjs.TILE * surface.channels);
932
941
  if (surface.defaultValue) data.fill(surface.defaultValue);
933
942
  return data;
934
943
  }
@@ -967,7 +976,7 @@ var PaintStrokeSession = (_class6 = class {
967
976
  if (brush.engine === "mixer") {
968
977
  this.mixerSmoother = new PenSmoother(brush.tip.smoothing, brush.pressureSmoothing);
969
978
  const load = init.mixerLoad;
970
- for (let i = 0; i < this.copies.length; i++) this.mixers.push(new (0, _chunkPV42JITTcjs.MixerStroke)(mixerTip(brush), brush.mixer, load, this.mixerTarget()));
979
+ for (let i = 0; i < this.copies.length; i++) this.mixers.push(new (0, _chunkHUFQD4CBcjs.MixerStroke)(mixerTip(brush), brush.mixer, load, this.mixerTarget()));
971
980
  } else {
972
981
  this.dry = new DryStroke(brush, { grain: init.grain, paperDepth: init.paperDepth, seed: init.seed, copies: this.copies });
973
982
  }
@@ -995,9 +1004,9 @@ var PaintStrokeSession = (_class6 = class {
995
1004
  offset: this.init.offset,
996
1005
  lockTransparency: this.init.lockTransparency,
997
1006
  selection: null,
998
- readTile: (tx, ty) => _nullishCoalesce(_optionalChain([this, 'access', _4 => _4.live, 'access', _5 => _5.get, 'call', _6 => _6(_chunkCRMAXIUVcjs.tileKey.call(void 0, tx, ty)), 'optionalAccess', _7 => _7.data]), () => ( null)),
1007
+ readTile: (tx, ty) => _nullishCoalesce(_optionalChain([this, 'access', _4 => _4.live, 'access', _5 => _5.get, 'call', _6 => _6(_chunkSZ6KMZNMcjs.tileKey.call(void 0, tx, ty)), 'optionalAccess', _7 => _7.data]), () => ( null)),
999
1008
  writeTile: (tx, ty) => {
1000
- const key = _chunkCRMAXIUVcjs.tileKey.call(void 0, tx, ty);
1009
+ const key = _chunkSZ6KMZNMcjs.tileKey.call(void 0, tx, ty);
1001
1010
  if (!this.touched.has(key)) {
1002
1011
  const src = _nullishCoalesce(_optionalChain([this, 'access', _8 => _8.base, 'access', _9 => _9.tiles, 'access', _10 => _10.get, 'call', _11 => _11(key), 'optionalAccess', _12 => _12.data]), () => ( defaultTile(this.base)));
1003
1012
  this.live.set(key, { data: new Uint8ClampedArray(src), uniform: null });
@@ -1035,14 +1044,14 @@ var PaintStrokeSession = (_class6 = class {
1035
1044
  if (!this.dry) {
1036
1045
  for (const key of this.fresh) this.live.set(key, { data: this.live.get(key).data, uniform: null });
1037
1046
  this.fresh.clear();
1038
- this.host.update(this.layerId, new (0, _chunkCRMAXIUVcjs.TiledSurface)(ch, new Map(this.live), this.base.defaultValue), rects);
1047
+ this.host.update(this.layerId, new (0, _chunkSZ6KMZNMcjs.TiledSurface)(ch, new Map(this.live), this.base.defaultValue), rects);
1039
1048
  return;
1040
1049
  }
1041
1050
  const off = this.init.offset;
1042
1051
  const regions = /* @__PURE__ */ new Map();
1043
1052
  for (const r of rects) {
1044
- for (const t of _chunkCRMAXIUVcjs.tilesInRect.call(void 0, { x: r.x - off.x, y: r.y - off.y, width: r.width, height: r.height })) {
1045
- const key = _chunkCRMAXIUVcjs.tileKey.call(void 0, t.tx, t.ty);
1053
+ for (const t of _chunkSZ6KMZNMcjs.tilesInRect.call(void 0, { x: r.x - off.x, y: r.y - off.y, width: r.width, height: r.height })) {
1054
+ const key = _chunkSZ6KMZNMcjs.tileKey.call(void 0, t.tx, t.ty);
1046
1055
  const cur = regions.get(key);
1047
1056
  regions.set(key, { tx: t.tx, ty: t.ty, r: cur ? union(cur.r, r) : r });
1048
1057
  }
@@ -1051,10 +1060,10 @@ var PaintStrokeSession = (_class6 = class {
1051
1060
  const src = _nullishCoalesce(_optionalChain([this, 'access', _13 => _13.base, 'access', _14 => _14.tiles, 'access', _15 => _15.get, 'call', _16 => _16(key), 'optionalAccess', _17 => _17.data]), () => ( defaultTile(this.base)));
1052
1061
  const prev = this.touched.has(key) ? _optionalChain([this, 'access', _18 => _18.live, 'access', _19 => _19.get, 'call', _20 => _20(key), 'optionalAccess', _21 => _21.data]) : void 0;
1053
1062
  this.touched.add(key);
1054
- const data = _chunkPV42JITTcjs.applyStrokeToTile.call(void 0, this.dry.coverage, src, ch, tx, ty, this.apply, prev ? { into: prev, region: r } : {});
1063
+ const data = _chunkHUFQD4CBcjs.applyStrokeToTile.call(void 0, this.dry.coverage, src, ch, tx, ty, this.apply, prev ? { into: prev, region: r } : {});
1055
1064
  this.live.set(key, { data, uniform: null });
1056
1065
  }
1057
- this.host.update(this.layerId, new (0, _chunkCRMAXIUVcjs.TiledSurface)(ch, new Map(this.live), this.base.defaultValue), rects);
1066
+ this.host.update(this.layerId, new (0, _chunkSZ6KMZNMcjs.TiledSurface)(ch, new Map(this.live), this.base.defaultValue), rects);
1058
1067
  }
1059
1068
  /** Ends the stroke (one undo step) and returns what changed. */
1060
1069
  end() {
@@ -1071,19 +1080,19 @@ var PaintStrokeSession = (_class6 = class {
1071
1080
  const tiles = new Map(this.base.tiles);
1072
1081
  let changed = false;
1073
1082
  for (const key of this.touched) {
1074
- const tile = _chunkCRMAXIUVcjs.finishTile.call(void 0, this.live.get(key).data, ch, this.base.defaultValue);
1083
+ const tile = _chunkSZ6KMZNMcjs.finishTile.call(void 0, this.live.get(key).data, ch, this.base.defaultValue);
1075
1084
  const prev = this.base.tiles.get(key);
1076
1085
  if (tile) tiles.set(key, tile);
1077
1086
  else tiles.delete(key);
1078
1087
  if (!sameTile(prev, tile)) changed = true;
1079
1088
  }
1080
- const surface = changed ? new (0, _chunkCRMAXIUVcjs.TiledSurface)(ch, tiles, this.base.defaultValue) : null;
1089
+ const surface = changed ? new (0, _chunkSZ6KMZNMcjs.TiledSurface)(ch, tiles, this.base.defaultValue) : null;
1081
1090
  const dabs = this.dry ? this.dry.dabCount : this.mixers.reduce((n, m) => n + m.dabCount, 0);
1082
1091
  this.result = { layerId: this.layerId, bounds: changed ? this.bounds : null, dabs, strokeId: null };
1083
1092
  if (this.mixers.length) {
1084
1093
  const brush = this.init.brush;
1085
1094
  let load = this.mixers[0].load;
1086
- if (brush.mixer.cleanEachStroke) load = _chunkPV42JITTcjs.cleanMixer.call(void 0, load);
1095
+ if (brush.mixer.cleanEachStroke) load = _chunkHUFQD4CBcjs.cleanMixer.call(void 0, load);
1087
1096
  this.result.mixerLoad = load;
1088
1097
  }
1089
1098
  this.host.commit(this, surface, false);
@@ -1098,7 +1107,7 @@ var PaintStrokeSession = (_class6 = class {
1098
1107
  }, _class6);
1099
1108
  function mixerLoadForStroke(brush, current, color) {
1100
1109
  if (!brush.loadsColor) return { reservoir: null, amount: 0, pickup: brush.mixer.cleanEachStroke ? null : current.pickup };
1101
- if (brush.mixer.loadEachStroke || !current.reservoir) return _chunkPV42JITTcjs.loadMixer.call(void 0, current, color);
1110
+ if (brush.mixer.loadEachStroke || !current.reservoir) return _chunkHUFQD4CBcjs.loadMixer.call(void 0, current, color);
1102
1111
  return current;
1103
1112
  }
1104
1113
 
@@ -1265,7 +1274,7 @@ var PROFILE = {
1265
1274
  }
1266
1275
  };
1267
1276
  function createPaintCompositor() {
1268
- return new (0, _chunkWSTEXEKDcjs.RasterCompositor)(PROFILE);
1277
+ return new (0, _chunkT3QZ6S47cjs.RasterCompositor)(PROFILE);
1269
1278
  }
1270
1279
  function downsampleRgba(data, width, height, tw, th) {
1271
1280
  tw = Math.max(1, Math.round(tw));
@@ -1336,11 +1345,11 @@ function header(state, options) {
1336
1345
  return out;
1337
1346
  }
1338
1347
  function serializePaintDocument(state, options = {}) {
1339
- const { layers, assets } = _chunkZID226ZGcjs.serializeLayers.call(void 0, state.layers);
1348
+ const { layers, assets } = _chunkFRD3FUXIcjs.serializeLayers.call(void 0, state.layers);
1340
1349
  return { ...header(state, options), layers, assets };
1341
1350
  }
1342
1351
  async function serializePaintDocumentExternal(state, store, options = {}) {
1343
- const { layers, assets } = await _chunkZID226ZGcjs.serializeLayersExternal.call(void 0, state.layers, store);
1352
+ const { layers, assets } = await _chunkFRD3FUXIcjs.serializeLayersExternal.call(void 0, state.layers, store);
1344
1353
  return { ...header(state, options), layers, assets };
1345
1354
  }
1346
1355
  function paintLayersOnly(layers, problems) {
@@ -1377,16 +1386,16 @@ function deserializePaintDocument(raw) {
1377
1386
  const canvas = normalizeCanvas({ width: r.width, height: r.height, dpi: _nullishCoalesce(r.dpi, () => ( void 0)) });
1378
1387
  const paper = normalizePaper(_nullishCoalesce(r.paper, () => ( {})));
1379
1388
  const assets = r.assets && typeof r.assets === "object" ? r.assets : {};
1380
- const layers = paintLayersOnly(_chunkZID226ZGcjs.deserializeLayers.call(void 0, r.layers, { assets, problems }), problems);
1389
+ const layers = paintLayersOnly(_chunkFRD3FUXIcjs.deserializeLayers.call(void 0, r.layers, { assets, problems }), problems);
1381
1390
  const wanted = typeof r.activeLayerId === "string" ? r.activeLayerId : null;
1382
- const activeLayerId = wanted && _chunkWSTEXEKDcjs.findLayer.call(void 0, layers, wanted) ? wanted : _nullishCoalesce(_optionalChain([_chunkWSTEXEKDcjs.flattenLayers.call(void 0, layers), 'access', _25 => _25.filter, 'call', _26 => _26((l) => l.type === "pixel"), 'access', _27 => _27.pop, 'call', _28 => _28(), 'optionalAccess', _29 => _29.id]), () => ( null));
1391
+ const activeLayerId = wanted && _chunkT3QZ6S47cjs.findLayer.call(void 0, layers, wanted) ? wanted : _nullishCoalesce(_optionalChain([_chunkT3QZ6S47cjs.flattenLayers.call(void 0, layers), 'access', _25 => _25.filter, 'call', _26 => _26((l) => l.type === "pixel"), 'access', _27 => _27.pop, 'call', _28 => _28(), 'optionalAccess', _29 => _29.id]), () => ( null));
1383
1392
  return { state: { canvas, paper, layers, activeLayerId, strokes: readStrokes(r.strokes, problems) }, extensions: documentExtensions(r), guides: r.guides, swatches: r.swatches, problems };
1384
1393
  }
1385
1394
  async function deserializePaintDocumentAsync(raw, store) {
1386
1395
  if (!raw || typeof raw !== "object") throw new Error("Not a paint document: expected a JSON object.");
1387
1396
  const r = raw;
1388
1397
  const problems = [];
1389
- const assets = await _chunkZID226ZGcjs.resolveExternalAssets.call(void 0, _nullishCoalesce(r.assets, () => ( {})), store, problems);
1398
+ const assets = await _chunkFRD3FUXIcjs.resolveExternalAssets.call(void 0, _nullishCoalesce(r.assets, () => ( {})), store, problems);
1390
1399
  const loaded = deserializePaintDocument({ ...r, assets });
1391
1400
  return { ...loaded, problems: [...problems, ...loaded.problems] };
1392
1401
  }
@@ -1565,7 +1574,7 @@ function paintTestStroke(surface, brush, paper, color, width, height) {
1565
1574
  colorHex: color,
1566
1575
  affineCopies: [],
1567
1576
  copies: [IDENTITY_COPY],
1568
- mixerLoad: brush.engine === "mixer" ? mixerLoadForStroke(brush, _chunkPV42JITTcjs.EMPTY_MIXER_LOAD, [r / 255, g / 255, b / 255]) : _chunkPV42JITTcjs.EMPTY_MIXER_LOAD
1577
+ mixerLoad: brush.engine === "mixer" ? mixerLoadForStroke(brush, _chunkHUFQD4CBcjs.EMPTY_MIXER_LOAD, [r / 255, g / 255, b / 255]) : _chunkHUFQD4CBcjs.EMPTY_MIXER_LOAD
1569
1578
  }
1570
1579
  );
1571
1580
  session.push(thumbnailStroke(width, height));
@@ -1578,13 +1587,13 @@ function renderBrushThumbnail(brush, options) {
1578
1587
  const maxSize = height * 0.42;
1579
1588
  const b = brush.tip.size > maxSize ? normalizePaintBrush({ tip: { ...brush.tip, size: maxSize } }, brush) : brush;
1580
1589
  const rgba = [...hexToRgb8(options.color), 255];
1581
- let surface = _chunkCRMAXIUVcjs.emptySurface.call(void 0, 4);
1590
+ let surface = _chunkSZ6KMZNMcjs.emptySurface.call(void 0, 4);
1582
1591
  if (b.engine === "eraser") {
1583
- surface = _chunkCRMAXIUVcjs.fillRect.call(void 0, surface, { x: 0, y: 0, width, height }, rgba);
1592
+ surface = _chunkSZ6KMZNMcjs.fillRect.call(void 0, surface, { x: 0, y: 0, width, height }, rgba);
1584
1593
  } else if (b.engine === "mixer" && !b.loadsColor) {
1585
1594
  const half = Math.ceil(height / 2);
1586
- surface = _chunkCRMAXIUVcjs.fillRect.call(void 0, surface, { x: 0, y: 0, width, height: half }, rgba);
1587
- surface = _chunkCRMAXIUVcjs.fillRect.call(void 0, surface, { x: 0, y: half, width, height: height - half }, [232, 196, 64, 255]);
1595
+ surface = _chunkSZ6KMZNMcjs.fillRect.call(void 0, surface, { x: 0, y: 0, width, height: half }, rgba);
1596
+ surface = _chunkSZ6KMZNMcjs.fillRect.call(void 0, surface, { x: 0, y: half, width, height: height - half }, [232, 196, 64, 255]);
1588
1597
  }
1589
1598
  surface = paintTestStroke(surface, b, options.paper, options.color, width, height);
1590
1599
  const layer = { type: "pixel", id: "thumbnail", name: "thumbnail", visible: true, opacity: 1, blend: "normal", surface, offset: { x: 0, y: 0 } };
@@ -1912,7 +1921,7 @@ var PAD_KNIFE = normalizePaintBrush({
1912
1921
  var MixingPad = (_class8 = class {constructor() { _class8.prototype.__init29.call(this);_class8.prototype.__init30.call(this);_class8.prototype.__init31.call(this);_class8.prototype.__init32.call(this); }
1913
1922
  __init29() {this.width = MIXING_PAD_WIDTH}
1914
1923
  __init30() {this.height = MIXING_PAD_HEIGHT}
1915
- __init31() {this.surface = _chunkCRMAXIUVcjs.emptySurface.call(void 0, 4)}
1924
+ __init31() {this.surface = _chunkSZ6KMZNMcjs.emptySurface.call(void 0, 4)}
1916
1925
  /** Increments on every change (for redrawing). */
1917
1926
  __init32() {this.version = 0}
1918
1927
  /** Paints (`paint`, with `color`) or smears (`knife`) through `points` in pad pixels. */
@@ -1944,7 +1953,7 @@ var MixingPad = (_class8 = class {constructor() { _class8.prototype.__init29.cal
1944
1953
  colorHex: options.color,
1945
1954
  affineCopies: [],
1946
1955
  copies: [IDENTITY_COPY],
1947
- mixerLoad: mixerLoadForStroke(brush, _chunkPV42JITTcjs.EMPTY_MIXER_LOAD, [r / 255, g / 255, b / 255])
1956
+ mixerLoad: mixerLoadForStroke(brush, _chunkHUFQD4CBcjs.EMPTY_MIXER_LOAD, [r / 255, g / 255, b / 255])
1948
1957
  }
1949
1958
  );
1950
1959
  session.push(points);
@@ -1963,7 +1972,7 @@ var MixingPad = (_class8 = class {constructor() { _class8.prototype.__init29.cal
1963
1972
  const y0 = Math.max(0, Math.floor(y) - r);
1964
1973
  const x1 = Math.min(this.width, Math.floor(x) + r + 1);
1965
1974
  const y1 = Math.min(this.height, Math.floor(y) + r + 1);
1966
- const px = _chunkCRMAXIUVcjs.readRegion.call(void 0, this.surface, { x: x0, y: y0, width: x1 - x0, height: y1 - y0 });
1975
+ const px = _chunkSZ6KMZNMcjs.readRegion.call(void 0, this.surface, { x: x0, y: y0, width: x1 - x0, height: y1 - y0 });
1967
1976
  let R = 0;
1968
1977
  let G = 0;
1969
1978
  let B = 0;
@@ -1980,12 +1989,12 @@ var MixingPad = (_class8 = class {constructor() { _class8.prototype.__init29.cal
1980
1989
  return `#${hex(R)}${hex(G)}${hex(B)}`;
1981
1990
  }
1982
1991
  clear() {
1983
- this.surface = _chunkCRMAXIUVcjs.emptySurface.call(void 0, 4);
1992
+ this.surface = _chunkSZ6KMZNMcjs.emptySurface.call(void 0, 4);
1984
1993
  this.version++;
1985
1994
  }
1986
1995
  /** The pad over white, `width × height` RGBA. */
1987
1996
  pixels() {
1988
- const px = _chunkCRMAXIUVcjs.readRegion.call(void 0, this.surface, { x: 0, y: 0, width: this.width, height: this.height });
1997
+ const px = _chunkSZ6KMZNMcjs.readRegion.call(void 0, this.surface, { x: 0, y: 0, width: this.width, height: this.height });
1989
1998
  for (let i = 0; i < px.length; i += 4) {
1990
1999
  const a = px[i + 3] / 255;
1991
2000
  px[i] = Math.round(px[i] * a + 255 * (1 - a));
@@ -2034,7 +2043,7 @@ var PaintEditorController = (_class9 = class {
2034
2043
 
2035
2044
 
2036
2045
  __init36() {this.secondaryColor = "#ffffff"}
2037
- __init37() {this.mixerLoad = _chunkPV42JITTcjs.EMPTY_MIXER_LOAD}
2046
+ __init37() {this.mixerLoad = _chunkHUFQD4CBcjs.EMPTY_MIXER_LOAD}
2038
2047
  __init38() {this.view = { ...DEFAULT_VIEW, pan: { ...DEFAULT_VIEW.pan } }}
2039
2048
 
2040
2049
 
@@ -2204,7 +2213,7 @@ var PaintEditorController = (_class9 = class {
2204
2213
  }
2205
2214
  // --- Layers --------------------------------------------------------------------
2206
2215
  getLayer(id) {
2207
- return _optionalChain([_chunkWSTEXEKDcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _35 => _35.layer]);
2216
+ return _optionalChain([_chunkT3QZ6S47cjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _35 => _35.layer]);
2208
2217
  }
2209
2218
  /** The active pixel layer (or `undefined`). */
2210
2219
  getActiveLayer() {
@@ -2223,12 +2232,12 @@ var PaintEditorController = (_class9 = class {
2223
2232
  walk(this.doc.layers, null, 0);
2224
2233
  return out;
2225
2234
  }
2226
- describeLayer(l, parentId = _nullishCoalesce(_optionalChain([_chunkWSTEXEKDcjs.findLayer.call(void 0, this.doc.layers, l.id), 'optionalAccess', _36 => _36.parent, 'optionalAccess', _37 => _37.id]), () => ( null)), depth = _nullishCoalesce(_optionalChain([_chunkWSTEXEKDcjs.findLayer.call(void 0, this.doc.layers, l.id), 'optionalAccess', _38 => _38.path, 'access', _39 => _39.length]), () => ( 0))) {
2235
+ describeLayer(l, parentId = _nullishCoalesce(_optionalChain([_chunkT3QZ6S47cjs.findLayer.call(void 0, this.doc.layers, l.id), 'optionalAccess', _36 => _36.parent, 'optionalAccess', _37 => _37.id]), () => ( null)), depth = _nullishCoalesce(_optionalChain([_chunkT3QZ6S47cjs.findLayer.call(void 0, this.doc.layers, l.id), 'optionalAccess', _38 => _38.path, 'access', _39 => _39.length]), () => ( 0))) {
2227
2236
  let bounds = null;
2228
2237
  if (l.type === "pixel") {
2229
- const b = _chunkCRMAXIUVcjs.contentBounds.call(void 0, l.surface);
2238
+ const b = _chunkSZ6KMZNMcjs.contentBounds.call(void 0, l.surface);
2230
2239
  bounds = b ? { ...b, x: b.x + l.offset.x, y: b.y + l.offset.y } : null;
2231
- } else for (const c of _chunkWSTEXEKDcjs.flattenLayers.call(void 0, l.children)) if (c.type === "pixel") bounds = unionRect(bounds, this.describeLayer(c, l.id, depth + 1).bounds);
2240
+ } else for (const c of _chunkT3QZ6S47cjs.flattenLayers.call(void 0, l.children)) if (c.type === "pixel") bounds = unionRect(bounds, this.describeLayer(c, l.id, depth + 1).bounds);
2232
2241
  return {
2233
2242
  id: l.id,
2234
2243
  name: l.name,
@@ -2255,7 +2264,7 @@ var PaintEditorController = (_class9 = class {
2255
2264
  if (!id) throw new PaintEditorError(`There is no active layer to ${what}; add one with add_layer.`);
2256
2265
  const l = this.requireLayer(id);
2257
2266
  if (!isPixelLayer(l)) throw new PaintEditorError(`Layer "${l.name}" is a group; ${what} a pixel layer inside it.`);
2258
- if (_chunkWSTEXEKDcjs.isLayerLocked.call(void 0, l, "pixels")) throw new PaintEditorError(`Layer "${l.name}" has its pixels locked; unlock it (update_layer locks) before you ${what} it.`);
2267
+ if (_chunkT3QZ6S47cjs.isLayerLocked.call(void 0, l, "pixels")) throw new PaintEditorError(`Layer "${l.name}" has its pixels locked; unlock it (update_layer locks) before you ${what} it.`);
2259
2268
  if (!l.visible) throw new PaintEditorError(`Layer "${l.name}" is hidden; show it (update_layer visible true) before you ${what} it.`);
2260
2269
  return l;
2261
2270
  }
@@ -2268,7 +2277,7 @@ var PaintEditorController = (_class9 = class {
2268
2277
  /** Adds an empty pixel layer or group above `aboveId` (default: the active layer) and makes it active. */
2269
2278
  addLayer(options = {}) {
2270
2279
  this.requireIdle("adding a layer");
2271
- const count = _chunkWSTEXEKDcjs.flattenLayers.call(void 0, this.doc.layers).length;
2280
+ const count = _chunkT3QZ6S47cjs.flattenLayers.call(void 0, this.doc.layers).length;
2272
2281
  const type = _nullishCoalesce(options.type, () => ( "pixel"));
2273
2282
  const name = _optionalChain([options, 'access', _40 => _40.name, 'optionalAccess', _41 => _41.trim, 'call', _42 => _42()]) || (type === "group" ? `Group ${count + 1}` : `Layer ${count + 1}`);
2274
2283
  const layer = type === "group" ? { type: "group", id: newPaintLayerId(), name, visible: true, opacity: 1, blend: "pass-through", children: [] } : createPaintLayer(name);
@@ -2280,21 +2289,21 @@ var PaintEditorController = (_class9 = class {
2280
2289
  if (g.type !== "group") throw new PaintEditorError(`Layer "${g.name}" is not a group; pass a group id as parentId.`);
2281
2290
  parentId = g.id;
2282
2291
  } else if (above) {
2283
- const loc = _chunkWSTEXEKDcjs.findLayer.call(void 0, this.doc.layers, above);
2292
+ const loc = _chunkT3QZ6S47cjs.findLayer.call(void 0, this.doc.layers, above);
2284
2293
  if (!loc) throw new PaintEditorError(`Unknown layer "${above}". Call list_layers for the ids.`);
2285
2294
  parentId = _nullishCoalesce(_optionalChain([loc, 'access', _43 => _43.parent, 'optionalAccess', _44 => _44.id]), () => ( null));
2286
2295
  index = loc.index + 1;
2287
2296
  }
2288
- const layers = _chunkWSTEXEKDcjs.insertLayer.call(void 0, this.doc.layers, layer, parentId, index);
2297
+ const layers = _chunkT3QZ6S47cjs.insertLayer.call(void 0, this.doc.layers, layer, parentId, index);
2289
2298
  this.commit(type === "group" ? "Add group" : "Add layer", { ...this.doc, layers, activeLayerId: layer.id });
2290
2299
  return this.describeLayer(layer);
2291
2300
  }
2292
2301
  updateLayer(id, update) {
2293
2302
  this.requireIdle("changing a layer");
2294
2303
  const l = this.requireLayer(id);
2295
- if (_chunkWSTEXEKDcjs.isLayerLocked.call(void 0, l, "all") && Object.keys(update).some((k) => k !== "locks")) throw new PaintEditorError(`Layer "${l.name}" is fully locked; unlock it first (locks {all: false}).`);
2304
+ if (_chunkT3QZ6S47cjs.isLayerLocked.call(void 0, l, "all") && Object.keys(update).some((k) => k !== "locks")) throw new PaintEditorError(`Layer "${l.name}" is fully locked; unlock it first (locks {all: false}).`);
2296
2305
  if (update.opacity !== void 0 && !(update.opacity >= 0 && update.opacity <= 1)) throw new PaintEditorError(`opacity ${update.opacity} is out of range; use 0..1.`);
2297
- if (update.blend !== void 0 && !_chunkCRMAXIUVcjs.isBlendMode.call(void 0, update.blend) && !(l.type === "group" && update.blend === "pass-through")) {
2306
+ if (update.blend !== void 0 && !_chunkSZ6KMZNMcjs.isBlendMode.call(void 0, update.blend) && !(l.type === "group" && update.blend === "pass-through")) {
2298
2307
  throw new PaintEditorError(`Unknown blend mode "${update.blend}". Call get_canvas_info for the blend modes.`);
2299
2308
  }
2300
2309
  if (update.name !== void 0 && !update.name.trim()) throw new PaintEditorError("name is empty; give the layer a name.");
@@ -2308,66 +2317,66 @@ var PaintEditorController = (_class9 = class {
2308
2317
  const locks = { ..._nullishCoalesce(l.locks, () => ( {})), ...update.locks };
2309
2318
  next.locks = Object.values(locks).some(Boolean) ? locks : void 0;
2310
2319
  }
2311
- this.commit("Layer properties", { ...this.doc, layers: _chunkWSTEXEKDcjs.mapLayer.call(void 0, this.doc.layers, id, () => next) });
2320
+ this.commit("Layer properties", { ...this.doc, layers: _chunkT3QZ6S47cjs.mapLayer.call(void 0, this.doc.layers, id, () => next) });
2312
2321
  return this.describeLayer(next);
2313
2322
  }
2314
2323
  removeLayer(id) {
2315
2324
  this.requireIdle("removing a layer");
2316
2325
  const l = this.requireLayer(id);
2317
- if (_chunkWSTEXEKDcjs.isLayerLocked.call(void 0, l, "all")) throw new PaintEditorError(`Layer "${l.name}" is fully locked; unlock it before removing it.`);
2318
- const layers = _chunkWSTEXEKDcjs.mapLayer.call(void 0, this.doc.layers, id, () => null);
2326
+ if (_chunkT3QZ6S47cjs.isLayerLocked.call(void 0, l, "all")) throw new PaintEditorError(`Layer "${l.name}" is fully locked; unlock it before removing it.`);
2327
+ const layers = _chunkT3QZ6S47cjs.mapLayer.call(void 0, this.doc.layers, id, () => null);
2319
2328
  let active = this.doc.activeLayerId;
2320
- if (active && !_chunkWSTEXEKDcjs.findLayer.call(void 0, layers, active)) active = _nullishCoalesce(_optionalChain([_chunkWSTEXEKDcjs.flattenLayers.call(void 0, layers), 'access', _45 => _45.filter, 'call', _46 => _46((x) => x.type === "pixel"), 'access', _47 => _47.pop, 'call', _48 => _48(), 'optionalAccess', _49 => _49.id]), () => ( null));
2329
+ if (active && !_chunkT3QZ6S47cjs.findLayer.call(void 0, layers, active)) active = _nullishCoalesce(_optionalChain([_chunkT3QZ6S47cjs.flattenLayers.call(void 0, layers), 'access', _45 => _45.filter, 'call', _46 => _46((x) => x.type === "pixel"), 'access', _47 => _47.pop, 'call', _48 => _48(), 'optionalAccess', _49 => _49.id]), () => ( null));
2321
2330
  this.commit("Remove layer", { ...this.doc, layers, activeLayerId: active });
2322
2331
  return { removed: id, activeLayerId: active };
2323
2332
  }
2324
2333
  duplicateLayer(id) {
2325
2334
  this.requireIdle("duplicating a layer");
2326
- const loc = _chunkWSTEXEKDcjs.findLayer.call(void 0, this.doc.layers, id);
2335
+ const loc = _chunkT3QZ6S47cjs.findLayer.call(void 0, this.doc.layers, id);
2327
2336
  if (!loc) throw new PaintEditorError(`Unknown layer "${id}". Call list_layers for the ids.`);
2328
2337
  const copy = (l) => l.type === "group" ? { ...l, id: newPaintLayerId(), children: l.children.map(copy) } : { ...l, id: newPaintLayerId() };
2329
2338
  const dup = { ...copy(loc.layer), name: `${loc.layer.name} copy` };
2330
- const layers = _chunkWSTEXEKDcjs.insertLayer.call(void 0, this.doc.layers, dup, _nullishCoalesce(_optionalChain([loc, 'access', _50 => _50.parent, 'optionalAccess', _51 => _51.id]), () => ( null)), loc.index + 1);
2339
+ const layers = _chunkT3QZ6S47cjs.insertLayer.call(void 0, this.doc.layers, dup, _nullishCoalesce(_optionalChain([loc, 'access', _50 => _50.parent, 'optionalAccess', _51 => _51.id]), () => ( null)), loc.index + 1);
2331
2340
  this.commit("Duplicate layer", { ...this.doc, layers, activeLayerId: dup.id });
2332
2341
  return this.describeLayer(dup);
2333
2342
  }
2334
2343
  /** Moves a layer to `index` (0 = bottom) within `parentId` (default its own parent; `null` = top level). */
2335
2344
  moveLayer(id, index, parentId) {
2336
2345
  this.requireIdle("moving a layer");
2337
- const loc = _chunkWSTEXEKDcjs.findLayer.call(void 0, this.doc.layers, id);
2346
+ const loc = _chunkT3QZ6S47cjs.findLayer.call(void 0, this.doc.layers, id);
2338
2347
  if (!loc) throw new PaintEditorError(`Unknown layer "${id}". Call list_layers for the ids.`);
2339
2348
  const target = parentId === void 0 ? _nullishCoalesce(_optionalChain([loc, 'access', _52 => _52.parent, 'optionalAccess', _53 => _53.id]), () => ( null)) : parentId;
2340
2349
  if (target) {
2341
2350
  const g = this.requireLayer(target);
2342
2351
  if (g.type !== "group") throw new PaintEditorError(`Layer "${g.name}" is not a group; pass a group id as parentId.`);
2343
- if (target === id || loc.layer.type === "group" && _chunkWSTEXEKDcjs.findLayer.call(void 0, loc.layer.children, target)) throw new PaintEditorError("A group cannot move into itself.");
2352
+ if (target === id || loc.layer.type === "group" && _chunkT3QZ6S47cjs.findLayer.call(void 0, loc.layer.children, target)) throw new PaintEditorError("A group cannot move into itself.");
2344
2353
  }
2345
- const without = _chunkWSTEXEKDcjs.mapLayer.call(void 0, this.doc.layers, id, () => null);
2346
- const siblings = target ? _chunkWSTEXEKDcjs.findLayer.call(void 0, without, target).layer.children : without;
2354
+ const without = _chunkT3QZ6S47cjs.mapLayer.call(void 0, this.doc.layers, id, () => null);
2355
+ const siblings = target ? _chunkT3QZ6S47cjs.findLayer.call(void 0, without, target).layer.children : without;
2347
2356
  if (!Number.isInteger(index) || index < 0 || index > siblings.length) throw new PaintEditorError(`index ${index} is out of range; use 0..${siblings.length} (0 is the bottom).`);
2348
- const layers = _chunkWSTEXEKDcjs.insertLayer.call(void 0, without, loc.layer, target, index);
2357
+ const layers = _chunkT3QZ6S47cjs.insertLayer.call(void 0, without, loc.layer, target, index);
2349
2358
  this.commit("Move layer", { ...this.doc, layers });
2350
2359
  return this.describeLayer(loc.layer);
2351
2360
  }
2352
2361
  /** Merges a pixel layer into the pixel layer below it (keeping the lower one's settings). */
2353
2362
  mergeDown(id) {
2354
2363
  this.requireIdle("merging");
2355
- const loc = _chunkWSTEXEKDcjs.findLayer.call(void 0, this.doc.layers, id);
2364
+ const loc = _chunkT3QZ6S47cjs.findLayer.call(void 0, this.doc.layers, id);
2356
2365
  if (!loc) throw new PaintEditorError(`Unknown layer "${id}". Call list_layers for the ids.`);
2357
2366
  const siblings = loc.parent ? loc.parent.children : this.doc.layers;
2358
2367
  const below = siblings[loc.index - 1];
2359
2368
  const upper = loc.layer;
2360
2369
  if (!isPixelLayer(upper) || !isPixelLayer(below)) throw new PaintEditorError("Merge down needs a pixel layer directly above another pixel layer in the same group.");
2361
- if (_chunkWSTEXEKDcjs.isLayerLocked.call(void 0, below, "pixels")) throw new PaintEditorError(`Layer "${below.name}" has its pixels locked; unlock it to merge into it.`);
2370
+ if (_chunkT3QZ6S47cjs.isLayerLocked.call(void 0, below, "pixels")) throw new PaintEditorError(`Layer "${below.name}" has its pixels locked; unlock it to merge into it.`);
2362
2371
  const rect = unionRect(this.describeLayer(below).bounds, this.describeLayer(upper).bounds);
2363
- let surface = _chunkCRMAXIUVcjs.emptySurface.call(void 0, 4);
2372
+ let surface = _chunkSZ6KMZNMcjs.emptySurface.call(void 0, 4);
2364
2373
  if (rect) {
2365
2374
  const base = { ...below, opacity: 1, blend: "normal", visible: true, clipped: void 0, mask: void 0 };
2366
2375
  const px = createPaintCompositor().composite([base, upper.visible ? upper : { ...upper, opacity: 0 }], rect, this.sources());
2367
- surface = _chunkCRMAXIUVcjs.surfaceFromPixels.call(void 0, { width: rect.width, height: rect.height, data: px }, 4, rect.x, rect.y);
2376
+ surface = _chunkSZ6KMZNMcjs.surfaceFromPixels.call(void 0, { width: rect.width, height: rect.height, data: px }, 4, rect.x, rect.y);
2368
2377
  }
2369
2378
  const merged = { ...below, surface, offset: { x: 0, y: 0 } };
2370
- const layers = _chunkWSTEXEKDcjs.mapLayer.call(void 0, _chunkWSTEXEKDcjs.mapLayer.call(void 0, this.doc.layers, upper.id, () => null), below.id, () => merged);
2379
+ const layers = _chunkT3QZ6S47cjs.mapLayer.call(void 0, _chunkT3QZ6S47cjs.mapLayer.call(void 0, this.doc.layers, upper.id, () => null), below.id, () => merged);
2371
2380
  this.commit("Merge down", { ...this.doc, layers, activeLayerId: below.id });
2372
2381
  return this.describeLayer(merged);
2373
2382
  }
@@ -2376,7 +2385,7 @@ var PaintEditorController = (_class9 = class {
2376
2385
  this.requireIdle("clearing");
2377
2386
  const l = this.paintTarget(layerId, "clear");
2378
2387
  const bounds = this.describeLayer(l).bounds;
2379
- this.commit("Clear layer", { ...this.doc, layers: _chunkWSTEXEKDcjs.mapLayer.call(void 0, this.doc.layers, l.id, () => ({ ...l, surface: _chunkCRMAXIUVcjs.emptySurface.call(void 0, 4) })) });
2388
+ this.commit("Clear layer", { ...this.doc, layers: _chunkT3QZ6S47cjs.mapLayer.call(void 0, this.doc.layers, l.id, () => ({ ...l, surface: _chunkSZ6KMZNMcjs.emptySurface.call(void 0, 4) })) });
2380
2389
  return { layerId: l.id, bounds };
2381
2390
  }
2382
2391
  /**
@@ -2393,14 +2402,14 @@ var PaintEditorController = (_class9 = class {
2393
2402
  if (!(grainAmount >= 0 && grainAmount <= 1)) throw new PaintEditorError(`grain ${grainAmount} is out of range; use 0..1.`);
2394
2403
  const pressure = _nullishCoalesce(options.pressure, () => ( 0.5));
2395
2404
  const blend = _nullishCoalesce(options.blend, () => ( "normal"));
2396
- if (!_chunkCRMAXIUVcjs.isBlendMode.call(void 0, blend)) throw new PaintEditorError(`Unknown blend mode "${blend}".`);
2405
+ if (!_chunkSZ6KMZNMcjs.isBlendMode.call(void 0, blend)) throw new PaintEditorError(`Unknown blend mode "${blend}".`);
2397
2406
  const { width, height } = this.doc.canvas;
2398
2407
  const rect = { x: 0, y: 0, width, height };
2399
- const coverage = new (0, _chunkPV42JITTcjs.CoverageMap)();
2408
+ const coverage = new (0, _chunkHUFQD4CBcjs.CoverageMap)();
2400
2409
  const depth = grainAmount * this.doc.paper.depth;
2401
2410
  const grain = depth > 0 ? paperGrain(this.doc.paper) : null;
2402
- for (const { tx, ty } of _chunkCRMAXIUVcjs.tilesInRect.call(void 0, rect)) {
2403
- const r = { x: tx * _chunkCRMAXIUVcjs.TILE, y: ty * _chunkCRMAXIUVcjs.TILE, width: Math.min(_chunkCRMAXIUVcjs.TILE, width - tx * _chunkCRMAXIUVcjs.TILE), height: Math.min(_chunkCRMAXIUVcjs.TILE, height - ty * _chunkCRMAXIUVcjs.TILE) };
2411
+ for (const { tx, ty } of _chunkSZ6KMZNMcjs.tilesInRect.call(void 0, rect)) {
2412
+ const r = { x: tx * _chunkSZ6KMZNMcjs.TILE, y: ty * _chunkSZ6KMZNMcjs.TILE, width: Math.min(_chunkSZ6KMZNMcjs.TILE, width - tx * _chunkSZ6KMZNMcjs.TILE), height: Math.min(_chunkSZ6KMZNMcjs.TILE, height - ty * _chunkSZ6KMZNMcjs.TILE) };
2404
2413
  const vals = new Float32Array(r.width * r.height);
2405
2414
  for (let y = 0, k = 0; y < r.height; y++) for (let x = 0; x < r.width; x++, k++) vals[k] = grain ? grainCatch(grain.at(r.x + x + 0.5, r.y + y + 0.5), depth, pressure) : 1;
2406
2415
  coverage.accumulate(r, vals, 1);
@@ -2411,25 +2420,25 @@ var PaintEditorController = (_class9 = class {
2411
2420
  background: rgbaOf(this.doc.paper.color),
2412
2421
  opacity,
2413
2422
  blend,
2414
- lockTransparency: _chunkWSTEXEKDcjs.isLayerLocked.call(void 0, l, "transparency"),
2423
+ lockTransparency: _chunkT3QZ6S47cjs.isLayerLocked.call(void 0, l, "transparency"),
2415
2424
  selection: null,
2416
2425
  offset: l.offset
2417
2426
  };
2418
2427
  const surface = this.applyCoverage(l, coverage, rect, apply);
2419
- this.commit("Fill layer", { ...this.doc, layers: _chunkWSTEXEKDcjs.mapLayer.call(void 0, this.doc.layers, l.id, () => ({ ...l, surface })) });
2428
+ this.commit("Fill layer", { ...this.doc, layers: _chunkT3QZ6S47cjs.mapLayer.call(void 0, this.doc.layers, l.id, () => ({ ...l, surface })) });
2420
2429
  return { layerId: l.id, bounds: rect };
2421
2430
  }
2422
2431
  applyCoverage(l, coverage, rect, apply) {
2423
2432
  const base = l.surface;
2424
2433
  const tiles = new Map(base.tiles);
2425
- for (const { tx, ty } of _chunkCRMAXIUVcjs.tilesInRect.call(void 0, { x: rect.x - l.offset.x, y: rect.y - l.offset.y, width: rect.width, height: rect.height })) {
2426
- const key = _chunkCRMAXIUVcjs.tileKey.call(void 0, tx, ty);
2427
- const src = _nullishCoalesce(_optionalChain([base, 'access', _54 => _54.tiles, 'access', _55 => _55.get, 'call', _56 => _56(key), 'optionalAccess', _57 => _57.data]), () => ( new Uint8ClampedArray(_chunkCRMAXIUVcjs.TILE * _chunkCRMAXIUVcjs.TILE * 4)));
2428
- const tile = _chunkCRMAXIUVcjs.finishTile.call(void 0, _chunkPV42JITTcjs.applyStrokeToTile.call(void 0, coverage, src, 4, tx, ty, apply), 4, 0);
2434
+ for (const { tx, ty } of _chunkSZ6KMZNMcjs.tilesInRect.call(void 0, { x: rect.x - l.offset.x, y: rect.y - l.offset.y, width: rect.width, height: rect.height })) {
2435
+ const key = _chunkSZ6KMZNMcjs.tileKey.call(void 0, tx, ty);
2436
+ const src = _nullishCoalesce(_optionalChain([base, 'access', _54 => _54.tiles, 'access', _55 => _55.get, 'call', _56 => _56(key), 'optionalAccess', _57 => _57.data]), () => ( new Uint8ClampedArray(_chunkSZ6KMZNMcjs.TILE * _chunkSZ6KMZNMcjs.TILE * 4)));
2437
+ const tile = _chunkSZ6KMZNMcjs.finishTile.call(void 0, _chunkHUFQD4CBcjs.applyStrokeToTile.call(void 0, coverage, src, 4, tx, ty, apply), 4, 0);
2429
2438
  if (tile) tiles.set(key, tile);
2430
2439
  else tiles.delete(key);
2431
2440
  }
2432
- return new (0, _chunkCRMAXIUVcjs.TiledSurface)(4, tiles, 0);
2441
+ return new (0, _chunkSZ6KMZNMcjs.TiledSurface)(4, tiles, 0);
2433
2442
  }
2434
2443
  // --- Brushes -------------------------------------------------------------------
2435
2444
  findBrush(id) {
@@ -2549,7 +2558,7 @@ var PaintEditorController = (_class9 = class {
2549
2558
  if (options.layerId !== void 0) {
2550
2559
  const l = this.requireLayer(options.layerId);
2551
2560
  if (!isPixelLayer(l)) throw new PaintEditorError(`Layer "${l.name}" is a group; pick from a pixel layer or the composite.`);
2552
- const [r, g, b, a] = _chunkCRMAXIUVcjs.readPixel.call(void 0, l.surface, px - l.offset.x, py - l.offset.y);
2561
+ const [r, g, b, a] = _chunkSZ6KMZNMcjs.readPixel.call(void 0, l.surface, px - l.offset.x, py - l.offset.y);
2553
2562
  return { color: rgbToHex(r, g, b), alpha: Math.round(a / 255 * 1e3) / 1e3 };
2554
2563
  }
2555
2564
  const d = this.exportCompositor.composite(this.renderLayers({}), { x: px, y: py, width: 1, height: 1 }, this.sources());
@@ -2559,13 +2568,13 @@ var PaintEditorController = (_class9 = class {
2559
2568
  /** Fills the Mixer Brush reservoir with a colour (default the editor colour). */
2560
2569
  loadMixerBrush(color) {
2561
2570
  const [r, g, b] = hexToRgb8(color === void 0 ? this.color : parseColor(color));
2562
- this.mixerLoad = _chunkPV42JITTcjs.loadMixer.call(void 0, this.mixerLoad, [r / 255, g / 255, b / 255]);
2571
+ this.mixerLoad = _chunkHUFQD4CBcjs.loadMixer.call(void 0, this.mixerLoad, [r / 255, g / 255, b / 255]);
2563
2572
  this.emit([]);
2564
2573
  return this.mixerLoad;
2565
2574
  }
2566
2575
  /** Empties the pickup well (and with `emptyReservoir` the loaded paint too). */
2567
2576
  cleanMixerBrush(emptyReservoir = false) {
2568
- this.mixerLoad = emptyReservoir ? _chunkPV42JITTcjs.EMPTY_MIXER_LOAD : _chunkPV42JITTcjs.cleanMixer.call(void 0, this.mixerLoad);
2577
+ this.mixerLoad = emptyReservoir ? _chunkHUFQD4CBcjs.EMPTY_MIXER_LOAD : _chunkHUFQD4CBcjs.cleanMixer.call(void 0, this.mixerLoad);
2569
2578
  this.emit([]);
2570
2579
  return this.mixerLoad;
2571
2580
  }
@@ -2599,11 +2608,11 @@ var PaintEditorController = (_class9 = class {
2599
2608
  const layer = (() => {
2600
2609
  const id = _nullishCoalesce(init.layerId, () => ( doc.activeLayerId));
2601
2610
  if (!id) throw new PaintEditorError("There is no active layer to paint on; add one with add_layer.");
2602
- const loc = _chunkWSTEXEKDcjs.findLayer.call(void 0, doc.layers, id);
2611
+ const loc = _chunkT3QZ6S47cjs.findLayer.call(void 0, doc.layers, id);
2603
2612
  if (!loc) throw new PaintEditorError(`Unknown layer "${id}". Call list_layers for the ids.`);
2604
2613
  const l = loc.layer;
2605
2614
  if (!isPixelLayer(l)) throw new PaintEditorError(`Layer "${l.name}" is a group; paint on a pixel layer inside it.`);
2606
- if (_chunkWSTEXEKDcjs.isLayerLocked.call(void 0, l, "pixels")) throw new PaintEditorError(`Layer "${l.name}" has its pixels locked; unlock it (update_layer locks) to paint on it.`);
2615
+ if (_chunkT3QZ6S47cjs.isLayerLocked.call(void 0, l, "pixels")) throw new PaintEditorError(`Layer "${l.name}" has its pixels locked; unlock it (update_layer locks) to paint on it.`);
2607
2616
  if (!l.visible) throw new PaintEditorError(`Layer "${l.name}" is hidden; show it (update_layer visible true) to paint on it.`);
2608
2617
  return l;
2609
2618
  })();
@@ -2620,7 +2629,7 @@ var PaintEditorController = (_class9 = class {
2620
2629
  layerId: layer.id,
2621
2630
  surface: layer.surface,
2622
2631
  offset: layer.offset,
2623
- lockTransparency: _chunkWSTEXEKDcjs.isLayerLocked.call(void 0, layer, "transparency"),
2632
+ lockTransparency: _chunkT3QZ6S47cjs.isLayerLocked.call(void 0, layer, "transparency"),
2624
2633
  brush,
2625
2634
  color: rgba,
2626
2635
  background: rgbaOf(doc.paper.color),
@@ -2631,7 +2640,7 @@ var PaintEditorController = (_class9 = class {
2631
2640
  affineCopies: copies,
2632
2641
  copies: [IDENTITY_AFFINE, ...copies].map(affineCopy),
2633
2642
  inputFilter: snapper ? (p) => snapper.snap(p) : void 0,
2634
- mixerLoad: brush.engine === "mixer" ? mixerLoadForStroke(brush, this.mixerLoad, [rgba[0] / 255, rgba[1] / 255, rgba[2] / 255]) : _chunkPV42JITTcjs.EMPTY_MIXER_LOAD
2643
+ mixerLoad: brush.engine === "mixer" ? mixerLoadForStroke(brush, this.mixerLoad, [rgba[0] / 255, rgba[1] / 255, rgba[2] / 255]) : _chunkHUFQD4CBcjs.EMPTY_MIXER_LOAD
2635
2644
  });
2636
2645
  return session;
2637
2646
  }
@@ -2672,7 +2681,7 @@ var PaintEditorController = (_class9 = class {
2672
2681
  const stroke = this.record(s);
2673
2682
  s.result.strokeId = stroke.id;
2674
2683
  const l = this.getLayer(s.layerId);
2675
- this.commit(`${brush.name} stroke`, { ...this.doc, layers: _chunkWSTEXEKDcjs.mapLayer.call(void 0, this.doc.layers, l.id, () => ({ ...l, surface })), strokes: [...this.doc.strokes, stroke] });
2684
+ this.commit(`${brush.name} stroke`, { ...this.doc, layers: _chunkT3QZ6S47cjs.mapLayer.call(void 0, this.doc.layers, l.id, () => ({ ...l, surface })), strokes: [...this.doc.strokes, stroke] });
2676
2685
  }
2677
2686
  };
2678
2687
  const session = this.sessionFor(this.doc, { snapToPerspective: true, ...init }, host);
@@ -2694,8 +2703,8 @@ var PaintEditorController = (_class9 = class {
2694
2703
  if (cancelled || !surface) return;
2695
2704
  const stroke = this.record(s);
2696
2705
  s.result.strokeId = stroke.id;
2697
- const l = _chunkWSTEXEKDcjs.findLayer.call(void 0, out.layers, s.layerId).layer;
2698
- out = { ...out, layers: _chunkWSTEXEKDcjs.mapLayer.call(void 0, out.layers, l.id, () => ({ ...l, surface })), strokes: [...out.strokes, stroke] };
2706
+ const l = _chunkT3QZ6S47cjs.findLayer.call(void 0, out.layers, s.layerId).layer;
2707
+ out = { ...out, layers: _chunkT3QZ6S47cjs.mapLayer.call(void 0, out.layers, l.id, () => ({ ...l, surface })), strokes: [...out.strokes, stroke] };
2699
2708
  }
2700
2709
  };
2701
2710
  const session = this.sessionFor(doc, init, host);
@@ -2713,6 +2722,7 @@ var PaintEditorController = (_class9 = class {
2713
2722
  else this.emit([]);
2714
2723
  return result;
2715
2724
  }
2725
+ /** Checks stroke samples (finite x and y, pressure 0..1) and returns them; throws a sentence naming the bad point. */
2716
2726
  checkPoints(points) {
2717
2727
  if (!Array.isArray(points) || !points.length) throw new PaintEditorError("points is empty; give at least one {x, y} in document pixels.");
2718
2728
  const out = [];
@@ -2766,7 +2776,7 @@ var PaintEditorController = (_class9 = class {
2766
2776
  brush = normalizePaintBrush({ tip: { ...b.tip, size: b.tip.size * (v.brush.tip.size / s.brush.tip.size) } }, b);
2767
2777
  }
2768
2778
  const layerId = _nullishCoalesce(options.layerId, () => ( s.layerId));
2769
- if (!_chunkWSTEXEKDcjs.findLayer.call(void 0, doc.layers, layerId)) throw new PaintEditorError(`Stroke "${s.id}" was painted on layer "${layerId}", which no longer exists; pass layerId to replay it elsewhere.`);
2779
+ if (!_chunkT3QZ6S47cjs.findLayer.call(void 0, doc.layers, layerId)) throw new PaintEditorError(`Stroke "${s.id}" was painted on layer "${layerId}", which no longer exists; pass layerId to replay it elsewhere.`);
2770
2780
  const run = this.runStroke(doc, { layerId, color: _nullishCoalesce(options.color, () => ( s.color)), brush, seed: s.seed, copies: _nullishCoalesce(v.copies, () => ( [])) }, v.points);
2771
2781
  doc = run.doc;
2772
2782
  bounds = unionRect(bounds, run.result.bounds);
@@ -2786,7 +2796,7 @@ var PaintEditorController = (_class9 = class {
2786
2796
  const live = this.live;
2787
2797
  if (!live) return this.doc.layers;
2788
2798
  if (_optionalChain([this, 'access', _63 => _63.liveLayers, 'optionalAccess', _64 => _64.key]) === live.surface) return this.liveLayers.layers;
2789
- const layers = _chunkWSTEXEKDcjs.mapLayer.call(void 0, this.doc.layers, live.layerId, (l) => ({ ...l, surface: live.surface }));
2799
+ const layers = _chunkT3QZ6S47cjs.mapLayer.call(void 0, this.doc.layers, live.layerId, (l) => ({ ...l, surface: live.surface }));
2790
2800
  this.liveLayers = { key: live.surface, layers };
2791
2801
  return layers;
2792
2802
  }
@@ -2890,7 +2900,7 @@ var PaintEditorController = (_class9 = class {
2890
2900
  /** The canvas as PNG bytes (paper included by default; `scale` below 1 shrinks it). */
2891
2901
  exportPng(options = {}) {
2892
2902
  const img = this.scaled(options);
2893
- return _chunkWSTEXEKDcjs.encodePng.call(void 0, img.width, img.height, img.data);
2903
+ return _chunkT3QZ6S47cjs.encodePng.call(void 0, img.width, img.height, img.data);
2894
2904
  }
2895
2905
  scaled(options) {
2896
2906
  const full = this.compositePixels(options);
@@ -2932,19 +2942,32 @@ var PaintEditorController = (_class9 = class {
2932
2942
  opacity: 1,
2933
2943
  blend: "normal",
2934
2944
  locks: { all: true },
2935
- surface: _chunkCRMAXIUVcjs.surfaceFromPixels.call(void 0, paperPixels, 4),
2945
+ surface: _chunkSZ6KMZNMcjs.surfaceFromPixels.call(void 0, paperPixels, 4),
2936
2946
  offset: { x: 0, y: 0 }
2937
2947
  };
2938
2948
  const merged = this.compositePixels({ paper: true }).data;
2939
- const result = _chunkZID226ZGcjs.exportPsd.call(void 0, { width, height, layers: [paperLayer, ...this.doc.layers], merged, resolution: dpi });
2940
- const pigment = _chunkWSTEXEKDcjs.flattenLayers.call(void 0, this.doc.layers).filter((l) => l.blend === "pigment");
2941
- if (pigment.length) result.warnings.push(`Pigment blending has no PSD equivalent; ${pigment.map((l) => `"${l.name}"`).join(", ")} ${pigment.length === 1 ? "was" : "were"} written as Normal, so ${pigment.length === 1 ? "it looks" : "they look"} different in Photoshop.`);
2949
+ const changed = /* @__PURE__ */ new Map();
2950
+ const toStandard = (layers2) => layers2.map((l) => {
2951
+ const blend = l.blend === "pass-through" ? l.blend : _chunkSZ6KMZNMcjs.standardBlendMode.call(void 0, l.blend);
2952
+ if (blend !== l.blend) changed.set(l.blend, [..._nullishCoalesce(changed.get(l.blend), () => ( [])), l.name]);
2953
+ const next = blend === l.blend ? l : { ...l, blend };
2954
+ return next.type === "group" ? { ...next, children: toStandard(next.children) } : next;
2955
+ });
2956
+ const layers = toStandard(this.doc.layers);
2957
+ const result = _chunkFRD3FUXIcjs.exportPsd.call(void 0, { width, height, layers: [paperLayer, ...layers], merged, resolution: dpi });
2958
+ for (const [mode, names] of changed) {
2959
+ const label = _nullishCoalesce(_optionalChain([_chunkSZ6KMZNMcjs.BLEND_MODES, 'access', _72 => _72.find, 'call', _73 => _73((m) => m.id === mode), 'optionalAccess', _74 => _74.label]), () => ( mode));
2960
+ const std = _nullishCoalesce(_optionalChain([_chunkSZ6KMZNMcjs.BLEND_MODES, 'access', _75 => _75.find, 'call', _76 => _76((m) => m.id === _chunkSZ6KMZNMcjs.standardBlendMode.call(void 0, mode)), 'optionalAccess', _77 => _77.label]), () => ( _chunkSZ6KMZNMcjs.standardBlendMode.call(void 0, mode)));
2961
+ const list = names.map((n) => `"${n}"`).join(", ");
2962
+ const one = names.length === 1;
2963
+ 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).`);
2964
+ }
2942
2965
  return result;
2943
2966
  }
2944
2967
  /** `render_preview` as a base64 PNG. */
2945
2968
  previewPngBase64(options = {}) {
2946
2969
  const img = this.renderPreview(options);
2947
- return { data: _chunkWSTEXEKDcjs.bytesToBase64.call(void 0, _chunkWSTEXEKDcjs.encodePng.call(void 0, img.width, img.height, img.data)), width: img.width, height: img.height };
2970
+ return { data: _chunkT3QZ6S47cjs.bytesToBase64.call(void 0, _chunkT3QZ6S47cjs.encodePng.call(void 0, img.width, img.height, img.data)), width: img.width, height: img.height };
2948
2971
  }
2949
2972
  // --- Guides --------------------------------------------------------------------
2950
2973
  setGuides(next) {
@@ -2982,17 +3005,17 @@ var PaintEditorController = (_class9 = class {
2982
3005
  pixels = this.decodeImage(input.png.trim().startsWith("data:") ? input.png.trim() : `data:image/png;base64,${input.png.trim()}`, what);
2983
3006
  } else throw new PaintEditorError(`${what}: pass png (a PNG as base64 or a data URL) or pixels.`);
2984
3007
  if (pixels.width > MAX_IMAGE_SIDE || pixels.height > MAX_IMAGE_SIDE) throw new PaintEditorError(`${what} is ${pixels.width}\xD7${pixels.height}; the limit is ${MAX_IMAGE_SIDE} px per side.`);
2985
- const src = _chunkWSTEXEKDcjs.pngDataUrl.call(void 0, pixels.width, pixels.height, pixels.data);
3008
+ const src = _chunkT3QZ6S47cjs.pngDataUrl.call(void 0, pixels.width, pixels.height, pixels.data);
2986
3009
  this.imagePixels.set(src, pixels);
2987
3010
  return { src, pixels };
2988
3011
  }
2989
3012
  decodeImage(src, what = "Image") {
2990
3013
  const cached = this.imagePixels.get(src);
2991
3014
  if (cached) return cached;
2992
- const parsed = _chunkWSTEXEKDcjs.parseDataUrl.call(void 0, src);
3015
+ const parsed = _chunkT3QZ6S47cjs.parseDataUrl.call(void 0, src);
2993
3016
  if (!parsed) throw new PaintEditorError(`${what} is not a data URL or base64 PNG.`);
2994
3017
  try {
2995
- const png = _chunkWSTEXEKDcjs.decodePng.call(void 0, parsed.bytes);
3018
+ const png = _chunkT3QZ6S47cjs.decodePng.call(void 0, parsed.bytes);
2996
3019
  const px = { width: png.width, height: png.height, data: png.data };
2997
3020
  this.imagePixels.set(src, px);
2998
3021
  return px;
@@ -3050,7 +3073,7 @@ var PaintEditorController = (_class9 = class {
3050
3073
  const { src, pixels } = this.importImage(options, "The reference image");
3051
3074
  const ref = {
3052
3075
  id: `ref${this.nextReferenceId++}`,
3053
- name: _optionalChain([options, 'access', _72 => _72.name, 'optionalAccess', _73 => _73.trim, 'call', _74 => _74()]) || `Reference ${this.guides.references.length + 1}`,
3076
+ name: _optionalChain([options, 'access', _78 => _78.name, 'optionalAccess', _79 => _79.trim, 'call', _80 => _80()]) || `Reference ${this.guides.references.length + 1}`,
3054
3077
  src,
3055
3078
  width: pixels.width,
3056
3079
  height: pixels.height,
@@ -3129,7 +3152,7 @@ var PaintEditorController = (_class9 = class {
3129
3152
  try {
3130
3153
  const px = this.decodeImage(ref.src, `Reference "${ref.name}"`);
3131
3154
  guides.references.push({ id: ref.id, name: String(_nullishCoalesce(ref.name, () => ( ref.id))), src: ref.src, width: px.width, height: px.height, x: Number(ref.x) || 0, y: Number(ref.y) || 0, displayWidth: Number(ref.displayWidth) || 240, visible: ref.visible !== false });
3132
- const n = Number(_nullishCoalesce(_optionalChain([/^ref(\d+)$/, 'access', _75 => _75.exec, 'call', _76 => _76(ref.id), 'optionalAccess', _77 => _77[1]]), () => ( 0)));
3155
+ const n = Number(_nullishCoalesce(_optionalChain([/^ref(\d+)$/, 'access', _81 => _81.exec, 'call', _82 => _82(ref.id), 'optionalAccess', _83 => _83[1]]), () => ( 0)));
3133
3156
  if (n >= this.nextReferenceId) this.nextReferenceId = n + 1;
3134
3157
  } catch (e) {
3135
3158
  problems.push(e.message);
@@ -3149,7 +3172,7 @@ var PaintEditorController = (_class9 = class {
3149
3172
  }
3150
3173
  addSwatch(color, name) {
3151
3174
  const c = parseColor(color);
3152
- this.swatches = [...this.swatches, _optionalChain([name, 'optionalAccess', _78 => _78.trim, 'call', _79 => _79()]) ? { color: c, name: name.trim() } : { color: c }];
3175
+ this.swatches = [...this.swatches, _optionalChain([name, 'optionalAccess', _84 => _84.trim, 'call', _85 => _85()]) ? { color: c, name: name.trim() } : { color: c }];
3153
3176
  this.emit([]);
3154
3177
  return this.swatches;
3155
3178
  }
@@ -3197,7 +3220,7 @@ var PaintEditorController = (_class9 = class {
3197
3220
  }
3198
3221
  /** A layer's tile surface (live while stroking), for thumbnails. */
3199
3222
  layerSurface(id) {
3200
- const l = _optionalChain([_chunkWSTEXEKDcjs.findLayer.call(void 0, this.currentLayers(), id), 'optionalAccess', _80 => _80.layer]);
3223
+ const l = _optionalChain([_chunkT3QZ6S47cjs.findLayer.call(void 0, this.currentLayers(), id), 'optionalAccess', _86 => _86.layer]);
3201
3224
  return isPixelLayer(l) ? l.surface : null;
3202
3225
  }
3203
3226
  }, _class9);
@@ -3234,6 +3257,169 @@ function resampleInto(src, rect, width, height) {
3234
3257
  return { width, height, data: out };
3235
3258
  }
3236
3259
 
3260
+ // src/paint-editor/presence.ts
3261
+ var PaintPresence = class extends _chunkEGFUVXKKcjs.PresenceStore {
3262
+ };
3263
+ var FRAME = 16;
3264
+ function strokeSchedule(points) {
3265
+ if (points.length < 2) return points.map(() => 1);
3266
+ const t0 = points[0].t;
3267
+ const t1 = points[points.length - 1].t;
3268
+ if (points.every((p) => Number.isFinite(p.t)) && t1 > t0) {
3269
+ return points.map((p) => Math.min(1, Math.max(0, (p.t - t0) / (t1 - t0))));
3270
+ }
3271
+ const acc = [0];
3272
+ for (let i = 1; i < points.length; i++) acc.push(acc[i - 1] + Math.hypot(points[i].x - points[i - 1].x, points[i].y - points[i - 1].y));
3273
+ const total = acc[acc.length - 1];
3274
+ return total > 0 ? acc.map((d) => d / total) : points.map(() => 1);
3275
+ }
3276
+ function strokeDuration(points, max = 1800) {
3277
+ const t0 = _optionalChain([points, 'access', _87 => _87[0], 'optionalAccess', _88 => _88.t]);
3278
+ const t1 = _optionalChain([points, 'access', _89 => _89[points.length - 1], 'optionalAccess', _90 => _90.t]);
3279
+ let ms;
3280
+ if (points.every((p) => Number.isFinite(p.t)) && t1 > t0) ms = t1 - t0;
3281
+ else {
3282
+ let length = 0;
3283
+ for (let i = 1; i < points.length; i++) length += Math.hypot(points[i].x - points[i - 1].x, points[i].y - points[i - 1].y);
3284
+ ms = length / 1.5;
3285
+ }
3286
+ return Math.min(max, Math.max(250, ms));
3287
+ }
3288
+ function sweepPath(rect, rows = 4) {
3289
+ const inset = Math.min(rect.width, rect.height) * 0.08;
3290
+ const left = rect.x + inset;
3291
+ const right = rect.x + rect.width - inset;
3292
+ const out = [];
3293
+ for (let r = 0; r < rows; r++) {
3294
+ const y = rect.y + inset + (rect.height - 2 * inset) * (r + 0.5) / rows;
3295
+ out.push(r % 2 ? { x: right, y } : { x: left, y }, r % 2 ? { x: left, y } : { x: right, y });
3296
+ }
3297
+ return out;
3298
+ }
3299
+ var centre = (r) => ({ x: r.x + r.width / 2, y: r.y + r.height / 2 });
3300
+ var PaintDirector = class {
3301
+ constructor(controller, presence, options = {}) {
3302
+ this.controller = controller;
3303
+ this.presence = presence;
3304
+ this.options = options;
3305
+ this.clock = _nullishCoalesce(options.clock, () => ( _chunkEGFUVXKKcjs.realPresenceClock));
3306
+ this.queue = new (0, _chunkEGFUVXKKcjs.PerformanceQueue)(presence, { clock: this.clock, linger: options.linger });
3307
+ }
3308
+
3309
+
3310
+
3311
+
3312
+
3313
+ /** Acts out `commands` in order for `actor`. Resolves with one result per command. */
3314
+ perform(actor, commands) {
3315
+ return this.queue.run(actor, async () => {
3316
+ const results = [];
3317
+ for (const command of commands) {
3318
+ try {
3319
+ results.push({ ok: true, command, result: await this.performOne(actor.id, command) });
3320
+ } catch (error) {
3321
+ results.push({ ok: false, command, message: error instanceof Error ? error.message : String(error) });
3322
+ }
3323
+ }
3324
+ return results;
3325
+ });
3326
+ }
3327
+ ms(n) {
3328
+ return Math.round(n / Math.max(0.1, _nullishCoalesce(this.options.speed, () => ( 1))));
3329
+ }
3330
+ where(id) {
3331
+ const a = this.presence.get(id);
3332
+ return { x: _nullishCoalesce(_optionalChain([a, 'optionalAccess', _91 => _91.x]), () => ( 0)), y: _nullishCoalesce(_optionalChain([a, 'optionalAccess', _92 => _92.y]), () => ( 0)) };
3333
+ }
3334
+ /** Glides to `to`; an actor that just appeared starts there instead of the corner. */
3335
+ async glide(id, to, ms = 380) {
3336
+ const a = this.presence.get(id);
3337
+ if (!a || a.x === 0 && a.y === 0) {
3338
+ this.presence.set({ id, x: to.x, y: to.y });
3339
+ return;
3340
+ }
3341
+ await _chunkEGFUVXKKcjs.tweenPresenceCursor.call(void 0, this.presence, this.clock, id, this.where(id), to, this.ms(ms));
3342
+ }
3343
+ async say(id, text, ms) {
3344
+ if (!text) return;
3345
+ this.presence.set({ id, message: text });
3346
+ await this.clock.wait(this.ms(ms));
3347
+ }
3348
+ async performOne(id, command) {
3349
+ const c = this.controller;
3350
+ switch (command.kind) {
3351
+ case "say":
3352
+ await this.say(id, command.text, 900);
3353
+ return void 0;
3354
+ case "point":
3355
+ await this.say(id, command.note, 500);
3356
+ await this.glide(id, command.at);
3357
+ this.presence.set({ id, pressed: true });
3358
+ await this.clock.wait(this.ms(110));
3359
+ this.presence.set({ id, pressed: false });
3360
+ return void 0;
3361
+ case "stroke":
3362
+ await this.say(id, command.note, 500);
3363
+ return this.stroke(id, command.stroke);
3364
+ case "fill": {
3365
+ await this.say(id, command.note, 500);
3366
+ const { width, height } = c.getState().document.canvas;
3367
+ const path = sweepPath({ x: 0, y: 0, width, height });
3368
+ await this.glide(id, path[0]);
3369
+ this.presence.set({ id, pressed: true });
3370
+ try {
3371
+ for (let i = 1; i < path.length; i++) await _chunkEGFUVXKKcjs.tweenPresenceCursor.call(void 0, this.presence, this.clock, id, path[i - 1], path[i], this.ms(i % 2 ? 260 : 90));
3372
+ } finally {
3373
+ this.presence.set({ id, pressed: false });
3374
+ }
3375
+ return c.fillLayer(command.fill);
3376
+ }
3377
+ case "replay": {
3378
+ await this.say(id, command.note, 500);
3379
+ const source = c.getStrokes().filter((s) => _optionalChain([command, 'access', _93 => _93.replay, 'access', _94 => _94.strokeIds, 'optionalAccess', _95 => _95.includes, 'call', _96 => _96(s.id)]));
3380
+ const first = _optionalChain([source, 'access', _97 => _97[0], 'optionalAccess', _98 => _98.points, 'access', _99 => _99[0]]);
3381
+ if (first) await this.glide(id, first);
3382
+ const result = c.replayStrokes(command.replay);
3383
+ if (result.bounds) await this.glide(id, centre(result.bounds), 520);
3384
+ return result;
3385
+ }
3386
+ }
3387
+ }
3388
+ /** Paints a stroke live: begins it, pushes its points frame by frame as the cursor reaches them, then ends it (one undo step). */
3389
+ async stroke(id, init) {
3390
+ const c = this.controller;
3391
+ const points = c.checkPoints(init.points);
3392
+ const { points: _points, ...rest } = init;
3393
+ const session = c.beginStroke({ snapToPerspective: false, start: points[0], ...rest });
3394
+ try {
3395
+ await this.glide(id, points[0]);
3396
+ this.presence.set({ id, pressed: true });
3397
+ const at = strokeSchedule(points);
3398
+ const duration = this.ms(strokeDuration(points, this.options.maxStrokeMs));
3399
+ let next = 0;
3400
+ const frames = Math.max(1, Math.round(duration / FRAME));
3401
+ for (let f = 1; f <= frames; f++) {
3402
+ const t = f / frames;
3403
+ const from = next;
3404
+ while (next < points.length && at[next] <= t + 1e-9) next++;
3405
+ if (next > from) {
3406
+ session.push(points.slice(from, next));
3407
+ const p = points[next - 1];
3408
+ this.presence.set({ id, x: p.x, y: p.y });
3409
+ }
3410
+ if (f < frames) await this.clock.wait(duration / frames);
3411
+ }
3412
+ if (next < points.length) session.push(points.slice(next));
3413
+ this.presence.set({ id, pressed: false });
3414
+ return session.end();
3415
+ } catch (error) {
3416
+ if (c.activeStroke === session) session.cancel();
3417
+ this.presence.set({ id, pressed: false });
3418
+ throw error;
3419
+ }
3420
+ }
3421
+ };
3422
+
3237
3423
  // src/paint-editor/guide-tools.ts
3238
3424
  var READ = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
3239
3425
  var WRITE = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
@@ -3554,7 +3740,7 @@ function createPaintGuideTools(c) {
3554
3740
  const pad = c.mixingPad;
3555
3741
  return {
3556
3742
  content: [
3557
- { type: "image", data: _chunkWSTEXEKDcjs.bytesToBase64.call(void 0, _chunkWSTEXEKDcjs.encodePng.call(void 0, pad.width, pad.height, pad.pixels())), mimeType: "image/png" },
3743
+ { type: "image", data: _chunkT3QZ6S47cjs.bytesToBase64.call(void 0, _chunkT3QZ6S47cjs.encodePng.call(void 0, pad.width, pad.height, pad.pixels())), mimeType: "image/png" },
3558
3744
  { type: "text", text: `Mixing pad ${pad.width}\xD7${pad.height}` }
3559
3745
  ]
3560
3746
  };
@@ -3575,7 +3761,7 @@ var TIP = {
3575
3761
  type: "object",
3576
3762
  description: "The tip (the shared brush engine). Missing fields keep their current values.",
3577
3763
  properties: {
3578
- size: { type: "number", minimum: 1, maximum: _chunkPV42JITTcjs.MAX_BRUSH_SIZE, description: "Diameter in document pixels." },
3764
+ size: { type: "number", minimum: 1, maximum: _chunkHUFQD4CBcjs.MAX_BRUSH_SIZE, description: "Diameter in document pixels." },
3579
3765
  hardness: { type: "number", minimum: 0, maximum: 1, description: "Edge hardness, 0 (soft) .. 1 (hard)." },
3580
3766
  spacing: { type: "number", minimum: 0.01, maximum: 10, description: "Dab spacing as a fraction of the diameter (0.05 is smooth, 1 is dotted)." },
3581
3767
  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." },
@@ -3585,7 +3771,11 @@ var TIP = {
3585
3771
  smoothing: { type: "number", minimum: 0, maximum: 0.95, description: "Position smoothing of the input, 0..0.95." },
3586
3772
  pressureSize: { type: "boolean", description: "Pressure scales the size (down to dynamics.minSize)." },
3587
3773
  pressureOpacity: { type: "boolean", description: "Pressure scales the opacity." },
3588
- blend: { type: "string", enum: _chunkCRMAXIUVcjs.BLEND_MODES.map((m) => m.id), description: "How paint combines with the layer. pigment mixes it in like real paint (blue into yellow gives green); multiply darkens like marker ink." }
3774
+ blend: {
3775
+ type: "string",
3776
+ enum: _chunkSZ6KMZNMcjs.BLEND_MODES.map((m) => m.id),
3777
+ 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)."
3778
+ }
3589
3779
  },
3590
3780
  additionalProperties: false
3591
3781
  };
@@ -3616,7 +3806,7 @@ var MIXER = {
3616
3806
  mix: { type: "number", minimum: 0, maximum: 1, description: "How far each dab's paint moves from the reservoir towards the picked-up colour." },
3617
3807
  loadEachStroke: { type: "boolean", description: "Refill the reservoir with the colour before each stroke." },
3618
3808
  cleanEachStroke: { type: "boolean", description: "Empty the pickup well after each stroke." },
3619
- mixing: { type: "string", enum: [..._chunkPV42JITTcjs.MIXING_MODELS], description: "rgb: RGB averages. pigment: mixes like paint (Kubelka-Munk)." }
3809
+ mixing: { type: "string", enum: [..._chunkHUFQD4CBcjs.MIXING_MODELS], description: "rgb: RGB averages. pigment: mixes like paint (Kubelka-Munk)." }
3620
3810
  },
3621
3811
  additionalProperties: false
3622
3812
  };
@@ -3665,6 +3855,12 @@ function createPaintEditorToolProvider(controller, options = {}) {
3665
3855
  const c = controller;
3666
3856
  const tools = [];
3667
3857
  const add = (t) => tools.push(t);
3858
+ const act = async (command, direct) => {
3859
+ if (!options.director) return direct();
3860
+ const [r] = await options.director.perform(_nullishCoalesce(options.actor, () => ( { id: "agent", name: "Agent" })), [command]);
3861
+ if (!r || !r.ok) throw new Error(r && !r.ok ? r.message : "The director did not run the command.");
3862
+ return r.result;
3863
+ };
3668
3864
  add({
3669
3865
  name: "get_canvas_info",
3670
3866
  title: "Get the canvas",
@@ -3689,7 +3885,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
3689
3885
  strokes: d.strokes.length,
3690
3886
  undo: s.undoLabel,
3691
3887
  redo: s.redoLabel,
3692
- blendModes: _chunkCRMAXIUVcjs.BLEND_MODES.map((m) => m.id)
3888
+ blendModes: _chunkSZ6KMZNMcjs.BLEND_MODES.map((m) => m.id)
3693
3889
  };
3694
3890
  }
3695
3891
  });
@@ -3820,7 +4016,11 @@ function createPaintEditorToolProvider(controller, options = {}) {
3820
4016
  name: { type: "string", minLength: 1, description: "New name." },
3821
4017
  visible: { type: "boolean", description: "Show or hide." },
3822
4018
  opacity: { type: "number", minimum: 0, maximum: 1, description: "Layer opacity 0..1." },
3823
- blend: { type: "string", enum: [..._chunkCRMAXIUVcjs.BLEND_MODES.map((m) => m.id), "pass-through"], description: "Blend mode (pass-through for groups only)." },
4019
+ blend: {
4020
+ type: "string",
4021
+ enum: [..._chunkSZ6KMZNMcjs.BLEND_MODES.map((m) => m.id), "pass-through"],
4022
+ description: "Blend mode (pass-through for groups only). Painterly modes: watercolor (the layer glazes like a transparent wash), tint (recolours keeping lightness), highlight (adds soft coloured light), shadow (shades with ambient fill); see list_blend_modes."
4023
+ },
3824
4024
  clipped: { type: "boolean", description: "Clip to the layer below (paint only shows where it has paint)." },
3825
4025
  locks: {
3826
4026
  type: "object",
@@ -3840,6 +4040,22 @@ function createPaintEditorToolProvider(controller, options = {}) {
3840
4040
  annotations: { title: "Change a layer", ...SET2 },
3841
4041
  handler: ({ layerId, ...u }) => c.updateLayer(layerId, u)
3842
4042
  });
4043
+ add({
4044
+ name: "list_blend_modes",
4045
+ title: "List blend modes",
4046
+ description: "Lists every layer and brush blend mode: id, label, group (standard Photoshop modes, pigment, or painterly), what the pigment and painterly modes do, and the standard mode PSD export writes in their place. Changes nothing. Read it before choosing a painterly mode for update_layer or a brush tip.",
4047
+ inputSchema: EMPTY2,
4048
+ annotations: { title: "List blend modes", ...READ2 },
4049
+ handler: () => ({
4050
+ modes: _chunkSZ6KMZNMcjs.BLEND_MODES.map((m) => ({
4051
+ id: m.id,
4052
+ label: m.label,
4053
+ group: m.painterly ? "painterly" : m.id === "pigment" ? "pigment" : "standard",
4054
+ ...m.description ? { description: m.description } : {},
4055
+ psd: _chunkSZ6KMZNMcjs.standardBlendMode.call(void 0, m.id)
4056
+ }))
4057
+ })
4058
+ });
3843
4059
  add({
3844
4060
  name: "set_active_layer",
3845
4061
  title: "Choose the active layer",
@@ -3904,12 +4120,12 @@ function createPaintEditorToolProvider(controller, options = {}) {
3904
4120
  opacity: { type: "number", minimum: 0, maximum: 1, description: "Opacity 0..1 (default 1)." },
3905
4121
  grain: { type: "number", minimum: 0, maximum: 1, description: "Paper grain response 0..1 (default 0: flat)." },
3906
4122
  pressure: { type: "number", minimum: 0, maximum: 1, description: "With grain: how far into the valleys, 0..1 (default 0.5)." },
3907
- blend: { type: "string", enum: _chunkCRMAXIUVcjs.BLEND_MODES.map((m) => m.id), description: "Blend mode (default normal; pigment mixes like paint)." }
4123
+ blend: { type: "string", enum: _chunkSZ6KMZNMcjs.BLEND_MODES.map((m) => m.id), description: "Blend mode (default normal; pigment mixes like paint, watercolor glazes; see list_blend_modes)." }
3908
4124
  },
3909
4125
  additionalProperties: false
3910
4126
  },
3911
4127
  annotations: { title: "Fill a layer", ...WRITE2 },
3912
- handler: (a) => c.fillLayer(a)
4128
+ handler: (a) => act({ kind: "fill", fill: a }, () => c.fillLayer(a))
3913
4129
  });
3914
4130
  add({
3915
4131
  name: "clear_layer",
@@ -3927,7 +4143,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
3927
4143
  annotations: { title: "List brushes", ...READ2 },
3928
4144
  handler: () => {
3929
4145
  const s = c.getState();
3930
- return { activeBrushId: s.brush.id, activeEdited: !s.brush.builtin && Boolean(_optionalChain([c, 'access', _81 => _81.getBrush, 'call', _82 => _82(s.brush.id), 'optionalAccess', _83 => _83.builtin])), brushes: s.brushes.map(brushSummary) };
4146
+ return { activeBrushId: s.brush.id, activeEdited: !s.brush.builtin && Boolean(_optionalChain([c, 'access', _100 => _100.getBrush, 'call', _101 => _101(s.brush.id), 'optionalAccess', _102 => _102.builtin])), brushes: s.brushes.map(brushSummary) };
3931
4147
  }
3932
4148
  });
3933
4149
  add({
@@ -4025,7 +4241,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
4025
4241
  const t = c.brushThumbnail(_nullishCoalesce(id, () => ( c.getState().brush.id)), { width, height, color });
4026
4242
  return {
4027
4243
  content: [
4028
- { type: "image", data: _chunkWSTEXEKDcjs.bytesToBase64.call(void 0, _chunkWSTEXEKDcjs.encodePng.call(void 0, t.width, t.height, t.data)), mimeType: "image/png" },
4244
+ { type: "image", data: _chunkT3QZ6S47cjs.bytesToBase64.call(void 0, _chunkT3QZ6S47cjs.encodePng.call(void 0, t.width, t.height, t.data)), mimeType: "image/png" },
4029
4245
  { type: "text", text: `Brush ${_nullishCoalesce(id, () => ( c.getState().brush.id))} ${t.width}\xD7${t.height}` }
4030
4246
  ]
4031
4247
  };
@@ -4092,7 +4308,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
4092
4308
  add({
4093
4309
  name: "paint_stroke",
4094
4310
  title: "Paint a brush stroke",
4095
- 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, blender, smudge) picks up and moves paint already on the layer. 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. One undo step. Returns the layer id, changed bounds, dab count, the recorded strokeId (for replay_strokes) and, for the mixer, its load after the stroke.",
4311
+ 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, blender, smudge) picks up and moves paint already on the layer. 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) and, for the mixer, its load after the stroke.",
4096
4312
  inputSchema: {
4097
4313
  type: "object",
4098
4314
  properties: {
@@ -4108,8 +4324,9 @@ function createPaintEditorToolProvider(controller, options = {}) {
4108
4324
  additionalProperties: false
4109
4325
  },
4110
4326
  annotations: { title: "Paint a brush stroke", ...WRITE2 },
4111
- handler: (a) => {
4112
- const r = c.paintStroke({ points: a.points, layerId: a.layerId, brushId: a.brushId, brush: a.brush, color: a.color, seed: a.seed, snapToPerspective: a.snapToPerspective });
4327
+ handler: async (a) => {
4328
+ const stroke = { points: a.points, layerId: a.layerId, brushId: a.brushId, brush: a.brush, color: a.color, seed: a.seed, snapToPerspective: a.snapToPerspective };
4329
+ const r = await act({ kind: "stroke", stroke }, () => c.paintStroke(stroke));
4113
4330
  return r.mixerLoad ? { ...r, mixerLoad: loadResult(r.mixerLoad) } : r;
4114
4331
  }
4115
4332
  });
@@ -4146,7 +4363,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
4146
4363
  color: s.color,
4147
4364
  points: ids ? s.points : s.points.length,
4148
4365
  seed: s.seed,
4149
- copies: _nullishCoalesce(_optionalChain([s, 'access', _84 => _84.copies, 'optionalAccess', _85 => _85.length]), () => ( 0)),
4366
+ copies: _nullishCoalesce(_optionalChain([s, 'access', _103 => _103.copies, 'optionalAccess', _104 => _104.length]), () => ( 0)),
4150
4367
  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) }
4151
4368
  };
4152
4369
  })
@@ -4183,7 +4400,10 @@ function createPaintEditorToolProvider(controller, options = {}) {
4183
4400
  additionalProperties: false
4184
4401
  },
4185
4402
  annotations: { title: "Replay strokes, varied", ...WRITE2 },
4186
- handler: (a) => c.replayStrokes(a)
4403
+ handler: (a) => {
4404
+ const replay = a;
4405
+ return act({ kind: "replay", replay }, () => c.replayStrokes(replay));
4406
+ }
4187
4407
  });
4188
4408
  add({
4189
4409
  name: "set_view",
@@ -4276,18 +4496,18 @@ function createPaintEditorToolProvider(controller, options = {}) {
4276
4496
  annotations: { title: "Export the painting", ...READ2 },
4277
4497
  handler: async ({ format, quality, scale, paper }) => {
4278
4498
  const bytes = await c.exportImage({ format, quality, scale, paper });
4279
- return { mimeType: _nullishCoalesce(format, () => ( "image/png")), bytes: bytes.length, data: _chunkWSTEXEKDcjs.bytesToBase64.call(void 0, bytes) };
4499
+ return { mimeType: _nullishCoalesce(format, () => ( "image/png")), bytes: bytes.length, data: _chunkT3QZ6S47cjs.bytesToBase64.call(void 0, bytes) };
4280
4500
  }
4281
4501
  });
4282
4502
  add({
4283
4503
  name: "export_psd",
4284
4504
  title: "Export as PSD",
4285
- description: 'Writes the painting as an 8-bit RGB PSD (PSB above 30000 px) through the shared PSD writer: every layer and group with its opacity, blend, mask and locks, the paper as a locked "Paper" pixel layer at the bottom, and the composite as the merged image. Changes nothing. Returns the file as base64, its size, whether it is a PSB, and warnings (pigment blending has no PSD equivalent).',
4505
+ description: 'Writes the painting as an 8-bit RGB PSD (PSB above 30000 px) through the shared PSD writer: every layer and group with its opacity, blend, mask and locks, the paper as a locked "Paper" pixel layer at the bottom, and the composite as the merged image. Changes nothing. Returns the file as base64, its size, whether it is a PSB, and warnings (pigment and painterly blend modes have no PSD equivalent: they are written as the nearest standard mode, see list_blend_modes).',
4286
4506
  inputSchema: EMPTY2,
4287
4507
  annotations: { title: "Export as PSD", ...READ2 },
4288
4508
  handler: () => {
4289
4509
  const r = c.exportPsd();
4290
- return { data: _chunkWSTEXEKDcjs.bytesToBase64.call(void 0, r.bytes), bytes: r.bytes.length, psb: r.psb, warnings: r.warnings };
4510
+ return { data: _chunkT3QZ6S47cjs.bytesToBase64.call(void 0, r.bytes), bytes: r.bytes.length, psb: r.psb, warnings: r.warnings };
4291
4511
  }
4292
4512
  });
4293
4513
  add({
@@ -4311,7 +4531,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
4311
4531
  }
4312
4532
  });
4313
4533
  tools.push(...createPaintGuideTools(c));
4314
- tools.push(..._chunkPV42JITTcjs.createPigmentTools.call(void 0, ));
4534
+ tools.push(..._chunkHUFQD4CBcjs.createPigmentTools.call(void 0, ));
4315
4535
  return { id: _nullishCoalesce(options.id, () => ( "paint-editor")), namespace: options.namespace, tools };
4316
4536
  }
4317
4537
 
@@ -4417,12 +4637,12 @@ var PaintGesture = (_class10 = class {
4417
4637
  if (!m || m.pointerId !== e.pointerId) return;
4418
4638
  this.mode = null;
4419
4639
  this.predicted = [];
4420
- if (m.kind === "stroke") _optionalChain([this, 'access', _86 => _86.controller, 'access', _87 => _87.activeStroke, 'optionalAccess', _88 => _88.end, 'call', _89 => _89()]);
4640
+ if (m.kind === "stroke") _optionalChain([this, 'access', _105 => _105.controller, 'access', _106 => _106.activeStroke, 'optionalAccess', _107 => _107.end, 'call', _108 => _108()]);
4421
4641
  }
4422
4642
  cancel() {
4423
4643
  this.penDown = false;
4424
4644
  this.predicted = [];
4425
- if (_optionalChain([this, 'access', _90 => _90.mode, 'optionalAccess', _91 => _91.kind]) === "stroke") _optionalChain([this, 'access', _92 => _92.controller, 'access', _93 => _93.activeStroke, 'optionalAccess', _94 => _94.cancel, 'call', _95 => _95()]);
4645
+ if (_optionalChain([this, 'access', _109 => _109.mode, 'optionalAccess', _110 => _110.kind]) === "stroke") _optionalChain([this, 'access', _111 => _111.controller, 'access', _112 => _112.activeStroke, 'optionalAccess', _113 => _113.cancel, 'call', _114 => _114()]);
4426
4646
  this.mode = null;
4427
4647
  }
4428
4648
  get active() {
@@ -4506,11 +4726,11 @@ var PaintCanvasPresenter = (_class11 = class {
4506
4726
  const key = `${tx},${ty}`;
4507
4727
  if (this.uploaded.get(key) === data) return;
4508
4728
  this.uploaded.set(key, data);
4509
- if (!this.scratch) this.scratch = ctx.createImageData(_chunkCRMAXIUVcjs.TILE, _chunkCRMAXIUVcjs.TILE);
4729
+ if (!this.scratch) this.scratch = ctx.createImageData(_chunkSZ6KMZNMcjs.TILE, _chunkSZ6KMZNMcjs.TILE);
4510
4730
  this.scratch.data.set(data);
4511
- const ox = tx * _chunkCRMAXIUVcjs.TILE;
4512
- const oy = ty * _chunkCRMAXIUVcjs.TILE;
4513
- ctx.putImageData(this.scratch, ox, oy, 0, 0, Math.min(_chunkCRMAXIUVcjs.TILE, width - ox), Math.min(_chunkCRMAXIUVcjs.TILE, height - oy));
4731
+ const ox = tx * _chunkSZ6KMZNMcjs.TILE;
4732
+ const oy = ty * _chunkSZ6KMZNMcjs.TILE;
4733
+ ctx.putImageData(this.scratch, ox, oy, 0, 0, Math.min(_chunkSZ6KMZNMcjs.TILE, width - ox), Math.min(_chunkSZ6KMZNMcjs.TILE, height - oy));
4514
4734
  drawn++;
4515
4735
  }, { dirty });
4516
4736
  return drawn;
@@ -4550,7 +4770,7 @@ var PAPER_SLIDERS = [
4550
4770
  ];
4551
4771
  function readPath(obj, path) {
4552
4772
  let v = obj;
4553
- for (const k of path.split(".")) v = _optionalChain([v, 'optionalAccess', _96 => _96[k]]);
4773
+ for (const k of path.split(".")) v = _optionalChain([v, 'optionalAccess', _115 => _115[k]]);
4554
4774
  return typeof v === "number" ? v : 0;
4555
4775
  }
4556
4776
  function patchPath(obj, path, value) {
@@ -4591,6 +4811,19 @@ function wheelPick(dx, dy, wheel, color) {
4591
4811
  const [nr, ng, nb] = hsvToRgb(wheelToHue(wheelAngle(dx, dy), wheel), s || 1, v || 1);
4592
4812
  return rgbToHexColor(nr, ng, nb);
4593
4813
  }
4814
+ var BLEND_MENU_GROUPS = [
4815
+ { label: "Standard", modes: _chunkSZ6KMZNMcjs.BLEND_MODES.filter((m) => !m.painterly && m.id !== "pigment") },
4816
+ { label: "Paint", modes: _chunkSZ6KMZNMcjs.BLEND_MODES.filter((m) => m.painterly || m.id === "pigment") }
4817
+ ];
4818
+
4819
+
4820
+
4821
+
4822
+
4823
+
4824
+
4825
+
4826
+
4594
4827
 
4595
4828
 
4596
4829
 
@@ -4729,5 +4962,5 @@ function wheelPick(dx, dy, wheel, color) {
4729
4962
 
4730
4963
 
4731
4964
 
4732
- exports.BLEND_MODES = _chunkCRMAXIUVcjs.BLEND_MODES; exports.BRUSH_ID = BRUSH_ID; exports.BRUSH_ROTATIONS = BRUSH_ROTATIONS; exports.BRUSH_SLIDERS = BRUSH_SLIDERS; exports.BUILTIN_BRUSHES = BUILTIN_BRUSHES; exports.DEFAULT_BRUSH_ID = DEFAULT_BRUSH_ID; exports.DEFAULT_DPI = DEFAULT_DPI; exports.DEFAULT_DYNAMICS = DEFAULT_DYNAMICS; exports.DEFAULT_PAPER = DEFAULT_PAPER; exports.DEFAULT_SWATCHES = DEFAULT_SWATCHES; exports.DEFAULT_VIEW = DEFAULT_VIEW; exports.DryStroke = DryStroke; exports.GRAIN_PATTERNS = GRAIN_PATTERNS; exports.GRAIN_TILE = GRAIN_TILE; exports.HARMONY_KINDS = HARMONY_KINDS; exports.IDENTITY_AFFINE = IDENTITY_AFFINE; exports.IDENTITY_COPY = IDENTITY_COPY; exports.MAX_BRUSH_SIZE = _chunkPV42JITTcjs.MAX_BRUSH_SIZE; exports.MAX_CANVAS_SIDE = MAX_CANVAS_SIDE; exports.MAX_COORDINATE = MAX_COORDINATE; exports.MAX_IMAGE_SIDE = MAX_IMAGE_SIDE; exports.MAX_ZOOM = MAX_ZOOM; exports.MIN_CANVAS_SIDE = MIN_CANVAS_SIDE; exports.MIN_ZOOM = MIN_ZOOM; exports.MIXING_PAD_HEIGHT = MIXING_PAD_HEIGHT; exports.MIXING_PAD_WIDTH = MIXING_PAD_WIDTH; exports.MixingPad = MixingPad; exports.PAINT_BRUSH_CATEGORIES = PAINT_BRUSH_CATEGORIES; exports.PAINT_BRUSH_ENGINES = PAINT_BRUSH_ENGINES; exports.PAINT_FORMAT = PAINT_FORMAT; exports.PAINT_SCHEMA_VERSION = PAINT_SCHEMA_VERSION; exports.PAINT_TOOLS = PAINT_TOOLS; exports.PAPER_FAMILIES = PAPER_FAMILIES; exports.PAPER_LIBRARY = PAPER_LIBRARY; exports.PAPER_NODE_ID = PAPER_NODE_ID; exports.PAPER_SLIDERS = PAPER_SLIDERS; exports.PaintCanvasPresenter = PaintCanvasPresenter; exports.PaintDocumentError = PaintDocumentError; exports.PaintEditorController = PaintEditorController; exports.PaintEditorError = PaintEditorError; exports.PaintGesture = PaintGesture; exports.PaintStrokeSession = PaintStrokeSession; exports.PaperGrain = PaperGrain; exports.PenDabWalker = PenDabWalker; exports.PenSmoother = PenSmoother; exports.PerspectiveSnapper = PerspectiveSnapper; exports.SNAP_DECIDE_DISTANCE = SNAP_DECIDE_DISTANCE; exports.SYMMETRY_MODES = SYMMETRY_MODES; exports.TRACING_NODE_ID = TRACING_NODE_ID; exports.TileableNoise = TileableNoise; exports.affineCopy = affineCopy; exports.applyAffine = applyAffine; exports.brushToJSON = brushToJSON; exports.clonePaper = clonePaper; exports.colorHarmony = colorHarmony; exports.composeAffine = composeAffine; exports.createPaintCompositor = createPaintCompositor; exports.createPaintDocument = createPaintDocument; exports.createPaintEditorToolProvider = createPaintEditorToolProvider; exports.createPaintLayer = createPaintLayer; exports.decodeImageBlob = decodeImageBlob; exports.defaultGuides = defaultGuides; exports.defaultImageEncoder = defaultImageEncoder; exports.deserializePaintDocument = deserializePaintDocument; exports.deserializePaintDocumentAsync = deserializePaintDocumentAsync; exports.documentExtensions = documentExtensions; exports.documentToScreen = documentToScreen; exports.downloadBytes = downloadBytes; exports.downsampleRgba = downsampleRgba; exports.fitZoom = fitZoom; exports.grainCatch = grainCatch; exports.grainHeights = grainHeights; exports.guideOverlay = guideOverlay; exports.handlePaintShortcut = handlePaintShortcut; exports.hash2 = hash2; exports.hexToRgb8 = hexToRgb8; exports.hslToRgb = hslToRgb; exports.hsvToRgb = hsvToRgb; exports.hueToWheel = hueToWheel; exports.invertAffine = invertAffine; exports.isBlendMode = _chunkCRMAXIUVcjs.isBlendMode; exports.isPalmTouch = isPalmTouch; exports.mapPenPoint = mapPenPoint; exports.mix32 = mix32; exports.mixerLoadForStroke = mixerLoadForStroke; exports.mixerTip = mixerTip; exports.newPaintLayerId = newPaintLayerId; exports.normalizeBrushStroke = normalizeBrushStroke; exports.normalizeCanvas = normalizeCanvas; exports.normalizeDynamics = normalizeDynamics; exports.normalizePaintBrush = normalizePaintBrush; exports.normalizePaper = normalizePaper; exports.normalizePerspective = normalizePerspective; exports.normalizeRotation = normalizeRotation; exports.normalizeSymmetry = normalizeSymmetry; exports.normalizeView = normalizeView; exports.paperGrain = paperGrain; exports.paperKey = paperKey; exports.paperNode = paperNode; exports.paperPreset = paperPreset; exports.parseBrushLibrary = parseBrushLibrary; exports.parseHexColor = parseHexColor; exports.patchPath = patchPath; exports.penOrientation = penOrientation; exports.perspectiveDirections = perspectiveDirections; exports.perspectiveGuideLines = perspectiveGuideLines; exports.pointerToPenPoint = pointerToPenPoint; exports.rand01 = rand01; exports.randSigned = randSigned; exports.readPath = readPath; exports.renderBrushThumbnail = renderBrushThumbnail; exports.renderColorWheel = renderColorWheel; exports.renderPaper = renderPaper; exports.rgbToHexColor = rgbToHexColor; exports.rgbToHsl = rgbToHsl; exports.rgbToHsv = rgbToHsv; exports.samplePressure = samplePressure; exports.screenToDocument = screenToDocument; exports.seedFromString = seedFromString; exports.serializePaintDocument = serializePaintDocument; exports.serializePaintDocumentExternal = serializePaintDocumentExternal; exports.strokeBounds = strokeBounds; exports.symmetryAxisAngles = symmetryAxisAngles; exports.symmetryAxisSegments = symmetryAxisSegments; exports.symmetryCopies = symmetryCopies; exports.thumbnailStroke = thumbnailStroke; exports.tiltToOrientation = tiltToOrientation; exports.toStrokePoint = toStrokePoint; exports.variationAffine = variationAffine; exports.varyStroke = varyStroke; exports.viewCssTransform = viewCssTransform; exports.viewMatrix = viewMatrix; exports.viewPenToDocument = viewPenToDocument; exports.wheelAngle = wheelAngle; exports.wheelPick = wheelPick; exports.wheelPoint = wheelPoint; exports.wheelToHue = wheelToHue;
4965
+ exports.BLEND_MENU_GROUPS = BLEND_MENU_GROUPS; exports.BLEND_MODES = _chunkSZ6KMZNMcjs.BLEND_MODES; exports.BRUSH_ID = BRUSH_ID; exports.BRUSH_ROTATIONS = BRUSH_ROTATIONS; exports.BRUSH_SLIDERS = BRUSH_SLIDERS; exports.BUILTIN_BRUSHES = BUILTIN_BRUSHES; exports.DEFAULT_BRUSH_ID = DEFAULT_BRUSH_ID; exports.DEFAULT_DPI = DEFAULT_DPI; exports.DEFAULT_DYNAMICS = DEFAULT_DYNAMICS; exports.DEFAULT_PAPER = DEFAULT_PAPER; exports.DEFAULT_SWATCHES = DEFAULT_SWATCHES; exports.DEFAULT_VIEW = DEFAULT_VIEW; exports.DryStroke = DryStroke; exports.GRAIN_PATTERNS = GRAIN_PATTERNS; exports.GRAIN_TILE = GRAIN_TILE; exports.HARMONY_KINDS = HARMONY_KINDS; exports.IDENTITY_AFFINE = IDENTITY_AFFINE; exports.IDENTITY_COPY = IDENTITY_COPY; exports.MAX_BRUSH_SIZE = _chunkHUFQD4CBcjs.MAX_BRUSH_SIZE; exports.MAX_CANVAS_SIDE = MAX_CANVAS_SIDE; exports.MAX_COORDINATE = MAX_COORDINATE; exports.MAX_IMAGE_SIDE = MAX_IMAGE_SIDE; exports.MAX_ZOOM = MAX_ZOOM; exports.MIN_CANVAS_SIDE = MIN_CANVAS_SIDE; exports.MIN_ZOOM = MIN_ZOOM; exports.MIXING_PAD_HEIGHT = MIXING_PAD_HEIGHT; exports.MIXING_PAD_WIDTH = MIXING_PAD_WIDTH; exports.MixingPad = MixingPad; exports.PAINTERLY_BLEND_MODES = _chunkSZ6KMZNMcjs.PAINTERLY_BLEND_MODES; exports.PAINT_BRUSH_CATEGORIES = PAINT_BRUSH_CATEGORIES; exports.PAINT_BRUSH_ENGINES = PAINT_BRUSH_ENGINES; exports.PAINT_FORMAT = PAINT_FORMAT; exports.PAINT_SCHEMA_VERSION = PAINT_SCHEMA_VERSION; exports.PAINT_TOOLS = PAINT_TOOLS; exports.PAPER_FAMILIES = PAPER_FAMILIES; exports.PAPER_LIBRARY = PAPER_LIBRARY; exports.PAPER_NODE_ID = PAPER_NODE_ID; exports.PAPER_SLIDERS = PAPER_SLIDERS; exports.PaintCanvasPresenter = PaintCanvasPresenter; exports.PaintDirector = PaintDirector; exports.PaintDocumentError = PaintDocumentError; exports.PaintEditorController = PaintEditorController; exports.PaintEditorError = PaintEditorError; exports.PaintGesture = PaintGesture; exports.PaintPresence = PaintPresence; exports.PaintStrokeSession = PaintStrokeSession; exports.PaperGrain = PaperGrain; exports.PenDabWalker = PenDabWalker; exports.PenSmoother = PenSmoother; exports.PerspectiveSnapper = PerspectiveSnapper; exports.SNAP_DECIDE_DISTANCE = SNAP_DECIDE_DISTANCE; exports.SYMMETRY_MODES = SYMMETRY_MODES; exports.TRACING_NODE_ID = TRACING_NODE_ID; exports.TileableNoise = TileableNoise; exports.affineCopy = affineCopy; exports.applyAffine = applyAffine; exports.brushToJSON = brushToJSON; exports.clonePaper = clonePaper; exports.colorHarmony = colorHarmony; exports.composeAffine = composeAffine; exports.createPaintCompositor = createPaintCompositor; exports.createPaintDocument = createPaintDocument; exports.createPaintEditorToolProvider = createPaintEditorToolProvider; exports.createPaintLayer = createPaintLayer; exports.decodeImageBlob = decodeImageBlob; exports.defaultGuides = defaultGuides; exports.defaultImageEncoder = defaultImageEncoder; exports.deserializePaintDocument = deserializePaintDocument; exports.deserializePaintDocumentAsync = deserializePaintDocumentAsync; exports.documentExtensions = documentExtensions; exports.documentToScreen = documentToScreen; exports.downloadBytes = downloadBytes; exports.downsampleRgba = downsampleRgba; exports.fitZoom = fitZoom; exports.grainCatch = grainCatch; exports.grainHeights = grainHeights; exports.guideOverlay = guideOverlay; exports.handlePaintShortcut = handlePaintShortcut; exports.hash2 = hash2; exports.hexToRgb8 = hexToRgb8; exports.hslToRgb = hslToRgb; exports.hsvToRgb = hsvToRgb; exports.hueToWheel = hueToWheel; exports.invertAffine = invertAffine; exports.isBlendMode = _chunkSZ6KMZNMcjs.isBlendMode; exports.isPainterlyBlendMode = _chunkSZ6KMZNMcjs.isPainterlyBlendMode; exports.isPalmTouch = isPalmTouch; exports.mapPenPoint = mapPenPoint; exports.mix32 = mix32; exports.mixerLoadForStroke = mixerLoadForStroke; exports.mixerTip = mixerTip; exports.newPaintLayerId = newPaintLayerId; exports.normalizeBrushStroke = normalizeBrushStroke; exports.normalizeCanvas = normalizeCanvas; exports.normalizeDynamics = normalizeDynamics; exports.normalizePaintBrush = normalizePaintBrush; exports.normalizePaper = normalizePaper; exports.normalizePerspective = normalizePerspective; exports.normalizeRotation = normalizeRotation; exports.normalizeSymmetry = normalizeSymmetry; exports.normalizeView = normalizeView; exports.paperGrain = paperGrain; exports.paperKey = paperKey; exports.paperNode = paperNode; exports.paperPreset = paperPreset; exports.parseBrushLibrary = parseBrushLibrary; exports.parseHexColor = parseHexColor; exports.patchPath = patchPath; exports.penOrientation = penOrientation; exports.perspectiveDirections = perspectiveDirections; exports.perspectiveGuideLines = perspectiveGuideLines; exports.pointerToPenPoint = pointerToPenPoint; exports.rand01 = rand01; exports.randSigned = randSigned; exports.readPath = readPath; exports.renderBrushThumbnail = renderBrushThumbnail; exports.renderColorWheel = renderColorWheel; exports.renderPaper = renderPaper; exports.rgbToHexColor = rgbToHexColor; exports.rgbToHsl = rgbToHsl; exports.rgbToHsv = rgbToHsv; exports.samplePressure = samplePressure; exports.screenToDocument = screenToDocument; exports.seedFromString = seedFromString; exports.serializePaintDocument = serializePaintDocument; exports.serializePaintDocumentExternal = serializePaintDocumentExternal; exports.standardBlendMode = _chunkSZ6KMZNMcjs.standardBlendMode; exports.strokeBounds = strokeBounds; exports.strokeDuration = strokeDuration; exports.strokeSchedule = strokeSchedule; exports.sweepPath = sweepPath; exports.symmetryAxisAngles = symmetryAxisAngles; exports.symmetryAxisSegments = symmetryAxisSegments; exports.symmetryCopies = symmetryCopies; exports.thumbnailStroke = thumbnailStroke; exports.tiltToOrientation = tiltToOrientation; exports.toStrokePoint = toStrokePoint; exports.variationAffine = variationAffine; exports.varyStroke = varyStroke; exports.viewCssTransform = viewCssTransform; exports.viewMatrix = viewMatrix; exports.viewPenToDocument = viewPenToDocument; exports.wheelAngle = wheelAngle; exports.wheelPick = wheelPick; exports.wheelPoint = wheelPoint; exports.wheelToHue = wheelToHue;
4733
4966
  //# sourceMappingURL=index.cjs.map