@pixerate/editor 0.137.0 → 0.139.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 (127) hide show
  1. package/dist/agent/index.cjs +2 -2
  2. package/dist/agent/index.d.cts +3 -3
  3. package/dist/agent/index.d.ts +3 -3
  4. package/dist/agent/index.js +1 -1
  5. package/dist/animation-editor/index.cjs +57 -57
  6. package/dist/animation-editor/index.d.cts +6 -5
  7. package/dist/animation-editor/index.d.ts +6 -5
  8. package/dist/animation-editor/index.js +4 -4
  9. package/dist/{arrange-CKXK_hf7.d.cts → arrange-j_mLiFMO.d.cts} +1 -1
  10. package/dist/{arrange-BUREmgD9.d.ts → arrange-q5HQvnnB.d.ts} +1 -1
  11. package/dist/{bezier-Dywv3Bw8.d.ts → bezier-B6cK8SR6.d.ts} +2 -2
  12. package/dist/{bezier-CZ2AhjID.d.cts → bezier-CEJ8Uw4O.d.cts} +2 -2
  13. package/dist/{brushTypes-C7N3EBK7.d.cts → brushTypes-MX5UVs_m.d.cts} +27 -2
  14. package/dist/{brushTypes-C7N3EBK7.d.ts → brushTypes-MX5UVs_m.d.ts} +27 -2
  15. package/dist/{brushes-DJmUbIgz.d.ts → brushes-CQpL7_Lc.d.ts} +2 -107
  16. package/dist/{brushes-CnvZSYYU.d.cts → brushes-aEnjqoji.d.cts} +2 -107
  17. package/dist/{brushstrokeRender-IMFY3FF6.cjs → brushstrokeRender-PP6NTF6M.cjs} +52 -24
  18. package/dist/brushstrokeRender-PP6NTF6M.cjs.map +1 -0
  19. package/dist/{brushstrokeRender-2FAXA3XC.js → brushstrokeRender-QGEYJ4OZ.js} +40 -12
  20. package/dist/brushstrokeRender-QGEYJ4OZ.js.map +1 -0
  21. package/dist/{builtins-Cc-bH-3U.d.cts → builtins-BakDiKWf.d.cts} +3 -2
  22. package/dist/{builtins-ZU1GJnUA.d.ts → builtins-CE33vyv2.d.ts} +3 -2
  23. package/dist/canvas/index.cjs +16 -9
  24. package/dist/canvas/index.cjs.map +1 -1
  25. package/dist/canvas/index.d.cts +60 -14
  26. package/dist/canvas/index.d.ts +60 -14
  27. package/dist/canvas/index.js +10 -3
  28. package/dist/canvas/index.js.map +1 -1
  29. package/dist/{chunk-PRSRYHQD.cjs → chunk-3QHPFSQM.cjs} +36 -36
  30. package/dist/{chunk-PRSRYHQD.cjs.map → chunk-3QHPFSQM.cjs.map} +1 -1
  31. package/dist/{chunk-QBWEH3IM.cjs → chunk-3T5O225T.cjs} +391 -76
  32. package/dist/chunk-3T5O225T.cjs.map +1 -0
  33. package/dist/{chunk-EQQMGO42.js → chunk-C2J7GOMJ.js} +18 -5
  34. package/dist/chunk-C2J7GOMJ.js.map +1 -0
  35. package/dist/{chunk-2XS6LTUP.cjs → chunk-C46AZEBE.cjs} +104 -339
  36. package/dist/chunk-C46AZEBE.cjs.map +1 -0
  37. package/dist/{chunk-HUO3TI4C.js → chunk-CPSMARTX.js} +6 -241
  38. package/dist/chunk-CPSMARTX.js.map +1 -0
  39. package/dist/{chunk-KEENUAFN.cjs → chunk-DLLUOVQX.cjs} +18 -5
  40. package/dist/chunk-DLLUOVQX.cjs.map +1 -0
  41. package/dist/{chunk-LSXXAJG3.js → chunk-J7DSKTKB.js} +5 -4
  42. package/dist/chunk-J7DSKTKB.js.map +1 -0
  43. package/dist/{chunk-6S6362D2.js → chunk-NI6RORDS.js} +2 -2
  44. package/dist/{chunk-XN2NBLV5.cjs → chunk-PMEHFHSP.cjs} +82 -82
  45. package/dist/{chunk-XN2NBLV5.cjs.map → chunk-PMEHFHSP.cjs.map} +1 -1
  46. package/dist/{chunk-5FSRTP6E.js → chunk-PQFVLOMR.js} +319 -4
  47. package/dist/chunk-PQFVLOMR.js.map +1 -0
  48. package/dist/{chunk-OIBIRXRG.js → chunk-PSPLRQL6.js} +2 -2
  49. package/dist/{chunk-SYT2TLQF.js → chunk-QEIN6JQO.js} +2 -2
  50. package/dist/{chunk-3D77LOBM.js → chunk-TJBYBSTN.js} +51 -6
  51. package/dist/chunk-TJBYBSTN.js.map +1 -0
  52. package/dist/{chunk-DFSZO2B5.cjs → chunk-UFL5N4DK.cjs} +5 -4
  53. package/dist/chunk-UFL5N4DK.cjs.map +1 -0
  54. package/dist/{chunk-TLCTTQFF.cjs → chunk-VEHVXRJU.cjs} +17 -17
  55. package/dist/{chunk-TLCTTQFF.cjs.map → chunk-VEHVXRJU.cjs.map} +1 -1
  56. package/dist/{chunk-5OOIUXNJ.cjs → chunk-XFXHA5MU.cjs} +55 -10
  57. package/dist/chunk-XFXHA5MU.cjs.map +1 -0
  58. package/dist/commands/index.cjs +2 -2
  59. package/dist/commands/index.d.cts +3 -3
  60. package/dist/commands/index.d.ts +3 -3
  61. package/dist/commands/index.js +1 -1
  62. package/dist/effects/index.d.cts +5 -4
  63. package/dist/effects/index.d.ts +5 -4
  64. package/dist/{export-DwnZ_hvQ.d.ts → export-0ZaTK__4.d.ts} +4 -4
  65. package/dist/{export-41rL6Cne.d.ts → export-C45v6MYq.d.ts} +1 -1
  66. package/dist/{export-CyJdfP_Z.d.cts → export-D-7WCDJ9.d.cts} +4 -4
  67. package/dist/{export-D9mXp05Q.d.cts → export-DSdCfd6O.d.cts} +1 -1
  68. package/dist/grain-BWmGZxP4.d.cts +58 -0
  69. package/dist/grain-BWmGZxP4.d.ts +58 -0
  70. package/dist/{helpers-v6GMazzg.d.cts → helpers-Cavy1TB7.d.cts} +21 -1
  71. package/dist/{helpers-C-RgeyvH.d.ts → helpers-LZQ4cpg4.d.ts} +21 -1
  72. package/dist/image-editor/index.cjs +695 -677
  73. package/dist/image-editor/index.cjs.map +1 -1
  74. package/dist/image-editor/index.d.cts +12 -11
  75. package/dist/image-editor/index.d.ts +12 -11
  76. package/dist/image-editor/index.js +23 -5
  77. package/dist/image-editor/index.js.map +1 -1
  78. package/dist/{opentype-KR_jj6b_.d.cts → opentype-BpIJhGpj.d.cts} +1 -1
  79. package/dist/{opentype-a1KAW-qs.d.ts → opentype-CyxDScVz.d.ts} +1 -1
  80. package/dist/paint/index.cjs +21 -3
  81. package/dist/paint/index.cjs.map +1 -1
  82. package/dist/paint/index.d.cts +72 -5
  83. package/dist/paint/index.d.ts +72 -5
  84. package/dist/paint/index.js +20 -2
  85. package/dist/paint-editor/index.cjs +171 -171
  86. package/dist/paint-editor/index.cjs.map +1 -1
  87. package/dist/paint-editor/index.d.cts +77 -29
  88. package/dist/paint-editor/index.d.ts +77 -29
  89. package/dist/paint-editor/index.js +12 -12
  90. package/dist/{pathfinder-BHS4vQNm.d.cts → pathfinder-BMQEcS0k.d.cts} +2 -2
  91. package/dist/{pathfinder-BVvTIBMo.d.ts → pathfinder-CQIxubuP.d.ts} +2 -2
  92. package/dist/{pool-CZQOrSXZ.d.ts → pool-Cynuj89K.d.ts} +1 -1
  93. package/dist/{pool-FjZZmZ80.d.cts → pool-DedjxDKo.d.cts} +1 -1
  94. package/dist/{rand-8xbUb6ur.d.ts → rand-COS4_E1g.d.ts} +17 -1
  95. package/dist/{rand-Cw9VLrVC.d.cts → rand-D1JqpR-p.d.cts} +17 -1
  96. package/dist/{svg-DTb40ICU.d.cts → svg-RcixtBFR.d.cts} +2 -2
  97. package/dist/{svg-CSz3mzkw.d.ts → svg-nWBJEpnk.d.ts} +2 -2
  98. package/dist/{tools-Ca0kI1qo.d.cts → tools-CL82d7nw.d.cts} +1 -1
  99. package/dist/{tools-B0wXP5cF.d.ts → tools-DrxgDnXY.d.ts} +1 -1
  100. package/dist/vector/index.cjs +995 -955
  101. package/dist/vector/index.cjs.map +1 -1
  102. package/dist/vector/index.d.cts +44 -18
  103. package/dist/vector/index.d.ts +44 -18
  104. package/dist/vector/index.js +55 -15
  105. package/dist/vector/index.js.map +1 -1
  106. package/dist/video-editor/index.d.cts +5 -4
  107. package/dist/video-editor/index.d.ts +5 -4
  108. package/dist/{warp-DTOp0lON.d.cts → warp-CHi_P_G6.d.cts} +1 -1
  109. package/dist/{warp-pd7hrH4T.d.ts → warp-CPaHULUL.d.ts} +1 -1
  110. package/package.json +1 -1
  111. package/skills/pixerate-canvas/SKILL.md +12 -5
  112. package/skills/pixerate-vector/SKILL.md +4 -2
  113. package/dist/brushstrokeRender-2FAXA3XC.js.map +0 -1
  114. package/dist/brushstrokeRender-IMFY3FF6.cjs.map +0 -1
  115. package/dist/chunk-2XS6LTUP.cjs.map +0 -1
  116. package/dist/chunk-3D77LOBM.js.map +0 -1
  117. package/dist/chunk-5FSRTP6E.js.map +0 -1
  118. package/dist/chunk-5OOIUXNJ.cjs.map +0 -1
  119. package/dist/chunk-DFSZO2B5.cjs.map +0 -1
  120. package/dist/chunk-EQQMGO42.js.map +0 -1
  121. package/dist/chunk-HUO3TI4C.js.map +0 -1
  122. package/dist/chunk-KEENUAFN.cjs.map +0 -1
  123. package/dist/chunk-LSXXAJG3.js.map +0 -1
  124. package/dist/chunk-QBWEH3IM.cjs.map +0 -1
  125. /package/dist/{chunk-6S6362D2.js.map → chunk-NI6RORDS.js.map} +0 -0
  126. /package/dist/{chunk-OIBIRXRG.js.map → chunk-PSPLRQL6.js.map} +0 -0
  127. /package/dist/{chunk-SYT2TLQF.js.map → chunk-QEIN6JQO.js.map} +0 -0
