@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
@@ -27,7 +27,7 @@ var _chunkPFHJS4HEcjs = require('./chunk-PFHJS4HE.cjs');
27
27
 
28
28
 
29
29
 
30
- var _chunkEU2ZZA6Lcjs = require('./chunk-EU2ZZA6L.cjs');
30
+ var _chunkGHGBIAWQcjs = require('./chunk-GHGBIAWQ.cjs');
31
31
 
32
32
 
33
33
  var _chunkW5M3J7PVcjs = require('./chunk-W5M3J7PV.cjs');
@@ -38,13 +38,13 @@ var _chunkXFM3OCHUcjs = require('./chunk-XFM3OCHU.cjs');
38
38
  // src/brushes/patch.ts
39
39
  var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
40
40
  var copy = (v) => JSON.parse(JSON.stringify(v));
41
- var FACETS = _chunkEU2ZZA6Lcjs.BRUSH_JSON_SCHEMA.properties;
41
+ var FACETS = _chunkGHGBIAWQcjs.BRUSH_JSON_SCHEMA.properties;
42
42
  var BRUSH_PATCH_PROPERTIES = (() => {
43
43
  const { id: _id, name: _name, ...rest } = FACETS;
44
44
  const { required: _r, ...tip } = rest.tip;
45
45
  return { ...rest, tip: { ...tip, description: `${tip.description} In a patch, shape may be left out to keep it.` } };
46
46
  })();
