@pixerate/editor 0.270.0 → 0.272.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 (77) hide show
  1. package/dist/animation-editor/index.cjs +62 -62
  2. package/dist/animation-editor/index.js +5 -5
  3. package/dist/brushes/index.cjs +69 -66
  4. package/dist/brushes/index.js +6 -3
  5. package/dist/brushes/patch.d.cts +1 -1
  6. package/dist/brushes/patch.d.ts +1 -1
  7. package/dist/brushes/schema.d.cts +1 -0
  8. package/dist/brushes/schema.d.ts +1 -0
  9. package/dist/brushes/types.d.cts +8 -0
  10. package/dist/brushes/types.d.ts +8 -0
  11. package/dist/{brushstrokeRender-WR2N5HHY.cjs → brushstrokeRender-5YBCLFDQ.cjs} +15 -15
  12. package/dist/{brushstrokeRender-A727TTNQ.js → brushstrokeRender-DZGFU3J4.js} +3 -3
  13. package/dist/canvas/index.cjs +15 -15
  14. package/dist/canvas/index.js +2 -2
  15. package/dist/{chunk-THBJHPUL.js → chunk-2F3YDXCN.js} +1 -1
  16. package/dist/{chunk-4CPOKP27.js → chunk-2XDNF73E.js} +1 -1
  17. package/dist/{chunk-3KNQ2W6X.cjs → chunk-3JKCREEU.cjs} +59 -53
  18. package/dist/{chunk-4YSPQGZW.js → chunk-5HP2VSAS.js} +1 -1
  19. package/dist/{chunk-BPJSI4NT.cjs → chunk-7W2EQQBP.cjs} +2 -2
  20. package/dist/{chunk-LETF75CA.js → chunk-CLB2I2FU.js} +1 -1
  21. package/dist/{chunk-BAZMCFVL.js → chunk-DZVRH63Y.js} +1 -1
  22. package/dist/{chunk-PY4GWSE2.cjs → chunk-EBFPMSJO.cjs} +27 -5
  23. package/dist/{chunk-VBRHE4AM.cjs → chunk-FXVCB6YG.cjs} +35 -35
  24. package/dist/{chunk-EU2ZZA6L.cjs → chunk-GHGBIAWQ.cjs} +126 -39
  25. package/dist/{chunk-CBVNCWJM.cjs → chunk-LBDC5434.cjs} +2 -2
  26. package/dist/{chunk-2WOGXEDX.cjs → chunk-M3RZOF3G.cjs} +1 -1
  27. package/dist/{chunk-GSTSZPSR.js → chunk-N3SKPQEH.js} +225 -18
  28. package/dist/{chunk-J5VQYK7T.cjs → chunk-N5IMDAHM.cjs} +251 -44
  29. package/dist/{chunk-ININNHLM.js → chunk-NAHJV3O6.js} +11 -5
  30. package/dist/{chunk-MWUZCEFT.js → chunk-S2XPXA47.js} +1 -1
  31. package/dist/{chunk-56RHCIJV.cjs → chunk-SNAFFCAX.cjs} +296 -203
  32. package/dist/{chunk-EHLOCVWB.js → chunk-T2URHAJX.js} +27 -5
  33. package/dist/{chunk-BENSE3VX.cjs → chunk-TNLKFW7D.cjs} +23 -23
  34. package/dist/{chunk-KZI3YWKW.js → chunk-UXYCY3HP.js} +93 -6
  35. package/dist/{chunk-4NMPUJUK.cjs → chunk-YJANF2BL.cjs} +86 -86
  36. package/dist/{chunk-FUDP5QBB.js → chunk-ZEI7ZEA4.js} +101 -8
  37. package/dist/effects/index.cjs +5 -2
  38. package/dist/effects/index.js +4 -1
  39. package/dist/effects/pool.d.cts +9 -0
  40. package/dist/effects/pool.d.ts +9 -0
  41. package/dist/effects/types.d.cts +2 -0
  42. package/dist/effects/types.d.ts +2 -0
  43. package/dist/image-editor/index.cjs +791 -791
  44. package/dist/image-editor/index.js +6 -6
  45. package/dist/paint/index.cjs +2 -2
  46. package/dist/paint/index.js +1 -1
  47. package/dist/paint/wet/world.d.cts +37 -1
  48. package/dist/paint/wet/world.d.ts +37 -1
  49. package/dist/paint-editor/brush-controls.d.cts +2 -0
  50. package/dist/paint-editor/brush-controls.d.ts +2 -0
  51. package/dist/paint-editor/brush-model.d.cts +14 -1
  52. package/dist/paint-editor/brush-model.d.ts +14 -1
  53. package/dist/paint-editor/controller.d.cts +75 -4
  54. package/dist/paint-editor/controller.d.ts +75 -4
  55. package/dist/paint-editor/effect-paint.d.cts +33 -8
  56. package/dist/paint-editor/effect-paint.d.ts +33 -8
  57. package/dist/paint-editor/effects.d.cts +4 -0
  58. package/dist/paint-editor/effects.d.ts +4 -0
  59. package/dist/paint-editor/index.cjs +814 -483
  60. package/dist/paint-editor/index.js +408 -77
  61. package/dist/paint-editor/stroke.d.cts +13 -5
  62. package/dist/paint-editor/stroke.d.ts +13 -5
  63. package/dist/paint-editor/ui.d.cts +1 -1
  64. package/dist/paint-editor/ui.d.ts +1 -1
  65. package/dist/paint-editor/wet.d.cts +8 -1
  66. package/dist/paint-editor/wet.d.ts +8 -1
  67. package/dist/vector/index.cjs +999 -999
  68. package/dist/vector/index.js +5 -5
  69. package/dist/video-editor/index.cjs +317 -317
  70. package/dist/video-editor/index.js +2 -2
  71. package/package.json +1 -1
  72. package/skills/pixerate-brushes/SKILL.md +1 -0
  73. package/skills/pixerate-paint-editor/SKILL.md +6 -13
  74. package/skills/pixerate-paint-editor/references/brush-facets.md +1 -0
  75. package/skills/pixerate-paint-editor/references/effect-paint.md +28 -6
  76. package/skills/pixerate-paint-editor/references/ghost.md +47 -0
  77. package/skills/pixerate-paint-watercolour/SKILL.md +1 -0
@@ -18,7 +18,7 @@
18
18
 
19
19
 
20
20
 
21
- var _chunk56RHCIJVcjs = require('./chunk-56RHCIJV.cjs');
21
+ var _chunkSNAFFCAXcjs = require('./chunk-SNAFFCAX.cjs');
22
22
 
23
23
 
24
24
 
