@pixerate/editor 0.266.1 → 0.267.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 (117) hide show
  1. package/dist/agent/index.cjs +8 -4
  2. package/dist/agent/index.js +6 -2
  3. package/dist/animation-editor/controller.d.cts +8 -0
  4. package/dist/animation-editor/controller.d.ts +8 -0
  5. package/dist/animation-editor/effect-tools.d.cts +1 -1
  6. package/dist/animation-editor/effect-tools.d.ts +1 -1
  7. package/dist/animation-editor/index.cjs +172 -105
  8. package/dist/animation-editor/index.js +91 -24
  9. package/dist/brushes/index.cjs +59 -59
  10. package/dist/brushes/index.js +5 -5
  11. package/dist/brushes/profiles.d.cts +6 -1
  12. package/dist/brushes/profiles.d.ts +6 -1
  13. package/dist/{brushstrokeRender-FSUWXUZY.cjs → brushstrokeRender-L7JYRR2R.cjs} +16 -16
  14. package/dist/{brushstrokeRender-KD453OBX.js → brushstrokeRender-NLFPEBGI.js} +4 -4
  15. package/dist/canvas/brushTypes.d.cts +12 -0
  16. package/dist/canvas/brushTypes.d.ts +12 -0
  17. package/dist/canvas/brushstroke.d.cts +1 -1
  18. package/dist/canvas/brushstroke.d.ts +1 -1
  19. package/dist/canvas/drawController.d.cts +19 -4
  20. package/dist/canvas/drawController.d.ts +19 -4
  21. package/dist/canvas/index.cjs +144 -105
  22. package/dist/canvas/index.js +46 -7
  23. package/dist/{chunk-XORJ7UZO.cjs → chunk-3VHH6V67.cjs} +13 -12
  24. package/dist/{chunk-T2LDTEXK.js → chunk-4IDUYB45.js} +2217 -56
  25. package/dist/chunk-7UKFXXWL.js +802 -0
  26. package/dist/chunk-ADMRNWR7.js +340 -0
  27. package/dist/{chunk-CIJBSUM5.js → chunk-AGNUD5BI.js} +2 -2
  28. package/dist/{chunk-WLUVZKVD.cjs → chunk-DT4YQUGT.cjs} +32 -32
  29. package/dist/{chunk-DXYHQ2VN.js → chunk-EF7LZAXQ.js} +1 -1
  30. package/dist/chunk-EXB2EGBE.cjs +802 -0
  31. package/dist/{chunk-4ODRXQRW.js → chunk-EYSHTYLG.js} +1 -1
  32. package/dist/{chunk-R44Y3EFS.js → chunk-FGJHJIMN.js} +8 -336
  33. package/dist/{chunk-AQZQWXEU.cjs → chunk-G7NHE2VD.cjs} +35 -35
  34. package/dist/{chunk-XC6DPRYI.js → chunk-GSTSZPSR.js} +154 -949
  35. package/dist/{chunk-VRK322ZC.cjs → chunk-HIO6E7LC.cjs} +2 -2
  36. package/dist/{chunk-TOID45I2.cjs → chunk-J2TNIZ55.cjs} +1 -1
  37. package/dist/{chunk-YHDHFJUC.cjs → chunk-J5VQYK7T.cjs} +217 -1012
  38. package/dist/{chunk-3C33YTNN.js → chunk-JGWVZPT6.js} +2 -2
  39. package/dist/{chunk-ACFSFUQH.js → chunk-JL6YH5WD.js} +4 -0
  40. package/dist/{chunk-3SBLVGOM.cjs → chunk-LA5Y4ETA.cjs} +23 -23
  41. package/dist/{chunk-MVUQSK5J.cjs → chunk-LHPEG5AU.cjs} +107 -435
  42. package/dist/{chunk-DOZ6F2K2.js → chunk-NSETJI74.js} +3 -2
  43. package/dist/{chunk-XRXFVRGY.cjs → chunk-OKHKA43L.cjs} +2364 -203
  44. package/dist/{chunk-LK4SXL3V.js → chunk-OSEXT7JL.js} +1 -1
  45. package/dist/{chunk-PE6YJMQT.cjs → chunk-PFHJS4HE.cjs} +20 -19
  46. package/dist/{chunk-ZQI3WUPP.js → chunk-QCLY5SFS.js} +12 -0
  47. package/dist/{chunk-7KNW3WXZ.cjs → chunk-QEVLRLUN.cjs} +63 -0
  48. package/dist/{chunk-OTN6VB5S.cjs → chunk-RDFHWAHL.cjs} +5 -1
  49. package/dist/{chunk-6JL2D5SG.js → chunk-VE6UKYQ2.js} +3 -2
  50. package/dist/{chunk-RFJZGTHA.cjs → chunk-XVOP3CGQ.cjs} +9 -9
  51. package/dist/{chunk-EZOJBP4D.js → chunk-YIC6MAJ2.js} +1 -1
  52. package/dist/chunk-YZWM6ZIP.cjs +340 -0
  53. package/dist/{chunk-472INMWH.js → chunk-ZA7L5YJB.js} +63 -0
  54. package/dist/{chunk-YBC3RKT2.cjs → chunk-ZGXJ7BTR.cjs} +13 -1
  55. package/dist/commands/builtins.d.cts +12 -1
  56. package/dist/commands/builtins.d.ts +12 -1
  57. package/dist/commands/index.cjs +2 -2
  58. package/dist/commands/index.js +1 -1
  59. package/dist/image-editor/controller.d.cts +1 -1
  60. package/dist/image-editor/controller.d.ts +1 -1
  61. package/dist/image-editor/index.cjs +837 -833
  62. package/dist/image-editor/index.js +105 -101
  63. package/dist/paint/index.cjs +5 -3
  64. package/dist/paint/index.js +46 -44
  65. package/dist/paint-editor/controller.d.cts +5 -3
  66. package/dist/paint-editor/controller.d.ts +5 -3
  67. package/dist/paint-editor/index.cjs +832 -2295
  68. package/dist/paint-editor/index.js +285 -1748
  69. package/dist/paint-editor/path-samples.d.cts +2 -0
  70. package/dist/paint-editor/path-samples.d.ts +2 -0
  71. package/dist/paint-editor/presence.d.cts +20 -1
  72. package/dist/paint-editor/presence.d.ts +20 -1
  73. package/dist/stickers/helpers.d.cts +2 -0
  74. package/dist/stickers/helpers.d.ts +2 -0
  75. package/dist/stickers/index.cjs +41 -35
  76. package/dist/stickers/index.js +22 -16
  77. package/dist/stickers/types.d.cts +4 -2
  78. package/dist/stickers/types.d.ts +4 -2
  79. package/dist/tools/conformance.d.cts +8 -0
  80. package/dist/tools/conformance.d.ts +8 -0
  81. package/dist/tools/index.cjs +6 -2
  82. package/dist/tools/index.js +5 -1
  83. package/dist/vector/backdrop.d.cts +13 -0
  84. package/dist/vector/backdrop.d.ts +13 -0
  85. package/dist/vector/brushstroke.d.cts +54 -7
  86. package/dist/vector/brushstroke.d.ts +54 -7
  87. package/dist/vector/brushstrokeMedia.d.cts +96 -0
  88. package/dist/vector/brushstrokeMedia.d.ts +96 -0
  89. package/dist/vector/controller.d.cts +17 -3
  90. package/dist/vector/controller.d.ts +17 -3
  91. package/dist/vector/index.cjs +1846 -1386
  92. package/dist/vector/index.d.cts +2 -0
  93. package/dist/vector/index.d.ts +2 -0
  94. package/dist/vector/index.js +517 -57
  95. package/dist/vector/render.d.cts +6 -0
  96. package/dist/vector/render.d.ts +6 -0
  97. package/dist/vector/types.d.cts +14 -0
  98. package/dist/vector/types.d.ts +14 -0
  99. package/package.json +1 -1
  100. package/skills/pixerate-animation-editor/SKILL.md +1 -0
  101. package/skills/pixerate-brushes/SKILL.md +2 -2
  102. package/skills/pixerate-brushes-design/SKILL.md +7 -4
  103. package/skills/pixerate-brushes-design/evals/port-to-vector.json +8 -8
  104. package/skills/pixerate-canvas/SKILL.md +11 -1
  105. package/skills/pixerate-image-editor/SKILL.md +19 -64
  106. package/skills/pixerate-image-editor/references/color-management.md +2 -1
  107. package/skills/pixerate-image-editor/references/free-transform.md +12 -0
  108. package/skills/pixerate-image-editor/references/layer-effects.md +10 -0
  109. package/skills/pixerate-image-editor/references/painting.md +17 -0
  110. package/skills/pixerate-image-editor/references/photoshop-files.md +1 -1
  111. package/skills/pixerate-image-editor/references/shapes-and-type.md +14 -0
  112. package/skills/pixerate-image-editor/references/smart-objects.md +10 -0
  113. package/skills/pixerate-paint-editor/SKILL.md +8 -4
  114. package/skills/pixerate-paint-editor/references/wet-media.md +9 -0
  115. package/skills/pixerate-vector/SKILL.md +16 -6
  116. package/skills/pixerate-vector/references/best-practices.md +1 -0
  117. package/skills/pixerate-vector/references/commands.md +19 -0
