@pixerate/editor 0.275.1 → 0.277.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 (81) hide show
  1. package/dist/animation-editor/index.cjs +62 -62
  2. package/dist/animation-editor/index.js +6 -6
  3. package/dist/brushes/index.cjs +84 -71
  4. package/dist/brushes/index.js +20 -7
  5. package/dist/brushes/patch.d.cts +4 -4
  6. package/dist/brushes/patch.d.ts +4 -4
  7. package/dist/brushes/profiles.d.cts +4 -0
  8. package/dist/brushes/profiles.d.ts +4 -0
  9. package/dist/brushes/schema.d.cts +2 -0
  10. package/dist/brushes/schema.d.ts +2 -0
  11. package/dist/brushes/types.d.cts +32 -1
  12. package/dist/brushes/types.d.ts +32 -1
  13. package/dist/{brushstrokeRender-2RQL46WB.cjs → brushstrokeRender-7HOMKZNO.cjs} +21 -21
  14. package/dist/{brushstrokeRender-WGY4DZHF.js → brushstrokeRender-EIK3625T.js} +5 -5
  15. package/dist/canvas/index.cjs +13 -13
  16. package/dist/canvas/index.js +1 -1
  17. package/dist/{chunk-T6KNJVBP.cjs → chunk-4NZTK7LM.cjs} +35 -35
  18. package/dist/{chunk-LMG57L5A.js → chunk-CTHWXW5M.js} +121 -8
  19. package/dist/{chunk-43XJC3PP.js → chunk-DWPFGWW5.js} +1 -1
  20. package/dist/{chunk-MSWLJI4G.js → chunk-FNIWHSLI.js} +2 -2
  21. package/dist/{chunk-JDXWLCXF.cjs → chunk-H3EME3S5.cjs} +2 -2
  22. package/dist/{chunk-Y2ISSVPH.js → chunk-HHX7ST6Z.js} +167 -9
  23. package/dist/{chunk-6QNDGMK7.cjs → chunk-HRUK5TFW.cjs} +187 -45
  24. package/dist/{chunk-NIBFKXMD.cjs → chunk-IFWLZZCW.cjs} +619 -2
  25. package/dist/{chunk-W6JDUXP3.js → chunk-J23JOHPR.js} +1 -1
  26. package/dist/{chunk-HVO6XCI4.js → chunk-JPB65KQ6.js} +1 -1
  27. package/dist/{chunk-Y354ETAE.cjs → chunk-JVFGK3DK.cjs} +69 -58
  28. package/dist/{chunk-ACTHSQOI.js → chunk-LDZOXESA.js} +618 -1
  29. package/dist/{chunk-IEEY5RJV.js → chunk-LZE2QZCT.js} +1 -1
  30. package/dist/{chunk-DHC4E2DU.cjs → chunk-MITQGHN3.cjs} +121 -8
  31. package/dist/{chunk-75SYKUOT.js → chunk-N4MCWQZ7.js} +1 -1
  32. package/dist/{chunk-G5TCMKX5.js → chunk-NJLPW4MM.js} +17 -6
  33. package/dist/{chunk-STLTOISW.cjs → chunk-NPPMKMCU.cjs} +17 -17
  34. package/dist/{chunk-OLZXXAER.cjs → chunk-PEQWARCP.cjs} +408 -250
  35. package/dist/{chunk-ZM7IKQ4X.js → chunk-PPDUCZZV.js} +152 -10
  36. package/dist/{chunk-RAPNRK4R.cjs → chunk-QBZEC2JJ.cjs} +88 -88
  37. package/dist/{chunk-RJGW3RQS.js → chunk-ROURHJYT.js} +1 -1
  38. package/dist/{chunk-62MFUHSI.cjs → chunk-UQXULAMQ.cjs} +16 -16
  39. package/dist/{chunk-YYZC2EQO.cjs → chunk-VNF7A2JA.cjs} +23 -23
  40. package/dist/{chunk-C6VB7CPY.cjs → chunk-WFSYZO5Z.cjs} +1 -1
  41. package/dist/image-editor/index.cjs +880 -852
  42. package/dist/image-editor/index.js +36 -8
  43. package/dist/paint/index.cjs +33 -5
  44. package/dist/paint/index.d.cts +1 -0
  45. package/dist/paint/index.d.ts +1 -0
  46. package/dist/paint/index.js +32 -4
  47. package/dist/paint/live-patterns.d.cts +149 -0
  48. package/dist/paint/live-patterns.d.ts +149 -0
  49. package/dist/paint/wet/world.d.cts +13 -0
  50. package/dist/paint/wet/world.d.ts +13 -0
  51. package/dist/paint-editor/brush-model.d.cts +21 -1
  52. package/dist/paint-editor/brush-model.d.ts +21 -1
  53. package/dist/paint-editor/controller.d.cts +102 -1
  54. package/dist/paint-editor/controller.d.ts +102 -1
  55. package/dist/paint-editor/document.d.cts +8 -1
  56. package/dist/paint-editor/document.d.ts +8 -1
  57. package/dist/paint-editor/ferro-tools.d.cts +10 -0
  58. package/dist/paint-editor/ferro-tools.d.ts +10 -0
  59. package/dist/paint-editor/ferro.d.cts +134 -0
  60. package/dist/paint-editor/ferro.d.ts +134 -0
  61. package/dist/paint-editor/index.cjs +2291 -904
  62. package/dist/paint-editor/index.d.cts +2 -0
  63. package/dist/paint-editor/index.d.ts +2 -0
  64. package/dist/paint-editor/index.js +1533 -146
  65. package/dist/paint-editor/stroke.d.cts +14 -0
  66. package/dist/paint-editor/stroke.d.ts +14 -0
  67. package/dist/paint-editor/thick.d.cts +15 -2
  68. package/dist/paint-editor/thick.d.ts +15 -2
  69. package/dist/paint-editor/ui.d.cts +7 -1
  70. package/dist/paint-editor/ui.d.ts +7 -1
  71. package/dist/paint-editor/wet-tools.d.cts +42 -0
  72. package/dist/paint-editor/wet-tools.d.ts +42 -0
  73. package/dist/paint-editor/wet.d.cts +22 -1
  74. package/dist/paint-editor/wet.d.ts +22 -1
  75. package/dist/vector/index.cjs +1002 -1002
  76. package/dist/vector/index.js +7 -7
  77. package/package.json +1 -1
  78. package/skills/pixerate-brushes/SKILL.md +1 -0
  79. package/skills/pixerate-paint-editor/SKILL.md +11 -29
  80. package/skills/pixerate-paint-editor/references/brush-facets.md +1 -0
  81. package/skills/pixerate-paint-editor/references/ferrofluid.md +36 -0
