@pixerate/editor 0.270.0 → 0.272.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/animation-editor/index.cjs +62 -62
- package/dist/animation-editor/index.js +5 -5
- package/dist/brushes/index.cjs +69 -66
- package/dist/brushes/index.js +6 -3
- package/dist/brushes/patch.d.cts +1 -1
- package/dist/brushes/patch.d.ts +1 -1
- package/dist/brushes/schema.d.cts +1 -0
- package/dist/brushes/schema.d.ts +1 -0
- package/dist/brushes/types.d.cts +8 -0
- package/dist/brushes/types.d.ts +8 -0
- package/dist/{brushstrokeRender-WR2N5HHY.cjs → brushstrokeRender-5YBCLFDQ.cjs} +15 -15
- package/dist/{brushstrokeRender-A727TTNQ.js → brushstrokeRender-DZGFU3J4.js} +3 -3
- package/dist/canvas/index.cjs +15 -15
- package/dist/canvas/index.js +2 -2
- package/dist/{chunk-THBJHPUL.js → chunk-2F3YDXCN.js} +1 -1
- package/dist/{chunk-4CPOKP27.js → chunk-2XDNF73E.js} +1 -1
- package/dist/{chunk-3KNQ2W6X.cjs → chunk-3JKCREEU.cjs} +59 -53
- package/dist/{chunk-4YSPQGZW.js → chunk-5HP2VSAS.js} +1 -1
- package/dist/{chunk-BPJSI4NT.cjs → chunk-7W2EQQBP.cjs} +2 -2
- package/dist/{chunk-LETF75CA.js → chunk-CLB2I2FU.js} +1 -1
- package/dist/{chunk-BAZMCFVL.js → chunk-DZVRH63Y.js} +1 -1
- package/dist/{chunk-PY4GWSE2.cjs → chunk-EBFPMSJO.cjs} +27 -5
- package/dist/{chunk-VBRHE4AM.cjs → chunk-FXVCB6YG.cjs} +35 -35
- package/dist/{chunk-EU2ZZA6L.cjs → chunk-GHGBIAWQ.cjs} +126 -39
- package/dist/{chunk-CBVNCWJM.cjs → chunk-LBDC5434.cjs} +2 -2
- package/dist/{chunk-2WOGXEDX.cjs → chunk-M3RZOF3G.cjs} +1 -1
- package/dist/{chunk-GSTSZPSR.js → chunk-N3SKPQEH.js} +225 -18
- package/dist/{chunk-J5VQYK7T.cjs → chunk-N5IMDAHM.cjs} +251 -44
- package/dist/{chunk-ININNHLM.js → chunk-NAHJV3O6.js} +11 -5
- package/dist/{chunk-MWUZCEFT.js → chunk-S2XPXA47.js} +1 -1
- package/dist/{chunk-56RHCIJV.cjs → chunk-SNAFFCAX.cjs} +296 -203
- package/dist/{chunk-EHLOCVWB.js → chunk-T2URHAJX.js} +27 -5
- package/dist/{chunk-BENSE3VX.cjs → chunk-TNLKFW7D.cjs} +23 -23
- package/dist/{chunk-KZI3YWKW.js → chunk-UXYCY3HP.js} +93 -6
- package/dist/{chunk-4NMPUJUK.cjs → chunk-YJANF2BL.cjs} +86 -86
- package/dist/{chunk-FUDP5QBB.js → chunk-ZEI7ZEA4.js} +101 -8
- package/dist/effects/index.cjs +5 -2
- package/dist/effects/index.js +4 -1
- package/dist/effects/pool.d.cts +9 -0
- package/dist/effects/pool.d.ts +9 -0
- package/dist/effects/types.d.cts +2 -0
- package/dist/effects/types.d.ts +2 -0
- package/dist/image-editor/index.cjs +791 -791
- package/dist/image-editor/index.js +6 -6
- package/dist/paint/index.cjs +2 -2
- package/dist/paint/index.js +1 -1
- package/dist/paint/wet/world.d.cts +37 -1
- package/dist/paint/wet/world.d.ts +37 -1
- package/dist/paint-editor/brush-controls.d.cts +2 -0
- package/dist/paint-editor/brush-controls.d.ts +2 -0
- package/dist/paint-editor/brush-model.d.cts +14 -1
- package/dist/paint-editor/brush-model.d.ts +14 -1
- package/dist/paint-editor/controller.d.cts +75 -4
- package/dist/paint-editor/controller.d.ts +75 -4
- package/dist/paint-editor/effect-paint.d.cts +33 -8
- package/dist/paint-editor/effect-paint.d.ts +33 -8
- package/dist/paint-editor/effects.d.cts +4 -0
- package/dist/paint-editor/effects.d.ts +4 -0
- package/dist/paint-editor/index.cjs +814 -483
- package/dist/paint-editor/index.js +408 -77
- package/dist/paint-editor/stroke.d.cts +13 -5
- package/dist/paint-editor/stroke.d.ts +13 -5
- package/dist/paint-editor/ui.d.cts +1 -1
- package/dist/paint-editor/ui.d.ts +1 -1
- package/dist/paint-editor/wet.d.cts +8 -1
- package/dist/paint-editor/wet.d.ts +8 -1
- package/dist/vector/index.cjs +999 -999
- package/dist/vector/index.js +5 -5
- package/dist/video-editor/index.cjs +317 -317
- package/dist/video-editor/index.js +2 -2
- package/package.json +1 -1
- package/skills/pixerate-brushes/SKILL.md +1 -0
- package/skills/pixerate-paint-editor/SKILL.md +6 -13
- package/skills/pixerate-paint-editor/references/brush-facets.md +1 -0
- package/skills/pixerate-paint-editor/references/effect-paint.md +28 -6
- package/skills/pixerate-paint-editor/references/ghost.md +47 -0
- package/skills/pixerate-paint-watercolour/SKILL.md +1 -0
|
@@ -149,7 +149,7 @@ import {
|
|
|
149
149
|
videoTransitionEase,
|
|
150
150
|
videoValueAt,
|
|
151
151
|
videoWipeRect
|
|
152
|
-
} from "../chunk-
|
|
152
|
+
} from "../chunk-S2XPXA47.js";
|
|
153
153
|
import {
|
|
154
154
|
namedWithSuggestion
|
|
155
155
|
} from "../chunk-EUKY4KFX.js";
|
|
@@ -160,7 +160,7 @@ import {
|
|
|
160
160
|
effectTemplateTools,
|
|
161
161
|
fillEffectTemplate
|
|
162
162
|
} from "../chunk-DHQPRKXF.js";
|
|
163
|
-
import "../chunk-
|
|
163
|
+
import "../chunk-T2URHAJX.js";
|
|
164
164
|
import {
|
|
165
165
|
CAMERA_MOVE_MAX_MS,
|
|
166
166
|
EffectsSlot,
|
package/package.json
CHANGED
|
@@ -20,6 +20,7 @@ built-in presets (read-only) and the user's brushes, shared by every editor that
|
|
|
20
20
|
| Dynamics | Pen feel: pressure to size and opacity, smoothing, tilt, velocity, jitter (`sizeJitter`, `angleJitter` for rotation, `opacityJitter`, `scatter`), rotation, `count` (dabs per spacing step, each jittered) and `flip` (mirror dabs at random: `x`, `y`, `xy`). |
|
|
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
|
+
| Ghost | On wet paint (`behaviour.surface: "wet"`): `linger` (0.5..60 s before the brush's own colour fades away) and `smear` (0..1, how much it lifts and drags the paint it crosses). Presets `ghost-wash`, `ghost-gouache`, `ghost-oil` and `invisible-ink`. |
|
|
23
24
|
| Motion | Animation after painting (live effect paint, particle `waveSpeed`). |
|
|
24
25
|
| 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. Canvas strokes and vector brushstrokes take it too, when they are given no colour. Canvas and vector have the same lock (`canvas.setColorLocked`, `vector.setColorLocked`), and a canvas colour taken from a light / dark default follows the scheme like the paint editor's; vector strokes already made keep theirs. |
|
|
25
26
|
|
|
@@ -142,10 +142,7 @@ Which facet sets which engine setting: [references/brush-facets.md](references/b
|
|
|
142
142
|
|
|
143
143
|
## Wet media
|
|
144
144
|
|
|
145
|
-
Watercolour, gouache and wet oil run on a fluid simulation: lay washes light to dark, let them
|
|
146
|
-
flow (`advance_wet_paint`), dry them (`dry_paint`) before glazing. Nothing moves for an agent
|
|
147
|
-
until you advance or dry it, and saving dries the paint. Load `pixerate-paint-watercolour`, and
|
|
148
|
-
read [references/wet-media.md](references/wet-media.md) for the engine and the wet tools.
|
|
145
|
+
Watercolour, gouache and wet oil run on a fluid simulation: lay washes light to dark, let them flow (`advance_wet_paint`), dry them (`dry_paint`) before glazing. Nothing moves for an agent until you advance or dry it, and saving dries the paint. Load `pixerate-paint-watercolour`, and read [references/wet-media.md](references/wet-media.md) for the engine and the wet tools. **Ghost paint and invisible ink** (`ghost` facet: `ghost-wash`, `ghost-gouache`, `ghost-oil`, `invisible-ink`) mix and flow while wet, then fade without leaving their own colour, leaving only a smear in the paint they touched: read [references/ghost.md](references/ghost.md).
|
|
149
146
|
|
|
150
147
|
## Oils and thick paint
|
|
151
148
|
|
|
@@ -235,7 +232,7 @@ When to use which:
|
|
|
235
232
|
| The effect in a wash that flows, or in thick paint | `set_effect_paint` and a watercolour, gouache, oil or impasto brush |
|
|
236
233
|
| The effect inside an exact shape, unchanged by water | Paint the shape, dry it, then `fill_layer_with_effect` with `lockTransparency: true` |
|
|
237
234
|
| The effect over the whole sheet | `set_paper_effect` or `add_effect_layer` |
|
|
238
|
-
| A pattern that follows the stroke, or paint that moves | `map: { by: "stroke" }
|
|
235
|
+
| A pattern that follows the stroke, or paint that moves | `map: { by: "stroke" }` (bends any effect as a strip), or `map: { by: "path" }` for effects with a path control (`accepts: ["path"]`: beams, trails, signatures); `live: true` on a stroke layer |
|
|
239
236
|
|
|
240
237
|
## Canvas-hosted layer
|
|
241
238
|
|
|
@@ -295,7 +292,7 @@ Listing, saving, sharing and previewing brushes are the brush library's tools (`
|
|
|
295
292
|
| Tool | Use |
|
|
296
293
|
| --- | --- |
|
|
297
294
|
| `get_brush` | Read a brush as facets (`brush`), or the active brush as edited (no `id`), with the `engine` and `category` it paints with, `builtin` (an unchanged preset) and `strokePaint` (what its next stroke paints). Read before changing a brush you did not build. |
|
|
298
|
-
| `set_brush` | Choose the active brush (`id`, from `list_brush_presets`) and / or lay facets over it: `tip`, `marks`, `dynamics`, `behaviour`, `light`, `motion`, `colour` (objects merge, lists replace; marks of another kind replace the marks), `unset` facets to drop. Editor state, not saved: `create_brush` stores a brush. Returns `brush` (facets), `engine` and `problems` (values clamped). The old flat fields (`particle`, `impasto`, `behavior`…) are refused. |
|
|
295
|
+
| `set_brush` | Choose the active brush (`id`, from `list_brush_presets`) and / or lay facets over it: `tip`, `marks`, `dynamics`, `behaviour`, `light`, `ghost`, `motion`, `colour` (objects merge, lists replace; marks of another kind replace the marks), `unset` facets to drop. Editor state, not saved: `create_brush` stores a brush. Returns `brush` (facets), `engine` and `problems` (values clamped). The old flat fields (`particle`, `impasto`, `behavior`…) are refused. |
|
|
299
296
|
|
|
300
297
|
### Colour
|
|
301
298
|
|
|
@@ -345,7 +342,7 @@ Listing, saving, sharing and previewing brushes are the brush library's tools (`
|
|
|
345
342
|
|
|
346
343
|
| Tool | Use |
|
|
347
344
|
| --- | --- |
|
|
348
|
-
| `get_wet_paint` | Read the wet paint: `wet`, the clock, `paused`, `speed`, `tilt`, the kernel (`backend`, `message` when it runs slower than it could, e.g. on one thread because the page is not cross-origin isolated (COOP / COEP)), the GPU accelerator (`engine`) and each wet layer (`wetCells`, `wetBounds`, `activeTiles`, settings, flow map). Call after wet strokes. |
|
|
345
|
+
| `get_wet_paint` | Read the wet paint: `wet`, the clock, `paused`, `speed`, `tilt`, the kernel (`backend`, `message` when it runs slower than it could, e.g. on one thread because the page is not cross-origin isolated (COOP / COEP)), the GPU accelerator (`engine`) and each wet layer (`wetCells`, `wetBounds`, `activeTiles`, settings, flow map, and `ghost: { remaining }` while ghost paint is fading). Call after wet strokes. |
|
|
349
346
|
| `advance_wet_paint` | Let time pass: `steps` (120 = one second at the default speed) or `seconds`. The paint spreads, blooms, runs and dries. Not an undo step. Returns `steps`, `clock`, `stillWet`, `layers`. Call after a group of wet strokes, before `render_preview`. |
|
|
350
347
|
| `dry_paint` | Dry wet paint at once where it is (one layer with `layerId` or all, optionally inside `rect`). One undo step. Returns `dried` (layer ids and rectangles) and `stillWet`. Dry before glazing over a wash. |
|
|
351
348
|
| `wet_paper` | Pre-wet the paper with clear water over `rect` (default the canvas) on a layer, `amount` 0..1, for wet-in-wet. One undo step. Returns the rectangle and `wet`. Then paint into it. |
|
|
@@ -394,7 +391,7 @@ Listing, saving, sharing and previewing brushes are the brush library's tools (`
|
|
|
394
391
|
| `set_paper_effect` | Draw a generator over the paper (`values`, `opacity`, `blend` default `multiply`, `time`); `effect: null` removes it. One undo step. Returns the effect paper. |
|
|
395
392
|
| `add_effect_layer` | Add a layer drawn by a generator, overlay or title effect (`values`, `name`, `aboveId`, `opacity`, `blend`, `time`); it becomes active. Returns the layer and its effect. |
|
|
396
393
|
| `fill_layer_with_effect` | Composite a generator, overlay or title effect onto a layer (`layerId`, `values`, `opacity`, `lockTransparency`, `time`). One undo step. Returns the layer id and the effect. |
|
|
397
|
-
| `set_effect_paint` | Paint with a generator, overlay or title effect (`effect`, `values`, `time` ms default 0): rendered once at the canvas size, strokes take each pixel's colour from it; `map` `{ by: "stroke", length, repeat }`
|
|
394
|
+
| `set_effect_paint` | Paint with a generator, overlay or title effect (`effect`, `values`, `time` ms default 0): rendered once at the canvas size, strokes take each pixel's colour from it; `map` `{ by: "stroke", length, repeat }` bends a strip along each stroke, or `{ by: "path" }` passes the stroke's centreline to an effect with a path control (`format: "svg-path"`, `accepts: ["path"]`); `live` keeps it playing on stroke layers. Call after `describe_effect`, then `paint_stroke`. Editor state, not an undo step. Returns `effectPaint`. |
|
|
398
395
|
| `set_effect_playback` | Play or pause live effect paint in the view (`playing`) and cap its frame rate (`fps` 1..60). Editor state. Returns `playing`, `fps`, `time` and `animation` (what plays, or null). Export a moment with `export_image` / `export_psd` `time`. |
|
|
399
396
|
|
|
400
397
|
### Guides
|
|
@@ -476,11 +473,7 @@ The host may add the shared document tools (see `pixerate-agent-tools`). A paint
|
|
|
476
473
|
- **Wet paint keeps changing.** A preview right after a wet stroke shows it before it has
|
|
477
474
|
flowed; `advance_wet_paint` first. Paint that should stay exactly where it was laid needs
|
|
478
475
|
`dry_paint` (or a dry medium).
|
|
479
|
-
- **Wet strokes on one layer interact**; washes that must not mix go on separate layers, or dry
|
|
480
|
-
the first before painting the second (glazing). At most 8 layers hold wet paint at once, and the simulation holds at most 328 wet tiles (256 × 256 px each) across them; water that spreads past
|
|
481
|
-
that limit is lost (`dry_paint` frees tiles). Multi-threaded wet media needs a cross-origin isolated
|
|
482
|
-
page (COOP / COEP, for `SharedArrayBuffer`) and runs on one thread otherwise, more slowly but with
|
|
483
|
-
the same result.
|
|
476
|
+
- **Wet strokes on one layer interact**; washes that must not mix go on separate layers, or dry the first before painting the second (glazing). Ghost paint (`ghost-wash`, `ghost-gouache`, `ghost-oil`, `invisible-ink`) only meets and smears paint on its own layer, so a ghost stroke on a new empty layer simply vanishes; ghost paint and light paint cannot share a layer while the ghost is fading. At most 8 layers hold wet paint at once, and the simulation holds at most 328 wet tiles (256 × 256 px each) across them; water that spreads past that limit is lost (`dry_paint` frees tiles). Multi-threaded wet media needs a cross-origin isolated page (COOP / COEP, for `SharedArrayBuffer`) and runs on one thread otherwise, more slowly but with the same result.
|
|
484
477
|
- **Undoing far back** past the wet undo memory (512 MB by default) leaves that paint dry as it
|
|
485
478
|
looked, rather than wet.
|
|
486
479
|
- **Replays repeat what was recorded**: strokes, fills, clears, flattened relief and wet events.
|
|
@@ -20,6 +20,7 @@ more; this is where each one went.
|
|
|
20
20
|
| Bristles | `tip.shape` `bristle` and `tip.bristle` |
|
|
21
21
|
| A brush's own gradient (paint) | `colour.default` (a gradient); `unset: ['colour']` drops it |
|
|
22
22
|
| Light | `light` (`amount`, `pressure`) |
|
|
23
|
+
| Ghost paint (linger, smear) | `ghost` (`linger`, `smear`); `unset: ['ghost']` drops it |
|
|
23
24
|
|
|
24
25
|
## Examples
|
|
25
26
|
|
|
@@ -1,14 +1,36 @@
|
|
|
1
1
|
# Effect paint along the stroke, and live effect paint
|
|
2
2
|
|
|
3
|
-
- **Along the stroke** (`set_effect_paint` `map: { by: "
|
|
4
|
-
|
|
3
|
+
- **Along the stroke (native path)** (`set_effect_paint` `map: { by: "path" }`): when an effect has
|
|
4
|
+
a path control (`format: "svg-path"`, reported by `describe_effect` as `pathControls` and
|
|
5
|
+
`accepts: ["path"]`), each stroke passes its centreline `[x0, y0, x1, y1, …]` in canvas pixels
|
|
6
|
+
directly to that control and renders at the canvas size. The effect draws and lights itself along
|
|
7
|
+
the stroke's exact curve (e.g. a neon beam, laser trail or signature whose glow and lighting
|
|
8
|
+
belong to the path), while the brush's dabs and coverage still decide where paint lands. Strokes
|
|
9
|
+
with more than 256 points are evenly resampled to 256 points rather than refused. **Prefer
|
|
10
|
+
`by: "path"` over `by: "stroke"` whenever the effect has a path control** (`accepts: ["path"]`);
|
|
11
|
+
`set_effect_paint` refuses `by: "path"` on effects without a path control and tells you to use
|
|
12
|
+
`by: "stroke"` or `by: "canvas"`. Each stroke is a render of its own at the canvas size, so:
|
|
13
|
+
- A stroke painted by hand shows the effect along the path drawn so far while it is drawn,
|
|
14
|
+
re-rendered one render at a time, so it trails the pen by about one render. It is painted
|
|
15
|
+
again along its whole path when the pen lifts, as one undo step; if the preview already
|
|
16
|
+
rendered the whole path, at once. On a slow provider the editor is busy until that lands
|
|
17
|
+
(`effectPaintRendering`). `paint_stroke` and `stroke_path` know the path up front and paint
|
|
18
|
+
it at once.
|
|
19
|
+
- Wet brushes can't be painted by hand this way, as the simulation can't run twice; give them
|
|
20
|
+
the points through `paint_stroke`, or use `by: "stroke"`.
|
|
21
|
+
- With `live: true`, every stroke is a live source of its own, so at most 8 can play.
|
|
22
|
+
- Symmetry copies sample the same render, which only follows the original stroke: paint each
|
|
23
|
+
copy as its own stroke if it should draw too.
|
|
24
|
+
- **Along the stroke (strip)** (`set_effect_paint` `map: { by: "stroke", length, repeat }`): for
|
|
25
|
+
effects without a path control, the effect is rendered as a strip `length` px long (16..4096,
|
|
26
|
+
default 300) and 256 px across. Each pixel takes
|
|
5
27
|
the colour at its distance along the stroke and its place across the tip, so the pattern follows
|
|
6
28
|
the stroke's turns instead of staying fixed to the canvas. `repeat` starts the strip again
|
|
7
29
|
(default), `mirror` runs it back, `clamp` holds the last colour. Use it for ribbons, ropes,
|
|
8
|
-
flames and textures that
|
|
9
|
-
hidden picture across many strokes. Every colour-laying brush takes it (watercolour,
|
|
10
|
-
and impasto too; sprayed stickers at their centre); particle and bristle marks take
|
|
11
|
-
their pen dab.
|
|
30
|
+
flames and textures that have no path control of their own; use the default canvas mapping to
|
|
31
|
+
reveal one hidden picture across many strokes. Every colour-laying brush takes it (watercolour,
|
|
32
|
+
gouache, oil and impasto too; sprayed stickers at their centre); particle and bristle marks take
|
|
33
|
+
the place of their pen dab.
|
|
12
34
|
Scaled replays (`export_high_res`) scale `length` with the canvas.
|
|
13
35
|
- **Live** (`live: true`): on a stroke layer (`add_layer {type: "strokes"}`) each stroke keeps
|
|
14
36
|
playing the effect, so the paint moves. Paint the strokes, then `set_effect_playback`
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Ghost paint and invisible ink
|
|
2
|
+
|
|
3
|
+
Ghost paint is wet paint (`behaviour.surface: "wet"`) with a `ghost` facet (`linger` 0.5..60 s,
|
|
4
|
+
default 4; `smear` 0..1, default 0.3). While wet it looks and behaves like any watercolour,
|
|
5
|
+
gouache or wet oil: it flows with the water and its colour mixes visibly with the paint it meets.
|
|
6
|
+
Then its own colour fades away completely, leaving only what it did to the paint already on the
|
|
7
|
+
layer — a smear where it lifted and dragged that paint along. On bare paper it leaves nothing at
|
|
8
|
+
all.
|
|
9
|
+
|
|
10
|
+
## Presets and settings
|
|
11
|
+
|
|
12
|
+
- **`ghost-wash`**: transparent watercolour ghost (`linger: 4`, `smear: 0.35`).
|
|
13
|
+
- **`ghost-gouache`**: opaque gouache ghost that mixes strongly while wet, then vanishes (`linger: 4`, `smear: 0.45`).
|
|
14
|
+
- **`ghost-oil`**: slow wet oil ghost (`linger: 8`, `smear: 0.55`).
|
|
15
|
+
- **`invisible-ink`**: a ghost brush with `behaviour.wet.pigment: 0` and `smear: 0.6`. Nothing
|
|
16
|
+
shows on bare paper; it reveals itself only as a smear in the wet or dried paint it crosses.
|
|
17
|
+
Because it lays no pigment, it lays no tracer, needs no fade, and does not interrupt another
|
|
18
|
+
ghost already fading on the layer.
|
|
19
|
+
- Any wet paint brush becomes a ghost brush with `set_brush` `{ ghost: { linger, smear } }`;
|
|
20
|
+
`unset: ["ghost"]` makes it ordinary wet paint again.
|
|
21
|
+
|
|
22
|
+
## Working method
|
|
23
|
+
|
|
24
|
+
1. **Paint on the layer that holds the paint you want to disturb.** Wet paint is per layer:
|
|
25
|
+
a ghost stroke on a new empty layer has nothing to smear and vanishes into bare paper.
|
|
26
|
+
2. **Watch it mix while wet.** Call `advance_wet_paint` in short steps (`seconds: 0.5..1`) and
|
|
27
|
+
`render_preview` to see the ghost colour mixing and flowing with the layer's paint, and check
|
|
28
|
+
`get_wet_paint` (`layers[].ghost.remaining`, from 1 down to 0) to see how much of the fade is
|
|
29
|
+
left.
|
|
30
|
+
3. **Finish the fade.** Advance past `linger` seconds, or call `dry_paint` (which finishes the
|
|
31
|
+
ghost fade at once before baking). With `smear: 0`, ghost paint passes over dried paint and
|
|
32
|
+
leaves it untouched; with `smear > 0`, it lifts dried paint along its path (`rewet` scaled by
|
|
33
|
+
`smear`) and drags both wet and lifted paint along the stroke.
|
|
34
|
+
|
|
35
|
+
## Pitfalls
|
|
36
|
+
|
|
37
|
+
- **Wet paint is per layer.** Ghost paint only meets paint on its own layer. Painting a ghost
|
|
38
|
+
stroke on a new empty layer leaves nothing behind once it fades.
|
|
39
|
+
- **One ghost colour per layer at a time.** Painting a ghost stroke in a new colour on a layer
|
|
40
|
+
whose earlier ghost is still fading finishes the earlier ghost's colour fade at once (keeping
|
|
41
|
+
its smear) before starting the new colour.
|
|
42
|
+
- **Ghost and light paint cannot share a layer.** The ghost tracer uses the wet layer's light
|
|
43
|
+
channel, so a ghost stroke is refused on a layer that has light paint (`clear_light` or paint on
|
|
44
|
+
another layer), and a light brush is refused on a layer where ghost paint is still fading
|
|
45
|
+
(`dry_paint` first or use another layer). Once the ghost has faded, the layer is free again.
|
|
46
|
+
- **One solid colour per stroke.** Gradient paint, effect paint and multi-colour are refused on
|
|
47
|
+
ghost brushes.
|
|
@@ -77,6 +77,7 @@ block the light. See `references/light-paint.md` in `pixerate-paint-editor`.
|
|
|
77
77
|
| Cauliflower blooms | Add water into a drying wash; `bloom` up |
|
|
78
78
|
| A glowing (neon) wash | Dark paper (`set_paper` `color`), `glow-wash` or `light.amount` on a wet brush; flow, dry, `get_light` |
|
|
79
79
|
| Stained glass, a lightbox | `set_paper` `stained-glass` (or `backlight`); strong glazes for panes, opaque black lines above |
|
|
80
|
+
| Disturb or smear a wash without adding colour | `ghost-wash`, `ghost-gouache` or `invisible-ink` (`ghost` `linger`, `smear`) on the same layer; see `references/ghost.md` |
|
|
80
81
|
|
|
81
82
|
## Recipes
|
|
82
83
|
|