@pixerate/editor 0.255.0 → 0.257.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 (129) hide show
  1. package/dist/agent/index.cjs +40 -38
  2. package/dist/agent/index.js +9 -7
  3. package/dist/animation/index.cjs +4 -2
  4. package/dist/animation/index.js +4 -2
  5. package/dist/animation-editor/index.cjs +63 -61
  6. package/dist/animation-editor/index.js +7 -5
  7. package/dist/brushes/colour.d.cts +11 -0
  8. package/dist/brushes/colour.d.ts +11 -0
  9. package/dist/brushes/index.cjs +51 -30
  10. package/dist/brushes/index.d.cts +1 -0
  11. package/dist/brushes/index.d.ts +1 -0
  12. package/dist/brushes/index.js +25 -4
  13. package/dist/brushes/resolve.d.cts +2 -0
  14. package/dist/brushes/resolve.d.ts +2 -0
  15. package/dist/brushes/schema.d.cts +1 -0
  16. package/dist/brushes/schema.d.ts +1 -0
  17. package/dist/brushes/tools.d.cts +7 -0
  18. package/dist/brushes/tools.d.ts +7 -0
  19. package/dist/brushes/types.d.cts +10 -2
  20. package/dist/brushes/types.d.ts +10 -2
  21. package/dist/brushes/ui.d.cts +14 -3
  22. package/dist/brushes/ui.d.ts +14 -3
  23. package/dist/{brushstrokeRender-HCOQUSWW.js → brushstrokeRender-JI4W6F2G.js} +2 -2
  24. package/dist/{brushstrokeRender-ZZOXI5O5.cjs → brushstrokeRender-MQ6PSDM5.cjs} +11 -11
  25. package/dist/canvas/index.cjs +20 -18
  26. package/dist/canvas/index.js +7 -5
  27. package/dist/chart/index.cjs +159 -157
  28. package/dist/chart/index.js +9 -7
  29. package/dist/{chunk-7272D3K2.js → chunk-2EUW2XZX.js} +27 -276
  30. package/dist/{chunk-L6Y7TSQ4.js → chunk-2VJ6OVJV.js} +1 -1
  31. package/dist/{chunk-6ZZKRH7R.js → chunk-47V3WXDG.js} +2 -2
  32. package/dist/{chunk-H7ET2ISK.cjs → chunk-4IMD2TLY.cjs} +52 -52
  33. package/dist/{chunk-VUKUTT2W.js → chunk-4M4E3N6X.js} +1 -1
  34. package/dist/{chunk-TBAVCLEQ.cjs → chunk-5Q5MLXAD.cjs} +23 -23
  35. package/dist/{chunk-MONXNVZK.js → chunk-6I23ZCGK.js} +5 -3
  36. package/dist/{chunk-GOBOCZZI.js → chunk-6NQPKNUZ.js} +1 -1
  37. package/dist/{chunk-WYGSR3IJ.js → chunk-AORZ5M5C.js} +1 -1
  38. package/dist/chunk-AVTPZO4Z.cjs +142 -0
  39. package/dist/{chunk-WKMUBATU.js → chunk-C2WEIEUB.js} +1 -1
  40. package/dist/{chunk-P3K2JCJA.js → chunk-D5BXSOSU.js} +3 -3
  41. package/dist/chunk-E2V5DA3W.js +36 -0
  42. package/dist/{chunk-WZOGDKCQ.js → chunk-F7CPSRLN.js} +0 -133
  43. package/dist/chunk-FJBQTZS4.js +17 -0
  44. package/dist/{chunk-SOSBOS5T.cjs → chunk-G23BTQA5.cjs} +22 -22
  45. package/dist/{chunk-EUIDTZNQ.cjs → chunk-I3Y2Q3PM.cjs} +59 -308
  46. package/dist/{chunk-YHUMGBZD.js → chunk-ICTPLVSR.js} +22 -4
  47. package/dist/{chunk-LRNUZKWV.cjs → chunk-IPUTIUGQ.cjs} +1 -1
  48. package/dist/{chunk-6GRUVGKU.js → chunk-ITURMC2M.js} +3 -3
  49. package/dist/{chunk-HYWRU5VX.js → chunk-IXQZHCOF.js} +1 -1
  50. package/dist/chunk-J5UQHWVL.js +142 -0
  51. package/dist/{chunk-YBAPT7NL.js → chunk-JC2SHA4A.js} +1 -23
  52. package/dist/chunk-LRTR4ASZ.cjs +17 -0
  53. package/dist/{chunk-HUAISCUX.cjs → chunk-M2HG5DJ2.cjs} +18 -18
  54. package/dist/{chunk-N76AMOKE.cjs → chunk-MDLEGVEN.cjs} +42 -42
  55. package/dist/chunk-MEGSQUQO.cjs +36 -0
  56. package/dist/chunk-MLLTWAXH.cjs +276 -0
  57. package/dist/{chunk-RHPSE2YR.js → chunk-MQ6MGIQM.js} +2 -2
  58. package/dist/{chunk-PGPFWC35.cjs → chunk-MQGQTKVW.cjs} +51 -33
  59. package/dist/{chunk-5YWWQ36H.cjs → chunk-O3ZVZSNJ.cjs} +9 -9
  60. package/dist/{chunk-GCTUOTCW.cjs → chunk-P3PZ63M3.cjs} +35 -35
  61. package/dist/{chunk-WRZ6C4TU.cjs → chunk-P6WYDBTH.cjs} +4 -4
  62. package/dist/{chunk-CJ6TBL2N.cjs → chunk-RHEMMGCN.cjs} +16 -16
  63. package/dist/{chunk-HIMGBZAM.cjs → chunk-RSIKDWOP.cjs} +201 -38
  64. package/dist/{chunk-SABJMH6M.cjs → chunk-RVGP2XLF.cjs} +2 -135
  65. package/dist/{chunk-JVRLGV3C.js → chunk-SMTUQWGY.js} +184 -21
  66. package/dist/{chunk-DMTEQ6SH.js → chunk-SSFMWJDK.js} +4 -4
  67. package/dist/{chunk-TFF2GTGN.cjs → chunk-SXQHWXEL.cjs} +2 -24
  68. package/dist/{chunk-IWEVV63O.cjs → chunk-UEYLANO3.cjs} +18 -16
  69. package/dist/chunk-VR6OGHU5.js +276 -0
  70. package/dist/{chunk-AF23QK5F.js → chunk-YQ4PQTBB.js} +1 -1
  71. package/dist/{chunk-B7V34GIH.cjs → chunk-YSGW7VV4.cjs} +88 -88
  72. package/dist/{chunk-3NS5C7FB.cjs → chunk-YYBW6DF2.cjs} +76 -76
  73. package/dist/{chunk-UFEDHACQ.js → chunk-Z7BX4TWO.js} +2 -2
  74. package/dist/{chunk-RUONPPMC.cjs → chunk-ZSE25IZA.cjs} +8 -8
  75. package/dist/color/index.cjs +7 -3
  76. package/dist/color/index.js +18 -14
  77. package/dist/export/index.cjs +8 -6
  78. package/dist/export/index.js +7 -5
  79. package/dist/extensions/index.cjs +11 -9
  80. package/dist/extensions/index.js +10 -8
  81. package/dist/gradient/index.cjs +33 -31
  82. package/dist/gradient/index.js +5 -3
  83. package/dist/image-editor/brush-presets.d.cts +4 -1
  84. package/dist/image-editor/brush-presets.d.ts +4 -1
  85. package/dist/image-editor/controller.d.cts +10 -5
  86. package/dist/image-editor/controller.d.ts +10 -5
  87. package/dist/image-editor/index.cjs +1090 -1073
  88. package/dist/image-editor/index.js +37 -20
  89. package/dist/index.cjs +17 -15
  90. package/dist/index.js +11 -9
  91. package/dist/paint-editor/brushes.d.cts +18 -1
  92. package/dist/paint-editor/brushes.d.ts +18 -1
  93. package/dist/paint-editor/collaboration-tools.d.cts +19 -0
  94. package/dist/paint-editor/collaboration-tools.d.ts +19 -0
  95. package/dist/paint-editor/collaboration.d.cts +180 -0
  96. package/dist/paint-editor/collaboration.d.ts +180 -0
  97. package/dist/paint-editor/controller.d.cts +83 -0
  98. package/dist/paint-editor/controller.d.ts +83 -0
  99. package/dist/paint-editor/engine.d.cts +7 -0
  100. package/dist/paint-editor/engine.d.ts +7 -0
  101. package/dist/paint-editor/index.cjs +2027 -1331
  102. package/dist/paint-editor/index.d.cts +2 -0
  103. package/dist/paint-editor/index.d.ts +2 -0
  104. package/dist/paint-editor/index.js +1671 -975
  105. package/dist/paint-editor/mark-settings.d.cts +1 -1
  106. package/dist/paint-editor/mark-settings.d.ts +1 -1
  107. package/dist/paint-editor/procedural.d.cts +4 -2
  108. package/dist/paint-editor/procedural.d.ts +4 -2
  109. package/dist/paint-editor/stamp-tip.d.cts +45 -0
  110. package/dist/paint-editor/stamp-tip.d.ts +45 -0
  111. package/dist/paint-editor/stroke.d.cts +2 -0
  112. package/dist/paint-editor/stroke.d.ts +2 -0
  113. package/dist/stickers/index.cjs +4 -2
  114. package/dist/stickers/index.js +6 -4
  115. package/dist/typography/index.cjs +3 -2
  116. package/dist/typography/index.js +2 -1
  117. package/dist/vector/index.cjs +971 -969
  118. package/dist/vector/index.js +8 -6
  119. package/dist/video-editor/index.cjs +4 -2
  120. package/dist/video-editor/index.js +4 -2
  121. package/package.json +1 -1
  122. package/skills/pixerate-brushes/SKILL.md +21 -11
  123. package/skills/pixerate-brushes-design/SKILL.md +6 -2
  124. package/skills/pixerate-brushes-design/evals/canvas-chalk.json +8 -8
  125. package/skills/pixerate-canvas/SKILL.md +3 -2
  126. package/skills/pixerate-image-editor/SKILL.md +1 -1
  127. package/skills/pixerate-paint-editor/SKILL.md +35 -47
  128. package/skills/pixerate-paint-editor/references/painting-alongside.md +19 -0
  129. package/skills/pixerate-vector/SKILL.md +1 -1