@@ -27,7 +27,8 @@ var _chunkPFHJS4HEcjs = require('./chunk-PFHJS4HE.cjs');
27
27
 
28
28
 
29
29
 
30
- var _chunk6QNDGMK7cjs = require('./chunk-6QNDGMK7.cjs');
30
+
31
+ var _chunkHRUK5TFWcjs = require('./chunk-HRUK5TFW.cjs');
31
32
 
32
33
 
33
34
  var _chunkW5M3J7PVcjs = require('./chunk-W5M3J7PV.cjs');
@@ -38,13 +39,20 @@ var _chunkXFM3OCHUcjs = require('./chunk-XFM3OCHU.cjs');
38
39
  // src/brushes/patch.ts
39
40
  var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
40
41
  var copy = (v) => JSON.parse(JSON.stringify(v));
41
- var FACETS = _chunk6QNDGMK7cjs.BRUSH_JSON_SCHEMA.properties;
42
+ var FACETS = _chunkHRUK5TFWcjs.BRUSH_JSON_SCHEMA.properties;
42
43
  var BRUSH_PATCH_PROPERTIES = (() => {
43
44
  const { id: _id, name: _name, ...rest } = FACETS;
44
45
  const { required: _r, ...tip } = rest.tip;
45
- return { ...rest, tip: { ...tip, description: `${tip.description} In a patch, shape may be left out to keep it.` } };
46
+ const ferro = {
47
+ description: "Liquid ferrofluid paint: 0..1 (amount), or { amount, wavelength, threshold }. Rises into glossy Rosensweig spikes near magnets until cured.",
48
+ anyOf: [
49
+ { type: "number", minimum: 0, maximum: 1, description: "How much liquid ferrofluid the brush lays per dab (0..1)." },
50
+ _chunkHRUK5TFWcjs.BRUSH_FACET_SCHEMAS.ferro
51
+ ]
52
+ };
53
+ return { ...rest, tip: { ...tip, description: `${tip.description} In a patch, shape may be left out to keep it.` }, ferro };
46
54
  })();
