@pixerate/editor 0.254.0 → 0.255.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.
- package/dist/agent/index.cjs +2 -2
- package/dist/agent/index.js +1 -1
- package/dist/animation-editor/index.cjs +59 -59
- package/dist/animation-editor/index.js +3 -3
- package/dist/brushes/index.cjs +31 -29
- package/dist/brushes/index.d.cts +1 -1
- package/dist/brushes/index.d.ts +1 -1
- package/dist/brushes/index.js +27 -25
- package/dist/brushes/library.d.cts +17 -0
- package/dist/brushes/library.d.ts +17 -0
- package/dist/{brushstrokeRender-5PYSKZIJ.js → brushstrokeRender-HCOQUSWW.js} +53 -18
- package/dist/{brushstrokeRender-7FLLSQEC.cjs → brushstrokeRender-ZZOXI5O5.cjs} +55 -20
- package/dist/canvas/brushTypes.d.cts +22 -3
- package/dist/canvas/brushTypes.d.ts +22 -3
- package/dist/canvas/brushstroke.d.cts +34 -12
- package/dist/canvas/brushstroke.d.ts +34 -12
- package/dist/canvas/brushstrokeRender.d.cts +14 -8
- package/dist/canvas/brushstrokeRender.d.ts +14 -8
- package/dist/canvas/changeFeed.d.cts +6 -0
- package/dist/canvas/changeFeed.d.ts +6 -0
- package/dist/canvas/drawController.d.cts +11 -3
- package/dist/canvas/drawController.d.ts +11 -3
- package/dist/canvas/freehand.d.cts +6 -1
- package/dist/canvas/freehand.d.ts +6 -1
- package/dist/canvas/index.cjs +123 -104
- package/dist/canvas/index.js +25 -6
- package/dist/{chunk-XVIK73LS.js → chunk-5P4JEOIV.js} +4 -4
- package/dist/{chunk-JPEHXIB5.cjs → chunk-5YWWQ36H.cjs} +66 -21
- package/dist/{chunk-CHAWTXBE.cjs → chunk-6WCQ35GI.cjs} +4 -4
- package/dist/{chunk-GYMMNCFT.js → chunk-AF23QK5F.js} +56 -11
- package/dist/{chunk-JFHBXNR2.cjs → chunk-B7V34GIH.cjs} +86 -86
- package/dist/{chunk-QC3OXRE4.js → chunk-DMTEQ6SH.js} +1 -1
- package/dist/{chunk-TLOGFIIV.cjs → chunk-GCTUOTCW.cjs} +35 -35
- package/dist/{chunk-34KLWUH4.cjs → chunk-HIMGBZAM.cjs} +1133 -597
- package/dist/{chunk-7P6VF3FG.js → chunk-HYWRU5VX.js} +1 -1
- package/dist/{chunk-QPHNVZHO.js → chunk-JVRLGV3C.js} +1118 -582
- package/dist/{chunk-LFMKWGFL.cjs → chunk-LRNUZKWV.cjs} +22 -8
- package/dist/chunk-PGPFWC35.cjs +517 -0
- package/dist/{chunk-QLSGTCYT.cjs → chunk-TBAVCLEQ.cjs} +23 -23
- package/dist/{chunk-2ZJ4DT3M.js → chunk-VUKUTT2W.js} +1 -1
- package/dist/{chunk-5JNA6LLY.js → chunk-WYGSR3IJ.js} +22 -8
- package/dist/chunk-YHUMGBZD.js +517 -0
- package/dist/commands/builtins.d.cts +1 -1
- package/dist/commands/builtins.d.ts +1 -1
- package/dist/commands/index.cjs +2 -2
- package/dist/commands/index.js +1 -1
- package/dist/image-editor/brush-presets.d.cts +32 -0
- package/dist/image-editor/brush-presets.d.ts +32 -0
- package/dist/image-editor/controller.d.cts +15 -0
- package/dist/image-editor/controller.d.ts +15 -0
- package/dist/image-editor/index.cjs +848 -775
- package/dist/image-editor/index.d.cts +1 -0
- package/dist/image-editor/index.d.ts +1 -0
- package/dist/image-editor/index.js +81 -8
- package/dist/image-editor/types.d.cts +7 -0
- package/dist/image-editor/types.d.ts +7 -0
- package/dist/paint-editor/index.cjs +80 -80
- package/dist/paint-editor/index.js +13 -13
- package/dist/vector/brushstroke.d.cts +21 -5
- package/dist/vector/brushstroke.d.ts +21 -5
- package/dist/vector/controller.d.cts +14 -1
- package/dist/vector/controller.d.ts +14 -1
- package/dist/vector/index.cjs +1220 -1199
- package/dist/vector/index.js +34 -13
- package/dist/vector/types.d.cts +7 -0
- package/dist/vector/types.d.ts +7 -0
- package/package.json +1 -1
- package/skills/pixerate-brushes/SKILL.md +9 -3
- package/skills/pixerate-canvas/SKILL.md +10 -5
- package/skills/pixerate-image-editor/SKILL.md +2 -1
- package/skills/pixerate-vector/SKILL.md +1 -1
- package/dist/chunk-HS6QDWDF.cjs +0 -1029
- package/dist/chunk-MTKY6K3Q.js +0 -1029
package/dist/vector/index.js
CHANGED
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
traceField,
|
|
27
27
|
traceVectorImage,
|
|
28
28
|
vectorTraceContours
|
|
29
|
-
} from "../chunk-
|
|
29
|
+
} from "../chunk-VUKUTT2W.js";
|
|
30
30
|
import {
|
|
31
31
|
applyHomography,
|
|
32
32
|
homographyFromPoints,
|
|
@@ -53,7 +53,7 @@ import {
|
|
|
53
53
|
reverseMorphContour,
|
|
54
54
|
subpathToMorphContour,
|
|
55
55
|
turnMorphContour
|
|
56
|
-
} from "../chunk-
|
|
56
|
+
} from "../chunk-HYWRU5VX.js";
|
|
57
57
|
import {
|
|
58
58
|
DEFAULT_VECTOR_FONT,
|
|
59
59
|
IDENTITY_MATRIX,
|
|
@@ -376,6 +376,8 @@ import {
|
|
|
376
376
|
vectorBoundsInside,
|
|
377
377
|
vectorBoxMatrix,
|
|
378
378
|
vectorBrushstrokeBrush,
|
|
379
|
+
vectorBrushstrokeBrushError,
|
|
380
|
+
vectorBrushstrokeBrushOf,
|
|
379
381
|
vectorBrushstrokeBrushes,
|
|
380
382
|
vectorBrushstrokeCharacterError,
|
|
381
383
|
vectorBrushstrokeImages,
|
|
@@ -526,8 +528,10 @@ import {
|
|
|
526
528
|
withVectorStrokes,
|
|
527
529
|
withVectorTargetPaint,
|
|
528
530
|
zigzagPaths
|
|
529
|
-
} from "../chunk-
|
|
530
|
-
import
|
|
531
|
+
} from "../chunk-AF23QK5F.js";
|
|
532
|
+
import {
|
|
533
|
+
snapshotBrushLibrary
|
|
534
|
+
} from "../chunk-JVRLGV3C.js";
|
|
531
535
|
import "../chunk-APX63ILU.js";
|
|
532
536
|
import {
|
|
533
537
|
createProvenance
|
|
@@ -3689,7 +3693,7 @@ function getVectorAppearancePanel(state) {
|
|
|
3689
3693
|
...kind === "stroke" ? { strokeWidth: l.strokeWidth ?? 1, strokeAlign: l.strokeAlign ?? "center" } : {},
|
|
3690
3694
|
...isVectorBrushstrokeLayer(l) ? (() => {
|
|
3691
3695
|
const b = l.brush;
|
|
3692
|
-
const preset =
|
|
3696
|
+
const preset = vectorBrushstrokeBrushOf(b);
|
|
3693
3697
|
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 } };
|
|
3694
3698
|
})() : (l.kind ?? "paint") !== "paint" ? { unknownKind: String(l.kind) } : {},
|
|
3695
3699
|
editing: edit.target === kind && (edit.layer === null ? index === count - 1 : edit.layer === index)
|
|
@@ -6818,6 +6822,7 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
6818
6822
|
revision = 0;
|
|
6819
6823
|
state;
|
|
6820
6824
|
constructor(options = {}) {
|
|
6825
|
+
this.brushes = options.brushLibrary ? snapshotBrushLibrary(options.brushLibrary, () => this.notify()) : null;
|
|
6821
6826
|
this.history = options.history ?? new HistoryManager();
|
|
6822
6827
|
this.doc = options.document ? loadedDocument(options.document) : { width: 800, height: 600, nodes: [] };
|
|
6823
6828
|
this.doc = this.refreshed(this.doc);
|
|
@@ -6853,6 +6858,16 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
6853
6858
|
* Stops listening to the history and drops all listeners. A later `subscribe` reconnects, so a
|
|
6854
6859
|
* controller torn down by React StrictMode's double effect keeps working when it is reused.
|
|
6855
6860
|
*/
|
|
6861
|
+
/** The saved brushes of the brush library as last read (empty without one). */
|
|
6862
|
+
brushes;
|
|
6863
|
+
/** The brushes a brushstroke can use: the presets, then the brush library's saved brushes the vector profile admits. */
|
|
6864
|
+
listBrushstrokeBrushes() {
|
|
6865
|
+
return vectorBrushstrokeBrushes(this.brushes?.user ?? []);
|
|
6866
|
+
}
|
|
6867
|
+
/** Resolves once the brush library has been read (its saved brushes can be used from then on). */
|
|
6868
|
+
whenBrushesLoaded() {
|
|
6869
|
+
return this.brushes?.ready ?? Promise.resolve();
|
|
6870
|
+
}
|
|
6856
6871
|
destroy() {
|
|
6857
6872
|
if (this.dwellTimer) clearTimeout(this.dwellTimer);
|
|
6858
6873
|
this.dwellTimer = null;
|
|
@@ -8163,15 +8178,17 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
8163
8178
|
}
|
|
8164
8179
|
/**
|
|
8165
8180
|
* Adds a brushstroke to the selected (or given) paths: a stroke layer that paints the path with
|
|
8166
|
-
* brush `brushId`
|
|
8181
|
+
* brush `brushId` (a preset, or a saved brush of the brush library: `listBrushstrokeBrushes`), `size` document
|
|
8167
8182
|
* units across (default the brush's own), an optional `pressure` profile along the length, in
|
|
8168
8183
|
* `color` (default the top stroke's paint, else black) at `opacity`. At the top of the stroke
|
|
8169
8184
|
* stack or at `index`. A `seed` gives it the brush's character (jitter and the grain of `paper`,
|
|
8170
8185
|
* `null` for none); without one it renders plain. One undo step.
|
|
8171
8186
|
*/
|
|
8172
8187
|
addBrushstroke(brush, options = {}) {
|
|
8173
|
-
const
|
|
8174
|
-
|
|
8188
|
+
const user = this.brushes?.user ?? [];
|
|
8189
|
+
const brushError = typeof brush?.brushId === "string" ? vectorBrushstrokeBrushError(brush.brushId, user) : "brushId must be a brush id (vector.listBrushes lists them).";
|
|
8190
|
+
const clean = brushError ? null : sanitizeVectorBrushstroke(brush, user);
|
|
8191
|
+
if (!clean) return { ok: false, message: brushError ?? `Brush "${brush.brushId}" can't paint a brushstroke (vector.listBrushes lists the ones that can).` };
|
|
8175
8192
|
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)." };
|
|
8176
8193
|
const characterError = vectorBrushstrokeCharacterError(brush);
|
|
8177
8194
|
if (characterError) return { ok: false, message: characterError };
|
|
@@ -8193,7 +8210,9 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
8193
8210
|
* brushstroke. With `merge`, consecutive edits fold into one undo step.
|
|
8194
8211
|
*/
|
|
8195
8212
|
setBrushstroke(index, patch, options = {}) {
|
|
8196
|
-
|
|
8213
|
+
const user = this.brushes?.user ?? [];
|
|
8214
|
+
const brushError = patch.brushId !== void 0 ? vectorBrushstrokeBrushError(patch.brushId, user) : null;
|
|
8215
|
+
if (brushError) return { ok: false, message: brushError };
|
|
8197
8216
|
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)." };
|
|
8198
8217
|
if (patch.color !== void 0 && !parseVectorColor(patch.color)) return { ok: false, message: `"${patch.color}" is not a colour.` };
|
|
8199
8218
|
if (patch.opacity !== void 0 && !(patch.opacity >= 0 && patch.opacity <= 1)) return { ok: false, message: "opacity must be from 0 to 1." };
|
|
@@ -8207,7 +8226,7 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
8207
8226
|
(stack, path) => {
|
|
8208
8227
|
const layer = stack[index];
|
|
8209
8228
|
if (!layer || layer.kind !== "brushstroke" || !layer.brush) return `Path "${path.id}" has no brushstroke at stroke ${index} (vector.getAppearance lists its strokes; 0 is the bottom).`;
|
|
8210
|
-
const brush =
|
|
8229
|
+
const brush = patch.brushId && patch.brushId !== layer.brush.brushId ? { ...layer.brush, brushId: patch.brushId, spec: void 0 } : { ...layer.brush };
|
|
8211
8230
|
if (patch.size === null) delete brush.size;
|
|
8212
8231
|
else if (patch.size !== void 0) brush.size = patch.size;
|
|
8213
8232
|
if (patch.pressure === null) delete brush.pressure;
|
|
@@ -8215,7 +8234,7 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
8215
8234
|
if (patch.seed === null) delete brush.seed;
|
|
8216
8235
|
else if (patch.seed !== void 0) brush.seed = patch.seed;
|
|
8217
8236
|
if (patch.paper !== void 0) brush.paper = patch.paper;
|
|
8218
|
-
const next = { ...layer, brush: sanitizeVectorBrushstroke(brush) ?? layer.brush, ...patch.color ? { paint: patch.color } : {}, ...patch.opacity !== void 0 ? { opacity: patch.opacity } : {} };
|
|
8237
|
+
const next = { ...layer, brush: sanitizeVectorBrushstroke(brush, user) ?? layer.brush, ...patch.color ? { paint: patch.color } : {}, ...patch.opacity !== void 0 ? { opacity: patch.opacity } : {} };
|
|
8219
8238
|
return stack.map((l, i) => i === index ? next : l);
|
|
8220
8239
|
},
|
|
8221
8240
|
merge
|
|
@@ -15894,9 +15913,9 @@ function createVectorCommands(controller, options = {}) {
|
|
|
15894
15913
|
label: "Brushstroke Brushes",
|
|
15895
15914
|
readOnly: true,
|
|
15896
15915
|
keywords: ["brush", "brushstroke", "pencil", "pastel", "charcoal", "ink", "marker", "natural media"],
|
|
15897
|
-
description: "Lists the brushes a brushstroke can use (the
|
|
15916
|
+
description: "Lists the brushes a brushstroke can use (the dry presets, then saved brushes from the brush library the vector profile admits): { brushes: [{ id, name, category, size, builtin }] } (size: the brush's own diameter in document units).",
|
|
15898
15917
|
params: { type: "object", properties: {}, additionalProperties: false },
|
|
15899
|
-
run: () => ({ brushes:
|
|
15918
|
+
run: () => ({ brushes: controller.listBrushstrokeBrushes().map((b) => ({ id: b.id, name: b.name, category: b.category, size: b.tip.size, builtin: vectorBrushstrokeBrush(b.id) !== null })) })
|
|
15900
15919
|
},
|
|
15901
15920
|
{
|
|
15902
15921
|
...base,
|
|
@@ -18848,6 +18867,8 @@ export {
|
|
|
18848
18867
|
vectorBoxCorners,
|
|
18849
18868
|
vectorBoxMatrix,
|
|
18850
18869
|
vectorBrushstrokeBrush,
|
|
18870
|
+
vectorBrushstrokeBrushError,
|
|
18871
|
+
vectorBrushstrokeBrushOf,
|
|
18851
18872
|
vectorBrushstrokeBrushes,
|
|
18852
18873
|
vectorBrushstrokeCharacterError,
|
|
18853
18874
|
vectorBrushstrokeImages,
|
package/dist/vector/types.d.cts
CHANGED
|
@@ -2,6 +2,7 @@ import type { GenerationProvenance } from '../generation/provenance.cjs';
|
|
|
2
2
|
import type { CanvasGradientDef } from '../canvas/gradient.cjs';
|
|
3
3
|
import type { WarpMesh, WarpStyle } from '../geom/types.cjs';
|
|
4
4
|
import type { GrainPattern } from '../paint/grain.cjs';
|
|
5
|
+
import type { Brush } from '../brushes/types.cjs';
|
|
5
6
|
/** An affine matrix `[a, b, c, d, e, f]`: `x' = a·x + c·y + e`, `y' = b·x + d·y + f` (SVG order). */
|
|
6
7
|
export type VectorMatrix = readonly [number, number, number, number, number, number];
|
|
7
8
|
/** A point in document coordinates. */
|
|
@@ -268,7 +269,13 @@ export interface VectorBrushstrokePaper {
|
|
|
268
269
|
* renders plain dabs, as before, and `paper` is ignored.
|
|
269
270
|
*/
|
|
270
271
|
export interface VectorBrushstroke {
|
|
272
|
+
/** A preset id, or a saved brush's id from the brush library. */
|
|
271
273
|
brushId: string;
|
|
274
|
+
/**
|
|
275
|
+
* The saved brush `brushId` names (a facet brush of `@pixerate/editor/brushes`), embedded when it
|
|
276
|
+
* is not a preset, so the document renders without the library.
|
|
277
|
+
*/
|
|
278
|
+
spec?: Brush;
|
|
272
279
|
size?: number;
|
|
273
280
|
pressure?: number[];
|
|
274
281
|
/** Jitter seed, an integer 0–2147483647. Turns the brush's character on. */
|
package/dist/vector/types.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { GenerationProvenance } from '../generation/provenance.js';
|
|
|
2
2
|
import type { CanvasGradientDef } from '../canvas/gradient.js';
|
|
3
3
|
import type { WarpMesh, WarpStyle } from '../geom/types.js';
|
|
4
4
|
import type { GrainPattern } from '../paint/grain.js';
|
|
5
|
+
import type { Brush } from '../brushes/types.js';
|
|
5
6
|
/** An affine matrix `[a, b, c, d, e, f]`: `x' = a·x + c·y + e`, `y' = b·x + d·y + f` (SVG order). */
|
|
6
7
|
export type VectorMatrix = readonly [number, number, number, number, number, number];
|
|
7
8
|
/** A point in document coordinates. */
|
|
@@ -268,7 +269,13 @@ export interface VectorBrushstrokePaper {
|
|
|
268
269
|
* renders plain dabs, as before, and `paper` is ignored.
|
|
269
270
|
*/
|
|
270
271
|
export interface VectorBrushstroke {
|
|
272
|
+
/** A preset id, or a saved brush's id from the brush library. */
|
|
271
273
|
brushId: string;
|
|
274
|
+
/**
|
|
275
|
+
* The saved brush `brushId` names (a facet brush of `@pixerate/editor/brushes`), embedded when it
|
|
276
|
+
* is not a preset, so the document renders without the library.
|
|
277
|
+
*/
|
|
278
|
+
spec?: Brush;
|
|
272
279
|
size?: number;
|
|
273
280
|
pressure?: number[];
|
|
274
281
|
/** Jitter seed, an integer 0–2147483647. Turns the brush's character on. */
|
package/package.json
CHANGED
|
@@ -38,9 +38,15 @@ paints without (warnings), each with a fix; lists and writes use the current hos
|
|
|
38
38
|
| Host | Renders |
|
|
39
39
|
| --- | --- |
|
|
40
40
|
| Paint editor (`paint`) | Everything. |
|
|
41
|
-
| Image editor (`image`) | Dry dabs on round, flat and chisel tips, the Mixer Brush and the eraser; no wet or thick surface, particles, objects, light or motion. |
|
|
42
|
-
| Canvas (`canvas`) | Dry dab brushes along a path (no tools, wet, thick, particles, objects or light); velocity is ignored. |
|
|
43
|
-
| Vector strokes (`vector`) | As canvas, but light brushes paint as plain colour. |
|
|
41
|
+
| Image editor (`image`) | Dry dabs on round, flat and chisel tips, the Mixer Brush and the eraser; no wet or thick surface, particles, objects, light or motion. Pick one with `set_brush_preset`. |
|
|
42
|
+
| Canvas (`canvas`) | Dry dab brushes along a path (no tools, wet, thick, particles, objects or light); velocity is ignored. Draw with one as `canvas.drawFreehand` `brush`. |
|
|
43
|
+
| Vector strokes (`vector`) | As canvas, but light brushes paint as plain colour. Draw with one as `vector.addBrushstroke` `brushId`. |
|
|
44
|
+
|
|
45
|
+
Every host lists the presets its profile admits and the library's saved brushes it admits, and
|
|
46
|
+
each registers these tools with its own profile, so `list_brush_presets` shows that host's brushes.
|
|
47
|
+
A saved brush used in canvas or vector strokes is copied into the stroke, so the document renders
|
|
48
|
+
where the library is not; changing the brush in the library later doesn't change strokes already
|
|
49
|
+
drawn.
|
|
44
50
|
|
|
45
51
|
## Working method
|
|
46
52
|
|
|
@@ -250,8 +250,8 @@ character: seeded jitter and the paper grain they catch) and, when a width was c
|
|
|
250
250
|
|
|
251
251
|
| Command | Use it to |
|
|
252
252
|
| --- | --- |
|
|
253
|
-
| `canvas.drawFreehand` | Draw a pen or highlighter stroke through `points` (`[x, y]` pairs in canvas units, in drawing order; one undo step). `tool` picks the defaults (`pen`: blue, width 3; `highlighter`: yellow, width 24, opacity 0.35); `color`, `width`, `opacity` override them (with a `brush`, `width` is the brush diameter and defaults to the preset's own size). Pass `brush` (a preset id from `canvas.listBrushes`, or tip settings) to paint it with a dry brush, plus `pressure` / `tiltX` / `tiltY` profiles spread along its length (`[0.2, 1, 0.3]` swells in the middle). Add `paint` (only with `brush`) for gradient paint that changes colour along the stroke: `{ "type": "gradient", "stops": [...], "map": { "by": "distance", "length": 200 } }` (length in canvas units), or `by` `pressure`, `tilt`, `direction`, `across-tip`, `random`. Returns the node `id`, its `bounds` and the stored `brush` (with `paint` normalised: defaults filled in, colours lowercased). |
|
|
254
|
-
| `canvas.listBrushes` | Read-only: the
|
|
253
|
+
| `canvas.drawFreehand` | Draw a pen or highlighter stroke through `points` (`[x, y]` pairs in canvas units, in drawing order; one undo step). `tool` picks the defaults (`pen`: blue, width 3; `highlighter`: yellow, width 24, opacity 0.35); `color`, `width`, `opacity` override them (with a `brush`, `width` is the brush diameter and defaults to the preset's own size). Pass `brush` (a preset or saved brush id from `canvas.listBrushes`, or tip settings) to paint it with a dry brush, plus `pressure` / `tiltX` / `tiltY` profiles spread along its length (`[0.2, 1, 0.3]` swells in the middle). Add `paint` (only with `brush`) for gradient paint that changes colour along the stroke: `{ "type": "gradient", "stops": [...], "map": { "by": "distance", "length": 200 } }` (length in canvas units), or `by` `pressure`, `tilt`, `direction`, `across-tip`, `random`. Returns the node `id`, its `bounds` and the stored `brush` (with `paint` normalised: defaults filled in, colours lowercased). |
|
|
254
|
+
| `canvas.listBrushes` | Read-only: the brushes `canvas.drawFreehand` and the gestures accept as `brush`: the dry presets, then saved brushes from the brush library the canvas can paint (`id`, `name`, `category`, the brush's own `size`, which a stroke uses unless you pass `width`, and `builtin`). Call it before the first brushed stroke instead of guessing ids. |
|
|
255
255
|
|
|
256
256
|
Gestures draw one hand-drawn stroke node each (one undo step) through the same path as
|
|
257
257
|
`canvas.drawFreehand`, and the agent's cursor traces them. Targets are boxes
|
|
@@ -348,9 +348,14 @@ effects provider (for example Flair); without one the read tools say so and the
|
|
|
348
348
|
- **A shape node holds one effect.** `apply_effect` replaces the effect that is there. Effects draw on shape nodes only (nodes with `data.shape`).
|
|
349
349
|
- **Effects belong to the provider they came from.** Each saved effect keeps its provider id. After the provider changes (another effects library), check `list_applied_effects` for `available: false` and re-apply those effects with ids from the new provider's `search_effects`; the old effect ids mean nothing to it.
|
|
350
350
|
|
|
351
|
-
- **Brushes are dry only.**
|
|
352
|
-
|
|
353
|
-
|
|
351
|
+
- **Brushes are dry only.** The canvas profile (`CANVAS_PROFILE`, see `pixerate-brushes`) refuses
|
|
352
|
+
wet and thick brushes (watercolour, gouache, wet oils, impasto), particle and sticker brushes,
|
|
353
|
+
tools (mixer, blender, smudge, eraser) and light brushes, saying why and which ids to use:
|
|
354
|
+
wet paint needs an area to flow in, tools need paint under them, light needs the paint editor's
|
|
355
|
+
light channel. Saved brushes from the brush library work when they are dry (`check_brush` with
|
|
356
|
+
`host: "canvas"` says, and gives a `degraded` brush to save instead); a stroke keeps a copy of
|
|
357
|
+
the saved brush, so it renders without the library. `pressure` and tilt without a `brush` are
|
|
358
|
+
refused too.
|
|
354
359
|
- **Gradient paint needs a brush, and no timing.** `paint` without `brush` is refused; use
|
|
355
360
|
`color` for a plain stroke. Canvas strokes record no timing, so `velocity` and `time` mappings
|
|
356
361
|
are refused: use `distance` for colour that changes along the stroke. The stroke `color` still
|
|
@@ -313,7 +313,8 @@ in the source frame at the document's bit depth, colour mode and profile. Read
|
|
|
313
313
|
| `set_paint` | Set what the brush paints: one colour (it becomes the foreground) or gradient paint (`stops` sorted by offset, `space` pigment / oklab / srgb, `map`, `softness`). Errors say what is wrong. Returns `paint`, `foreground`, `background`, `brush`. |
|
|
314
314
|
| `sample_color` | The Eyedropper: read the composite colour at a document point (`size` averages a square; default 1 px) and, unless `setForeground` is false, make it the paint foreground. Use it to match a colour already in the image before painting or retouching. Fails outside the canvas or on transparent pixels. Returns `color` and `foreground`. |
|
|
315
315
|
| `sample_gradient` | Read the composite along a line (`start` → `end`, document pixels) and fit the fewest gradient stops to it (`tolerance` OKLab ΔE, `maxStops`, `sampleSize` averaging, `snapStep`). Changes nothing. Returns a linear `gradient` (angle of the line, oklab), its `css` and `pointsRead`. Use it to match a sky, a backdrop or a light falloff before painting a gradient or styling one. |
|
|
316
|
-
| `get_paint` | Read-only. What the brush paints (`paint`), the foreground and background colours and the
|
|
316
|
+
| `get_paint` | Read-only. What the brush paints (`paint`), the foreground and background colours, the brush settings, and `brushPreset` (the preset they came from, null once changed by hand). |
|
|
317
|
+
| `set_brush_preset` | Paint with a brush from the brush library: `id` from `list_brush_presets` (the image host lists only what it can paint). Sets the paint tool it needs (`brush`, `mixer` for a Mixer Brush, `eraser`), its brush and mixer settings and a brush's own gradient. Refuses wet, thick, particle, sticker and light brushes with the reason. Returns `tool`, `brush`, `mixer`, `paint`, `warnings` (e.g. paper grain, which the image editor paints without). Then `paint_stroke` with that tool. |
|
|
317
318
|
| `get_mixer_brush` | Read-only. The Mixer Brush settings and what it carries (`reservoir` #rrggbb or null, `amount` left 0..1, `pickup` #rrggbb or null). Call it before a mixer stroke with `loadEachStroke: false`. |
|
|
318
319
|
| `load_mixer_brush` | Fill the Mixer Brush reservoir with `color` (default the foreground), amount 1; keeps the pickup. View state, not an undo step. Use before strokes with `loadEachStroke: false`. Returns the load. |
|
|
319
320
|
| `clean_mixer_brush` | Empty the Mixer Brush pickup well (`emptyReservoir: true` also drops the loaded paint, so it only smears). View state, not an undo step. Returns the load. |
|
|
@@ -373,7 +373,7 @@ contents whole while you work, without losing the mask.
|
|
|
373
373
|
|
|
374
374
|
| Command | Use it to |
|
|
375
375
|
| --- | --- |
|
|
376
|
-
| `vector.listBrushes` | List the
|
|
376
|
+
| `vector.listBrushes` | List the brushes a brushstroke can use: the dry presets (pencils, pastels, charcoal, markers, inks), then saved brushes from the brush library the vector profile admits, with their sizes and `builtin`. Brushes it refuses (wet, thick, particles, stickers, tools) are refused by `vector.addBrushstroke` with the reason. A saved brush is kept in the layer, so the document renders without the library. |
|
|
377
377
|
| `vector.addBrushstroke` | Paint paths with a brush along their outline (`brushId`, `size`, `pressure` profile such as [0.2, 1, 0.2] for a taper, `color`): sketchy, hand-drawn or inked lines that stay editable. Pass a `seed` (any integer) so the brush gets its character, the seeded jitter and paper grain that make pencil, pastel and charcoal look real; `paper` picks the grain (`{ pattern, seed, scale, depth }`) or `null` turns it off. Returns the stroke stacks. |
|
|
378
378
|
| `vector.setBrushstroke` | Change brushstroke layer `index` of path `id`: brush, size, pressure, colour, opacity, `seed` (a new seed is a new take on the same stroke; null: plain dabs) and `paper` (replaced whole; null: no grain; {}: the default sanded paper). Remove it with `vector.removeStroke`. |
|
|
379
379
|
|