@pixerate/editor 0.275.1 → 0.277.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 +6 -6
- package/dist/brushes/index.cjs +84 -71
- package/dist/brushes/index.js +20 -7
- package/dist/brushes/patch.d.cts +4 -4
- package/dist/brushes/patch.d.ts +4 -4
- package/dist/brushes/profiles.d.cts +4 -0
- package/dist/brushes/profiles.d.ts +4 -0
- package/dist/brushes/schema.d.cts +2 -0
- package/dist/brushes/schema.d.ts +2 -0
- package/dist/brushes/types.d.cts +32 -1
- package/dist/brushes/types.d.ts +32 -1
- package/dist/{brushstrokeRender-2RQL46WB.cjs → brushstrokeRender-7HOMKZNO.cjs} +21 -21
- package/dist/{brushstrokeRender-WGY4DZHF.js → brushstrokeRender-EIK3625T.js} +5 -5
- package/dist/canvas/index.cjs +13 -13
- package/dist/canvas/index.js +1 -1
- package/dist/{chunk-T6KNJVBP.cjs → chunk-4NZTK7LM.cjs} +35 -35
- package/dist/{chunk-LMG57L5A.js → chunk-CTHWXW5M.js} +121 -8
- package/dist/{chunk-43XJC3PP.js → chunk-DWPFGWW5.js} +1 -1
- package/dist/{chunk-MSWLJI4G.js → chunk-FNIWHSLI.js} +2 -2
- package/dist/{chunk-JDXWLCXF.cjs → chunk-H3EME3S5.cjs} +2 -2
- package/dist/{chunk-Y2ISSVPH.js → chunk-HHX7ST6Z.js} +167 -9
- package/dist/{chunk-6QNDGMK7.cjs → chunk-HRUK5TFW.cjs} +187 -45
- package/dist/{chunk-NIBFKXMD.cjs → chunk-IFWLZZCW.cjs} +619 -2
- package/dist/{chunk-W6JDUXP3.js → chunk-J23JOHPR.js} +1 -1
- package/dist/{chunk-HVO6XCI4.js → chunk-JPB65KQ6.js} +1 -1
- package/dist/{chunk-Y354ETAE.cjs → chunk-JVFGK3DK.cjs} +69 -58
- package/dist/{chunk-ACTHSQOI.js → chunk-LDZOXESA.js} +618 -1
- package/dist/{chunk-IEEY5RJV.js → chunk-LZE2QZCT.js} +1 -1
- package/dist/{chunk-DHC4E2DU.cjs → chunk-MITQGHN3.cjs} +121 -8
- package/dist/{chunk-75SYKUOT.js → chunk-N4MCWQZ7.js} +1 -1
- package/dist/{chunk-G5TCMKX5.js → chunk-NJLPW4MM.js} +17 -6
- package/dist/{chunk-STLTOISW.cjs → chunk-NPPMKMCU.cjs} +17 -17
- package/dist/{chunk-OLZXXAER.cjs → chunk-PEQWARCP.cjs} +408 -250
- package/dist/{chunk-ZM7IKQ4X.js → chunk-PPDUCZZV.js} +152 -10
- package/dist/{chunk-RAPNRK4R.cjs → chunk-QBZEC2JJ.cjs} +88 -88
- package/dist/{chunk-RJGW3RQS.js → chunk-ROURHJYT.js} +1 -1
- package/dist/{chunk-62MFUHSI.cjs → chunk-UQXULAMQ.cjs} +16 -16
- package/dist/{chunk-YYZC2EQO.cjs → chunk-VNF7A2JA.cjs} +23 -23
- package/dist/{chunk-C6VB7CPY.cjs → chunk-WFSYZO5Z.cjs} +1 -1
- package/dist/image-editor/index.cjs +880 -852
- package/dist/image-editor/index.js +36 -8
- package/dist/paint/index.cjs +33 -5
- package/dist/paint/index.d.cts +1 -0
- package/dist/paint/index.d.ts +1 -0
- package/dist/paint/index.js +32 -4
- package/dist/paint/live-patterns.d.cts +149 -0
- package/dist/paint/live-patterns.d.ts +149 -0
- package/dist/paint/wet/world.d.cts +13 -0
- package/dist/paint/wet/world.d.ts +13 -0
- package/dist/paint-editor/brush-model.d.cts +21 -1
- package/dist/paint-editor/brush-model.d.ts +21 -1
- package/dist/paint-editor/controller.d.cts +102 -1
- package/dist/paint-editor/controller.d.ts +102 -1
- package/dist/paint-editor/document.d.cts +8 -1
- package/dist/paint-editor/document.d.ts +8 -1
- package/dist/paint-editor/ferro-tools.d.cts +10 -0
- package/dist/paint-editor/ferro-tools.d.ts +10 -0
- package/dist/paint-editor/ferro.d.cts +134 -0
- package/dist/paint-editor/ferro.d.ts +134 -0
- package/dist/paint-editor/index.cjs +2291 -904
- package/dist/paint-editor/index.d.cts +2 -0
- package/dist/paint-editor/index.d.ts +2 -0
- package/dist/paint-editor/index.js +1533 -146
- package/dist/paint-editor/stroke.d.cts +14 -0
- package/dist/paint-editor/stroke.d.ts +14 -0
- package/dist/paint-editor/thick.d.cts +15 -2
- package/dist/paint-editor/thick.d.ts +15 -2
- package/dist/paint-editor/ui.d.cts +7 -1
- package/dist/paint-editor/ui.d.ts +7 -1
- package/dist/paint-editor/wet-tools.d.cts +42 -0
- package/dist/paint-editor/wet-tools.d.ts +42 -0
- package/dist/paint-editor/wet.d.cts +22 -1
- package/dist/paint-editor/wet.d.ts +22 -1
- package/dist/vector/index.cjs +1002 -1002
- package/dist/vector/index.js +7 -7
- package/package.json +1 -1
- package/skills/pixerate-brushes/SKILL.md +1 -0
- package/skills/pixerate-paint-editor/SKILL.md +11 -29
- package/skills/pixerate-paint-editor/references/brush-facets.md +1 -0
- package/skills/pixerate-paint-editor/references/ferrofluid.md +36 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Live patterns: Gray-Scott reaction-diffusion fields `(U, V)` that grow inside wet paint and
|
|
3
|
+
* freeze where the paint dries.
|
|
4
|
+
*
|
|
5
|
+
* Each wet layer with live patterns active holds a sparse set of half-resolution (`128 × 128`)
|
|
6
|
+
* pattern tiles paired with the `256 × 256` tiles of `WetWorld`, outside the wet-media LBM kernel.
|
|
7
|
+
* Every wet simulation step runs Gray-Scott substeps gated by the wet layer's water (`P_RHO` +
|
|
8
|
+
* `P_SW > DRY_EPS`): where water remains, `U` and `V` react and diffuse into Turing spots,
|
|
9
|
+
* stripes, coral dendrites, mazes or worms; where the paint has dried, the reaction and diffusion
|
|
10
|
+
* rates drop to zero so the pattern freezes in place.
|
|
11
|
+
*/
|
|
12
|
+
import { TiledSurface, type RasterRect } from '../raster/surface.js';
|
|
13
|
+
/** Side length of one half-resolution pattern tile (`WET_TILE / 2`). */
|
|
14
|
+
export declare const PATTERN_TILE = 128;
|
|
15
|
+
/** Cells per pattern tile (`128 × 128`). */
|
|
16
|
+
export declare const PATTERN_CELLS: number;
|
|
17
|
+
/** Gray-Scott substeps run for each wet simulation step. */
|
|
18
|
+
export declare const PATTERN_SUBSTEPS = 4;
|
|
19
|
+
/** Threshold of `V` above which a cell counts as pattern-bearing in stats and relief. */
|
|
20
|
+
export declare const PATTERN_V_EPS = 0.02;
|
|
21
|
+
/** Named Gray-Scott Pearson pattern presets. */
|
|
22
|
+
export declare const LIVE_PATTERN_KINDS: readonly ["spots", "stripes", "coral", "maze", "worms"];
|
|
23
|
+
export type LivePatternKind = (typeof LIVE_PATTERN_KINDS)[number];
|
|
24
|
+
export interface LivePatternPresetInfo {
|
|
25
|
+
readonly kind: LivePatternKind;
|
|
26
|
+
readonly label: string;
|
|
27
|
+
readonly description: string;
|
|
28
|
+
readonly feed: number;
|
|
29
|
+
readonly kill: number;
|
|
30
|
+
}
|
|
31
|
+
/** Built-in Pearson (1993) feed / kill parameter presets. */
|
|
32
|
+
export declare const LIVE_PATTERN_PRESETS: Readonly<Record<LivePatternKind, LivePatternPresetInfo>>;
|
|
33
|
+
/** Resolved live-pattern parameters for a brush or wet layer. */
|
|
34
|
+
export interface LivePatternsSettings {
|
|
35
|
+
/** Named Gray-Scott preset (`spots`, `stripes`, `coral`, `maze`, `worms`). */
|
|
36
|
+
pattern: LivePatternKind;
|
|
37
|
+
/** Gray-Scott feed rate F (0.01..0.1). */
|
|
38
|
+
feed: number;
|
|
39
|
+
/** Gray-Scott kill rate k (0.03..0.08). */
|
|
40
|
+
kill: number;
|
|
41
|
+
/** Pattern feature scale (0.5..4, default 1). Scales the diffusion rates. */
|
|
42
|
+
scale: number;
|
|
43
|
+
/** Visual contrast of the V concentration field (0..2, default 1). */
|
|
44
|
+
contrast: number;
|
|
45
|
+
/** Optional hex colour (`#rrggbb`) that V blends the wet paint towards; `null` modulates pigment contrast. */
|
|
46
|
+
secondColor: string | null;
|
|
47
|
+
/** Impasto relief written to the layer's thick height map as patterns grow (0..1, default 0). */
|
|
48
|
+
relief: number;
|
|
49
|
+
}
|
|
50
|
+
export type LivePatternsInput = Partial<LivePatternsSettings>;
|
|
51
|
+
export declare const DEFAULT_LIVE_PATTERNS: Readonly<LivePatternsSettings>;
|
|
52
|
+
export declare function isLivePatternKind(v: unknown): v is LivePatternKind;
|
|
53
|
+
/** Normalizes a hex colour string (`#rgb` or `#rrggbb`) to lowercase `#rrggbb`, or `null`. */
|
|
54
|
+
export declare function normalizePatternHexColor(v: unknown, fallback?: string | null): string | null;
|
|
55
|
+
/** Parses a `#rrggbb` colour to `[r, g, b]` bytes, or `null`. */
|
|
56
|
+
export declare function parsePatternHexColor(hex: string | null): [number, number, number] | null;
|
|
57
|
+
/** Clamps and fills a `LivePatternsSettings` object from partial input. */
|
|
58
|
+
export declare function normalizeLivePatterns(raw?: LivePatternsInput | null | undefined, base?: LivePatternsSettings): LivePatternsSettings;
|
|
59
|
+
/** Deterministic 32-bit integer hash in `[0, 1)` shared between TypeScript and Swift. */
|
|
60
|
+
export declare function patternNoise(gx: number, gy: number, seed: number): number;
|
|
61
|
+
/** Summary statistics for one wet layer's Gray-Scott field. */
|
|
62
|
+
export interface LivePatternStats {
|
|
63
|
+
/** Whether live patterns are enabled on this layer. */
|
|
64
|
+
enabled: boolean;
|
|
65
|
+
/** Current Gray-Scott reaction-diffusion settings for this layer. */
|
|
66
|
+
settings: LivePatternsSettings;
|
|
67
|
+
/** Half-resolution (`128 × 128`) tiles currently holding pattern state. */
|
|
68
|
+
activeTiles: number;
|
|
69
|
+
/** Pattern cells (`2 × 2` px each) where `V >= PATTERN_V_EPS`. */
|
|
70
|
+
patternCells: number;
|
|
71
|
+
/** Pattern cells where `V >= PATTERN_V_EPS` that are still wet (actively growing). */
|
|
72
|
+
wetPatternCells: number;
|
|
73
|
+
/** Mean `V` concentration across active pattern cells (0..1). */
|
|
74
|
+
meanV: number;
|
|
75
|
+
/** Peak `V` concentration across the layer (0..1). */
|
|
76
|
+
maxV: number;
|
|
77
|
+
/** Document pixel bounding box of active pattern cells, or `null` when none. */
|
|
78
|
+
bounds: RasterRect | null;
|
|
79
|
+
}
|
|
80
|
+
export interface LivePatternTileState {
|
|
81
|
+
readonly u: Float64Array;
|
|
82
|
+
readonly v: Float64Array;
|
|
83
|
+
readonly bakedV: Float64Array;
|
|
84
|
+
}
|
|
85
|
+
export interface LivePatternFieldSnapshot {
|
|
86
|
+
readonly settings: LivePatternsSettings;
|
|
87
|
+
readonly enabled: boolean;
|
|
88
|
+
readonly tiles: ReadonlyMap<number, LivePatternTileState>;
|
|
89
|
+
readonly bytes: number;
|
|
90
|
+
}
|
|
91
|
+
/** Callback returning whether a half-res pattern cell `(tx, ty, lx, ly)` still holds water. */
|
|
92
|
+
export type WetCellPredicate = (tx: number, ty: number, lx: number, ly: number) => boolean;
|
|
93
|
+
/**
|
|
94
|
+
* Per-wet-layer Gray-Scott reaction-diffusion field `(U, V)` stored in `128 × 128` tiles.
|
|
95
|
+
*/
|
|
96
|
+
export declare class LivePatternField {
|
|
97
|
+
width: number;
|
|
98
|
+
height: number;
|
|
99
|
+
tilesX: number;
|
|
100
|
+
tilesY: number;
|
|
101
|
+
settings: LivePatternsSettings;
|
|
102
|
+
enabled: boolean;
|
|
103
|
+
readonly tiles: Map<number, {
|
|
104
|
+
u: Float64Array;
|
|
105
|
+
v: Float64Array;
|
|
106
|
+
bakedV: Float64Array;
|
|
107
|
+
}>;
|
|
108
|
+
constructor(width: number, height: number, settings?: LivePatternsInput);
|
|
109
|
+
resize(width: number, height: number): void;
|
|
110
|
+
configure(settings: LivePatternsInput): LivePatternsSettings;
|
|
111
|
+
clear(): void;
|
|
112
|
+
private ensureTile;
|
|
113
|
+
/**
|
|
114
|
+
* Seeds Gray-Scott reagent `V` inside a circle at document coordinates `(cx, cy)` with document
|
|
115
|
+
* `radius` (pixels). Returns the number of half-resolution cells seeded.
|
|
116
|
+
*/
|
|
117
|
+
seedDisc(cx: number, cy: number, radius: number, seed?: number, strength?: number): number;
|
|
118
|
+
/**
|
|
119
|
+
* Advances the Gray-Scott reaction-diffusion field for `wetSteps` wet simulation steps.
|
|
120
|
+
* Only cells where `isWetCell(tx, ty, lx, ly)` is true update; dry cells have zero rate and freeze.
|
|
121
|
+
* Returns whether any cell updated.
|
|
122
|
+
*/
|
|
123
|
+
step(wetSteps: number, isWetCell: WetCellPredicate, canWakeTile?: (tx: number, ty: number) => boolean): boolean;
|
|
124
|
+
/**
|
|
125
|
+
* Bilinearly samples unbaked `V` (`max(0, v - bakedV)`) at document-tile pixel `(x, y)` in `0..255`.
|
|
126
|
+
*/
|
|
127
|
+
private sampleUnbakedV;
|
|
128
|
+
/**
|
|
129
|
+
* Blends the pattern's `V` concentration into a shaded `256 × 256` RGBA wet tile `out`.
|
|
130
|
+
* Returns whether any pixel in `out` was modified.
|
|
131
|
+
*/
|
|
132
|
+
shadeTile(tx: number, ty: number, out: Uint8ClampedArray, w: number, h: number): boolean;
|
|
133
|
+
/** Marks a tile's current `V` values as baked into the layer's base surface so they are not baked twice. */
|
|
134
|
+
markBaked(tx: number, ty: number): void;
|
|
135
|
+
/**
|
|
136
|
+
* When `settings.relief > 0`, writes pattern `V` ridges into a 1-channel thick height surface.
|
|
137
|
+
* Returns the updated height `TiledSurface`, or `currentHeight` when `relief <= 0` or nothing changed.
|
|
138
|
+
*/
|
|
139
|
+
applyReliefHeight(currentHeight: TiledSurface): TiledSurface;
|
|
140
|
+
/** Computes summary statistics of the layer's live pattern field. */
|
|
141
|
+
stats(isWetCell?: WetCellPredicate): LivePatternStats;
|
|
142
|
+
snapshot(): LivePatternFieldSnapshot;
|
|
143
|
+
restore(snap: LivePatternFieldSnapshot): void;
|
|
144
|
+
}
|
|
145
|
+
/** Shifts a `LivePatternFieldSnapshot` by `(tx0, ty0)` whole wet tiles for a resized canvas `to`. */
|
|
146
|
+
export declare function moveLivePatternSnapshot(snap: LivePatternFieldSnapshot, to: {
|
|
147
|
+
width: number;
|
|
148
|
+
height: number;
|
|
149
|
+
}, tx0: number, ty0: number): LivePatternFieldSnapshot;
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
* only feeds the display.
|
|
30
30
|
*/
|
|
31
31
|
import { TiledSurface, type RasterRect } from '../../raster/surface.cjs';
|
|
32
|
+
import { LivePatternField, type LivePatternFieldSnapshot, type LivePatternStats, type LivePatternsInput, type LivePatternsSettings } from '../live-patterns.cjs';
|
|
32
33
|
import { type WetPaper, type WetParams, type WetTilt } from './model.cjs';
|
|
33
34
|
import { type WetWorkerLayout } from './wasm.cjs';
|
|
34
35
|
import type { WetGpuEngine } from './gpu.cjs';
|
|
@@ -81,6 +82,8 @@ export interface WetLaneOptions {
|
|
|
81
82
|
flowStrength?: number;
|
|
82
83
|
/** The layer's light paint under the wet paint (one channel; default none). */
|
|
83
84
|
light?: TiledSurface | null;
|
|
85
|
+
/** Shared per-layer reaction-diffusion field outside the wet kernel. */
|
|
86
|
+
livePatterns?: LivePatternField;
|
|
84
87
|
/** Active ghost paint state on the layer, if any. */
|
|
85
88
|
ghost?: WetGhostState | null;
|
|
86
89
|
}
|
|
@@ -111,12 +114,15 @@ export interface WetSnapshot {
|
|
|
111
114
|
light?: TiledSurface;
|
|
112
115
|
lit?: boolean;
|
|
113
116
|
ghost?: WetGhostState | null;
|
|
117
|
+
livePatterns?: LivePatternFieldSnapshot;
|
|
114
118
|
}>;
|
|
115
119
|
/** Per active key: the current set and the deposit planes; and its last flags. */
|
|
116
120
|
readonly slots: ReadonlyMap<number, {
|
|
117
121
|
planes: Float32Array;
|
|
118
122
|
last: number;
|
|
119
123
|
}>;
|
|
124
|
+
/** Per-layer live-pattern snapshots (including layers whose water has already dried). */
|
|
125
|
+
readonly patterns?: ReadonlyMap<string, LivePatternFieldSnapshot>;
|
|
120
126
|
/** Bytes held. */
|
|
121
127
|
readonly bytes: number;
|
|
122
128
|
}
|
|
@@ -190,6 +196,13 @@ export declare class WetWorld {
|
|
|
190
196
|
removeLane(id: string): void;
|
|
191
197
|
getParams(id: string): WetParams;
|
|
192
198
|
setParams(id: string, params: Partial<WetParams>): WetParams;
|
|
199
|
+
getLivePatterns(id: string): LivePatternsSettings;
|
|
200
|
+
hasLivePatterns(id: string): boolean;
|
|
201
|
+
livePatternField(id: string): LivePatternField;
|
|
202
|
+
setLivePatterns(id: string, settings: LivePatternsInput): LivePatternsSettings;
|
|
203
|
+
seedLivePatterns(id: string, cx: number, cy: number, radius: number, seed?: number, strength?: number, settings?: LivePatternsInput): number;
|
|
204
|
+
livePatternStats(id: string): LivePatternStats;
|
|
205
|
+
private isPatternCellWet;
|
|
193
206
|
getTilt(): WetTilt;
|
|
194
207
|
setTilt(tilt: Partial<WetTilt>): WetTilt;
|
|
195
208
|
/** Changes the paper: heights of live tiles are refilled, rates repacked. */
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
* only feeds the display.
|
|
30
30
|
*/
|
|
31
31
|
import { TiledSurface, type RasterRect } from '../../raster/surface.js';
|
|
32
|
+
import { LivePatternField, type LivePatternFieldSnapshot, type LivePatternStats, type LivePatternsInput, type LivePatternsSettings } from '../live-patterns.js';
|
|
32
33
|
import { type WetPaper, type WetParams, type WetTilt } from './model.js';
|
|
33
34
|
import { type WetWorkerLayout } from './wasm.js';
|
|
34
35
|
import type { WetGpuEngine } from './gpu.js';
|
|
@@ -81,6 +82,8 @@ export interface WetLaneOptions {
|
|
|
81
82
|
flowStrength?: number;
|
|
82
83
|
/** The layer's light paint under the wet paint (one channel; default none). */
|
|
83
84
|
light?: TiledSurface | null;
|
|
85
|
+
/** Shared per-layer reaction-diffusion field outside the wet kernel. */
|
|
86
|
+
livePatterns?: LivePatternField;
|
|
84
87
|
/** Active ghost paint state on the layer, if any. */
|
|
85
88
|
ghost?: WetGhostState | null;
|
|
86
89
|
}
|
|
@@ -111,12 +114,15 @@ export interface WetSnapshot {
|
|
|
111
114
|
light?: TiledSurface;
|
|
112
115
|
lit?: boolean;
|
|
113
116
|
ghost?: WetGhostState | null;
|
|
117
|
+
livePatterns?: LivePatternFieldSnapshot;
|
|
114
118
|
}>;
|
|
115
119
|
/** Per active key: the current set and the deposit planes; and its last flags. */
|
|
116
120
|
readonly slots: ReadonlyMap<number, {
|
|
117
121
|
planes: Float32Array;
|
|
118
122
|
last: number;
|
|
119
123
|
}>;
|
|
124
|
+
/** Per-layer live-pattern snapshots (including layers whose water has already dried). */
|
|
125
|
+
readonly patterns?: ReadonlyMap<string, LivePatternFieldSnapshot>;
|
|
120
126
|
/** Bytes held. */
|
|
121
127
|
readonly bytes: number;
|
|
122
128
|
}
|
|
@@ -190,6 +196,13 @@ export declare class WetWorld {
|
|
|
190
196
|
removeLane(id: string): void;
|
|
191
197
|
getParams(id: string): WetParams;
|
|
192
198
|
setParams(id: string, params: Partial<WetParams>): WetParams;
|
|
199
|
+
getLivePatterns(id: string): LivePatternsSettings;
|
|
200
|
+
hasLivePatterns(id: string): boolean;
|
|
201
|
+
livePatternField(id: string): LivePatternField;
|
|
202
|
+
setLivePatterns(id: string, settings: LivePatternsInput): LivePatternsSettings;
|
|
203
|
+
seedLivePatterns(id: string, cx: number, cy: number, radius: number, seed?: number, strength?: number, settings?: LivePatternsInput): number;
|
|
204
|
+
livePatternStats(id: string): LivePatternStats;
|
|
205
|
+
private isPatternCellWet;
|
|
193
206
|
getTilt(): WetTilt;
|
|
194
207
|
setTilt(tilt: Partial<WetTilt>): WetTilt;
|
|
195
208
|
/** Changes the paper: heights of live tiles are refilled, rates repacked. */
|
|
@@ -8,7 +8,9 @@ import { type BlenderSettings, type SmudgeSettings } from '../paint/blending.cjs
|
|
|
8
8
|
import type { MixingModel } from '../paint/exchange.cjs';
|
|
9
9
|
import { type PaintGradientSource, type PaintSource } from '../paint/gradient-paint.cjs';
|
|
10
10
|
import { type MixerSettings } from '../paint/mixer.cjs';
|
|
11
|
+
import { DEFAULT_LIVE_PATTERNS, LIVE_PATTERN_KINDS, LIVE_PATTERN_PRESETS, normalizeLivePatterns, type LivePatternKind, type LivePatternsInput, type LivePatternsSettings } from '../paint/live-patterns.cjs';
|
|
11
12
|
import { type BristleSettings, type ParticleSettings, type StickerSettings } from './mark-settings.cjs';
|
|
13
|
+
export { DEFAULT_LIVE_PATTERNS, LIVE_PATTERN_KINDS, LIVE_PATTERN_PRESETS, normalizeLivePatterns, type LivePatternKind, type LivePatternsInput, type LivePatternsSettings };
|
|
12
14
|
/**
|
|
13
15
|
* How a brush makes marks: `dab` (dabs into a stroke buffer, or dab by dab through the pick-up /
|
|
14
16
|
* mix exchange when its behaviour asks for it), `eraser` (removes alpha), `mixer` (the Mixer
|
|
@@ -147,6 +149,17 @@ export interface MutationSettings {
|
|
|
147
149
|
}
|
|
148
150
|
export declare const DEFAULT_MUTATION: Readonly<MutationSettings>;
|
|
149
151
|
export declare function normalizeMutation(raw?: Partial<MutationSettings>, base?: MutationSettings): MutationSettings;
|
|
152
|
+
/** Ferrofluid paint: how much liquid ferrofluid a brush lays, and its Rosensweig spike settings (see `doc.ferro`). */
|
|
153
|
+
export interface FerroSettings {
|
|
154
|
+
/** How much liquid ferrofluid each dab lays, scaled by coverage and flow (0..1, default 0: none). */
|
|
155
|
+
amount: number;
|
|
156
|
+
/** Capillary wavelength (spike-to-spike spacing) in pixels (4..64, default 16). */
|
|
157
|
+
wavelength: number;
|
|
158
|
+
/** Critical magnetic field |B| threshold where spikes begin to rise (0.01..0.95, default 0.12). */
|
|
159
|
+
threshold: number;
|
|
160
|
+
}
|
|
161
|
+
export declare const DEFAULT_FERRO: Readonly<FerroSettings>;
|
|
162
|
+
export declare function normalizeFerro(raw?: number | Partial<FerroSettings> | null | undefined, base?: FerroSettings): FerroSettings;
|
|
150
163
|
export declare function normalizeImpasto(raw?: Partial<ImpastoSettings>, base?: ImpastoSettings): ImpastoSettings;
|
|
151
164
|
/** Multi-coloured brush: `tip` lays the colours across the tip, `dab` changes colour from dab to dab. */
|
|
152
165
|
export type MultiColorMode = 'off' | 'tip' | 'dab';
|
|
@@ -281,6 +294,8 @@ export interface PaintBrush {
|
|
|
281
294
|
ghost?: GhostSettings;
|
|
282
295
|
/** Mutation paint settings (missing when not a mutation brush). */
|
|
283
296
|
mutation?: MutationSettings;
|
|
297
|
+
/** Ferrofluid paint: liquid ferrofluid it lays and its Rosensweig spike settings (amount 0: none). */
|
|
298
|
+
ferro: FerroSettings;
|
|
284
299
|
/**
|
|
285
300
|
* Dab engine: a stamp tip. Each dab (and each spray droplet) is this sticker's shape, an editor
|
|
286
301
|
* stamp (`editor:star`) or any sticker ref from the sticker library, laid in the paint colour;
|
|
@@ -291,6 +306,8 @@ export interface PaintBrush {
|
|
|
291
306
|
spray: SpraySettings | null;
|
|
292
307
|
/** Dab engines: texture inside the tip (missing: none). Recorded with the stroke, source ref included, so replays match. */
|
|
293
308
|
tipGrain?: TipGrainSettings;
|
|
309
|
+
/** Wet engine: Gray-Scott reaction-diffusion pattern seeded into the wet paint (missing: none). */
|
|
310
|
+
livePatterns?: LivePatternsSettings;
|
|
294
311
|
/**
|
|
295
312
|
* The brush's own gradient paint (`@pixerate/editor/paint` `PaintGradientSource`), used instead
|
|
296
313
|
* of the editor's paint; `null` (default): the editor's paint. Stops may be `paint` / `secondary`
|
|
@@ -317,7 +334,7 @@ export interface SpraySettings {
|
|
|
317
334
|
size: number;
|
|
318
335
|
}
|
|
319
336
|
export declare const DEFAULT_SPRAY: Readonly<SpraySettings>;
|
|
320
|
-
export type PaintBrushInput = Partial<Omit<PaintBrush, 'tip' | 'dynamics' | 'mixer' | 'behavior' | 'blender' | 'smudge' | 'wet' | 'impasto' | 'particle' | 'bristle' | 'sticker' | 'paint' | 'light' | 'fluorescence' | 'thermochromic' | 'iridescence' | 'ghost' | 'mutation' | 'spray' | 'tipGrain'>> & {
|
|
337
|
+
export type PaintBrushInput = Partial<Omit<PaintBrush, 'tip' | 'dynamics' | 'mixer' | 'behavior' | 'blender' | 'smudge' | 'wet' | 'impasto' | 'particle' | 'bristle' | 'sticker' | 'paint' | 'light' | 'fluorescence' | 'thermochromic' | 'iridescence' | 'ghost' | 'mutation' | 'ferro' | 'spray' | 'tipGrain' | 'livePatterns'>> & {
|
|
321
338
|
spray?: Partial<SpraySettings> | null;
|
|
322
339
|
/** Tip grain (`null` removes it). */
|
|
323
340
|
tipGrain?: Partial<TipGrainSettings> | null;
|
|
@@ -325,11 +342,14 @@ export type PaintBrushInput = Partial<Omit<PaintBrush, 'tip' | 'dynamics' | 'mix
|
|
|
325
342
|
ghost?: Partial<GhostSettings> | null;
|
|
326
343
|
/** Mutation paint (`null` removes it). */
|
|
327
344
|
mutation?: Partial<MutationSettings> | null;
|
|
345
|
+
/** Live reaction-diffusion patterns (`null` removes it). */
|
|
346
|
+
livePatterns?: LivePatternsInput | null;
|
|
328
347
|
light?: Partial<LightSettings>;
|
|
329
348
|
fluorescence?: Partial<FluorescenceSettings> | number;
|
|
330
349
|
thermochromic?: Partial<ThermochromicSettings>;
|
|
331
350
|
/** Thin-film iridescence (`null` removes it). */
|
|
332
351
|
iridescence?: Partial<IridescenceSettings> | null;
|
|
352
|
+
ferro?: number | Partial<FerroSettings>;
|
|
333
353
|
/** A gradient (or `null` for the editor's paint); a plain colour source clears it. */
|
|
334
354
|
paint?: PaintSource | null;
|
|
335
355
|
tip?: Partial<BrushSettings>;
|
|
@@ -8,7 +8,9 @@ import { type BlenderSettings, type SmudgeSettings } from '../paint/blending.js'
|
|
|
8
8
|
import type { MixingModel } from '../paint/exchange.js';
|
|
9
9
|
import { type PaintGradientSource, type PaintSource } from '../paint/gradient-paint.js';
|
|
10
10
|
import { type MixerSettings } from '../paint/mixer.js';
|
|
11
|
+
import { DEFAULT_LIVE_PATTERNS, LIVE_PATTERN_KINDS, LIVE_PATTERN_PRESETS, normalizeLivePatterns, type LivePatternKind, type LivePatternsInput, type LivePatternsSettings } from '../paint/live-patterns.js';
|
|
11
12
|
import { type BristleSettings, type ParticleSettings, type StickerSettings } from './mark-settings.js';
|
|
13
|
+
export { DEFAULT_LIVE_PATTERNS, LIVE_PATTERN_KINDS, LIVE_PATTERN_PRESETS, normalizeLivePatterns, type LivePatternKind, type LivePatternsInput, type LivePatternsSettings };
|
|
12
14
|
/**
|
|
13
15
|
* How a brush makes marks: `dab` (dabs into a stroke buffer, or dab by dab through the pick-up /
|
|
14
16
|
* mix exchange when its behaviour asks for it), `eraser` (removes alpha), `mixer` (the Mixer
|
|
@@ -147,6 +149,17 @@ export interface MutationSettings {
|
|
|
147
149
|
}
|
|
148
150
|
export declare const DEFAULT_MUTATION: Readonly<MutationSettings>;
|
|
149
151
|
export declare function normalizeMutation(raw?: Partial<MutationSettings>, base?: MutationSettings): MutationSettings;
|
|
152
|
+
/** Ferrofluid paint: how much liquid ferrofluid a brush lays, and its Rosensweig spike settings (see `doc.ferro`). */
|
|
153
|
+
export interface FerroSettings {
|
|
154
|
+
/** How much liquid ferrofluid each dab lays, scaled by coverage and flow (0..1, default 0: none). */
|
|
155
|
+
amount: number;
|
|
156
|
+
/** Capillary wavelength (spike-to-spike spacing) in pixels (4..64, default 16). */
|
|
157
|
+
wavelength: number;
|
|
158
|
+
/** Critical magnetic field |B| threshold where spikes begin to rise (0.01..0.95, default 0.12). */
|
|
159
|
+
threshold: number;
|
|
160
|
+
}
|
|
161
|
+
export declare const DEFAULT_FERRO: Readonly<FerroSettings>;
|
|
162
|
+
export declare function normalizeFerro(raw?: number | Partial<FerroSettings> | null | undefined, base?: FerroSettings): FerroSettings;
|
|
150
163
|
export declare function normalizeImpasto(raw?: Partial<ImpastoSettings>, base?: ImpastoSettings): ImpastoSettings;
|
|
151
164
|
/** Multi-coloured brush: `tip` lays the colours across the tip, `dab` changes colour from dab to dab. */
|
|
152
165
|
export type MultiColorMode = 'off' | 'tip' | 'dab';
|
|
@@ -281,6 +294,8 @@ export interface PaintBrush {
|
|
|
281
294
|
ghost?: GhostSettings;
|
|
282
295
|
/** Mutation paint settings (missing when not a mutation brush). */
|
|
283
296
|
mutation?: MutationSettings;
|
|
297
|
+
/** Ferrofluid paint: liquid ferrofluid it lays and its Rosensweig spike settings (amount 0: none). */
|
|
298
|
+
ferro: FerroSettings;
|
|
284
299
|
/**
|
|
285
300
|
* Dab engine: a stamp tip. Each dab (and each spray droplet) is this sticker's shape, an editor
|
|
286
301
|
* stamp (`editor:star`) or any sticker ref from the sticker library, laid in the paint colour;
|
|
@@ -291,6 +306,8 @@ export interface PaintBrush {
|
|
|
291
306
|
spray: SpraySettings | null;
|
|
292
307
|
/** Dab engines: texture inside the tip (missing: none). Recorded with the stroke, source ref included, so replays match. */
|
|
293
308
|
tipGrain?: TipGrainSettings;
|
|
309
|
+
/** Wet engine: Gray-Scott reaction-diffusion pattern seeded into the wet paint (missing: none). */
|
|
310
|
+
livePatterns?: LivePatternsSettings;
|
|
294
311
|
/**
|
|
295
312
|
* The brush's own gradient paint (`@pixerate/editor/paint` `PaintGradientSource`), used instead
|
|
296
313
|
* of the editor's paint; `null` (default): the editor's paint. Stops may be `paint` / `secondary`
|
|
@@ -317,7 +334,7 @@ export interface SpraySettings {
|
|
|
317
334
|
size: number;
|
|
318
335
|
}
|
|
319
336
|
export declare const DEFAULT_SPRAY: Readonly<SpraySettings>;
|
|
320
|
-
export type PaintBrushInput = Partial<Omit<PaintBrush, 'tip' | 'dynamics' | 'mixer' | 'behavior' | 'blender' | 'smudge' | 'wet' | 'impasto' | 'particle' | 'bristle' | 'sticker' | 'paint' | 'light' | 'fluorescence' | 'thermochromic' | 'iridescence' | 'ghost' | 'mutation' | 'spray' | 'tipGrain'>> & {
|
|
337
|
+
export type PaintBrushInput = Partial<Omit<PaintBrush, 'tip' | 'dynamics' | 'mixer' | 'behavior' | 'blender' | 'smudge' | 'wet' | 'impasto' | 'particle' | 'bristle' | 'sticker' | 'paint' | 'light' | 'fluorescence' | 'thermochromic' | 'iridescence' | 'ghost' | 'mutation' | 'ferro' | 'spray' | 'tipGrain' | 'livePatterns'>> & {
|
|
321
338
|
spray?: Partial<SpraySettings> | null;
|
|
322
339
|
/** Tip grain (`null` removes it). */
|
|
323
340
|
tipGrain?: Partial<TipGrainSettings> | null;
|
|
@@ -325,11 +342,14 @@ export type PaintBrushInput = Partial<Omit<PaintBrush, 'tip' | 'dynamics' | 'mix
|
|
|
325
342
|
ghost?: Partial<GhostSettings> | null;
|
|
326
343
|
/** Mutation paint (`null` removes it). */
|
|
327
344
|
mutation?: Partial<MutationSettings> | null;
|
|
345
|
+
/** Live reaction-diffusion patterns (`null` removes it). */
|
|
346
|
+
livePatterns?: LivePatternsInput | null;
|
|
328
347
|
light?: Partial<LightSettings>;
|
|
329
348
|
fluorescence?: Partial<FluorescenceSettings> | number;
|
|
330
349
|
thermochromic?: Partial<ThermochromicSettings>;
|
|
331
350
|
/** Thin-film iridescence (`null` removes it). */
|
|
332
351
|
iridescence?: Partial<IridescenceSettings> | null;
|
|
352
|
+
ferro?: number | Partial<FerroSettings>;
|
|
333
353
|
/** A gradient (or `null` for the editor's paint); a plain colour source clears it. */
|
|
334
354
|
paint?: PaintSource | null;
|
|
335
355
|
tip?: Partial<BrushSettings>;
|
|
@@ -50,6 +50,7 @@ import { PaintWetLayers, type PaintWetOptions, type WetEngineInfo, type WetGpuMo
|
|
|
50
50
|
import { type WetParams, type WetTilt } from '../paint/wet/model.cjs';
|
|
51
51
|
import { type WetFlowSpec } from '../paint/wet/flow.cjs';
|
|
52
52
|
import { type WetBackendInfo } from '../paint/wet/world.cjs';
|
|
53
|
+
import { type LivePatternKind, type LivePatternStats, type LivePatternsInput } from '../paint/live-patterns.cjs';
|
|
53
54
|
import { type TimeLapse, type TimeLapseOptions } from './replay.cjs';
|
|
54
55
|
import { EffectsSlot } from '../effects/helpers.cjs';
|
|
55
56
|
import type { EffectDescription, EffectProvider, EffectValue } from '../effects/types.cjs';
|
|
@@ -62,6 +63,7 @@ import type { PaintDirector } from './presence.cjs';
|
|
|
62
63
|
import type { PresenceActorInfo } from '../animation/presence.cjs';
|
|
63
64
|
import { type PaintProposals } from './collaboration.cjs';
|
|
64
65
|
import { type BreedStrokesResult, type ProposalGenomeResult, type StrokeMutationRates } from './evolution.cjs';
|
|
66
|
+
import { type PaintMagnet } from './ferro.cjs';
|
|
65
67
|
export declare class PaintEditorError extends Error {
|
|
66
68
|
constructor(message: string);
|
|
67
69
|
}
|
|
@@ -121,6 +123,13 @@ export interface PaintWetStateInfo {
|
|
|
121
123
|
/** Engine B is shading the wet paint now. */
|
|
122
124
|
gpuActive: boolean;
|
|
123
125
|
}
|
|
126
|
+
/** One layer's Gray-Scott live-pattern state and wet coverage. */
|
|
127
|
+
export interface PaintLayerLivePatternsInfo extends LivePatternStats {
|
|
128
|
+
layerId: string;
|
|
129
|
+
wet: boolean;
|
|
130
|
+
wetCells: number;
|
|
131
|
+
wetBounds: RasterRect | null;
|
|
132
|
+
}
|
|
124
133
|
export interface PaintEditorState {
|
|
125
134
|
document: PaintDocumentState;
|
|
126
135
|
/** The active brush (possibly edited from its preset). */
|
|
@@ -540,6 +549,9 @@ export declare class PaintEditorController {
|
|
|
540
549
|
private readonly litCaches;
|
|
541
550
|
/** The live impasto stroke's channels. */
|
|
542
551
|
private liveThick;
|
|
552
|
+
/** The live ferrofluid stroke's channel. */
|
|
553
|
+
private liveFerro;
|
|
554
|
+
private nextMagnetId;
|
|
543
555
|
/** The UV / blacklight setting (saved with the document, not undo steps). */
|
|
544
556
|
private uvLight;
|
|
545
557
|
private readonly uvCaches;
|
|
@@ -1278,6 +1290,51 @@ export declare class PaintEditorController {
|
|
|
1278
1290
|
layerId: string;
|
|
1279
1291
|
flattened: boolean;
|
|
1280
1292
|
};
|
|
1293
|
+
/** The document's `ferro` and `ferroSettings` without these layers. */
|
|
1294
|
+
private ferroWithout;
|
|
1295
|
+
/** Runs deterministic advection on all pixel layers with liquid ferrofluid toward `magnets`. */
|
|
1296
|
+
private advectDocumentFerro;
|
|
1297
|
+
/** Lists the magnets on the canvas. */
|
|
1298
|
+
listMagnets(): PaintMagnet[];
|
|
1299
|
+
/** Places a dipole magnet on the canvas and advects liquid ferrofluid toward it (one undo step). */
|
|
1300
|
+
addMagnet(input: {
|
|
1301
|
+
x: number;
|
|
1302
|
+
y: number;
|
|
1303
|
+
strength?: number;
|
|
1304
|
+
radius?: number;
|
|
1305
|
+
}): PaintMagnet;
|
|
1306
|
+
/** Moves or retunes a magnet and advects liquid ferrofluid toward the magnets (one undo step). */
|
|
1307
|
+
updateMagnet(id: string, update: {
|
|
1308
|
+
x?: number;
|
|
1309
|
+
y?: number;
|
|
1310
|
+
strength?: number;
|
|
1311
|
+
radius?: number;
|
|
1312
|
+
}, commitToHistory?: boolean): PaintMagnet;
|
|
1313
|
+
/** Removes magnets by id, or all magnets when `ids` is omitted or empty (one undo step). Returns the removed ids. */
|
|
1314
|
+
removeMagnets(ids?: readonly string[]): string[];
|
|
1315
|
+
/** Replaces the canvas magnets (used by replay). */
|
|
1316
|
+
replaceMagnets(magnets: readonly PaintMagnet[], advect?: boolean): void;
|
|
1317
|
+
/** Reads a layer's liquid ferrofluid coverage and active Rosensweig spike relief under the canvas magnets. */
|
|
1318
|
+
getFerrofluid(layerId?: string): {
|
|
1319
|
+
layerId: string;
|
|
1320
|
+
ferro: boolean;
|
|
1321
|
+
bounds: RasterRect | null;
|
|
1322
|
+
peak: number;
|
|
1323
|
+
coverage: number;
|
|
1324
|
+
activeSpikeArea: number;
|
|
1325
|
+
maxSpikeHeight: number;
|
|
1326
|
+
magnetCount: number;
|
|
1327
|
+
wavelength: number;
|
|
1328
|
+
threshold: number;
|
|
1329
|
+
};
|
|
1330
|
+
/** Cures a layer's liquid ferrofluid: bakes the current Rosensweig spikes and glossy metallic material into `doc.thick` and clears `doc.ferro` (one undo step). */
|
|
1331
|
+
cureFerrofluid(layerId?: string): {
|
|
1332
|
+
layerId: string;
|
|
1333
|
+
cured: boolean;
|
|
1334
|
+
bounds: RasterRect | null;
|
|
1335
|
+
maxSpikeHeight: number;
|
|
1336
|
+
activeSpikeArea: number;
|
|
1337
|
+
};
|
|
1281
1338
|
/**
|
|
1282
1339
|
* A fresh, headless editor for replaying this painting at `scale` (canvas, dpi and paper grain
|
|
1283
1340
|
* scaled; every pixel layer empty; the same brushes, lighting and wet options). Dispose of it
|
|
@@ -1406,6 +1463,50 @@ export declare class PaintEditorController {
|
|
|
1406
1463
|
ty: number;
|
|
1407
1464
|
data: Uint8ClampedArray;
|
|
1408
1465
|
}>;
|
|
1466
|
+
private layerLivePatternsInfo;
|
|
1467
|
+
private checkLivePatternsInput;
|
|
1468
|
+
/**
|
|
1469
|
+
* Reads a layer's Gray-Scott reaction-diffusion live patterns (`layerId`, default the active
|
|
1470
|
+
* layer), plus all layers with wet paint or live patterns and the built-in Pearson presets.
|
|
1471
|
+
*/
|
|
1472
|
+
getLivePatterns(layerId?: string): PaintLayerLivePatternsInfo & {
|
|
1473
|
+
layers: PaintLayerLivePatternsInfo[];
|
|
1474
|
+
presets: Readonly<Record<LivePatternKind, {
|
|
1475
|
+
feed: number;
|
|
1476
|
+
kill: number;
|
|
1477
|
+
}>>;
|
|
1478
|
+
brushPresets: readonly string[];
|
|
1479
|
+
};
|
|
1480
|
+
/**
|
|
1481
|
+
* Configures a layer's Gray-Scott reaction-diffusion live patterns (or clears them with
|
|
1482
|
+
* `enabled: false`). One undo step.
|
|
1483
|
+
*/
|
|
1484
|
+
setLivePatterns(layerId: string | undefined, update: LivePatternsInput & {
|
|
1485
|
+
enabled?: boolean;
|
|
1486
|
+
}): PaintLayerLivePatternsInfo;
|
|
1487
|
+
/**
|
|
1488
|
+
* Seeds Gray-Scott reaction-diffusion activator (`V`) discs into a layer's live-pattern field so
|
|
1489
|
+
* patterns grow where the layer holds wet water and freeze where it dries. One undo step.
|
|
1490
|
+
*/
|
|
1491
|
+
seedLivePatterns(options: {
|
|
1492
|
+
layerId?: string;
|
|
1493
|
+
points: ReadonlyArray<{
|
|
1494
|
+
x: number;
|
|
1495
|
+
y: number;
|
|
1496
|
+
strength?: number;
|
|
1497
|
+
}>;
|
|
1498
|
+
radius?: number;
|
|
1499
|
+
seed?: number;
|
|
1500
|
+
pattern?: LivePatternKind;
|
|
1501
|
+
feed?: number;
|
|
1502
|
+
kill?: number;
|
|
1503
|
+
scale?: number;
|
|
1504
|
+
contrast?: number;
|
|
1505
|
+
secondColor?: string | null;
|
|
1506
|
+
relief?: number;
|
|
1507
|
+
}): PaintLayerLivePatternsInfo & {
|
|
1508
|
+
seededCells: number;
|
|
1509
|
+
};
|
|
1409
1510
|
private sources;
|
|
1410
1511
|
/** The layers with the live stroke's surface in place. */
|
|
1411
1512
|
private currentLayers;
|
|
@@ -1425,7 +1526,7 @@ export declare class PaintEditorController {
|
|
|
1425
1526
|
* Linear Dodge (`::uv`) spill layer directly above it.
|
|
1426
1527
|
*/
|
|
1427
1528
|
private uvLayers;
|
|
1428
|
-
/** The layers with thick paint lit (each thick layer's pixels replaced by its lit tiles). */
|
|
1529
|
+
/** The layers with thick paint and ferrofluid spikes lit (each thick or ferrofluid layer's pixels replaced by its lit tiles). */
|
|
1429
1530
|
private litLayers;
|
|
1430
1531
|
/**
|
|
1431
1532
|
* Light paint over the (lit) layers: glow, rim and clarity in each layer's pixels, and its spill
|