47
- var UNSETTABLE_BRUSH_FACETS = ["description", "tags", "medium", "variety", "marks", "dynamics", "behaviour", "light", "fluorescence", "thermochromic", "iridescence", "ghost", "mutation", "motion", "colour"];
55
+ var UNSETTABLE_BRUSH_FACETS = ["description", "tags", "medium", "variety", "marks", "dynamics", "behaviour", "light", "fluorescence", "thermochromic", "iridescence", "ghost", "mutation", "ferro", "motion", "livePatterns", "colour"];
48
56
  var BRUSH_UNSET_PROPERTY = {
49
57
  type: "array",
50
58
  minItems: 1,
@@ -54,9 +62,11 @@ var BRUSH_UNSET_PROPERTY = {
54
62
  };
55
63
  function mergeBrushPatch(base, patch, path = "") {
56
64
  const out = { ...base };
57
- for (const [k, v] of Object.entries(patch)) {
58
- if (v === void 0) continue;
59
- const old = out[k];
65
+ for (const [k, rawV] of Object.entries(patch)) {
66
+ if (rawV === void 0) continue;
67
+ const v = path === "" && k === "ferro" && typeof rawV === "number" ? { amount: rawV } : rawV;
68
+ const rawOld = out[k];
69
+ const old = path === "" && k === "ferro" && typeof rawOld === "number" ? { amount: rawOld } : rawOld;
60
70
  const replaceMarks = path === "" && k === "marks" && isObject(old) && isObject(v) && old.kind !== v.kind;
61
71
  out[k] = isObject(v) && isObject(old) && !replaceMarks ? mergeBrushPatch(old, v, `${path}${k}.`) : copy(v);
62
72
  }
@@ -557,7 +567,7 @@ function idMaker(prefix) {
557
567
  return (name) => {
558
568
  const base = `${prefix}-${slug(name, 20) || "brush"}`.slice(0, 58).replace(/-+$/, "");
559
569
  let id = base;
560
- for (let n = 2; used.has(id) || !_chunk6QNDGMK7cjs.BRUSH_ID.test(id); n++) id = `${base}-${n}`;
570
+ for (let n = 2; used.has(id) || !_chunkHRUK5TFWcjs.BRUSH_ID.test(id); n++) id = `${base}-${n}`;
561
571
  used.add(id);
562
572
  return id;
563
573
  };
@@ -582,9 +592,9 @@ function readAbrPack(bytes, name, prefix, licence, pack) {
582
592
  return;
583
593
  }
584
594
  try {
585
- const source = _chunk6QNDGMK7cjs.brushSourceFromMask.call(void 0, { id: `${brushId}-shape`, name: label, licence, origin: `${name}.abr` }, tip.width, tip.height, tip.mask);
595
+ const source = _chunkHRUK5TFWcjs.brushSourceFromMask.call(void 0, { id: `${brushId}-shape`, name: label, licence, origin: `${name}.abr` }, tip.width, tip.height, tip.mask);
586
596
  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: [_chunk6QNDGMK7cjs.brushSourceRef.call(void 0, source.id)] } });
597
+ pack.brushes.push({ ...base, tip: { shape: "stamp", size: clamp2(Math.max(tip.width, tip.height), 1, 2500), spacing: _nullishCoalesce(tip.spacing, () => ( 0.25)), stamps: [_chunkHRUK5TFWcjs.brushSourceRef.call(void 0, source.id)] } });
588
598
  } catch (e) {
589
599
  pack.unsupported.push(`"${label}": ${e.message}`);
590
600
  }
@@ -626,7 +636,7 @@ function readProcreatePack(bytes, name, prefix, licence, pack) {
626
636
  const e = byName.get(`${dir}${file}`);
627
637
  if (!e) return null;
628
638
  try {
629
- const s = _chunk6QNDGMK7cjs.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}` });
639
+ const s = _chunkHRUK5TFWcjs.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
640
  pack.sources.push(s);
631
641
  return s;
632
642
  } catch (err) {
@@ -647,8 +657,8 @@ function readProcreatePack(bytes, name, prefix, licence, pack) {
647
657
  shape: shape ? "stamp" : "round",
648
658
  size: 40,
649
659
  ...plot !== void 0 ? { spacing: plot } : {},
650
- ...shape ? { stamps: [_chunk6QNDGMK7cjs.brushSourceRef.call(void 0, shape.id)] } : {},
651
- ...grain ? { grain: { source: _chunk6QNDGMK7cjs.brushSourceRef.call(void 0, grain.id), mode: "moving" } } : {}
660
+ ...shape ? { stamps: [_chunkHRUK5TFWcjs.brushSourceRef.call(void 0, shape.id)] } : {},
661
+ ...grain ? { grain: { source: _chunkHRUK5TFWcjs.brushSourceRef.call(void 0, grain.id), mode: "moving" } } : {}
652
662
  }
653
663
  });
654
664
  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 +712,17 @@ async function importBrushFile(library, file, options = {}) {
702
712
  // src/brushes/tools.ts
703
713
  var READ = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
704
714
  var WRITE = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
705
- var FACETS2 = _chunk6QNDGMK7cjs.BRUSH_JSON_SCHEMA.properties;
715
+ var FACETS2 = _chunkHRUK5TFWcjs.BRUSH_JSON_SCHEMA.properties;
706
716
  var ID = { type: "string", pattern: String(FACETS2.id.pattern), description: "Brush id from list_brush_presets (lowercase letters, digits and dashes)." };
707
717
  var FACET_PROPS = BRUSH_PATCH_PROPERTIES;
708
- var HOSTS = Object.keys(_chunk6QNDGMK7cjs.BRUSH_HOST_PROFILES);
718
+ var HOSTS = Object.keys(_chunkHRUK5TFWcjs.BRUSH_HOST_PROFILES);
709
719
  var copy2 = (v) => JSON.parse(JSON.stringify(v));
710
720
  var merge = mergeBrushPatch;
711
721
  var changedPaths = changedBrushPaths;
712
722
  function summary(entry, profile, withCheck) {
713
723
  const b = entry.brush;
714
- const engine = _chunk6QNDGMK7cjs.resolveEngine.call(void 0, b);
715
- const check = withCheck ? _chunk6QNDGMK7cjs.checkBrush.call(void 0, b, profile) : null;
724
+ const engine = _chunkHRUK5TFWcjs.resolveEngine.call(void 0, b);
725
+ const check = withCheck ? _chunkHRUK5TFWcjs.checkBrush.call(void 0, b, profile) : null;
716
726
  return {
717
727
  id: b.id,
718
728
  name: b.name,
@@ -721,47 +731,48 @@ function summary(entry, profile, withCheck) {
721
731
  ...b.medium ? { medium: b.medium } : {},
722
732
  ...b.variety ? { variety: b.variety } : {},
723
733
  ...b.tool ? { tool: b.tool } : {},
724
- category: _chunk6QNDGMK7cjs.resolveCategory.call(void 0, b, engine),
734
+ category: _chunkHRUK5TFWcjs.resolveCategory.call(void 0, b, engine),
725
735
  engine,
726
736
  tip: b.tip.shape,
727
737
  ...b.tip.size !== void 0 ? { size: b.tip.size } : {},
728
738
  marks: _nullishCoalesce(_optionalChain([b, 'access', _16 => _16.marks, 'optionalAccess', _17 => _17.kind]), () => ( "continuous")),
729
739
  surface: _nullishCoalesce(_optionalChain([b, 'access', _18 => _18.behaviour, 'optionalAccess', _19 => _19.surface]), () => ( "dry")),
730
740
  ..._optionalChain([b, 'access', _20 => _20.light, 'optionalAccess', _21 => _21.amount]) ? { light: b.light.amount } : {},
731
- ..._optionalChain([b, 'access', _22 => _22.tags, 'optionalAccess', _23 => _23.length]) ? { tags: b.tags } : {},
741
+ ..._optionalChain([b, 'access', _22 => _22.ferro, 'optionalAccess', _23 => _23.amount]) ? { ferro: b.ferro.amount } : {},
742
+ ..._optionalChain([b, 'access', _24 => _24.tags, 'optionalAccess', _25 => _25.length]) ? { tags: b.tags } : {},
732
743
  ...check ? { renderable: check.ok } : {}
733
744
  };
734
745
  }
735
746
  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
747
  var warnings = (check) => check.issues.filter((i) => i.severity === "warning");
737
748
  function createBrushLibraryTools(library, options = {}) {
738
- const profile = _nullishCoalesce(options.profile, () => ( _chunk6QNDGMK7cjs.PAINT_PROFILE));
749
+ const profile = _nullishCoalesce(options.profile, () => ( _chunkHRUK5TFWcjs.PAINT_PROFILE));
739
750
  const hostOf = (id) => {
740
751
  if (id === void 0) return profile;
741
- const p = _chunk6QNDGMK7cjs.BRUSH_HOST_PROFILES[id];
742
- if (!p) throw new (0, _chunk6QNDGMK7cjs.BrushLibraryError)("invalid", `No host "${id}"; use one of: ${HOSTS.join(", ")}.`);
752
+ const p = _chunkHRUK5TFWcjs.BRUSH_HOST_PROFILES[id];
753
+ if (!p) throw new (0, _chunkHRUK5TFWcjs.BrushLibraryError)("invalid", `No host "${id}"; use one of: ${HOSTS.join(", ")}.`);
743
754
  return p;
744
755
  };
745
756
  const entry = async (id) => {
746
757
  const found = await library.get(id);
747
758
  if (found) return found;
748
759
  const ids = (await library.list()).map((e) => e.brush.id);
749
- throw new (0, _chunk6QNDGMK7cjs.BrushLibraryError)("unknown_brush", `No brush "${id}". ${_chunk6QNDGMK7cjs.closest.call(void 0, id, ids)}list_brush_presets lists them.`);
760
+ throw new (0, _chunkHRUK5TFWcjs.BrushLibraryError)("unknown_brush", `No brush "${id}". ${_chunkHRUK5TFWcjs.closest.call(void 0, id, ids)}list_brush_presets lists them.`);
750
761
  };
751
762
  const checkFor = async (brush, p) => {
752
- const check2 = _chunk6QNDGMK7cjs.checkBrush.call(void 0, brush, p);
763
+ const check2 = _chunkHRUK5TFWcjs.checkBrush.call(void 0, brush, p);
753
764
  const issues = [...check2.issues];
754
765
  const refs = [...(_nullishCoalesce(brush.tip.stamps, () => ( []))).map((r) => ["tip.stamps", r]), ...brush.tip.grain ? [["tip.grain.source", brush.tip.grain.source]] : []];
755
766
  for (const [facet, ref] of refs) {
756
- const id = _chunk6QNDGMK7cjs.brushSourceIdOf.call(void 0, ref);
767
+ const id = _chunkHRUK5TFWcjs.brushSourceIdOf.call(void 0, ref);
757
768
  if (id === null || await library.getSource(id)) continue;
758
769
  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. ${_chunk6QNDGMK7cjs.closest.call(void 0, id, ids)}`.trim(), fix: "Add it with add_brush_source, or use a ref list_brush_sources lists." });
