@pixerate/editor 0.259.0 → 0.261.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 (80) hide show
  1. package/dist/agent/index.cjs +2 -2
  2. package/dist/agent/index.js +1 -1
  3. package/dist/animation-editor/index.cjs +61 -59
  4. package/dist/animation-editor/index.js +5 -3
  5. package/dist/brushes/index.cjs +52 -52
  6. package/dist/brushes/index.js +6 -6
  7. package/dist/{brushstrokeRender-JI4W6F2G.js → brushstrokeRender-25Q5BEY6.js} +17 -7
  8. package/dist/{brushstrokeRender-MQ6PSDM5.cjs → brushstrokeRender-N6UPZSQS.cjs} +31 -21
  9. package/dist/canvas/brushTypes.d.cts +5 -0
  10. package/dist/canvas/brushTypes.d.ts +5 -0
  11. package/dist/canvas/drawController.d.cts +15 -1
  12. package/dist/canvas/drawController.d.ts +15 -1
  13. package/dist/canvas/index.cjs +136 -102
  14. package/dist/canvas/index.js +35 -1
  15. package/dist/{chunk-3PPJRMIG.js → chunk-3O47TPGX.js} +197 -18
  16. package/dist/{chunk-5Q5MLXAD.cjs → chunk-3TQW5MPW.cjs} +23 -23
  17. package/dist/{chunk-JBBJE76O.cjs → chunk-3ZRNK3RO.cjs} +1138 -85
  18. package/dist/{chunk-YSGW7VV4.cjs → chunk-43NT242D.cjs} +1401 -228
  19. package/dist/{chunk-SMTUQWGY.js → chunk-5IW65VQ6.js} +1 -1
  20. package/dist/{chunk-YQ4PQTBB.js → chunk-6NZL24W4.js} +9 -1
  21. package/dist/{chunk-O3ZVZSNJ.cjs → chunk-7AUQ2UJ3.cjs} +137 -129
  22. package/dist/{chunk-4M4E3N6X.js → chunk-CQVTGBQI.js} +1 -1
  23. package/dist/{chunk-SSFMWJDK.js → chunk-D4TE5JNW.js} +1192 -19
  24. package/dist/{chunk-AORZ5M5C.js → chunk-EHALWBBD.js} +1 -1
  25. package/dist/{chunk-6WCQ35GI.cjs → chunk-NHA26O5X.cjs} +2 -2
  26. package/dist/{chunk-DPYAO5U6.cjs → chunk-PVJMTLPJ.cjs} +197 -18
  27. package/dist/{chunk-MQGQTKVW.cjs → chunk-PYTJBVW5.cjs} +29 -29
  28. package/dist/{chunk-IXQZHCOF.js → chunk-QAR2N7HZ.js} +1 -1
  29. package/dist/{chunk-5P4JEOIV.js → chunk-TMDDMJCR.js} +2 -2
  30. package/dist/{chunk-RSIKDWOP.cjs → chunk-TZOX7KWV.cjs} +15 -15
  31. package/dist/{chunk-IPUTIUGQ.cjs → chunk-UVZ7RQOE.cjs} +1 -1
  32. package/dist/{chunk-A7GJ6BXI.js → chunk-WJ4WQJCC.js} +1062 -9
  33. package/dist/{chunk-ICTPLVSR.js → chunk-X2EXYY4J.js} +1 -1
  34. package/dist/{chunk-WQCNC4DK.js → chunk-XC6DPRYI.js} +695 -4
  35. package/dist/{chunk-KBYB7OWB.cjs → chunk-YHDHFJUC.cjs} +776 -85
  36. package/dist/{chunk-P3PZ63M3.cjs → chunk-YLUIFXSL.cjs} +35 -35
  37. package/dist/commands/index.cjs +2 -2
  38. package/dist/commands/index.js +1 -1
  39. package/dist/image-editor/index.cjs +1385 -2484
  40. package/dist/image-editor/index.js +139 -1238
  41. package/dist/image-editor/selection-worker.cjs +3 -4
  42. package/dist/image-editor/selection-worker.js +1 -2
  43. package/dist/paint/index.cjs +3 -5
  44. package/dist/paint/index.js +40 -42
  45. package/dist/paint-editor/contract.d.cts +29 -0
  46. package/dist/paint-editor/contract.d.ts +29 -0
  47. package/dist/paint-editor/controller.d.cts +17 -0
  48. package/dist/paint-editor/controller.d.ts +17 -0
  49. package/dist/paint-editor/dab-stroke.d.cts +5 -0
  50. package/dist/paint-editor/dab-stroke.d.ts +5 -0
  51. package/dist/paint-editor/index.cjs +610 -327
  52. package/dist/paint-editor/index.d.cts +2 -0
  53. package/dist/paint-editor/index.d.ts +2 -0
  54. package/dist/paint-editor/index.js +337 -54
  55. package/dist/paint-editor/path-samples.d.cts +19 -0
  56. package/dist/paint-editor/path-samples.d.ts +19 -0
  57. package/dist/paint-editor/stamp-tip.d.cts +17 -0
  58. package/dist/paint-editor/stamp-tip.d.ts +17 -0
  59. package/dist/paint-editor/ui.d.cts +27 -1
  60. package/dist/paint-editor/ui.d.ts +27 -1
  61. package/dist/raster/index.cjs +2 -4
  62. package/dist/raster/index.js +6 -8
  63. package/dist/vector/brushstroke.d.cts +6 -0
  64. package/dist/vector/brushstroke.d.ts +6 -0
  65. package/dist/vector/controller.d.cts +11 -2
  66. package/dist/vector/controller.d.ts +11 -2
  67. package/dist/vector/index.cjs +990 -973
  68. package/dist/vector/index.js +28 -11
  69. package/package.json +1 -1
  70. package/skills/pixerate-brushes/SKILL.md +1 -1
  71. package/skills/pixerate-canvas/SKILL.md +3 -1
  72. package/skills/pixerate-paint-editor/SKILL.md +2 -0
  73. package/skills/pixerate-paint-sketch-to-finish/SKILL.md +5 -1
  74. package/skills/pixerate-vector/SKILL.md +2 -2
  75. package/dist/chunk-2VJAVXLI.js +0 -192
  76. package/dist/chunk-62Z5WLRA.js +0 -700
  77. package/dist/chunk-BOHDJJ2O.cjs +0 -192
  78. package/dist/chunk-NKGB64CW.cjs +0 -700
  79. package/dist/chunk-SS53NNZO.cjs +0 -1066
  80. package/dist/chunk-ZNA3IQZF.js +0 -1066
@@ -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-JI4W6F2G.js").catch((error) => {
77
+ loading ??= import("./brushstrokeRender-25Q5BEY6.js").catch((error) => {
78
78
  loading = null;
79
79
  throw error;
80
80
  });
@@ -337,7 +337,7 @@ function createDrawCommands(target, options = {}) {
337
337
  description: "Stroke points as [x, y] pairs in canvas (flow) units, in drawing order. Use a point every few units along curves."
338
338
  },
339
339
  tool: { type: "string", enum: ["pen", "highlighter"], description: "Pen (default: blue, width 3) or highlighter (yellow, width 24, opacity 0.35); sets the defaults below." },
340
- color: { type: "string", description: "Stroke colour, any CSS colour (default from the tool)." },
340
+ color: { type: "string", description: "Stroke colour, any CSS colour (default: the brush's default colour, such as the ballpoint's blue, else the tool's)." },
341
341
  width: { type: "number", exclusiveMinimum: 0, maximum: 2500, description: "Stroke width in canvas units (default from the tool). For brushed strokes it is the brush diameter; leave it out to use the preset's own size (canvas.listBrushes gives it)." },
342
342
  opacity: { type: "number", minimum: 0, maximum: 1, description: "Stroke opacity 0..1 (default from the tool)." },
