@pixerate/editor 0.239.0 → 0.240.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/paint-editor/controller.d.cts +91 -1
- package/dist/paint-editor/controller.d.ts +91 -1
- package/dist/paint-editor/document.d.cts +7 -2
- package/dist/paint-editor/document.d.ts +7 -2
- package/dist/paint-editor/index.cjs +743 -173
- package/dist/paint-editor/index.d.cts +1 -0
- package/dist/paint-editor/index.d.ts +1 -0
- package/dist/paint-editor/index.js +608 -38
- package/dist/paint-editor/live-strokes.d.cts +24 -0
- package/dist/paint-editor/live-strokes.d.ts +24 -0
- package/dist/paint-editor/ui.d.cts +24 -4
- package/dist/paint-editor/ui.d.ts +24 -4
- package/package.json +1 -1
- package/skills/pixerate-paint-editor/SKILL.md +30 -15
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Live stroke layers: a paint layer whose pixels are always drawn from its recorded strokes, so a
|
|
3
|
+
* stroke's brush, colour, paint, seed and points can be changed after it is painted
|
|
4
|
+
* (`PaintEditorController.updateStroke` and the rest). The document keeps the strokes
|
|
5
|
+
* (`liveStrokes`), and the layer's surface is a cache of them drawn bottom first.
|
|
6
|
+
*
|
|
7
|
+
* Only brushes whose result depends on the stroke itself can be redrawn exactly: dab, particle and
|
|
8
|
+
* bristle brushes, and the Mixer Brush, none of them picking up paint. Wet paint needs the
|
|
9
|
+
* simulation's history, thick paint has relief channels, stickers are their own objects, and
|
|
10
|
+
* smudges, blenders, pick-up brushes and erasers read the paint under them.
|
|
11
|
+
*/
|
|
12
|
+
import type { PaintBrush, PaintBrushEngine } from './brushes.cjs';
|
|
13
|
+
import { type RecordedStroke } from './strokes.cjs';
|
|
14
|
+
/** The engines a live stroke layer takes. */
|
|
15
|
+
export declare const LIVE_STROKE_ENGINES: readonly PaintBrushEngine[];
|
|
16
|
+
/** Why a brush can't paint on a live stroke layer, or `null` when it can. */
|
|
17
|
+
export declare function liveStrokeRefusal(brush: PaintBrush): string | null;
|
|
18
|
+
/** A stroke's extent in document pixels: its points and symmetry copies, padded by the brush. */
|
|
19
|
+
export declare function liveStrokeBounds(stroke: RecordedStroke): {
|
|
20
|
+
x: number;
|
|
21
|
+
y: number;
|
|
22
|
+
width: number;
|
|
23
|
+
height: number;
|
|
24
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Live stroke layers: a paint layer whose pixels are always drawn from its recorded strokes, so a
|
|
3
|
+
* stroke's brush, colour, paint, seed and points can be changed after it is painted
|
|
4
|
+
* (`PaintEditorController.updateStroke` and the rest). The document keeps the strokes
|
|
5
|
+
* (`liveStrokes`), and the layer's surface is a cache of them drawn bottom first.
|
|
6
|
+
*
|
|
7
|
+
* Only brushes whose result depends on the stroke itself can be redrawn exactly: dab, particle and
|
|
8
|
+
* bristle brushes, and the Mixer Brush, none of them picking up paint. Wet paint needs the
|
|
9
|
+
* simulation's history, thick paint has relief channels, stickers are their own objects, and
|
|
10
|
+
* smudges, blenders, pick-up brushes and erasers read the paint under them.
|
|
11
|
+
*/
|
|
12
|
+
import type { PaintBrush, PaintBrushEngine } from './brushes.js';
|
|
13
|
+
import { type RecordedStroke } from './strokes.js';
|
|
14
|
+
/** The engines a live stroke layer takes. */
|
|
15
|
+
export declare const LIVE_STROKE_ENGINES: readonly PaintBrushEngine[];
|
|
16
|
+
/** Why a brush can't paint on a live stroke layer, or `null` when it can. */
|
|
17
|
+
export declare function liveStrokeRefusal(brush: PaintBrush): string | null;
|
|
18
|
+
/** A stroke's extent in document pixels: its points and symmetry copies, padded by the brush. */
|
|
19
|
+
export declare function liveStrokeBounds(stroke: RecordedStroke): {
|
|
20
|
+
x: number;
|
|
21
|
+
y: number;
|
|
22
|
+
width: number;
|
|
23
|
+
height: number;
|
|
24
|
+
};
|
|
@@ -34,7 +34,7 @@ export interface PaintPointerEvent extends PointerSample {
|
|
|
34
34
|
getCoalescedEvents?(): PaintPointerEvent[];
|
|
35
35
|
getPredictedEvents?(): PaintPointerEvent[];
|
|
36
36
|
}
|
|
37
|
-
export type PaintTool = 'brush' | 'eyedropper' | 'pan' | 'rotate' | 'sticker';
|
|
37
|
+
export type PaintTool = 'brush' | 'eyedropper' | 'pan' | 'rotate' | 'sticker' | 'stroke';
|
|
38
38
|
export declare const PAINT_TOOLS: ReadonlyArray<{
|
|
39
39
|
id: PaintTool;
|
|
40
40
|
label: string;
|
|
@@ -63,6 +63,17 @@ export declare class PaintGesture {
|
|
|
63
63
|
private pen;
|
|
64
64
|
/** Pointer down; returns true when the gesture took the pointer (capture it). */
|
|
65
65
|
down(e: PaintPointerEvent): boolean;
|
|
66
|
+
/**
|
|
67
|
+
* The Select stroke tool, on a stroke layer: pressing a stroke picks it and dragging moves it
|
|
68
|
+
* (one undo step at the drop); pressing where no stroke painted clears the pick.
|
|
69
|
+
*/
|
|
70
|
+
private strokeDown;
|
|
71
|
+
/** While a stroke is dragged: how far it has moved (document pixels), to draw its outline there. */
|
|
72
|
+
get strokeDrag(): {
|
|
73
|
+
id: string;
|
|
74
|
+
dx: number;
|
|
75
|
+
dy: number;
|
|
76
|
+
} | null;
|
|
66
77
|
/**
|
|
67
78
|
* The Stickers tool: pressing a sticker picks it and dragging moves it (one undo step at the
|
|
68
79
|
* drop); pressing anywhere else places the active brush's first stamp there, at its tip size and
|
|
@@ -107,9 +118,16 @@ export declare class PaintCanvasPresenter {
|
|
|
107
118
|
/** Draws what changed into `ctx` (a canvas the size of the document); returns the tiles drawn. */
|
|
108
119
|
render(ctx: Paint2DContext): number;
|
|
109
120
|
}
|
|
110
|
-
export type GuideOverlayKind = 'symmetry' | 'perspective' | 'snap' | 'stencil' | 'sticker';
|
|
111
|
-
/**
|
|
112
|
-
|
|
121
|
+
export type GuideOverlayKind = 'symmetry' | 'perspective' | 'snap' | 'stencil' | 'sticker' | 'stroke';
|
|
122
|
+
/**
|
|
123
|
+
* Lines to draw over the canvas for the guides, the picked sticker and the picked stroke of a stroke layer (moved by
|
|
124
|
+
* `drag` while it is dragged), in document pixels, with a style key.
|
|
125
|
+
*/
|
|
126
|
+
export declare function guideOverlay(controller: PaintEditorController, drag?: {
|
|
127
|
+
id: string;
|
|
128
|
+
dx: number;
|
|
129
|
+
dy: number;
|
|
130
|
+
} | null): Array<{
|
|
113
131
|
from: Point2;
|
|
114
132
|
to: Point2;
|
|
115
133
|
kind: GuideOverlayKind;
|
|
@@ -238,6 +256,8 @@ export declare const STAMP_LABELS: Readonly<Record<StampKind, string>>;
|
|
|
238
256
|
/** Toggles one stamp in a sticker brush's set (never leaving it empty). */
|
|
239
257
|
export declare function toggleStamp(stamps: readonly StampKind[], stamp: StampKind): StampKind[];
|
|
240
258
|
/** The sticker panel's sliders for the selected sticker. */
|
|
259
|
+
/** The brush sliders of a picked stroke on a stroke layer (paths into its brush; see `updateStroke`). */
|
|
260
|
+
export declare const STROKE_SLIDERS: readonly SliderControl[];
|
|
241
261
|
export declare const STICKER_SLIDERS: readonly SliderControl[];
|
|
242
262
|
/** Stencils a toolbar can lay with one click, centred on the canvas. */
|
|
243
263
|
export declare function quickStencil(kind: 'ruler' | 'circle' | 'ellipse-mask' | 'edge-mask', canvas: {
|
|
@@ -34,7 +34,7 @@ export interface PaintPointerEvent extends PointerSample {
|
|
|
34
34
|
getCoalescedEvents?(): PaintPointerEvent[];
|
|
35
35
|
getPredictedEvents?(): PaintPointerEvent[];
|
|
36
36
|
}
|
|
37
|
-
export type PaintTool = 'brush' | 'eyedropper' | 'pan' | 'rotate' | 'sticker';
|
|
37
|
+
export type PaintTool = 'brush' | 'eyedropper' | 'pan' | 'rotate' | 'sticker' | 'stroke';
|
|
38
38
|
export declare const PAINT_TOOLS: ReadonlyArray<{
|
|
39
39
|
id: PaintTool;
|
|
40
40
|
label: string;
|
|
@@ -63,6 +63,17 @@ export declare class PaintGesture {
|
|
|
63
63
|
private pen;
|
|
64
64
|
/** Pointer down; returns true when the gesture took the pointer (capture it). */
|
|
65
65
|
down(e: PaintPointerEvent): boolean;
|
|
66
|
+
/**
|
|
67
|
+
* The Select stroke tool, on a stroke layer: pressing a stroke picks it and dragging moves it
|
|
68
|
+
* (one undo step at the drop); pressing where no stroke painted clears the pick.
|
|
69
|
+
*/
|
|
70
|
+
private strokeDown;
|
|
71
|
+
/** While a stroke is dragged: how far it has moved (document pixels), to draw its outline there. */
|
|
72
|
+
get strokeDrag(): {
|
|
73
|
+
id: string;
|
|
74
|
+
dx: number;
|
|
75
|
+
dy: number;
|
|
76
|
+
} | null;
|
|
66
77
|
/**
|
|
67
78
|
* The Stickers tool: pressing a sticker picks it and dragging moves it (one undo step at the
|
|
68
79
|
* drop); pressing anywhere else places the active brush's first stamp there, at its tip size and
|
|
@@ -107,9 +118,16 @@ export declare class PaintCanvasPresenter {
|
|
|
107
118
|
/** Draws what changed into `ctx` (a canvas the size of the document); returns the tiles drawn. */
|
|
108
119
|
render(ctx: Paint2DContext): number;
|
|
109
120
|
}
|
|
110
|
-
export type GuideOverlayKind = 'symmetry' | 'perspective' | 'snap' | 'stencil' | 'sticker';
|
|
111
|
-
/**
|
|
112
|
-
|
|
121
|
+
export type GuideOverlayKind = 'symmetry' | 'perspective' | 'snap' | 'stencil' | 'sticker' | 'stroke';
|
|
122
|
+
/**
|
|
123
|
+
* Lines to draw over the canvas for the guides, the picked sticker and the picked stroke of a stroke layer (moved by
|
|
124
|
+
* `drag` while it is dragged), in document pixels, with a style key.
|
|
125
|
+
*/
|
|
126
|
+
export declare function guideOverlay(controller: PaintEditorController, drag?: {
|
|
127
|
+
id: string;
|
|
128
|
+
dx: number;
|
|
129
|
+
dy: number;
|
|
130
|
+
} | null): Array<{
|
|
113
131
|
from: Point2;
|
|
114
132
|
to: Point2;
|
|
115
133
|
kind: GuideOverlayKind;
|
|
@@ -238,6 +256,8 @@ export declare const STAMP_LABELS: Readonly<Record<StampKind, string>>;
|
|
|
238
256
|
/** Toggles one stamp in a sticker brush's set (never leaving it empty). */
|
|
239
257
|
export declare function toggleStamp(stamps: readonly StampKind[], stamp: StampKind): StampKind[];
|
|
240
258
|
/** The sticker panel's sliders for the selected sticker. */
|
|
259
|
+
/** The brush sliders of a picked stroke on a stroke layer (paths into its brush; see `updateStroke`). */
|
|
260
|
+
export declare const STROKE_SLIDERS: readonly SliderControl[];
|
|
241
261
|
export declare const STICKER_SLIDERS: readonly SliderControl[];
|
|
242
262
|
/** Stencils a toolbar can lay with one click, centred on the canvas. */
|
|
243
263
|
export declare function quickStencil(kind: 'ruler' | 'circle' | 'ellipse-mask' | 'edge-mask', canvas: {
|
package/package.json
CHANGED
|
@@ -40,6 +40,8 @@ is never part of a layer. Coordinates are document pixels, (0, 0) top-left, y do
|
|
|
40
40
|
- **Strokes are data.** Every stroke is recorded (brush, colour, raw points, seed, symmetry
|
|
41
41
|
copies) and gets a `strokeId`. `replay_strokes` paints recorded strokes again, exactly or
|
|
42
42
|
varied. That is the main way an agent should make many similar marks.
|
|
43
|
+
- **Stroke layers keep strokes editable** (`add_layer {type: "strokes"}`): tune a stroke's brush,
|
|
44
|
+
colour, seed or points after painting it instead of repainting. See "Stroke layers" below.
|
|
43
45
|
- **Guides** are editor state saved with the document: a symmetry guide makes every stroke paint
|
|
44
46
|
its mirror or kaleidoscope copies (one stroke), a perspective guide snaps strokes to lines
|
|
45
47
|
towards one to three vanishing points, a tracing image sits under the paint (never exported)
|
|
@@ -196,11 +198,13 @@ Paint that changes colour as the stroke goes: give a gradient where a colour wou
|
|
|
196
198
|
bristle draws its own line: press harder to splay the tuft, tilt to flatten it; soft bristles
|
|
197
199
|
bend into curves at turns; a low `bristle.load` runs dry into broken streaks.
|
|
198
200
|
- **Sticker spray** (category `sticker`): stamps (`star`, `leaf`, `confetti`, `flower`, `heart`,
|
|
199
|
-
`splat`, `sparkle`, `ring`, `dot`) sprayed
|
|
200
|
-
|
|
201
|
-
`
|
|
202
|
-
|
|
203
|
-
|
|
201
|
+
`splat`, `sparkle`, `ring`, `dot`) sprayed onto an **empty layer**, each staying an object:
|
|
202
|
+
`add_stickers` (exact places), `sticker_at`, `list_stickers`, `update_sticker`, `arrange_stickers`,
|
|
203
|
+
`remove_stickers`. A sticker layer takes no other paint; sprays are refused under an enabled
|
|
204
|
+
mask stencil (hide it with `update_stencil` `enabled` false, then remove unwanted stickers).
|
|
205
|
+
- **Stroke layers**: pixels drawn from the layer's strokes; they take `dab`, `particle`, `bristle`
|
|
206
|
+
and Mixer Brush strokes that pick up no paint. `list_strokes {live: true}` → `update_stroke` /
|
|
207
|
+
`edit_stroke_points` / `reorder_stroke` / `remove_strokes`; `rasterize_stroke_layer` once settled.
|
|
204
208
|
- **Stencils**: `add_stencil` lays a `ruler` or `arc` (strokes that start within `snap` px follow
|
|
205
209
|
it exactly: straight lines, circles, rainbows) or a `line` / `shape` mask (paint lands only on
|
|
206
210
|
one side or inside a rect, ellipse or polygon; `invert` for outside). Stencils stay until
|
|
@@ -239,9 +243,11 @@ an overlay paints only where it has pixels.
|
|
|
239
243
|
1. `search_effects` (`use` generator, overlay or title) and `describe_effect` for the controls.
|
|
240
244
|
2. `set_effect_paint` with `effect`, `values` and `time` (ms, default 0). Wait for it: strokes that
|
|
241
245
|
would use it are refused while it renders.
|
|
242
|
-
3. Paint
|
|
243
|
-
|
|
244
|
-
|
|
246
|
+
3. Paint: dab, particle and bristle brushes take the colour per pixel (the most faithful); the
|
|
247
|
+
Mixer Brush and dab brushes with `behavior.pickup` take it per dab at its centre. Wet and
|
|
248
|
+
impasto brushes take it per pixel too, shifted by any paint they pick up: in watercolour and
|
|
249
|
+
gouache the pattern then flows, blooms and granulates with the water; impasto keeps its relief.
|
|
250
|
+
Sprayed stickers each take the colour at their centre (they stay recolourable).
|
|
245
251
|
4. `set_color` or `set_paint` goes back to colour; `remove_effect` (target and effect `paint`)
|
|
246
252
|
does too, and `update_effect` (target and effect `paint`, `values`) renders new values.
|
|
247
253
|
|
|
@@ -250,7 +256,8 @@ When to use which:
|
|
|
250
256
|
| Want | Use |
|
|
251
257
|
| --- | --- |
|
|
252
258
|
| The effect inside brushed marks, hand-painted edges | `set_effect_paint` and a dry brush |
|
|
253
|
-
| The effect
|
|
259
|
+
| The effect in a wash that flows, or in thick paint | `set_effect_paint` and a watercolour, gouache, oil or impasto brush |
|
|
260
|
+
| The effect inside an exact shape, unchanged by water | Paint the shape, dry it, then `fill_layer_with_effect` with `lockTransparency: true` |
|
|
254
261
|
| The effect over the whole sheet | `set_paper_effect` or `add_effect_layer` |
|
|
255
262
|
|
|
256
263
|
## Canvas-hosted layer
|
|
@@ -281,7 +288,7 @@ view), so work with the tools you are given.
|
|
|
281
288
|
| Tool | Use |
|
|
282
289
|
| --- | --- |
|
|
283
290
|
| `list_layers` | Read the layers top first: id, name, type (`pixel` / `group`), visible, opacity, blend, clipped, locks, `active`, painted `bounds` (null when empty), parent and depth. |
|
|
284
|
-
| `add_layer` | Add an empty pixel layer (or `type: "group"`) above the active layer, above `aboveId`, or at the top of group `parentId`; it becomes active. Returns the layer. Put each pass of a painting on its own layer. |
|
|
291
|
+
| `add_layer` | Add an empty pixel layer (or `type: "group"`, or `type: "strokes"` for a stroke layer whose strokes stay editable) above the active layer, above `aboveId`, or at the top of group `parentId`; it becomes active. Returns the layer. Put each pass of a painting on its own layer. |
|
|
285
292
|
| `update_layer` | Change `name`, `visible`, `opacity` (0..1), `blend`, `clipped` (clip to the layer below) or `locks` (`pixels`, `transparency`: paint only where there is paint, `position`, `all`). Returns the layer. |
|
|
286
293
|
| `list_blend_modes` | Read every blend mode: id, label, group (`standard`, `pigment`, `painterly`), what the pigment and painterly modes do, and the `psd` mode export writes instead. Read before choosing a painterly mode. Changes nothing. |
|
|
287
294
|
| `set_active_layer` | Make a layer the default target of strokes, fills and clears. Editor state. |
|
|
@@ -335,7 +342,14 @@ view), so work with the tools you are given.
|
|
|
335
342
|
| Tool | Use |
|
|
336
343
|
| --- | --- |
|
|
337
344
|
| `paint_stroke` | Paint one stroke through `points` (document px; `pressure` 0..1, `t` ms, `tiltX` / `tiltY` or `altitude` / `azimuth`, `twist`) with `brushId` (default the active brush), optional per-stroke `brush` changes, `color` or `paint` (a gradient for this stroke), `layerId`, `seed`, `snapToPerspective`. The symmetry guide adds its copies; a sampling tracing image supplies the colour when `color` is missing. Returns `layerId`, `bounds`, `dabs`, `strokeId` and, for brushes that pick up paint, `mixerLoad` (what the brush carries now). Refused on locked, hidden or group layers, with the fix in the message. |
|
|
338
|
-
| `list_strokes` | Read the recorded strokes, oldest first (default the last 100): id, layer, brush, colour, point count, seed, bounds
|
|
345
|
+
| `list_strokes` | Read the recorded strokes, oldest first (default the last 100): id, layer, brush, colour, point count, seed, bounds, `live`. With `ids`, their points too; with `layerId`, one layer's. With `live: true`, the editable strokes of stroke layers as they are now, bottom first: the ids for the stroke layer tools. |
|
|
346
|
+
| `stroke_at` | Read the top-most stroke of a stroke layer that painted the pixel at `x`, `y`, or null. Use it to pick one stroke among overlapping ones. |
|
|
347
|
+
| `update_stroke` | Change a stroke on a stroke layer: `brushId` (keeps its size), `brush` settings, `color`, `paint` (null drops a gradient), `seed`. Redraws exactly. One undo step. Returns the stroke and the changed `bounds`. |
|
|
348
|
+
| `edit_stroke_points` | Replace a stroke's `points`, or `transform` it (`dx`, `dy`, `scale`, `rotate`, `flipX`, about its centre or `origin`). One undo step. Returns the stroke with its points and the changed `bounds`. |
|
|
349
|
+
| `reorder_stroke` | Move a stroke to `index` in its stroke layer (0 = bottom). One undo step. Returns the order. |
|
|
350
|
+
| `remove_strokes` | Delete strokes from stroke layers (their eraser). One undo step. Returns the ids and `bounds`. |
|
|
351
|
+
| `convert_to_stroke_layer` | Make an empty pixel layer a stroke layer. Returns the layer. |
|
|
352
|
+
| `rasterize_stroke_layer` | Turn a stroke layer into a plain pixel layer with the same pixels (strokes no longer editable). Do it before erasing, smudging or filling on it. |
|
|
339
353
|
| `replay_strokes` | Paint recorded `strokeIds` again: exactly, or varied by `dx` / `dy` (px), `rotate` (degrees clockwise), `scale` (brush size follows), `flipX`, `origin`, `pressureScale`, `color`, `brushId`, `layerId`, `repeat` (each copy applies the variation again). One undo step. Returns the new stroke ids, bounds and layers. |
|
|
340
354
|
| `undo_paint` | Undo the last step (a wet stroke's undo puts the wet paint back as it was before it). Returns what was undone and what is next. |
|
|
341
355
|
| `redo_paint` | Redo the step just undone. |
|
|
@@ -481,10 +495,11 @@ The host may add the shared document tools (see `pixerate-agent-tools`). A paint
|
|
|
481
495
|
strokes record it, and replays render it again first, so they need the same provider (an
|
|
482
496
|
error names the effect and provider when it is missing; `color` on `replay_strokes` repaints
|
|
483
497
|
in one colour instead).
|
|
484
|
-
- **Effect paint
|
|
485
|
-
|
|
486
|
-
`lockTransparency: true`. Erasers, blenders and smudges ignore
|
|
487
|
-
gradient, a stroke `color` or `paint`, or `set_color` /
|
|
498
|
+
- **Effect paint in wet paint moves with the water**: the pattern bleeds and blooms like any
|
|
499
|
+
pigment, so fine detail softens. For a crisp pattern in an exact shape, paint the shape, dry it,
|
|
500
|
+
and `fill_layer_with_effect` with `lockTransparency: true`. Erasers, blenders and smudges ignore
|
|
501
|
+
effect paint; a brush with its own gradient, a stroke `color` or `paint`, or `set_color` /
|
|
502
|
+
`set_paint` paints colour instead.
|
|
488
503
|
- **Effect paint is fixed to the canvas, not the stroke**: a replayed or moved stroke shows the
|
|
489
504
|
part of the effect under its new place. Wait for `set_effect_paint` to return before painting;
|
|
490
505
|
strokes are refused while it renders.
|