@pixerate/editor 0.255.0 → 0.257.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 +40 -38
- package/dist/agent/index.js +9 -7
- package/dist/animation/index.cjs +4 -2
- package/dist/animation/index.js +4 -2
- package/dist/animation-editor/index.cjs +63 -61
- package/dist/animation-editor/index.js +7 -5
- package/dist/brushes/colour.d.cts +11 -0
- package/dist/brushes/colour.d.ts +11 -0
- package/dist/brushes/index.cjs +51 -30
- package/dist/brushes/index.d.cts +1 -0
- package/dist/brushes/index.d.ts +1 -0
- package/dist/brushes/index.js +25 -4
- package/dist/brushes/resolve.d.cts +2 -0
- package/dist/brushes/resolve.d.ts +2 -0
- package/dist/brushes/schema.d.cts +1 -0
- package/dist/brushes/schema.d.ts +1 -0
- package/dist/brushes/tools.d.cts +7 -0
- package/dist/brushes/tools.d.ts +7 -0
- package/dist/brushes/types.d.cts +10 -2
- package/dist/brushes/types.d.ts +10 -2
- package/dist/brushes/ui.d.cts +14 -3
- package/dist/brushes/ui.d.ts +14 -3
- package/dist/{brushstrokeRender-HCOQUSWW.js → brushstrokeRender-JI4W6F2G.js} +2 -2
- package/dist/{brushstrokeRender-ZZOXI5O5.cjs → brushstrokeRender-MQ6PSDM5.cjs} +11 -11
- package/dist/canvas/index.cjs +20 -18
- package/dist/canvas/index.js +7 -5
- package/dist/chart/index.cjs +159 -157
- package/dist/chart/index.js +9 -7
- package/dist/{chunk-7272D3K2.js → chunk-2EUW2XZX.js} +27 -276
- package/dist/{chunk-L6Y7TSQ4.js → chunk-2VJ6OVJV.js} +1 -1
- package/dist/{chunk-6ZZKRH7R.js → chunk-47V3WXDG.js} +2 -2
- package/dist/{chunk-H7ET2ISK.cjs → chunk-4IMD2TLY.cjs} +52 -52
- package/dist/{chunk-VUKUTT2W.js → chunk-4M4E3N6X.js} +1 -1
- package/dist/{chunk-TBAVCLEQ.cjs → chunk-5Q5MLXAD.cjs} +23 -23
- package/dist/{chunk-MONXNVZK.js → chunk-6I23ZCGK.js} +5 -3
- package/dist/{chunk-GOBOCZZI.js → chunk-6NQPKNUZ.js} +1 -1
- package/dist/{chunk-WYGSR3IJ.js → chunk-AORZ5M5C.js} +1 -1
- package/dist/chunk-AVTPZO4Z.cjs +142 -0
- package/dist/{chunk-WKMUBATU.js → chunk-C2WEIEUB.js} +1 -1
- package/dist/{chunk-P3K2JCJA.js → chunk-D5BXSOSU.js} +3 -3
- package/dist/chunk-E2V5DA3W.js +36 -0
- package/dist/{chunk-WZOGDKCQ.js → chunk-F7CPSRLN.js} +0 -133
- package/dist/chunk-FJBQTZS4.js +17 -0
- package/dist/{chunk-SOSBOS5T.cjs → chunk-G23BTQA5.cjs} +22 -22
- package/dist/{chunk-EUIDTZNQ.cjs → chunk-I3Y2Q3PM.cjs} +59 -308
- package/dist/{chunk-YHUMGBZD.js → chunk-ICTPLVSR.js} +22 -4
- package/dist/{chunk-LRNUZKWV.cjs → chunk-IPUTIUGQ.cjs} +1 -1
- package/dist/{chunk-6GRUVGKU.js → chunk-ITURMC2M.js} +3 -3
- package/dist/{chunk-HYWRU5VX.js → chunk-IXQZHCOF.js} +1 -1
- package/dist/chunk-J5UQHWVL.js +142 -0
- package/dist/{chunk-YBAPT7NL.js → chunk-JC2SHA4A.js} +1 -23
- package/dist/chunk-LRTR4ASZ.cjs +17 -0
- package/dist/{chunk-HUAISCUX.cjs → chunk-M2HG5DJ2.cjs} +18 -18
- package/dist/{chunk-N76AMOKE.cjs → chunk-MDLEGVEN.cjs} +42 -42
- package/dist/chunk-MEGSQUQO.cjs +36 -0
- package/dist/chunk-MLLTWAXH.cjs +276 -0
- package/dist/{chunk-RHPSE2YR.js → chunk-MQ6MGIQM.js} +2 -2
- package/dist/{chunk-PGPFWC35.cjs → chunk-MQGQTKVW.cjs} +51 -33
- package/dist/{chunk-5YWWQ36H.cjs → chunk-O3ZVZSNJ.cjs} +9 -9
- package/dist/{chunk-GCTUOTCW.cjs → chunk-P3PZ63M3.cjs} +35 -35
- package/dist/{chunk-WRZ6C4TU.cjs → chunk-P6WYDBTH.cjs} +4 -4
- package/dist/{chunk-CJ6TBL2N.cjs → chunk-RHEMMGCN.cjs} +16 -16
- package/dist/{chunk-HIMGBZAM.cjs → chunk-RSIKDWOP.cjs} +201 -38
- package/dist/{chunk-SABJMH6M.cjs → chunk-RVGP2XLF.cjs} +2 -135
- package/dist/{chunk-JVRLGV3C.js → chunk-SMTUQWGY.js} +184 -21
- package/dist/{chunk-DMTEQ6SH.js → chunk-SSFMWJDK.js} +4 -4
- package/dist/{chunk-TFF2GTGN.cjs → chunk-SXQHWXEL.cjs} +2 -24
- package/dist/{chunk-IWEVV63O.cjs → chunk-UEYLANO3.cjs} +18 -16
- package/dist/chunk-VR6OGHU5.js +276 -0
- package/dist/{chunk-AF23QK5F.js → chunk-YQ4PQTBB.js} +1 -1
- package/dist/{chunk-B7V34GIH.cjs → chunk-YSGW7VV4.cjs} +88 -88
- package/dist/{chunk-3NS5C7FB.cjs → chunk-YYBW6DF2.cjs} +76 -76
- package/dist/{chunk-UFEDHACQ.js → chunk-Z7BX4TWO.js} +2 -2
- package/dist/{chunk-RUONPPMC.cjs → chunk-ZSE25IZA.cjs} +8 -8
- package/dist/color/index.cjs +7 -3
- package/dist/color/index.js +18 -14
- package/dist/export/index.cjs +8 -6
- package/dist/export/index.js +7 -5
- package/dist/extensions/index.cjs +11 -9
- package/dist/extensions/index.js +10 -8
- package/dist/gradient/index.cjs +33 -31
- package/dist/gradient/index.js +5 -3
- package/dist/image-editor/brush-presets.d.cts +4 -1
- package/dist/image-editor/brush-presets.d.ts +4 -1
- package/dist/image-editor/controller.d.cts +10 -5
- package/dist/image-editor/controller.d.ts +10 -5
- package/dist/image-editor/index.cjs +1090 -1073
- package/dist/image-editor/index.js +37 -20
- package/dist/index.cjs +17 -15
- package/dist/index.js +11 -9
- package/dist/paint-editor/brushes.d.cts +18 -1
- package/dist/paint-editor/brushes.d.ts +18 -1
- package/dist/paint-editor/collaboration-tools.d.cts +19 -0
- package/dist/paint-editor/collaboration-tools.d.ts +19 -0
- package/dist/paint-editor/collaboration.d.cts +180 -0
- package/dist/paint-editor/collaboration.d.ts +180 -0
- package/dist/paint-editor/controller.d.cts +83 -0
- package/dist/paint-editor/controller.d.ts +83 -0
- package/dist/paint-editor/engine.d.cts +7 -0
- package/dist/paint-editor/engine.d.ts +7 -0
- package/dist/paint-editor/index.cjs +2027 -1331
- package/dist/paint-editor/index.d.cts +2 -0
- package/dist/paint-editor/index.d.ts +2 -0
- package/dist/paint-editor/index.js +1671 -975
- package/dist/paint-editor/mark-settings.d.cts +1 -1
- package/dist/paint-editor/mark-settings.d.ts +1 -1
- package/dist/paint-editor/procedural.d.cts +4 -2
- package/dist/paint-editor/procedural.d.ts +4 -2
- package/dist/paint-editor/stamp-tip.d.cts +45 -0
- package/dist/paint-editor/stamp-tip.d.ts +45 -0
- package/dist/paint-editor/stroke.d.cts +2 -0
- package/dist/paint-editor/stroke.d.ts +2 -0
- package/dist/stickers/index.cjs +4 -2
- package/dist/stickers/index.js +6 -4
- package/dist/typography/index.cjs +3 -2
- package/dist/typography/index.js +2 -1
- package/dist/vector/index.cjs +971 -969
- package/dist/vector/index.js +8 -6
- package/dist/video-editor/index.cjs +4 -2
- package/dist/video-editor/index.js +4 -2
- package/package.json +1 -1
- package/skills/pixerate-brushes/SKILL.md +21 -11
- package/skills/pixerate-brushes-design/SKILL.md +6 -2
- package/skills/pixerate-brushes-design/evals/canvas-chalk.json +8 -8
- package/skills/pixerate-canvas/SKILL.md +3 -2
- package/skills/pixerate-image-editor/SKILL.md +1 -1
- package/skills/pixerate-paint-editor/SKILL.md +35 -47
- package/skills/pixerate-paint-editor/references/painting-alongside.md +19 -0
- package/skills/pixerate-vector/SKILL.md +1 -1
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-4M4E3N6X.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-IXQZHCOF.js";
|
|
57
57
|
import {
|
|
58
58
|
DEFAULT_VECTOR_FONT,
|
|
59
59
|
IDENTITY_MATRIX,
|
|
@@ -528,10 +528,10 @@ import {
|
|
|
528
528
|
withVectorStrokes,
|
|
529
529
|
withVectorTargetPaint,
|
|
530
530
|
zigzagPaths
|
|
531
|
-
} from "../chunk-
|
|
531
|
+
} from "../chunk-YQ4PQTBB.js";
|
|
532
532
|
import {
|
|
533
533
|
snapshotBrushLibrary
|
|
534
|
-
} from "../chunk-
|
|
534
|
+
} from "../chunk-SMTUQWGY.js";
|
|
535
535
|
import "../chunk-APX63ILU.js";
|
|
536
536
|
import {
|
|
537
537
|
createProvenance
|
|
@@ -599,8 +599,10 @@ import "../chunk-M2TPMYJE.js";
|
|
|
599
599
|
import {
|
|
600
600
|
hexToRgba
|
|
601
601
|
} from "../chunk-2WPNAGHI.js";
|
|
602
|
-
import "../chunk-
|
|
603
|
-
import "../chunk-
|
|
602
|
+
import "../chunk-2EUW2XZX.js";
|
|
603
|
+
import "../chunk-E2V5DA3W.js";
|
|
604
|
+
import "../chunk-VR6OGHU5.js";
|
|
605
|
+
import "../chunk-JC2SHA4A.js";
|
|
604
606
|
import "../chunk-MHLU6GRJ.js";
|
|
605
607
|
import "../chunk-6ONMQ6WF.js";
|
|
606
608
|
|
|
@@ -189,8 +189,10 @@ var _chunkM5GLQQWGcjs = require('../chunk-M5GLQQWG.cjs');
|
|
|
189
189
|
var _chunkDWJJI6RTcjs = require('../chunk-DWJJI6RT.cjs');
|
|
190
190
|
require('../chunk-4ZC5QJE2.cjs');
|
|
191
191
|
require('../chunk-A6QWKBJP.cjs');
|
|
192
|
-
require('../chunk-
|
|
193
|
-
require('../chunk-
|
|
192
|
+
require('../chunk-I3Y2Q3PM.cjs');
|
|
193
|
+
require('../chunk-MEGSQUQO.cjs');
|
|
194
|
+
require('../chunk-MLLTWAXH.cjs');
|
|
195
|
+
require('../chunk-SXQHWXEL.cjs');
|
|
194
196
|
require('../chunk-5UEFBM2M.cjs');
|
|
195
197
|
require('../chunk-IPJ3TEYR.cjs');
|
|
196
198
|
|
|
@@ -189,8 +189,10 @@ import {
|
|
|
189
189
|
} from "../chunk-5UJHB3BW.js";
|
|
190
190
|
import "../chunk-M2TPMYJE.js";
|
|
191
191
|
import "../chunk-2WPNAGHI.js";
|
|
192
|
-
import "../chunk-
|
|
193
|
-
import "../chunk-
|
|
192
|
+
import "../chunk-2EUW2XZX.js";
|
|
193
|
+
import "../chunk-E2V5DA3W.js";
|
|
194
|
+
import "../chunk-VR6OGHU5.js";
|
|
195
|
+
import "../chunk-JC2SHA4A.js";
|
|
194
196
|
import "../chunk-MHLU6GRJ.js";
|
|
195
197
|
import "../chunk-6ONMQ6WF.js";
|
|
196
198
|
|
package/package.json
CHANGED
|
@@ -15,20 +15,23 @@ built-in presets (read-only) and the user's brushes, shared by every editor that
|
|
|
15
15
|
| Kind | `mark` lays a material; `tool` works on paint already down. |
|
|
16
16
|
| Medium and variety | Marks: what it lays (`paint`, `ink`, `dry`, `spray`) and what kind (`oil`, `watercolor`, `gouache`, `pencil`, `charcoal`, `airbrush`, `marker`, `highlighter`…). Descriptive, for finding brushes; a wet brush whose variety is `watercolor`, `gouache` or `oil` paints that medium. |
|
|
17
17
|
| Tool | Tools: `eraser`, `blender`, `smudge`, and on wet paint `water`, `dryer`, `blow`, `blot`, `wet-blend`, `wet-drag`. |
|
|
18
|
-
| Tip | `shape` (`round`, `flat`, `chisel` are ellipses set by `roundness` and `angle`; `bristle` has a tuft; `stamp`
|
|
19
|
-
| Marks | `continuous` dabs (default), `particles` (strands, springs, ribbons, sparks) or `objects` (each mark an editable sticker). |
|
|
18
|
+
| Tip | `shape` (`round`, `flat`, `chisel` are ellipses set by `roundness` and `angle`; `bristle` has a tuft; `stamp` takes the shape of `stamps`: an editor stamp `editor:star` or any sticker ref from `find_stickers`), size in px, hardness, spacing, opacity, flow, blend mode. |
|
|
19
|
+
| Marks | `continuous` dabs (default; on a stamp tip every dab is the first stamp's shape, in the paint colour), `scatter` (a spray: droplets across the tip, `density`, `size`), `particles` (strands, springs, ribbons, sparks; textured dots from the stamps) or `objects` (each mark an editable sticker, in its own colours). |
|
|
20
20
|
| Dynamics | Pen feel: pressure to size and opacity, smoothing, tilt, velocity, jitter, rotation. |
|
|
21
21
|
| Behaviour | `surface` `dry`, `wet` (`wet` settings) or `thick` (`thick` impasto settings); paper `grain`; `exchange` (pick-up and mix; a `reservoir` makes a Mixer Brush); tool `strength`. |
|
|
22
22
|
| Light | Light the brush gives off (`amount`), plus suggested layer `spill` and `glow`. |
|
|
23
23
|
| Motion | Animation after painting (live effect paint, particle `waveSpeed`). |
|
|
24
|
-
| Colour | A `default` colour, a `palette` of up to 16, `own` (always its own colour). A gradient default is always painted; a solid
|
|
24
|
+
| Colour | A `default` colour, a `palette` of up to 16, `own` (always its own colour). Each is a hex or `rgba()` colour, a light / dark pair `{ light, dark }`, a gradient or effect paint. A gradient default is always painted; a solid or light / dark default becomes the editor's colour when the brush is chosen (unless the user locked theirs), resolved for the colour scheme. |
|
|
25
25
|
|
|
26
26
|
How media map to facets: a **pencil** or **charcoal** is `dry` with high `grain` and tilt;
|
|
27
27
|
**ink** is a hard round tip with pressure to size (a pen thins with velocity); **watercolour**
|
|
28
28
|
and **wet oil** are `paint` on `surface: 'wet'`; **impasto** is `surface: 'thick'`; an
|
|
29
|
-
**airbrush** is `spray`, soft and low flow; a **
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
**airbrush** is `spray`, soft and low flow; a **spray can** is `spray` with `marks` scatter; a
|
|
30
|
+
**ballpoint**, **gel pen** or **fineliner** is `ink` with a small hard tip (a fineliner without
|
|
31
|
+
pressure to size); **crayon** and **chalk** are `dry` with high `grain`; a **highlighter** is
|
|
32
|
+
`ink` / `highlighter`, a multiply chisel tip with a little light, `spill` radius 0, fluorescent
|
|
33
|
+
yellow by default; a **stamp brush** is a `stamp` tip with continuous marks; **particle** and
|
|
34
|
+
**sticker** brushes are `marks` particles or objects on a `stamp` tip.
|
|
32
35
|
|
|
33
36
|
## Host profiles
|
|
34
37
|
|
|
@@ -74,16 +77,23 @@ drawn.
|
|
|
74
77
|
glow stays on the stroke.
|
|
75
78
|
- Keep `variety` truthful (it is how people find the brush) and add `tags` for the job
|
|
76
79
|
(`lettering`, `foliage`).
|
|
77
|
-
-
|
|
80
|
+
- Give a brush a `colour.default` only when the medium has a typical colour (blue ballpoint,
|
|
81
|
+
yellow highlighter): choosing the brush sets it as the user's colour. Use a light / dark pair
|
|
82
|
+
when the right colour depends on the background (white chalk on a dark board, graphite on
|
|
83
|
+
paper), and a `palette` for the other usual colours. `colour.own` only for brushes that must
|
|
78
84
|
always paint their own (a rainbow marker).
|
|
85
|
+
- Stamp tips paint the sticker's shape in the paint colour; to keep a sticker's own colours, use
|
|
86
|
+
`marks` objects instead.
|
|
79
87
|
|
|
80
88
|
## Pitfalls
|
|
81
89
|
|
|
82
90
|
- **A facet the host refuses.** `create_brush` and `update_brush` refuse it with the facet and
|
|
83
91
|
fix; `check_brush` returns `degraded`, the brush with those facets stripped, to start from.
|
|
84
92
|
- **Ids.** Built-in ids can't be reused or changed; a taken id is refused (update it instead).
|
|
85
|
-
- **Stamps.**
|
|
86
|
-
|
|
93
|
+
- **Stamps.** Any marks take any sticker ref from `find_stickers`, or an editor stamp
|
|
94
|
+
(`editor:star`…). A ref the host's sticker library can't load is refused with the closest
|
|
95
|
+
refs. Only the paint editor renders stamp tips and scatter marks; canvas, vector and the image
|
|
96
|
+
editor refuse them (`check_brush` says so).
|
|
87
97
|
- **Out-of-range values** are refused by the schema (`tip.size` is 1..2500 px); a stored brush
|
|
88
98
|
is clamped on import and reported in `problems`.
|
|
89
99
|
- **The paint editor paints from this library.** Its `set_brush` picks a brush by id here and
|
|
@@ -101,8 +111,8 @@ drawn.
|
|
|
101
111
|
| Tool | Use |
|
|
102
112
|
| --- | --- |
|
|
103
113
|
| `list_brush_presets` | Find brushes this host renders: `kind`, `medium`, `variety`, `tool`, `tag`, `text`, `source` (all, builtin, user), `all`, `offset`, `limit`. Returns `brushes` (id, name, builtin, kind, medium, variety or tool, category, engine, tip, size, marks, surface, light) and `total`. Call first. |
|
|
104
|
-
| `describe_brush` | One brush by `id`: its full facet `brush
|
|
105
|
-
| `create_brush` | Save a new brush: `id`, `name`, optional `basedOn`, and the facets (to keep an editor's current brush, pass the `brush` its `get_brush` returns). Normalised and checked for this host; refused brushes save nothing. Returns `id`, `brush`, `engine`, `problems`, `warnings`. |
|
|
114
|
+
| `describe_brush` | One brush by `id`: its full facet `brush` (with its `colour`: default, palette, own), `builtin`, `engine`, `category` and `check` for this host (stamp stickers included). Unknown ids are refused with the closest ones. |
|
|
115
|
+
| `create_brush` | Save a new brush: `id`, `name`, optional `basedOn`, and the facets, `colour` included (to keep an editor's current brush, pass the `brush` its `get_brush` returns). Normalised and checked for this host (and its sticker library, for stamp tips); refused brushes save nothing. Returns `id`, `brush`, `engine`, `problems`, `warnings`. |
|
|
106
116
|
| `update_brush` | Change a saved brush: facets to merge in, `unset` facets to drop. Refuses built-ins (duplicate first) and changes the host can't render. Returns `brush`, `changed` paths, `problems`, `warnings`. |
|
|
107
117
|
| `duplicate_brush` | Copy any brush, built-ins included, to a saved brush (`newId` default `<id>-copy`, `name`). Returns the new `id` and `brush`; then `update_brush` it. |
|
|
108
118
|
| `remove_brush` | Delete a saved brush for good (export it first to keep a copy). Built-ins are refused. Returns `removed`. |
|
|
@@ -57,6 +57,9 @@ Ask when you cannot tell from the request; say what you assumed when you can.
|
|
|
57
57
|
| A brush that must work in another editor | `check_brush` with that `host`, then `create_brush` from its `degraded` brush under a new id. |
|
|
58
58
|
| A texture (chalk, charcoal, dry brush) | Raise `behaviour.grain` (0.8..1) and add `dynamics.sizeJitter`; test on rough paper. |
|
|
59
59
|
| A light brush (neon, glow) | `light.amount`, and paint it on dark paper; a highlighter keeps `light.spill.radius` 0. |
|
|
60
|
+
| A colour that depends on the background (chalk, white ink) | `colour.default` as a light / dark pair `{ light, dark }`: the editor takes the side for its colour scheme when the brush is chosen. |
|
|
61
|
+
| A shape as the tip (stars, leaves, a logo) | `tip.shape` stamp with `stamps` (an editor stamp or a ref from `find_stickers`), continuous marks; it paints in the user's colour. Keep the sticker's colours with `marks` objects. Paint editor only. |
|
|
62
|
+
| A spray can or mist | `basedOn` `spray-can`, or `medium` spray with `marks` scatter (`density`, `size`). Paint editor only. |
|
|
60
63
|
| A change to a built-in | `duplicate_brush`, then `update_brush` the copy. |
|
|
61
64
|
|
|
62
65
|
## Recipes
|
|
@@ -64,8 +67,9 @@ Ask when you cannot tell from the request; say what you assumed when you can.
|
|
|
64
67
|
**A pink highlighter.** `create_brush` `{ id: "pink-highlighter", name: "Pink highlighter",
|
|
65
68
|
basedOn: "highlighter", colour: { default: "#ff6ec7" } }`, then `check_brush`.
|
|
66
69
|
|
|
67
|
-
**Chalk for canvas strokes.** On the canvas host, `create_brush`
|
|
68
|
-
|
|
70
|
+
**Chalk on a blackboard, for canvas strokes.** On the canvas host, `create_brush`
|
|
71
|
+
`{ id: "board-chalk", name: "Board chalk", basedOn: "chalk", colour: { default: { light:
|
|
72
|
+
"#334155", dark: "#f8fafc" } } }`: white chalk in dark mode, slate on light paper.
|
|
69
73
|
|
|
70
74
|
**Port a wet brush to vector.** `check_brush` `{ id, host: "vector" }`; `create_brush` from the
|
|
71
75
|
`degraded` brush with `id` `<id>-vector`; `check_brush` again.
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
|
-
"prompt": "I'm drawing brushed strokes on the canvas. Make a
|
|
2
|
+
"prompt": "I'm drawing brushed strokes on the canvas, on a dark blackboard in dark mode and on paper in light mode. Make a grainy chalk brush with the id board-chalk that the canvas can use: near-white chalk in dark mode, a dark slate on light backgrounds.",
|
|
3
3
|
"fixture": { "editor": "brushes", "host": "canvas" },
|
|
4
4
|
"checks": [
|
|
5
|
-
{ "why": "the canvas can render it", "tool": "check_brush", "args": { "id": "chalk", "host": "canvas" }, "expect": { "ok": true } },
|
|
6
|
-
{ "why": "a dry chalk", "tool": "describe_brush", "args": { "id": "chalk" }, "expect": { "brush": { "kind": "mark", "medium": "dry", "variety": "chalk" } } },
|
|
7
|
-
{ "why": "it catches the paper grain strongly", "tool": "describe_brush", "args": { "id": "chalk" }, "expect": { "brush": { "behaviour": { "grain": { "$min": 0.8 } } } } },
|
|
8
|
-
{ "why": "
|
|
5
|
+
{ "why": "the canvas can render it", "tool": "check_brush", "args": { "id": "board-chalk", "host": "canvas" }, "expect": { "ok": true } },
|
|
6
|
+
{ "why": "a dry chalk", "tool": "describe_brush", "args": { "id": "board-chalk" }, "expect": { "brush": { "kind": "mark", "medium": "dry", "variety": "chalk" } } },
|
|
7
|
+
{ "why": "it catches the paper grain strongly", "tool": "describe_brush", "args": { "id": "board-chalk" }, "expect": { "brush": { "behaviour": { "grain": { "$min": 0.8 } } } } },
|
|
8
|
+
{ "why": "its default colour is a light / dark pair: light chalk on dark, dark on light", "tool": "describe_brush", "args": { "id": "board-chalk" }, "expect": { "brush": { "colour": { "default": { "$expr": "typeof v === 'object' && /^#[c-f]/i.test(v.dark) && /^#[0-6]/i.test(v.light)" } } } } }
|
|
9
9
|
],
|
|
10
10
|
"solution": [
|
|
11
|
-
{ "tool": "list_brush_presets", "args": { "
|
|
12
|
-
{ "tool": "create_brush", "args": { "id": "chalk", "name": "
|
|
13
|
-
{ "tool": "check_brush", "args": { "id": "chalk", "host": "canvas" } }
|
|
11
|
+
{ "tool": "list_brush_presets", "args": { "variety": "chalk" } },
|
|
12
|
+
{ "tool": "create_brush", "args": { "id": "board-chalk", "name": "Board chalk", "basedOn": "chalk", "colour": { "default": { "light": "#334155", "dark": "#f8fafc" } } } },
|
|
13
|
+
{ "tool": "check_brush", "args": { "id": "board-chalk", "host": "canvas" } }
|
|
14
14
|
]
|
|
15
15
|
}
|
|
@@ -94,8 +94,9 @@ you to. Withdraw stale ones with `reject_proposal`: when the user changes what a
|
|
|
94
94
|
use the preset's own size (`canvas.listBrushes` gives it); pass it only to make the mark finer
|
|
95
95
|
or bolder.
|
|
96
96
|
- **Brush character.** Each preset draws with its own character: charcoal and pastel are broad and
|
|
97
|
-
grainy (they catch the paper's tooth),
|
|
98
|
-
|
|
97
|
+
grainy (they catch the paper's tooth), as are crayon and chalk; pencil is fine and slightly
|
|
98
|
+
grainy; ink, marker, brush pen, ballpoint, gel pen and fineliner are clean (the fineliner keeps
|
|
99
|
+
one width), the airbrush is a soft spray. The grain and jitter are seeded per stroke, so a
|
|
99
100
|
stroke always looks the same, and neighbouring strokes share one sheet of paper. Pick the brush
|
|
100
101
|
for the look, then the colour; for a sketch, use one or two brushes rather than all of them.
|
|
101
102
|
- **Annotate with gestures, not points.** To mark up work the way a designer marks up a print,
|
|
@@ -314,7 +314,7 @@ in the source frame at the document's bit depth, colour mode and profile. Read
|
|
|
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
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
|
|
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: pencils, pastels, charcoal, crayon, chalk, markers, ink pens, ballpoint, gel pen, fineliner, the airbrush, the Mixer Brush, erasers). Sets the paint tool it needs (`brush`, `mixer` for a Mixer Brush, `eraser`), its brush and mixer settings, a brush's own gradient, and its default colour as the foreground (`keepColour` keeps yours; `colorScheme` picks the side of a light / dark colour). 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. |
|
|
318
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`. |
|
|
319
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. |
|
|
320
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. |
|
|
@@ -11,6 +11,9 @@ seed: its grain is a height map (peaks and valleys) that grain-responsive brushe
|
|
|
11
11
|
is never part of a layer. Coordinates are document pixels, (0, 0) top-left, y down. See
|
|
12
12
|
`pixerate-agent-tools` for errors, namespacing and batching.
|
|
13
13
|
|
|
14
|
+
- **Brush colours.** Choosing a brush with a default colour (highlighter yellow, ballpoint
|
|
15
|
+
blue, chalk light or dark for the colour scheme) makes it the paint colour, unless the colour is
|
|
16
|
+
locked (`set_color` `locked`). Set the colour after choosing the brush, or lock it first.
|
|
14
17
|
- **Brushes** come from the shared brush library (`pixerate-brushes`: `list_brush_presets`,
|
|
15
18
|
`create_brush`, `preview_brush`…) and are made of facets: a tip (size, hardness, spacing, angle,
|
|
16
19
|
roundness, opacity, flow, blend), dynamics (pressure, tilt, velocity, jitter, a **rotation**
|
|
@@ -101,58 +104,32 @@ the pitfalls, and uses the tools below.
|
|
|
101
104
|
|
|
102
105
|
## Best practices
|
|
103
106
|
|
|
104
|
-
- **Big to small, dark to light (or light to dark), one decision per layer.** Name layers by
|
|
105
|
-
|
|
106
|
-
- **
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
- **
|
|
110
|
-
ink or brush pen: velocity dynamics thin fast strokes. Without `t` there is no velocity effect.
|
|
111
|
-
- **Tilt** (`altitude` near 0.3..0.6 radians with an `azimuth`) turns a pencil into broad side
|
|
112
|
-
shading; upright points draw a fine line.
|
|
113
|
-
- **Space points** about a third of the brush size apart or closer; the brush fills in dabs
|
|
114
|
-
between them. Long smooth curves need more points than straight lines.
|
|
115
|
-
- **Use `rotation: "stroke"`** for flat tips (pastel, charcoal, chisel marker) so the mark turns
|
|
116
|
-
with the path; `fixed` for calligraphic nibs.
|
|
107
|
+
- **Big to small, dark to light (or light to dark), one decision per layer.** Name layers by purpose ("Underpainting", "Shadows", "Line"). Lower a layer's `opacity` instead of repainting.
|
|
108
|
+
- **Pressure is your value control** on grainy media: points with `pressure` 0.2..0.4 give texture-catching, broken marks; 0.8..1 fills the grain. Vary pressure along a stroke (swell in the middle, lighten at the ends) for natural marks.
|
|
109
|
+
- **Give points a time `t`** (milliseconds, about 8..16 ms apart for natural speed) when using an ink or brush pen: velocity dynamics thin fast strokes. Without `t` there is no velocity effect.
|
|
110
|
+
- **Tilt** (`altitude` near 0.3..0.6 radians with an `azimuth`) turns a pencil into broad side shading; upright points draw a fine line.
|
|
111
|
+
- **Space points** about a third of the brush size apart or closer; the brush fills in dabs between them. Long smooth curves need more points than straight lines.
|
|
112
|
+
- **Use `rotation: "stroke"`** for flat tips (pastel, charcoal, chisel marker) so the mark turns with the path; `fixed` for calligraphic nibs.
|
|
117
113
|
- **Blending tools**:
|
|
118
|
-
- `blender`: `strength` 0.3..0.6 for soft transitions, `distance` 0.2..0.5 (fraction of the
|
|
119
|
-
|
|
120
|
-
blends like a soft blur. Work along an edge in short strokes rather than over everything.
|
|
121
|
-
- `smudge`: `length` near 0.9 drags paint far (long streaks), 0.5 short pushes; `strength`
|
|
122
|
-
0.5..0.8. `mixing: "pigment"` (the `wet-smudge` preset) smears colours into each other like
|
|
123
|
-
wet paint.
|
|
114
|
+
- `blender`: `strength` 0.3..0.6 for soft transitions, `distance` 0.2..0.5 (fraction of the tip) for how far colours travel. Keep `mixing: "pigment"` for painterly blends; `rgb` blends like a soft blur. Work along an edge in short strokes rather than over everything.
|
|
115
|
+
- `smudge`: `length` near 0.9 drags paint far (long streaks), 0.5 short pushes; `strength` 0.5..0.8. `mixing: "pigment"` (the `wet-smudge` preset) smears colours into each other like wet paint.
|
|
124
116
|
- Mixer Brush: blend with flow 0.3..0.6; at full flow it paints only its own colour.
|
|
125
|
-
- **Pick-up and mix ratios**: `pickup` 0.3..0.7 with `mix` 0.4..0.7 gives a brush that drags
|
|
126
|
-
the colours it crosses into its own; `dirty: true` keeps them for the next stroke (wipe with
|
|
117
|
+
- **Pick-up and mix ratios**: `pickup` 0.3..0.7 with `mix` 0.4..0.7 gives a brush that drags the colours it crosses into its own; `dirty: true` keeps them for the next stroke (wipe with
|
|
127
118
|
`clean_mixer_brush`). Keep `pickup` 0 for clean, predictable colour.
|
|
128
|
-
- **Multi-colour**: give 2..8 `colors` (or none for the paint and secondary colours). `tip` mode
|
|
129
|
-
with a flat tip and `rotation: "stroke"` paints ribbons; `softness` 0.3..0.7 keeps the stripes
|
|
130
|
-
readable. `dab` mode with `order: "sequence"` and `length` 5..20 walks through a palette;
|
|
119
|
+
- **Multi-colour**: give 2..8 `colors` (or none for the paint and secondary colours). `tip` mode with a flat tip and `rotation: "stroke"` paints ribbons; `softness` 0.3..0.7 keeps the stripes readable. `dab` mode with `order: "sequence"` and `length` 5..20 walks through a palette;
|
|
131
120
|
`random` for foliage and confetti.
|
|
132
|
-
- **Pigment for paint, multiply for markers**: tip `blend: "pigment"` mixes subtractively on the
|
|
133
|
-
canvas; `multiply` darkens where marker strokes overlap. Pigment layers are written as Normal
|
|
134
|
-
to PSD (the export warns).
|
|
121
|
+
- **Pigment for paint, multiply for markers**: tip `blend: "pigment"` mixes subtractively on the canvas; `multiply` darkens where marker strokes overlap. Pigment layers are written as Normal to PSD (the export warns).
|
|
135
122
|
- **Painterly layer modes do the glazing for you** (`update_layer` `blend`, or a brush tip):
|
|
136
|
-
- `watercolor`: the layer is a transparent wash. Washes multiply wavelength by wavelength, so
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
- `
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
- `shadow`: shades as if light were blocked, coloured by the layer (paint shadows in a cool
|
|
144
|
-
blue-violet), never crushing to black. White does nothing.
|
|
145
|
-
|
|
146
|
-
PSD has none of them: `export_psd` writes the nearest standard mode (watercolor and shadow
|
|
147
|
-
as Multiply, tint as Color, highlight as Screen) and warns; the merged image stays exact.
|
|
148
|
-
- **Grow the canvas instead of starting big** with `extend_canvas` (pixels per side; nothing
|
|
149
|
-
painted moves relative to anything else). Adding `left` or `top` shifts every coordinate you
|
|
150
|
-
hold by (+left, +top): re-read `list_layers` or use the returned `rect`. Dry wet paint first.
|
|
123
|
+
- `watercolor`: the layer is a transparent wash. Washes multiply wavelength by wavelength, so each glaze darkens and blue over yellow makes green. White is clear: paint glazes on a layer over the underpainting, at opacity 0.4..0.8.
|
|
124
|
+
- `tint`: recolours what is below (its hue and chroma) and keeps its lightness, gently near white and black. Use it to warm or cool a whole passage.
|
|
125
|
+
- `highlight`: adds coloured light that rolls off towards white instead of clipping. Use it for glints and glow; black does nothing.
|
|
126
|
+
- `shadow`: shades as if light were blocked, coloured by the layer (paint shadows in a cool blue-violet), never crushing to black. White does nothing.
|
|
127
|
+
|
|
128
|
+
PSD has none of them: `export_psd` writes the nearest standard mode (watercolor and shadow as Multiply, tint as Color, highlight as Screen) and warns; the merged image stays exact.
|
|
129
|
+
- **Grow the canvas instead of starting big** with `extend_canvas` (pixels per side; nothing painted moves relative to anything else). Adding `left` or `top` shifts every coordinate you hold by (+left, +top): re-read `list_layers` or use the returned `rect`. Dry wet paint first.
|
|
151
130
|
`set_canvas` only crops or grows at the bottom-right.
|
|
152
|
-
- **Save brushes you build** in the brush library: `create_brush` with `basedOn` and the facets
|
|
153
|
-
|
|
154
|
-
`export_brushes` / `import_brushes`. A saved brush shows in every editor that shares the
|
|
155
|
-
library; `set_brush` its id to paint with it.
|
|
131
|
+
- **Save brushes you build** in the brush library: `create_brush` with `basedOn` and the facets you changed (or `get_brush` then `create_brush` with its `brush`), and share them with
|
|
132
|
+
`export_brushes` / `import_brushes`. A saved brush shows in every editor that shares the library; `set_brush` its id to paint with it.
|
|
156
133
|
|
|
157
134
|
Which facet sets which engine setting: [references/brush-facets.md](references/brush-facets.md).
|
|
158
135
|
|
|
@@ -272,6 +249,17 @@ is a canvas coordinate: read [references/canvas-hosted.md](references/canvas-hos
|
|
|
272
249
|
| `get_paper` | Read every setting of the current paper (pattern, seed, scale, tiling, depth, shading, dry and wet tuning, and `metallic`, `backlight`, `backlightColor` when set). |
|
|
273
250
|
| `set_paper` | Change the paper: `preset`, then any of `color`, `depth` (0..1), `scale` (0.25..8), `seed` (another sheet), `pattern`, `tiling`, `shading`, `dry` / `wet` tuning (`contrast` 0..3, `invert`), `metallic`, `backlight` (0..1, light from behind: glazes glow, opaque paint blocks; preset `stained-glass`) and `backlightColor`. Affects new strokes' grain and how the paper shows; strokes already painted keep their pixels. Returns the paper. |
|
|
274
251
|
|
|
252
|
+
### Suggesting paint
|
|
253
|
+
|
|
254
|
+
Contributing while the user paints: suggest, don't paint. Read [references/painting-alongside.md](references/painting-alongside.md).
|
|
255
|
+
|
|
256
|
+
| Tool | Use |
|
|
257
|
+
| --- | --- |
|
|
258
|
+
| `propose_paint` | Suggest paint as a ghost the user accepts or dismisses: `title`, `rationale`, `ops` (`stroke` with points and a dry brush, `wash` over its layer, `echo` of stroke ids moved / turned / scaled / repeated) and where its new layer goes (`place` top, bottom or above `layerId`). Returns the proposal id, the ghost's `bounds` and the strokes it echoes. Use it for contributions the user didn't ask for. |
|
|
259
|
+
| `list_paint_proposals` | Read the pending paint proposals: id, title, rationale, who proposed it, op kinds, placement, bounds, the strokes it echoes and any since removed (`missing`), and whether accepting is allowed. Call before accepting or rejecting. |
|
|
260
|
+
| `accept_paint_proposal` | Paint a pending proposal on a new layer as one undo step recorded as the proposer's (`proposalId`). Only when the user said yes. Returns the layer id, stroke ids and undo step name. Refuses when a stroke it echoes is gone. |
|
|
261
|
+
| `reject_paint_proposal` | Dismiss a pending proposal (`proposalId`); nothing changes. Use it to withdraw a suggestion that no longer fits. Returns the id and title. |
|
|
262
|
+
|
|
275
263
|
### Layers
|
|
276
264
|
|
|
277
265
|
| Tool | Use |
|
|
@@ -307,7 +295,7 @@ Listing, saving, sharing and previewing brushes are the brush library's tools (`
|
|
|
307
295
|
| Tool | Use |
|
|
308
296
|
| --- | --- |
|
|
309
297
|
| `mix_colors` | Predict a mix: `colors` with `weight` parts (and optional tinting `strength`), `model` `pigment` (default, Kubelka-Munk: what pigment blends, the Mixer Brush, pigment blending tools and the pad do) or `rgb` (what normal blending and rgb mixing do). Returns `mixed` by the model plus `pigment` and `rgbLerp` for comparison. Changes nothing. Use it to choose stroke colours. |
|
|
310
|
-
| `set_color` | Set the default paint `color` (and `secondaryColor`); back to one colour after gradient paint or effect paint. |
|
|
298
|
+
| `set_color` | Set the default paint `color` (and `secondaryColor`); back to one colour after gradient paint or effect paint. `locked: true` keeps it when you choose a brush with a default colour (by default choosing the highlighter makes your colour its yellow). Returns both colours and `locked`. |
|
|
311
299
|
| `set_paint` | Set the paint: one colour, or gradient paint (`stops`, `space`, `map`, `softness`; see Gradient paint). Ends effect paint. Errors say what is wrong (unsorted stops, a bad mapping). Returns `paint`, `color`, `secondaryColor`. |
|
|
312
300
|
| `pick_color` | Read the colour at `x`, `y`: of the painting with its paper, or of one layer (with alpha). |
|
|
313
301
|
| `get_mixer_brush` | Read what the brush carries: the Mixer Brush `reservoir` and `amount` left, and `pickup` (paint picked up, kept by dirty brushes). |
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Painting alongside the user
|
|
2
|
+
|
|
3
|
+
When the user is painting and you contribute on your own initiative, **suggest, don't paint**:
|
|
4
|
+
`propose_paint` shows your idea as a ghost over the canvas, and the user accepts or dismisses it.
|
|
5
|
+
Accepted, it lands on a new layer of its own as one undo step recorded as yours, and the user's
|
|
6
|
+
active layer stays theirs. Paint directly only when asked to.
|
|
7
|
+
|
|
8
|
+
- **Play to what agents do well**: a `wash` (a warm ground with `place: "bottom"`, a glaze over a
|
|
9
|
+
passage), an `echo` of the user's own strokes (grass along the horizon, rain, hatching, a
|
|
10
|
+
repeated motif: `list_strokes` for the ids, then `dx` / `dy` / `rotate` / `scale` / `repeat`),
|
|
11
|
+
or a few deliberate `stroke`s. Not a stroke-by-stroke rendering of a subject.
|
|
12
|
+
- **Small and complementary.** One idea per proposal, with a `title` that says what it adds and a
|
|
13
|
+
`rationale` that says why it fits what the user just painted.
|
|
14
|
+
- **Dry brushes only** (dab, particle, bristle or mixer without pickup). Suggestions are previewed
|
|
15
|
+
and painted on their own layer, which wet paint, thick paint and pickup can't do.
|
|
16
|
+
- **Withdraw what no longer fits** with `reject_paint_proposal`; an echo whose strokes the user
|
|
17
|
+
removed can't be accepted (`missing` in `list_paint_proposals`).
|
|
18
|
+
|
|
19
|
+
The tools are `propose_paint`, `list_paint_proposals`, `accept_paint_proposal` and `reject_paint_proposal` (see SKILL.md, Suggesting paint).
|
|
@@ -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 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. |
|
|
376
|
+
| `vector.listBrushes` | List the brushes a brushstroke can use: the dry presets (pencils, pastels, charcoal, crayon, chalk, markers, inks, ballpoint, gel pen, fineliner), 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
|
|