343
343
  brush: {
@@ -420,7 +420,7 @@ var gestureBoxes = (what) => ({
420
420
  });
421
421
  var GESTURE_STYLE_PARAMS = {
422
422
  tool: { type: "string", enum: ["pen", "highlighter"], description: "Pen (default: blue, width 3) or highlighter (yellow, width 24, opacity 0.35); sets the defaults below." },
423
- color: { type: "string", description: "Stroke colour, any CSS colour (default from the tool)." },
423
+ color: { type: "string", description: "Stroke colour, any CSS colour (default: the brush's default colour, such as the ballpoint's blue, else the tool's)." },
424
424
  width: { type: "number", exclusiveMinimum: 0, maximum: 2500, description: "Stroke width in canvas units (default from the tool; with a brush, the preset's own size)." },
425
425
  opacity: { type: "number", minimum: 0, maximum: 1, description: "Stroke opacity 0..1 (default from the tool)." },
426
426
  brush: {
@@ -26,6 +26,7 @@ var _chunkK6PXS6DOcjs = require('./chunk-K6PXS6DO.cjs');
26
26
 
27
27
 
28
28
 
29
+
29
30
  var _chunk2VX55NFMcjs = require('./chunk-2VX55NFM.cjs');
30
31
 
31
32
 
@@ -762,8 +763,8 @@ function edtNearest(inside, w, h) {
762
763
  dt1(f, w, o, nr, v, z);
763
764
  for (let x = 0; x < w; x++) {
764
765
  d[y * w + x] = Math.sqrt(o[x]);
765
- const px = nr[x];
766
- near[y * w + x] = nc[px * h + y] * w + px;
766
+ const px2 = nr[x];
767
+ near[y * w + x] = nc[px2 * h + y] * w + px2;
767
768
  }
768
769
  }
769
770
  return { d, near };
@@ -3446,21 +3447,21 @@ function readWindow(src, srcRect, rect, depth = null) {
3446
3447
  const win = { x: rect.x, y: rect.y, w: rect.width, h: rect.height, n, data };
3447
3448
  const r = intersect(rect, srcRect);
3448
3449
  if (!r) return win;
3449
- const px = depth ? readScaled(src, r, depth) : _chunk474IQG74cjs.readRegion.call(void 0, src, r);
3450
+ const px2 = depth ? readScaled(src, r, depth) : _chunk474IQG74cjs.readRegion.call(void 0, src, r);
3450
3451
  for (let y = 0; y < r.height; y++) {
3451
3452
  let s = y * r.width * src.channels;
3452
3453
  let d = ((r.y - rect.y + y) * rect.width + (r.x - rect.x)) * n;
3453
3454
  if (n === 4) {
3454
3455
  for (let x = 0; x < r.width; x++, s += 4, d += 4) {
3455
- const a = px[s + 3] / 255;
3456
- data[d] = px[s] * a;
3457
- data[d + 1] = px[s + 1] * a;
3458
- data[d + 2] = px[s + 2] * a;
3456
+ const a = px2[s + 3] / 255;
3457
+ data[d] = px2[s] * a;
3458
+ data[d + 1] = px2[s + 1] * a;
3459
+ data[d + 2] = px2[s + 2] * a;
3459
3460
  data[d + 3] = a;
3460
3461
  }
3461
3462
  } else {
3462
3463
  for (let x = 0; x < r.width; x++, s++, d += 2) {
3463
- data[d] = px[s];
3464
+ data[d] = px2[s];
3464
3465
  data[d + 1] = 1;
3465
3466
  }
3466
3467
  }
@@ -3631,7 +3632,7 @@ function boxReduce(src, srcRect, kx, ky, depth = null) {
3631
3632
  for (let ry = ry0; ry < ry1; ry += rowsPer) {
3632
3633
  const rows = Math.min(rowsPer, ry1 - ry);
3633
3634
  const strip = { x: rx0 * kx, y: ry * ky, width: rw * kx, height: rows * ky };
3634
- const px = depth ? readScaled(src, strip, depth) : _chunk474IQG74cjs.readRegion.call(void 0, src, strip);
3635
+ const px2 = depth ? readScaled(src, strip, depth) : _chunk474IQG74cjs.readRegion.call(void 0, src, strip);
3635
3636
  const red = depth ? new Float32Array(rw * rows * ch) : new Uint8ClampedArray(rw * rows * ch);
3636
3637
  for (let j = 0; j < rows; j++) {
3637
3638
  for (let i = 0; i < rw; i++) {
@@ -3643,11 +3644,11 @@ function boxReduce(src, srcRect, kx, ky, depth = null) {
3643
3644
  for (let y = 0; y < ky; y++) {
3644
3645
  let s = ((j * ky + y) * strip.width + i * kx) * 4;
3645
3646
  for (let x = 0; x < kx; x++, s += 4) {
3646
- const al = px[s + 3];
3647
+ const al = px2[s + 3];
3647
3648
  a += al;
3648
- r += px[s] * al;
3649
- g += px[s + 1] * al;
3650
- b += px[s + 2] * al;
3649
+ r += px2[s] * al;
3650
+ g += px2[s + 1] * al;
3651
+ b += px2[s + 2] * al;
3651
3652
  }
3652
3653
  }
3653
3654
  const o = (j * rw + i) * 4;
@@ -3661,7 +3662,7 @@ function boxReduce(src, srcRect, kx, ky, depth = null) {
3661
3662
  let v = 0;
3662
3663
  for (let y = 0; y < ky; y++) {
3663
3664
  const s = (j * ky + y) * strip.width + i * kx;
3664
- for (let x = 0; x < kx; x++) v += px[s + x];
3665
+ for (let x = 0; x < kx; x++) v += px2[s + x];
3665
3666
  }
3666
3667
  red[j * rw + i] = v / area;
3667
3668
  }
@@ -4038,9 +4039,9 @@ function warpSurface(src, f, options = {}) {
4038
4039
  for (let y = ay0; y < ry1; y += step) {
4039
4040
  const py = y + 0.5;
4040
4041
  for (let x = ax0; x < rx1; x += step) {
4041
- const px = x + 0.5;
4042
- const l1 = ((px - p0x) * (p2y - p0y) - (p2x - p0x) * (py - p0y)) / det;
4043
- const l2 = ((p1x - p0x) * (py - p0y) - (px - p0x) * (p1y - p0y)) / det;
4042
+ const px2 = x + 0.5;
4043
+ const l1 = ((px2 - p0x) * (p2y - p0y) - (p2x - p0x) * (py - p0y)) / det;
4044
+ const l2 = ((p1x - p0x) * (py - p0y) - (px2 - p0x) * (p1y - p0y)) / det;
4044
4045
  const l0 = 1 - l1 - l2;
4045
4046
  if (l0 < eps || l1 < eps || l2 < eps) continue;
4046
4047
  const o = (y - t.y) * tw + (x - t.x);
@@ -4197,6 +4198,184 @@ function compositeSurfaceOver(base, top) {
4197
4198
  return new (0, _chunk474IQG74cjs.TiledSurface)(ch, tiles, base.defaultValue);
4198
4199
  }
4199
4200
 
4201
+ // src/raster/effects/ui.ts
4202
+ function layerEffectsPanel(layer) {
4203
+ const empty = { readOnly: true, enabled: true, scale: 1, rows: [] };
4204
+ if (!layer) return { ...empty, available: false, reason: "Select a layer to add a layer style." };
4205
+ if (layer.type === "adjustment") return { ...empty, available: false, reason: "Adjustment layers cannot have a layer style." };
4206
+ const fx = layer.effects;
4207
+ const readOnly = Boolean(_optionalChain([layer, 'access', _95 => _95.locks, 'optionalAccess', _96 => _96.all]));
4208
+ return {
4209
+ available: true,
4210
+ readOnly,
4211
+ reason: readOnly ? "The layer is locked; unlock it to change its layer style." : void 0,
4212
+ enabled: _nullishCoalesce(_optionalChain([fx, 'optionalAccess', _97 => _97.enabled]), () => ( true)),
4213
+ scale: _nullishCoalesce(_optionalChain([fx, 'optionalAccess', _98 => _98.scale]), () => ( 1)),
4214
+ rows: (_nullishCoalesce(_optionalChain([fx, 'optionalAccess', _99 => _99.items]), () => ( []))).map((e) => ({ id: e.id, kind: e.kind, label: layerEffectLabel(e.kind), enabled: e.enabled }))
4215
+ };
4216
+ }
4217
+ function layerEffectsBadge(layer) {
4218
+ if (!_optionalChain([layer, 'access', _100 => _100.effects, 'optionalAccess', _101 => _101.items, 'access', _102 => _102.length])) return null;
4219
+ return hasActiveEffects(layer.effects) ? "on" : "off";
4220
+ }
4221
+ var LAYER_EFFECT_MENU = LAYER_EFFECT_KINDS.map((kind) => ({ kind, label: layerEffectLabel(kind) }));
4222
+ var BLENDS = _chunk2VX55NFMcjs.BLEND_MODES.filter((m) => m.id !== "pigment").map((m) => ({ value: m.id, label: m.label }));
4223
+ var opt = (...pairs) => pairs.map(([value, label]) => ({ value, label }));
4224
+ function patternOptions(patterns) {
4225
+ return [...patterns.map((p) => ({ value: p.id, label: p.name || p.id })), ...builtinPatternIds().map((id) => ({ value: id, label: builtinPattern(id).name }))];
4226
+ }
4227
+ function getPath(o, path) {
4228
+ let v = o;
4229
+ for (const p of path.split(".")) {
4230
+ if (v === null || v === void 0) return void 0;
4231
+ if (Array.isArray(v)) v = p === "last" ? v[v.length - 1] : v[Number(p)];
4232
+ else v = v[p];
4233
+ }
4234
+ return v;
4235
+ }
4236
+ function setPath(o, parts, value) {
4237
+ if (!parts.length) return value;
4238
+ const [p, ...rest] = parts;
4239
+ if (Array.isArray(o)) {
4240
+ const i = p === "last" ? o.length - 1 : Number(p);
4241
+ const out = [...o];
4242
+ out[i] = setPath(o[i], rest, value);
4243
+ return out;
4244
+ }
4245
+ const r = _nullishCoalesce(o, () => ( {}));
4246
+ return { ...r, [p]: setPath(r[p], rest, value) };
4247
+ }
4248
+ function fillControls(f, allowPattern, patterns) {
4249
+ const types = allowPattern ? opt(["color", "Color"], ["gradient", "Gradient"], ["pattern", "Pattern"]) : opt(["color", "Color"], ["gradient", "Gradient"]);
4250
+ const out = [{ key: "fill.type", label: "Fill", type: "select", value: f.type, options: types }];
4251
+ if (f.type === "color") out.push({ key: "fill.color", label: "Color", type: "color", value: f.color });
4252
+ else if (f.type === "gradient") out.push(...gradientControls("fill.gradient", f.gradient));
4253
+ else {
4254
+ out.push(
4255
+ { key: "fill.patternId", label: "Pattern", type: "select", value: f.patternId, options: patternOptions(patterns) },
4256
+ { key: "fill.scale", label: "Scale", type: "range", min: 0.01, max: 10, step: 0.01, value: f.scale, percent: true, unit: "%" }
4257
+ );
4258
+ }
4259
+ return out;
4260
+ }
4261
+ function gradientControls(prefix, g) {
4262
+ return [
4263
+ { key: `${prefix}.stops.0.color`, label: "Start colour", type: "color", value: _nullishCoalesce(_optionalChain([g, 'access', _103 => _103.stops, 'access', _104 => _104[0], 'optionalAccess', _105 => _105.color]), () => ( "#000000")) },
4264
+ { key: `${prefix}.stops.last.color`, label: "End colour", type: "color", value: _nullishCoalesce(_optionalChain([g, 'access', _106 => _106.stops, 'access', _107 => _107[g.stops.length - 1], 'optionalAccess', _108 => _108.color]), () => ( "#ffffff")) },
4265
+ { key: `${prefix}.style`, label: "Style", type: "select", value: g.style, options: opt(["linear", "Linear"], ["radial", "Radial"], ["angle", "Angle"], ["reflected", "Reflected"], ["diamond", "Diamond"]) },
4266
+ { key: `${prefix}.angle`, label: "Angle", type: "range", min: -180, max: 180, step: 1, value: g.angle, unit: "\xB0" },
4267
+ { key: `${prefix}.scale`, label: "Scale", type: "range", min: 0.1, max: 1.5, step: 0.01, value: g.scale, percent: true, unit: "%" },
4268
+ { key: `${prefix}.reverse`, label: "Reverse", type: "checkbox", value: g.reverse },
4269
+ { key: `${prefix}.align`, label: "Align with layer", type: "checkbox", value: g.align }
4270
+ ];
4271
+ }
4272
+ var px = (key, label, value, max = 250) => ({ key, label, type: "range", min: 0, max, step: 1, value, unit: "px" });
4273
+ var pct = (key, label, value, min = 0, max = 1) => ({ key, label, type: "range", min, max, step: 0.01, value, percent: true, unit: "%" });
4274
+ var deg = (key, label, value, min = -180, max = 180) => ({ key, label, type: "range", min, max, step: 1, value, unit: "\xB0" });
4275
+ function layerEffectControls(e, patterns = []) {
4276
+ const blended = e.kind === "bevel-emboss" ? [] : [
4277
+ { key: "blend", label: "Blend mode", type: "select", value: e.blend, options: BLENDS },
4278
+ pct("opacity", "Opacity", e.opacity)
4279
+ ];
4280
+ switch (e.kind) {
4281
+ case "drop-shadow":
4282
+ case "inner-shadow":
4283
+ return [
4284
+ ...blended,
4285
+ { key: "color", label: "Color", type: "color", value: e.color },
4286
+ { key: "useGlobalLight", label: "Use global light", type: "checkbox", value: e.useGlobalLight },
4287
+ deg("angle", "Angle", e.angle),
4288
+ px("distance", "Distance", e.distance, 500),
4289
+ e.kind === "drop-shadow" ? pct("spread", "Spread", e.spread) : pct("choke", "Choke", e.choke),
4290
+ px("size", "Size", e.size),
4291
+ pct("noise", "Noise", e.noise),
4292
+ ...e.kind === "drop-shadow" ? [{ key: "knocksOut", label: "Layer knocks out shadow", type: "checkbox", value: e.knocksOut }] : []
4293
+ ];
4294
+ case "outer-glow":
4295
+ case "inner-glow":
4296
+ return [
4297
+ ...blended,
4298
+ ...fillControls(e.fill, false, patterns),
4299
+ { key: "technique", label: "Technique", type: "select", value: e.technique, options: opt(["softer", "Softer"], ["precise", "Precise"]) },
4300
+ ...e.kind === "inner-glow" ? [{ key: "source", label: "Source", type: "select", value: e.source, options: opt(["edge", "Edge"], ["center", "Center"]) }] : [],
4301
+ e.kind === "outer-glow" ? pct("spread", "Spread", e.spread) : pct("choke", "Choke", e.choke),
4302
+ px("size", "Size", e.size),
4303
+ pct("range", "Range", e.range, 0.01, 1),
4304
+ pct("noise", "Noise", e.noise)
4305
+ ];
4306
+ case "bevel-emboss":
4307
+ return [
4308
+ { key: "style", label: "Style", type: "select", value: e.style, options: opt(["inner-bevel", "Inner Bevel"], ["outer-bevel", "Outer Bevel"], ["emboss", "Emboss"], ["pillow-emboss", "Pillow Emboss"], ["stroke-emboss", "Stroke Emboss"]) },
4309
+ { key: "technique", label: "Technique", type: "select", value: e.technique, options: opt(["smooth", "Smooth"], ["chisel-hard", "Chisel Hard"], ["chisel-soft", "Chisel Soft"]) },
4310
+ pct("depth", "Depth", e.depth, 0, 10),
4311
+ { key: "direction", label: "Direction", type: "select", value: e.direction, options: opt(["up", "Up"], ["down", "Down"]) },
4312
+ px("size", "Size", e.size),
4313
+ px("soften", "Soften", e.soften, 16),
4314
+ { key: "useGlobalLight", label: "Use global light", type: "checkbox", value: e.useGlobalLight },
4315
+ deg("angle", "Angle", e.angle),
4316
+ deg("altitude", "Altitude", e.altitude, 0, 90),
4317
+ { key: "highlightColor", label: "Highlight", type: "color", value: e.highlightColor },
4318
+ { key: "highlightBlend", label: "Highlight mode", type: "select", value: e.highlightBlend, options: BLENDS },
4319
+ pct("highlightOpacity", "Highlight opacity", e.highlightOpacity),
4320
+ { key: "shadowColor", label: "Shadow", type: "color", value: e.shadowColor },
4321
+ { key: "shadowBlend", label: "Shadow mode", type: "select", value: e.shadowBlend, options: BLENDS },
4322
+ pct("shadowOpacity", "Shadow opacity", e.shadowOpacity)
4323
+ ];
4324
+ case "satin":
4325
+ return [
4326
+ ...blended,
4327
+ { key: "color", label: "Color", type: "color", value: e.color },
4328
+ deg("angle", "Angle", e.angle),
4329
+ px("distance", "Distance", e.distance),
4330
+ px("size", "Size", e.size),
4331
+ { key: "invert", label: "Invert", type: "checkbox", value: e.invert }
4332
+ ];
4333
+ case "color-overlay":
4334
+ return [...blended, { key: "color", label: "Color", type: "color", value: e.color }];
4335
+ case "gradient-overlay":
4336
+ return [...blended, ...gradientControls("gradient", e.gradient)];
4337
+ case "pattern-overlay":
4338
+ return [
4339
+ ...blended,
4340
+ { key: "patternId", label: "Pattern", type: "select", value: e.patternId, options: patternOptions(patterns) },
4341
+ pct("scale", "Scale", e.scale, 0.01, 10),
4342
+ deg("angle", "Angle", _nullishCoalesce(e.angle, () => ( 0))),
4343
+ { key: "link", label: "Link with layer", type: "checkbox", value: _nullishCoalesce(e.link, () => ( true)) }
4344
+ ];
4345
+ case "stroke":
4346
+ return [
4347
+ ...blended,
4348
+ px("size", "Size", e.size),
4349
+ { key: "position", label: "Position", type: "select", value: e.position, options: opt(["outside", "Outside"], ["inside", "Inside"], ["center", "Center"]) },
4350
+ ...fillControls(e.fill, true, patterns)
4351
+ ];
4352
+ }
4353
+ }
4354
+ function fillOfType(current, type, patterns) {
4355
+ if (type === "gradient") return { type: "gradient", gradient: defaultEffectGradient() };
4356
+ if (type === "pattern") return { type: "pattern", patternId: _nullishCoalesce(_optionalChain([patterns, 'access', _109 => _109[0], 'optionalAccess', _110 => _110.id]), () => ( "checker")), scale: 1 };
4357
+ return { type: "color", color: current.type === "color" ? current.color : "#000000" };
4358
+ }
4359
+ function effectControlChange(effect, key, value, patterns = []) {
4360
+ const [top, ...rest] = key.split(".");
4361
+ if (top === "fill" && rest[0] === "type") return { fill: fillOfType(effect.fill, String(value), patterns) };
4362
+ if (top === "patternId" && !rest.length) {
4363
+ const name = _optionalChain([patternOptions, 'call', _111 => _111(patterns), 'access', _112 => _112.find, 'call', _113 => _113((o) => o.value === value), 'optionalAccess', _114 => _114.label]);
4364
+ return name ? { patternId: value, name } : { patternId: value };
4365
+ }
4366
+ if (!rest.length) return { [top]: value };
4367
+ if (top === "fill" && rest[0] === "patternId") {
4368
+ const name = _optionalChain([patternOptions, 'call', _115 => _115(patterns), 'access', _116 => _116.find, 'call', _117 => _117((o) => o.value === value), 'optionalAccess', _118 => _118.label]);
4369
+ return { fill: { ...effect.fill, patternId: value, ...name ? { name } : {} } };
4370
+ }
4371
+ return { [top]: setPath(getPath(effect, top), rest, value) };
4372
+ }
4373
+
4374
+
4375
+
4376
+
4377
+
4378
+
4200
4379
 
4201
4380
 
4202
4381
 
@@ -4259,4 +4438,4 @@ function compositeSurfaceOver(base, top) {
4259
4438
 
4260
4439
 
4261
4440
 
4262
- exports.DEFAULT_GLOBAL_LIGHT = DEFAULT_GLOBAL_LIGHT; exports.LAYER_EFFECT_KINDS = LAYER_EFFECT_KINDS; exports.layerEffectLabel = layerEffectLabel; exports.isLayerEffectKind = isLayerEffectKind; exports.defaultEffectGradient = defaultEffectGradient; exports.newEffectId = newEffectId; exports.defaultLayerEffect = defaultLayerEffect; exports.hasActiveEffects = hasActiveEffects; exports.MAX_EFFECT_REACH = MAX_EFFECT_REACH; exports.effectReach = effectReach; exports.effectsMargin = effectsMargin; exports.effectsScale = effectsScale; exports.scaleLayerEffect = scaleLayerEffect; exports.parseEffectColor = parseEffectColor; exports.effectColorHex = effectColorHex; exports.LayerEffectError = LayerEffectError; exports.validateEffectGradient = validateEffectGradient; exports.layerEffectFields = layerEffectFields; exports.validateLayerEffect = validateLayerEffect; exports.mergeLayerEffect = mergeLayerEffect; exports.validateLayerEffects = validateLayerEffects; exports.normalizeLayerEffects = normalizeLayerEffects; exports.effectsFingerprint = effectsFingerprint; exports.PatternTile = PatternTile; exports.PatternPlacement = PatternPlacement; exports.builtinPatternIds = builtinPatternIds; exports.builtinPattern = builtinPattern; exports.hashNoise = hashNoise; exports.CURVE_LUT_SIZE = CURVE_LUT_SIZE; exports.curveLut = curveLut; exports.STROKE_CHAMFER_MAX = STROKE_CHAMFER_MAX; exports.contourLut = contourLut; exports.activeEffectItems = activeEffectItems; exports.effectsAreLocal = effectsAreLocal; exports.buildEffectMaps = buildEffectMaps; exports.patchEffectMaps = patchEffectMaps; exports.gradientT = gradientT; exports.effectFillColors = effectFillColors; exports.compositeLayerEffects = compositeLayerEffects; exports.renderLayerEffects = renderLayerEffects; exports.applyEdgeAmbient = applyEdgeAmbient; exports.blendTile = blendTile; exports.RasterCompositor = RasterCompositor; exports.changedTiles = changedTiles; exports.DeepCompositor = DeepCompositor; exports.workingToSamples = workingToSamples; exports.flattenLayers = flattenLayers; exports.findLayer = findLayer; exports.mapLayer = mapLayer; exports.insertLayer = insertLayer; exports.isLayerLocked = isLayerLocked; exports.INTERPOLATIONS = INTERPOLATIONS; exports.isInterpolation = isInterpolation; exports.MAX_TRANSFORM_PIXELS = MAX_TRANSFORM_PIXELS; exports.TransformTooLargeError = TransformTooLargeError; exports.keysWeight = keysWeight; exports.reduceSurface = reduceSurface; exports.transformedBounds = transformedBounds; exports.transformSurface = transformSurface; exports.warpSurface = warpSurface; exports.compositeSurfaceOver = compositeSurfaceOver;
4441
+ exports.DEFAULT_GLOBAL_LIGHT = DEFAULT_GLOBAL_LIGHT; exports.LAYER_EFFECT_KINDS = LAYER_EFFECT_KINDS; exports.layerEffectLabel = layerEffectLabel; exports.isLayerEffectKind = isLayerEffectKind; exports.defaultEffectGradient = defaultEffectGradient; exports.newEffectId = newEffectId; exports.defaultLayerEffect = defaultLayerEffect; exports.hasActiveEffects = hasActiveEffects; exports.MAX_EFFECT_REACH = MAX_EFFECT_REACH; exports.effectReach = effectReach; exports.effectsMargin = effectsMargin; exports.effectsScale = effectsScale; exports.scaleLayerEffect = scaleLayerEffect; exports.parseEffectColor = parseEffectColor; exports.effectColorHex = effectColorHex; exports.LayerEffectError = LayerEffectError; exports.validateEffectGradient = validateEffectGradient; exports.layerEffectFields = layerEffectFields; exports.validateLayerEffect = validateLayerEffect; exports.mergeLayerEffect = mergeLayerEffect; exports.validateLayerEffects = validateLayerEffects; exports.normalizeLayerEffects = normalizeLayerEffects; exports.effectsFingerprint = effectsFingerprint; exports.PatternTile = PatternTile; exports.PatternPlacement = PatternPlacement; exports.builtinPatternIds = builtinPatternIds; exports.builtinPattern = builtinPattern; exports.hashNoise = hashNoise; exports.CURVE_LUT_SIZE = CURVE_LUT_SIZE; exports.curveLut = curveLut; exports.STROKE_CHAMFER_MAX = STROKE_CHAMFER_MAX; exports.contourLut = contourLut; exports.activeEffectItems = activeEffectItems; exports.effectsAreLocal = effectsAreLocal; exports.buildEffectMaps = buildEffectMaps; exports.patchEffectMaps = patchEffectMaps; exports.gradientT = gradientT; exports.effectFillColors = effectFillColors; exports.compositeLayerEffects = compositeLayerEffects; exports.renderLayerEffects = renderLayerEffects; exports.applyEdgeAmbient = applyEdgeAmbient; exports.blendTile = blendTile; exports.RasterCompositor = RasterCompositor; exports.changedTiles = changedTiles; exports.DeepCompositor = DeepCompositor; exports.workingToSamples = workingToSamples; exports.flattenLayers = flattenLayers; exports.findLayer = findLayer; exports.mapLayer = mapLayer; exports.insertLayer = insertLayer; exports.isLayerLocked = isLayerLocked; exports.INTERPOLATIONS = INTERPOLATIONS; exports.isInterpolation = isInterpolation; exports.MAX_TRANSFORM_PIXELS = MAX_TRANSFORM_PIXELS; exports.TransformTooLargeError = TransformTooLargeError; exports.keysWeight = keysWeight; exports.reduceSurface = reduceSurface; exports.transformedBounds = transformedBounds; exports.transformSurface = transformSurface; exports.warpSurface = warpSurface; exports.compositeSurfaceOver = compositeSurfaceOver; exports.layerEffectsPanel = layerEffectsPanel; exports.layerEffectsBadge = layerEffectsBadge; exports.LAYER_EFFECT_MENU = LAYER_EFFECT_MENU; exports.layerEffectControls = layerEffectControls; exports.effectControlChange = effectControlChange;
@@ -15,12 +15,12 @@ var _chunkAVTPZO4Zcjs = require('./chunk-AVTPZO4Z.cjs');
15
15
 
16
16
 
17
17
 
18
- var _chunkRSIKDWOPcjs = require('./chunk-RSIKDWOP.cjs');
18
+ var _chunkTZOX7KWVcjs = require('./chunk-TZOX7KWV.cjs');
19
19
 
20
20
  // src/brushes/patch.ts
21
21
  var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
22
22
  var copy = (v) => JSON.parse(JSON.stringify(v));
23
- var FACETS = _chunkRSIKDWOPcjs.BRUSH_JSON_SCHEMA.properties;
23
+ var FACETS = _chunkTZOX7KWVcjs.BRUSH_JSON_SCHEMA.properties;
24
24
  var BRUSH_PATCH_PROPERTIES = (() => {
25
25
  const { id: _id, name: _name, ...rest } = FACETS;
26
26
  const { required: _r, ...tip } = rest.tip;
@@ -52,17 +52,17 @@ function changedBrushPaths(a, b, path = "") {
52
52
  // src/brushes/tools.ts
53
53
  var READ = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
54
54
  var WRITE = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
55
- var FACETS2 = _chunkRSIKDWOPcjs.BRUSH_JSON_SCHEMA.properties;
55
+ var FACETS2 = _chunkTZOX7KWVcjs.BRUSH_JSON_SCHEMA.properties;
56
56
  var ID = { type: "string", pattern: String(FACETS2.id.pattern), description: "Brush id from list_brush_presets (lowercase letters, digits and dashes)." };
57
57
  var FACET_PROPS = BRUSH_PATCH_PROPERTIES;
58
- var HOSTS = Object.keys(_chunkRSIKDWOPcjs.BRUSH_HOST_PROFILES);
58
+ var HOSTS = Object.keys(_chunkTZOX7KWVcjs.BRUSH_HOST_PROFILES);
59
59
  var copy2 = (v) => JSON.parse(JSON.stringify(v));
60
60
  var merge = mergeBrushPatch;
61
61
  var changedPaths = changedBrushPaths;
62
62
  function summary(entry, profile, withCheck) {
63
63
  const b = entry.brush;
64
- const engine = _chunkRSIKDWOPcjs.resolveEngine.call(void 0, b);
65
- const check = withCheck ? _chunkRSIKDWOPcjs.checkBrush.call(void 0, b, profile) : null;
64
+ const engine = _chunkTZOX7KWVcjs.resolveEngine.call(void 0, b);
65
+ const check = withCheck ? _chunkTZOX7KWVcjs.checkBrush.call(void 0, b, profile) : null;
66
66
  return {
67
67
  id: b.id,
68
68
  name: b.name,
@@ -71,7 +71,7 @@ function summary(entry, profile, withCheck) {
71
71
  ...b.medium ? { medium: b.medium } : {},
72
72
  ...b.variety ? { variety: b.variety } : {},
73
73
  ...b.tool ? { tool: b.tool } : {},
74
- category: _chunkRSIKDWOPcjs.resolveCategory.call(void 0, b, engine),
74
+ category: _chunkTZOX7KWVcjs.resolveCategory.call(void 0, b, engine),
75
75
  engine,
76
76
  tip: b.tip.shape,
77
77
  ...b.tip.size !== void 0 ? { size: b.tip.size } : {},
@@ -85,21 +85,21 @@ function summary(entry, profile, withCheck) {
85
85
  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.)`;
86
86
  var warnings = (check) => check.issues.filter((i) => i.severity === "warning");
87
87
  function createBrushLibraryTools(library, options = {}) {
88
- const profile = _nullishCoalesce(options.profile, () => ( _chunkRSIKDWOPcjs.PAINT_PROFILE));
88
+ const profile = _nullishCoalesce(options.profile, () => ( _chunkTZOX7KWVcjs.PAINT_PROFILE));
89
89
  const hostOf = (id) => {
90
90
  if (id === void 0) return profile;
91
- const p = _chunkRSIKDWOPcjs.BRUSH_HOST_PROFILES[id];
92
- if (!p) throw new (0, _chunkRSIKDWOPcjs.BrushLibraryError)("invalid", `No host "${id}"; use one of: ${HOSTS.join(", ")}.`);
91
+ const p = _chunkTZOX7KWVcjs.BRUSH_HOST_PROFILES[id];
92
+ if (!p) throw new (0, _chunkTZOX7KWVcjs.BrushLibraryError)("invalid", `No host "${id}"; use one of: ${HOSTS.join(", ")}.`);
93
93
  return p;
94
94
  };
95
95
  const entry = async (id) => {
96
96
  const found = await library.get(id);
97
97
  if (found) return found;
98
98
  const ids = (await library.list()).map((e) => e.brush.id);
99
- throw new (0, _chunkRSIKDWOPcjs.BrushLibraryError)("unknown_brush", `No brush "${id}". ${_chunkRSIKDWOPcjs.closest.call(void 0, id, ids)}list_brush_presets lists them.`);
99
+ throw new (0, _chunkTZOX7KWVcjs.BrushLibraryError)("unknown_brush", `No brush "${id}". ${_chunkTZOX7KWVcjs.closest.call(void 0, id, ids)}list_brush_presets lists them.`);
100
100
  };
101
101
  const checkFor = async (brush, p) => {
102
- const check2 = _chunkRSIKDWOPcjs.checkBrush.call(void 0, brush, p);
102
+ const check2 = _chunkTZOX7KWVcjs.checkBrush.call(void 0, brush, p);
103
103
  const provider = _optionalChain([options, 'access', _9 => _9.stickers, 'optionalCall', _10 => _10()]);
104
104
  if (!provider || brush.tip.shape !== "stamp") return check2;
105
105
  const issues = [...check2.issues];
@@ -117,12 +117,12 @@ function createBrushLibraryTools(library, options = {}) {
117
117
  const problems = [];
118
118
  let brush;
119
119
  try {
120
- brush = _chunkRSIKDWOPcjs.normalizeBrushSpec.call(void 0, raw, problems);
120
+ brush = _chunkTZOX7KWVcjs.normalizeBrushSpec.call(void 0, raw, problems);
121
121
  } catch (e) {
122
- throw new (0, _chunkRSIKDWOPcjs.BrushLibraryError)("invalid", e.message);
122
+ throw new (0, _chunkTZOX7KWVcjs.BrushLibraryError)("invalid", e.message);
123
123
  }
124
124
  const check2 = await checkFor(brush, profile);
125
- if (!check2.ok) throw new (0, _chunkRSIKDWOPcjs.BrushLibraryError)("invalid", refusal(check2, profile));
125
+ if (!check2.ok) throw new (0, _chunkTZOX7KWVcjs.BrushLibraryError)("invalid", refusal(check2, profile));
126
126
  const saved = await library.save(brush, { overwrite });
127
127
  return { ...saved, problems, check: check2 };
128
128
  };
@@ -133,10 +133,10 @@ function createBrushLibraryTools(library, options = {}) {
133
133
  inputSchema: {
134
134
  type: "object",
135
135
  properties: {
136
- kind: { type: "string", enum: [..._chunkRSIKDWOPcjs.BRUSH_KINDS], description: "mark (lays a material) or tool (works on paint already down)." },
137
- medium: { type: "string", enum: [..._chunkRSIKDWOPcjs.BRUSH_MEDIA], description: "Marks laying this medium." },
136
+ kind: { type: "string", enum: [..._chunkTZOX7KWVcjs.BRUSH_KINDS], description: "mark (lays a material) or tool (works on paint already down)." },
137
+ medium: { type: "string", enum: [..._chunkTZOX7KWVcjs.BRUSH_MEDIA], description: "Marks laying this medium." },
138
138
  variety: { type: "string", maxLength: 40, description: "This variety (oil, watercolor, pencil, highlighter\u2026)." },
139
- tool: { type: "string", enum: [..._chunkRSIKDWOPcjs.BRUSH_TOOLS], description: "Tools that do this." },
139
+ tool: { type: "string", enum: [..._chunkTZOX7KWVcjs.BRUSH_TOOLS], description: "Tools that do this." },
140
140
  tag: { type: "string", maxLength: 40, description: "Brushes with this tag." },
141
141
  text: { type: "string", maxLength: 200, description: "Words in the id, name, description, variety or tags (each word must match the start of one)." },
142
142
  source: { type: "string", enum: ["all", "builtin", "user"], description: "all (default), builtin presets only, or user (saved) brushes only." },
@@ -163,8 +163,8 @@ function createBrushLibraryTools(library, options = {}) {
163
163
  annotations: { title: "Describe a brush", ...READ },
164
164
  handler: async ({ id }) => {
165
165
  const e = await entry(id);
166
- const engine = _chunkRSIKDWOPcjs.resolveEngine.call(void 0, e.brush);
167
- return { brush: e.brush, builtin: e.builtin, engine, category: _chunkRSIKDWOPcjs.resolveCategory.call(void 0, e.brush, engine), check: await checkFor(e.brush, profile) };
166
+ const engine = _chunkTZOX7KWVcjs.resolveEngine.call(void 0, e.brush);
167
+ return { brush: e.brush, builtin: e.builtin, engine, category: _chunkTZOX7KWVcjs.resolveCategory.call(void 0, e.brush, engine), check: await checkFor(e.brush, profile) };
168
168
  }
169
169
  };
170
170
  const check = {
@@ -182,20 +182,20 @@ function createBrushLibraryTools(library, options = {}) {
182
182
  },
183
183
  annotations: { title: "Check a brush for a host", ...READ },
184
184
  handler: async ({ id, brush, host }) => {
185
- if (id === void 0 === (brush === void 0)) throw new (0, _chunkRSIKDWOPcjs.BrushLibraryError)("invalid", "Give either id (a library brush) or brush (a spec), not both or neither.");
185
+ if (id === void 0 === (brush === void 0)) throw new (0, _chunkTZOX7KWVcjs.BrushLibraryError)("invalid", "Give either id (a library brush) or brush (a spec), not both or neither.");
186
186
  const p = hostOf(host);
187
187
  let b;
188
188
  const problems = [];
189
189
  if (id !== void 0) b = (await entry(id)).brush;
190
190
  else {
191
191
  try {
192
- b = _chunkRSIKDWOPcjs.normalizeBrushSpec.call(void 0, brush, problems);
192
+ b = _chunkTZOX7KWVcjs.normalizeBrushSpec.call(void 0, brush, problems);
193
193
  } catch (e) {
194
- throw new (0, _chunkRSIKDWOPcjs.BrushLibraryError)("invalid", e.message);
194
+ throw new (0, _chunkTZOX7KWVcjs.BrushLibraryError)("invalid", e.message);
195
195
  }
196
196
  }
197
197
  const result = await checkFor(b, p);
198
- return { host: p.id, ...result, ...problems.length ? { problems } : {}, ...!result.ok ? { degraded: _chunkRSIKDWOPcjs.degrade.call(void 0, b, p) } : {} };
198
+ return { host: p.id, ...result, ...problems.length ? { problems } : {}, ...!result.ok ? { degraded: _chunkTZOX7KWVcjs.degrade.call(void 0, b, p) } : {} };
199
199
  }
200
200
  };
201
201
  const exportTool = {
@@ -254,12 +254,12 @@ function createBrushLibraryTools(library, options = {}) {
254
254
  },
255
255
  annotations: { title: "Save a new brush", ...WRITE },
256
256
  handler: async ({ basedOn, ...spec }) => {
257
- if (library.isBuiltin(spec.id)) throw new (0, _chunkRSIKDWOPcjs.BrushLibraryError)("builtin", `"${spec.id}" is a built-in brush id; pick another id (or basedOn "${spec.id}" with a new id).`);
258
- if (await library.get(spec.id)) throw new (0, _chunkRSIKDWOPcjs.BrushLibraryError)("exists", `A brush "${spec.id}" exists already; pick another id, or change it with update_brush.`);
257
+ if (library.isBuiltin(spec.id)) throw new (0, _chunkTZOX7KWVcjs.BrushLibraryError)("builtin", `"${spec.id}" is a built-in brush id; pick another id (or basedOn "${spec.id}" with a new id).`);
258
+ if (await library.get(spec.id)) throw new (0, _chunkTZOX7KWVcjs.BrushLibraryError)("exists", `A brush "${spec.id}" exists already; pick another id, or change it with update_brush.`);
259
259
  const base = basedOn !== void 0 ? (await entry(basedOn)).brush : void 0;
260
260
  const raw = base ? merge(base, spec) : spec;
261
261
  const saved = await store(raw, false);
262
- return { id: saved.brush.id, brush: saved.brush, engine: _chunkRSIKDWOPcjs.resolveEngine.call(void 0, saved.brush), problems: saved.problems, warnings: warnings(saved.check) };
262
+ return { id: saved.brush.id, brush: saved.brush, engine: _chunkTZOX7KWVcjs.resolveEngine.call(void 0, saved.brush), problems: saved.problems, warnings: warnings(saved.check) };
263
263
  }
264
264
  },
265
265
  {
@@ -280,7 +280,7 @@ function createBrushLibraryTools(library, options = {}) {
280
280
  annotations: { title: "Update a brush", ...WRITE, idempotentHint: true },
281
281
  handler: async ({ id, unset, ...patch }) => {
282
282
  const e = await entry(id);
283
- if (e.builtin) throw new (0, _chunkRSIKDWOPcjs.BrushLibraryError)("builtin", `"${id}" is a built-in brush and can't be changed; duplicate_brush makes a copy you can change.`);
283
+ if (e.builtin) throw new (0, _chunkTZOX7KWVcjs.BrushLibraryError)("builtin", `"${id}" is a built-in brush and can't be changed; duplicate_brush makes a copy you can change.`);
284
284
  const base = copy2(e.brush);
285
285
  for (const k of _nullishCoalesce(unset, () => ( []))) delete base[k];
286
286
  const saved = await store(merge(base, { ...patch, id }), true);
@@ -339,7 +339,7 @@ function createBrushLibraryTools(library, options = {}) {
339
339
  return tools;
340
340
  }
341
341
  function createBrushLibraryToolProvider(library, options = {}) {
342
- const profile = _nullishCoalesce(options.profile, () => ( _chunkRSIKDWOPcjs.PAINT_PROFILE));
342
+ const profile = _nullishCoalesce(options.profile, () => ( _chunkTZOX7KWVcjs.PAINT_PROFILE));
343
343
  const tools = createBrushLibraryTools(library, options);
344
344
  return {
345
345
  id: _nullishCoalesce(options.id, () => ( "brushes")),
@@ -18,7 +18,7 @@ import {
18
18
  unionBounds,
19
19
  vectorGradientPoints,
20
20
  widthProfileAt
21
- } from "./chunk-YQ4PQTBB.js";
21
+ } from "./chunk-6NZL24W4.js";
22
22
  import {
23
23
  segmentLength,
24
24
  segmentParamAtLength,
@@ -337,7 +337,7 @@ function createDrawCommands(target, options = {}) {
337
337
  description: "Stroke points as [x, y] pairs in canvas (flow) units, in drawing order. Use a point every few units along curves."
338
338
  },
339
339
  tool: { type: "string", enum: ["pen", "highlighter"], description: "Pen (default: blue, width 3) or highlighter (yellow, width 24, opacity 0.35); sets the defaults below." },
340
- color: { type: "string", description: "Stroke colour, any CSS colour (default from the tool)." },
340
+ color: { type: "string", description: "Stroke colour, any CSS colour (default: the brush's default colour, such as the ballpoint's blue, else the tool's)." },
341
341
  width: { type: "number", exclusiveMinimum: 0, maximum: 2500, description: "Stroke width in canvas units (default from the tool). For brushed strokes it is the brush diameter; leave it out to use the preset's own size (canvas.listBrushes gives it)." },
342
342
  opacity: { type: "number", minimum: 0, maximum: 1, description: "Stroke opacity 0..1 (default from the tool)." },
343
343
  brush: {
@@ -420,7 +420,7 @@ var gestureBoxes = (what) => ({
420
420
  });
421
421
  var GESTURE_STYLE_PARAMS = {
422
422
  tool: { type: "string", enum: ["pen", "highlighter"], description: "Pen (default: blue, width 3) or highlighter (yellow, width 24, opacity 0.35); sets the defaults below." },
423
- color: { type: "string", description: "Stroke colour, any CSS colour (default from the tool)." },
423
+ color: { type: "string", description: "Stroke colour, any CSS colour (default: the brush's default colour, such as the ballpoint's blue, else the tool's)." },
424
424
  width: { type: "number", exclusiveMinimum: 0, maximum: 2500, description: "Stroke width in canvas units (default from the tool; with a brush, the preset's own size)." },
425
425
  opacity: { type: "number", minimum: 0, maximum: 1, description: "Stroke opacity 0..1 (default from the tool)." },
426
426
  brush: {
@@ -1692,13 +1692,13 @@ function normalizeBrushSpec(raw, problems = []) {
1692
1692
  }
1693
1693
  if (_optionalChain([brush, 'access', _26 => _26.marks, 'optionalAccess', _27 => _27.kind]) === "scatter") {
1694
1694
  const surface = _optionalChain([brush, 'access', _28 => _28.behaviour, 'optionalAccess', _29 => _29.surface]);
1695
- const why = brush.tip.shape === "bristle" ? "bristle tips lay their own marks" : surface === "wet" || surface === "thick" ? `${surface} paint is not sprayed` : _optionalChain([brush, 'access', _30 => _30.behaviour, 'optionalAccess', _31 => _31.exchange]) ? "a spray does not pick paint up" : null;
1695
+ const why = brush.tip.shape === "bristle" ? "bristle tips lay their own marks" : surface === "wet" || surface === "thick" ? `${surface} paint is not sprayed` : _optionalChain([brush, 'access', _30 => _30.behaviour, 'optionalAccess', _31 => _31.exchange, 'optionalAccess', _32 => _32.reservoir]) ? "the Mixer Brush is not sprayed" : null;
1696
1696
  if (why) {
1697
1697
  drop("marks", why);
1698
1698
  delete brush.marks;
1699
1699
  }
1700
1700
  }
1701
- if (_optionalChain([brush, 'access', _32 => _32.marks, 'optionalAccess', _33 => _33.kind]) === "objects" && brush.tip.shape !== "stamp") {
1701
+ if (_optionalChain([brush, 'access', _33 => _33.marks, 'optionalAccess', _34 => _34.kind]) === "objects" && brush.tip.shape !== "stamp") {
1702
1702
  problems.push("marks objects lay stamps: tip.shape set to stamp.");
1703
1703
  brush.tip.shape = "stamp";
1704
1704
  }
@@ -1748,7 +1748,7 @@ function normalizeBrushSpec(raw, problems = []) {
1748
1748
  if (b.exchange && kind === "tool" && !wetTool) {
1749
1749
  drop("behaviour.exchange", `the ${brush.tool} does not pick paint up`);
1750
1750
  delete b.exchange;
1751
- } else if (b.exchange && (_optionalChain([brush, 'access', _34 => _34.marks, 'optionalAccess', _35 => _35.kind]) === "particles" || _optionalChain([brush, 'access', _36 => _36.marks, 'optionalAccess', _37 => _37.kind]) === "objects" || brush.tip.shape === "bristle")) {
1751
+ } else if (b.exchange && (_optionalChain([brush, 'access', _35 => _35.marks, 'optionalAccess', _36 => _36.kind]) === "particles" || _optionalChain([brush, 'access', _37 => _37.marks, 'optionalAccess', _38 => _38.kind]) === "objects" || brush.tip.shape === "bristle")) {
1752
1752
  drop("behaviour.exchange", "particle, object and bristle marks do not pick paint up");
1753
1753
  delete b.exchange;
1754
1754
  }
@@ -2582,26 +2582,26 @@ function checkBrush(brush, profile) {
2582
2582
  add("tool", "error", `${host} has no ${brush.tool} tool.`, profile.tools.length ? `Use one of: ${list(profile.tools)}.` : `${host} has no tools; use a mark brush.`);
2583
2583
  }
2584
2584
  if (!profile.tipShapes.includes(brush.tip.shape)) add("tip.shape", "error", `${host} can't lay a ${brush.tip.shape} tip.`, `Set tip.shape to one of: ${list(profile.tipShapes)}.`);
2585
- const marks = _nullishCoalesce(_optionalChain([brush, 'access', _38 => _38.marks, 'optionalAccess', _39 => _39.kind]), () => ( "continuous"));
2585
+ const marks = _nullishCoalesce(_optionalChain([brush, 'access', _39 => _39.marks, 'optionalAccess', _40 => _40.kind]), () => ( "continuous"));
2586
2586
  if (!profile.marks.includes(marks)) add("marks", "error", `${host} can't lay ${marks} marks.`, `Use marks ${list(profile.marks)} (remove marks for continuous dabs).`);
2587
- const surface = _nullishCoalesce(_optionalChain([brush, 'access', _40 => _40.behaviour, 'optionalAccess', _41 => _41.surface]), () => ( "dry"));
2587
+ const surface = _nullishCoalesce(_optionalChain([brush, 'access', _41 => _41.behaviour, 'optionalAccess', _42 => _42.surface]), () => ( "dry"));
2588
2588
  if (brush.kind === "mark" && !profile.surfaces.includes(surface)) add("behaviour.surface", "error", `${host} has no ${surface} surface.`, `Set behaviour.surface to ${list(profile.surfaces)}.`);
2589
- const ex = _optionalChain([brush, 'access', _42 => _42.behaviour, 'optionalAccess', _43 => _43.exchange]);
2590
- feature(profile.reservoir, !!_optionalChain([ex, 'optionalAccess', _44 => _44.reservoir]), "behaviour.exchange.reservoir", "a Mixer Brush reservoir", "Remove behaviour.exchange.reservoir.");
2591
- feature(profile.exchange, !_optionalChain([ex, 'optionalAccess', _45 => _45.reservoir]) && (nonZero(_optionalChain([ex, 'optionalAccess', _46 => _46.pickup])) || !!_optionalChain([ex, 'optionalAccess', _47 => _47.dirty])), "behaviour.exchange", "picking paint up", "Remove behaviour.exchange.");
2592
- feature(profile.grain, nonZero(_optionalChain([brush, 'access', _48 => _48.behaviour, 'optionalAccess', _49 => _49.grain])), "behaviour.grain", "paper grain", "Set behaviour.grain to 0.");
2593
- feature(profile.light, nonZero(_optionalChain([brush, 'access', _50 => _50.light, 'optionalAccess', _51 => _51.amount])), "light", "light paint (glow and spill)", "Remove light (or set light.amount to 0).");
2589
+ const ex = _optionalChain([brush, 'access', _43 => _43.behaviour, 'optionalAccess', _44 => _44.exchange]);
2590
+ feature(profile.reservoir, !!_optionalChain([ex, 'optionalAccess', _45 => _45.reservoir]), "behaviour.exchange.reservoir", "a Mixer Brush reservoir", "Remove behaviour.exchange.reservoir.");
2591
+ feature(profile.exchange, !_optionalChain([ex, 'optionalAccess', _46 => _46.reservoir]) && (nonZero(_optionalChain([ex, 'optionalAccess', _47 => _47.pickup])) || !!_optionalChain([ex, 'optionalAccess', _48 => _48.dirty])), "behaviour.exchange", "picking paint up", "Remove behaviour.exchange.");
2592
+ feature(profile.grain, nonZero(_optionalChain([brush, 'access', _49 => _49.behaviour, 'optionalAccess', _50 => _50.grain])), "behaviour.grain", "paper grain", "Set behaviour.grain to 0.");
2593
+ feature(profile.light, nonZero(_optionalChain([brush, 'access', _51 => _51.light, 'optionalAccess', _52 => _52.amount])), "light", "light paint (glow and spill)", "Remove light (or set light.amount to 0).");
2594
2594
  const m = brush.motion;
2595
2595
  feature(profile.motion, !!m && (!!m.live || nonZero(m.waveSpeed) || m.fps !== void 0), "motion", "animation", "Remove motion.");
2596
2596
  const d = _nullishCoalesce(brush.dynamics, () => ( {}));
2597
2597
  feature(profile.velocity, nonZero(d.velocitySize) || nonZero(d.velocityOpacity), "dynamics.velocity", "velocity dynamics (its strokes carry no timing)", "Set dynamics.velocitySize and velocityOpacity to 0.");
2598
2598
  feature(profile.tilt, nonZero(d.tiltSize) || nonZero(d.tiltRoundness) || nonZero(d.tiltOpacity), "dynamics.tilt", "tilt dynamics", "Set dynamics.tiltSize, tiltRoundness and tiltOpacity to 0.");
2599
2599
  const colour = brush.colour;
2600
- if (_optionalChain([colour, 'optionalAccess', _52 => _52.default]) !== void 0) {
2600
+ if (_optionalChain([colour, 'optionalAccess', _53 => _53.default]) !== void 0) {
2601
2601
  const kind = brushColourKind(colour.default);
2602
2602
  if (!profile.colours.includes(kind)) add("colour.default", "error", `${host} can't paint ${kind} colours.`, `Use a ${list(profile.colours)} colour, or remove colour.default.`);
2603
2603
  }
2604
- const foreign = [...new Set((_nullishCoalesce(_optionalChain([colour, 'optionalAccess', _53 => _53.palette]), () => ( []))).map(brushColourKind).filter((k) => !profile.colours.includes(k)))];
2604
+ const foreign = [...new Set((_nullishCoalesce(_optionalChain([colour, 'optionalAccess', _54 => _54.palette]), () => ( []))).map(brushColourKind).filter((k) => !profile.colours.includes(k)))];
2605
2605
  if (foreign.length) add("colour.palette", "warning", `${host} skips the palette's ${list(foreign)} colours.`, `Nothing to do; or keep to ${list(profile.colours)} colours.`);
2606
2606
  return { ok: !issues.some((i) => i.severity === "error"), issues };
2607
2607
  }
@@ -2663,7 +2663,7 @@ function degrade(brush, profile) {
2663
2663
  }
2664
2664
  dropped.push(issue);
2665
2665
  }
2666
- if (_optionalChain([b, 'access', _54 => _54.behaviour, 'optionalAccess', _55 => _55.exchange]) && !Object.keys(b.behaviour.exchange).length) delete b.behaviour.exchange;
2666
+ if (_optionalChain([b, 'access', _55 => _55.behaviour, 'optionalAccess', _56 => _56.exchange]) && !Object.keys(b.behaviour.exchange).length) delete b.behaviour.exchange;
2667
2667
  const after = checkBrush(b, profile).issues.filter((i) => i.severity === "error");
2668
2668
  return { brush: b, dropped, issues: after };
2669
2669
  }
@@ -2693,7 +2693,7 @@ function parseBrushLibrary2(raw, problems = []) {
2693
2693
  if (file && file.version !== void 0 && file.version !== 1 && file.version !== 2) {
2694
2694
  throw new BrushLibraryError("invalid", `Brush library version ${JSON.stringify(file.version)} is not supported; this library reads versions 1 and 2.`);
2695
2695
  }
2696
- const v1File = _optionalChain([file, 'optionalAccess', _56 => _56.version]) === 1;
2696
+ const v1File = _optionalChain([file, 'optionalAccess', _57 => _57.version]) === 1;
2697
2697
  const out = [];
2698
2698
  items.forEach((item, i) => {
2699
2699
  const at = `brushes[${i}]`;
@@ -2876,7 +2876,7 @@ function snapshotBrushLibrary(library, onChange) {
2876
2876
  (list2) => {
2877
2877
  entries = list2;
2878
2878
  user = list2.filter((e) => !e.builtin).map((e) => e.brush);
2879
- _optionalChain([onChange, 'optionalCall', _57 => _57()]);
2879
+ _optionalChain([onChange, 'optionalCall', _58 => _58()]);
2880
2880
  },
2881
2881
  () => void 0
2882
2882
  );
@@ -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 ??= Promise.resolve().then(() => _interopRequireWildcard(require("./brushstrokeRender-MQ6PSDM5.cjs"))).catch((error) => {
77
+ loading ??= Promise.resolve().then(() => _interopRequireWildcard(require("./brushstrokeRender-N6UPZSQS.cjs"))).catch((error) => {
78
78
  loading = null;
79
79
  throw error;
80
80
  });