770
+ issues.push({ facet, severity: "error", reason: `There is no image source "${id}" in the brush library. ${_chunkHRUK5TFWcjs.closest.call(void 0, id, ids)}`.trim(), fix: "Add it with add_brush_source, or use a ref list_brush_sources lists." });
760
771
  }
761
- const provider = _optionalChain([options, 'access', _24 => _24.stickers, 'optionalCall', _25 => _25()]);
772
+ const provider = _optionalChain([options, 'access', _26 => _26.stickers, 'optionalCall', _27 => _27()]);
762
773
  if (!provider || brush.tip.shape !== "stamp") return { ok: !issues.some((i) => i.severity === "error"), issues };
763
774
  for (const ref of _nullishCoalesce(brush.tip.stamps, () => ( []))) {
764
- if (ref.startsWith("editor:") || _chunk6QNDGMK7cjs.isBrushSourceRef.call(void 0, ref)) continue;
775
+ if (ref.startsWith("editor:") || _chunkHRUK5TFWcjs.isBrushSourceRef.call(void 0, ref)) continue;
765
776
  try {
766
777
  await _chunkPFHJS4HEcjs.describeStickerRef.call(void 0, provider, ref);
767
778
  } catch (e) {
@@ -774,12 +785,12 @@ function createBrushLibraryTools(library, options = {}) {
774
785
  const problems = [];
775
786
  let brush;
776
787
  try {
777
- brush = _chunk6QNDGMK7cjs.normalizeBrushSpec.call(void 0, raw, problems);
788
+ brush = _chunkHRUK5TFWcjs.normalizeBrushSpec.call(void 0, raw, problems);
778
789
  } catch (e) {
779
- throw new (0, _chunk6QNDGMK7cjs.BrushLibraryError)("invalid", e.message);
790
+ throw new (0, _chunkHRUK5TFWcjs.BrushLibraryError)("invalid", e.message);
780
791
  }
781
- const check2 = _chunk6QNDGMK7cjs.withKeptIssues.call(void 0, await checkFor(brush, profile), original ? await checkFor(original, profile) : null);
782
- if (!check2.ok) throw new (0, _chunk6QNDGMK7cjs.BrushLibraryError)("invalid", refusal(check2, profile));
792
+ const check2 = _chunkHRUK5TFWcjs.withKeptIssues.call(void 0, await checkFor(brush, profile), original ? await checkFor(original, profile) : null);
793
+ if (!check2.ok) throw new (0, _chunkHRUK5TFWcjs.BrushLibraryError)("invalid", refusal(check2, profile));
783
794
  const saved = await library.save(brush, { overwrite });
784
795
  return { ...saved, problems, check: check2 };
785
796
  };
@@ -790,10 +801,10 @@ function createBrushLibraryTools(library, options = {}) {
790
801
  inputSchema: {
791
802
  type: "object",
792
803
  properties: {
793
- kind: { type: "string", enum: [..._chunk6QNDGMK7cjs.BRUSH_KINDS], description: "mark (lays a material) or tool (works on paint already down)." },
794
- medium: { type: "string", enum: [..._chunk6QNDGMK7cjs.BRUSH_MEDIA], description: "Marks laying this medium." },
804
+ kind: { type: "string", enum: [..._chunkHRUK5TFWcjs.BRUSH_KINDS], description: "mark (lays a material) or tool (works on paint already down)." },
805
+ medium: { type: "string", enum: [..._chunkHRUK5TFWcjs.BRUSH_MEDIA], description: "Marks laying this medium." },
795
806
  variety: { type: "string", maxLength: 40, description: "This variety (oil, watercolor, pencil, highlighter\u2026)." },
796
- tool: { type: "string", enum: [..._chunk6QNDGMK7cjs.BRUSH_TOOLS], description: "Tools that do this." },
807
+ tool: { type: "string", enum: [..._chunkHRUK5TFWcjs.BRUSH_TOOLS], description: "Tools that do this." },
797
808
  tag: { type: "string", maxLength: 40, description: "Brushes with this tag." },
798
809
  text: { type: "string", maxLength: 200, description: "Words in the id, name, description, variety or tags (each word must match the start of one)." },
799
810
  source: { type: "string", enum: ["all", "builtin", "user"], description: "all (default), builtin presets only, or user (saved) brushes only." },
@@ -820,8 +831,8 @@ function createBrushLibraryTools(library, options = {}) {
820
831
  annotations: { title: "Describe a brush", ...READ },
821
832
  handler: async ({ id }) => {
822
833
  const e = await entry(id);
823
- const engine = _chunk6QNDGMK7cjs.resolveEngine.call(void 0, e.brush);
824
- return { brush: e.brush, builtin: e.builtin, engine, category: _chunk6QNDGMK7cjs.resolveCategory.call(void 0, e.brush, engine), check: await checkFor(e.brush, profile) };
834
+ const engine = _chunkHRUK5TFWcjs.resolveEngine.call(void 0, e.brush);
835
+ return { brush: e.brush, builtin: e.builtin, engine, category: _chunkHRUK5TFWcjs.resolveCategory.call(void 0, e.brush, engine), check: await checkFor(e.brush, profile) };
825
836
  }
826
837
  };
827
838
  const check = {
@@ -839,20 +850,20 @@ function createBrushLibraryTools(library, options = {}) {
839
850
  },
840
851
  annotations: { title: "Check a brush for a host", ...READ },
841
852
  handler: async ({ id, brush, host }) => {
842
- if (id === void 0 === (brush === void 0)) throw new (0, _chunk6QNDGMK7cjs.BrushLibraryError)("invalid", "Give either id (a library brush) or brush (a spec), not both or neither.");
853
+ if (id === void 0 === (brush === void 0)) throw new (0, _chunkHRUK5TFWcjs.BrushLibraryError)("invalid", "Give either id (a library brush) or brush (a spec), not both or neither.");
843
854
  const p = hostOf(host);
844
855
  let b;
845
856
  const problems = [];
846
857
  if (id !== void 0) b = (await entry(id)).brush;
847
858
  else {
848
859
  try {
849
- b = _chunk6QNDGMK7cjs.normalizeBrushSpec.call(void 0, brush, problems);
860
+ b = _chunkHRUK5TFWcjs.normalizeBrushSpec.call(void 0, brush, problems);
850
861
  } catch (e) {
851
- throw new (0, _chunk6QNDGMK7cjs.BrushLibraryError)("invalid", e.message);
862
+ throw new (0, _chunkHRUK5TFWcjs.BrushLibraryError)("invalid", e.message);
852
863
  }
853
864
  }
854
865
  const result = await checkFor(b, p);
855
- return { host: p.id, ...result, ...problems.length ? { problems } : {}, ...!result.ok ? { degraded: _chunk6QNDGMK7cjs.degrade.call(void 0, b, p) } : {} };
866
+ return { host: p.id, ...result, ...problems.length ? { problems } : {}, ...!result.ok ? { degraded: _chunkHRUK5TFWcjs.degrade.call(void 0, b, p) } : {} };
856
867
  }
857
868
  };
858
869
  const exportTool = {
@@ -887,7 +898,7 @@ function createBrushLibraryTools(library, options = {}) {
887
898
  });
888
899
  const start = _nullishCoalesce(offset, () => ( 0));
889
900
  const page = found.slice(start, start + (_nullishCoalesce(limit, () => ( 100))));
890
- return { total: found.length, sources: page.map((x) => ({ ..._chunk6QNDGMK7cjs.summarizeBrushSource.call(void 0, x), usedBy: brushes.filter((b) => _chunk6QNDGMK7cjs.brushSourceIds.call(void 0, b).includes(x.id)).map((b) => b.id) })) };
901
+ return { total: found.length, sources: page.map((x) => ({ ..._chunkHRUK5TFWcjs.summarizeBrushSource.call(void 0, x), usedBy: brushes.filter((b) => _chunkHRUK5TFWcjs.brushSourceIds.call(void 0, b).includes(x.id)).map((b) => b.id) })) };
891
902
  }
892
903
  };
893
904
  const tools = [list, describe, check, exportTool, listSources];
@@ -911,7 +922,7 @@ function createBrushLibraryTools(library, options = {}) {
911
922
  annotations: { title: "Preview a brush", ...READ },
912
923
  handler: async ({ id, width, height, color }) => {
913
924
  const { brush } = await entry(id);
914
- const own = typeof _optionalChain([brush, 'access', _26 => _26.colour, 'optionalAccess', _27 => _27.default]) === "string" && /^#[0-9a-f]{6}/i.test(brush.colour.default) ? brush.colour.default.slice(0, 7) : void 0;
925
+ const own = typeof _optionalChain([brush, 'access', _28 => _28.colour, 'optionalAccess', _29 => _29.default]) === "string" && /^#[0-9a-f]{6}/i.test(brush.colour.default) ? brush.colour.default.slice(0, 7) : void 0;
915
926
  const w = _nullishCoalesce(width, () => ( 256));
916
927
  const h = _nullishCoalesce(height, () => ( 96));
917
928
  const image = await render(brush, { width: w, height: h, color: _nullishCoalesce(_nullishCoalesce(color, () => ( own)), () => ( "#1f2937")) });
@@ -938,12 +949,12 @@ function createBrushLibraryTools(library, options = {}) {
938
949
  },
939
950
  annotations: { title: "Save a new brush", ...WRITE },
940
951
  handler: async ({ basedOn, ...spec }) => {
941
- if (library.isBuiltin(spec.id)) throw new (0, _chunk6QNDGMK7cjs.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, _chunk6QNDGMK7cjs.BrushLibraryError)("exists", `A brush "${spec.id}" exists already; pick another id, or change it with update_brush.`);
952
+ if (library.isBuiltin(spec.id)) throw new (0, _chunkHRUK5TFWcjs.BrushLibraryError)("builtin", `"${spec.id}" is a built-in brush id; pick another id (or basedOn "${spec.id}" with a new id).`);
953
+ if (await library.get(spec.id)) throw new (0, _chunkHRUK5TFWcjs.BrushLibraryError)("exists", `A brush "${spec.id}" exists already; pick another id, or change it with update_brush.`);
943
954
  const base = basedOn !== void 0 ? (await entry(basedOn)).brush : void 0;
944
955
  const raw = base ? merge(base, spec) : spec;
945
956
  const saved = await store(raw, false);
946
- return { id: saved.brush.id, brush: saved.brush, engine: _chunk6QNDGMK7cjs.resolveEngine.call(void 0, saved.brush), problems: saved.problems, warnings: warnings(saved.check) };
957
+ return { id: saved.brush.id, brush: saved.brush, engine: _chunkHRUK5TFWcjs.resolveEngine.call(void 0, saved.brush), problems: saved.problems, warnings: warnings(saved.check) };
947
958
  }
948
959
  },
949
960
  {
@@ -964,7 +975,7 @@ function createBrushLibraryTools(library, options = {}) {
964
975
  annotations: { title: "Update a brush", ...WRITE, idempotentHint: true },
965
976
  handler: async ({ id, unset, ...patch }) => {
966
977
  const e = await entry(id);
967
- if (e.builtin) throw new (0, _chunk6QNDGMK7cjs.BrushLibraryError)("builtin", `"${id}" is a built-in brush and can't be changed; duplicate_brush makes a copy you can change.`);
978
+ if (e.builtin) throw new (0, _chunkHRUK5TFWcjs.BrushLibraryError)("builtin", `"${id}" is a built-in brush and can't be changed; duplicate_brush makes a copy you can change.`);
968
979
  const base = copy2(e.brush);
969
980
  for (const k of _nullishCoalesce(unset, () => ( []))) delete base[k];
970
981
  const saved = await store(merge(base, { ...patch, id }), true, e.brush);
@@ -974,14 +985,14 @@ function createBrushLibraryTools(library, options = {}) {
974
985
  {
975
986
  name: "add_brush_source",
976
987
  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 ${_chunk6QNDGMK7cjs.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.`,
988
+ 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 ${_chunkHRUK5TFWcjs.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
989
  inputSchema: {
979
990
  type: "object",
980
991
  properties: {
981
992
  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 ${_chunk6QNDGMK7cjs.MAX_BRUSH_SOURCE_INPUT_PIXELS} pixels; larger than ${_chunk6QNDGMK7cjs.MAX_BRUSH_SOURCE_SIZE} px it is scaled down.` },
993
+ image: { type: "string", pattern: "^data:image/png;base64,", maxLength: 4e7, description: `The image: a PNG data: URL, at most ${_chunkHRUK5TFWcjs.MAX_BRUSH_SOURCE_INPUT_PIXELS} pixels; larger than ${_chunkHRUK5TFWcjs.MAX_BRUSH_SOURCE_SIZE} px it is scaled down.` },
983
994
  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: [..._chunk6QNDGMK7cjs.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)." },
995
+ channel: { type: "string", enum: [..._chunkHRUK5TFWcjs.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
996
  invert: { type: "boolean", description: "Swap painted and empty parts (default false)." },
986
997
  licence: { type: "string", maxLength: 2e3, description: "The licence or terms the image came with, kept with the source." },
987
998
  origin: { type: "string", maxLength: 200, description: "Where it came from: a file name, a pack or a URL." },
@@ -993,7 +1004,7 @@ function createBrushLibraryTools(library, options = {}) {
993
1004
  annotations: { title: "Add a brush image source", ...WRITE },
994
1005
  handler: async ({ overwrite, ...input }) => {
995
1006
  const r = await library.addSource(input, { overwrite: !!overwrite });
996
- return { id: r.source.id, ref: _chunk6QNDGMK7cjs.brushSourceRef.call(void 0, r.source.id), width: r.source.width, height: r.source.height, problems: r.problems, replaced: r.replaced };
1007
+ return { id: r.source.id, ref: _chunkHRUK5TFWcjs.brushSourceRef.call(void 0, r.source.id), width: r.source.width, height: r.source.height, problems: r.problems, replaced: r.replaced };
997
1008
  }
998
1009
  },
999
1010
  {
@@ -1067,24 +1078,24 @@ function createBrushLibraryTools(library, options = {}) {
1067
1078
  try {
1068
1079
  bytes = _chunkW5M3J7PVcjs.base64ToBytes.call(void 0, file.replace(/^data:[^,]*,/, ""));
1069
1080
  } catch (e6) {
1070
- throw new (0, _chunk6QNDGMK7cjs.BrushLibraryError)("invalid", "file is not base64: pass the pack's bytes as base64 (a data: URL works too).");
1081
+ throw new (0, _chunkHRUK5TFWcjs.BrushLibraryError)("invalid", "file is not base64: pass the pack's bytes as base64 (a data: URL works too).");
1071
1082
  }
1072
1083
  let r;
1073
1084
  try {
1074
1085
  r = await importBrushPack(library, bytes, { fileName, ...format ? { format } : {}, ...prefix ? { prefix } : {}, ...licence ? { licence } : {}, overwrite: !!overwrite });
1075
1086
  } catch (e) {
1076
- if (e instanceof _chunk6QNDGMK7cjs.BrushLibraryError) throw e;
1077
- throw new (0, _chunk6QNDGMK7cjs.BrushLibraryError)("invalid", `${e.message} Nothing was imported.`);
1087
+ if (e instanceof _chunkHRUK5TFWcjs.BrushLibraryError) throw e;
1088
+ throw new (0, _chunkHRUK5TFWcjs.BrushLibraryError)("invalid", `${e.message} Nothing was imported.`);
1078
1089
  }
1079
1090
  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] ? _chunk6QNDGMK7cjs.checkBrush.call(void 0, entries[i].brush, profile).ok : false })) };
1091
+ return { ...r, brushes: r.brushes.map((b, i) => ({ ...b, renderable: entries[i] ? _chunkHRUK5TFWcjs.checkBrush.call(void 0, entries[i].brush, profile).ok : false })) };
1081
1092
  }
1082
1093
  }
1083
1094
  );
1084
1095
  return tools;
1085
1096
  }
1086
1097
  function createBrushLibraryToolProvider(library, options = {}) {
1087
- const profile = _nullishCoalesce(options.profile, () => ( _chunk6QNDGMK7cjs.PAINT_PROFILE));
1098
+ const profile = _nullishCoalesce(options.profile, () => ( _chunkHRUK5TFWcjs.PAINT_PROFILE));
1088
1099
  const tools = createBrushLibraryTools(library, options);
1089
1100
  return {
1090
1101
  id: _nullishCoalesce(options.id, () => ( "brushes")),
@@ -1135,7 +1146,7 @@ function brushEngineControls(brush) {
1135
1146
  const c = engineControls(brush);
1136
1147
  if (!c) return null;
1137
1148
  const mut = brush.mutation ? MUTATION_SLIDERS : [];
1138
- const wetPaint = brush.engine === "wet" && _optionalChain([brush, 'access', _28 => _28.wet, 'optionalAccess', _29 => _29.tool]) === "paint" && !brush.ghost && !brush.mutation;
1149
+ const wetPaint = brush.engine === "wet" && _optionalChain([brush, 'access', _30 => _30.wet, 'optionalAccess', _31 => _31.tool]) === "paint" && !brush.ghost && !brush.mutation;
1139
1150
  if (!(wetPaint || ["dab", "mixer", "particle", "bristle", "impasto"].includes(brush.engine))) {
1140
1151
  return mut.length ? { ...c, sliders: [...c.sliders, ...mut] } : c;
1141
1152
  }
@@ -1221,7 +1232,7 @@ function engineControls(brush) {
1221
1232
  impastoTool: true
1222
1233
  };
1223
1234
  case "wet": {
1224
- const tool = _nullishCoalesce(_optionalChain([brush, 'access', _30 => _30.wet, 'optionalAccess', _31 => _31.tool]), () => ( "paint"));
1235
+ const tool = _nullishCoalesce(_optionalChain([brush, 'access', _32 => _32.wet, 'optionalAccess', _33 => _33.tool]), () => ( "paint"));
1225
1236
  const ghost = tool === "paint" && (Boolean(brush.ghost) || Boolean(brush.mutation));
1226
1237
  const sliders = tool === "paint" ? [
1227
1238
  { path: "wet.water", label: "Water", min: 0, max: 1, step: 0.01 },