@@ -37,7 +37,7 @@ var lerpP = (a, b, t) => [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
37
37
  var toP = (v) => [v.x, v.y];
38
38
  var mapP = (m, p) => [m[0] * p[0] + m[2] * p[1] + m[4], m[1] * p[0] + m[3] * p[1] + m[5]];
39
39
  var curvesOf = (c) => Math.max(0, (c.pts.length - 1) / 3) | 0;
40
- function subpathToMorphContour(sp, m = _chunk56RHCIJVcjs.IDENTITY_MATRIX) {
40
+ function subpathToMorphContour(sp, m = _chunkSNAFFCAXcjs.IDENTITY_MATRIX) {
41
41
  const n = sp.anchors.length;
42
42
  if (!n) return null;
43
43
  const first = mapP(m, toP(sp.anchors[0]));
@@ -67,8 +67,8 @@ function isStraight(p0, p1, p2, p3) {
67
67
  const u2 = along(p2);
68
68
  return off(p1) < tol && off(p2) < tol && u1 >= -1e-9 && u1 <= 1 + 1e-9 && u2 >= -1e-9 && u2 <= 1 + 1e-9;
69
69
  }
70
- function morphContourToSubpath(c, m = _chunk56RHCIJVcjs.IDENTITY_MATRIX, closed = c.closed) {
71
- const pts = _chunk56RHCIJVcjs.isIdentityMatrix.call(void 0, m) ? c.pts : c.pts.map((p) => mapP(m, p));
70
+ function morphContourToSubpath(c, m = _chunkSNAFFCAXcjs.IDENTITY_MATRIX, closed = c.closed) {
71
+ const pts = _chunkSNAFFCAXcjs.isIdentityMatrix.call(void 0, m) ? c.pts : c.pts.map((p) => mapP(m, p));
72
72
  const curves = curvesOf(c);
73
73
  const dropLast = closed && c.closed && curves > 0;
74
74
  const count = dropLast ? curves : curves + 1;
@@ -84,7 +84,7 @@ function morphContourToSubpath(c, m = _chunk56RHCIJVcjs.IDENTITY_MATRIX, closed
84
84
  anchors[(k + 1) % count].in = { x: p2[0], y: p2[1] };
85
85
  }
86
86
  for (const a of anchors) {
87
- const type = _chunk56RHCIJVcjs.inferAnchorType.call(void 0, a);
87
+ const type = _chunkSNAFFCAXcjs.inferAnchorType.call(void 0, a);
88
88
  if (type !== "corner") a.type = type;
89
89
  }
90
90
  const isClosed = closed && curves > 0;
@@ -267,7 +267,7 @@ function bestStart(fixed, free, useShapeContext) {
267
267
  return best;
268
268
  }
269
269
  function placeIn(c, from, to) {
270
- const b = _chunk56RHCIJVcjs.unionBounds.call(void 0, [boundsOfPoints(c.pts)]);
270
+ const b = _chunkSNAFFCAXcjs.unionBounds.call(void 0, [boundsOfPoints(c.pts)]);
271
271
  const p = b ? [b.x + b.width / 2, b.y + b.height / 2] : c.pts[0];
272
272
  if (!from || !to) return p;
273
273
  const fx = from.width > 0 ? (p[0] - from.x) / from.width : 0.5;
@@ -456,7 +456,7 @@ function interpolateVectorColor(a, b, t) {
456
456
  }
457
457
  function resampleGradientStops(g, offsets) {
458
458
  return offsets.map((offset) => {
459
- const s = _chunk56RHCIJVcjs.sampleVectorGradient.call(void 0, g, offset);
459
+ const s = _chunkSNAFFCAXcjs.sampleVectorGradient.call(void 0, g, offset);
460
460
  return s.opacity < 1 ? { offset, color: s.color, opacity: Math.round(s.opacity * 1e4) / 1e4 } : { offset, color: s.color };
461
461
  });
462
462
  }
@@ -467,11 +467,11 @@ function lerpAngle(a, b, t) {
467
467
  var lerpPoint = (a, b, t) => ({ x: lerpN(a.x, b.x, t), y: lerpN(a.y, b.y, t) });
468
468
  var sameColourModel = (a, b) => (_nullishCoalesce(a.interpolation, () => ( "srgb"))) === (_nullishCoalesce(b.interpolation, () => ( "srgb"))) && (_nullishCoalesce(a.smoothness, () => ( 0))) === (_nullishCoalesce(b.smoothness, () => ( 0)));
469
469
  function lerpStops(a, b, t) {
470
- let stopsA = _chunk56RHCIJVcjs.sortedVectorGradientStops.call(void 0, a);
471
- let stopsB = _chunk56RHCIJVcjs.sortedVectorGradientStops.call(void 0, b);
470
+ let stopsA = _chunkSNAFFCAXcjs.sortedVectorGradientStops.call(void 0, a);
471
+ let stopsB = _chunkSNAFFCAXcjs.sortedVectorGradientStops.call(void 0, b);
472
472
  const resampled = stopsA.length !== stopsB.length || !sameColourModel(a, b);
473
473
  if (resampled) {
474
- const offs = [..._chunk56RHCIJVcjs.expandVectorGradientStops.call(void 0, a), ..._chunk56RHCIJVcjs.expandVectorGradientStops.call(void 0, b), ...stopsA, ...stopsB].map((s) => s.offset).filter(Number.isFinite).sort((x, y) => x - y);
474
+ const offs = [..._chunkSNAFFCAXcjs.expandVectorGradientStops.call(void 0, a), ..._chunkSNAFFCAXcjs.expandVectorGradientStops.call(void 0, b), ...stopsA, ...stopsB].map((s) => s.offset).filter(Number.isFinite).sort((x, y) => x - y);
475
475
  const common = offs.filter((o, i) => i === 0 || o - offs[i - 1] > 1e-4);
476
476
  stopsA = resampleGradientStops(a, common);
477
477
  stopsB = resampleGradientStops(b, common);
@@ -498,8 +498,8 @@ function lerpGradient(a, b, t) {
498
498
  }
499
499
  if (near.spread && near.spread !== "pad") out.spread = near.spread;
500
500
  if (near.strokeMode && near.strokeMode !== "within") out.strokeMode = near.strokeMode;
501
- const ea = _chunk56RHCIJVcjs.hasExplicitGradientGeometry.call(void 0, a);
502
- const eb = _chunk56RHCIJVcjs.hasExplicitGradientGeometry.call(void 0, b);
501
+ const ea = _chunkSNAFFCAXcjs.hasExplicitGradientGeometry.call(void 0, a);
502
+ const eb = _chunkSNAFFCAXcjs.hasExplicitGradientGeometry.call(void 0, b);
503
503
  if (!ea && !eb) {
504
504
  if (a.angle !== void 0 || b.angle !== void 0 || a.type === "linear" || a.type === "reflected") {
505
505
  const fallback = a.type === "linear" || a.type === "reflected" ? 180 : 90;
@@ -512,10 +512,10 @@ function lerpGradient(a, b, t) {
512
512
  }
513
513
  return out;
514
514
  }
515
- const pa = _chunk56RHCIJVcjs.vectorGradientPoints.call(void 0, a);
516
- const pb = _chunk56RHCIJVcjs.vectorGradientPoints.call(void 0, b);
515
+ const pa = _chunkSNAFFCAXcjs.vectorGradientPoints.call(void 0, a);
516
+ const pb = _chunkSNAFFCAXcjs.vectorGradientPoints.call(void 0, b);
517
517
  if (pa.units !== pb.units) {
518
- const src = _chunk56RHCIJVcjs.explicitVectorGradient.call(void 0, near);
518
+ const src = _chunkSNAFFCAXcjs.explicitVectorGradient.call(void 0, near);
519
519
  return { ...src, stops: out.stops, ...out.interpolation ? { interpolation: out.interpolation } : {}, ...out.smoothness ? { smoothness: out.smoothness } : {} };
520
520
  }
521
521
  out.start = lerpPoint(pa.start, pb.start, t);
@@ -535,14 +535,14 @@ function solidLike(color, like) {
535
535
  function interpolateVectorPaint(a, b, t) {
536
536
  if (t <= 0) return a;
537
537
  if (t >= 1) return b;
538
- const pa = _chunk56RHCIJVcjs.hasPaint.call(void 0, a);
539
- const pb = _chunk56RHCIJVcjs.hasPaint.call(void 0, b);
538
+ const pa = _chunkSNAFFCAXcjs.hasPaint.call(void 0, a);
539
+ const pb = _chunkSNAFFCAXcjs.hasPaint.call(void 0, b);
540
540
  if (!pa && !pb) return t < 0.5 ? a : b;
541
541
  if (typeof a === "string" && pa && typeof b === "string" && pb) return interpolateVectorColor(a, b, t);
542
542
  if (!pa && typeof b === "string") return interpolateVectorColor("transparent", b, t);
543
543
  if (!pb && typeof a === "string") return interpolateVectorColor(a, "transparent", t);
544
- const ga = pa && _chunk56RHCIJVcjs.isVectorGradient.call(void 0, a) ? a : null;
545
- const gb = pb && _chunk56RHCIJVcjs.isVectorGradient.call(void 0, b) ? b : null;
544
+ const ga = pa && _chunkSNAFFCAXcjs.isVectorGradient.call(void 0, a) ? a : null;
545
+ const gb = pb && _chunkSNAFFCAXcjs.isVectorGradient.call(void 0, b) ? b : null;
546
546
  if (ga && gb) return _nullishCoalesce(lerpGradient(ga, gb, t), () => ( (t < 0.5 ? a : b)));
547
547
  if (gb) return _nullishCoalesce(lerpGradient(solidLike(pa ? a : null, gb), gb, t), () => ( b));
548
548
  if (ga) return _nullishCoalesce(lerpGradient(ga, solidLike(pb ? b : null, ga), t), () => ( a));
@@ -553,8 +553,8 @@ function interpolateWidthProfiles(a, b, t) {
553
553
  const at = [..._nullishCoalesce(a, () => ( [])), ..._nullishCoalesce(b, () => ( [])), { t: 0 }, { t: 1 }].map((p) => p.t).sort((x, y) => x - y);
554
554
  const ts = at.filter((v, i) => i === 0 || v - at[i - 1] > 1e-6);
555
555
  return ts.map((pos) => {
556
- const x = _chunk56RHCIJVcjs.widthProfileAt.call(void 0, a, pos);
557
- const y = _chunk56RHCIJVcjs.widthProfileAt.call(void 0, b, pos);
556
+ const x = _chunkSNAFFCAXcjs.widthProfileAt.call(void 0, a, pos);
557
+ const y = _chunkSNAFFCAXcjs.widthProfileAt.call(void 0, b, pos);
558
558
  return { t: pos, left: lerpN(x.left, y.left, t), right: lerpN(x.right, y.right, t) };
559
559
  });
560
560
  }
@@ -597,7 +597,7 @@ function reversedStyle(s) {
597
597
  out.endArrow = s.startArrow;
598
598
  out.startArrowScale = s.endArrowScale;
599
599
  out.endArrowScale = s.startArrowScale;
600
- if (_optionalChain([s, 'access', _6 => _6.strokeWidthProfile, 'optionalAccess', _7 => _7.length])) out.strokeWidthProfile = _chunk56RHCIJVcjs.reverseWidthProfile.call(void 0, s.strokeWidthProfile);
600
+ if (_optionalChain([s, 'access', _6 => _6.strokeWidthProfile, 'optionalAccess', _7 => _7.length])) out.strokeWidthProfile = _chunkSNAFFCAXcjs.reverseWidthProfile.call(void 0, s.strokeWidthProfile);
601
601
  for (const k of ["startArrow", "endArrow", "startArrowScale", "endArrowScale"]) if (out[k] === void 0) delete out[k];
602
602
  return out;
603
603
  }
@@ -623,19 +623,19 @@ function styleOf(n) {
623
623
  return out;
624
624
  }
625
625
  function contoursOf(node, m) {
626
- return _chunk56RHCIJVcjs.expandVectorCorners.call(void 0, node.subpaths).map((sp) => subpathToMorphContour(sp, m)).filter((c) => !!c);
626
+ return _chunkSNAFFCAXcjs.expandVectorCorners.call(void 0, node.subpaths).map((sp) => subpathToMorphContour(sp, m)).filter((c) => !!c);
627
627
  }
628
- function preparePathMorph(a, b, options, ma = _chunk56RHCIJVcjs.nodeMatrix.call(void 0, a), mb = _chunk56RHCIJVcjs.nodeMatrix.call(void 0, b)) {
628
+ function preparePathMorph(a, b, options, ma = _chunkSNAFFCAXcjs.nodeMatrix.call(void 0, a), mb = _chunkSNAFFCAXcjs.nodeMatrix.call(void 0, b)) {
629
629
  const corr = correspondMorphContours(contoursOf(a, ma), contoursOf(b, mb), options);
630
630
  const sim = procrustes(corr.a, corr.b);
631
631
  const styleA = styleOf(a);
632
632
  const styleB = corr.reversed ? reversedStyle(styleOf(b)) : styleOf(b);
633
- const rigid = !_chunk56RHCIJVcjs.isIdentityMatrix.call(void 0, ma) || !_chunk56RHCIJVcjs.isIdentityMatrix.call(void 0, mb);
633
+ const rigid = !_chunkSNAFFCAXcjs.isIdentityMatrix.call(void 0, ma) || !_chunkSNAFFCAXcjs.isIdentityMatrix.call(void 0, mb);
634
634
  const id = _nullishCoalesce(options.id, () => ( a.id));
635
635
  return (t) => {
636
636
  const contours = interpolateMorphContours(corr.a, corr.b, t, { linear: options.linear, rigidity: options.rigidity, similarity: sim });
637
- const m = rigid ? interpolateRigidMatrix(ma, mb, t) : _chunk56RHCIJVcjs.IDENTITY_MATRIX;
638
- const back = rigid ? _chunk56RHCIJVcjs.invertMatrix.call(void 0, m) : _chunk56RHCIJVcjs.IDENTITY_MATRIX;
637
+ const m = rigid ? interpolateRigidMatrix(ma, mb, t) : _chunkSNAFFCAXcjs.IDENTITY_MATRIX;
638
+ const back = rigid ? _chunkSNAFFCAXcjs.invertMatrix.call(void 0, m) : _chunkSNAFFCAXcjs.IDENTITY_MATRIX;
639
639
  const subpaths = contours.map((c, k) => {
640
640
  const closed = t <= 0 ? corr.a[k].closed : t >= 1 ? corr.b[k].closed : corr.a[k].closed && corr.b[k].closed;
641
641
  return morphContourToSubpath({ closed: corr.a[k].closed && corr.b[k].closed, pts: c.pts }, back, closed);
@@ -643,14 +643,14 @@ function preparePathMorph(a, b, options, ma = _chunk56RHCIJVcjs.nodeMatrix.call(
643
643
  const node = { id, type: "path", subpaths, ...interpolateVectorStyle(styleA, styleB, t) };
644
644
  const opacity = lerpN(_nullishCoalesce(a.opacity, () => ( 1)), _nullishCoalesce(b.opacity, () => ( 1)), t);
645
645
  if (opacity < 1) node.opacity = opacity;
646
- if (rigid && !_chunk56RHCIJVcjs.isIdentityMatrix.call(void 0, m)) node.transform = m;
646
+ if (rigid && !_chunkSNAFFCAXcjs.isIdentityMatrix.call(void 0, m)) node.transform = m;
647
647
  return node;
648
648
  };
649
649
  }
650
- function flattenPaths(node, parent = _chunk56RHCIJVcjs.IDENTITY_MATRIX) {
651
- const m = _chunk56RHCIJVcjs.multiplyMatrices.call(void 0, _chunk56RHCIJVcjs.nodeMatrix.call(void 0, node), parent);
650
+ function flattenPaths(node, parent = _chunkSNAFFCAXcjs.IDENTITY_MATRIX) {
651
+ const m = _chunkSNAFFCAXcjs.multiplyMatrices.call(void 0, _chunkSNAFFCAXcjs.nodeMatrix.call(void 0, node), parent);
652
652
  if (node.type === "path") return [{ path: node, m, opacity: 1 }];
653
- if (node.type === "text" || node.type === "instance") return flattenPaths(_chunk56RHCIJVcjs.expandVectorAppearance.call(void 0, node), parent);
653
+ if (node.type === "text" || node.type === "instance") return flattenPaths(_chunkSNAFFCAXcjs.expandVectorAppearance.call(void 0, node), parent);
654
654
  const o = _nullishCoalesce(node.opacity, () => ( 1));
655
655
  return node.children.filter((c) => c.visible !== false).flatMap((c) => flattenPaths(c, m)).map((e) => ({ ...e, opacity: e.opacity * o }));
656
656
  }
@@ -672,8 +672,8 @@ function createVectorMorph(a, b, options = {}) {
672
672
  }
673
673
  const pa = flattenPaths(a);
674
674
  const pb = flattenPaths(b);
675
- const ba = _chunk56RHCIJVcjs.unionBounds.call(void 0, pa.map((e) => placedBounds(e.path, e.m)));
676
- const bb = _chunk56RHCIJVcjs.unionBounds.call(void 0, pb.map((e) => placedBounds(e.path, e.m)));
675
+ const ba = _chunkSNAFFCAXcjs.unionBounds.call(void 0, pa.map((e) => placedBounds(e.path, e.m)));
676
+ const bb = _chunkSNAFFCAXcjs.unionBounds.call(void 0, pb.map((e) => placedBounds(e.path, e.m)));
677
677
  const id = _nullishCoalesce(options.id, () => ( a.id));
678
678
  const parts = [];
679
679
  const opacities = [];
@@ -685,10 +685,10 @@ function createVectorMorph(a, b, options = {}) {
685
685
  parts.push(preparePathMorph(x.path, y.path, sub, x.m, y.m));
686
686
  opacities.push([x.opacity, y.opacity]);
687
687
  } else if (x) {
688
- parts.push(preparePathMorph(x.path, collapsedPath(x.path, x.m, ba, bb), sub, x.m, _chunk56RHCIJVcjs.IDENTITY_MATRIX));
688
+ parts.push(preparePathMorph(x.path, collapsedPath(x.path, x.m, ba, bb), sub, x.m, _chunkSNAFFCAXcjs.IDENTITY_MATRIX));
689
689
  opacities.push([x.opacity, x.opacity]);
690
690
  } else if (y) {
691
- parts.push(preparePathMorph(collapsedPath(y.path, y.m, bb, ba), y.path, sub, _chunk56RHCIJVcjs.IDENTITY_MATRIX, y.m));
691
+ parts.push(preparePathMorph(collapsedPath(y.path, y.m, bb, ba), y.path, sub, _chunkSNAFFCAXcjs.IDENTITY_MATRIX, y.m));
692
692
  opacities.push([y.opacity, y.opacity]);
693
693
  }
694
694
  }
@@ -775,6 +775,51 @@ var BRUSH_PRESETS = [
775
775
  marks: { kind: "scatter", density: 0.7, size: 0.04 },
776
776
  dynamics: { smoothing: 0.2, pressureSize: false, pressureOpacity: true },
777
777
  colour: { palette: ["#ef4444", "#f97316", "#facc15", "#22c55e", "#3b82f6", "#a855f7", "#111827", "#f8fafc"] }
778
+ },
779
+ // --- Ghost paint: wet paint whose colour vanishes, leaving only what it smeared ---
780
+ {
781
+ id: "ghost-wash",
782
+ name: "Ghost wash",
783
+ kind: "mark",
784
+ medium: "paint",
785
+ variety: "watercolor",
786
+ tip: { shape: "round", size: 32, hardness: 0.55, spacing: 0.12 },
787
+ dynamics: { smoothing: 0.25, pressureOpacity: true, minSize: 0.35 },
788
+ behaviour: { surface: "wet", wet: { water: 0.65, rewet: 0.2 } },
789
+ ghost: {}
790
+ },
791
+ {
792
+ id: "ghost-gouache",
793
+ name: "Ghost gouache",
794
+ kind: "mark",
795
+ medium: "paint",
796
+ variety: "gouache",
797
+ tip: { shape: "round", size: 26, hardness: 0.7 },
798
+ dynamics: { smoothing: 0.25, minSize: 0.5 },
799
+ behaviour: { surface: "wet", wet: { water: 0.35, pigment: 0.85, body: 1, rewet: 0.3 } },
800
+ ghost: { linger: 5, smear: 0.4 }
801
+ },
802
+ {
803
+ id: "ghost-oil",
804
+ name: "Ghost oil",
805
+ kind: "mark",
806
+ medium: "paint",
807
+ variety: "oil",
808
+ tip: { shape: "round", size: 24, hardness: 0.75, spacing: 0.08 },
809
+ dynamics: { smoothing: 0.25, minSize: 0.5 },
810
+ behaviour: { surface: "wet", wet: { water: 0.4, pigment: 0.9, body: 1, load: 0.97 } },
811
+ ghost: { linger: 10, smear: 0.5 }
812
+ },
813
+ {
814
+ id: "invisible-ink",
815
+ name: "Invisible ink",
816
+ kind: "mark",
817
+ medium: "paint",
818
+ variety: "watercolor",
819
+ tip: { shape: "round", size: 24, hardness: 0.65 },
820
+ dynamics: { smoothing: 0.3, minSize: 0.4 },
821
+ behaviour: { surface: "wet", wet: { water: 0.45, pigment: 0, rewet: 0.35 } },
822
+ ghost: { smear: 0.65 }
778
823
  }
779
824
  ];
780
825
 
@@ -897,6 +942,13 @@ var DEFAULT_LIGHT = { amount: 0, pressure: false };
897
942
  function normalizeLight(raw = {}, base = DEFAULT_LIGHT) {
898
943
  return { amount: unit2(raw.amount, base.amount), pressure: typeof raw.pressure === "boolean" ? raw.pressure : base.pressure };
899
944
  }
945
+ var DEFAULT_GHOST = { linger: 4, smear: 0.3 };
946
+ function normalizeGhost(raw = {}, base = DEFAULT_GHOST) {
947
+ return {
948
+ linger: range(raw.linger, 0.5, 60, base.linger),
949
+ smear: unit2(raw.smear, base.smear)
950
+ };
951
+ }
900
952
  function normalizeImpasto(raw = {}, base = DEFAULT_IMPASTO) {
901
953
  return {
902
954
  tool: IMPASTO_TOOLS.includes(raw.tool) ? raw.tool : base.tool,
@@ -1085,6 +1137,10 @@ function normalizePaintBrush(raw = {}, base) {
1085
1137
  paint = mc.mode === "off" ? paintToMultiColor(paint) ? null : paint : multiColorToPaint(mc, behavior.mixing);
1086
1138
  }
1087
1139
  behavior = { ...behavior, multicolor: _nullishCoalesce(paintToMultiColor(paint), () => ( { ...DEFAULT_MULTI_COLOR, colors: [] })) };
1140
+ const wet = normalizeWetBrush(_nullishCoalesce(raw.wet, () => ( {})), _nullishCoalesce(b.wet, () => ( DEFAULT_WET_BRUSH)));
1141
+ const wantsLight = typeof _optionalChain([raw, 'access', _3 => _3.light, 'optionalAccess', _4 => _4.amount]) === "number" && raw.light.amount > 0;
1142
+ const ghost = engine === "wet" && wet.tool === "paint" && (raw.ghost !== void 0 ? raw.ghost !== null : !wantsLight && Boolean(b.ghost)) ? normalizeGhost(_nullishCoalesce(raw.ghost, () => ( {})), _nullishCoalesce(b.ghost, () => ( DEFAULT_GHOST))) : void 0;
1143
+ if (ghost) behavior = { ...behavior, pickup: 0, dirty: false };
1088
1144
  return {
1089
1145
  id,
1090
1146
  name: typeof raw.name === "string" && raw.name.trim() ? raw.name.trim().slice(0, 80) : b.name,
@@ -1100,12 +1156,13 @@ function normalizePaintBrush(raw = {}, base) {
1100
1156
  behavior,
1101
1157
  blender: _chunkNIBFKXMDcjs.normalizeBlender.call(void 0, _nullishCoalesce(raw.blender, () => ( {})), b.blender),
1102
1158
  smudge: _chunkNIBFKXMDcjs.normalizeSmudge.call(void 0, _nullishCoalesce(raw.smudge, () => ( {})), b.smudge),
1103
- wet: normalizeWetBrush(_nullishCoalesce(raw.wet, () => ( {})), _nullishCoalesce(b.wet, () => ( DEFAULT_WET_BRUSH))),
1159
+ wet,
1104
1160
  impasto: normalizeImpasto(_nullishCoalesce(raw.impasto, () => ( {})), _nullishCoalesce(b.impasto, () => ( DEFAULT_IMPASTO))),
1105
1161
  particle: normalizeParticle(_nullishCoalesce(raw.particle, () => ( {})), _nullishCoalesce(b.particle, () => ( DEFAULT_PARTICLE))),
1106
1162
  bristle: normalizeBristle(_nullishCoalesce(raw.bristle, () => ( {})), _nullishCoalesce(b.bristle, () => ( DEFAULT_BRISTLE))),
1107
1163
  sticker: normalizeStickerSettings(_nullishCoalesce(raw.sticker, () => ( {})), _nullishCoalesce(b.sticker, () => ( DEFAULT_STICKER))),
1108
- light: normalizeLight(_nullishCoalesce(raw.light, () => ( {})), _nullishCoalesce(b.light, () => ( DEFAULT_LIGHT))),
1164
+ light: ghost && !wantsLight ? { ...DEFAULT_LIGHT } : normalizeLight(_nullishCoalesce(raw.light, () => ( {})), _nullishCoalesce(b.light, () => ( DEFAULT_LIGHT))),
1165
+ ...ghost ? { ghost } : {},
1109
1166
  stamp: readStamp(raw.stamp, _nullishCoalesce(b.stamp, () => ( null))),
1110
1167
  spray: readSpray(raw.spray, _nullishCoalesce(b.spray, () => ( null))),
1111
1168
  ...withTipGrain(readTipGrain(raw.tipGrain, _nullishCoalesce(b.tipGrain, () => ( null)))),
@@ -1194,6 +1251,7 @@ var BRUSH_FIELDS = [
1194
1251
  f("behaviour.strength", "wet.strength", ["wet"]),
1195
1252
  // Surfaces.
1196
1253
  ...each("behaviour.wet", "wet", ["medium", "water", "pigment", "body", "rewet", "load", "thinner"], ["wet"]),
1254
+ ...each("ghost", "ghost", ["linger", "smear"], ["wet"]),
1197
1255
  f("behaviour.thick.applicator", "impasto.tool", ["impasto"]),
1198
1256
  ...each("behaviour.thick", "impasto", ["thickness", "gloss", "metallic", "load", "thinner", "drag", "rim", "clarity"], ["impasto"]),
1199
1257
  // Marks.
@@ -1232,13 +1290,13 @@ function setPath(o, path, value) {
1232
1290
  var copy = (v) => v !== null && typeof v === "object" ? JSON.parse(JSON.stringify(v)) : v;
1233
1291
  function resolveEngine(brush) {
1234
1292
  if (brush.kind === "tool") return brush.tool === "eraser" || brush.tool === "blender" || brush.tool === "smudge" ? brush.tool : "wet";
1235
- if (_optionalChain([brush, 'access', _3 => _3.marks, 'optionalAccess', _4 => _4.kind]) === "particles") return "particle";
1236
- if (_optionalChain([brush, 'access', _5 => _5.marks, 'optionalAccess', _6 => _6.kind]) === "objects") return "sticker";
1293
+ if (_optionalChain([brush, 'access', _5 => _5.marks, 'optionalAccess', _6 => _6.kind]) === "particles") return "particle";
1294
+ if (_optionalChain([brush, 'access', _7 => _7.marks, 'optionalAccess', _8 => _8.kind]) === "objects") return "sticker";
1237
1295
  if (brush.tip.shape === "bristle") return "bristle";
1238
- const surface = _optionalChain([brush, 'access', _7 => _7.behaviour, 'optionalAccess', _8 => _8.surface]);
1296
+ const surface = _optionalChain([brush, 'access', _9 => _9.behaviour, 'optionalAccess', _10 => _10.surface]);
1239
1297
  if (surface === "thick") return "impasto";
1240
1298
  if (surface === "wet") return "wet";
1241
- if (_optionalChain([brush, 'access', _9 => _9.behaviour, 'optionalAccess', _10 => _10.exchange, 'optionalAccess', _11 => _11.reservoir])) return "mixer";
1299
+ if (_optionalChain([brush, 'access', _11 => _11.behaviour, 'optionalAccess', _12 => _12.exchange, 'optionalAccess', _13 => _13.reservoir])) return "mixer";
1242
1300
  return "dab";
1243
1301
  }
1244
1302
  var VARIETY_CATEGORY = {
@@ -1254,11 +1312,11 @@ var VARIETY_CATEGORY = {
1254
1312
  };
1255
1313
  var MEDIUM_CATEGORY = { paint: "paint", ink: "ink", dry: "pencil", spray: "airbrush" };
1256
1314
  function resolveWetMedium(brush) {
1257
- return _nullishCoalesce(_optionalChain([brush, 'access', _12 => _12.behaviour, 'optionalAccess', _13 => _13.wet, 'optionalAccess', _14 => _14.medium]), () => ( (WET_MEDIA.includes(brush.variety) ? brush.variety : void 0)));
1315
+ return _nullishCoalesce(_optionalChain([brush, 'access', _14 => _14.behaviour, 'optionalAccess', _15 => _15.wet, 'optionalAccess', _16 => _16.medium]), () => ( (WET_MEDIA.includes(brush.variety) ? brush.variety : void 0)));
1258
1316
  }
1259
1317
  function resolveCategory(brush, engine = resolveEngine(brush)) {
1260
1318
  if (brush.kind === "tool") return brush.tool === "eraser" || brush.tool === "blender" || brush.tool === "smudge" ? brush.tool : "wet-tool";
1261
- if ((_nullishCoalesce(_optionalChain([brush, 'access', _15 => _15.light, 'optionalAccess', _16 => _16.amount]), () => ( 0))) > 0) return "light";
1319
+ if ((_nullishCoalesce(_optionalChain([brush, 'access', _17 => _17.light, 'optionalAccess', _18 => _18.amount]), () => ( 0))) > 0) return "light";
1262
1320
  switch (engine) {
1263
1321
  case "particle":
1264
1322
  return "procedural";
@@ -1280,18 +1338,19 @@ function resolveBrush(brush, options = {}) {
1280
1338
  const engine = resolveEngine(brush);
1281
1339
  const input = { id: brush.id, name: brush.name, category: resolveCategory(brush, engine), engine };
1282
1340
  for (const field of BRUSH_FIELDS) {
1283
- if (!field.engines.includes(engine) || field.shapes && !field.shapes.includes(brush.tip.shape) || field.marks && !field.marks.includes(_nullishCoalesce(_optionalChain([brush, 'access', _17 => _17.marks, 'optionalAccess', _18 => _18.kind]), () => ( "continuous")))) continue;
1341
+ if (!field.engines.includes(engine) || field.shapes && !field.shapes.includes(brush.tip.shape) || field.marks && !field.marks.includes(_nullishCoalesce(_optionalChain([brush, 'access', _19 => _19.marks, 'optionalAccess', _20 => _20.kind]), () => ( "continuous")))) continue;
1284
1342
  const v = getPath(brush, field.facet);
1285
1343
  if (v !== void 0) setPath(input, field.engine, field.map ? field.map.toEngine(v) : copy(v));
1286
1344
  }
1287
- if (engine === "dab" && _optionalChain([brush, 'access', _19 => _19.marks, 'optionalAccess', _20 => _20.kind]) === "scatter") input.spray = { ..._nullishCoalesce(input.spray, () => ( {})) };
1345
+ if (engine === "dab" && _optionalChain([brush, 'access', _21 => _21.marks, 'optionalAccess', _22 => _22.kind]) === "scatter") input.spray = { ..._nullishCoalesce(input.spray, () => ( {})) };
1288
1346
  if (engine === "wet") {
1289
1347
  setPath(input, "wet.tool", brush.kind === "tool" ? WET_TOOL_OF[brush.tool] : "paint");
1290
1348
  const medium = resolveWetMedium(brush);
1291
1349
  if (medium) setPath(input, "wet.medium", medium);
1350
+ if (brush.kind !== "tool" && brush.ghost) input.ghost = { ..._nullishCoalesce(input.ghost, () => ( {})) };
1292
1351
  }
1293
1352
  if (engine === "blender" || engine === "smudge") input.loadsColor = false;
1294
- const paint = _optionalChain([brush, 'access', _21 => _21.colour, 'optionalAccess', _22 => _22.default]);
1353
+ const paint = _optionalChain([brush, 'access', _23 => _23.colour, 'optionalAccess', _24 => _24.default]);
1295
1354
  if (paint && typeof paint === "object" && "type" in paint && paint.type === "gradient") input.paint = copy(paint);
1296
1355
  return normalizePaintBrush({ ...input, ...options.builtin ? { builtin: true } : {} });
1297
1356
  }
@@ -1354,7 +1413,7 @@ function skeleton(b) {
1354
1413
  }
1355
1414
  switch (b.engine) {
1356
1415
  case "wet":
1357
- return { ...brush, medium: "paint", variety: b.wet.medium, behaviour: { surface: "wet" } };
1416
+ return { ...brush, medium: "paint", variety: b.wet.medium, behaviour: { surface: "wet" }, ...b.ghost ? { ghost: {} } : {} };
1358
1417
  case "impasto":
1359
1418
  return { ...brush, medium: "paint", behaviour: { surface: "thick" } };
1360
1419
  case "mixer":
@@ -1371,13 +1430,13 @@ function skeleton(b) {
1371
1430
  }
1372
1431
  }
1373
1432
  }
1374
- var ORDER = ["id", "name", "description", "tags", "kind", "medium", "variety", "tool", "tip", "marks", "dynamics", "behaviour", "light", "motion", "colour"];
1433
+ var ORDER = ["id", "name", "description", "tags", "kind", "medium", "variety", "tool", "tip", "marks", "dynamics", "behaviour", "light", "ghost", "motion", "colour"];
1375
1434
  function migrateBrushV1(raw) {
1376
1435
  const b = normalizePaintBrush(raw);
1377
1436
  const brush = skeleton(b);
1378
1437
  const defaults = resolveBrush(brush);
1379
1438
  for (const field of BRUSH_FIELDS) {
1380
- if (!field.engines.includes(b.engine) || field.shapes && !field.shapes.includes(brush.tip.shape) || field.marks && !field.marks.includes(_nullishCoalesce(_optionalChain([brush, 'access', _23 => _23.marks, 'optionalAccess', _24 => _24.kind]), () => ( "continuous")))) continue;
1439
+ if (!field.engines.includes(b.engine) || field.shapes && !field.shapes.includes(brush.tip.shape) || field.marks && !field.marks.includes(_nullishCoalesce(_optionalChain([brush, 'access', _25 => _25.marks, 'optionalAccess', _26 => _26.kind]), () => ( "continuous")))) continue;
1381
1440
  const v = getPath(b, field.engine);
1382
1441
  if (!equal(v, getPath(defaults, field.engine))) setPath(brush, field.facet, field.map ? field.map.toFacet(v) : copy2(v));
1383
1442
  }
@@ -1586,6 +1645,10 @@ var LIGHT = object("Light the brush gives off with its colour (glow and spill).
1586
1645
  }),
1587
1646
  glow: bool("Suggest a glow layer effect for the layer (glow stays a layer effect).")
1588
1647
  });
1648
+ var GHOST = object('Ghost paint: wet paint that flows and mixes visibly while wet, then fades away without leaving its colour, keeping only the smear it made in the paint it touched (needs behaviour.surface "wet").', {
1649
+ linger: num(0.5, 60, "Seconds of simulated time before the ghost paint has fully faded (default 4)."),
1650
+ smear: unit3("How much the ghost paint drags and lifts the paint it passes through: 0 none .. 1 full (default 0.3).")
1651
+ });
1589
1652
  var MOTION = object("Animation after painting.", {
1590
1653
  live: bool("Effect paint keeps playing on stroke layers (default false)."),
1591
1654
  fps: int(1, 60, "Suggested playback rate in frames per second."),
@@ -1649,6 +1712,7 @@ var BRUSH_JSON_SCHEMA = object(
1649
1712
  dynamics: DYNAMICS,
1650
1713
  behaviour: BEHAVIOUR,
1651
1714
  light: LIGHT,
1715
+ ghost: GHOST,
1652
1716
  motion: MOTION,
1653
1717
  colour: COLOUR
1654
1718
  },
@@ -1661,6 +1725,7 @@ var BRUSH_FACET_SCHEMAS = {
1661
1725
  dynamics: DYNAMICS,
1662
1726
  behaviour: BEHAVIOUR,
1663
1727
  light: LIGHT,
1728
+ ghost: GHOST,
1664
1729
  motion: MOTION,
1665
1730
  colour: COLOUR,
1666
1731
  paint: PAINT
@@ -1866,7 +1931,7 @@ function readObject(value, schema, path, problems) {
1866
1931
  const out = {};
1867
1932
  for (const [key, v] of Object.entries(value)) {
1868
1933
  if (v === void 0) continue;
1869
- const child = _optionalChain([schema, 'access', _25 => _25.properties, 'optionalAccess', _26 => _26[key]]);
1934
+ const child = _optionalChain([schema, 'access', _27 => _27.properties, 'optionalAccess', _28 => _28[key]]);
1870
1935
  if (!child) {
1871
1936
  problems.push(`${path}.${key} is not a brush field; dropped.`);
1872
1937
  continue;
@@ -1906,8 +1971,8 @@ function normalizeBrushSpec(raw, problems = []) {
1906
1971
  const out = readObject(rest, BRUSH_JSON_SCHEMA, "brush", problems);
1907
1972
  const brush = { id: raw.id, name, ...out, kind, ...tool ? { tool } : {}, tip: _nullishCoalesce(out.tip, () => ( { shape: "round" })) };
1908
1973
  const ordered = () => {
1909
- const { id, name: n, description, tags, kind: k, medium, variety, tool: t, tip, marks, dynamics, behaviour, light, motion, colour } = brush;
1910
- const all = { id, name: n, description, tags, kind: k, medium, variety, tool: t, tip, marks, dynamics, behaviour, light, motion, colour };
1974
+ const { id, name: n, description, tags, kind: k, medium, variety, tool: t, tip, marks, dynamics, behaviour, light, ghost, motion, colour } = brush;
1975
+ const all = { id, name: n, description, tags, kind: k, medium, variety, tool: t, tip, marks, dynamics, behaviour, light, ghost, motion, colour };
1911
1976
  return Object.fromEntries(Object.entries(all).filter(([, v]) => v !== void 0));
1912
1977
  };
1913
1978
  if (!out.tip) problems.push("tip is missing; a round tip is used.");
@@ -1956,15 +2021,15 @@ function normalizeBrushSpec(raw, problems = []) {
1956
2021
  delete brush.marks;
1957
2022
  }
1958
2023
  }
1959
- if (_optionalChain([brush, 'access', _27 => _27.marks, 'optionalAccess', _28 => _28.kind]) === "scatter") {
1960
- const surface = _optionalChain([brush, 'access', _29 => _29.behaviour, 'optionalAccess', _30 => _30.surface]);
1961
- const why = brush.tip.shape === "bristle" ? "bristle tips lay their own marks" : surface === "wet" || surface === "thick" ? `${surface} paint is not sprayed` : _optionalChain([brush, 'access', _31 => _31.behaviour, 'optionalAccess', _32 => _32.exchange, 'optionalAccess', _33 => _33.reservoir]) ? "the Mixer Brush is not sprayed" : null;
2024
+ if (_optionalChain([brush, 'access', _29 => _29.marks, 'optionalAccess', _30 => _30.kind]) === "scatter") {
2025
+ const surface = _optionalChain([brush, 'access', _31 => _31.behaviour, 'optionalAccess', _32 => _32.surface]);
2026
+ const why = brush.tip.shape === "bristle" ? "bristle tips lay their own marks" : surface === "wet" || surface === "thick" ? `${surface} paint is not sprayed` : _optionalChain([brush, 'access', _33 => _33.behaviour, 'optionalAccess', _34 => _34.exchange, 'optionalAccess', _35 => _35.reservoir]) ? "the Mixer Brush is not sprayed" : null;
1962
2027
  if (why) {
1963
2028
  drop("marks", why);
1964
2029
  delete brush.marks;
1965
2030
  }
1966
2031
  }
1967
- if (_optionalChain([brush, 'access', _34 => _34.marks, 'optionalAccess', _35 => _35.kind]) === "objects" && brush.tip.shape !== "stamp") {
2032
+ if (_optionalChain([brush, 'access', _36 => _36.marks, 'optionalAccess', _37 => _37.kind]) === "objects" && brush.tip.shape !== "stamp") {
1968
2033
  problems.push("marks objects lay stamps: tip.shape set to stamp.");
1969
2034
  brush.tip.shape = "stamp";
1970
2035
  }
@@ -1978,7 +2043,7 @@ function normalizeBrushSpec(raw, problems = []) {
1978
2043
  }
1979
2044
  if (brush.tip.stamps) {
1980
2045
  let stamps = brush.tip.stamps.map((s) => _chunkRDFHWAHLcjs.normalizeStickerRef.call(void 0, s));
1981
- if (_optionalChain([brush, 'access', _36 => _36.marks, 'optionalAccess', _37 => _37.kind]) === "objects" && stamps.some(isBrushSourceRef)) {
2046
+ if (_optionalChain([brush, 'access', _38 => _38.marks, 'optionalAccess', _39 => _39.kind]) === "objects" && stamps.some(isBrushSourceRef)) {
1982
2047
  problems.push("tip.stamps: image sources (source:\u2026) dropped: objects marks lay stickers; use continuous, scatter or particles marks for an image tip.");
1983
2048
  stamps = stamps.filter((s) => !isBrushSourceRef(s));
1984
2049
  }
@@ -1989,8 +2054,8 @@ function normalizeBrushSpec(raw, problems = []) {
1989
2054
  }
1990
2055
  }
1991
2056
  if (brush.tip.grain) {
1992
- const surface = _optionalChain([brush, 'access', _38 => _38.behaviour, 'optionalAccess', _39 => _39.surface]);
1993
- const marks = _optionalChain([brush, 'access', _40 => _40.marks, 'optionalAccess', _41 => _41.kind]);
2057
+ const surface = _optionalChain([brush, 'access', _40 => _40.behaviour, 'optionalAccess', _41 => _41.surface]);
2058
+ const marks = _optionalChain([brush, 'access', _42 => _42.marks, 'optionalAccess', _43 => _43.kind]);
1994
2059
  const why = !brush.tip.grain.source ? "it needs a source (a grain pattern or source:<id>)" : brush.tip.shape === "bristle" ? "bristle tips lay their own marks" : marks === "particles" || marks === "objects" ? `${marks} marks are not dabs` : surface === "wet" || surface === "thick" ? `${surface} paint lays its own texture` : kind === "tool" && WET_BRUSH_TOOLS.includes(brush.tool) ? "the wet tools work on the wet layer" : null;
1995
2060
  if (why) {
1996
2061
  drop("tip.grain", why);
@@ -2027,11 +2092,26 @@ function normalizeBrushSpec(raw, problems = []) {
2027
2092
  if (b.exchange && kind === "tool" && !wetTool) {
2028
2093
  drop("behaviour.exchange", `the ${brush.tool} does not pick paint up`);
2029
2094
  delete b.exchange;
2030
- } else if (b.exchange && (_optionalChain([brush, 'access', _42 => _42.marks, 'optionalAccess', _43 => _43.kind]) === "particles" || _optionalChain([brush, 'access', _44 => _44.marks, 'optionalAccess', _45 => _45.kind]) === "objects" || brush.tip.shape === "bristle")) {
2095
+ } else if (b.exchange && (_optionalChain([brush, 'access', _44 => _44.marks, 'optionalAccess', _45 => _45.kind]) === "particles" || _optionalChain([brush, 'access', _46 => _46.marks, 'optionalAccess', _47 => _47.kind]) === "objects" || brush.tip.shape === "bristle")) {
2031
2096
  drop("behaviour.exchange", "particle, object and bristle marks do not pick paint up");
2032
2097
  delete b.exchange;
2033
2098
  }
2034
2099
  }
2100
+ if (brush.ghost) {
2101
+ if (kind === "tool" || _optionalChain([brush, 'access', _48 => _48.behaviour, 'optionalAccess', _49 => _49.surface]) !== "wet") {
2102
+ drop("ghost", "it needs a mark brush with behaviour.surface wet");
2103
+ delete brush.ghost;
2104
+ } else {
2105
+ if (brush.light) {
2106
+ drop("light", "ghost paint uses the wet light channel as its tracer");
2107
+ delete brush.light;
2108
+ }
2109
+ if (_optionalChain([brush, 'access', _50 => _50.behaviour, 'optionalAccess', _51 => _51.exchange])) {
2110
+ drop("behaviour.exchange", "ghost paint does not pick paint up");
2111
+ delete brush.behaviour.exchange;
2112
+ }
2113
+ }
2114
+ }
2035
2115
  return ordered();
2036
2116
  }
2037
2117
 
@@ -2121,15 +2201,16 @@ function checkBrush(brush, profile) {
2121
2201
  const image = brush.tip.shape === "stamp" && (_nullishCoalesce(brush.tip.stamps, () => ( []))).some(isBrushSourceRef);
2122
2202
  add("tip.shape", "error", `${host} can't lay a ${image ? "stamp tip (image tips are stamps)" : `${brush.tip.shape} tip`}.`, `Set tip.shape to one of: ${list(profile.tipShapes)}.`);
2123
2203
  }
2124
- const marks = _nullishCoalesce(_optionalChain([brush, 'access', _46 => _46.marks, 'optionalAccess', _47 => _47.kind]), () => ( "continuous"));
2204
+ const marks = _nullishCoalesce(_optionalChain([brush, 'access', _52 => _52.marks, 'optionalAccess', _53 => _53.kind]), () => ( "continuous"));
2125
2205
  if (!profile.marks.includes(marks)) add("marks", "error", `${host} can't lay ${marks} marks.`, `Use marks ${list(profile.marks)} (remove marks for continuous dabs).`);
2126
- const surface = _nullishCoalesce(_optionalChain([brush, 'access', _48 => _48.behaviour, 'optionalAccess', _49 => _49.surface]), () => ( "dry"));
2206
+ const surface = _nullishCoalesce(_optionalChain([brush, 'access', _54 => _54.behaviour, 'optionalAccess', _55 => _55.surface]), () => ( "dry"));
2127
2207
  if (brush.kind === "mark" && !profile.surfaces.includes(surface)) add("behaviour.surface", "error", `${host} has no ${surface} surface.`, `Set behaviour.surface to ${list(profile.surfaces)}.`);
2128
- const ex = _optionalChain([brush, 'access', _50 => _50.behaviour, 'optionalAccess', _51 => _51.exchange]);
2129
- feature(profile.reservoir, !!_optionalChain([ex, 'optionalAccess', _52 => _52.reservoir]), "behaviour.exchange.reservoir", "a Mixer Brush reservoir", "Remove behaviour.exchange.reservoir.");
2130
- feature(profile.exchange, !_optionalChain([ex, 'optionalAccess', _53 => _53.reservoir]) && (nonZero(_optionalChain([ex, 'optionalAccess', _54 => _54.pickup])) || !!_optionalChain([ex, 'optionalAccess', _55 => _55.dirty])), "behaviour.exchange", "picking paint up", "Remove behaviour.exchange.");
2131
- feature(profile.grain, nonZero(_optionalChain([brush, 'access', _56 => _56.behaviour, 'optionalAccess', _57 => _57.grain])), "behaviour.grain", "paper grain", "Set behaviour.grain to 0.");
2132
- feature(profile.light, nonZero(_optionalChain([brush, 'access', _58 => _58.light, 'optionalAccess', _59 => _59.amount])), "light", "light paint (glow and spill)", "Remove light (or set light.amount to 0).");
2208
+ const ex = _optionalChain([brush, 'access', _56 => _56.behaviour, 'optionalAccess', _57 => _57.exchange]);
2209
+ feature(profile.reservoir, !!_optionalChain([ex, 'optionalAccess', _58 => _58.reservoir]), "behaviour.exchange.reservoir", "a Mixer Brush reservoir", "Remove behaviour.exchange.reservoir.");
2210
+ feature(profile.exchange, !_optionalChain([ex, 'optionalAccess', _59 => _59.reservoir]) && (nonZero(_optionalChain([ex, 'optionalAccess', _60 => _60.pickup])) || !!_optionalChain([ex, 'optionalAccess', _61 => _61.dirty])), "behaviour.exchange", "picking paint up", "Remove behaviour.exchange.");
2211
+ feature(profile.grain, nonZero(_optionalChain([brush, 'access', _62 => _62.behaviour, 'optionalAccess', _63 => _63.grain])), "behaviour.grain", "paper grain", "Set behaviour.grain to 0.");
2212
+ feature(profile.light, nonZero(_optionalChain([brush, 'access', _64 => _64.light, 'optionalAccess', _65 => _65.amount])), "light", "light paint (glow and spill)", "Remove light (or set light.amount to 0).");
2213
+ feature(profile.surfaces.includes("wet") && profile.light === "full" ? "full" : "none", !!brush.ghost, "ghost", "ghost paint", "Remove ghost.");
2133
2214
  const m = brush.motion;
2134
2215
  feature(profile.motion, !!m && (!!m.live || nonZero(m.waveSpeed) || m.fps !== void 0), "motion", "animation", "Remove motion.");
2135
2216
  const d = _nullishCoalesce(brush.dynamics, () => ( {}));
@@ -2138,16 +2219,16 @@ function checkBrush(brush, profile) {
2138
2219
  feature(profile.velocity, nonZero(d.velocitySize) || nonZero(d.velocityOpacity), "dynamics.velocity", "velocity dynamics (its strokes carry no timing)", "Set dynamics.velocitySize and velocityOpacity to 0.");
2139
2220
  feature(profile.tilt, nonZero(d.tiltSize) || nonZero(d.tiltRoundness) || nonZero(d.tiltOpacity), "dynamics.tilt", "tilt dynamics", "Set dynamics.tiltSize, tiltRoundness and tiltOpacity to 0.");
2140
2221
  const colour = brush.colour;
2141
- if (_optionalChain([colour, 'optionalAccess', _60 => _60.default]) !== void 0) {
2222
+ if (_optionalChain([colour, 'optionalAccess', _66 => _66.default]) !== void 0) {
2142
2223
  const kind = brushColourKind(colour.default);
2143
2224
  if (!profile.colours.includes(kind)) add("colour.default", "error", `${host} can't paint ${kind} colours.`, `Use a ${list(profile.colours)} colour, or remove colour.default.`);
2144
2225
  }
2145
- const foreign = [...new Set((_nullishCoalesce(_optionalChain([colour, 'optionalAccess', _61 => _61.palette]), () => ( []))).map(brushColourKind).filter((k) => !profile.colours.includes(k)))];
2226
+ const foreign = [...new Set((_nullishCoalesce(_optionalChain([colour, 'optionalAccess', _67 => _67.palette]), () => ( []))).map(brushColourKind).filter((k) => !profile.colours.includes(k)))];
2146
2227
  if (foreign.length) add("colour.palette", "warning", `${host} skips the palette's ${list(foreign)} colours.`, `Nothing to do; or keep to ${list(profile.colours)} colours.`);
2147
2228
  return { ok: !issues.some((i) => i.severity === "error"), issues };
2148
2229
  }
2149
2230
  function withKeptIssues(check, before) {
2150
- const had = new Set((_nullishCoalesce(_optionalChain([before, 'optionalAccess', _62 => _62.issues]), () => ( []))).filter((i) => i.severity === "error").map((i) => i.facet));
2231
+ const had = new Set((_nullishCoalesce(_optionalChain([before, 'optionalAccess', _68 => _68.issues]), () => ( []))).filter((i) => i.severity === "error").map((i) => i.facet));
2151
2232
  const kept = check.issues.filter((i) => i.severity === "error" && had.has(i.facet));
2152
2233
  const issues = check.issues.filter((i) => !kept.includes(i));
2153
2234
  return { ok: !issues.some((i) => i.severity === "error"), issues, kept };
@@ -2180,6 +2261,10 @@ function degrade(brush, profile, options = {}) {
2180
2261
  delete b.behaviour.surface;
2181
2262
  delete b.behaviour.wet;
2182
2263
  delete b.behaviour.thick;
2264
+ delete b.ghost;
2265
+ break;
2266
+ case "ghost":
2267
+ delete b.ghost;
2183
2268
  break;
2184
2269
  case "behaviour.exchange.reservoir":
2185
2270
  delete b.behaviour.exchange.reservoir;
@@ -2223,7 +2308,7 @@ function degrade(brush, profile, options = {}) {
2223
2308
  }
2224
2309
  dropped.push(issue);
2225
2310
  }
2226
- if (_optionalChain([b, 'access', _63 => _63.behaviour, 'optionalAccess', _64 => _64.exchange]) && !Object.keys(b.behaviour.exchange).length) delete b.behaviour.exchange;
2311
+ if (_optionalChain([b, 'access', _69 => _69.behaviour, 'optionalAccess', _70 => _70.exchange]) && !Object.keys(b.behaviour.exchange).length) delete b.behaviour.exchange;
2227
2312
  if (b.colour && !Object.keys(b.colour).length) delete b.colour;
2228
2313
  const after = checkBrush(b, profile).issues.filter((i) => i.severity === "error");
2229
2314
  return { brush: b, dropped, issues: after };
@@ -2267,7 +2352,7 @@ function parseBrushLibrary2(raw, problems = []) {
2267
2352
  if (file && file.version !== void 0 && file.version !== 1 && file.version !== 2) {
2268
2353
  throw new BrushLibraryError("invalid", `Brush library version ${JSON.stringify(file.version)} is not supported; this library reads versions 1 and 2.`);
2269
2354
  }
2270
- const v1File = _optionalChain([file, 'optionalAccess', _65 => _65.version]) === 1;
2355
+ const v1File = _optionalChain([file, 'optionalAccess', _71 => _71.version]) === 1;
2271
2356
  const out = [];
2272
2357
  items.forEach((item, i) => {
2273
2358
  const at = `brushes[${i}]`;
@@ -2528,7 +2613,7 @@ function snapshotBrushLibrary(library, onChange) {
2528
2613
  (list2) => {
2529
2614
  entries = list2;
2530
2615
  user = list2.filter((e) => !e.builtin).map((e) => e.brush);
2531
- _optionalChain([onChange, 'optionalCall', _66 => _66()]);
2616
+ _optionalChain([onChange, 'optionalCall', _72 => _72()]);
2532
2617
  },
2533
2618
  () => void 0
2534
2619
  );
@@ -2659,4 +2744,6 @@ function snapshotBrushLibrary(library, onChange) {
2659
2744
 
2660
2745
 
2661
2746
 
2662
- exports.BRUSH_PRESETS = BRUSH_PRESETS; exports.MAX_STICKER_STAMPS = MAX_STICKER_STAMPS; exports.DEFAULT_STICKER = DEFAULT_STICKER; exports.normalizeStickerSettings = normalizeStickerSettings; exports.PARTICLE_KINDS = PARTICLE_KINDS; exports.PARTICLE_RENDERS = PARTICLE_RENDERS; exports.RIBBON_PAIRS = RIBBON_PAIRS; exports.DOT_TEXTURE_ORDERS = DOT_TEXTURE_ORDERS; exports.DOT_ROTATIONS = DOT_ROTATIONS; exports.MAX_DOT_TEXTURES = MAX_DOT_TEXTURES; exports.DEFAULT_PARTICLE = DEFAULT_PARTICLE; exports.normalizeParticle = normalizeParticle; exports.DEFAULT_BRISTLE = DEFAULT_BRISTLE; exports.normalizeBristle = normalizeBristle; exports.PAINT_BRUSH_ENGINES = PAINT_BRUSH_ENGINES; exports.PAINT_BRUSH_CATEGORIES = PAINT_BRUSH_CATEGORIES; exports.WET_TOOLS = WET_TOOLS; exports.WET_MEDIA = WET_MEDIA; exports.DEFAULT_WET_BRUSH = DEFAULT_WET_BRUSH; exports.normalizeWetBrush = normalizeWetBrush; exports.IMPASTO_TOOLS = IMPASTO_TOOLS; exports.DEFAULT_IMPASTO = DEFAULT_IMPASTO; exports.DEFAULT_LIGHT = DEFAULT_LIGHT; exports.normalizeLight = normalizeLight; exports.normalizeImpasto = normalizeImpasto; exports.MULTI_COLOR_MODES = MULTI_COLOR_MODES; exports.DEFAULT_MULTI_COLOR = DEFAULT_MULTI_COLOR; exports.DEFAULT_BEHAVIOR = DEFAULT_BEHAVIOR; exports.BRUSH_ROTATIONS = BRUSH_ROTATIONS; exports.DAB_FLIPS = DAB_FLIPS; exports.TIP_GRAIN_MODES = TIP_GRAIN_MODES; exports.DEFAULT_TIP_GRAIN = DEFAULT_TIP_GRAIN; exports.DEFAULT_DYNAMICS = DEFAULT_DYNAMICS; exports.normalizeDynamics = normalizeDynamics; exports.BRUSH_ID = BRUSH_ID; exports.normalizeMultiColor = normalizeMultiColor; exports.normalizeBehavior = normalizeBehavior; exports.DEFAULT_SPRAY = DEFAULT_SPRAY; exports.isWetCapable = isWetCapable; exports.isWetBrush = isWetBrush; exports.usesPaintExchange = usesPaintExchange; exports.brushTakesPaint = brushTakesPaint; exports.paintToMultiColor = paintToMultiColor; exports.multiColorToPaint = multiColorToPaint; exports.normalizePaintBrush = normalizePaintBrush; exports.BRUSH_FIELDS = BRUSH_FIELDS; exports.getPath = getPath; exports.setPath = setPath; exports.resolveEngine = resolveEngine; exports.resolveWetMedium = resolveWetMedium; exports.resolveCategory = resolveCategory; exports.resolveBrush = resolveBrush; exports.BUILTIN_BRUSHES = BUILTIN_BRUSHES; exports.DEFAULT_BRUSH_ID = DEFAULT_BRUSH_ID; exports.brushToJSON = brushToJSON; exports.parseBrushLibrary = parseBrushLibrary; exports.migrateBrushV1 = migrateBrushV1; exports.BRUSH_KINDS = BRUSH_KINDS; exports.BRUSH_MEDIA = BRUSH_MEDIA; exports.BRUSH_TOOLS = BRUSH_TOOLS; exports.BRUSH_TIP_SHAPES = BRUSH_TIP_SHAPES; exports.BRUSH_MARKS_KINDS = BRUSH_MARKS_KINDS; exports.BRUSH_SURFACES = BRUSH_SURFACES; exports.BRUSH_GRAIN_MODES = BRUSH_GRAIN_MODES; exports.BRUSH_FLIPS = BRUSH_FLIPS; exports.MAX_BRUSH_PALETTE = MAX_BRUSH_PALETTE; exports.BRUSH_WORD = BRUSH_WORD; exports.TIP_GRAIN_PATTERNS = TIP_GRAIN_PATTERNS; exports.BRUSH_GRAIN_SOURCE_PATTERN = BRUSH_GRAIN_SOURCE_PATTERN; exports.BRUSH_JSON_SCHEMA = BRUSH_JSON_SCHEMA; exports.BRUSH_FACET_SCHEMAS = BRUSH_FACET_SCHEMAS; exports.BRUSH_SOURCE_PROVIDER = BRUSH_SOURCE_PROVIDER; exports.MAX_BRUSH_SOURCE_SIZE = MAX_BRUSH_SOURCE_SIZE; exports.MAX_BRUSH_SOURCE_INPUT_PIXELS = MAX_BRUSH_SOURCE_INPUT_PIXELS; exports.MAX_BRUSH_SOURCES = MAX_BRUSH_SOURCES; exports.BRUSH_SOURCE_CHANNELS = BRUSH_SOURCE_CHANNELS; exports.BrushSourceError = BrushSourceError; exports.brushSourceRef = brushSourceRef; exports.isBrushSourceRef = isBrushSourceRef; exports.brushSourceIdOf = brushSourceIdOf; exports.brushSourceIds = brushSourceIds; exports.summarizeBrushSource = summarizeBrushSource; exports.brushSourceIdFromName = brushSourceIdFromName; exports.brushSourceFromMask = brushSourceFromMask; exports.makeBrushSource = makeBrushSource; exports.readBrushSource = readBrushSource; exports.decodeBrushSource = decodeBrushSource; exports.WET_BRUSH_TOOLS = WET_BRUSH_TOOLS; exports.normalizeBrushSpec = normalizeBrushSpec; exports.PAINT_PROFILE = PAINT_PROFILE; exports.IMAGE_PROFILE = IMAGE_PROFILE; exports.CANVAS_PROFILE = CANVAS_PROFILE; exports.VECTOR_PROFILE = VECTOR_PROFILE; exports.BRUSH_HOST_PROFILES = BRUSH_HOST_PROFILES; exports.brushColourKind = brushColourKind; exports.checkBrush = checkBrush; exports.withKeptIssues = withKeptIssues; exports.checkBrushEdit = checkBrushEdit; exports.listPresets = listPresets; exports.degrade = degrade; exports.BrushLibraryError = BrushLibraryError; exports.isBrushLibrary = isBrushLibrary; exports.parseBrushLibrarySources = parseBrushLibrarySources; exports.parseBrushLibrary2 = parseBrushLibrary2; exports.createBrushLibrary = createBrushLibrary; exports.closest = closest; exports.snapshotBrushLibrary = snapshotBrushLibrary;
2747
+
2748
+
2749
+ exports.BRUSH_PRESETS = BRUSH_PRESETS; exports.MAX_STICKER_STAMPS = MAX_STICKER_STAMPS; exports.DEFAULT_STICKER = DEFAULT_STICKER; exports.normalizeStickerSettings = normalizeStickerSettings; exports.PARTICLE_KINDS = PARTICLE_KINDS; exports.PARTICLE_RENDERS = PARTICLE_RENDERS; exports.RIBBON_PAIRS = RIBBON_PAIRS; exports.DOT_TEXTURE_ORDERS = DOT_TEXTURE_ORDERS; exports.DOT_ROTATIONS = DOT_ROTATIONS; exports.MAX_DOT_TEXTURES = MAX_DOT_TEXTURES; exports.DEFAULT_PARTICLE = DEFAULT_PARTICLE; exports.normalizeParticle = normalizeParticle; exports.DEFAULT_BRISTLE = DEFAULT_BRISTLE; exports.normalizeBristle = normalizeBristle; exports.PAINT_BRUSH_ENGINES = PAINT_BRUSH_ENGINES; exports.PAINT_BRUSH_CATEGORIES = PAINT_BRUSH_CATEGORIES; exports.WET_TOOLS = WET_TOOLS; exports.WET_MEDIA = WET_MEDIA; exports.DEFAULT_WET_BRUSH = DEFAULT_WET_BRUSH; exports.normalizeWetBrush = normalizeWetBrush; exports.IMPASTO_TOOLS = IMPASTO_TOOLS; exports.DEFAULT_IMPASTO = DEFAULT_IMPASTO; exports.DEFAULT_LIGHT = DEFAULT_LIGHT; exports.normalizeLight = normalizeLight; exports.DEFAULT_GHOST = DEFAULT_GHOST; exports.normalizeGhost = normalizeGhost; exports.normalizeImpasto = normalizeImpasto; exports.MULTI_COLOR_MODES = MULTI_COLOR_MODES; exports.DEFAULT_MULTI_COLOR = DEFAULT_MULTI_COLOR; exports.DEFAULT_BEHAVIOR = DEFAULT_BEHAVIOR; exports.BRUSH_ROTATIONS = BRUSH_ROTATIONS; exports.DAB_FLIPS = DAB_FLIPS; exports.TIP_GRAIN_MODES = TIP_GRAIN_MODES; exports.DEFAULT_TIP_GRAIN = DEFAULT_TIP_GRAIN; exports.DEFAULT_DYNAMICS = DEFAULT_DYNAMICS; exports.normalizeDynamics = normalizeDynamics; exports.BRUSH_ID = BRUSH_ID; exports.normalizeMultiColor = normalizeMultiColor; exports.normalizeBehavior = normalizeBehavior; exports.DEFAULT_SPRAY = DEFAULT_SPRAY; exports.isWetCapable = isWetCapable; exports.isWetBrush = isWetBrush; exports.usesPaintExchange = usesPaintExchange; exports.brushTakesPaint = brushTakesPaint; exports.paintToMultiColor = paintToMultiColor; exports.multiColorToPaint = multiColorToPaint; exports.normalizePaintBrush = normalizePaintBrush; exports.BRUSH_FIELDS = BRUSH_FIELDS; exports.getPath = getPath; exports.setPath = setPath; exports.resolveEngine = resolveEngine; exports.resolveWetMedium = resolveWetMedium; exports.resolveCategory = resolveCategory; exports.resolveBrush = resolveBrush; exports.BUILTIN_BRUSHES = BUILTIN_BRUSHES; exports.DEFAULT_BRUSH_ID = DEFAULT_BRUSH_ID; exports.brushToJSON = brushToJSON; exports.parseBrushLibrary = parseBrushLibrary; exports.migrateBrushV1 = migrateBrushV1; exports.BRUSH_KINDS = BRUSH_KINDS; exports.BRUSH_MEDIA = BRUSH_MEDIA; exports.BRUSH_TOOLS = BRUSH_TOOLS; exports.BRUSH_TIP_SHAPES = BRUSH_TIP_SHAPES; exports.BRUSH_MARKS_KINDS = BRUSH_MARKS_KINDS; exports.BRUSH_SURFACES = BRUSH_SURFACES; exports.BRUSH_GRAIN_MODES = BRUSH_GRAIN_MODES; exports.BRUSH_FLIPS = BRUSH_FLIPS; exports.MAX_BRUSH_PALETTE = MAX_BRUSH_PALETTE; exports.BRUSH_WORD = BRUSH_WORD; exports.TIP_GRAIN_PATTERNS = TIP_GRAIN_PATTERNS; exports.BRUSH_GRAIN_SOURCE_PATTERN = BRUSH_GRAIN_SOURCE_PATTERN; exports.BRUSH_JSON_SCHEMA = BRUSH_JSON_SCHEMA; exports.BRUSH_FACET_SCHEMAS = BRUSH_FACET_SCHEMAS; exports.BRUSH_SOURCE_PROVIDER = BRUSH_SOURCE_PROVIDER; exports.MAX_BRUSH_SOURCE_SIZE = MAX_BRUSH_SOURCE_SIZE; exports.MAX_BRUSH_SOURCE_INPUT_PIXELS = MAX_BRUSH_SOURCE_INPUT_PIXELS; exports.MAX_BRUSH_SOURCES = MAX_BRUSH_SOURCES; exports.BRUSH_SOURCE_CHANNELS = BRUSH_SOURCE_CHANNELS; exports.BrushSourceError = BrushSourceError; exports.brushSourceRef = brushSourceRef; exports.isBrushSourceRef = isBrushSourceRef; exports.brushSourceIdOf = brushSourceIdOf; exports.brushSourceIds = brushSourceIds; exports.summarizeBrushSource = summarizeBrushSource; exports.brushSourceIdFromName = brushSourceIdFromName; exports.brushSourceFromMask = brushSourceFromMask; exports.makeBrushSource = makeBrushSource; exports.readBrushSource = readBrushSource; exports.decodeBrushSource = decodeBrushSource; exports.WET_BRUSH_TOOLS = WET_BRUSH_TOOLS; exports.normalizeBrushSpec = normalizeBrushSpec; exports.PAINT_PROFILE = PAINT_PROFILE; exports.IMAGE_PROFILE = IMAGE_PROFILE; exports.CANVAS_PROFILE = CANVAS_PROFILE; exports.VECTOR_PROFILE = VECTOR_PROFILE; exports.BRUSH_HOST_PROFILES = BRUSH_HOST_PROFILES; exports.brushColourKind = brushColourKind; exports.checkBrush = checkBrush; exports.withKeptIssues = withKeptIssues; exports.checkBrushEdit = checkBrushEdit; exports.listPresets = listPresets; exports.degrade = degrade; exports.BrushLibraryError = BrushLibraryError; exports.isBrushLibrary = isBrushLibrary; exports.parseBrushLibrarySources = parseBrushLibrarySources; exports.parseBrushLibrary2 = parseBrushLibrary2; exports.createBrushLibrary = createBrushLibrary; exports.closest = closest; exports.snapshotBrushLibrary = snapshotBrushLibrary;
@@ -1,6 +1,6 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2;
2
2
 
3
- var _chunkPY4GWSE2cjs = require('./chunk-PY4GWSE2.cjs');
3
+ var _chunkEBFPMSJOcjs = require('./chunk-EBFPMSJO.cjs');
4
4
 
5
5
 
6
6
 
@@ -1369,7 +1369,7 @@ var VideoEffectsEngine = (_class2 = class {
1369
1369
  this.slot = _nullishCoalesce(options.slot, () => ( new (0, _chunkL2JTLW6Bcjs.EffectsSlot)()));
1370
1370
  this.maxEntries = _nullishCoalesce(options.maxEntries, () => ( 120));
1371
1371
  this.toImage = _nullishCoalesce(options.toImage, () => ( defaultToImage));
1372
- this.pool = new (0, _chunkPY4GWSE2cjs.EffectRendererPool)({ maxRenderers: options.maxRenderers });
1372
+ this.pool = new (0, _chunkEBFPMSJOcjs.EffectRendererPool)({ maxRenderers: options.maxRenderers });
1373
1373
  this.detach = this.slot.subscribe(() => {
1374
1374
  this.reset();
1375
1375
  this.notify();