@@ -8,9 +8,12 @@
8
8
 
9
9
 
10
10
 
11
- var _chunkPGPFWC35cjs = require('../chunk-PGPFWC35.cjs');
11
+ var _chunkMQGQTKVWcjs = require('../chunk-MQGQTKVW.cjs');
12
+ require('../chunk-AVTPZO4Z.cjs');
12
13
 
13
14
 
15
+ var _chunkLRTR4ASZcjs = require('../chunk-LRTR4ASZ.cjs');
16
+ require('../chunk-A2IS7EHE.cjs');
14
17
 
15
18
 
16
19
 
@@ -54,7 +57,9 @@ var _chunkPGPFWC35cjs = require('../chunk-PGPFWC35.cjs');
54
57
 
55
58
 
56
59
 
57
- var _chunkHIMGBZAMcjs = require('../chunk-HIMGBZAM.cjs');
60
+
61
+
62
+ var _chunkRSIKDWOPcjs = require('../chunk-RSIKDWOP.cjs');
58
63
 
59
64
 
60
65
  var _chunkJSDND7DFcjs = require('../chunk-JSDND7DF.cjs');
@@ -69,6 +74,12 @@ require('../chunk-3K6HWEXZ.cjs');
69
74
  var _chunk2VX55NFMcjs = require('../chunk-2VX55NFM.cjs');
70
75
  require('../chunk-474IQG74.cjs');
71
76
 
77
+
78
+ var _chunkMLLTWAXHcjs = require('../chunk-MLLTWAXH.cjs');
79
+ require('../chunk-SXQHWXEL.cjs');
80
+ require('../chunk-5UEFBM2M.cjs');
81
+ require('../chunk-IPJ3TEYR.cjs');
82
+
72
83
  // src/brushes/ui.ts
73
84
  var title = (s) => s.charAt(0).toUpperCase() + s.slice(1).replace(/-/g, " ");
74
85
  var options = (values, labels = {}) => values.map((value) => ({ value, label: _nullishCoalesce(labels[value], () => ( title(value))) }));
@@ -98,20 +109,20 @@ var ARIA = {
98
109
  "light.pressure": "Light follows pressure"
99
110
  };
100
111
  var aria = (path, label) => _nullishCoalesce(ARIA[path], () => ( `Brush ${label.toLowerCase()}`));
