@pixerate/editor 0.243.0 → 0.245.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 +34 -32
- package/dist/agent/index.js +6 -4
- package/dist/animation-editor/index.cjs +61 -61
- package/dist/animation-editor/index.js +4 -4
- package/dist/{brushstrokeRender-274HGNZR.js → brushstrokeRender-4542T5HP.js} +2 -2
- package/dist/{brushstrokeRender-C7RJZPMC.cjs → brushstrokeRender-QA5WVIDT.cjs} +5 -5
- package/dist/canvas/changeFeed.d.cts +71 -0
- package/dist/canvas/changeFeed.d.ts +71 -0
- package/dist/canvas/index.cjs +490 -34
- package/dist/canvas/index.d.cts +3 -0
- package/dist/canvas/index.d.ts +3 -0
- package/dist/canvas/index.js +483 -27
- package/dist/canvas/proposal-tools.d.cts +21 -0
- package/dist/canvas/proposal-tools.d.ts +21 -0
- package/dist/canvas/proposals.d.cts +112 -0
- package/dist/canvas/proposals.d.ts +112 -0
- package/dist/chart/index.cjs +21 -21
- package/dist/chart/index.js +2 -2
- package/dist/{chunk-6L3WWIDW.js → chunk-4EQY4TZJ.js} +1 -1
- package/dist/{chunk-5FZS7J7C.cjs → chunk-4T47Z4J3.cjs} +18 -2
- package/dist/{chunk-4I76OCVD.cjs → chunk-5DLCOQOQ.cjs} +16 -1
- package/dist/{chunk-4ZHXLFXS.js → chunk-5RFENYO5.js} +1 -1
- package/dist/{chunk-SRXWDOUI.js → chunk-7YQNKSQ7.js} +1 -1
- package/dist/{chunk-WGN7AUKB.js → chunk-7YW7T5TJ.js} +1 -1
- package/dist/{chunk-X3ZINLIP.js → chunk-AU6MWQKZ.js} +1 -1
- package/dist/{chunk-OONFIFEU.cjs → chunk-BDIH4DYR.cjs} +23 -23
- package/dist/{chunk-AIS56JOO.js → chunk-BVRRIW7F.js} +1 -1
- package/dist/{chunk-KK2FWMA2.cjs → chunk-HZ547SGQ.cjs} +1 -1
- package/dist/{chunk-3WOZEBXZ.cjs → chunk-IZL5V5RK.cjs} +2 -2
- package/dist/{chunk-IXI5KATU.js → chunk-L5PB7EG3.js} +1 -1
- package/dist/{chunk-R2FVAKFH.cjs → chunk-M6JORA5Z.cjs} +86 -86
- package/dist/{chunk-RNSANXPT.js → chunk-NS62CQ2B.js} +112 -14
- package/dist/{chunk-UZU6DIZA.cjs → chunk-NUTMINJZ.cjs} +45 -45
- package/dist/{chunk-H4Z72Z4Z.js → chunk-OSTKS3YN.js} +1 -1
- package/dist/{chunk-HLBTRSQJ.js → chunk-P3NIPIKS.js} +263 -63
- package/dist/{chunk-7V7QMFTI.cjs → chunk-QOBCBGGI.cjs} +2 -2
- package/dist/{chunk-UV7OOZJQ.cjs → chunk-SD23XMVJ.cjs} +35 -35
- package/dist/{chunk-FQVVO5YA.js → chunk-SGPIVHJB.js} +1 -1
- package/dist/{chunk-HQZHOPNE.js → chunk-TBJEMELS.js} +18 -2
- package/dist/{chunk-QTMQ5TGA.js → chunk-UCYW4M66.js} +16 -1
- package/dist/{chunk-XFYLA3ZO.cjs → chunk-VMROIWLL.cjs} +290 -90
- package/dist/{chunk-W7GRGGBH.cjs → chunk-W7L4HUT2.cjs} +8 -8
- package/dist/{chunk-FJ2MSI43.cjs → chunk-WKPXOGZZ.cjs} +124 -26
- package/dist/{chunk-D2SGV525.cjs → chunk-XZNU4DUX.cjs} +2 -2
- package/dist/diagram/index.cjs +2 -2
- package/dist/diagram/index.js +1 -1
- package/dist/effects/index.cjs +4 -4
- package/dist/effects/index.js +2 -2
- package/dist/extensions/index.cjs +5 -5
- package/dist/extensions/index.js +4 -4
- package/dist/gradient/index.cjs +2 -2
- package/dist/gradient/index.js +1 -1
- package/dist/history/HistoryManager.d.cts +20 -1
- package/dist/history/HistoryManager.d.ts +20 -1
- package/dist/history/index.cjs +8 -2
- package/dist/history/index.js +8 -2
- package/dist/history/types.d.cts +31 -0
- package/dist/history/types.d.ts +31 -0
- package/dist/image-editor/index.cjs +785 -777
- package/dist/image-editor/index.js +13 -5
- package/dist/index.cjs +16 -10
- package/dist/index.js +11 -5
- package/dist/kernel-wasm-4KVONDAU.js +9 -0
- package/dist/kernel-wasm-TTYRBGAK.cjs +9 -0
- package/dist/paint/index.cjs +10 -2
- package/dist/paint/index.js +9 -1
- package/dist/paint/wet/film.d.cts +19 -1
- package/dist/paint/wet/film.d.ts +19 -1
- package/dist/paint/wet/gpu-kernels.d.cts +2 -2
- package/dist/paint/wet/gpu-kernels.d.ts +2 -2
- package/dist/paint/wet/kernel-wasm.d.cts +5 -5
- package/dist/paint/wet/kernel-wasm.d.ts +5 -5
- package/dist/paint/wet/kernel.d.cts +1 -1
- package/dist/paint/wet/kernel.d.ts +1 -1
- package/dist/paint/wet/medium.d.cts +3 -1
- package/dist/paint/wet/medium.d.ts +3 -1
- package/dist/paint/wet/model.d.cts +19 -4
- package/dist/paint/wet/model.d.ts +19 -4
- package/dist/paint/wet/world.d.cts +34 -8
- package/dist/paint/wet/world.d.ts +34 -8
- package/dist/paint-editor/backlight.d.cts +77 -0
- package/dist/paint-editor/backlight.d.ts +77 -0
- package/dist/paint-editor/controller.d.cts +11 -0
- package/dist/paint-editor/controller.d.ts +11 -0
- package/dist/paint-editor/index.cjs +685 -397
- package/dist/paint-editor/index.d.cts +1 -0
- package/dist/paint-editor/index.d.ts +1 -0
- package/dist/paint-editor/index.js +308 -20
- package/dist/paint-editor/paper.d.cts +7 -0
- package/dist/paint-editor/paper.d.ts +7 -0
- package/dist/paint-editor/wet.d.cts +9 -0
- package/dist/paint-editor/wet.d.ts +9 -0
- package/dist/parameters/index.cjs +2 -2
- package/dist/parameters/index.js +1 -1
- package/dist/tools/index.cjs +4 -2
- package/dist/tools/index.d.cts +1 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.js +3 -1
- package/dist/tools/origin.d.cts +22 -0
- package/dist/tools/origin.d.ts +22 -0
- package/dist/vector/index.cjs +964 -964
- package/dist/vector/index.js +5 -5
- package/dist/video-editor/index.cjs +4 -4
- package/dist/video-editor/index.js +2 -2
- package/package.json +1 -1
- package/skills/pixerate-canvas/SKILL.md +25 -0
- package/skills/pixerate-paint-editor/SKILL.md +3 -3
- package/skills/pixerate-paint-editor/references/light-paint.md +30 -7
- package/skills/pixerate-paint-watercolour/SKILL.md +10 -1
- package/skills/pixerate-paint-watercolour/evals/glowing-wash.json +22 -0
- package/skills/pixerate-paint-watercolour/evals/stained-glass.json +16 -0
- package/dist/kernel-wasm-6FPOLVUZ.cjs +0 -9
- package/dist/kernel-wasm-WIMMJUF2.js +0 -9
|
@@ -22,6 +22,10 @@
|
|
|
22
22
|
* `S = Σ cᵢSᵢ`) and transparent washes multiply like glazes. A colour becomes `K` and `S` with the
|
|
23
23
|
* same two-flux formulas as the shipped pigment model (`K/S = (1 − R)² / 2R`).
|
|
24
24
|
*
|
|
25
|
+
* - **Light** (light paint, a fifth mass channel) rides with the pigment: suspended and settled,
|
|
26
|
+
* advected, bled, settled and lifted exactly as pigment is, so a glowing wash flows, pools at
|
|
27
|
+
* its edges, granulates and blooms with its colour.
|
|
28
|
+
*
|
|
25
29
|
* `stepCellsTs` in `kernel.ts` is the specification of one step, in exact f32 arithmetic. The
|
|
26
30
|
* WebAssembly SIMD kernel (`assembly/wet.ts`) is a lane-for-lane port of it and gives the same bits,
|
|
27
31
|
* so the simulation is deterministic across browsers, kernels and worker counts.
|
|
@@ -33,19 +37,25 @@ export declare const SLOT_SIDE = 258;
|
|
|
33
37
|
/** Floats per plane of a slot. */
|
|
34
38
|
export declare const PLANE: number;
|
|
35
39
|
export declare const PLANE_BYTES: number;
|
|
36
|
-
/**
|
|
37
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Planes in each ping-ponged set: f0..f8, depth, velocity, paper water, 4 pigment channels,
|
|
42
|
+
* suspended light, edge.
|
|
43
|
+
*/
|
|
44
|
+
export declare const SET_PLANES = 19;
|
|
38
45
|
export declare const P_RHO = 9;
|
|
39
46
|
export declare const P_UX = 10;
|
|
40
47
|
export declare const P_UY = 11;
|
|
41
48
|
/** Water held in the paper. */
|
|
42
49
|
export declare const P_SW = 12;
|
|
43
|
-
/** Suspended pigment: K red, K green, K blue, S. */
|
|
50
|
+
/** Suspended pigment: K red, K green, K blue, S; then suspended light (`P_P0 + 4`). */
|
|
44
51
|
export declare const P_P0 = 13;
|
|
52
|
+
/** Suspended light paint: light carried by the water, moving exactly as pigment mass does. */
|
|
53
|
+
export declare const P_L: number;
|
|
45
54
|
/** Edge: 1 at the wet front, fading over a few cells into the wet area (0 where dry). */
|
|
46
|
-
export declare const P_EDGE =
|
|
55
|
+
export declare const P_EDGE = 18;
|
|
47
56
|
/** Single (not ping-ponged) planes, after the two sets. */
|
|
48
57
|
export declare const P_D0: number;
|
|
58
|
+
export declare const P_DL: number;
|
|
49
59
|
export declare const P_H: number;
|
|
50
60
|
export declare const P_FX: number;
|
|
51
61
|
export declare const P_FY: number;
|
|
@@ -53,6 +63,11 @@ export declare const SLOT_PLANES: number;
|
|
|
53
63
|
export declare const SLOT_BYTES: number;
|
|
54
64
|
/** Pigment channels per cell. */
|
|
55
65
|
export declare const PIGMENT_CHANNELS = 4;
|
|
66
|
+
/**
|
|
67
|
+
* Mass channels per cell: the 4 pigment channels and light. Light is a property of the paint, so
|
|
68
|
+
* the step advects, bleeds, settles and lifts it with the same flux and rates as pigment.
|
|
69
|
+
*/
|
|
70
|
+
export declare const MASS_CHANNELS = 5;
|
|
56
71
|
/** D2Q9 lattice velocities: 0 rest, 1–4 axis (E, S, W, N in screen space), 5–8 diagonals. */
|
|
57
72
|
export declare const EX: readonly [0, 1, 0, -1, 0, 1, -1, -1, 1];
|
|
58
73
|
export declare const EY: readonly [0, 0, 1, 0, -1, 1, 1, -1, -1];
|
|
@@ -17,6 +17,10 @@
|
|
|
17
17
|
* - **Display.** Each lane has a `base` surface: the layer's pixels under the wet paint. `display`
|
|
18
18
|
* gives the base with every live tile shaded (`filmPixel`), as an ordinary RGBA surface for the
|
|
19
19
|
* compositor. Tiles that dry are baked into the base and their slots freed.
|
|
20
|
+
* - **Light paint.** Light is a fifth mass channel (suspended and settled), moving exactly as
|
|
21
|
+
* pigment does. A lane's `light` surface (one channel, see `paint-editor/light.ts`) is the
|
|
22
|
+
* light under the wet paint; `lightDisplay` shades the live light over it and drying bakes it
|
|
23
|
+
* in, as the colour is.
|
|
20
24
|
* - **Engine B (WebGPU).** With a GPU engine attached (`attachGpu`) and at least `gpuMinTiles` live
|
|
21
25
|
* tiles, the GPU keeps a mirror of the slots: each edit uploads the rows it changed, each batch
|
|
22
26
|
* runs on the GPU too, and `displayGpu` shades every stale tile there at once. In lead mode
|
|
@@ -30,8 +34,8 @@ import { type WetWorkerLayout } from './wasm.cjs';
|
|
|
30
34
|
import type { WetGpuEngine } from './gpu.cjs';
|
|
31
35
|
/** Wet layers a world can hold at once. */
|
|
32
36
|
export declare const MAX_WET_LANES = 8;
|
|
33
|
-
/** Tile slots at most (about 3.
|
|
34
|
-
export declare const MAX_WET_SLOTS =
|
|
37
|
+
/** Tile slots at most (about 3.75 GB, inside wasm32's 4 GB). Water reaching a tile past this is lost. */
|
|
38
|
+
export declare const MAX_WET_SLOTS = 328;
|
|
35
39
|
/** A flow map: a vector per document pixel, in cells per step² at strength 1. */
|
|
36
40
|
export type WetFlowField = (x: number, y: number) => readonly [number, number];
|
|
37
41
|
/** The paper as the simulation reads it. */
|
|
@@ -62,6 +66,8 @@ export interface WetLaneOptions {
|
|
|
62
66
|
flow?: WetFlowField | null;
|
|
63
67
|
/** Flow map strength (default 1 when a flow map is given). */
|
|
64
68
|
flowStrength?: number;
|
|
69
|
+
/** The layer's light paint under the wet paint (one channel; default none). */
|
|
70
|
+
light?: TiledSurface | null;
|
|
65
71
|
}
|
|
66
72
|
/** Totals for one wet layer. */
|
|
67
73
|
export interface WetLaneStats {
|
|
@@ -87,6 +93,8 @@ export interface WetSnapshot {
|
|
|
87
93
|
flow: WetFlowField | null;
|
|
88
94
|
flowStrength: number;
|
|
89
95
|
base: TiledSurface;
|
|
96
|
+
light?: TiledSurface;
|
|
97
|
+
lit?: boolean;
|
|
90
98
|
}>;
|
|
91
99
|
/** Per active key: the current set and the deposit planes; and its last flags. */
|
|
92
100
|
readonly slots: ReadonlyMap<number, {
|
|
@@ -177,6 +185,12 @@ export declare class WetWorld {
|
|
|
177
185
|
getBase(id: string): TiledSurface;
|
|
178
186
|
/** Replaces the pixels under a layer's wet paint. */
|
|
179
187
|
setBase(id: string, base: TiledSurface): void;
|
|
188
|
+
/** The light paint under a layer's wet paint (one channel). */
|
|
189
|
+
getLight(id: string): TiledSurface;
|
|
190
|
+
/** Whether a layer has light paint, under its wet paint or in it. */
|
|
191
|
+
isLit(id: string): boolean;
|
|
192
|
+
/** Replaces the light paint under a layer's wet paint. */
|
|
193
|
+
setLight(id: string, light: TiledSurface): void;
|
|
180
194
|
private pack;
|
|
181
195
|
private touchAll;
|
|
182
196
|
private laneIndexOf;
|
|
@@ -247,10 +261,10 @@ export declare class WetWorld {
|
|
|
247
261
|
private addWaterAt;
|
|
248
262
|
/**
|
|
249
263
|
* Lays paint: `water` depth and pigment mass `pigment` (K r, g, b, S) per unit of coverage, or
|
|
250
|
-
* per pixel from `field` (4 values per pixel of `rect`)
|
|
251
|
-
* the paper (settled).
|
|
264
|
+
* per pixel from `field` (4 values per pixel of `rect`), and `light` (light paint mass) per unit
|
|
265
|
+
* of coverage. Pigment and light without water land straight in the paper (settled).
|
|
252
266
|
*/
|
|
253
|
-
paint(id: string, rect: RasterRect, cov: ArrayLike<number> | null, water: number, pigment: ArrayLike<number> | null, field?: ArrayLike<number> | null): void;
|
|
267
|
+
paint(id: string, rect: RasterRect, cov: ArrayLike<number> | null, water: number, pigment: ArrayLike<number> | null, field?: ArrayLike<number> | null, light?: number): void;
|
|
254
268
|
/** Damp paper: fills the paper's water towards its capacity by `amount` (0..1) × coverage, plus a thin film of surface water. */
|
|
255
269
|
wetPaper(id: string, rect: RasterRect, cov: ArrayLike<number> | null, amount: number): void;
|
|
256
270
|
/**
|
|
@@ -261,16 +275,17 @@ export declare class WetWorld {
|
|
|
261
275
|
remove(id: string, rect: RasterRect, cov: ArrayLike<number> | null, water: number, suspended: number, settled: number, paperWater?: number): void;
|
|
262
276
|
/** Pushes the water: adds velocity (`ux`, `uy` cells per step, each at most 0.1) × coverage. */
|
|
263
277
|
push(id: string, rect: RasterRect, cov: ArrayLike<number> | null, ux: number, uy: number): void;
|
|
264
|
-
/** Blends wet paint: each wet cell's suspended pigment moves `strength` × coverage towards the footprint's mean. */
|
|
278
|
+
/** Blends wet paint: each wet cell's suspended pigment (and light) moves `strength` × coverage towards the footprint's mean. */
|
|
265
279
|
blend(id: string, rect: RasterRect, cov: ArrayLike<number> | null, strength: number): void;
|
|
266
280
|
/**
|
|
267
281
|
* Drags wet paint by (`dx`, `dy`) cells: each footprint cell takes `strength` × coverage of the
|
|
268
|
-
* water and suspended pigment of the cell it came from (a smudge through wet paint).
|
|
282
|
+
* water and suspended pigment (and light) of the cell it came from (a smudge through wet paint).
|
|
269
283
|
*/
|
|
270
284
|
drag(id: string, rect: RasterRect, cov: ArrayLike<number> | null, dx: number, dy: number, strength: number): void;
|
|
271
285
|
/**
|
|
272
286
|
* Re-wetting: lifts `amount` × coverage of the dried paint in the layer's pixels (`base`) back into
|
|
273
|
-
* the paper as settled pigment, so water can move it again
|
|
287
|
+
* the paper as settled pigment, so water can move it again, and the same share of its light
|
|
288
|
+
* paint (`light`) as settled light. Only where there is surface water.
|
|
274
289
|
*/
|
|
275
290
|
rewet(id: string, rect: RasterRect, cov: ArrayLike<number> | null, amount: number, paper: readonly [number, number, number]): void;
|
|
276
291
|
/**
|
|
@@ -284,6 +299,8 @@ export declare class WetWorld {
|
|
|
284
299
|
* Returns whether any pixel changed.
|
|
285
300
|
*/
|
|
286
301
|
private bakeKey;
|
|
302
|
+
/** `shadeSlot` for light paint: one channel over a light tile (see `shadeLightTile`); `null` when nothing would change. */
|
|
303
|
+
private shadeLightSlot;
|
|
287
304
|
/**
|
|
288
305
|
* Shades one slot over a base tile. `display`: the wet look (suspended + settled, wet paper a
|
|
289
306
|
* little darker); `bake`: settled pigment only; `bake-all`: suspended and settled (dry now).
|
|
@@ -292,6 +309,8 @@ export declare class WetWorld {
|
|
|
292
309
|
private shadeSlot;
|
|
293
310
|
/** The layer's pixels with all its wet paint dried where it is (the bake of "dry on save"); changes nothing. */
|
|
294
311
|
bakedSurface(id: string): TiledSurface;
|
|
312
|
+
/** The layer's light paint with all its wet paint dried where it is (`bakedSurface` for light); changes nothing. */
|
|
313
|
+
bakedLight(id: string): TiledSurface;
|
|
295
314
|
/**
|
|
296
315
|
* Sums over a footprint of a lane, weighted by coverage: `weight` (coverage), `water` (surface
|
|
297
316
|
* depth), `wet` (coverage of wet cells), `pigment` (suspended, 4 channels), `settled` (4 channels).
|
|
@@ -323,6 +342,12 @@ export declare class WetWorld {
|
|
|
323
342
|
changed: RasterRect[];
|
|
324
343
|
pending: number;
|
|
325
344
|
};
|
|
345
|
+
/**
|
|
346
|
+
* The layer's light paint with its live light shaded in (`null` when the layer has none): the
|
|
347
|
+
* light under the wet paint with each live tile's light over it. Like `display`, every stale
|
|
348
|
+
* tile is reshaded (light tiles are cheap: one channel, no colour maths).
|
|
349
|
+
*/
|
|
350
|
+
lightDisplay(id: string): TiledSurface | null;
|
|
326
351
|
/**
|
|
327
352
|
* The water as an overlay tile (RGBA, blue, alpha from surface depth and damp paper) for a
|
|
328
353
|
* document tile, or `null` where nothing is wet.
|
|
@@ -388,6 +413,7 @@ export declare class WetWorld {
|
|
|
388
413
|
/** A layer's base and flow map in a moved snapshot (see `moveWetSnapshot`). */
|
|
389
414
|
export interface WetSnapshotLaneMove {
|
|
390
415
|
base?: TiledSurface;
|
|
416
|
+
light?: TiledSurface;
|
|
391
417
|
flow?: WetFlowField | null;
|
|
392
418
|
}
|
|
393
419
|
/**
|
|
@@ -17,6 +17,10 @@
|
|
|
17
17
|
* - **Display.** Each lane has a `base` surface: the layer's pixels under the wet paint. `display`
|
|
18
18
|
* gives the base with every live tile shaded (`filmPixel`), as an ordinary RGBA surface for the
|
|
19
19
|
* compositor. Tiles that dry are baked into the base and their slots freed.
|
|
20
|
+
* - **Light paint.** Light is a fifth mass channel (suspended and settled), moving exactly as
|
|
21
|
+
* pigment does. A lane's `light` surface (one channel, see `paint-editor/light.ts`) is the
|
|
22
|
+
* light under the wet paint; `lightDisplay` shades the live light over it and drying bakes it
|
|
23
|
+
* in, as the colour is.
|
|
20
24
|
* - **Engine B (WebGPU).** With a GPU engine attached (`attachGpu`) and at least `gpuMinTiles` live
|
|
21
25
|
* tiles, the GPU keeps a mirror of the slots: each edit uploads the rows it changed, each batch
|
|
22
26
|
* runs on the GPU too, and `displayGpu` shades every stale tile there at once. In lead mode
|
|
@@ -30,8 +34,8 @@ import { type WetWorkerLayout } from './wasm.js';
|
|
|
30
34
|
import type { WetGpuEngine } from './gpu.js';
|
|
31
35
|
/** Wet layers a world can hold at once. */
|
|
32
36
|
export declare const MAX_WET_LANES = 8;
|
|
33
|
-
/** Tile slots at most (about 3.
|
|
34
|
-
export declare const MAX_WET_SLOTS =
|
|
37
|
+
/** Tile slots at most (about 3.75 GB, inside wasm32's 4 GB). Water reaching a tile past this is lost. */
|
|
38
|
+
export declare const MAX_WET_SLOTS = 328;
|
|
35
39
|
/** A flow map: a vector per document pixel, in cells per step² at strength 1. */
|
|
36
40
|
export type WetFlowField = (x: number, y: number) => readonly [number, number];
|
|
37
41
|
/** The paper as the simulation reads it. */
|
|
@@ -62,6 +66,8 @@ export interface WetLaneOptions {
|
|
|
62
66
|
flow?: WetFlowField | null;
|
|
63
67
|
/** Flow map strength (default 1 when a flow map is given). */
|
|
64
68
|
flowStrength?: number;
|
|
69
|
+
/** The layer's light paint under the wet paint (one channel; default none). */
|
|
70
|
+
light?: TiledSurface | null;
|
|
65
71
|
}
|
|
66
72
|
/** Totals for one wet layer. */
|
|
67
73
|
export interface WetLaneStats {
|
|
@@ -87,6 +93,8 @@ export interface WetSnapshot {
|
|
|
87
93
|
flow: WetFlowField | null;
|
|
88
94
|
flowStrength: number;
|
|
89
95
|
base: TiledSurface;
|
|
96
|
+
light?: TiledSurface;
|
|
97
|
+
lit?: boolean;
|
|
90
98
|
}>;
|
|
91
99
|
/** Per active key: the current set and the deposit planes; and its last flags. */
|
|
92
100
|
readonly slots: ReadonlyMap<number, {
|
|
@@ -177,6 +185,12 @@ export declare class WetWorld {
|
|
|
177
185
|
getBase(id: string): TiledSurface;
|
|
178
186
|
/** Replaces the pixels under a layer's wet paint. */
|
|
179
187
|
setBase(id: string, base: TiledSurface): void;
|
|
188
|
+
/** The light paint under a layer's wet paint (one channel). */
|
|
189
|
+
getLight(id: string): TiledSurface;
|
|
190
|
+
/** Whether a layer has light paint, under its wet paint or in it. */
|
|
191
|
+
isLit(id: string): boolean;
|
|
192
|
+
/** Replaces the light paint under a layer's wet paint. */
|
|
193
|
+
setLight(id: string, light: TiledSurface): void;
|
|
180
194
|
private pack;
|
|
181
195
|
private touchAll;
|
|
182
196
|
private laneIndexOf;
|
|
@@ -247,10 +261,10 @@ export declare class WetWorld {
|
|
|
247
261
|
private addWaterAt;
|
|
248
262
|
/**
|
|
249
263
|
* Lays paint: `water` depth and pigment mass `pigment` (K r, g, b, S) per unit of coverage, or
|
|
250
|
-
* per pixel from `field` (4 values per pixel of `rect`)
|
|
251
|
-
* the paper (settled).
|
|
264
|
+
* per pixel from `field` (4 values per pixel of `rect`), and `light` (light paint mass) per unit
|
|
265
|
+
* of coverage. Pigment and light without water land straight in the paper (settled).
|
|
252
266
|
*/
|
|
253
|
-
paint(id: string, rect: RasterRect, cov: ArrayLike<number> | null, water: number, pigment: ArrayLike<number> | null, field?: ArrayLike<number> | null): void;
|
|
267
|
+
paint(id: string, rect: RasterRect, cov: ArrayLike<number> | null, water: number, pigment: ArrayLike<number> | null, field?: ArrayLike<number> | null, light?: number): void;
|
|
254
268
|
/** Damp paper: fills the paper's water towards its capacity by `amount` (0..1) × coverage, plus a thin film of surface water. */
|
|
255
269
|
wetPaper(id: string, rect: RasterRect, cov: ArrayLike<number> | null, amount: number): void;
|
|
256
270
|
/**
|
|
@@ -261,16 +275,17 @@ export declare class WetWorld {
|
|
|
261
275
|
remove(id: string, rect: RasterRect, cov: ArrayLike<number> | null, water: number, suspended: number, settled: number, paperWater?: number): void;
|
|
262
276
|
/** Pushes the water: adds velocity (`ux`, `uy` cells per step, each at most 0.1) × coverage. */
|
|
263
277
|
push(id: string, rect: RasterRect, cov: ArrayLike<number> | null, ux: number, uy: number): void;
|
|
264
|
-
/** Blends wet paint: each wet cell's suspended pigment moves `strength` × coverage towards the footprint's mean. */
|
|
278
|
+
/** Blends wet paint: each wet cell's suspended pigment (and light) moves `strength` × coverage towards the footprint's mean. */
|
|
265
279
|
blend(id: string, rect: RasterRect, cov: ArrayLike<number> | null, strength: number): void;
|
|
266
280
|
/**
|
|
267
281
|
* Drags wet paint by (`dx`, `dy`) cells: each footprint cell takes `strength` × coverage of the
|
|
268
|
-
* water and suspended pigment of the cell it came from (a smudge through wet paint).
|
|
282
|
+
* water and suspended pigment (and light) of the cell it came from (a smudge through wet paint).
|
|
269
283
|
*/
|
|
270
284
|
drag(id: string, rect: RasterRect, cov: ArrayLike<number> | null, dx: number, dy: number, strength: number): void;
|
|
271
285
|
/**
|
|
272
286
|
* Re-wetting: lifts `amount` × coverage of the dried paint in the layer's pixels (`base`) back into
|
|
273
|
-
* the paper as settled pigment, so water can move it again
|
|
287
|
+
* the paper as settled pigment, so water can move it again, and the same share of its light
|
|
288
|
+
* paint (`light`) as settled light. Only where there is surface water.
|
|
274
289
|
*/
|
|
275
290
|
rewet(id: string, rect: RasterRect, cov: ArrayLike<number> | null, amount: number, paper: readonly [number, number, number]): void;
|
|
276
291
|
/**
|
|
@@ -284,6 +299,8 @@ export declare class WetWorld {
|
|
|
284
299
|
* Returns whether any pixel changed.
|
|
285
300
|
*/
|
|
286
301
|
private bakeKey;
|
|
302
|
+
/** `shadeSlot` for light paint: one channel over a light tile (see `shadeLightTile`); `null` when nothing would change. */
|
|
303
|
+
private shadeLightSlot;
|
|
287
304
|
/**
|
|
288
305
|
* Shades one slot over a base tile. `display`: the wet look (suspended + settled, wet paper a
|
|
289
306
|
* little darker); `bake`: settled pigment only; `bake-all`: suspended and settled (dry now).
|
|
@@ -292,6 +309,8 @@ export declare class WetWorld {
|
|
|
292
309
|
private shadeSlot;
|
|
293
310
|
/** The layer's pixels with all its wet paint dried where it is (the bake of "dry on save"); changes nothing. */
|
|
294
311
|
bakedSurface(id: string): TiledSurface;
|
|
312
|
+
/** The layer's light paint with all its wet paint dried where it is (`bakedSurface` for light); changes nothing. */
|
|
313
|
+
bakedLight(id: string): TiledSurface;
|
|
295
314
|
/**
|
|
296
315
|
* Sums over a footprint of a lane, weighted by coverage: `weight` (coverage), `water` (surface
|
|
297
316
|
* depth), `wet` (coverage of wet cells), `pigment` (suspended, 4 channels), `settled` (4 channels).
|
|
@@ -323,6 +342,12 @@ export declare class WetWorld {
|
|
|
323
342
|
changed: RasterRect[];
|
|
324
343
|
pending: number;
|
|
325
344
|
};
|
|
345
|
+
/**
|
|
346
|
+
* The layer's light paint with its live light shaded in (`null` when the layer has none): the
|
|
347
|
+
* light under the wet paint with each live tile's light over it. Like `display`, every stale
|
|
348
|
+
* tile is reshaded (light tiles are cheap: one channel, no colour maths).
|
|
349
|
+
*/
|
|
350
|
+
lightDisplay(id: string): TiledSurface | null;
|
|
326
351
|
/**
|
|
327
352
|
* The water as an overlay tile (RGBA, blue, alpha from surface depth and damp paper) for a
|
|
328
353
|
* document tile, or `null` where nothing is wet.
|
|
@@ -388,6 +413,7 @@ export declare class WetWorld {
|
|
|
388
413
|
/** A layer's base and flow map in a moved snapshot (see `moveWetSnapshot`). */
|
|
389
414
|
export interface WetSnapshotLaneMove {
|
|
390
415
|
base?: TiledSurface;
|
|
416
|
+
light?: TiledSurface;
|
|
391
417
|
flow?: WetFlowField | null;
|
|
392
418
|
}
|
|
393
419
|
/**
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backlit paper: the paper as a light source behind the paint (a lightbox, stained glass). The
|
|
3
|
+
* light that makes it through the paint is drawn as one Linear Dodge (Add) layer, "Backlight", at
|
|
4
|
+
* the top of the stack (opaque pixels whose colour is the light added, so the sRGB blend adds
|
|
5
|
+
* exactly that; the linear light value is added as is, an approximation of adding light) (it shines through everything, so nothing composited above it may cover
|
|
6
|
+
* it), with a soft spill where it comes through paint, so a lit glaze lights its surroundings.
|
|
7
|
+
*
|
|
8
|
+
* Per pixel, the light starts as `backlight × backlightColor` (linear), a little stronger in the
|
|
9
|
+
* paper's valleys (thinner paper, by its grain depth), and passes through each visible pixel layer
|
|
10
|
+
* from the bottom up:
|
|
11
|
+
*
|
|
12
|
+
* - **Paint as a film over the paper.** A layer pixel (colour `c`, alpha `a`) over the paper `p`
|
|
13
|
+
* shows `e = a·c + (1 − a)·p`. Its transmission is `T = min(1, e / p)` per channel (linear):
|
|
14
|
+
* exact for a transparent glaze, whose film over the paper is `T·p` (the wet bake writes
|
|
15
|
+
* watercolour that way). Alpha above the least the colour needs over the paper
|
|
16
|
+
* (`aMin`, as `film.ts` computes it) is hiding: `hide = (a − aMin) / (1 − aMin)`, and the light
|
|
17
|
+
* through is `(1 − hide)·T`. The wet bake writes gouache and oil with their hiding in alpha, and
|
|
18
|
+
* opaque dry paint (alpha 1) hides by this rule too, so glazes glow in their own colour and
|
|
19
|
+
* opaque paint blocks the light.
|
|
20
|
+
* - **Thick paint** blocks the light by its height; impasto clarity (material A) lets some through.
|
|
21
|
+
* - **Layer opacity** mixes towards no change. Blend modes are not modelled (every layer is read
|
|
22
|
+
* as a film); over other layers rather than the paper the film rule is an approximation.
|
|
23
|
+
*
|
|
24
|
+
* Exact for watercolour straight over the paper; approximate for stacks of layers and for blend
|
|
25
|
+
* modes. Changing the backlight never repaints: it is a few numbers on the paper.
|
|
26
|
+
*/
|
|
27
|
+
import { TiledSurface } from '../raster/surface.cjs';
|
|
28
|
+
import { type LightSpill } from './light.cjs';
|
|
29
|
+
import { type PaperGrain, type PaperSettings } from './paper.cjs';
|
|
30
|
+
import type { ThickChannels } from './thick.cjs';
|
|
31
|
+
/** Default backlight colour: warm white, like a lightbox. */
|
|
32
|
+
export declare const DEFAULT_BACKLIGHT_COLOR = "#fff1d6";
|
|
33
|
+
/** Spill of the light that comes through paint (px, strength), at backlight 1. */
|
|
34
|
+
export declare const BACKLIGHT_SPILL: Readonly<LightSpill>;
|
|
35
|
+
/** One visible pixel layer as the backlight reads it, bottom first. */
|
|
36
|
+
export interface BacklitLayer {
|
|
37
|
+
surface: TiledSurface;
|
|
38
|
+
offset: {
|
|
39
|
+
x: number;
|
|
40
|
+
y: number;
|
|
41
|
+
};
|
|
42
|
+
/** Effective opacity (its groups' opacities multiplied in). */
|
|
43
|
+
opacity: number;
|
|
44
|
+
thick?: ThickChannels;
|
|
45
|
+
}
|
|
46
|
+
/** The paper's backlight (0 when it has none). */
|
|
47
|
+
export declare function backlightOf(paper: PaperSettings): number;
|
|
48
|
+
/**
|
|
49
|
+
* Computes and caches the backlight per 256 px document tile: a tile is recomputed only when one of
|
|
50
|
+
* the layer tiles over it (or the paper, or the layer list) changed.
|
|
51
|
+
*/
|
|
52
|
+
export declare class BacklightCache {
|
|
53
|
+
private tiles;
|
|
54
|
+
private key;
|
|
55
|
+
private spillOf;
|
|
56
|
+
private out;
|
|
57
|
+
/**
|
|
58
|
+
* The backlight layer's pixels for `layers` (bottom first) on `paper` over a `width` × `height`
|
|
59
|
+
* canvas, or `null` when the paper has no backlight. `spillFrom` is the committed painting (the
|
|
60
|
+
* spill is drawn from it, so a stroke in progress does not redo the blur every frame).
|
|
61
|
+
*/
|
|
62
|
+
surface(paper: PaperSettings, grain: PaperGrain, width: number, height: number, layers: readonly BacklitLayer[], spillFrom: BacklightCache | null): {
|
|
63
|
+
light: TiledSurface;
|
|
64
|
+
color: TiledSurface;
|
|
65
|
+
painted: TiledSurface;
|
|
66
|
+
} | null;
|
|
67
|
+
/**
|
|
68
|
+
* The full Backlight layer: the light through the paint (`current`) plus the spill of the light
|
|
69
|
+
* through the committed paint (`committed`), both Linear Dodge. Cached on their tiles.
|
|
70
|
+
*/
|
|
71
|
+
layer(current: {
|
|
72
|
+
light: TiledSurface;
|
|
73
|
+
}, committed: {
|
|
74
|
+
color: TiledSurface;
|
|
75
|
+
painted: TiledSurface;
|
|
76
|
+
} | null, amount: number): TiledSurface;
|
|
77
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backlit paper: the paper as a light source behind the paint (a lightbox, stained glass). The
|
|
3
|
+
* light that makes it through the paint is drawn as one Linear Dodge (Add) layer, "Backlight", at
|
|
4
|
+
* the top of the stack (opaque pixels whose colour is the light added, so the sRGB blend adds
|
|
5
|
+
* exactly that; the linear light value is added as is, an approximation of adding light) (it shines through everything, so nothing composited above it may cover
|
|
6
|
+
* it), with a soft spill where it comes through paint, so a lit glaze lights its surroundings.
|
|
7
|
+
*
|
|
8
|
+
* Per pixel, the light starts as `backlight × backlightColor` (linear), a little stronger in the
|
|
9
|
+
* paper's valleys (thinner paper, by its grain depth), and passes through each visible pixel layer
|
|
10
|
+
* from the bottom up:
|
|
11
|
+
*
|
|
12
|
+
* - **Paint as a film over the paper.** A layer pixel (colour `c`, alpha `a`) over the paper `p`
|
|
13
|
+
* shows `e = a·c + (1 − a)·p`. Its transmission is `T = min(1, e / p)` per channel (linear):
|
|
14
|
+
* exact for a transparent glaze, whose film over the paper is `T·p` (the wet bake writes
|
|
15
|
+
* watercolour that way). Alpha above the least the colour needs over the paper
|
|
16
|
+
* (`aMin`, as `film.ts` computes it) is hiding: `hide = (a − aMin) / (1 − aMin)`, and the light
|
|
17
|
+
* through is `(1 − hide)·T`. The wet bake writes gouache and oil with their hiding in alpha, and
|
|
18
|
+
* opaque dry paint (alpha 1) hides by this rule too, so glazes glow in their own colour and
|
|
19
|
+
* opaque paint blocks the light.
|
|
20
|
+
* - **Thick paint** blocks the light by its height; impasto clarity (material A) lets some through.
|
|
21
|
+
* - **Layer opacity** mixes towards no change. Blend modes are not modelled (every layer is read
|
|
22
|
+
* as a film); over other layers rather than the paper the film rule is an approximation.
|
|
23
|
+
*
|
|
24
|
+
* Exact for watercolour straight over the paper; approximate for stacks of layers and for blend
|
|
25
|
+
* modes. Changing the backlight never repaints: it is a few numbers on the paper.
|
|
26
|
+
*/
|
|
27
|
+
import { TiledSurface } from '../raster/surface.js';
|
|
28
|
+
import { type LightSpill } from './light.js';
|
|
29
|
+
import { type PaperGrain, type PaperSettings } from './paper.js';
|
|
30
|
+
import type { ThickChannels } from './thick.js';
|
|
31
|
+
/** Default backlight colour: warm white, like a lightbox. */
|
|
32
|
+
export declare const DEFAULT_BACKLIGHT_COLOR = "#fff1d6";
|
|
33
|
+
/** Spill of the light that comes through paint (px, strength), at backlight 1. */
|
|
34
|
+
export declare const BACKLIGHT_SPILL: Readonly<LightSpill>;
|
|
35
|
+
/** One visible pixel layer as the backlight reads it, bottom first. */
|
|
36
|
+
export interface BacklitLayer {
|
|
37
|
+
surface: TiledSurface;
|
|
38
|
+
offset: {
|
|
39
|
+
x: number;
|
|
40
|
+
y: number;
|
|
41
|
+
};
|
|
42
|
+
/** Effective opacity (its groups' opacities multiplied in). */
|
|
43
|
+
opacity: number;
|
|
44
|
+
thick?: ThickChannels;
|
|
45
|
+
}
|
|
46
|
+
/** The paper's backlight (0 when it has none). */
|
|
47
|
+
export declare function backlightOf(paper: PaperSettings): number;
|
|
48
|
+
/**
|
|
49
|
+
* Computes and caches the backlight per 256 px document tile: a tile is recomputed only when one of
|
|
50
|
+
* the layer tiles over it (or the paper, or the layer list) changed.
|
|
51
|
+
*/
|
|
52
|
+
export declare class BacklightCache {
|
|
53
|
+
private tiles;
|
|
54
|
+
private key;
|
|
55
|
+
private spillOf;
|
|
56
|
+
private out;
|
|
57
|
+
/**
|
|
58
|
+
* The backlight layer's pixels for `layers` (bottom first) on `paper` over a `width` × `height`
|
|
59
|
+
* canvas, or `null` when the paper has no backlight. `spillFrom` is the committed painting (the
|
|
60
|
+
* spill is drawn from it, so a stroke in progress does not redo the blur every frame).
|
|
61
|
+
*/
|
|
62
|
+
surface(paper: PaperSettings, grain: PaperGrain, width: number, height: number, layers: readonly BacklitLayer[], spillFrom: BacklightCache | null): {
|
|
63
|
+
light: TiledSurface;
|
|
64
|
+
color: TiledSurface;
|
|
65
|
+
painted: TiledSurface;
|
|
66
|
+
} | null;
|
|
67
|
+
/**
|
|
68
|
+
* The full Backlight layer: the light through the paint (`current`) plus the spill of the light
|
|
69
|
+
* through the committed paint (`committed`), both Linear Dodge. Cached on their tiles.
|
|
70
|
+
*/
|
|
71
|
+
layer(current: {
|
|
72
|
+
light: TiledSurface;
|
|
73
|
+
}, committed: {
|
|
74
|
+
color: TiledSurface;
|
|
75
|
+
painted: TiledSurface;
|
|
76
|
+
} | null, amount: number): TiledSurface;
|
|
77
|
+
}
|
|
@@ -318,6 +318,9 @@ export declare class PaintEditorController {
|
|
|
318
318
|
/** Light paint: each layer's spill settings (saved with the document, not undo steps; missing = the defaults). */
|
|
319
319
|
private lightSpills;
|
|
320
320
|
private readonly lightCaches;
|
|
321
|
+
/** Backlit paper: the light through the paint as drawn (live strokes too), and as committed (its spill). */
|
|
322
|
+
private readonly backlightView;
|
|
323
|
+
private readonly backlightCommitted;
|
|
321
324
|
/** Live effect paint: playing and the frame rate cap (editor state), and the time the view shows. */
|
|
322
325
|
private effectPlaybackState;
|
|
323
326
|
private effectTime;
|
|
@@ -917,6 +920,14 @@ export declare class PaintEditorController {
|
|
|
917
920
|
* progress does not redraw the blur every frame).
|
|
918
921
|
*/
|
|
919
922
|
private lightLayers;
|
|
923
|
+
/** Visible pixel layers bottom first, as the backlight reads them (group opacities multiplied in). */
|
|
924
|
+
private backlitLayers;
|
|
925
|
+
/**
|
|
926
|
+
* Backlit paper: the light that makes it through `base` (the layers as drawn), with the spill of
|
|
927
|
+
* the light through the committed painting, as a Linear Dodge (Add) layer for the top of the
|
|
928
|
+
* stack; `null` when the paper has no backlight.
|
|
929
|
+
*/
|
|
930
|
+
private backlightLayer;
|
|
920
931
|
private renderLayers;
|
|
921
932
|
/**
|
|
922
933
|
* Composites the viewport stack (paper, view-only underlays, layers with the live stroke) tile by
|
|
@@ -318,6 +318,9 @@ export declare class PaintEditorController {
|
|
|
318
318
|
/** Light paint: each layer's spill settings (saved with the document, not undo steps; missing = the defaults). */
|
|
319
319
|
private lightSpills;
|
|
320
320
|
private readonly lightCaches;
|
|
321
|
+
/** Backlit paper: the light through the paint as drawn (live strokes too), and as committed (its spill). */
|
|
322
|
+
private readonly backlightView;
|
|
323
|
+
private readonly backlightCommitted;
|
|
321
324
|
/** Live effect paint: playing and the frame rate cap (editor state), and the time the view shows. */
|
|
322
325
|
private effectPlaybackState;
|
|
323
326
|
private effectTime;
|
|
@@ -917,6 +920,14 @@ export declare class PaintEditorController {
|
|
|
917
920
|
* progress does not redraw the blur every frame).
|
|
918
921
|
*/
|
|
919
922
|
private lightLayers;
|
|
923
|
+
/** Visible pixel layers bottom first, as the backlight reads them (group opacities multiplied in). */
|
|
924
|
+
private backlitLayers;
|
|
925
|
+
/**
|
|
926
|
+
* Backlit paper: the light that makes it through `base` (the layers as drawn), with the spill of
|
|
927
|
+
* the light through the committed painting, as a Linear Dodge (Add) layer for the top of the
|
|
928
|
+
* stack; `null` when the paper has no backlight.
|
|
929
|
+
*/
|
|
930
|
+
private backlightLayer;
|
|
920
931
|
private renderLayers;
|
|
921
932
|
/**
|
|
922
933
|
* Composites the viewport stack (paper, view-only underlays, layers with the live stroke) tile by
|