@@ -1,8 +1,10 @@
1
1
  import {
2
2
  CONFORMANCE_BINARY_MIN_LENGTH,
3
+ CONFORMANCE_NUMBER_TOLERANCE,
3
4
  ConformanceIds,
4
5
  callEvalTool,
5
6
  conformanceResult,
7
+ conformanceValuesMatch,
6
8
  createOriginMiddleware,
7
9
  createStyleResolver,
8
10
  createStyleToolProvider,
@@ -21,7 +23,7 @@ import {
21
23
  runToolScript,
22
24
  toolResultError,
23
25
  toolResultValue
24
- } from "../chunk-ZQI3WUPP.js";
26
+ } from "../chunk-QCLY5SFS.js";
25
27
  import {
26
28
  JSON_RPC_ERRORS,
27
29
  MCP_PROTOCOL_VERSIONS,
@@ -121,6 +123,7 @@ export {
121
123
  CAPTURE_EXCLUDE_SELECTOR,
122
124
  CAPTURE_OVERLAY_SELECTORS,
123
125
  CONFORMANCE_BINARY_MIN_LENGTH,
126
+ CONFORMANCE_NUMBER_TOLERANCE,
124
127
  ConformanceIds,
125
128
  EDITOR_CANVAS_TOOLS,
126
129
  EDITOR_MCP_TOOLS,
@@ -161,6 +164,7 @@ export {
161
164
  captureOutputSize,
162
165
  cloneElementWithStyles,
163
166
  conformanceResult,
167
+ conformanceValuesMatch,
164
168
  connectToolBridge,
165
169
  createAgentPlayback,
166
170
  createCaptureTool,
@@ -0,0 +1,13 @@
1
+ import type { RasterRect } from '../raster/surface.cjs';
2
+ import { type VectorPaintDef } from './gradient.cjs';
3
+ import type { VectorRenderNode } from './render.cjs';
4
+ import type { VectorMatrix } from './types.cjs';
5
+ type M = VectorMatrix;
6
+ /** An SVG `transform` attribute (`matrix`, `translate`, `scale`, `rotate`, in order) as a matrix. */
7
+ export declare function parseVectorTransform(value: string | undefined): M;
8
+ /**
9
+ * The render data's `nodes` (document space) drawn over `rect` (pixels) through `toPixels`, the
10
+ * map from document space to those pixels: straight-alpha RGBA, `rect.width × rect.height`.
11
+ */
12
+ export declare function rasterizeVectorBackdrop(nodes: readonly VectorRenderNode[], defs: readonly VectorPaintDef[], toPixels: VectorMatrix, rect: RasterRect): Uint8ClampedArray;
13
+ export {};
@@ -0,0 +1,13 @@
1
+ import type { RasterRect } from '../raster/surface.js';
2
+ import { type VectorPaintDef } from './gradient.js';
3
+ import type { VectorRenderNode } from './render.js';
4
+ import type { VectorMatrix } from './types.js';
5
+ type M = VectorMatrix;
6
+ /** An SVG `transform` attribute (`matrix`, `translate`, `scale`, `rotate`, in order) as a matrix. */
7
+ export declare function parseVectorTransform(value: string | undefined): M;
8
+ /**
9
+ * The render data's `nodes` (document space) drawn over `rect` (pixels) through `toPixels`, the
10
+ * map from document space to those pixels: straight-alpha RGBA, `rect.width × rect.height`.
11
+ */
12
+ export declare function rasterizeVectorBackdrop(nodes: readonly VectorRenderNode[], defs: readonly VectorPaintDef[], toPixels: VectorMatrix, rect: RasterRect): Uint8ClampedArray;
13
+ export {};
@@ -1,11 +1,14 @@
1
1
  import { type PaintBrush } from '../paint-editor/brushes.cjs';
2
2
  import type { Brush } from '../brushes/types.cjs';
3
- import type { VectorBrushstroke, VectorBrushstrokePaper, VectorPathNode, VectorStrokeLayer } from './types.cjs';
3
+ import { type VectorBrushstrokeBackdrop } from './brushstrokeMedia.cjs';
4
+ import type { VectorBrushstroke, VectorBrushstrokePaint, VectorBrushstrokePaper, VectorDocument, VectorPathNode, VectorStrokeLayer } from './types.cjs';
4
5
  /** Image pixels per document unit brushstrokes are rendered at. */
5
6
  export declare const VECTOR_BRUSHSTROKE_SCALE = 2;
7
+ /** Whether a brush's engine paints vector brushstrokes: dry dab brushes, wet paint, the Mixer Brush, smudge and blender. */
8
+ export declare function isVectorBrushstrokeEngine(brush: PaintBrush): boolean;
6
9
  /**
7
10
  * The brushes a brushstroke can use, as the engine paints them: the presets `VECTOR_PROFILE`
8
- * admits (dry dab-engine brushes), then the saved brushes given (facet brushes, e.g. a brush
11
+ * admits (dry, wet paint, mixer, smudge and blender brushes), then the saved brushes given (facet brushes, e.g. a brush
9
12
  * library's) it admits.
10
13
  */
11
14
  export declare function vectorBrushstrokeBrushes(user?: readonly Brush[]): PaintBrush[];
@@ -30,6 +33,15 @@ export declare function vectorBrushstrokeDefaultColour(id: string, user?: readon
30
33
  * kept in `spec`.
31
34
  */
32
35
  export declare function sanitizeVectorBrushstroke(value: unknown, user?: readonly Brush[]): VectorBrushstroke | null;
36
+ /**
37
+ * What is wrong with a brushstroke's gradient `paint` (from an agent or a caller), or null when it
38
+ * is valid. Paint is `{ type: 'color', color }` or `{ type: 'gradient', stops, space, map, softness }`
39
+ * (the paint engine's `PaintSource`, lengths in document units). `velocity` and `time` mappings
40
+ * are refused: a vector path has no timing.
41
+ */
42
+ export declare function vectorBrushstrokePaintError(paint: unknown): string | null;
43
+ /** Reads brushstroke paint from untrusted data (a stored layer); null when it is not valid paint. */
44
+ export declare function readVectorBrushstrokePaint(value: unknown): VectorBrushstrokePaint | null;
33
45
  /** The largest brushstroke seed. */
34
46
  export declare const VECTOR_BRUSHSTROKE_MAX_SEED = 2147483647;
35
47
  /** Reads paper settings from untrusted data; null when there are none (the default paper). */
@@ -59,10 +71,45 @@ export interface VectorBrushstrokeImage {
59
71
  width: number;
60
72
  height: number;
61
73
  }
74
+ /** Where and how a brushstroke renders. */
75
+ export interface VectorBrushstrokeContext {
76
+ /**
77
+ * The document the path is in. A Mixer Brush, smudge or blender acts on what lies beneath the
78
+ * stroke there; without it, only on the path's own fills and lower strokes.
79
+ */
80
+ document?: VectorDocument | null;
81
+ /**
82
+ * `async` (default): a wet brushstroke shows the paint as laid until its simulation has settled
83
+ * (`onVectorBrushstrokesSettled` says when). `now`: settle it first (exports, agents).
84
+ */
85
+ settle?: 'async' | 'now';
86
+ }
87
+ /**
88
+ * What lies beneath stroke layer `index` of `node`: the objects it depends on (compared by
89
+ * identity: any change beneath gives a new one), and the backdrop renderer. The scene renderer
90
+ * registers it (`setVectorBackdropSource`), as it is the one that can draw the scene.
91
+ */
92
+ export type VectorBackdropSource = (document: VectorDocument | null, node: VectorPathNode, index: number, settle: 'async' | 'now') => {
93
+ deps: readonly unknown[];
94
+ backdrop: VectorBrushstrokeBackdrop;
95
+ };
96
+ /** Registers what draws the backdrop of mixer, smudge and blender brushstrokes (done by `render.ts`). */
97
+ export declare function setVectorBackdropSource(source: VectorBackdropSource | null): void;
98
+ /**
99
+ * Calls `listener` whenever a wet brushstroke has settled, so its final image replaces the one
100
+ * shown while it settled. Re-render the scene then (the controller does: it notifies its
101
+ * subscribers). Returns the unsubscribe function.
102
+ */
103
+ export declare function onVectorBrushstrokesSettled(listener: () => void): () => void;
104
+ /** How many wet brushstrokes are still settling. */
105
+ export declare function vectorBrushstrokesSettling(): number;
106
+ /** Settles every wet brushstroke still settling, now (slow for many long strokes). Returns how many there were. */
107
+ export declare function settleVectorBrushstrokes(): number;
62
108
  /**
63
- * The images of a brushstroke layer on a path, one per subpath, in the path's own space (cached
64
- * per path and layer object, and by the shared renderer's cache, whose key includes the seed and
65
- * paper). A layer with a seed renders with the brush's character, the grain laid in the path's
66
- * own space (paper point = path point).
109
+ * The images of a brushstroke layer on a path, one per subpath, in the path's own space. Cached
110
+ * per path and layer object, by the shared renderer's cache (whose key includes the seed and
111
+ * paper), and for mixer, smudge and blender strokes by what lies beneath them. A layer with a
112
+ * seed renders with the brush's character, the grain laid in the path's own space (paper point =
113
+ * path point). See `VectorBrushstrokeContext` for wet strokes and backdrops.
67
114
  */
68
- export declare function vectorBrushstrokeImages(node: VectorPathNode, layer: VectorStrokeLayer): VectorBrushstrokeImage[];
115
+ export declare function vectorBrushstrokeImages(node: VectorPathNode, layer: VectorStrokeLayer, context?: VectorBrushstrokeContext): VectorBrushstrokeImage[];
@@ -1,11 +1,14 @@
1
1
  import { type PaintBrush } from '../paint-editor/brushes.js';
2
2
  import type { Brush } from '../brushes/types.js';
3
- import type { VectorBrushstroke, VectorBrushstrokePaper, VectorPathNode, VectorStrokeLayer } from './types.js';
3
+ import { type VectorBrushstrokeBackdrop } from './brushstrokeMedia.js';
4
+ import type { VectorBrushstroke, VectorBrushstrokePaint, VectorBrushstrokePaper, VectorDocument, VectorPathNode, VectorStrokeLayer } from './types.js';
4
5
  /** Image pixels per document unit brushstrokes are rendered at. */
5
6
  export declare const VECTOR_BRUSHSTROKE_SCALE = 2;
7
+ /** Whether a brush's engine paints vector brushstrokes: dry dab brushes, wet paint, the Mixer Brush, smudge and blender. */
8
+ export declare function isVectorBrushstrokeEngine(brush: PaintBrush): boolean;
6
9
  /**
7
10
  * The brushes a brushstroke can use, as the engine paints them: the presets `VECTOR_PROFILE`
8
- * admits (dry dab-engine brushes), then the saved brushes given (facet brushes, e.g. a brush
11
+ * admits (dry, wet paint, mixer, smudge and blender brushes), then the saved brushes given (facet brushes, e.g. a brush
9
12
  * library's) it admits.
10
13
  */
11
14
  export declare function vectorBrushstrokeBrushes(user?: readonly Brush[]): PaintBrush[];
@@ -30,6 +33,15 @@ export declare function vectorBrushstrokeDefaultColour(id: string, user?: readon
30
33
  * kept in `spec`.
31
34
  */
32
35
  export declare function sanitizeVectorBrushstroke(value: unknown, user?: readonly Brush[]): VectorBrushstroke | null;
36
+ /**
37
+ * What is wrong with a brushstroke's gradient `paint` (from an agent or a caller), or null when it
38
+ * is valid. Paint is `{ type: 'color', color }` or `{ type: 'gradient', stops, space, map, softness }`
39
+ * (the paint engine's `PaintSource`, lengths in document units). `velocity` and `time` mappings
40
+ * are refused: a vector path has no timing.
41
+ */
42
+ export declare function vectorBrushstrokePaintError(paint: unknown): string | null;
43
+ /** Reads brushstroke paint from untrusted data (a stored layer); null when it is not valid paint. */
44
+ export declare function readVectorBrushstrokePaint(value: unknown): VectorBrushstrokePaint | null;
33
45
  /** The largest brushstroke seed. */
34
46
  export declare const VECTOR_BRUSHSTROKE_MAX_SEED = 2147483647;
35
47
  /** Reads paper settings from untrusted data; null when there are none (the default paper). */
@@ -59,10 +71,45 @@ export interface VectorBrushstrokeImage {
59
71
  width: number;
60
72
  height: number;
61
73
  }
74
+ /** Where and how a brushstroke renders. */
75
+ export interface VectorBrushstrokeContext {
76
+ /**
77
+ * The document the path is in. A Mixer Brush, smudge or blender acts on what lies beneath the
78
+ * stroke there; without it, only on the path's own fills and lower strokes.
79
+ */
80
+ document?: VectorDocument | null;
81
+ /**
82
+ * `async` (default): a wet brushstroke shows the paint as laid until its simulation has settled
83
+ * (`onVectorBrushstrokesSettled` says when). `now`: settle it first (exports, agents).
84
+ */
85
+ settle?: 'async' | 'now';
86
+ }
87
+ /**
88
+ * What lies beneath stroke layer `index` of `node`: the objects it depends on (compared by
89
+ * identity: any change beneath gives a new one), and the backdrop renderer. The scene renderer
90
+ * registers it (`setVectorBackdropSource`), as it is the one that can draw the scene.
91
+ */
92
+ export type VectorBackdropSource = (document: VectorDocument | null, node: VectorPathNode, index: number, settle: 'async' | 'now') => {
93
+ deps: readonly unknown[];
94
+ backdrop: VectorBrushstrokeBackdrop;
95
+ };
96
+ /** Registers what draws the backdrop of mixer, smudge and blender brushstrokes (done by `render.ts`). */
97
+ export declare function setVectorBackdropSource(source: VectorBackdropSource | null): void;
98
+ /**
99
+ * Calls `listener` whenever a wet brushstroke has settled, so its final image replaces the one
100
+ * shown while it settled. Re-render the scene then (the controller does: it notifies its
101
+ * subscribers). Returns the unsubscribe function.
102
+ */
103
+ export declare function onVectorBrushstrokesSettled(listener: () => void): () => void;
104
+ /** How many wet brushstrokes are still settling. */
105
+ export declare function vectorBrushstrokesSettling(): number;
106
+ /** Settles every wet brushstroke still settling, now (slow for many long strokes). Returns how many there were. */
107
+ export declare function settleVectorBrushstrokes(): number;
62
108
  /**
63
- * The images of a brushstroke layer on a path, one per subpath, in the path's own space (cached
64
- * per path and layer object, and by the shared renderer's cache, whose key includes the seed and
65
- * paper). A layer with a seed renders with the brush's character, the grain laid in the path's
66
- * own space (paper point = path point).
109
+ * The images of a brushstroke layer on a path, one per subpath, in the path's own space. Cached
110
+ * per path and layer object, by the shared renderer's cache (whose key includes the seed and
111
+ * paper), and for mixer, smudge and blender strokes by what lies beneath them. A layer with a
112
+ * seed renders with the brush's character, the grain laid in the path's own space (paper point =
113
+ * path point). See `VectorBrushstrokeContext` for wet strokes and backdrops.
67
114
  */
68
- export declare function vectorBrushstrokeImages(node: VectorPathNode, layer: VectorStrokeLayer): VectorBrushstrokeImage[];
115
+ export declare function vectorBrushstrokeImages(node: VectorPathNode, layer: VectorStrokeLayer, context?: VectorBrushstrokeContext): VectorBrushstrokeImage[];
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Brushstrokes on vector paths with media that need more than an empty image (#519): wet paint, and
3
+ * the Mixer Brush, smudge and blender, which act on the paint under them. The path stays the data
4
+ * and the pixels a cache, as for dry brushstrokes (`renderBrushstroke`).
5
+ *
6
+ * - **Wet** (`engine: 'wet'`, wet paint brushes: watercolour, gouache, wet oils): the stroke gets its
7
+ * own small `WetWorld` over its bounds, the paint editor's `WetStrokeDriver` lays it, the
8
+ * simulation runs `VECTOR_WET_STEPS` steps (time is counted in steps, never wall time) and the
9
+ * paint is dried where it is. The bytes depend only on the path, brush, colour and seed. The
10
+ * simulation costs about 9 ms per 256 px tile per step on the TypeScript kernel, so
11
+ * `WetBrushstrokeJob` can run it in slices: hosts show the bake of the paint as laid (step 0) at
12
+ * once, and swap in the settled image when it is done.
13
+ * - **Backdrop media** (`mixer`, `smudge`, `blender`): the stroke runs the paint editor's dab-by-dab
14
+ * engine (`PaintDabStroke`) over a local copy of what lies beneath it (the backdrop, rendered by
15
+ * the caller), and keeps only the pixels it changed. Drawn over the content it was made from,
16
+ * that is the stroke's result. A smudge can drag paint over bare paper, but it can't take paint
17
+ * away from the content underneath (the image is drawn over it).
18
+ *
19
+ * Coordinates: like `renderBrushstroke`, inputs are in path units, rendered at `scale` image pixels
20
+ * per unit, and the result's `bounds` place the image back in path units.
21
+ */
22
+ import { type BrushstrokeImage, type BrushstrokeInput } from '../paint/brushstroke.cjs';
23
+ import { type PaintSource } from '../paint/gradient-paint.cjs';
24
+ import type { PaintBrush } from '../paint-editor/brushes.cjs';
25
+ import { type RasterRect } from '../raster/surface.cjs';
26
+ /** Simulation steps a wet brushstroke runs before it is dried (enough to bleed, bloom and granulate). */
27
+ export declare const VECTOR_WET_STEPS = 120;
28
+ /** Engines a vector brushstroke paints through this module. */
29
+ export type VectorMediaEngine = 'wet' | 'mixer' | 'smudge' | 'blender';
30
+ /** Whether a brush paints through this module (and which way), or null for a dry dab brush. */
31
+ export declare function vectorMediaEngine(brush: Pick<PaintBrush, 'engine' | 'wet'>): VectorMediaEngine | null;
32
+ /** Whether a media engine acts on the paint beneath the stroke (and needs a backdrop). */
33
+ export declare const usesVectorBackdrop: (engine: VectorMediaEngine | null) => boolean;
34
+ export interface VectorMediaOptions {
35
+ /** Image pixels per path unit (default 1). */
36
+ scale?: number;
37
+ /** RGBA 0..255 of the paint (the alpha scales the result). */
38
+ color: readonly [number, number, number, number];
39
+ /** Gradient paint sampled dab by dab (lengths in path units), or null for `color`. */
40
+ paint?: PaintSource | null;
41
+ /** Jitter seed (default 0). */
42
+ seed?: number;
43
+ closed?: boolean;
44
+ /** The largest image to render, in pixels (default 4096²); a bigger stroke renders at a lower scale. */
45
+ maxPixels?: number;
46
+ }
47
+ /**
48
+ * One wet brushstroke's simulation: the paint is laid when the job is made; `run` advances it
49
+ * (within a time budget, for hosts that slice the work), `image` bakes it as it is now and
50
+ * `settled` once all `VECTOR_WET_STEPS` steps have run. Call `destroy` when done with it.
51
+ */
52
+ export declare class WetBrushstrokeJob {
53
+ readonly steps: number;
54
+ private readonly world;
55
+ private readonly placed;
56
+ private readonly dabs;
57
+ private done;
58
+ private final;
59
+ constructor(input: BrushstrokeInput, brush: PaintBrush, options: VectorMediaOptions, steps?: number);
60
+ /** Steps run so far. */
61
+ get progress(): number;
62
+ get finished(): boolean;
63
+ /** Runs steps until `budgetMs` has passed (at least one) or all have run. Returns whether it is finished. */
64
+ run(budgetMs?: number): boolean;
65
+ /** The paint dried where it is now (step 0: as laid). */
66
+ image(): BrushstrokeImage;
67
+ /** The settled image: runs the remaining steps now. */
68
+ settled(): BrushstrokeImage;
69
+ destroy(): void;
70
+ private bake;
71
+ }
72
+ /** A wet brushstroke rendered and settled at once (`VECTOR_WET_STEPS` steps; slow for long strokes). */
73
+ export declare function renderWetBrushstroke(input: BrushstrokeInput, brush: PaintBrush, options: VectorMediaOptions): BrushstrokeImage;
74
+ /**
75
+ * What lies beneath a stroke: straight-alpha RGBA of `rect` (image pixels at the stroke's scale,
76
+ * path units × scale), row by row. Called once per render.
77
+ */
78
+ export type VectorBrushstrokeBackdrop = (rect: RasterRect, scale: number) => Uint8ClampedArray;
79
+ /** The image pixels a backdrop brushstroke reads, in path units × the scale it renders at (for callers that render backdrops). */
80
+ export declare function vectorBackdropRect(input: BrushstrokeInput, brush: PaintBrush, options: VectorMediaOptions): {
81
+ rect: RasterRect;
82
+ scale: number;
83
+ } | null;
84
+ /**
85
+ * A Mixer Brush, smudge or blender stroke over `backdrop`: the pixels it changed (the rest are
86
+ * transparent). Without a backdrop it acts on bare paper: a Mixer Brush still paints from its
87
+ * reservoir; a smudge or blender changes nothing.
88
+ */
89
+ export declare function renderBackdropBrushstroke(input: BrushstrokeInput, brush: PaintBrush, options: VectorMediaOptions & {
90
+ backdrop?: VectorBrushstrokeBackdrop | null;
91
+ /** A cache for the result, given the backdrop's bytes (the result depends only on them and the stroke). */
92
+ cache?: (backdrop: Uint8ClampedArray) => {
93
+ get(): BrushstrokeImage | undefined;
94
+ set(image: BrushstrokeImage): void;
95
+ };
96
+ }): BrushstrokeImage;
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Brushstrokes on vector paths with media that need more than an empty image (#519): wet paint, and
3
+ * the Mixer Brush, smudge and blender, which act on the paint under them. The path stays the data
4
+ * and the pixels a cache, as for dry brushstrokes (`renderBrushstroke`).
5
+ *
6
+ * - **Wet** (`engine: 'wet'`, wet paint brushes: watercolour, gouache, wet oils): the stroke gets its
7
+ * own small `WetWorld` over its bounds, the paint editor's `WetStrokeDriver` lays it, the
8
+ * simulation runs `VECTOR_WET_STEPS` steps (time is counted in steps, never wall time) and the
9
+ * paint is dried where it is. The bytes depend only on the path, brush, colour and seed. The
10
+ * simulation costs about 9 ms per 256 px tile per step on the TypeScript kernel, so
11
+ * `WetBrushstrokeJob` can run it in slices: hosts show the bake of the paint as laid (step 0) at
12
+ * once, and swap in the settled image when it is done.
13
+ * - **Backdrop media** (`mixer`, `smudge`, `blender`): the stroke runs the paint editor's dab-by-dab
14
+ * engine (`PaintDabStroke`) over a local copy of what lies beneath it (the backdrop, rendered by
15
+ * the caller), and keeps only the pixels it changed. Drawn over the content it was made from,
16
+ * that is the stroke's result. A smudge can drag paint over bare paper, but it can't take paint
17
+ * away from the content underneath (the image is drawn over it).
18
+ *
19
+ * Coordinates: like `renderBrushstroke`, inputs are in path units, rendered at `scale` image pixels
20
+ * per unit, and the result's `bounds` place the image back in path units.
21
+ */
22
+ import { type BrushstrokeImage, type BrushstrokeInput } from '../paint/brushstroke.js';
23
+ import { type PaintSource } from '../paint/gradient-paint.js';
24
+ import type { PaintBrush } from '../paint-editor/brushes.js';
25
+ import { type RasterRect } from '../raster/surface.js';
26
+ /** Simulation steps a wet brushstroke runs before it is dried (enough to bleed, bloom and granulate). */
27
+ export declare const VECTOR_WET_STEPS = 120;
28
+ /** Engines a vector brushstroke paints through this module. */
29
+ export type VectorMediaEngine = 'wet' | 'mixer' | 'smudge' | 'blender';
30
+ /** Whether a brush paints through this module (and which way), or null for a dry dab brush. */
31
+ export declare function vectorMediaEngine(brush: Pick<PaintBrush, 'engine' | 'wet'>): VectorMediaEngine | null;
32
+ /** Whether a media engine acts on the paint beneath the stroke (and needs a backdrop). */
33
+ export declare const usesVectorBackdrop: (engine: VectorMediaEngine | null) => boolean;
34
+ export interface VectorMediaOptions {
35
+ /** Image pixels per path unit (default 1). */
36
+ scale?: number;
37
+ /** RGBA 0..255 of the paint (the alpha scales the result). */
38
+ color: readonly [number, number, number, number];
39
+ /** Gradient paint sampled dab by dab (lengths in path units), or null for `color`. */
40
+ paint?: PaintSource | null;
41
+ /** Jitter seed (default 0). */
42
+ seed?: number;
43
+ closed?: boolean;
44
+ /** The largest image to render, in pixels (default 4096²); a bigger stroke renders at a lower scale. */
45
+ maxPixels?: number;
46
+ }
47
+ /**
48
+ * One wet brushstroke's simulation: the paint is laid when the job is made; `run` advances it
49
+ * (within a time budget, for hosts that slice the work), `image` bakes it as it is now and
50
+ * `settled` once all `VECTOR_WET_STEPS` steps have run. Call `destroy` when done with it.
51
+ */
52
+ export declare class WetBrushstrokeJob {
53
+ readonly steps: number;
54
+ private readonly world;
55
+ private readonly placed;
56
+ private readonly dabs;
57
+ private done;
58
+ private final;
59
+ constructor(input: BrushstrokeInput, brush: PaintBrush, options: VectorMediaOptions, steps?: number);
60
+ /** Steps run so far. */
61
+ get progress(): number;
62
+ get finished(): boolean;
63
+ /** Runs steps until `budgetMs` has passed (at least one) or all have run. Returns whether it is finished. */
64
+ run(budgetMs?: number): boolean;
65
+ /** The paint dried where it is now (step 0: as laid). */
66
+ image(): BrushstrokeImage;
67
+ /** The settled image: runs the remaining steps now. */
68
+ settled(): BrushstrokeImage;
69
+ destroy(): void;
70
+ private bake;
71
+ }
72
+ /** A wet brushstroke rendered and settled at once (`VECTOR_WET_STEPS` steps; slow for long strokes). */
73
+ export declare function renderWetBrushstroke(input: BrushstrokeInput, brush: PaintBrush, options: VectorMediaOptions): BrushstrokeImage;
74
+ /**
75
+ * What lies beneath a stroke: straight-alpha RGBA of `rect` (image pixels at the stroke's scale,
76
+ * path units × scale), row by row. Called once per render.
77
+ */
78
+ export type VectorBrushstrokeBackdrop = (rect: RasterRect, scale: number) => Uint8ClampedArray;
79
+ /** The image pixels a backdrop brushstroke reads, in path units × the scale it renders at (for callers that render backdrops). */
80
+ export declare function vectorBackdropRect(input: BrushstrokeInput, brush: PaintBrush, options: VectorMediaOptions): {
81
+ rect: RasterRect;
82
+ scale: number;
83
+ } | null;
84
+ /**
85
+ * A Mixer Brush, smudge or blender stroke over `backdrop`: the pixels it changed (the rest are
86
+ * transparent). Without a backdrop it acts on bare paper: a Mixer Brush still paints from its
87
+ * reservoir; a smudge or blender changes nothing.
88
+ */
89
+ export declare function renderBackdropBrushstroke(input: BrushstrokeInput, brush: PaintBrush, options: VectorMediaOptions & {
90
+ backdrop?: VectorBrushstrokeBackdrop | null;
91
+ /** A cache for the result, given the backdrop's bytes (the result depends only on them and the stroke). */
92
+ cache?: (backdrop: Uint8ClampedArray) => {
93
+ get(): BrushstrokeImage | undefined;
94
+ set(image: BrushstrokeImage): void;
95
+ };
96
+ }): BrushstrokeImage;
@@ -29,7 +29,7 @@ import { type VectorSnapGuides, type VectorTrackingPoint } from './snap.cjs';
29
29
  import { type VectorBlendMode, type VectorFilterType, type VectorWarpMesh } from './types.cjs';
30
30
  import { EffectsSlot } from '../effects/helpers.cjs';
31
31
  import type { EffectProvider, EffectValue } from '../effects/types.cjs';
32
- import type { Vec2, VectorEffectType, VectorAlign, VectorAnchor, VectorAnchorRef, VectorAnchorType, VectorArrange, VectorAverageAxis, VectorBlendOptions, VectorBooleanOperation, VectorBounds, VectorCornerKind, VectorDefaults, VectorDistribute, VectorDocument, VectorGroupNode, VectorProviderEffect, VectorHandleRef, VectorMask, VectorMaskType, VectorModifiers, VectorNode, VectorPathfinderOperation, VectorPathNode, VectorSegmentRef, VectorStyle, VectorSubpath, VectorTool, VectorTransformHandle, VectorViewport, VectorWidthPoint, VectorCharacterStyle, VectorParagraphStyle, VectorTextAlign, VectorTextFrame, VectorTextNode, VectorMatrix, VectorSymbol, VectorPaint, VectorConstraint, VectorConstraintKind, VectorParameter, VectorBrushstroke, VectorBrushstrokePaper } from './types.cjs';
32
+ import type { Vec2, VectorEffectType, VectorAlign, VectorAnchor, VectorAnchorRef, VectorAnchorType, VectorArrange, VectorAverageAxis, VectorBlendOptions, VectorBooleanOperation, VectorBounds, VectorCornerKind, VectorDefaults, VectorDistribute, VectorDocument, VectorGroupNode, VectorProviderEffect, VectorHandleRef, VectorMask, VectorMaskType, VectorModifiers, VectorNode, VectorPathfinderOperation, VectorPathNode, VectorSegmentRef, VectorStyle, VectorSubpath, VectorTool, VectorTransformHandle, VectorViewport, VectorWidthPoint, VectorCharacterStyle, VectorParagraphStyle, VectorTextAlign, VectorTextFrame, VectorTextNode, VectorMatrix, VectorSymbol, VectorPaint, VectorConstraint, VectorConstraintKind, VectorParameter, VectorBrushstroke, VectorBrushstrokePaint, VectorBrushstrokePaper } from './types.cjs';
33
33
  export interface VectorSnapOptions {
34
34
  /** Grid size in document units (0 = off, default 0). Points and boxes that snap to no object snap to it. */
35
35
  grid: number;
@@ -113,6 +113,8 @@ export interface VectorEditorOptions {
113
113
  brushPreview?: BrushPreviewRenderer;
114
114
  /** The app's colour scheme, which picks the side of a brush's light / dark default colour (default light). */
115
115
  colorScheme?: 'light' | 'dark';
116
+ /** Start with the colour locked: new and rebrushed brushstrokes keep their colour (see `setColorLocked`). */
117
+ colorLocked?: boolean;
116
118
  /** History to record into, e.g. one shared with the rest of the app (default: a new one). */
117
119
  history?: HistoryManager;
118
120
  /** Starting tool (default `select`). */
@@ -408,6 +410,10 @@ export interface VectorEditorState {
408
410
  * a side skews along it (Alt: about the centre).
409
411
  */
410
412
  freeDistort: boolean;
413
+ /** The colour scheme that picks the side of a brush's light / dark default colour. */
414
+ colorScheme: 'light' | 'dark';
415
+ /** "Keep my colour": brushstrokes don't take a brush's default colour (`setColorLocked`). */
416
+ colorLocked: boolean;
411
417
  /** The text being edited on the canvas, or null. Typing goes to `textInput`, keys to `keyDown`. */
412
418
  textEdit: VectorTextEditState | null;
413
419
  /** Font and alignment new text gets. */
@@ -799,6 +805,7 @@ export declare class VectorEditorController {
799
805
  private revision;
800
806
  private state;
801
807
  private colorScheme;
808
+ private colorLocked;
802
809
  constructor(options?: VectorEditorOptions);
803
810
  /** Listens to the history (once; again after `destroy`). */
804
811
  private connect;
@@ -1133,7 +1140,7 @@ export declare class VectorEditorController {
1133
1140
  * Adds a brushstroke to the selected (or given) paths: a stroke layer that paints the path with
1134
1141
  * brush `brushId` (a preset, or a saved brush of the brush library: `listBrushstrokeBrushes`), `size` document
1135
1142
  * units across (default the brush's own), an optional `pressure` profile along the length, in
1136
- * `color` (default the brush's own default colour, unless `keepColour`; else the top stroke's
1143
+ * `color` (default the brush's own default colour, unless `keepColour` or the colour is locked; else the top stroke's
1137
1144
  * paint, else black) at `opacity`. At the top of the stroke
1138
1145
  * stack or at `index`. A `seed` gives it the brush's character (jitter and the grain of `paper`,
1139
1146
  * `null` for none); without one it renders plain. One undo step.
@@ -1150,7 +1157,7 @@ export declare class VectorEditorController {
1150
1157
  * given) paths: another brush, size, pressure profile (null removes it), colour or opacity, the
1151
1158
  * character `seed` (null removes it: plain dabs) or the `paper` (replaced whole: `null` for no
1152
1159
  * grain, `{}` for the default paper). Another brush without a `color` takes that brush's default
1153
- * colour, if it has one, unless `keepColour`. Fails, changing nothing, when that layer is not a
1160
+ * colour, if it has one, unless `keepColour` or the colour is locked. Fails, changing nothing, when that layer is not a
1154
1161
  * brushstroke. With `merge`, consecutive edits fold into one undo step.
1155
1162
  */
1156
1163
  setBrushstroke(index: number, patch: {
@@ -1162,12 +1169,19 @@ export declare class VectorEditorController {
1162
1169
  opacity?: number;
1163
1170
  seed?: number | null;
1164
1171
  paper?: VectorBrushstrokePaper | null;
1172
+ paint?: VectorBrushstrokePaint | null;
1165
1173
  }, options?: {
1166
1174
  ids?: readonly string[];
1167
1175
  merge?: boolean | string;
1168
1176
  }): VectorActionResult;
1169
1177
  /** Sets the colour scheme that picks the side of a brush's light / dark default colour. Existing strokes keep their colour. */
1170
1178
  setColorScheme(scheme: 'light' | 'dark'): void;
1179
+ /**
1180
+ * Locks the brushstroke colour ("Keep my colour"): `addBrushstroke` and `setBrushstroke` with
1181
+ * another brush keep the colour instead of taking the brush's default; an explicit `color` still
1182
+ * applies. Existing strokes are unchanged. Editor state, not an undo step.
1183
+ */
1184
+ setColorLocked(locked: boolean): void;
1171
1185
  /** Removes layer `index` of the fill or stroke stack of the selected (or given) paths. */
1172
1186
  removePaintLayer(kind: 'fill' | 'stroke', index: number, options?: {
1173
1187
  ids?: readonly string[];
@@ -29,7 +29,7 @@ import { type VectorSnapGuides, type VectorTrackingPoint } from './snap.js';
29
29
  import { type VectorBlendMode, type VectorFilterType, type VectorWarpMesh } from './types.js';
30
30
  import { EffectsSlot } from '../effects/helpers.js';
31
31
  import type { EffectProvider, EffectValue } from '../effects/types.js';
32
- import type { Vec2, VectorEffectType, VectorAlign, VectorAnchor, VectorAnchorRef, VectorAnchorType, VectorArrange, VectorAverageAxis, VectorBlendOptions, VectorBooleanOperation, VectorBounds, VectorCornerKind, VectorDefaults, VectorDistribute, VectorDocument, VectorGroupNode, VectorProviderEffect, VectorHandleRef, VectorMask, VectorMaskType, VectorModifiers, VectorNode, VectorPathfinderOperation, VectorPathNode, VectorSegmentRef, VectorStyle, VectorSubpath, VectorTool, VectorTransformHandle, VectorViewport, VectorWidthPoint, VectorCharacterStyle, VectorParagraphStyle, VectorTextAlign, VectorTextFrame, VectorTextNode, VectorMatrix, VectorSymbol, VectorPaint, VectorConstraint, VectorConstraintKind, VectorParameter, VectorBrushstroke, VectorBrushstrokePaper } from './types.js';
32
+ import type { Vec2, VectorEffectType, VectorAlign, VectorAnchor, VectorAnchorRef, VectorAnchorType, VectorArrange, VectorAverageAxis, VectorBlendOptions, VectorBooleanOperation, VectorBounds, VectorCornerKind, VectorDefaults, VectorDistribute, VectorDocument, VectorGroupNode, VectorProviderEffect, VectorHandleRef, VectorMask, VectorMaskType, VectorModifiers, VectorNode, VectorPathfinderOperation, VectorPathNode, VectorSegmentRef, VectorStyle, VectorSubpath, VectorTool, VectorTransformHandle, VectorViewport, VectorWidthPoint, VectorCharacterStyle, VectorParagraphStyle, VectorTextAlign, VectorTextFrame, VectorTextNode, VectorMatrix, VectorSymbol, VectorPaint, VectorConstraint, VectorConstraintKind, VectorParameter, VectorBrushstroke, VectorBrushstrokePaint, VectorBrushstrokePaper } from './types.js';
33
33
  export interface VectorSnapOptions {
34
34
  /** Grid size in document units (0 = off, default 0). Points and boxes that snap to no object snap to it. */
35
35
  grid: number;
@@ -113,6 +113,8 @@ export interface VectorEditorOptions {
113
113
  brushPreview?: BrushPreviewRenderer;
114
114
  /** The app's colour scheme, which picks the side of a brush's light / dark default colour (default light). */
115
115
  colorScheme?: 'light' | 'dark';
116
+ /** Start with the colour locked: new and rebrushed brushstrokes keep their colour (see `setColorLocked`). */
117
+ colorLocked?: boolean;
116
118
  /** History to record into, e.g. one shared with the rest of the app (default: a new one). */
117
119
  history?: HistoryManager;
118
120
  /** Starting tool (default `select`). */
@@ -408,6 +410,10 @@ export interface VectorEditorState {
408
410
  * a side skews along it (Alt: about the centre).
409
411
  */
410
412
  freeDistort: boolean;
413
+ /** The colour scheme that picks the side of a brush's light / dark default colour. */
414
+ colorScheme: 'light' | 'dark';
415
+ /** "Keep my colour": brushstrokes don't take a brush's default colour (`setColorLocked`). */
416
+ colorLocked: boolean;
411
417
  /** The text being edited on the canvas, or null. Typing goes to `textInput`, keys to `keyDown`. */
412
418
  textEdit: VectorTextEditState | null;
413
419
  /** Font and alignment new text gets. */
@@ -799,6 +805,7 @@ export declare class VectorEditorController {
799
805
  private revision;
800
806
  private state;
801
807
  private colorScheme;
808
+ private colorLocked;
802
809
  constructor(options?: VectorEditorOptions);
803
810
  /** Listens to the history (once; again after `destroy`). */
804
811
  private connect;
@@ -1133,7 +1140,7 @@ export declare class VectorEditorController {
1133
1140
  * Adds a brushstroke to the selected (or given) paths: a stroke layer that paints the path with
1134
1141
  * brush `brushId` (a preset, or a saved brush of the brush library: `listBrushstrokeBrushes`), `size` document
1135
1142
  * units across (default the brush's own), an optional `pressure` profile along the length, in
1136
- * `color` (default the brush's own default colour, unless `keepColour`; else the top stroke's
1143
+ * `color` (default the brush's own default colour, unless `keepColour` or the colour is locked; else the top stroke's
1137
1144
  * paint, else black) at `opacity`. At the top of the stroke
1138
1145
  * stack or at `index`. A `seed` gives it the brush's character (jitter and the grain of `paper`,
1139
1146
  * `null` for none); without one it renders plain. One undo step.
@@ -1150,7 +1157,7 @@ export declare class VectorEditorController {
1150
1157
  * given) paths: another brush, size, pressure profile (null removes it), colour or opacity, the
1151
1158
  * character `seed` (null removes it: plain dabs) or the `paper` (replaced whole: `null` for no
1152
1159
  * grain, `{}` for the default paper). Another brush without a `color` takes that brush's default
1153
- * colour, if it has one, unless `keepColour`. Fails, changing nothing, when that layer is not a
1160
+ * colour, if it has one, unless `keepColour` or the colour is locked. Fails, changing nothing, when that layer is not a
1154
1161
  * brushstroke. With `merge`, consecutive edits fold into one undo step.
1155
1162
  */
1156
1163
  setBrushstroke(index: number, patch: {
@@ -1162,12 +1169,19 @@ export declare class VectorEditorController {
1162
1169
  opacity?: number;
1163
1170
  seed?: number | null;
1164
1171
  paper?: VectorBrushstrokePaper | null;
1172
+ paint?: VectorBrushstrokePaint | null;
1165
1173
  }, options?: {
1166
1174
  ids?: readonly string[];
1167
1175
  merge?: boolean | string;
1168
1176
  }): VectorActionResult;
1169
1177
  /** Sets the colour scheme that picks the side of a brush's light / dark default colour. Existing strokes keep their colour. */
1170
1178
  setColorScheme(scheme: 'light' | 'dark'): void;
1179
+ /**
1180
+ * Locks the brushstroke colour ("Keep my colour"): `addBrushstroke` and `setBrushstroke` with
1181
+ * another brush keep the colour instead of taking the brush's default; an explicit `color` still
1182
+ * applies. Existing strokes are unchanged. Editor state, not an undo step.
1183
+ */
1184
+ setColorLocked(locked: boolean): void;
1171
1185
  /** Removes layer `index` of the fill or stroke stack of the selected (or given) paths. */
1172
1186
  removePaintLayer(kind: 'fill' | 'stroke', index: number, options?: {
1173
1187
  ids?: readonly string[];