47
- var UNSETTABLE_BRUSH_FACETS = ["description", "tags", "medium", "variety", "marks", "dynamics", "behaviour", "light", "motion", "colour"];
47
+ var UNSETTABLE_BRUSH_FACETS = ["description", "tags", "medium", "variety", "marks", "dynamics", "behaviour", "light", "ghost", "motion", "colour"];
48
48
  var BRUSH_UNSET_PROPERTY = {
49
49
  type: "array",
50
50
  minItems: 1,
@@ -557,7 +557,7 @@ function idMaker(prefix) {
557
557
  return (name) => {
558
558
  const base = `${prefix}-${slug(name, 20) || "brush"}`.slice(0, 58).replace(/-+$/, "");
559
559
  let id = base;
560
- for (let n = 2; used.has(id) || !_chunkEU2ZZA6Lcjs.BRUSH_ID.test(id); n++) id = `${base}-${n}`;
560
+ for (let n = 2; used.has(id) || !_chunkGHGBIAWQcjs.BRUSH_ID.test(id); n++) id = `${base}-${n}`;
561
561
  used.add(id);
562
562
  return id;
563
563
  };
@@ -582,9 +582,9 @@ function readAbrPack(bytes, name, prefix, licence, pack) {
582
582
  return;
583
583
  }
584
584
  try {
585
- const source = _chunkEU2ZZA6Lcjs.brushSourceFromMask.call(void 0, { id: `${brushId}-shape`, name: label, licence, origin: `${name}.abr` }, tip.width, tip.height, tip.mask);
585
+ const source = _chunkGHGBIAWQcjs.brushSourceFromMask.call(void 0, { id: `${brushId}-shape`, name: label, licence, origin: `${name}.abr` }, tip.width, tip.height, tip.mask);
586
586
  pack.sources.push(source);
587
- pack.brushes.push({ ...base, tip: { shape: "stamp", size: clamp2(Math.max(tip.width, tip.height), 1, 2500), spacing: _nullishCoalesce(tip.spacing, () => ( 0.25)), stamps: [_chunkEU2ZZA6Lcjs.brushSourceRef.call(void 0, source.id)] } });
587
+ pack.brushes.push({ ...base, tip: { shape: "stamp", size: clamp2(Math.max(tip.width, tip.height), 1, 2500), spacing: _nullishCoalesce(tip.spacing, () => ( 0.25)), stamps: [_chunkGHGBIAWQcjs.brushSourceRef.call(void 0, source.id)] } });
588
588
  } catch (e) {
589
589
  pack.unsupported.push(`"${label}": ${e.message}`);
590
590
  }
@@ -626,7 +626,7 @@ function readProcreatePack(bytes, name, prefix, licence, pack) {
626
626
  const e = byName.get(`${dir}${file}`);
627
627
  if (!e) return null;
628
628
  try {
629
- const s = _chunkEU2ZZA6Lcjs.makeBrushSource.call(void 0, { id: `${brushId}-${kind}`, name: `${label} ${kind}`, image: e.read(), channel: "lightness", licence: [licence, terms].filter(Boolean).join("\n\n") || void 0, origin: `${where}/${file}` });
629
+ const s = _chunkGHGBIAWQcjs.makeBrushSource.call(void 0, { id: `${brushId}-${kind}`, name: `${label} ${kind}`, image: e.read(), channel: "lightness", licence: [licence, terms].filter(Boolean).join("\n\n") || void 0, origin: `${where}/${file}` });
630
630
  pack.sources.push(s);
631
631
  return s;
632
632
  } catch (err) {
@@ -647,8 +647,8 @@ function readProcreatePack(bytes, name, prefix, licence, pack) {
647
647
  shape: shape ? "stamp" : "round",
648
648
  size: 40,
649
649
  ...plot !== void 0 ? { spacing: plot } : {},
650
- ...shape ? { stamps: [_chunkEU2ZZA6Lcjs.brushSourceRef.call(void 0, shape.id)] } : {},
651
- ...grain ? { grain: { source: _chunkEU2ZZA6Lcjs.brushSourceRef.call(void 0, grain.id), mode: "moving" } } : {}
650
+ ...shape ? { stamps: [_chunkGHGBIAWQcjs.brushSourceRef.call(void 0, shape.id)] } : {},
651
+ ...grain ? { grain: { source: _chunkGHGBIAWQcjs.brushSourceRef.call(void 0, grain.id), mode: "moving" } } : {}
652
652
  }
653
653
  });
654
654
  if (!settings) pack.unsupported.push(`"${label}": its Brush.archive could not be read; the brush takes its name from the file and default settings.`);
@@ -702,17 +702,17 @@ async function importBrushFile(library, file, options = {}) {
702
702
  // src/brushes/tools.ts
703
703
  var READ = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
704
704
  var WRITE = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
705
- var FACETS2 = _chunkEU2ZZA6Lcjs.BRUSH_JSON_SCHEMA.properties;
705
+ var FACETS2 = _chunkGHGBIAWQcjs.BRUSH_JSON_SCHEMA.properties;
706
706
  var ID = { type: "string", pattern: String(FACETS2.id.pattern), description: "Brush id from list_brush_presets (lowercase letters, digits and dashes)." };
707
707
  var FACET_PROPS = BRUSH_PATCH_PROPERTIES;
708
- var HOSTS = Object.keys(_chunkEU2ZZA6Lcjs.BRUSH_HOST_PROFILES);
708
+ var HOSTS = Object.keys(_chunkGHGBIAWQcjs.BRUSH_HOST_PROFILES);
709
709
  var copy2 = (v) => JSON.parse(JSON.stringify(v));
710
710
  var merge = mergeBrushPatch;
711
711
  var changedPaths = changedBrushPaths;
712
712
  function summary(entry, profile, withCheck) {
713
713
  const b = entry.brush;
714
- const engine = _chunkEU2ZZA6Lcjs.resolveEngine.call(void 0, b);
715
- const check = withCheck ? _chunkEU2ZZA6Lcjs.checkBrush.call(void 0, b, profile) : null;
714
+ const engine = _chunkGHGBIAWQcjs.resolveEngine.call(void 0, b);
715
+ const check = withCheck ? _chunkGHGBIAWQcjs.checkBrush.call(void 0, b, profile) : null;
716
716
  return {
717
717
  id: b.id,
718
718
  name: b.name,
@@ -721,7 +721,7 @@ function summary(entry, profile, withCheck) {
721
721
  ...b.medium ? { medium: b.medium } : {},
722
722
  ...b.variety ? { variety: b.variety } : {},
723
723
  ...b.tool ? { tool: b.tool } : {},
724
- category: _chunkEU2ZZA6Lcjs.resolveCategory.call(void 0, b, engine),
724
+ category: _chunkGHGBIAWQcjs.resolveCategory.call(void 0, b, engine),
725
725
  engine,
726
726
  tip: b.tip.shape,
727
727
  ...b.tip.size !== void 0 ? { size: b.tip.size } : {},
@@ -735,33 +735,33 @@ function summary(entry, profile, withCheck) {
735
735
  var refusal = (check, host) => `${host.name} can't use this brush: ${check.issues.filter((i) => i.severity === "error").map((i) => `${i.facet}: ${i.reason} ${i.fix}`).join(" ")} (check_brush lists every issue; nothing was saved.)`;
736
736
  var warnings = (check) => check.issues.filter((i) => i.severity === "warning");
737
737
  function createBrushLibraryTools(library, options = {}) {
738
- const profile = _nullishCoalesce(options.profile, () => ( _chunkEU2ZZA6Lcjs.PAINT_PROFILE));
738
+ const profile = _nullishCoalesce(options.profile, () => ( _chunkGHGBIAWQcjs.PAINT_PROFILE));
739
739
  const hostOf = (id) => {
740
740
  if (id === void 0) return profile;
741
- const p = _chunkEU2ZZA6Lcjs.BRUSH_HOST_PROFILES[id];
742
- if (!p) throw new (0, _chunkEU2ZZA6Lcjs.BrushLibraryError)("invalid", `No host "${id}"; use one of: ${HOSTS.join(", ")}.`);
741
+ const p = _chunkGHGBIAWQcjs.BRUSH_HOST_PROFILES[id];
742
+ if (!p) throw new (0, _chunkGHGBIAWQcjs.BrushLibraryError)("invalid", `No host "${id}"; use one of: ${HOSTS.join(", ")}.`);
743
743
  return p;
744
744
  };
745
745
  const entry = async (id) => {
746
746
  const found = await library.get(id);
747
747
  if (found) return found;
748
748
  const ids = (await library.list()).map((e) => e.brush.id);
749
- throw new (0, _chunkEU2ZZA6Lcjs.BrushLibraryError)("unknown_brush", `No brush "${id}". ${_chunkEU2ZZA6Lcjs.closest.call(void 0, id, ids)}list_brush_presets lists them.`);
749
+ throw new (0, _chunkGHGBIAWQcjs.BrushLibraryError)("unknown_brush", `No brush "${id}". ${_chunkGHGBIAWQcjs.closest.call(void 0, id, ids)}list_brush_presets lists them.`);
750
750
  };
751
751
  const checkFor = async (brush, p) => {
752
- const check2 = _chunkEU2ZZA6Lcjs.checkBrush.call(void 0, brush, p);
752
+ const check2 = _chunkGHGBIAWQcjs.checkBrush.call(void 0, brush, p);
753
753
  const issues = [...check2.issues];
754
754
  const refs = [...(_nullishCoalesce(brush.tip.stamps, () => ( []))).map((r) => ["tip.stamps", r]), ...brush.tip.grain ? [["tip.grain.source", brush.tip.grain.source]] : []];
755
755
  for (const [facet, ref] of refs) {
756
- const id = _chunkEU2ZZA6Lcjs.brushSourceIdOf.call(void 0, ref);
756
+ const id = _chunkGHGBIAWQcjs.brushSourceIdOf.call(void 0, ref);
757
757
  if (id === null || await library.getSource(id)) continue;
758
758
  const ids = (await library.listSources()).map((x) => x.id);
759
- issues.push({ facet, severity: "error", reason: `There is no image source "${id}" in the brush library. ${_chunkEU2ZZA6Lcjs.closest.call(void 0, id, ids)}`.trim(), fix: "Add it with add_brush_source, or use a ref list_brush_sources lists." });
759
+ issues.push({ facet, severity: "error", reason: `There is no image source "${id}" in the brush library. ${_chunkGHGBIAWQcjs.closest.call(void 0, id, ids)}`.trim(), fix: "Add it with add_brush_source, or use a ref list_brush_sources lists." });
760
760
  }
761
761
  const provider = _optionalChain([options, 'access', _24 => _24.stickers, 'optionalCall', _25 => _25()]);
762
762
  if (!provider || brush.tip.shape !== "stamp") return { ok: !issues.some((i) => i.severity === "error"), issues };
763
763
  for (const ref of _nullishCoalesce(brush.tip.stamps, () => ( []))) {
764
- if (ref.startsWith("editor:") || _chunkEU2ZZA6Lcjs.isBrushSourceRef.call(void 0, ref)) continue;
764
+ if (ref.startsWith("editor:") || _chunkGHGBIAWQcjs.isBrushSourceRef.call(void 0, ref)) continue;
765
765
  try {
766
766
  await _chunkPFHJS4HEcjs.describeStickerRef.call(void 0, provider, ref);
767
767
  } catch (e) {
@@ -774,12 +774,12 @@ function createBrushLibraryTools(library, options = {}) {
774
774
  const problems = [];
775
775
  let brush;
776
776
  try {
777
- brush = _chunkEU2ZZA6Lcjs.normalizeBrushSpec.call(void 0, raw, problems);
777
+ brush = _chunkGHGBIAWQcjs.normalizeBrushSpec.call(void 0, raw, problems);
778
778
  } catch (e) {
779
- throw new (0, _chunkEU2ZZA6Lcjs.BrushLibraryError)("invalid", e.message);
779
+ throw new (0, _chunkGHGBIAWQcjs.BrushLibraryError)("invalid", e.message);
780
780
  }
781
- const check2 = _chunkEU2ZZA6Lcjs.withKeptIssues.call(void 0, await checkFor(brush, profile), original ? await checkFor(original, profile) : null);
782
- if (!check2.ok) throw new (0, _chunkEU2ZZA6Lcjs.BrushLibraryError)("invalid", refusal(check2, profile));
781
+ const check2 = _chunkGHGBIAWQcjs.withKeptIssues.call(void 0, await checkFor(brush, profile), original ? await checkFor(original, profile) : null);
782
+ if (!check2.ok) throw new (0, _chunkGHGBIAWQcjs.BrushLibraryError)("invalid", refusal(check2, profile));
783
783
  const saved = await library.save(brush, { overwrite });
784
784
  return { ...saved, problems, check: check2 };
785
785
  };
@@ -790,10 +790,10 @@ function createBrushLibraryTools(library, options = {}) {
790
790
  inputSchema: {
791
791
  type: "object",
792
792
  properties: {
793
- kind: { type: "string", enum: [..._chunkEU2ZZA6Lcjs.BRUSH_KINDS], description: "mark (lays a material) or tool (works on paint already down)." },
794
- medium: { type: "string", enum: [..._chunkEU2ZZA6Lcjs.BRUSH_MEDIA], description: "Marks laying this medium." },
793
+ kind: { type: "string", enum: [..._chunkGHGBIAWQcjs.BRUSH_KINDS], description: "mark (lays a material) or tool (works on paint already down)." },
794
+ medium: { type: "string", enum: [..._chunkGHGBIAWQcjs.BRUSH_MEDIA], description: "Marks laying this medium." },
795
795
  variety: { type: "string", maxLength: 40, description: "This variety (oil, watercolor, pencil, highlighter\u2026)." },
796
- tool: { type: "string", enum: [..._chunkEU2ZZA6Lcjs.BRUSH_TOOLS], description: "Tools that do this." },
796
+ tool: { type: "string", enum: [..._chunkGHGBIAWQcjs.BRUSH_TOOLS], description: "Tools that do this." },
797
797
  tag: { type: "string", maxLength: 40, description: "Brushes with this tag." },
798
798
  text: { type: "string", maxLength: 200, description: "Words in the id, name, description, variety or tags (each word must match the start of one)." },
799
799
  source: { type: "string", enum: ["all", "builtin", "user"], description: "all (default), builtin presets only, or user (saved) brushes only." },
@@ -820,8 +820,8 @@ function createBrushLibraryTools(library, options = {}) {
820
820
  annotations: { title: "Describe a brush", ...READ },
821
821
  handler: async ({ id }) => {
822
822
  const e = await entry(id);
823
- const engine = _chunkEU2ZZA6Lcjs.resolveEngine.call(void 0, e.brush);
824
- return { brush: e.brush, builtin: e.builtin, engine, category: _chunkEU2ZZA6Lcjs.resolveCategory.call(void 0, e.brush, engine), check: await checkFor(e.brush, profile) };
823
+ const engine = _chunkGHGBIAWQcjs.resolveEngine.call(void 0, e.brush);
824
+ return { brush: e.brush, builtin: e.builtin, engine, category: _chunkGHGBIAWQcjs.resolveCategory.call(void 0, e.brush, engine), check: await checkFor(e.brush, profile) };
825
825
  }
826
826
  };
827
827
  const check = {
@@ -839,20 +839,20 @@ function createBrushLibraryTools(library, options = {}) {
839
839
  },
840
840
  annotations: { title: "Check a brush for a host", ...READ },
841
841
  handler: async ({ id, brush, host }) => {
842
- if (id === void 0 === (brush === void 0)) throw new (0, _chunkEU2ZZA6Lcjs.BrushLibraryError)("invalid", "Give either id (a library brush) or brush (a spec), not both or neither.");
842
+ if (id === void 0 === (brush === void 0)) throw new (0, _chunkGHGBIAWQcjs.BrushLibraryError)("invalid", "Give either id (a library brush) or brush (a spec), not both or neither.");
843
843
  const p = hostOf(host);
844
844
  let b;
845
845
  const problems = [];
846
846
  if (id !== void 0) b = (await entry(id)).brush;
847
847
  else {
848
848
  try {
849
- b = _chunkEU2ZZA6Lcjs.normalizeBrushSpec.call(void 0, brush, problems);
849
+ b = _chunkGHGBIAWQcjs.normalizeBrushSpec.call(void 0, brush, problems);
850
850
  } catch (e) {
851
- throw new (0, _chunkEU2ZZA6Lcjs.BrushLibraryError)("invalid", e.message);
851
+ throw new (0, _chunkGHGBIAWQcjs.BrushLibraryError)("invalid", e.message);
852
852
  }
853
853
  }
854
854
  const result = await checkFor(b, p);
855
- return { host: p.id, ...result, ...problems.length ? { problems } : {}, ...!result.ok ? { degraded: _chunkEU2ZZA6Lcjs.degrade.call(void 0, b, p) } : {} };
855
+ return { host: p.id, ...result, ...problems.length ? { problems } : {}, ...!result.ok ? { degraded: _chunkGHGBIAWQcjs.degrade.call(void 0, b, p) } : {} };
856
856
  }
857
857
  };
858
858
  const exportTool = {
@@ -887,7 +887,7 @@ function createBrushLibraryTools(library, options = {}) {
887
887
  });
888
888
  const start = _nullishCoalesce(offset, () => ( 0));
889
889
  const page = found.slice(start, start + (_nullishCoalesce(limit, () => ( 100))));
890
- return { total: found.length, sources: page.map((x) => ({ ..._chunkEU2ZZA6Lcjs.summarizeBrushSource.call(void 0, x), usedBy: brushes.filter((b) => _chunkEU2ZZA6Lcjs.brushSourceIds.call(void 0, b).includes(x.id)).map((b) => b.id) })) };
890
+ return { total: found.length, sources: page.map((x) => ({ ..._chunkGHGBIAWQcjs.summarizeBrushSource.call(void 0, x), usedBy: brushes.filter((b) => _chunkGHGBIAWQcjs.brushSourceIds.call(void 0, b).includes(x.id)).map((b) => b.id) })) };
891
891
  }
892
892
  };
893
893
  const tools = [list, describe, check, exportTool, listSources];
@@ -938,12 +938,12 @@ function createBrushLibraryTools(library, options = {}) {
938
938
  },
939
939
  annotations: { title: "Save a new brush", ...WRITE },
940
940
  handler: async ({ basedOn, ...spec }) => {
941
- if (library.isBuiltin(spec.id)) throw new (0, _chunkEU2ZZA6Lcjs.BrushLibraryError)("builtin", `"${spec.id}" is a built-in brush id; pick another id (or basedOn "${spec.id}" with a new id).`);
942
- if (await library.get(spec.id)) throw new (0, _chunkEU2ZZA6Lcjs.BrushLibraryError)("exists", `A brush "${spec.id}" exists already; pick another id, or change it with update_brush.`);
941
+ if (library.isBuiltin(spec.id)) throw new (0, _chunkGHGBIAWQcjs.BrushLibraryError)("builtin", `"${spec.id}" is a built-in brush id; pick another id (or basedOn "${spec.id}" with a new id).`);
942
+ if (await library.get(spec.id)) throw new (0, _chunkGHGBIAWQcjs.BrushLibraryError)("exists", `A brush "${spec.id}" exists already; pick another id, or change it with update_brush.`);
943
943
  const base = basedOn !== void 0 ? (await entry(basedOn)).brush : void 0;
944
944
  const raw = base ? merge(base, spec) : spec;
945
945
  const saved = await store(raw, false);
946
- return { id: saved.brush.id, brush: saved.brush, engine: _chunkEU2ZZA6Lcjs.resolveEngine.call(void 0, saved.brush), problems: saved.problems, warnings: warnings(saved.check) };
946
+ return { id: saved.brush.id, brush: saved.brush, engine: _chunkGHGBIAWQcjs.resolveEngine.call(void 0, saved.brush), problems: saved.problems, warnings: warnings(saved.check) };
947
947
  }
948
948
  },
949
949
  {
@@ -964,7 +964,7 @@ function createBrushLibraryTools(library, options = {}) {
964
964
  annotations: { title: "Update a brush", ...WRITE, idempotentHint: true },
965
965
  handler: async ({ id, unset, ...patch }) => {
966
966
  const e = await entry(id);
967
- if (e.builtin) throw new (0, _chunkEU2ZZA6Lcjs.BrushLibraryError)("builtin", `"${id}" is a built-in brush and can't be changed; duplicate_brush makes a copy you can change.`);
967
+ if (e.builtin) throw new (0, _chunkGHGBIAWQcjs.BrushLibraryError)("builtin", `"${id}" is a built-in brush and can't be changed; duplicate_brush makes a copy you can change.`);
968
968
  const base = copy2(e.brush);
969
969
  for (const k of _nullishCoalesce(unset, () => ( []))) delete base[k];
970
970
  const saved = await store(merge(base, { ...patch, id }), true, e.brush);
@@ -974,14 +974,14 @@ function createBrushLibraryTools(library, options = {}) {
974
974
  {
975
975
  name: "add_brush_source",
976
976
  title: "Add a brush image source",
977
- description: `Adds an image to the brush library as a source for image tips and image grain (as Procreate's shape and grain sources). The image is a PNG data: URL; the marks are read from its transparency, its dark parts (a scan of marks on paper) or its light parts (white on black), as channel says, and kept as a grey mask at most ${_chunkEU2ZZA6Lcjs.MAX_BRUSH_SOURCE_SIZE} px on a side. Returns id, ref (source:<id>), the stored source's width and height, problems (the channel auto picked, scaling) and replaced. Then make the brush: create_brush or update_brush with tip { shape: "stamp", stamps: [ref] } for an image tip, or tip.grain { source: ref } for grain. A taken id is refused unless overwrite.`,
977
+ description: `Adds an image to the brush library as a source for image tips and image grain (as Procreate's shape and grain sources). The image is a PNG data: URL; the marks are read from its transparency, its dark parts (a scan of marks on paper) or its light parts (white on black), as channel says, and kept as a grey mask at most ${_chunkGHGBIAWQcjs.MAX_BRUSH_SOURCE_SIZE} px on a side. Returns id, ref (source:<id>), the stored source's width and height, problems (the channel auto picked, scaling) and replaced. Then make the brush: create_brush or update_brush with tip { shape: "stamp", stamps: [ref] } for an image tip, or tip.grain { source: ref } for grain. A taken id is refused unless overwrite.`,
978
978
  inputSchema: {
979
979
  type: "object",
980
980
  properties: {
981
981
  name: { type: "string", minLength: 1, maxLength: 80, description: 'Display name, e.g. "Charcoal scan".' },
982
- image: { type: "string", pattern: "^data:image/png;base64,", maxLength: 4e7, description: `The image: a PNG data: URL, at most ${_chunkEU2ZZA6Lcjs.MAX_BRUSH_SOURCE_INPUT_PIXELS} pixels; larger than ${_chunkEU2ZZA6Lcjs.MAX_BRUSH_SOURCE_SIZE} px it is scaled down.` },
982
+ image: { type: "string", pattern: "^data:image/png;base64,", maxLength: 4e7, description: `The image: a PNG data: URL, at most ${_chunkGHGBIAWQcjs.MAX_BRUSH_SOURCE_INPUT_PIXELS} pixels; larger than ${_chunkGHGBIAWQcjs.MAX_BRUSH_SOURCE_SIZE} px it is scaled down.` },
983
983
  id: { type: "string", pattern: String(FACETS2.id.pattern), description: "The source id (default: from the name, made unique): lowercase letters, digits and dashes." },
984
- channel: { type: "string", enum: [..._chunkEU2ZZA6Lcjs.BRUSH_SOURCE_CHANNELS], description: "Where the marks are: auto (default: the transparency when the image has any, else the dark parts), alpha, darkness (dark marks on light paper) or lightness (light marks on black)." },
984
+ channel: { type: "string", enum: [..._chunkGHGBIAWQcjs.BRUSH_SOURCE_CHANNELS], description: "Where the marks are: auto (default: the transparency when the image has any, else the dark parts), alpha, darkness (dark marks on light paper) or lightness (light marks on black)." },
985
985
  invert: { type: "boolean", description: "Swap painted and empty parts (default false)." },
986
986
  licence: { type: "string", maxLength: 2e3, description: "The licence or terms the image came with, kept with the source." },
987
987
  origin: { type: "string", maxLength: 200, description: "Where it came from: a file name, a pack or a URL." },
@@ -993,7 +993,7 @@ function createBrushLibraryTools(library, options = {}) {
993
993
  annotations: { title: "Add a brush image source", ...WRITE },
994
994
  handler: async ({ overwrite, ...input }) => {
995
995
  const r = await library.addSource(input, { overwrite: !!overwrite });
996
- return { id: r.source.id, ref: _chunkEU2ZZA6Lcjs.brushSourceRef.call(void 0, r.source.id), width: r.source.width, height: r.source.height, problems: r.problems, replaced: r.replaced };
996
+ return { id: r.source.id, ref: _chunkGHGBIAWQcjs.brushSourceRef.call(void 0, r.source.id), width: r.source.width, height: r.source.height, problems: r.problems, replaced: r.replaced };
997
997
  }
998
998
  },
999
999
  {
@@ -1067,24 +1067,24 @@ function createBrushLibraryTools(library, options = {}) {
1067
1067
  try {
1068
1068
  bytes = _chunkW5M3J7PVcjs.base64ToBytes.call(void 0, file.replace(/^data:[^,]*,/, ""));
1069
1069
  } catch (e6) {
1070
- throw new (0, _chunkEU2ZZA6Lcjs.BrushLibraryError)("invalid", "file is not base64: pass the pack's bytes as base64 (a data: URL works too).");
1070
+ throw new (0, _chunkGHGBIAWQcjs.BrushLibraryError)("invalid", "file is not base64: pass the pack's bytes as base64 (a data: URL works too).");
1071
1071
  }
1072
1072
  let r;
1073
1073
  try {
1074
1074
  r = await importBrushPack(library, bytes, { fileName, ...format ? { format } : {}, ...prefix ? { prefix } : {}, ...licence ? { licence } : {}, overwrite: !!overwrite });
1075
1075
  } catch (e) {
1076
- if (e instanceof _chunkEU2ZZA6Lcjs.BrushLibraryError) throw e;
1077
- throw new (0, _chunkEU2ZZA6Lcjs.BrushLibraryError)("invalid", `${e.message} Nothing was imported.`);
1076
+ if (e instanceof _chunkGHGBIAWQcjs.BrushLibraryError) throw e;
1077
+ throw new (0, _chunkGHGBIAWQcjs.BrushLibraryError)("invalid", `${e.message} Nothing was imported.`);
1078
1078
  }
1079
1079
  const entries = await Promise.all(r.brushes.map((b) => library.get(b.id)));
1080
- return { ...r, brushes: r.brushes.map((b, i) => ({ ...b, renderable: entries[i] ? _chunkEU2ZZA6Lcjs.checkBrush.call(void 0, entries[i].brush, profile).ok : false })) };
1080
+ return { ...r, brushes: r.brushes.map((b, i) => ({ ...b, renderable: entries[i] ? _chunkGHGBIAWQcjs.checkBrush.call(void 0, entries[i].brush, profile).ok : false })) };
1081
1081
  }
1082
1082
  }
1083
1083
  );
1084
1084
  return tools;
1085
1085
  }
1086
1086
  function createBrushLibraryToolProvider(library, options = {}) {
1087
- const profile = _nullishCoalesce(options.profile, () => ( _chunkEU2ZZA6Lcjs.PAINT_PROFILE));
1087
+ const profile = _nullishCoalesce(options.profile, () => ( _chunkGHGBIAWQcjs.PAINT_PROFILE));
1088
1088
  const tools = createBrushLibraryTools(library, options);
1089
1089
  return {
1090
1090
  id: _nullishCoalesce(options.id, () => ( "brushes")),
@@ -1117,9 +1117,13 @@ var PICKUP_SLIDERS = [
1117
1117
  { path: "behavior.pickup", label: "Pick-up", min: 0, max: 1, step: 0.01 },
1118
1118
  { path: "behavior.mix", label: "Mix", min: 0, max: 1, step: 0.01 }
1119
1119
  ];
1120
+ var GHOST_SLIDERS = [
1121
+ { path: "ghost.linger", label: "Linger", min: 0.5, max: 60, step: 0.5 },
1122
+ { path: "ghost.smear", label: "Smear", min: 0, max: 1, step: 0.01 }
1123
+ ];
1120
1124
  function brushEngineControls(brush) {
1121
1125
  const c = engineControls(brush);
1122
- const wetPaint = brush.engine === "wet" && _optionalChain([brush, 'access', _28 => _28.wet, 'optionalAccess', _29 => _29.tool]) === "paint";
1126
+ const wetPaint = brush.engine === "wet" && _optionalChain([brush, 'access', _28 => _28.wet, 'optionalAccess', _29 => _29.tool]) === "paint" && !brush.ghost;
1123
1127
  if (!c || !(wetPaint || ["dab", "mixer", "particle", "bristle", "impasto"].includes(brush.engine))) return c;
1124
1128
  const extra = brush.engine === "impasto" ? [{ path: "impasto.rim", label: "Rim", min: 0, max: 1, step: 0.01 }, { path: "impasto.clarity", label: "Clarity", min: 0, max: 1, step: 0.01 }] : [];
1125
1129
  return { ...c, sliders: [...c.sliders, LIGHT_SLIDER, ...extra], light: true };
@@ -1203,6 +1207,7 @@ function engineControls(brush) {
1203
1207
  };
1204
1208
  case "wet": {
1205
1209
  const tool = _nullishCoalesce(_optionalChain([brush, 'access', _30 => _30.wet, 'optionalAccess', _31 => _31.tool]), () => ( "paint"));
1210
+ const ghost = tool === "paint" && Boolean(brush.ghost);
1206
1211
  const sliders = tool === "paint" ? [
1207
1212
  { path: "wet.water", label: "Water", min: 0, max: 1, step: 0.01 },
1208
1213
  { path: "wet.pigment", label: "Pigment", min: 0, max: 1, step: 0.01 },
@@ -1210,12 +1215,12 @@ function engineControls(brush) {
1210
1215
  { path: "wet.rewet", label: "Re-wet", min: 0, max: 1, step: 0.01 },
1211
1216
  { path: "wet.load", label: "Load", min: 0, max: 1, step: 0.01 },
1212
1217
  { path: "wet.thinner", label: "Thinner", min: 0, max: 1, step: 0.01 },
1213
- ...PICKUP_SLIDERS
1218
+ ...ghost ? GHOST_SLIDERS : PICKUP_SLIDERS
1214
1219
  ] : tool === "water" ? [
1215
1220
  { path: "wet.water", label: "Water", min: 0, max: 1, step: 0.01 },
1216
1221
  { path: "wet.rewet", label: "Re-wet", min: 0, max: 1, step: 0.01 }
1217
1222
  ] : [{ path: "wet.strength", label: "Strength", min: 0, max: 1, step: 0.01 }];
1218
- return { title: "Wet brush", sliders, mixingPath: tool === "paint" ? "behavior.mixing" : null, dirty: tool === "paint", multicolor: false, load: tool === "paint", wetTool: true };
1223
+ return { title: "Wet brush", sliders, mixingPath: tool === "paint" ? "behavior.mixing" : null, dirty: tool === "paint" && !ghost, multicolor: false, load: tool === "paint" && !ghost, wetTool: true };
1219
1224
  }
1220
1225
  case "blender":
1221
1226
  return {
@@ -1287,4 +1292,5 @@ function patchBrushValue(brush, path, value) {
1287
1292
 
1288
1293
 
1289
1294
 
1290
- exports.BRUSH_PATCH_PROPERTIES = BRUSH_PATCH_PROPERTIES; exports.UNSETTABLE_BRUSH_FACETS = UNSETTABLE_BRUSH_FACETS; exports.BRUSH_UNSET_PROPERTY = BRUSH_UNSET_PROPERTY; exports.mergeBrushPatch = mergeBrushPatch; exports.changedBrushPaths = changedBrushPaths; exports.AbrError = AbrError; exports.readAbr = readAbr; exports.BRUSH_PACK_FORMATS = BRUSH_PACK_FORMATS; exports.MAX_BRUSH_PACK_BYTES = MAX_BRUSH_PACK_BYTES; exports.MAX_PACK_BRUSHES = MAX_PACK_BRUSHES; exports.BrushPackError = BrushPackError; exports.brushPackFormat = brushPackFormat; exports.readBrushPack = readBrushPack; exports.importBrushPack = importBrushPack; exports.importBrushFile = importBrushFile; exports.createBrushLibraryTools = createBrushLibraryTools; exports.createBrushLibraryToolProvider = createBrushLibraryToolProvider; exports.BRUSH_SLIDERS = BRUSH_SLIDERS; exports.brushEngineControls = brushEngineControls; exports.multiColorSliders = multiColorSliders; exports.patchBrushValue = patchBrushValue;
1295
+
1296
+ exports.BRUSH_PATCH_PROPERTIES = BRUSH_PATCH_PROPERTIES; exports.UNSETTABLE_BRUSH_FACETS = UNSETTABLE_BRUSH_FACETS; exports.BRUSH_UNSET_PROPERTY = BRUSH_UNSET_PROPERTY; exports.mergeBrushPatch = mergeBrushPatch; exports.changedBrushPaths = changedBrushPaths; exports.AbrError = AbrError; exports.readAbr = readAbr; exports.BRUSH_PACK_FORMATS = BRUSH_PACK_FORMATS; exports.MAX_BRUSH_PACK_BYTES = MAX_BRUSH_PACK_BYTES; exports.MAX_PACK_BRUSHES = MAX_PACK_BRUSHES; exports.BrushPackError = BrushPackError; exports.brushPackFormat = brushPackFormat; exports.readBrushPack = readBrushPack; exports.importBrushPack = importBrushPack; exports.importBrushFile = importBrushFile; exports.createBrushLibraryTools = createBrushLibraryTools; exports.createBrushLibraryToolProvider = createBrushLibraryToolProvider; exports.BRUSH_SLIDERS = BRUSH_SLIDERS; exports.GHOST_SLIDERS = GHOST_SLIDERS; exports.brushEngineControls = brushEngineControls; exports.multiColorSliders = multiColorSliders; exports.patchBrushValue = patchBrushValue;
@@ -115,7 +115,7 @@ import {
115
115
  transformTextRect,
116
116
  translateMatrix,
117
117
  warpPresetMesh
118
- } from "./chunk-FUDP5QBB.js";
118
+ } from "./chunk-ZEI7ZEA4.js";
119
119
  import {
120
120
  bezierPathBounds,
121
121
  outlineStroke,
@@ -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; }
2
2
 
3
- var _chunkEU2ZZA6Lcjs = require('./chunk-EU2ZZA6L.cjs');
3
+ var _chunkGHGBIAWQcjs = require('./chunk-GHGBIAWQ.cjs');
4
4
 
5
5
 
6
6
  var _chunkJBZRVLXVcjs = require('./chunk-JBZRVLXV.cjs');
@@ -44,7 +44,7 @@ function brushPreviewStrength(brush) {
44
44
  }
45
45
  var over = (fg, bg, alpha) => ({ r: fg.r * alpha + bg.r * (1 - alpha), g: fg.g * alpha + bg.g * (1 - alpha), b: fg.b * alpha + bg.b * (1 - alpha), a: 1 });
46
46
  function brushPreviewColours(brush, options = {}) {
47
- const profile = _nullishCoalesce(options.profile, () => ( _chunkEU2ZZA6Lcjs.PAINT_PROFILE));
47
+ const profile = _nullishCoalesce(options.profile, () => ( _chunkGHGBIAWQcjs.PAINT_PROFILE));
48
48
  let background = profile.light === "full" && brushPreviewsOnDark(brush) ? BRUSH_PREVIEW_DARK_PAPER : hexOf(_nullishCoalesce(options.paper, () => ( "#ffffff")));
49
49
  if (!options.keepPaper && brush.tip.blend === "multiply" && _chunk5UEFBM2Mcjs.relativeLuminance.call(void 0, _chunk5UEFBM2Mcjs.parseColor.call(void 0, background)) < 0.18) background = "#ffffff";
50
50
  const bg = _chunk5UEFBM2Mcjs.parseColor.call(void 0, background);
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  PAINT_PROFILE
3
- } from "./chunk-KZI3YWKW.js";
3
+ } from "./chunk-UXYCY3HP.js";
4
4
  import {
5
5
  brushColourHex
6
6
  } from "./chunk-DVPQFMH6.js";
@@ -74,7 +74,7 @@ function profileAlongPolyline(points, values, count = 32) {
74
74
  var round3 = (v) => Math.round(v * 1e3) / 1e3;
75
75
  var loading = null;
76
76
  function loadCanvasBrushstrokeRenderer() {
77
- loading ??= import("./brushstrokeRender-A727TTNQ.js").catch((error) => {
77
+ loading ??= import("./brushstrokeRender-DZGFU3J4.js").catch((error) => {
78
78
  loading = null;
79
79
  throw error;
80
80
  });
@@ -9,6 +9,19 @@ var EffectRendererPool = (_class = class {
9
9
  get size() {
10
10
  return this.entries.size;
11
11
  }
12
+ /**
13
+ * Renders `request` on the caller's stack when this size's renderer is warm, idle and has
14
+ * `renderSync`; otherwise `null`, and nothing is rendered (an asynchronous provider never pays for it).
15
+ */
16
+ renderSync(provider, id, size, request) {
17
+ const depth = _nullishCoalesce(size.depth, () => ( 8));
18
+ const key = `${provider.id}:${id}@${size.width}x${size.height}x${depth}`;
19
+ const entry = this.entries.get(key);
20
+ if (!_optionalChain([entry, 'optionalAccess', _ => _.resolved, 'optionalAccess', _2 => _2.renderSync]) || entry.busy > 0) return null;
21
+ this.entries.delete(key);
22
+ this.entries.set(key, entry);
23
+ return entry.resolved.renderSync(request);
24
+ }
12
25
  /** Renders `request` with the provider's renderer for this effect, size and depth (made on first use). */
13
26
  render(provider, id, size, request) {
14
27
  const depth = _nullishCoalesce(size.depth, () => ( 8));
@@ -19,15 +32,24 @@ var EffectRendererPool = (_class = class {
19
32
  this.entries.set(key, entry);
20
33
  } else {
21
34
  const renderer = Promise.resolve().then(() => provider.createRenderer(id, { width: size.width, height: size.height, depth }));
22
- renderer.catch(() => {
23
- if (_optionalChain([this, 'access', _ => _.entries, 'access', _2 => _2.get, 'call', _3 => _3(key), 'optionalAccess', _4 => _4.renderer]) === renderer) this.entries.delete(key);
24
- });
25
- entry = { renderer, queue: Promise.resolve() };
35
+ const created = { renderer, busy: 0, queue: Promise.resolve() };
36
+ renderer.then(
37
+ (r) => {
38
+ created.resolved = r;
39
+ },
40
+ () => {
41
+ if (_optionalChain([this, 'access', _3 => _3.entries, 'access', _4 => _4.get, 'call', _5 => _5(key), 'optionalAccess', _6 => _6.renderer]) === renderer) this.entries.delete(key);
42
+ }
43
+ );
44
+ entry = created;
26
45
  this.entries.set(key, entry);
27
46
  this.evict();
28
47
  }
29
48
  const e = entry;
30
- const next = e.queue.then(() => e.renderer).then((r) => r.render(request));
49
+ e.busy++;
50
+ const next = e.queue.then(() => e.renderer).then((r) => r.render(request)).finally(() => {
51
+ e.busy--;
52
+ });
31
53
  e.queue = next.catch(() => void 0);
32
54
  return next;
33
55
  }