@pixerate/editor 0.280.0 → 0.282.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.
Files changed (66) hide show
  1. package/dist/animation-editor/index.cjs +59 -59
  2. package/dist/animation-editor/index.js +3 -3
  3. package/dist/brushes/index.cjs +76 -71
  4. package/dist/brushes/index.js +13 -8
  5. package/dist/brushes/schema.d.cts +1 -0
  6. package/dist/brushes/schema.d.ts +1 -0
  7. package/dist/brushes/types.d.cts +29 -3
  8. package/dist/brushes/types.d.ts +29 -3
  9. package/dist/{brushstrokeRender-EIK3625T.js → brushstrokeRender-4MA5CBW3.js} +3 -3
  10. package/dist/{brushstrokeRender-7HOMKZNO.cjs → brushstrokeRender-JVKVKWDA.cjs} +15 -15
  11. package/dist/canvas/edge-animation-tools.d.cts +115 -0
  12. package/dist/canvas/edge-animation-tools.d.ts +115 -0
  13. package/dist/canvas/edgeAnimation.d.cts +164 -0
  14. package/dist/canvas/edgeAnimation.d.ts +164 -0
  15. package/dist/canvas/edgePaths.d.cts +63 -0
  16. package/dist/canvas/edgePaths.d.ts +63 -0
  17. package/dist/canvas/index.cjs +691 -21
  18. package/dist/canvas/index.d.cts +3 -0
  19. package/dist/canvas/index.d.ts +3 -0
  20. package/dist/canvas/index.js +679 -9
  21. package/dist/{chunk-NJDEKU5D.js → chunk-2YGYYVSG.js} +1 -1
  22. package/dist/{chunk-JVFGK3DK.cjs → chunk-3JUKN3RM.cjs} +76 -53
  23. package/dist/{chunk-HN57I7KT.js → chunk-CG3FBNXE.js} +1 -1
  24. package/dist/{chunk-WFSYZO5Z.cjs → chunk-DFZ4I7EZ.cjs} +1 -1
  25. package/dist/{chunk-LZE2QZCT.js → chunk-IHMMHZGP.js} +1 -1
  26. package/dist/{chunk-K4ANWBF7.cjs → chunk-IJQ2YH2M.cjs} +35 -35
  27. package/dist/{chunk-HRUK5TFW.cjs → chunk-IUKPQCYQ.cjs} +164 -71
  28. package/dist/{chunk-WCC4NXWY.cjs → chunk-JD63B33V.cjs} +86 -86
  29. package/dist/{chunk-NJLPW4MM.js → chunk-KV7QHPKL.js} +27 -4
  30. package/dist/{chunk-H3EME3S5.cjs → chunk-MRIAR5DY.cjs} +2 -2
  31. package/dist/{chunk-ROURHJYT.js → chunk-NEDS6DSC.js} +1 -1
  32. package/dist/{chunk-FKO3CY2C.js → chunk-ULPXJ3NB.js} +1 -1
  33. package/dist/{chunk-WZYRYYXN.cjs → chunk-UOM5S4W5.cjs} +12 -12
  34. package/dist/{chunk-YOM76H2V.js → chunk-VEX6YVNG.js} +1 -1
  35. package/dist/{chunk-MNHP3AQT.cjs → chunk-WEXWDBUF.cjs} +23 -23
  36. package/dist/{chunk-PPDUCZZV.js → chunk-YRGTQLDN.js} +122 -29
  37. package/dist/image-editor/index.cjs +788 -788
  38. package/dist/image-editor/index.js +4 -4
  39. package/dist/paint-editor/antimatter.d.cts +154 -0
  40. package/dist/paint-editor/antimatter.d.ts +154 -0
  41. package/dist/paint-editor/brush-controls.d.cts +1 -0
  42. package/dist/paint-editor/brush-controls.d.ts +1 -0
  43. package/dist/paint-editor/brush-model.d.cts +9 -5
  44. package/dist/paint-editor/brush-model.d.ts +9 -5
  45. package/dist/paint-editor/controller.d.cts +23 -0
  46. package/dist/paint-editor/controller.d.ts +23 -0
  47. package/dist/paint-editor/index.cjs +1931 -891
  48. package/dist/paint-editor/index.d.cts +1 -0
  49. package/dist/paint-editor/index.d.ts +1 -0
  50. package/dist/paint-editor/index.js +1098 -58
  51. package/dist/paint-editor/mark-settings.d.cts +30 -0
  52. package/dist/paint-editor/mark-settings.d.ts +30 -0
  53. package/dist/paint-editor/stroke.d.cts +16 -0
  54. package/dist/paint-editor/stroke.d.ts +16 -0
  55. package/dist/paint-editor/strokes.d.cts +2 -0
  56. package/dist/paint-editor/strokes.d.ts +2 -0
  57. package/dist/paint-editor/ui.d.cts +4 -2
  58. package/dist/paint-editor/ui.d.ts +4 -2
  59. package/dist/vector/index.cjs +999 -999
  60. package/dist/vector/index.js +4 -4
  61. package/package.json +1 -1
  62. package/skills/pixerate-brushes/SKILL.md +1 -1
  63. package/skills/pixerate-canvas/SKILL.md +25 -2
  64. package/skills/pixerate-paint-editor/SKILL.md +8 -2
  65. package/skills/pixerate-paint-editor/references/antimatter.md +49 -0
  66. package/skills/pixerate-paint-editor/references/brush-facets.md +1 -0