@@ -38,7 +38,7 @@ import {
38
38
  reverseMorphContour,
39
39
  subpathToMorphContour,
40
40
  turnMorphContour
41
- } from "../chunk-6S6362D2.js";
41
+ } from "../chunk-NI6RORDS.js";
42
42
  import {
43
43
  DEFAULT_VECTOR_FONT,
44
44
  IDENTITY_MATRIX,
@@ -47,6 +47,7 @@ import {
47
47
  VECTOR_BLEND_MODES,
48
48
  VECTOR_BLEND_MODE_LABELS,
49
49
  VECTOR_BLEND_SPACINGS,
50
+ VECTOR_BRUSHSTROKE_MAX_SEED,
50
51
  VECTOR_BRUSHSTROKE_SCALE,
51
52
  VECTOR_CHARACTER_STYLE_KEYS,
52
53
  VECTOR_CONNECTOR_ROUTES,
@@ -259,6 +260,7 @@ import {
259
260
  pressureWidthProfile,
260
261
  puckerBloatPaths,
261
262
  pullWarpMesh,
263
+ randomVectorBrushstrokeSeed,
262
264
  rectSubpath,
263
265
  removeAnchors,
264
266
  removeVectorFreeformPoint,
@@ -286,6 +288,7 @@ import {
286
288
  sampleVectorGradientAt,
287
289
  sampleVectorPaintDefAt,
288
290
  sanitizeVectorBrushstroke,
291
+ sanitizeVectorBrushstrokePaper,
289
292
  sanitizeVectorConnector,
290
293
  sanitizeVectorEffects,
291
294
  sanitizeVectorFills,
@@ -356,6 +359,7 @@ import {
356
359
  vectorBoxMatrix,
357
360
  vectorBrushstrokeBrush,
358
361
  vectorBrushstrokeBrushes,
362
+ vectorBrushstrokeCharacterError,
359
363
  vectorBrushstrokeImages,
360
364
  vectorBrushstrokeReach,
361
365
  vectorChildAppearanceShapes,
@@ -503,8 +507,8 @@ import {
503
507
  withVectorStrokes,
504
508
  withVectorTargetPaint,
505
509
  zigzagPaths
506
- } from "../chunk-3D77LOBM.js";
507
- import "../chunk-HUO3TI4C.js";
510
+ } from "../chunk-TJBYBSTN.js";
511
+ import "../chunk-CPSMARTX.js";
508
512
  import {
509
513
  createProvenance
510
514
  } from "../chunk-A3BVTI3G.js";
@@ -539,7 +543,9 @@ import {
539
543
  resolveEffectValues
540
544
  } from "../chunk-QFSTQHZY.js";
541
545
  import "../chunk-4FX5ACVG.js";
542
- import "../chunk-5FSRTP6E.js";
546
+ import {
547
+ GRAIN_PATTERNS
548
+ } from "../chunk-PQFVLOMR.js";
543
549
  import "../chunk-63AZAUSN.js";
544
550
  import {
545
551
  bytesToBase64,
@@ -3938,7 +3944,7 @@ function getVectorAppearancePanel(state) {
3938
3944
  ...isVectorBrushstrokeLayer(l) ? (() => {
3939
3945
  const b = l.brush;
3940
3946
  const preset = vectorBrushstrokeBrush(b.brushId);
3941
- return { brushstroke: { brushId: b.brushId, name: preset.name, size: b.size ?? preset.tip.size } };
3947
+ return { brushstroke: { brushId: b.brushId, name: preset.name, size: b.size ?? preset.tip.size, ...b.seed !== void 0 ? { seed: b.seed } : {}, grain: b.seed !== void 0 && b.paper !== null } };
3942
3948
  })() : (l.kind ?? "paint") !== "paint" ? { unknownKind: String(l.kind) } : {},
3943
3949
  editing: edit.target === kind && (edit.layer === null ? index === count - 1 : edit.layer === index)
3944
3950
  });
@@ -8793,12 +8799,15 @@ var VectorEditorController = class _VectorEditorController {
8793
8799
  * brush `brushId` from the paint editor's library (`vectorBrushstrokeBrushes`), `size` document
8794
8800
  * units across (default the brush's own), an optional `pressure` profile along the length, in
8795
8801
  * `color` (default the top stroke's paint, else black) at `opacity`. At the top of the stroke
8796
- * stack or at `index`. One undo step.
8802
+ * stack or at `index`. A `seed` gives it the brush's character (jitter and the grain of `paper`,
8803
+ * `null` for none); without one it renders plain. One undo step.
8797
8804
  */
8798
8805
  addBrushstroke(brush, options = {}) {
8799
8806
  const clean = sanitizeVectorBrushstroke(brush);
8800
8807
  if (!clean) return { ok: false, message: `Unknown brush "${brush?.brushId}": use one of ${vectorBrushstrokeBrushes().map((b) => b.id).join(", ")}.` };
8801
8808
  if (brush.size !== void 0 && !(brush.size > 0 && brush.size <= 500)) return { ok: false, message: "size must be above 0 and at most 500 (document units)." };
8809
+ const characterError = vectorBrushstrokeCharacterError(brush);
8810
+ if (characterError) return { ok: false, message: characterError };
8802
8811
  if (options.color !== void 0 && !parseVectorColor(options.color)) return { ok: false, message: `"${options.color}" is not a colour.` };
8803
8812
  if (options.opacity !== void 0 && !(options.opacity >= 0 && options.opacity <= 1)) return { ok: false, message: "opacity must be from 0 to 1." };
8804
8813
  return this.editStacks("stroke", options.ids, "Add Brushstroke", (stack, path) => {
@@ -8811,15 +8820,18 @@ var VectorEditorController = class _VectorEditorController {
8811
8820
  }
8812
8821
  /**
8813
8822
  * Changes brushstroke layer `index` (in the stroke stack, 0 is the bottom) of the selected (or
8814
- * given) paths: another brush, size, pressure profile (null removes it), colour or opacity.
8815
- * Fails, changing nothing, when that layer is not a brushstroke. With `merge`, consecutive edits
8816
- * fold into one undo step.
8823
+ * given) paths: another brush, size, pressure profile (null removes it), colour or opacity, the
8824
+ * character `seed` (null removes it: plain dabs) or the `paper` (replaced whole: `null` for no
8825
+ * grain, `{}` for the default paper). Fails, changing nothing, when that layer is not a
8826
+ * brushstroke. With `merge`, consecutive edits fold into one undo step.
8817
8827
  */
8818
8828
  setBrushstroke(index, patch, options = {}) {
8819
8829
  if (patch.brushId !== void 0 && !vectorBrushstrokeBrush(patch.brushId)) return { ok: false, message: `Unknown brush "${patch.brushId}": use one of ${vectorBrushstrokeBrushes().map((b) => b.id).join(", ")}.` };
8820
8830
  if (patch.size !== void 0 && patch.size !== null && !(patch.size > 0 && patch.size <= 500)) return { ok: false, message: "size must be above 0 and at most 500 (document units)." };
8821
8831
  if (patch.color !== void 0 && !parseVectorColor(patch.color)) return { ok: false, message: `"${patch.color}" is not a colour.` };
8822
8832
  if (patch.opacity !== void 0 && !(patch.opacity >= 0 && patch.opacity <= 1)) return { ok: false, message: "opacity must be from 0 to 1." };
8833
+ const characterError = vectorBrushstrokeCharacterError({ ...patch.seed !== null && patch.seed !== void 0 ? { seed: patch.seed } : {}, ...patch.paper !== void 0 ? { paper: patch.paper } : {} });
8834
+ if (characterError) return { ok: false, message: characterError };
8823
8835
  const merge = options.merge === true ? `brushstroke:${index}` : options.merge || void 0;
8824
8836
  return this.editStacks(
8825
8837
  "stroke",
@@ -8833,6 +8845,9 @@ var VectorEditorController = class _VectorEditorController {
8833
8845
  else if (patch.size !== void 0) brush.size = patch.size;
8834
8846
  if (patch.pressure === null) delete brush.pressure;
8835
8847
  else if (patch.pressure !== void 0) brush.pressure = patch.pressure;
8848
+ if (patch.seed === null) delete brush.seed;
8849
+ else if (patch.seed !== void 0) brush.seed = patch.seed;
8850
+ if (patch.paper !== void 0) brush.paper = patch.paper;
8836
8851
  const next = { ...layer, brush: sanitizeVectorBrushstroke(brush) ?? layer.brush, ...patch.color ? { paint: patch.color } : {}, ...patch.opacity !== void 0 ? { opacity: patch.opacity } : {} };
8837
8852
  return stack.map((l, i) => i === index ? next : l);
8838
8853
  },
@@ -16279,6 +16294,17 @@ function createVectorCommands(controller, options = {}) {
16279
16294
  }
16280
16295
  }
16281
16296
  ];
16297
+ const BRUSH_SEED = { type: "integer", minimum: 0, maximum: VECTOR_BRUSHSTROKE_MAX_SEED };
16298
+ const BRUSH_PAPER = {
16299
+ type: "object",
16300
+ properties: {
16301
+ pattern: { type: "string", enum: [...GRAIN_PATTERNS], description: 'Grain pattern (default "sanded", a fine even tooth; "rough" and "cold-pressed" for watercolour paper, "canvas" and "linen" for a weave).' },
16302
+ seed: { ...BRUSH_SEED, description: "Grain seed: another seed gives another sheet of the same paper (default 1)." },
16303
+ scale: { type: "number", minimum: 0.25, maximum: 8, description: "Grain scale: 1 is the pattern's natural size, 2 twice as coarse (default 1)." },
16304
+ depth: { type: "number", minimum: 0, maximum: 1, description: "How deep the grain is 0\u20131, times the brush's own grain response (default 0.5)." }
16305
+ },
16306
+ additionalProperties: false
16307
+ };
16282
16308
  const brushstrokeCommands = () => [
16283
16309
  {
16284
16310
  ...base,
@@ -16295,7 +16321,7 @@ function createVectorCommands(controller, options = {}) {
16295
16321
  id: `${prefix}addBrushstroke`,
16296
16322
  label: "Add Brushstroke\u2026",
16297
16323
  keywords: ["brushstroke", "brush", "natural media", "pencil line", "chalk", "sketchy", "hand-drawn", "ink stroke"],
16298
- description: "Paints paths (`ids`, default the selection; groups: every path inside) with a natural-media brush along their outline, as a stroke layer of kind brushstroke: `brushId` from vector.listBrushes, `size` (document units), an optional `pressure` profile (0\u20131 values spread from start to end, e.g. [0.2, 1, 0.2] for a tapered stroke), `color` and `opacity`. The path stays editable; the strokes follow it. One undo step. Returns { paths: [{ id, strokes }] } (the brushstroke is a stroke layer; change it with vector.setBrushstroke, remove it with vector.removeStroke).",
16324
+ description: "Paints paths (`ids`, default the selection; groups: every path inside) with a natural-media brush along their outline, as a stroke layer of kind brushstroke: `brushId` from vector.listBrushes, `size` (document units), an optional `pressure` profile (0\u20131 values spread from start to end, e.g. [0.2, 1, 0.2] for a tapered stroke), `color` and `opacity`. Pass a `seed` for the brush's character (seeded size, angle, opacity and scatter jitter plus a paper grain: what makes pencil, pastel and charcoal look real), with `paper` to choose the grain or null for none; without a seed the brush paints plain, even dabs. The path stays editable; the strokes follow it. One undo step. Returns { paths: [{ id, strokes }] } (the brushstroke is a stroke layer; change it with vector.setBrushstroke, remove it with vector.removeStroke).",
16299
16325
  params: {
16300
16326
  type: "object",
16301
16327
  properties: {
@@ -16305,7 +16331,9 @@ function createVectorCommands(controller, options = {}) {
16305
16331
  pressure: { type: "array", items: { type: "number", minimum: 0, maximum: 1 }, minItems: 1, maxItems: 64, description: "Pressure 0\u20131 along the length, spread evenly from start to end (default: full pressure)." },
16306
16332
  color: { type: "string", description: "CSS colour (default: the path's stroke colour, else black)." },
16307
16333
  opacity: { type: "number", minimum: 0, maximum: 1, description: "Layer opacity 0\u20131 (default 1)." },
16308
- index: { type: "integer", minimum: 0, description: "Position in the stroke stack, 0 the bottom (default: on top)." }
16334
+ index: { type: "integer", minimum: 0, description: "Position in the stroke stack, 0 the bottom (default: on top)." },
16335
+ seed: { ...BRUSH_SEED, description: "Character seed 0\u20132147483647: turns on the brush's jitter and paper grain; the same seed always renders the same stroke (default: none, plain dabs)." },
16336
+ paper: { anyOf: [BRUSH_PAPER, { type: "null" }], description: "With `seed`: the paper the grain comes from { pattern, seed, scale, depth }, or null for jitter without grain (default: the sanded paper)." }
16309
16337
  },
16310
16338
  required: ["brushId"],
16311
16339
  additionalProperties: false
@@ -16316,7 +16344,13 @@ function createVectorCommands(controller, options = {}) {
16316
16344
  const targets = params.ids ?? controller.getState().selection;
16317
16345
  check2(
16318
16346
  controller.addBrushstroke(
16319
- { brushId: params.brushId, ...params.size !== void 0 ? { size: params.size } : {}, ...params.pressure ? { pressure: params.pressure } : {} },
16347
+ {
16348
+ brushId: params.brushId,
16349
+ ...params.size !== void 0 ? { size: params.size } : {},
16350
+ ...params.pressure ? { pressure: params.pressure } : {},
16351
+ ...params.seed !== void 0 ? { seed: params.seed } : {},
16352
+ ...params.paper !== void 0 ? { paper: params.paper } : {}
16353
+ },
16320
16354
  { ...params.ids ? { ids: params.ids } : {}, ...params.index !== void 0 ? { index: params.index } : {}, ...params.color ? { color: params.color } : {}, ...params.opacity !== void 0 ? { opacity: params.opacity } : {} }
16321
16355
  )
16322
16356
  );
@@ -16333,7 +16367,7 @@ function createVectorCommands(controller, options = {}) {
16333
16367
  id: `${prefix}setBrushstroke`,
16334
16368
  label: "Edit Brushstroke\u2026",
16335
16369
  keywords: ["brushstroke", "brush", "size", "pressure", "taper"],
16336
- description: "Changes the brushstroke at stroke layer `index` of path `id` (vector.getAppearance lists strokes; 0 is the bottom): `brushId`, `size` (null: the brush's own), `pressure` (null: full pressure), `color`, `opacity`. Pass at least one. One undo step. Returns { id, strokes }.",
16370
+ description: "Changes the brushstroke at stroke layer `index` of path `id` (vector.getAppearance lists strokes; 0 is the bottom): `brushId`, `size` (null: the brush's own), `pressure` (null: full pressure), `color`, `opacity`, `seed` (turns the brush's character on; null: plain dabs) and `paper` (replaced whole; null: no grain; {}: the default paper). Pass at least one. One undo step. Returns { id, strokes }.",
16337
16371
  params: {
16338
16372
  type: "object",
16339
16373
  properties: {
@@ -16343,7 +16377,9 @@ function createVectorCommands(controller, options = {}) {
16343
16377
  size: { type: ["number", "null"], description: "Diameter in document units, or null for the brush's own." },
16344
16378
  pressure: { type: ["array", "null"], items: { type: "number", minimum: 0, maximum: 1 }, description: "Pressure profile 0\u20131 from start to end, or null for full pressure." },
16345
16379
  color: { type: "string", description: "CSS colour." },
16346
- opacity: { type: "number", minimum: 0, maximum: 1, description: "Layer opacity 0\u20131." }
16380
+ opacity: { type: "number", minimum: 0, maximum: 1, description: "Layer opacity 0\u20131." },
16381
+ seed: { anyOf: [BRUSH_SEED, { type: "null" }], description: "Character seed 0\u20132147483647 (jitter and paper grain; a new seed gives a new take on the same stroke), or null for plain dabs." },
16382
+ paper: { anyOf: [BRUSH_PAPER, { type: "null" }], description: "The paper the grain comes from { pattern, seed, scale, depth } (applies with a seed), null for no grain, or {} for the default sanded paper." }
16347
16383
  },
16348
16384
  required: ["id", "index"],
16349
16385
  additionalProperties: false
@@ -16351,7 +16387,7 @@ function createVectorCommands(controller, options = {}) {
16351
16387
  undoable: true,
16352
16388
  run: (_ctx, params) => {
16353
16389
  const { id, index, ...patch } = params;
16354
- if (!Object.keys(patch).length) fail("Pass at least one of brushId, size, pressure, color, opacity.");
16390
+ if (!Object.keys(patch).length) fail("Pass at least one of brushId, size, pressure, color, opacity, seed, paper.");
16355
16391
  layerIndex(id, "stroke", index);
16356
16392
  check2(controller.setBrushstroke(index, patch, { ids: [id] }));
16357
16393
  return stackResult(id, "stroke");
@@ -18571,6 +18607,7 @@ export {
18571
18607
  VECTOR_BLEND_MODE_MENU,
18572
18608
  VECTOR_BLEND_SPACINGS,
18573
18609
  VECTOR_BLEND_SPACING_LABELS,
18610
+ VECTOR_BRUSHSTROKE_MAX_SEED,
18574
18611
  VECTOR_BRUSHSTROKE_SCALE,
18575
18612
  VECTOR_BUILDER_HATCH_GAP,
18576
18613
  VECTOR_CHARACTER_STYLE_KEYS,
@@ -18907,6 +18944,7 @@ export {
18907
18944
  pullWarpMesh as pullVectorMesh,
18908
18945
  purgeVectorConstraints,
18909
18946
  quantizeVectorTraceColors,
18947
+ randomVectorBrushstrokeSeed,
18910
18948
  recognizeInkShape,
18911
18949
  rectSubpath,
18912
18950
  refineMorphContour,
@@ -18946,6 +18984,7 @@ export {
18946
18984
  sampleVectorGradientAt,
18947
18985
  sampleVectorPaintDefAt,
18948
18986
  sanitizeVectorBrushstroke,
18987
+ sanitizeVectorBrushstrokePaper,
18949
18988
  sanitizeVectorConnector,
18950
18989
  sanitizeVectorEffects,
18951
18990
  sanitizeVectorFills,
@@ -19041,6 +19080,7 @@ export {
19041
19080
  vectorBoxMatrix,
19042
19081
  vectorBrushstrokeBrush,
19043
19082
  vectorBrushstrokeBrushes,
19083
+ vectorBrushstrokeCharacterError,
19044
19084
  vectorBrushstrokeImages,
19045
19085
  vectorBrushstrokeReach,
19046
19086
  vectorBuilderErasedEdges,