101
- function brushEditorSections(brush, profile = _chunkHIMGBZAMcjs.PAINT_PROFILE) {
102
- const resolved = _chunkHIMGBZAMcjs.resolveBrush.call(void 0, brush);
103
- const engine = _chunkHIMGBZAMcjs.resolveEngine.call(void 0, brush);
104
- const fieldOf = (facet) => _chunkHIMGBZAMcjs.BRUSH_FIELDS.find((f) => f.facet === facet && f.engines.includes(engine));
105
- const facetOf = (enginePath) => _optionalChain([(_nullishCoalesce(_chunkHIMGBZAMcjs.BRUSH_FIELDS.find((f) => f.engine === enginePath && f.engines.includes(engine)), () => ( _chunkHIMGBZAMcjs.BRUSH_FIELDS.find((f) => f.engine === enginePath)))), 'optionalAccess', _ => _.facet]);
112
+ function brushEditorSections(brush, profile = _chunkRSIKDWOPcjs.PAINT_PROFILE) {
113
+ const resolved = _chunkRSIKDWOPcjs.resolveBrush.call(void 0, brush);
114
+ const engine = _chunkRSIKDWOPcjs.resolveEngine.call(void 0, brush);
115
+ const fieldOf = (facet) => _chunkRSIKDWOPcjs.BRUSH_FIELDS.find((f) => f.facet === facet && f.engines.includes(engine));
116
+ const facetOf = (enginePath) => _optionalChain([(_nullishCoalesce(_chunkRSIKDWOPcjs.BRUSH_FIELDS.find((f) => f.engine === enginePath && f.engines.includes(engine)), () => ( _chunkRSIKDWOPcjs.BRUSH_FIELDS.find((f) => f.engine === enginePath)))), 'optionalAccess', _ => _.facet]);
106
117
  const value = (path) => {
107
- const own = _chunkHIMGBZAMcjs.getPath.call(void 0, brush, path);
118
+ const own = _chunkRSIKDWOPcjs.getPath.call(void 0, brush, path);
108
119
  if (own !== void 0) return own;
109
120
  const field = fieldOf(path);
110
121
  if (!field) return void 0;
111
- const v = _chunkHIMGBZAMcjs.getPath.call(void 0, resolved, field.engine);
122
+ const v = _chunkRSIKDWOPcjs.getPath.call(void 0, resolved, field.engine);
112
123
  return field.map ? field.map.toFacet(v) : v;
113
124
  };
114
- const warned = new Map(_chunkHIMGBZAMcjs.checkBrush.call(void 0, brush, profile).issues.filter((i) => i.severity === "warning").map((i) => [i.facet, i.reason]));
125
+ const warned = new Map(_chunkRSIKDWOPcjs.checkBrush.call(void 0, brush, profile).issues.filter((i) => i.severity === "warning").map((i) => [i.facet, i.reason]));
115
126
  const noteFor = (path) => _optionalChain([[...warned], 'access', _2 => _2.find, 'call', _3 => _3(([facet]) => path === facet || path.startsWith(`${facet}.`)), 'optionalAccess', _4 => _4[1]]);
116
127
  const withNote = (c) => {
117
128
  const note = noteFor(c.path);
@@ -135,18 +146,18 @@ function brushEditorSections(brush, profile = _chunkHIMGBZAMcjs.PAINT_PROFILE) {
135
146
  const marks = _nullishCoalesce(_optionalChain([brush, 'access', _7 => _7.marks, 'optionalAccess', _8 => _8.kind]), () => ( "continuous"));
136
147
  add("medium", "Medium", [
137
148
  profile.kinds.length > 1 && choice("kind", "Kind", options(profile.kinds, { mark: "Lays a material", tool: "Works on paint" })),
138
- !isTool && choice("medium", "Medium", [{ value: "", label: "Any" }, ...options(_chunkHIMGBZAMcjs.BRUSH_MEDIA, MEDIUM_LABELS)], ""),
149
+ !isTool && choice("medium", "Medium", [{ value: "", label: "Any" }, ...options(_chunkRSIKDWOPcjs.BRUSH_MEDIA, MEDIUM_LABELS)], ""),
139
150
  !isTool && withNote({ kind: "text", path: "variety", label: "Variety", ariaLabel: "Brush variety", value: _nullishCoalesce(brush.variety, () => ( "")), placeholder: "pencil, oil, highlighter\u2026" }),
140
151
  isTool && profile.tools.length > 0 && choice("tool", "Tool", options(profile.tools, TOOL_LABELS))
141
152
  ]);
142
- const engineControls = _chunkPGPFWC35cjs.brushEngineControls.call(void 0, resolved);
143
- const tipSliders = _chunkPGPFWC35cjs.BRUSH_SLIDERS.filter((c) => c.path.startsWith("tip.") && c.path !== "tip.smoothing");
153
+ const engineControls = _chunkMQGQTKVWcjs.brushEngineControls.call(void 0, resolved);
154
+ const tipSliders = _chunkMQGQTKVWcjs.BRUSH_SLIDERS.filter((c) => c.path.startsWith("tip.") && c.path !== "tip.smoothing");
144
155
  add("shape", "Shape", [
145
156
  choice("tip.shape", "Tip", options(profile.tipShapes.filter((s) => !isTool || s !== "stamp"), SHAPE_LABELS)),
146
157
  ...tipSliders.map((c) => slider(c)),
147
158
  engine === "dab" && choice("tip.blend", "Blend", _chunk2VX55NFMcjs.BLEND_MODES.map((m) => ({ value: m.id, label: m.label })), "normal"),
148
159
  ...shape === "bristle" && engineControls ? engineControls.sliders.filter((c) => c.path.startsWith("bristle.")).map((c) => slider(c)) : [],
149
- shape === "stamp" && withNote({ kind: "stamps", path: "tip.stamps", label: "Stamps", ariaLabel: "Brush stamps", value: [..._nullishCoalesce(value("tip.stamps"), () => ( []))], max: marks === "particles" ? _chunkHIMGBZAMcjs.MAX_DOT_TEXTURES : _chunkHIMGBZAMcjs.MAX_STICKER_STAMPS, options: STAMP_OPTIONS })
160
+ shape === "stamp" && withNote({ kind: "stamps", path: "tip.stamps", label: "Stamps", ariaLabel: "Brush stamps", value: [..._nullishCoalesce(value("tip.stamps"), () => ( []))], max: marks === "particles" ? _chunkRSIKDWOPcjs.MAX_DOT_TEXTURES : _chunkRSIKDWOPcjs.MAX_STICKER_STAMPS, options: STAMP_OPTIONS })
150
161
  ]);
151
162
  if (!isTool && profile.marks.length > 1) {
152
163
  const particles = marks === "particles" && engineControls ? engineControls.sliders.filter((c) => c.path.startsWith("particle.") && c.path !== "particle.waveSpeed") : [];
@@ -154,21 +165,21 @@ function brushEditorSections(brush, profile = _chunkHIMGBZAMcjs.PAINT_PROFILE) {
154
165
  const render = value("marks.render");
155
166
  add("marks", "Marks", [
156
167
  choice("marks.kind", "Laid as", options(profile.marks, MARKS_LABELS), "continuous"),
157
- marks === "particles" && choice("marks.physics", "Particles", options(_chunkHIMGBZAMcjs.PARTICLE_KINDS, PHYSICS_LABELS)),
158
- marks === "particles" && choice("marks.render", "Drawn as", options(_chunkHIMGBZAMcjs.PARTICLE_RENDERS, RENDER_LABELS)),
159
- marks === "particles" && render === "ribbon" && choice("marks.ribbonPairs", "Ribbon joins", options(_chunkHIMGBZAMcjs.RIBBON_PAIRS, { adjacent: "Neighbours", "first-last": "Outermost" })),
160
- marks === "particles" && shape === "stamp" && choice("marks.stampOrder", "Texture order", options(_chunkHIMGBZAMcjs.DOT_TEXTURE_ORDERS, { sequence: "In turn", random: "Random" })),
161
- marks === "particles" && shape === "stamp" && choice("marks.stampRotation", "Texture turn", options(_chunkHIMGBZAMcjs.DOT_ROTATIONS, { follow: "Follow motion", random: "Random", fixed: "Tip angle" })),
168
+ marks === "particles" && choice("marks.physics", "Particles", options(_chunkRSIKDWOPcjs.PARTICLE_KINDS, PHYSICS_LABELS)),
169
+ marks === "particles" && choice("marks.render", "Drawn as", options(_chunkRSIKDWOPcjs.PARTICLE_RENDERS, RENDER_LABELS)),
170
+ marks === "particles" && render === "ribbon" && choice("marks.ribbonPairs", "Ribbon joins", options(_chunkRSIKDWOPcjs.RIBBON_PAIRS, { adjacent: "Neighbours", "first-last": "Outermost" })),
171
+ marks === "particles" && shape === "stamp" && choice("marks.stampOrder", "Texture order", options(_chunkRSIKDWOPcjs.DOT_TEXTURE_ORDERS, { sequence: "In turn", random: "Random" })),
172
+ marks === "particles" && shape === "stamp" && choice("marks.stampRotation", "Texture turn", options(_chunkRSIKDWOPcjs.DOT_ROTATIONS, { follow: "Follow motion", random: "Random", fixed: "Tip angle" })),
162
173
  ...particles.map((c) => slider(c)),
163
174
  ...objects.map((c) => slider(c))
164
175
  ]);
165
176
  }
166
- const feel = _chunkPGPFWC35cjs.BRUSH_SLIDERS.filter((c) => ["tip.smoothing", "pressureSmoothing", "dynamics.minSize", "dynamics.tiltSize", "dynamics.velocitySize"].includes(c.path)).filter((c) => !(c.path === "dynamics.tiltSize" && profile.tilt === "none") && !(c.path === "dynamics.velocitySize" && profile.velocity === "none"));
177
+ const feel = _chunkMQGQTKVWcjs.BRUSH_SLIDERS.filter((c) => ["tip.smoothing", "pressureSmoothing", "dynamics.minSize", "dynamics.tiltSize", "dynamics.velocitySize"].includes(c.path)).filter((c) => !(c.path === "dynamics.tiltSize" && profile.tilt === "none") && !(c.path === "dynamics.velocitySize" && profile.velocity === "none"));
167
178
  add("feel", "Feel", [
168
179
  ...feel.map((c) => slider(c)),
169
180
  toggle("dynamics.pressureSize", "Pressure \u2192 size"),
170
181
  toggle("dynamics.pressureOpacity", "Pressure \u2192 opacity"),
171
- choice("dynamics.rotation", "Rotation", options(_chunkHIMGBZAMcjs.BRUSH_ROTATIONS, ROTATION_LABELS))
182
+ choice("dynamics.rotation", "Rotation", options(_chunkRSIKDWOPcjs.BRUSH_ROTATIONS, ROTATION_LABELS))
172
183
  ]);
173
184
  const surfaces = profile.surfaces;
174
185
  const engineSliders = (_nullishCoalesce(_optionalChain([engineControls, 'optionalAccess', _9 => _9.sliders]), () => ( []))).filter((c) => !/^(bristle|particle|sticker)\./.test(c.path) && c.path !== "light.amount" && c.path !== "impasto.rim" && c.path !== "impasto.clarity");
@@ -176,8 +187,8 @@ function brushEditorSections(brush, profile = _chunkHIMGBZAMcjs.PAINT_PROFILE) {
176
187
  add("behaviour", _nullishCoalesce(_optionalChain([engineControls, 'optionalAccess', _12 => _12.title]), () => ( "Behaviour")), [
177
188
  !isTool && surfaces.length > 1 && choice("behaviour.surface", "Surface", options(surfaces, SURFACE_LABELS), "dry"),
178
189
  profile.grain !== "none" && slider({ path: "grain", label: "Grain", min: 0, max: 1, step: 0.01 }, "behaviour.grain"),
179
- engine === "wet" && !isTool && choice("behaviour.wet.medium", "Medium", options(_chunkHIMGBZAMcjs.WET_MEDIA, WET_MEDIUM_LABELS), "watercolor"),
180
- engine === "impasto" && choice("behaviour.thick.applicator", "Tool", options(_chunkHIMGBZAMcjs.IMPASTO_TOOLS, APPLICATOR_LABELS), "brush"),
190
+ engine === "wet" && !isTool && choice("behaviour.wet.medium", "Medium", options(_chunkRSIKDWOPcjs.WET_MEDIA, WET_MEDIUM_LABELS), "watercolor"),
191
+ engine === "impasto" && choice("behaviour.thick.applicator", "Tool", options(_chunkRSIKDWOPcjs.IMPASTO_TOOLS, APPLICATOR_LABELS), "brush"),
181
192
  ...engineSliders.map((c) => exchangeOk(facetOf(c.path)) ? slider(c) : null),
182
193
  _optionalChain([engineControls, 'optionalAccess', _13 => _13.mixingPath]) && fieldOf("behaviour.mixing") && choice("behaviour.mixing", "Mixing", options(["pigment", "rgb"], { pigment: "Pigment", rgb: "RGB" })),
183
194
  _optionalChain([engineControls, 'optionalAccess', _14 => _14.dirty]) && profile.exchange !== "none" && fieldOf("behaviour.exchange.dirty") && toggle("behaviour.exchange.dirty", "Dirty brush"),
@@ -195,9 +206,18 @@ function brushEditorSections(brush, profile = _chunkHIMGBZAMcjs.PAINT_PROFILE) {
195
206
  if (profile.motion !== "none" && marks === "particles") add("motion", "Motion", [slider({ path: "particle.waveSpeed", label: "Wave speed", min: 0, max: 1, step: 0.01 })]);
196
207
  if (!isTool) {
197
208
  const own = _optionalChain([brush, 'access', _19 => _19.colour, 'optionalAccess', _20 => _20.default]);
209
+ const hex = (c) => typeof c === "string" ? _nullishCoalesce(_chunkLRTR4ASZcjs.brushColourHex.call(void 0, c, "light"), () => ( null)) : null;
210
+ const pair = _chunkMLLTWAXHcjs.isDualColor.call(void 0, own) ? own : null;
198
211
  add("colour", "Colour", [
199
- withNote({ kind: "colour", path: "colour.default", label: "Default colour", ariaLabel: "Brush default colour", value: typeof own === "string" && /^#[0-9a-f]{6}/i.test(own) ? own.slice(0, 7).toLowerCase() : null }),
200
- withNote({ kind: "palette", path: "colour.palette", label: "Palette", ariaLabel: "Brush palette", value: (_nullishCoalesce(_optionalChain([brush, 'access', _21 => _21.colour, 'optionalAccess', _22 => _22.palette]), () => ( []))).filter((c) => typeof c === "string"), max: _chunkHIMGBZAMcjs.MAX_BRUSH_PALETTE }),
212
+ withNote({ kind: "colour", path: "colour.default", label: "Default colour", ariaLabel: "Brush default colour", value: pair ? _nullishCoalesce(_chunkLRTR4ASZcjs.brushColourHex.call(void 0, pair, "light"), () => ( null)) : hex(own), dark: pair ? _nullishCoalesce(_chunkLRTR4ASZcjs.brushColourHex.call(void 0, pair, "dark"), () => ( null)) : null, gradient: own !== void 0 && typeof own === "object" && !pair }),
213
+ withNote({
214
+ kind: "palette",
215
+ path: "colour.palette",
216
+ label: "Palette",
217
+ ariaLabel: "Brush palette",
218
+ value: (_nullishCoalesce(_optionalChain([brush, 'access', _21 => _21.colour, 'optionalAccess', _22 => _22.palette]), () => ( []))).flatMap((c) => _chunkMLLTWAXHcjs.isDualColor.call(void 0, c) ? [{ light: _chunkLRTR4ASZcjs.brushColourHex.call(void 0, c, "light"), dark: _chunkLRTR4ASZcjs.brushColourHex.call(void 0, c, "dark") }] : hex(c) ? [hex(c)] : []),
219
+ max: _chunkRSIKDWOPcjs.MAX_BRUSH_PALETTE
220
+ }),
201
221
  toggle("colour.own", "Always its own colour")
202
222
  ]);
203
223
  }
@@ -225,13 +245,13 @@ function setBrushEditorValue(brush, path, value) {
225
245
  if (value !== "bristle") delete next.tip.bristle;
226
246
  } else if (value === void 0 || value === "") {
227
247
  const keys = path.split(".");
228
- const parent = _chunkHIMGBZAMcjs.getPath.call(void 0, next, keys.slice(0, -1).join("."));
248
+ const parent = _chunkRSIKDWOPcjs.getPath.call(void 0, next, keys.slice(0, -1).join("."));
229
249
  if (keys.length === 1) delete next[keys[0]];
230
250
  else if (parent) delete parent[keys[keys.length - 1]];
231
- } else _chunkHIMGBZAMcjs.setPath.call(void 0, next, path, value);
251
+ } else _chunkRSIKDWOPcjs.setPath.call(void 0, next, path, value);
232
252
  const problems = [];
233
253
  try {
234
- return { brush: _chunkHIMGBZAMcjs.normalizeBrushSpec.call(void 0, JSON.parse(JSON.stringify(next)), problems), problems };
254
+ return { brush: _chunkRSIKDWOPcjs.normalizeBrushSpec.call(void 0, JSON.parse(JSON.stringify(next)), problems), problems };
235
255
  } catch (e) {
236
256
  return { brush, problems: [e.message] };
237
257
  }
@@ -247,7 +267,7 @@ function brushLibraryGroups(entries, filter = {}) {
247
267
  const text = words([b.id, b.name, _nullishCoalesce(b.variety, () => ( "")), _nullishCoalesce(b.medium, () => ( "")), _nullishCoalesce(b.tool, () => ( "")), ..._nullishCoalesce(b.tags, () => ( []))].join(" "));
248
268
  if (!wanted.every((w) => text.some((t) => t.startsWith(w)))) continue;
249
269
  }
250
- if (filter.profile && !_chunkHIMGBZAMcjs.checkBrush.call(void 0, b, filter.profile).ok) continue;
270
+ if (filter.profile && !_chunkRSIKDWOPcjs.checkBrush.call(void 0, b, filter.profile).ok) continue;
251
271
  const id = b.kind === "tool" ? "tools" : _nullishCoalesce(b.medium, () => ( "other"));
252
272
  let g = groups.get(id);
253
273
  if (!g) groups.set(id, g = { id, title: id === "tools" ? "Tools" : id === "other" ? "Other" : MEDIUM_LABELS[id], varieties: [] });
@@ -301,4 +321,5 @@ function brushLibraryGroups(entries, filter = {}) {
301
321
 
302
322
 
303
323
 
304
- exports.BRUSH_FACET_SCHEMAS = _chunkHIMGBZAMcjs.BRUSH_FACET_SCHEMAS; exports.BRUSH_HOST_PROFILES = _chunkHIMGBZAMcjs.BRUSH_HOST_PROFILES; exports.BRUSH_JSON_SCHEMA = _chunkHIMGBZAMcjs.BRUSH_JSON_SCHEMA; exports.BRUSH_KINDS = _chunkHIMGBZAMcjs.BRUSH_KINDS; exports.BRUSH_MARKS_KINDS = _chunkHIMGBZAMcjs.BRUSH_MARKS_KINDS; exports.BRUSH_MEDIA = _chunkHIMGBZAMcjs.BRUSH_MEDIA; exports.BRUSH_PATCH_PROPERTIES = _chunkPGPFWC35cjs.BRUSH_PATCH_PROPERTIES; exports.BRUSH_PRESETS = _chunkHIMGBZAMcjs.BRUSH_PRESETS; exports.BRUSH_SURFACES = _chunkHIMGBZAMcjs.BRUSH_SURFACES; exports.BRUSH_TIP_SHAPES = _chunkHIMGBZAMcjs.BRUSH_TIP_SHAPES; exports.BRUSH_TOOLS = _chunkHIMGBZAMcjs.BRUSH_TOOLS; exports.BRUSH_UNSET_PROPERTY = _chunkPGPFWC35cjs.BRUSH_UNSET_PROPERTY; exports.BRUSH_WORD = _chunkHIMGBZAMcjs.BRUSH_WORD; exports.BrushLibraryError = _chunkHIMGBZAMcjs.BrushLibraryError; exports.CANVAS_PROFILE = _chunkHIMGBZAMcjs.CANVAS_PROFILE; exports.IMAGE_PROFILE = _chunkHIMGBZAMcjs.IMAGE_PROFILE; exports.MAX_BRUSH_PALETTE = _chunkHIMGBZAMcjs.MAX_BRUSH_PALETTE; exports.PAINT_PROFILE = _chunkHIMGBZAMcjs.PAINT_PROFILE; exports.UNSETTABLE_BRUSH_FACETS = _chunkPGPFWC35cjs.UNSETTABLE_BRUSH_FACETS; exports.VECTOR_PROFILE = _chunkHIMGBZAMcjs.VECTOR_PROFILE; exports.WET_BRUSH_TOOLS = _chunkHIMGBZAMcjs.WET_BRUSH_TOOLS; exports.brushColourKind = _chunkHIMGBZAMcjs.brushColourKind; exports.brushEditorSections = brushEditorSections; exports.brushLibraryGroups = brushLibraryGroups; exports.changedBrushPaths = _chunkPGPFWC35cjs.changedBrushPaths; exports.checkBrush = _chunkHIMGBZAMcjs.checkBrush; exports.createBrushLibrary = _chunkHIMGBZAMcjs.createBrushLibrary; exports.createBrushLibraryToolProvider = _chunkPGPFWC35cjs.createBrushLibraryToolProvider; exports.createBrushLibraryTools = _chunkPGPFWC35cjs.createBrushLibraryTools; exports.degrade = _chunkHIMGBZAMcjs.degrade; exports.listPresets = _chunkHIMGBZAMcjs.listPresets; exports.mergeBrushPatch = _chunkPGPFWC35cjs.mergeBrushPatch; exports.migrateBrushV1 = _chunkHIMGBZAMcjs.migrateBrushV1; exports.normalizeBrushSpec = _chunkHIMGBZAMcjs.normalizeBrushSpec; exports.parseBrushLibrary = _chunkHIMGBZAMcjs.parseBrushLibrary2; exports.resolveBrush = _chunkHIMGBZAMcjs.resolveBrush; exports.resolveCategory = _chunkHIMGBZAMcjs.resolveCategory; exports.resolveEngine = _chunkHIMGBZAMcjs.resolveEngine; exports.resolveWetMedium = _chunkHIMGBZAMcjs.resolveWetMedium; exports.setBrushEditorValue = setBrushEditorValue; exports.snapshotBrushLibrary = _chunkHIMGBZAMcjs.snapshotBrushLibrary;
324
+
325
+ exports.BRUSH_FACET_SCHEMAS = _chunkRSIKDWOPcjs.BRUSH_FACET_SCHEMAS; exports.BRUSH_HOST_PROFILES = _chunkRSIKDWOPcjs.BRUSH_HOST_PROFILES; exports.BRUSH_JSON_SCHEMA = _chunkRSIKDWOPcjs.BRUSH_JSON_SCHEMA; exports.BRUSH_KINDS = _chunkRSIKDWOPcjs.BRUSH_KINDS; exports.BRUSH_MARKS_KINDS = _chunkRSIKDWOPcjs.BRUSH_MARKS_KINDS; exports.BRUSH_MEDIA = _chunkRSIKDWOPcjs.BRUSH_MEDIA; exports.BRUSH_PATCH_PROPERTIES = _chunkMQGQTKVWcjs.BRUSH_PATCH_PROPERTIES; exports.BRUSH_PRESETS = _chunkRSIKDWOPcjs.BRUSH_PRESETS; exports.BRUSH_SURFACES = _chunkRSIKDWOPcjs.BRUSH_SURFACES; exports.BRUSH_TIP_SHAPES = _chunkRSIKDWOPcjs.BRUSH_TIP_SHAPES; exports.BRUSH_TOOLS = _chunkRSIKDWOPcjs.BRUSH_TOOLS; exports.BRUSH_UNSET_PROPERTY = _chunkMQGQTKVWcjs.BRUSH_UNSET_PROPERTY; exports.BRUSH_WORD = _chunkRSIKDWOPcjs.BRUSH_WORD; exports.BrushLibraryError = _chunkRSIKDWOPcjs.BrushLibraryError; exports.CANVAS_PROFILE = _chunkRSIKDWOPcjs.CANVAS_PROFILE; exports.IMAGE_PROFILE = _chunkRSIKDWOPcjs.IMAGE_PROFILE; exports.MAX_BRUSH_PALETTE = _chunkRSIKDWOPcjs.MAX_BRUSH_PALETTE; exports.PAINT_PROFILE = _chunkRSIKDWOPcjs.PAINT_PROFILE; exports.UNSETTABLE_BRUSH_FACETS = _chunkMQGQTKVWcjs.UNSETTABLE_BRUSH_FACETS; exports.VECTOR_PROFILE = _chunkRSIKDWOPcjs.VECTOR_PROFILE; exports.WET_BRUSH_TOOLS = _chunkRSIKDWOPcjs.WET_BRUSH_TOOLS; exports.brushColourHex = _chunkLRTR4ASZcjs.brushColourHex; exports.brushColourKind = _chunkRSIKDWOPcjs.brushColourKind; exports.brushEditorSections = brushEditorSections; exports.brushLibraryGroups = brushLibraryGroups; exports.changedBrushPaths = _chunkMQGQTKVWcjs.changedBrushPaths; exports.checkBrush = _chunkRSIKDWOPcjs.checkBrush; exports.createBrushLibrary = _chunkRSIKDWOPcjs.createBrushLibrary; exports.createBrushLibraryToolProvider = _chunkMQGQTKVWcjs.createBrushLibraryToolProvider; exports.createBrushLibraryTools = _chunkMQGQTKVWcjs.createBrushLibraryTools; exports.degrade = _chunkRSIKDWOPcjs.degrade; exports.listPresets = _chunkRSIKDWOPcjs.listPresets; exports.mergeBrushPatch = _chunkMQGQTKVWcjs.mergeBrushPatch; exports.migrateBrushV1 = _chunkRSIKDWOPcjs.migrateBrushV1; exports.normalizeBrushSpec = _chunkRSIKDWOPcjs.normalizeBrushSpec; exports.parseBrushLibrary = _chunkRSIKDWOPcjs.parseBrushLibrary2; exports.resolveBrush = _chunkRSIKDWOPcjs.resolveBrush; exports.resolveCategory = _chunkRSIKDWOPcjs.resolveCategory; exports.resolveEngine = _chunkRSIKDWOPcjs.resolveEngine; exports.resolveWetMedium = _chunkRSIKDWOPcjs.resolveWetMedium; exports.setBrushEditorValue = setBrushEditorValue; exports.snapshotBrushLibrary = _chunkRSIKDWOPcjs.snapshotBrushLibrary;
@@ -14,6 +14,7 @@ export { normalizeBrushSpec, WET_BRUSH_TOOLS } from './normalize.cjs';
14
14
  export { resolveBrush, resolveCategory, resolveEngine, resolveWetMedium, type ResolveBrushOptions } from './resolve.cjs';
15
15
  export { migrateBrushV1 } from './migrate.cjs';
16
16
  export { BRUSH_PRESETS } from './presets.cjs';
17
+ export { brushColourHex } from './colour.cjs';
17
18
  export { BRUSH_HOST_PROFILES, brushColourKind, CANVAS_PROFILE, checkBrush, degrade, IMAGE_PROFILE, listPresets, PAINT_PROFILE, VECTOR_PROFILE, type BrushCheck, type BrushColourKind, type BrushHostProfile, type BrushIssue, type BrushSupport, type DegradedBrush } from './profiles.cjs';
18
19
  export { BrushLibraryError, createBrushLibrary, parseBrushLibrary, snapshotBrushLibrary, type BrushFilter, type BrushLibrary, type BrushLibraryEntry, type BrushLibraryErrorCode, type BrushLibraryFile, type BrushLibrarySnapshot, type BrushLibraryOptions, type ImportBrushesResult, type SaveBrushResult, } from './library.cjs';
19
20
  export { BRUSH_PATCH_PROPERTIES, BRUSH_UNSET_PROPERTY, changedBrushPaths, mergeBrushPatch, UNSETTABLE_BRUSH_FACETS, type BrushPatch, type UnsettableBrushFacet } from './patch.cjs';
@@ -14,6 +14,7 @@ export { normalizeBrushSpec, WET_BRUSH_TOOLS } from './normalize.js';
14
14
  export { resolveBrush, resolveCategory, resolveEngine, resolveWetMedium, type ResolveBrushOptions } from './resolve.js';
15
15
  export { migrateBrushV1 } from './migrate.js';
16
16
  export { BRUSH_PRESETS } from './presets.js';
17
+ export { brushColourHex } from './colour.js';
17
18
  export { BRUSH_HOST_PROFILES, brushColourKind, CANVAS_PROFILE, checkBrush, degrade, IMAGE_PROFILE, listPresets, PAINT_PROFILE, VECTOR_PROFILE, type BrushCheck, type BrushColourKind, type BrushHostProfile, type BrushIssue, type BrushSupport, type DegradedBrush } from './profiles.js';
18
19
  export { BrushLibraryError, createBrushLibrary, parseBrushLibrary, snapshotBrushLibrary, type BrushFilter, type BrushLibrary, type BrushLibraryEntry, type BrushLibraryErrorCode, type BrushLibraryFile, type BrushLibrarySnapshot, type BrushLibraryOptions, type ImportBrushesResult, type SaveBrushResult, } from './library.js';
19
20
  export { BRUSH_PATCH_PROPERTIES, BRUSH_UNSET_PROPERTY, changedBrushPaths, mergeBrushPatch, UNSETTABLE_BRUSH_FACETS, type BrushPatch, type UnsettableBrushFacet } from './patch.js';
@@ -8,7 +8,12 @@ import {
8
8
  createBrushLibraryToolProvider,
9
9
  createBrushLibraryTools,
10
10
  mergeBrushPatch
11
- } from "../chunk-YHUMGBZD.js";
11
+ } from "../chunk-ICTPLVSR.js";
12
+ import "../chunk-J5UQHWVL.js";
13
+ import {
14
+ brushColourHex
15
+ } from "../chunk-FJBQTZS4.js";
16
+ import "../chunk-3CI7FRMK.js";
12
17
  import {
13
18
  BRUSH_FACET_SCHEMAS,
14
19
  BRUSH_FIELDS,
@@ -54,7 +59,7 @@ import {
54
59
  resolveWetMedium,
55
60
  setPath,
56
61
  snapshotBrushLibrary
57
- } from "../chunk-JVRLGV3C.js";
62
+ } from "../chunk-SMTUQWGY.js";
58
63
  import {
59
64
  STAMP_KINDS
60
65
  } from "../chunk-APX63ILU.js";
@@ -68,6 +73,12 @@ import {
68
73
  BLEND_MODES
69
74
  } from "../chunk-IRSTHLQQ.js";
70
75
  import "../chunk-HVVR5PZW.js";
76
+ import {
77
+ isDualColor
78
+ } from "../chunk-VR6OGHU5.js";
79
+ import "../chunk-JC2SHA4A.js";
80
+ import "../chunk-MHLU6GRJ.js";
81
+ import "../chunk-6ONMQ6WF.js";
71
82
 
72
83
  // src/brushes/ui.ts
73
84
  var title = (s) => s.charAt(0).toUpperCase() + s.slice(1).replace(/-/g, " ");
@@ -195,9 +206,18 @@ function brushEditorSections(brush, profile = PAINT_PROFILE) {
195
206
  if (profile.motion !== "none" && marks === "particles") add("motion", "Motion", [slider({ path: "particle.waveSpeed", label: "Wave speed", min: 0, max: 1, step: 0.01 })]);
196
207
  if (!isTool) {
197
208
  const own = brush.colour?.default;
209
+ const hex = (c) => typeof c === "string" ? brushColourHex(c, "light") ?? null : null;
210
+ const pair = isDualColor(own) ? own : null;
198
211
  add("colour", "Colour", [
199
- withNote({ kind: "colour", path: "colour.default", label: "Default colour", ariaLabel: "Brush default colour", value: typeof own === "string" && /^#[0-9a-f]{6}/i.test(own) ? own.slice(0, 7).toLowerCase() : null }),
200
- withNote({ kind: "palette", path: "colour.palette", label: "Palette", ariaLabel: "Brush palette", value: (brush.colour?.palette ?? []).filter((c) => typeof c === "string"), max: MAX_BRUSH_PALETTE }),
212
+ withNote({ kind: "colour", path: "colour.default", label: "Default colour", ariaLabel: "Brush default colour", value: pair ? brushColourHex(pair, "light") ?? null : hex(own), dark: pair ? brushColourHex(pair, "dark") ?? null : null, gradient: own !== void 0 && typeof own === "object" && !pair }),
213
+ withNote({
214
+ kind: "palette",
215
+ path: "colour.palette",
216
+ label: "Palette",
217
+ ariaLabel: "Brush palette",
218
+ value: (brush.colour?.palette ?? []).flatMap((c) => isDualColor(c) ? [{ light: brushColourHex(c, "light"), dark: brushColourHex(c, "dark") }] : hex(c) ? [hex(c)] : []),
219
+ max: MAX_BRUSH_PALETTE
220
+ }),
201
221
  toggle("colour.own", "Always its own colour")
202
222
  ]);
203
223
  }
@@ -281,6 +301,7 @@ export {
281
301
  UNSETTABLE_BRUSH_FACETS,
282
302
  VECTOR_PROFILE,
283
303
  WET_BRUSH_TOOLS,
304
+ brushColourHex,
284
305
  brushColourKind,
285
306
  brushEditorSections,
286
307
  brushLibraryGroups,
@@ -23,6 +23,8 @@ export interface BrushField {
23
23
  };
24
24
  /** Read only on these tip shapes. */
25
25
  shapes?: readonly string[];
26
+ /** Read only with these marks kinds (default any). */
27
+ marks?: readonly string[];
26
28
  }
27
29
  /** Every facet field and where it lands in the resolved brush. */
28
30
  export declare const BRUSH_FIELDS: readonly BrushField[];
@@ -23,6 +23,8 @@ export interface BrushField {
23
23
  };
24
24
  /** Read only on these tip shapes. */
25
25
  shapes?: readonly string[];
26
+ /** Read only with these marks kinds (default any). */
27
+ marks?: readonly string[];
26
28
  }
27
29
  /** Every facet field and where it lands in the resolved brush. */
28
30
  export declare const BRUSH_FIELDS: readonly BrushField[];
@@ -17,6 +17,7 @@ export declare const BRUSH_FACET_SCHEMAS: {
17
17
  readonly tip: JsonSchema;
18
18
  readonly marks: {
19
19
  readonly continuous: JsonSchema;
20
+ readonly scatter: JsonSchema;
20
21
  readonly particles: JsonSchema;
21
22
  readonly objects: JsonSchema;
22
23
  };
@@ -17,6 +17,7 @@ export declare const BRUSH_FACET_SCHEMAS: {
17
17
  readonly tip: JsonSchema;
18
18
  readonly marks: {
19
19
  readonly continuous: JsonSchema;
20
+ readonly scatter: JsonSchema;
20
21
  readonly particles: JsonSchema;
21
22
  readonly objects: JsonSchema;
22
23
  };
@@ -6,6 +6,7 @@
6
6
  * the host's.
7
7
  */
8
8
  import type { AgentTool, AgentToolProvider } from '../tools/registry.cjs';
9
+ import type { StickerProvider } from '../stickers/types.cjs';
9
10
  import { type BrushLibrary } from './library.cjs';
10
11
  import { type BrushHostProfile } from './profiles.cjs';
11
12
  import { type Brush } from './types.cjs';
@@ -27,6 +28,12 @@ export interface BrushLibraryToolProviderOptions {
27
28
  renderPreview?: BrushPreviewRenderer;
28
29
  /** Only the read tools (list, describe, export, check, preview). */
29
30
  readOnly?: boolean;
31
+ /**
32
+ * The host's sticker library (an editor's `StickersSlot` provider), read on every call: stamp
33
+ * tips naming a sticker it can't load are refused with the reason and the closest ones. Without
34
+ * it, sticker refs are not checked.
35
+ */
36
+ stickers?: () => StickerProvider;
30
37
  /** Provider id (default `brushes`), also the tool namespace unless `namespace` is set. */
31
38
  id?: string;
32
39
  namespace?: string;
@@ -6,6 +6,7 @@
6
6
  * the host's.
7
7
  */
8
8
  import type { AgentTool, AgentToolProvider } from '../tools/registry.js';
9
+ import type { StickerProvider } from '../stickers/types.js';
9
10
  import { type BrushLibrary } from './library.js';
10
11
  import { type BrushHostProfile } from './profiles.js';
11
12
  import { type Brush } from './types.js';
@@ -27,6 +28,12 @@ export interface BrushLibraryToolProviderOptions {
27
28
  renderPreview?: BrushPreviewRenderer;
28
29
  /** Only the read tools (list, describe, export, check, preview). */
29
30
  readOnly?: boolean;
31
+ /**
32
+ * The host's sticker library (an editor's `StickersSlot` provider), read on every call: stamp
33
+ * tips naming a sticker it can't load are refused with the reason and the closest ones. Without
34
+ * it, sticker refs are not checked.
35
+ */
36
+ stickers?: () => StickerProvider;
30
37
  /** Provider id (default `brushes`), also the tool namespace unless `namespace` is set. */
31
38
  id?: string;
32
39
  namespace?: string;
@@ -35,7 +35,7 @@ export declare const BRUSH_TOOLS: readonly BrushTool[];
35
35
  export type BrushTipShape = 'round' | 'flat' | 'chisel' | 'bristle' | 'stamp';
36
36
  export declare const BRUSH_TIP_SHAPES: readonly BrushTipShape[];
37
37
  /** How the tip is laid along the path. */
38
- export type BrushMarksKind = 'continuous' | 'particles' | 'objects';
38
+ export type BrushMarksKind = 'continuous' | 'scatter' | 'particles' | 'objects';
39
39
  export declare const BRUSH_MARKS_KINDS: readonly BrushMarksKind[];
40
40
  /** What the material does on the surface: stays where it lands (`dry`), flows and dries (`wet`) or stands up in relief (`thick`). */
41
41
  export type BrushSurface = 'dry' | 'wet' | 'thick';
@@ -88,6 +88,14 @@ export interface BrushTip {
88
88
  export interface BrushContinuousMarks {
89
89
  kind: 'continuous';
90
90
  }
91
+ /** A spray: each dab lays a seeded scatter of droplets across the tip (a spray can). */
92
+ export interface BrushScatterMarks {
93
+ kind: 'scatter';
94
+ /** Droplets per dab, 0..1: 1 + density × 31 (default 0.5). */
95
+ density?: number;
96
+ /** Droplet size as a fraction of the tip size, 0.02..1 (default 0.12). */
97
+ size?: number;
98
+ }
91
99
  /** Particles that move with the pen and draw as they go (each 0..1 unless noted). */
92
100
  export interface BrushParticleMarks {
93
101
  kind: 'particles';
@@ -142,7 +150,7 @@ export interface BrushObjectMarks {
142
150
  /** Random colour change, hue and lightness (default 0.2). */
143
151
  colourJitter?: number;
144
152
  }
145
- export type BrushMarks = BrushContinuousMarks | BrushParticleMarks | BrushObjectMarks;
153
+ export type BrushMarks = BrushContinuousMarks | BrushScatterMarks | BrushParticleMarks | BrushObjectMarks;
146
154
  /** Pen feel. Every amount is 0 (off) .. 1 unless noted. */
147
155
  export interface BrushDynamics {
148
156
  /** Pressure scales the size (default true). */
@@ -35,7 +35,7 @@ export declare const BRUSH_TOOLS: readonly BrushTool[];
35
35
  export type BrushTipShape = 'round' | 'flat' | 'chisel' | 'bristle' | 'stamp';
36
36
  export declare const BRUSH_TIP_SHAPES: readonly BrushTipShape[];
37
37
  /** How the tip is laid along the path. */
38
- export type BrushMarksKind = 'continuous' | 'particles' | 'objects';
38
+ export type BrushMarksKind = 'continuous' | 'scatter' | 'particles' | 'objects';
39
39
  export declare const BRUSH_MARKS_KINDS: readonly BrushMarksKind[];
40
40
  /** What the material does on the surface: stays where it lands (`dry`), flows and dries (`wet`) or stands up in relief (`thick`). */
41
41
  export type BrushSurface = 'dry' | 'wet' | 'thick';
@@ -88,6 +88,14 @@ export interface BrushTip {
88
88
  export interface BrushContinuousMarks {
89
89
  kind: 'continuous';
90
90
  }
91
+ /** A spray: each dab lays a seeded scatter of droplets across the tip (a spray can). */
92
+ export interface BrushScatterMarks {
93
+ kind: 'scatter';
94
+ /** Droplets per dab, 0..1: 1 + density × 31 (default 0.5). */
95
+ density?: number;
96
+ /** Droplet size as a fraction of the tip size, 0.02..1 (default 0.12). */
97
+ size?: number;
98
+ }
91
99
  /** Particles that move with the pen and draw as they go (each 0..1 unless noted). */
92
100
  export interface BrushParticleMarks {
93
101
  kind: 'particles';
@@ -142,7 +150,7 @@ export interface BrushObjectMarks {
142
150
  /** Random colour change, hue and lightness (default 0.2). */
143
151
  colourJitter?: number;
144
152
  }
145
- export type BrushMarks = BrushContinuousMarks | BrushParticleMarks | BrushObjectMarks;
153
+ export type BrushMarks = BrushContinuousMarks | BrushScatterMarks | BrushParticleMarks | BrushObjectMarks;
146
154
  /** Pen feel. Every amount is 0 (off) .. 1 unless noted. */
147
155
  export interface BrushDynamics {
148
156
  /** Pressure scales the size (default true). */
@@ -42,13 +42,24 @@ export type BrushEditorControl = (ControlBase & {
42
42
  value: string;
43
43
  placeholder?: string;
44
44
  })
45
- /** A solid colour (#rrggbb), or `null` when there is none (or the default is a gradient or effect). */
45
+ /**
46
+ * A solid colour (#rrggbb, its light side when `dark` is set), or `null` when there is none (or
47
+ * the default is a gradient or effect: `gradient` says so). `dark`: the dark side of a light /
48
+ * dark pair, `null` for one colour in both schemes.
49
+ */
46
50
  | (ControlBase & {
47
51
  kind: 'colour';
48
52
  value: string | null;
49
- }) | (ControlBase & {
53
+ dark: string | null;
54
+ gradient: boolean;
55
+ })
56
+ /** Suggested colours: solid (#rrggbb) or light / dark pairs; gradient and effect entries are left out. */
57
+ | (ControlBase & {
50
58
  kind: 'palette';
51
- value: string[];
59
+ value: Array<string | {
60
+ light: string;
61
+ dark: string;
62
+ }>;
52
63
  max: number;
53
64
  })
54
65
  /** Stamp refs (`editor:star`…): `options` are the editor's stamps; hosts may offer more refs. */
@@ -42,13 +42,24 @@ export type BrushEditorControl = (ControlBase & {
42
42
  value: string;
43
43
  placeholder?: string;
44
44
  })
45
- /** A solid colour (#rrggbb), or `null` when there is none (or the default is a gradient or effect). */
45
+ /**
46
+ * A solid colour (#rrggbb, its light side when `dark` is set), or `null` when there is none (or
47
+ * the default is a gradient or effect: `gradient` says so). `dark`: the dark side of a light /
48
+ * dark pair, `null` for one colour in both schemes.
49
+ */
46
50
  | (ControlBase & {
47
51
  kind: 'colour';
48
52
  value: string | null;
49
- }) | (ControlBase & {
53
+ dark: string | null;
54
+ gradient: boolean;
55
+ })
56
+ /** Suggested colours: solid (#rrggbb) or light / dark pairs; gradient and effect entries are left out. */
57
+ | (ControlBase & {
50
58
  kind: 'palette';
51
- value: string[];
59
+ value: Array<string | {
60
+ light: string;
61
+ dark: string;
62
+ }>;
52
63
  max: number;
53
64
  })
54
65
  /** Stamp refs (`editor:star`…): `options` are the editor's stamps; hosts may offer more refs. */
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  pathDataToPolyline
3
- } from "./chunk-WYGSR3IJ.js";
3
+ } from "./chunk-AORZ5M5C.js";
4
4
  import {
5
5
  parseCssColor
6
6
  } from "./chunk-3CI7FRMK.js";
@@ -14,7 +14,7 @@ import {
14
14
  normalizeBrushSpec,
15
15
  resolveBrush,
16
16
  resolveCategory
17
- } from "./chunk-JVRLGV3C.js";
17
+ } from "./chunk-SMTUQWGY.js";
18
18
  import "./chunk-APX63ILU.js";
19
19
  import {
20
20
  formatNumber,
@@ -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 _chunkLRNUZKWVcjs = require('./chunk-LRNUZKWV.cjs');
3
+ var _chunkIPUTIUGQcjs = require('./chunk-IPUTIUGQ.cjs');
4
4
 
5
5
 
6
6
  var _chunkA2IS7EHEcjs = require('./chunk-A2IS7EHE.cjs');
@@ -14,7 +14,7 @@ var _chunkA2IS7EHEcjs = require('./chunk-A2IS7EHE.cjs');
14
14
 
15
15
 
16
16
 
17
- var _chunkHIMGBZAMcjs = require('./chunk-HIMGBZAM.cjs');
17
+ var _chunkRSIKDWOPcjs = require('./chunk-RSIKDWOP.cjs');
18
18
  require('./chunk-JSDND7DF.cjs');
19
19
 
20
20
 
@@ -39,17 +39,17 @@ require('./chunk-474IQG74.cjs');
39
39
  require('./chunk-XFM3OCHU.cjs');
40
40
 
41
41
  // src/canvas/brushstrokeRender.ts
42
- var PRESETS = _chunkHIMGBZAMcjs.listPresets.call(void 0, _chunkHIMGBZAMcjs.CANVAS_PROFILE).map((spec) => _chunkHIMGBZAMcjs.BUILTIN_BRUSHES.find((b) => b.id === spec.id));
42
+ var PRESETS = _chunkRSIKDWOPcjs.listPresets.call(void 0, _chunkRSIKDWOPcjs.CANVAS_PROFILE).map((spec) => _chunkRSIKDWOPcjs.BUILTIN_BRUSHES.find((b) => b.id === spec.id));
43
43
  var presetIds = () => PRESETS.map((b) => b.id).join(", ");
44
- var refusal = (brush) => _chunkHIMGBZAMcjs.checkBrush.call(void 0, brush, _chunkHIMGBZAMcjs.CANVAS_PROFILE).issues.filter((i) => i.severity === "error").map((i) => `${i.reason} ${i.fix}`).join(" ");
44
+ var refusal = (brush) => _chunkRSIKDWOPcjs.checkBrush.call(void 0, brush, _chunkRSIKDWOPcjs.CANVAS_PROFILE).issues.filter((i) => i.severity === "error").map((i) => `${i.reason} ${i.fix}`).join(" ");
45
45
  function readCanvasBrushSpec(spec) {
46
46
  let brush;
47
47
  try {
48
- brush = _chunkHIMGBZAMcjs.normalizeBrushSpec.call(void 0, spec);
48
+ brush = _chunkRSIKDWOPcjs.normalizeBrushSpec.call(void 0, spec);
49
49
  } catch (e) {
50
50
  throw new Error(`Not a brush: ${e.message}`);
51
51
  }
52
- if (!_chunkHIMGBZAMcjs.checkBrush.call(void 0, brush, _chunkHIMGBZAMcjs.CANVAS_PROFILE).ok) throw new Error(`Brush '${brush.id}' (${brush.name}) can't brush a canvas stroke: ${refusal(brush)}`);
52
+ if (!_chunkRSIKDWOPcjs.checkBrush.call(void 0, brush, _chunkRSIKDWOPcjs.CANVAS_PROFILE).ok) throw new Error(`Brush '${brush.id}' (${brush.name}) can't brush a canvas stroke: ${refusal(brush)}`);
53
53
  return brush;
54
54
  }
55
55
  function listCanvasBrushes(user = []) {
@@ -58,7 +58,7 @@ function listCanvasBrushes(user = []) {
58
58
  try {
59
59
  const brush = readCanvasBrushSpec(raw);
60
60
  if (out.some((b) => b.id === brush.id)) continue;
61
- out.push({ id: brush.id, name: brush.name, category: _chunkHIMGBZAMcjs.resolveCategory.call(void 0, brush), size: _chunkHIMGBZAMcjs.resolveBrush.call(void 0, brush).tip.size, builtin: false, spec: brush });
61
+ out.push({ id: brush.id, name: brush.name, category: _chunkRSIKDWOPcjs.resolveCategory.call(void 0, brush), size: _chunkRSIKDWOPcjs.resolveBrush.call(void 0, brush).tip.size, builtin: false, spec: brush });
62
62
  } catch (e2) {
63
63
  }
64
64
  }
@@ -69,15 +69,15 @@ function resolveCanvasBrush(brush, width, spec) {
69
69
  const sized = (b) => given === void 0 ? b : { ...b, tip: { ...b.tip, size: given } };
70
70
  if (typeof brush === "string") {
71
71
  if (spec !== void 0 && spec !== null) {
72
- const saved = _chunkHIMGBZAMcjs.resolveBrush.call(void 0, readCanvasBrushSpec(spec));
72
+ const saved = _chunkRSIKDWOPcjs.resolveBrush.call(void 0, readCanvasBrushSpec(spec));
73
73
  if (!_chunkPXDIAYB6cjs.isBrushstrokeBrush.call(void 0, saved)) throw new Error(`Brush '${saved.id}' (${saved.name}) can't brush a canvas stroke: it is not a dry dab brush.`);
74
74
  return sized(saved);
75
75
  }
76
76
  const preset = PRESETS.find((b) => b.id === brush);
77
77
  if (preset) return sized(preset);
78
- const other = _chunkHIMGBZAMcjs.BRUSH_PRESETS.find((b) => b.id === brush);
78
+ const other = _chunkRSIKDWOPcjs.BRUSH_PRESETS.find((b) => b.id === brush);
79
79
  if (other) throw new Error(`Brush '${brush}' (${other.name}) can't brush a canvas stroke: ${refusal(other)} Use one of: ${presetIds()}, or a saved brush the canvas can paint.`);
80
- throw new Error(`Unknown brush '${brush}'. ${_chunkHIMGBZAMcjs.closest.call(void 0, brush, PRESETS.map((b) => b.id))}Use one of the dry presets (${presetIds()}), a saved brush from the brush library, or tip settings ({ hardness, spacing, flow, \u2026 }).`);
80
+ throw new Error(`Unknown brush '${brush}'. ${_chunkRSIKDWOPcjs.closest.call(void 0, brush, PRESETS.map((b) => b.id))}Use one of the dry presets (${presetIds()}), a saved brush from the brush library, or tip settings ({ hardness, spacing, flow, \u2026 }).`);
81
81
  }
82
82
  if (!brush || typeof brush !== "object" || Array.isArray(brush)) {
83
83
  throw new Error("A brush is a preset or saved brush id (see listCanvasBrushes / canvas.listBrushes) or an object of tip settings.");
@@ -113,7 +113,7 @@ function renderShapeBrushstrokeNow(shape, scale, place = {}) {
113
113
  const textured = typeof seed === "number" && Number.isFinite(seed);
114
114
  const size = _nullishCoalesce(shape.brush.size, () => ( (textured ? void 0 : _nullishCoalesce(shape.strokeWidth, () => ( 3)))));
115
115
  const brush = resolveCanvasBrush(shape.brush.brush, size, shape.brush.spec);
116
- const points = _chunkLRNUZKWVcjs.pathDataToPolyline.call(void 0, shape.d);
116
+ const points = _chunkIPUTIUGQcjs.pathDataToPolyline.call(void 0, shape.d);
117
117
  if (!points.length) return null;
118
118
  const { pressure, tiltX, tiltY } = shape.brush;
119
119
  const input = {