@@ -8,7 +8,7 @@ import {
8
8
  parseOpenTypeFont,
9
9
  removeAnchorsKeepingShape,
10
10
  traceField
11
- } from "../chunk-HN57I7KT.js";
11
+ } from "../chunk-CG3FBNXE.js";
12
12
  import {
13
13
  ADJUSTMENT_KEYS,
14
14
  ADJUSTMENT_KINDS,
@@ -409,7 +409,7 @@ import {
409
409
  writePsd,
410
410
  xyToTempTint,
411
411
  xyToUv
412
- } from "../chunk-NJDEKU5D.js";
412
+ } from "../chunk-2YGYYVSG.js";
413
413
  import {
414
414
  flattenPath,
415
415
  rasterizeCoverage
@@ -683,14 +683,14 @@ import {
683
683
  warpMeshParamAt,
684
684
  warpMeshRows,
685
685
  warpPresetMesh
686
- } from "../chunk-YOM76H2V.js";
686
+ } from "../chunk-VEX6YVNG.js";
687
687
  import {
688
688
  IMAGE_PROFILE,
689
689
  checkBrush,
690
690
  closest,
691
691
  createBrushLibrary,
692
692
  resolveBrush
693
- } from "../chunk-PPDUCZZV.js";
693
+ } from "../chunk-YRGTQLDN.js";
694
694
  import "../chunk-JL6YH5WD.js";
695
695
  import "../chunk-RWDSSK2I.js";
696
696
  import {
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Antimatter paint (`engine: 'antimatter'`, `marks.kind: 'antimatter'`): animated blasts that
3
+ * detonate where the brush touches paint across any visible layer, inverting colours in the core,
4
+ * removing alpha, burning a soot ring around the crater, denting thick relief, clearing core light,
5
+ * and throwing white-hot ballistic sparks on the active layer.
6
+ */
7
+ import { type PaintGradientSource } from '../paint/gradient-paint.cjs';
8
+ import { TiledSurface, type RasterRect } from '../raster/surface.cjs';
9
+ import type { PaintBrush } from './brushes.cjs';
10
+ import { type EffectPaintPixels } from './effect-paint.cjs';
11
+ import { type PenPoint, type StrokeCopy } from './engine.cjs';
12
+ import { DEFAULT_ANTIMATTER, INVERT_MODES, normalizeAntimatter, type AntimatterSettings, type InvertMode } from './mark-settings.cjs';
13
+ import type { ThickChannels } from './thick.cjs';
14
+ export { DEFAULT_ANTIMATTER, INVERT_MODES, normalizeAntimatter, type AntimatterSettings, type InvertMode };
15
+ /** One detonation along an antimatter stroke. */
16
+ export interface AntimatterBlast {
17
+ index: number;
18
+ x: number;
19
+ y: number;
20
+ /** Blast radius in document pixels. */
21
+ radius: number;
22
+ /** Tip diameter at the dab that fired this blast. */
23
+ tipSize: number;
24
+ /** Tip opacity at the dab that fired this blast (`0..1`). */
25
+ tipOpacity: number;
26
+ /** Fuel (`0..1`) that triggered this blast. */
27
+ fuel: number;
28
+ /** Copy-specific seed for noise and sparks. */
29
+ seed: number;
30
+ /** Spark target colour (0..255 RGB). */
31
+ color: [number, number, number];
32
+ /** Light intensity (`0..1`) sparks write to `doc.light` on the active layer. */
33
+ lightAmount: number;
34
+ /** Number of sparks spawned by this blast. */
35
+ sparkCount: number;
36
+ /** Birth timestamp in ms (from `PenPoint.t` or the host clock). */
37
+ t: number;
38
+ }
39
+ /** Summary returned on `PaintStrokeResult.antimatter`. */
40
+ export interface AntimatterStats {
41
+ blasts: number;
42
+ sparks: number;
43
+ fuel: number;
44
+ layers: string[];
45
+ skippedLayers: string[];
46
+ }
47
+ /** One visible layer that supplies fuel to the antimatter stroke (and is edited if `editable`). */
48
+ export interface AntimatterTarget {
49
+ id: string;
50
+ /** True for unlocked pixel layers (not stroke, sticker or effect layers). */
51
+ editable: boolean;
52
+ lockTransparency: boolean;
53
+ opacity: number;
54
+ offset: {
55
+ x: number;
56
+ y: number;
57
+ };
58
+ /** Pre-stroke pixel surface (read-only fuel & recomposite source). */
59
+ base: TiledSurface;
60
+ /** Pre-stroke light channel (`doc.light[id]`), if any. */
61
+ baseLight?: TiledSurface | null;
62
+ /** Pre-stroke thick-paint channels (`doc.thick[id]`), if any. */
63
+ baseThick?: ThickChannels | null;
64
+ }
65
+ /** Per-layer output surfaces produced by `AntimatterStrokeDriver`. */
66
+ export interface AntimatterLayerOutput {
67
+ id: string;
68
+ surface: TiledSurface;
69
+ light: TiledSurface | null;
70
+ thick: ThickChannels | null;
71
+ changed: boolean;
72
+ }
73
+ export interface AntimatterStrokeInit {
74
+ activeLayerId: string;
75
+ targets: readonly AntimatterTarget[];
76
+ brush: PaintBrush;
77
+ /** Paint colour 0..255 RGBA. */
78
+ color: readonly [number, number, number, number];
79
+ seed: number;
80
+ copies: readonly StrokeCopy[];
81
+ selection?: {
82
+ width: number;
83
+ height: number;
84
+ data: ArrayLike<number>;
85
+ } | null;
86
+ paint?: PaintGradientSource | null;
87
+ effect?: EffectPaintPixels | null;
88
+ /** Current clock in ms for stamping blast birth times during live strokes. */
89
+ now?: () => number;
90
+ }
91
+ /** Smooth 2D value noise in `0..1` using only `Math.floor` and `hash2` (identical across TS and Swift). */
92
+ export declare function blastNoise2D(ux: number, uy: number, salt: number): number;
93
+ /** Inverts an 8-bit sRGB colour in OKLab space by flipping lightness `1 - L` and hue `(-a, -b)`. */
94
+ export declare function invertOklab8(r: number, g: number, b: number): [number, number, number];
95
+ /** Core (`0..1`) and soot-ring (`0..1`) weights for a heat value `h` in `0..1`. */
96
+ export declare function heatProfile(h: number): {
97
+ core: number;
98
+ ring: number;
99
+ };
100
+ export declare class AntimatterStrokeDriver {
101
+ readonly init: AntimatterStrokeInit;
102
+ dabCount: number;
103
+ bounds: RasterRect | null;
104
+ readonly blasts: AntimatterBlast[];
105
+ private readonly smoother;
106
+ private readonly copies;
107
+ private readonly states;
108
+ private readonly sampler;
109
+ private readonly sample;
110
+ private readonly effRgb;
111
+ private readonly heat;
112
+ private readonly heatCoords;
113
+ private tipBuf;
114
+ private lastRaw;
115
+ private lastFed;
116
+ private totalFuel;
117
+ private readonly reachedSkipped;
118
+ private readonly editedIds;
119
+ private readonly outputs;
120
+ constructor(init: AntimatterStrokeInit);
121
+ /** Pushes raw pen samples and returns the bounding rectangles of any blasts that fired. */
122
+ push(points: readonly PenPoint[]): RasterRect[];
123
+ /** Flushes the smoother tail and finishes the stroke. */
124
+ finish(): RasterRect[];
125
+ private processDabs;
126
+ /** Measures fuel (`0..1`) under `d` from the pre-stroke pixels of every visible layer. */
127
+ private measureFuel;
128
+ private fireBlast;
129
+ /** Writes one blast into `heatMap` (at `progress` 0..1) and returns the bounding rectangle including sparks. */
130
+ private writeBlastToHeat;
131
+ /** Recomposites all editable target layers from their pre-stroke tiles using the current committed `heat` and `blasts`. */
132
+ private recompositeAll;
133
+ /**
134
+ * Builds per-layer outputs for the given `heatMap` and blast progress function `progressOf(b)`.
135
+ * At `progressOf(b) === 1`, no flash or shock ring is drawn and sparks reach 100%, matching the
136
+ * committed pixels bit-for-bit.
137
+ */
138
+ private buildOutputs;
139
+ /** Draws sparks and (when `progress < 1`) the view-only flash and expanding shock ring on the active layer. */
140
+ private drawActiveExtras;
141
+ /**
142
+ * Renders the blast state at `now` (ms) for view-only blast animation.
143
+ * When `active` is `false` (all blasts have reached `progress === 1`), `outputs` match `layerOutputs()` bit-for-bit.
144
+ */
145
+ renderAtTime(now: number): {
146
+ outputs: AntimatterLayerOutput[];
147
+ active: boolean;
148
+ };
149
+ hasBlasts(): boolean;
150
+ /** Rebases blast birth times so the earliest blast starts at `now` ms. */
151
+ rebaseTime(now: number): void;
152
+ layerOutputs(): AntimatterLayerOutput[];
153
+ stats(): AntimatterStats;
154
+ }
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Antimatter paint (`engine: 'antimatter'`, `marks.kind: 'antimatter'`): animated blasts that
3
+ * detonate where the brush touches paint across any visible layer, inverting colours in the core,
4
+ * removing alpha, burning a soot ring around the crater, denting thick relief, clearing core light,
5
+ * and throwing white-hot ballistic sparks on the active layer.
6
+ */
7
+ import { type PaintGradientSource } from '../paint/gradient-paint.js';
8
+ import { TiledSurface, type RasterRect } from '../raster/surface.js';
9
+ import type { PaintBrush } from './brushes.js';
10
+ import { type EffectPaintPixels } from './effect-paint.js';
11
+ import { type PenPoint, type StrokeCopy } from './engine.js';
12
+ import { DEFAULT_ANTIMATTER, INVERT_MODES, normalizeAntimatter, type AntimatterSettings, type InvertMode } from './mark-settings.js';
13
+ import type { ThickChannels } from './thick.js';
14
+ export { DEFAULT_ANTIMATTER, INVERT_MODES, normalizeAntimatter, type AntimatterSettings, type InvertMode };
15
+ /** One detonation along an antimatter stroke. */
16
+ export interface AntimatterBlast {
17
+ index: number;
18
+ x: number;
19
+ y: number;
20
+ /** Blast radius in document pixels. */
21
+ radius: number;
22
+ /** Tip diameter at the dab that fired this blast. */
23
+ tipSize: number;
24
+ /** Tip opacity at the dab that fired this blast (`0..1`). */
25
+ tipOpacity: number;
26
+ /** Fuel (`0..1`) that triggered this blast. */
27
+ fuel: number;
28
+ /** Copy-specific seed for noise and sparks. */
29
+ seed: number;
30
+ /** Spark target colour (0..255 RGB). */
31
+ color: [number, number, number];
32
+ /** Light intensity (`0..1`) sparks write to `doc.light` on the active layer. */
33
+ lightAmount: number;
34
+ /** Number of sparks spawned by this blast. */
35
+ sparkCount: number;
36
+ /** Birth timestamp in ms (from `PenPoint.t` or the host clock). */
37
+ t: number;
38
+ }
39
+ /** Summary returned on `PaintStrokeResult.antimatter`. */
40
+ export interface AntimatterStats {
41
+ blasts: number;
42
+ sparks: number;
43
+ fuel: number;
44
+ layers: string[];
45
+ skippedLayers: string[];
46
+ }
47
+ /** One visible layer that supplies fuel to the antimatter stroke (and is edited if `editable`). */
48
+ export interface AntimatterTarget {
49
+ id: string;
50
+ /** True for unlocked pixel layers (not stroke, sticker or effect layers). */
51
+ editable: boolean;
52
+ lockTransparency: boolean;
53
+ opacity: number;
54
+ offset: {
55
+ x: number;
56
+ y: number;
57
+ };
58
+ /** Pre-stroke pixel surface (read-only fuel & recomposite source). */
59
+ base: TiledSurface;
60
+ /** Pre-stroke light channel (`doc.light[id]`), if any. */
61
+ baseLight?: TiledSurface | null;
62
+ /** Pre-stroke thick-paint channels (`doc.thick[id]`), if any. */
63
+ baseThick?: ThickChannels | null;
64
+ }
65
+ /** Per-layer output surfaces produced by `AntimatterStrokeDriver`. */
66
+ export interface AntimatterLayerOutput {
67
+ id: string;
68
+ surface: TiledSurface;
69
+ light: TiledSurface | null;
70
+ thick: ThickChannels | null;
71
+ changed: boolean;
72
+ }
73
+ export interface AntimatterStrokeInit {
74
+ activeLayerId: string;
75
+ targets: readonly AntimatterTarget[];
76
+ brush: PaintBrush;
77
+ /** Paint colour 0..255 RGBA. */
78
+ color: readonly [number, number, number, number];
79
+ seed: number;
80
+ copies: readonly StrokeCopy[];
81
+ selection?: {
82
+ width: number;
83
+ height: number;
84
+ data: ArrayLike<number>;
85
+ } | null;
86
+ paint?: PaintGradientSource | null;
87
+ effect?: EffectPaintPixels | null;
88
+ /** Current clock in ms for stamping blast birth times during live strokes. */
89
+ now?: () => number;
90
+ }
91
+ /** Smooth 2D value noise in `0..1` using only `Math.floor` and `hash2` (identical across TS and Swift). */
92
+ export declare function blastNoise2D(ux: number, uy: number, salt: number): number;
93
+ /** Inverts an 8-bit sRGB colour in OKLab space by flipping lightness `1 - L` and hue `(-a, -b)`. */
94
+ export declare function invertOklab8(r: number, g: number, b: number): [number, number, number];
95
+ /** Core (`0..1`) and soot-ring (`0..1`) weights for a heat value `h` in `0..1`. */
96
+ export declare function heatProfile(h: number): {
97
+ core: number;
98
+ ring: number;
99
+ };
100
+ export declare class AntimatterStrokeDriver {
101
+ readonly init: AntimatterStrokeInit;
102
+ dabCount: number;
103
+ bounds: RasterRect | null;
104
+ readonly blasts: AntimatterBlast[];
105
+ private readonly smoother;
106
+ private readonly copies;
107
+ private readonly states;
108
+ private readonly sampler;
109
+ private readonly sample;
110
+ private readonly effRgb;
111
+ private readonly heat;
112
+ private readonly heatCoords;
113
+ private tipBuf;
114
+ private lastRaw;
115
+ private lastFed;
116
+ private totalFuel;
117
+ private readonly reachedSkipped;
118
+ private readonly editedIds;
119
+ private readonly outputs;
120
+ constructor(init: AntimatterStrokeInit);
121
+ /** Pushes raw pen samples and returns the bounding rectangles of any blasts that fired. */
122
+ push(points: readonly PenPoint[]): RasterRect[];
123
+ /** Flushes the smoother tail and finishes the stroke. */
124
+ finish(): RasterRect[];
125
+ private processDabs;
126
+ /** Measures fuel (`0..1`) under `d` from the pre-stroke pixels of every visible layer. */
127
+ private measureFuel;
128
+ private fireBlast;
129
+ /** Writes one blast into `heatMap` (at `progress` 0..1) and returns the bounding rectangle including sparks. */
130
+ private writeBlastToHeat;
131
+ /** Recomposites all editable target layers from their pre-stroke tiles using the current committed `heat` and `blasts`. */
132
+ private recompositeAll;
133
+ /**
134
+ * Builds per-layer outputs for the given `heatMap` and blast progress function `progressOf(b)`.
135
+ * At `progressOf(b) === 1`, no flash or shock ring is drawn and sparks reach 100%, matching the
136
+ * committed pixels bit-for-bit.
137
+ */
138
+ private buildOutputs;
139
+ /** Draws sparks and (when `progress < 1`) the view-only flash and expanding shock ring on the active layer. */
140
+ private drawActiveExtras;
141
+ /**
142
+ * Renders the blast state at `now` (ms) for view-only blast animation.
143
+ * When `active` is `false` (all blasts have reached `progress === 1`), `outputs` match `layerOutputs()` bit-for-bit.
144
+ */
145
+ renderAtTime(now: number): {
146
+ outputs: AntimatterLayerOutput[];
147
+ active: boolean;
148
+ };
149
+ hasBlasts(): boolean;
150
+ /** Rebases blast birth times so the earliest blast starts at `now` ms. */
151
+ rebaseTime(now: number): void;
152
+ layerOutputs(): AntimatterLayerOutput[];
153
+ stats(): AntimatterStats;
154
+ }
@@ -47,6 +47,7 @@ export interface BrushEngineControls {
47
47
  export declare const IRIDESCENCE_SLIDERS: readonly SliderControl[];
48
48
  export declare const GHOST_SLIDERS: readonly SliderControl[];
49
49
  export declare const MUTATION_SLIDERS: readonly SliderControl[];
50
+ export declare const ANTIMATTER_SLIDERS: readonly SliderControl[];
50
51
  /**
51
52
  * The controls the active brush's engine adds to the brush panel (`null` for the eraser):
52
53
  * blender strength and blend distance; smudge strength and length; the Mixer Brush's pick-up,
@@ -47,6 +47,7 @@ export interface BrushEngineControls {
47
47
  export declare const IRIDESCENCE_SLIDERS: readonly SliderControl[];
48
48
  export declare const GHOST_SLIDERS: readonly SliderControl[];
49
49
  export declare const MUTATION_SLIDERS: readonly SliderControl[];
50
+ export declare const ANTIMATTER_SLIDERS: readonly SliderControl[];
50
51
  /**
51
52
  * The controls the active brush's engine adds to the brush panel (`null` for the eraser):
52
53
  * blender strength and blend distance; smudge strength and length; the Mixer Brush's pick-up,
@@ -9,14 +9,15 @@ 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
11
  import { DEFAULT_LIVE_PATTERNS, LIVE_PATTERN_KINDS, LIVE_PATTERN_PRESETS, normalizeLivePatterns, type LivePatternKind, type LivePatternsInput, type LivePatternsSettings } from '../paint/live-patterns.cjs';
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
+ import { DEFAULT_ANTIMATTER, INVERT_MODES, normalizeAntimatter, type AntimatterSettings, type BristleSettings, type InvertMode, type ParticleSettings, type StickerSettings } from './mark-settings.cjs';
13
+ export { DEFAULT_ANTIMATTER, DEFAULT_LIVE_PATTERNS, INVERT_MODES, LIVE_PATTERN_KINDS, LIVE_PATTERN_PRESETS, normalizeAntimatter, normalizeLivePatterns, type AntimatterSettings, type InvertMode, type LivePatternKind, type LivePatternsInput, type LivePatternsSettings, };
14
14
  /**
15
15
  * How a brush makes marks: `dab` (dabs into a stroke buffer, or dab by dab through the pick-up /
16
16
  * mix exchange when its behaviour asks for it), `eraser` (removes alpha), `mixer` (the Mixer
17
- * Brush), `blender` (mixes the colours under and near the tip) or `smudge` (drags paint along).
17
+ * Brush), `blender` (mixes the colours under and near the tip), `smudge` (drags paint along), or
18
+ * `antimatter` (animated blasts that invert, scorch and destroy paint across every visible layer).
18
19
  */
19
- export type PaintBrushEngine = 'dab' | 'eraser' | 'mixer' | 'blender' | 'smudge' | 'wet' | 'impasto' | 'particle' | 'bristle' | 'sticker';
20
+ export type PaintBrushEngine = 'dab' | 'eraser' | 'mixer' | 'blender' | 'smudge' | 'wet' | 'impasto' | 'particle' | 'bristle' | 'sticker' | 'antimatter';
20
21
  export declare const PAINT_BRUSH_ENGINES: readonly PaintBrushEngine[];
21
22
  export type PaintBrushCategory = 'pencil' | 'pastel' | 'charcoal' | 'airbrush' | 'marker' | 'ink' | 'paint' | 'eraser' | 'blender' | 'smudge' | 'mixer' | 'watercolor' | 'wet-tool' | 'oil' | 'impasto' | 'procedural' | 'bristle' | 'sticker' | 'light' | 'custom';
22
23
  export declare const PAINT_BRUSH_CATEGORIES: readonly PaintBrushCategory[];
@@ -282,6 +283,8 @@ export interface PaintBrush {
282
283
  bristle: BristleSettings;
283
284
  /** Sticker engine only: the stamps and how they are sprayed. */
284
285
  sticker: StickerSettings;
286
+ /** Antimatter engine only: blast size, spacing, threshold, inversion, scorch, annihilation, sparks, crater and duration. */
287
+ antimatter: AntimatterSettings;
285
288
  /** Light paint: the light it lays with its colour (amount 0: none). */
286
289
  light: LightSettings;
287
290
  /** UV-fluorescent ink: glows under the virtual UV blacklight (amount 0: none). */
@@ -334,7 +337,7 @@ export interface SpraySettings {
334
337
  size: number;
335
338
  }
336
339
  export declare const DEFAULT_SPRAY: Readonly<SpraySettings>;
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'>> & {
340
+ export type PaintBrushInput = Partial<Omit<PaintBrush, 'tip' | 'dynamics' | 'mixer' | 'behavior' | 'blender' | 'smudge' | 'wet' | 'impasto' | 'particle' | 'bristle' | 'sticker' | 'antimatter' | 'paint' | 'light' | 'fluorescence' | 'thermochromic' | 'iridescence' | 'ghost' | 'mutation' | 'ferro' | 'spray' | 'tipGrain' | 'livePatterns'>> & {
338
341
  spray?: Partial<SpraySettings> | null;
339
342
  /** Tip grain (`null` removes it). */
340
343
  tipGrain?: Partial<TipGrainSettings> | null;
@@ -363,6 +366,7 @@ export type PaintBrushInput = Partial<Omit<PaintBrush, 'tip' | 'dynamics' | 'mix
363
366
  particle?: Partial<ParticleSettings>;
364
367
  bristle?: Partial<BristleSettings>;
365
368
  sticker?: Partial<StickerSettings>;
369
+ antimatter?: Partial<AntimatterSettings>;
366
370
  };
367
371
  /** Whether a brush can pick paint up from the canvas (the pick-up / mix ratios apply): dab, mixer and wet brushes. */
368
372
  export declare function isWetCapable(brush: Pick<PaintBrush, 'engine'>): boolean;
@@ -9,14 +9,15 @@ 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
11
  import { DEFAULT_LIVE_PATTERNS, LIVE_PATTERN_KINDS, LIVE_PATTERN_PRESETS, normalizeLivePatterns, type LivePatternKind, type LivePatternsInput, type LivePatternsSettings } from '../paint/live-patterns.js';
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
+ import { DEFAULT_ANTIMATTER, INVERT_MODES, normalizeAntimatter, type AntimatterSettings, type BristleSettings, type InvertMode, type ParticleSettings, type StickerSettings } from './mark-settings.js';
13
+ export { DEFAULT_ANTIMATTER, DEFAULT_LIVE_PATTERNS, INVERT_MODES, LIVE_PATTERN_KINDS, LIVE_PATTERN_PRESETS, normalizeAntimatter, normalizeLivePatterns, type AntimatterSettings, type InvertMode, type LivePatternKind, type LivePatternsInput, type LivePatternsSettings, };
14
14
  /**
15
15
  * How a brush makes marks: `dab` (dabs into a stroke buffer, or dab by dab through the pick-up /
16
16
  * mix exchange when its behaviour asks for it), `eraser` (removes alpha), `mixer` (the Mixer
17
- * Brush), `blender` (mixes the colours under and near the tip) or `smudge` (drags paint along).
17
+ * Brush), `blender` (mixes the colours under and near the tip), `smudge` (drags paint along), or
18
+ * `antimatter` (animated blasts that invert, scorch and destroy paint across every visible layer).
18
19
  */
19
- export type PaintBrushEngine = 'dab' | 'eraser' | 'mixer' | 'blender' | 'smudge' | 'wet' | 'impasto' | 'particle' | 'bristle' | 'sticker';
20
+ export type PaintBrushEngine = 'dab' | 'eraser' | 'mixer' | 'blender' | 'smudge' | 'wet' | 'impasto' | 'particle' | 'bristle' | 'sticker' | 'antimatter';
20
21
  export declare const PAINT_BRUSH_ENGINES: readonly PaintBrushEngine[];
21
22
  export type PaintBrushCategory = 'pencil' | 'pastel' | 'charcoal' | 'airbrush' | 'marker' | 'ink' | 'paint' | 'eraser' | 'blender' | 'smudge' | 'mixer' | 'watercolor' | 'wet-tool' | 'oil' | 'impasto' | 'procedural' | 'bristle' | 'sticker' | 'light' | 'custom';
22
23
  export declare const PAINT_BRUSH_CATEGORIES: readonly PaintBrushCategory[];
@@ -282,6 +283,8 @@ export interface PaintBrush {
282
283
  bristle: BristleSettings;
283
284
  /** Sticker engine only: the stamps and how they are sprayed. */
284
285
  sticker: StickerSettings;
286
+ /** Antimatter engine only: blast size, spacing, threshold, inversion, scorch, annihilation, sparks, crater and duration. */
287
+ antimatter: AntimatterSettings;
285
288
  /** Light paint: the light it lays with its colour (amount 0: none). */
286
289
  light: LightSettings;
287
290
  /** UV-fluorescent ink: glows under the virtual UV blacklight (amount 0: none). */
@@ -334,7 +337,7 @@ export interface SpraySettings {
334
337
  size: number;
335
338
  }
336
339
  export declare const DEFAULT_SPRAY: Readonly<SpraySettings>;
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'>> & {
340
+ export type PaintBrushInput = Partial<Omit<PaintBrush, 'tip' | 'dynamics' | 'mixer' | 'behavior' | 'blender' | 'smudge' | 'wet' | 'impasto' | 'particle' | 'bristle' | 'sticker' | 'antimatter' | 'paint' | 'light' | 'fluorescence' | 'thermochromic' | 'iridescence' | 'ghost' | 'mutation' | 'ferro' | 'spray' | 'tipGrain' | 'livePatterns'>> & {
338
341
  spray?: Partial<SpraySettings> | null;
339
342
  /** Tip grain (`null` removes it). */
340
343
  tipGrain?: Partial<TipGrainSettings> | null;
@@ -363,6 +366,7 @@ export type PaintBrushInput = Partial<Omit<PaintBrush, 'tip' | 'dynamics' | 'mix
363
366
  particle?: Partial<ParticleSettings>;
364
367
  bristle?: Partial<BristleSettings>;
365
368
  sticker?: Partial<StickerSettings>;
369
+ antimatter?: Partial<AntimatterSettings>;
366
370
  };
367
371
  /** Whether a brush can pick paint up from the canvas (the pick-up / mix ratios apply): dab, mixer and wet brushes. */
368
372
  export declare function isWetCapable(brush: Pick<PaintBrush, 'engine'>): boolean;
@@ -308,6 +308,8 @@ export interface PaintStrokeInit {
308
308
  stencils?: boolean;
309
309
  /** Mask with these stencils instead (replays pass the ones recorded with the stroke). */
310
310
  maskStencils?: readonly Stencil[];
311
+ /** Antimatter strokes: the fuel layer ids (the visible pixel layers when painted). A replay reads fuel from exactly these and changes the editable ones, whatever is visible now. */
312
+ targets?: readonly string[];
311
313
  }
312
314
  export interface LayerUpdate {
313
315
  name?: string;
@@ -511,6 +513,9 @@ export declare class PaintEditorController {
511
513
  private cached;
512
514
  private session;
513
515
  private live;
516
+ private liveMulti;
517
+ private liveThickMulti;
518
+ private liveLightMulti;
514
519
  private liveLayers;
515
520
  private dirty;
516
521
  private seedCounter;
@@ -528,6 +533,13 @@ export declare class PaintEditorController {
528
533
  private liveEffectAt;
529
534
  /** The view's stroke layers at `effectTime`, each with the document surface it was drawn from (stale once that changes). */
530
535
  private animatedLayers;
536
+ /** Blast animation frames (view only), kept apart from live effect frames so neither replaces the other. */
537
+ private blastLayers;
538
+ /** Blast animation light / thick channels (`null` light: none at this frame). */
539
+ private animatedLight;
540
+ private animatedThick;
541
+ private activeBlastAnim;
542
+ private playingClock;
531
543
  /** `renderAnimationFrame` / `withEffectTime`: layer surfaces at another time, for one render. */
532
544
  private frameOverride;
533
545
  /** The area each stroke painted (document pixels; `null`: nothing), learnt as it is painted or drawn, so a stroke layer edit redraws only where it changes (see `drawLiveStrokes`). */
@@ -1860,6 +1872,17 @@ export declare class PaintEditorController {
1860
1872
  }): {
1861
1873
  stop(): void;
1862
1874
  };
1875
+ /**
1876
+ * The fuel layers of an antimatter stroke: every visible, non-temporary pixel layer (group
1877
+ * opacity multiplied in), or on a replay exactly the recorded `targetIds` whatever their
1878
+ * visibility now. The editable ones (not locked, stroke, sticker or effect layers) change.
1879
+ */
1880
+ private antimatterTargetsOf;
1881
+ /** Applies every target layer's output from an antimatter stroke into a new document state. */
1882
+ private applyAntimatterOutputs;
1883
+ private startBlastAnimation;
1884
+ private stepBlastAnimation;
1885
+ private clearBlastAnimation;
1863
1886
  /**
1864
1887
  * Runs `fn` with the painting as it is `time` ms into its live effects (see `getAnimation`): for
1865
1888
  * exports at a moment. Nothing in the document changes.
@@ -308,6 +308,8 @@ export interface PaintStrokeInit {
308
308
  stencils?: boolean;
309
309
  /** Mask with these stencils instead (replays pass the ones recorded with the stroke). */
310
310
  maskStencils?: readonly Stencil[];
311
+ /** Antimatter strokes: the fuel layer ids (the visible pixel layers when painted). A replay reads fuel from exactly these and changes the editable ones, whatever is visible now. */
312
+ targets?: readonly string[];
311
313
  }
312
314
  export interface LayerUpdate {
313
315
  name?: string;
@@ -511,6 +513,9 @@ export declare class PaintEditorController {
511
513
  private cached;
512
514
  private session;
513
515
  private live;
516
+ private liveMulti;
517
+ private liveThickMulti;
518
+ private liveLightMulti;
514
519
  private liveLayers;
515
520
  private dirty;
516
521
  private seedCounter;
@@ -528,6 +533,13 @@ export declare class PaintEditorController {
528
533
  private liveEffectAt;
529
534
  /** The view's stroke layers at `effectTime`, each with the document surface it was drawn from (stale once that changes). */
530
535
  private animatedLayers;
536
+ /** Blast animation frames (view only), kept apart from live effect frames so neither replaces the other. */
537
+ private blastLayers;
538
+ /** Blast animation light / thick channels (`null` light: none at this frame). */
539
+ private animatedLight;
540
+ private animatedThick;
541
+ private activeBlastAnim;
542
+ private playingClock;
531
543
  /** `renderAnimationFrame` / `withEffectTime`: layer surfaces at another time, for one render. */
532
544
  private frameOverride;
533
545
  /** The area each stroke painted (document pixels; `null`: nothing), learnt as it is painted or drawn, so a stroke layer edit redraws only where it changes (see `drawLiveStrokes`). */
@@ -1860,6 +1872,17 @@ export declare class PaintEditorController {
1860
1872
  }): {
1861
1873
  stop(): void;
1862
1874
  };
1875
+ /**
1876
+ * The fuel layers of an antimatter stroke: every visible, non-temporary pixel layer (group
1877
+ * opacity multiplied in), or on a replay exactly the recorded `targetIds` whatever their
1878
+ * visibility now. The editable ones (not locked, stroke, sticker or effect layers) change.
1879
+ */
1880
+ private antimatterTargetsOf;
1881
+ /** Applies every target layer's output from an antimatter stroke into a new document state. */
1882
+ private applyAntimatterOutputs;
1883
+ private startBlastAnimation;
1884
+ private stepBlastAnimation;
1885
+ private clearBlastAnimation;
1863
1886
  /**
1864
1887
  * Runs `fn` with the painting as it is `time` ms into its live effects (see `getAnimation`): for
1865
1888
  * exports at a moment. Nothing in the document changes.