@pixerate/editor 0.226.0 → 0.227.1

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 (60) hide show
  1. package/dist/animation-editor/index.cjs +66 -66
  2. package/dist/animation-editor/index.js +4 -4
  3. package/dist/{brushstrokeRender-C3UU6GVC.js → brushstrokeRender-MAHOXL7K.js} +2 -2
  4. package/dist/{brushstrokeRender-EAJNE6WP.cjs → brushstrokeRender-WDTKD54B.cjs} +5 -5
  5. package/dist/canvas/effects.d.cts +18 -0
  6. package/dist/canvas/effects.d.ts +18 -0
  7. package/dist/canvas/index.cjs +34 -15
  8. package/dist/canvas/index.js +21 -2
  9. package/dist/{chunk-ABQ2VGUB.cjs → chunk-5MQOBTNP.cjs} +13 -2
  10. package/dist/{chunk-LCCMOWR7.cjs → chunk-ATKKG76G.cjs} +23 -23
  11. package/dist/{chunk-QAUIZPYI.cjs → chunk-BQE3Y6ZO.cjs} +2 -2
  12. package/dist/{chunk-G4E6RUPC.js → chunk-CDP2AKMA.js} +1 -1
  13. package/dist/{chunk-NDMXB4PR.js → chunk-CU6ANS5L.js} +1 -1
  14. package/dist/{chunk-ROVK6AXX.cjs → chunk-GNZI3KYK.cjs} +95 -23
  15. package/dist/{chunk-I7G3RSUJ.cjs → chunk-GXLZZVR5.cjs} +35 -35
  16. package/dist/{chunk-C6CMQXMI.cjs → chunk-IGPEBXUD.cjs} +7 -7
  17. package/dist/{chunk-4PA6YS6W.cjs → chunk-K5GXW5TR.cjs} +14 -14
  18. package/dist/{chunk-5YLOU7VF.js → chunk-KN3Y3FRY.js} +1 -1
  19. package/dist/{chunk-56RFHF7O.js → chunk-LPTFDCJO.js} +1 -1
  20. package/dist/{chunk-IWMDW7LB.cjs → chunk-MXJP77K4.cjs} +86 -86
  21. package/dist/{chunk-4MDWEX44.js → chunk-PB6JV62G.js} +1 -1
  22. package/dist/{chunk-F7YA3MMC.js → chunk-TQOL6CF7.js} +76 -4
  23. package/dist/{chunk-7DZ55AIE.js → chunk-UGYUGZE2.js} +13 -2
  24. package/dist/{chunk-ZMHPQ6HP.cjs → chunk-V3L7U63N.cjs} +1 -1
  25. package/dist/{chunk-DJBYJOHM.js → chunk-XSVUNSDJ.js} +1 -1
  26. package/dist/{chunk-BGOCAUXH.js → chunk-YMREOA67.js} +1 -1
  27. package/dist/effects/index.cjs +44 -44
  28. package/dist/effects/index.js +2 -2
  29. package/dist/image-editor/index.cjs +784 -784
  30. package/dist/image-editor/index.js +5 -5
  31. package/dist/paint-editor/controller.d.cts +54 -3
  32. package/dist/paint-editor/controller.d.ts +54 -3
  33. package/dist/paint-editor/dab-stroke.d.cts +3 -0
  34. package/dist/paint-editor/dab-stroke.d.ts +3 -0
  35. package/dist/paint-editor/effect-paint.d.cts +47 -0
  36. package/dist/paint-editor/effect-paint.d.ts +47 -0
  37. package/dist/paint-editor/effect-tools.d.cts +4 -2
  38. package/dist/paint-editor/effect-tools.d.ts +4 -2
  39. package/dist/paint-editor/effects.d.cts +3 -0
  40. package/dist/paint-editor/effects.d.ts +3 -0
  41. package/dist/paint-editor/engine.d.cts +4 -0
  42. package/dist/paint-editor/engine.d.ts +4 -0
  43. package/dist/paint-editor/index.cjs +542 -315
  44. package/dist/paint-editor/index.d.cts +1 -0
  45. package/dist/paint-editor/index.d.ts +1 -0
  46. package/dist/paint-editor/index.js +252 -25
  47. package/dist/paint-editor/procedural.d.cts +4 -0
  48. package/dist/paint-editor/procedural.d.ts +4 -0
  49. package/dist/paint-editor/stroke.d.cts +9 -0
  50. package/dist/paint-editor/stroke.d.ts +9 -0
  51. package/dist/paint-editor/strokes.d.cts +6 -2
  52. package/dist/paint-editor/strokes.d.ts +6 -2
  53. package/dist/vector/index.cjs +968 -968
  54. package/dist/vector/index.js +5 -5
  55. package/dist/video-editor/index.cjs +309 -309
  56. package/dist/video-editor/index.js +3 -3
  57. package/package.json +1 -1
  58. package/skills/pixerate-canvas/SKILL.md +2 -1
  59. package/skills/pixerate-paint-editor/SKILL.md +42 -6
  60. package/skills/pixerate-paint-sketch-to-finish/SKILL.md +7 -0
@@ -4,7 +4,7 @@ import {
4
4
  parseOpenTypeFont,
5
5
  removeAnchorsKeepingShape,
6
6
  traceField
7
- } from "../chunk-DJBYJOHM.js";
7
+ } from "../chunk-XSVUNSDJ.js";
8
8
  import {
9
9
  ColorGmm,
10
10
  GAMMA,
@@ -405,7 +405,7 @@ import {
405
405
  writePsd,
406
406
  xyToTempTint,
407
407
  xyToUv
408
- } from "../chunk-5YLOU7VF.js";
408
+ } from "../chunk-KN3Y3FRY.js";
409
409
  import {
410
410
  parseCssColor
411
411
  } from "../chunk-3CI7FRMK.js";
@@ -727,8 +727,8 @@ import {
727
727
  warpMeshParamAt,
728
728
  warpMeshRows,
729
729
  warpPresetMesh
730
- } from "../chunk-NDMXB4PR.js";
731
- import "../chunk-F7YA3MMC.js";
730
+ } from "../chunk-CU6ANS5L.js";
731
+ import "../chunk-TQOL6CF7.js";
732
732
  import "../chunk-M6DNZNVY.js";
733
733
  import {
734
734
  bezierPathToSvg,
@@ -743,7 +743,7 @@ import {
743
743
  createEffectToolProvider,
744
744
  linearToSrgb,
745
745
  resolveEffectValues
746
- } from "../chunk-7DZ55AIE.js";
746
+ } from "../chunk-UGYUGZE2.js";
747
747
  import "../chunk-V2ZCJRDM.js";
748
748
  import {
749
749
  BrushstrokeCache,
@@ -40,6 +40,7 @@ import { type WetBackendInfo } from '../paint/wet/world.cjs';
40
40
  import { type TimeLapse, type TimeLapseOptions } from './replay.cjs';
41
41
  import { EffectsSlot } from '../effects/helpers.cjs';
42
42
  import type { EffectDescription, EffectProvider, EffectValue } from '../effects/types.cjs';
43
+ import { type PaintEffectPaint } from './effect-paint.cjs';
43
44
  import { type PaintEffectPlace, type PaintEffectSource, type PaintPaperEffect, type PaperEffectBlend } from './effects.cjs';
44
45
  import { type PaintLighting } from './thick.cjs';
45
46
  /** A refusal with a message that says what is wrong and how to fix it. */
@@ -100,6 +101,13 @@ export interface PaintEditorState {
100
101
  * own gradient (`brush.paint`) paints that instead.
101
102
  */
102
103
  paint: PaintSource;
104
+ /**
105
+ * Effect paint (`setEffectPaint`): a provider effect strokes take each pixel's colour from,
106
+ * instead of `paint`; `null` when they paint `paint`. `setColor` and `setPaint` clear it.
107
+ */
108
+ effectPaint: PaintEffectPaint | null;
109
+ /** The effect paint is still rendering: strokes that would paint with it wait (they throw). */
110
+ effectPaintRendering: boolean;
103
111
  /** What the Mixer Brush carries between strokes. */
104
112
  mixerLoad: MixerLoad;
105
113
  view: PaintView;
@@ -145,10 +153,11 @@ export interface PaintStrokeInit {
145
153
  /** Default the editor colour. */
146
154
  color?: string;
147
155
  /**
148
- * What this stroke paints with, instead of the editor's paint: a colour, or gradient paint
149
- * (`@pixerate/editor/paint` `PaintSource`). A colour here is the same as `color`.
156
+ * What this stroke paints with, instead of the editor's paint: a colour, gradient paint
157
+ * (`@pixerate/editor/paint` `PaintSource`), or effect paint (render it first with
158
+ * `prepareEffectPaints`). A colour here is the same as `color`.
150
159
  */
151
- paint?: PaintSource | string;
160
+ paint?: PaintSource | PaintEffectPaint | string;
152
161
  /** Default the active brush. */
153
162
  brushId?: string;
154
163
  /** Changes to the brush for this stroke only. */
@@ -256,6 +265,13 @@ export declare class PaintEditorController {
256
265
  private secondaryColor;
257
266
  /** Gradient paint chosen with `setPaint` (`null`: the paint colour). */
258
267
  private gradient;
268
+ /** Effect paint chosen with `setEffectPaint` (rendered), and one still rendering. */
269
+ private effectPaint;
270
+ private effectPaintPending;
271
+ /** Changes whenever the paint is chosen, so an effect paint that finishes rendering late does not take over. */
272
+ private paintEpoch;
273
+ /** Rendered effect paints by `effectPaintKey` (most recently used last). */
274
+ private readonly effectPaintPixels;
259
275
  private mixerLoad;
260
276
  private view;
261
277
  private hand;
@@ -508,6 +524,41 @@ export declare class PaintEditorController {
508
524
  layerId: string;
509
525
  source: PaintEffectSource;
510
526
  }>;
527
+ /** At most this many rendered effect paints are kept (each is canvas-sized). */
528
+ private static readonly EFFECT_PAINT_CACHE;
529
+ /** The effect paint strokes use (or the one rendering), or `null`. */
530
+ getEffectPaint(): PaintEffectPaint | null;
531
+ /**
532
+ * Paints with a provider generator, overlay or title effect: it is rendered once at the canvas
533
+ * size, and brushes then take each pixel's colour (and alpha) from it, fixed to the canvas, as if
534
+ * painting a hidden picture into view. `setColor` and `setPaint` go back to colour. Editor state,
535
+ * not an undo step. Strokes that would paint with it throw while it renders. Returns the paint.
536
+ */
537
+ setEffectPaint(source: {
538
+ effect: string;
539
+ values?: Record<string, EffectValue | null>;
540
+ time?: number;
541
+ }): Promise<PaintEffectPaint>;
542
+ /** The rendered pixels of an effect paint at the current canvas size, or `null` when it has not been rendered. */
543
+ private effectPaintImage;
544
+ /** Renders an effect paint at the canvas size into the cache (nothing when it is there already). */
545
+ private renderEffectPaint;
546
+ /**
547
+ * Renders effect paints that are not rendered yet (strokes and replays need them rendered
548
+ * first, since strokes are synchronous). Throws naming the effect and provider when one cannot be.
549
+ */
550
+ prepareEffectPaints(paints: Iterable<PaintEffectPaint>): Promise<void>;
551
+ /** Renders the effect paints of recorded strokes (default all of them) before a replay. */
552
+ prepareStrokeEffects(strokeIds?: readonly string[]): Promise<void>;
553
+ /** A small preview of the effect paint (a PNG data URL `size` px wide), or `null` without a rendered one. */
554
+ effectPaintThumbnail(size?: number): string | null;
555
+ /**
556
+ * The effect paint a stroke paints with and its pixels, or `null`: the stroke's own effect
557
+ * `paint`, else (without its own `paint` or `color`, and with no brush gradient) the editor's.
558
+ * Throws while the editor's is still rendering, for an engine that cannot paint with it, or when
559
+ * its pixels are not rendered.
560
+ */
561
+ private strokeEffect;
511
562
  /**
512
563
  * Runs a filter effect (light, glow, colour grade …) on a layer's dried paint and bakes it in, at
513
564
  * `amount` strength (0..1, default 1). Transparent areas stay transparent; thick paint keeps its
@@ -40,6 +40,7 @@ import { type WetBackendInfo } from '../paint/wet/world.js';
40
40
  import { type TimeLapse, type TimeLapseOptions } from './replay.js';
41
41
  import { EffectsSlot } from '../effects/helpers.js';
42
42
  import type { EffectDescription, EffectProvider, EffectValue } from '../effects/types.js';
43
+ import { type PaintEffectPaint } from './effect-paint.js';
43
44
  import { type PaintEffectPlace, type PaintEffectSource, type PaintPaperEffect, type PaperEffectBlend } from './effects.js';
44
45
  import { type PaintLighting } from './thick.js';
45
46
  /** A refusal with a message that says what is wrong and how to fix it. */
@@ -100,6 +101,13 @@ export interface PaintEditorState {
100
101
  * own gradient (`brush.paint`) paints that instead.
101
102
  */
102
103
  paint: PaintSource;
104
+ /**
105
+ * Effect paint (`setEffectPaint`): a provider effect strokes take each pixel's colour from,
106
+ * instead of `paint`; `null` when they paint `paint`. `setColor` and `setPaint` clear it.
107
+ */
108
+ effectPaint: PaintEffectPaint | null;
109
+ /** The effect paint is still rendering: strokes that would paint with it wait (they throw). */
110
+ effectPaintRendering: boolean;
103
111
  /** What the Mixer Brush carries between strokes. */
104
112
  mixerLoad: MixerLoad;
105
113
  view: PaintView;
@@ -145,10 +153,11 @@ export interface PaintStrokeInit {
145
153
  /** Default the editor colour. */
146
154
  color?: string;
147
155
  /**
148
- * What this stroke paints with, instead of the editor's paint: a colour, or gradient paint
149
- * (`@pixerate/editor/paint` `PaintSource`). A colour here is the same as `color`.
156
+ * What this stroke paints with, instead of the editor's paint: a colour, gradient paint
157
+ * (`@pixerate/editor/paint` `PaintSource`), or effect paint (render it first with
158
+ * `prepareEffectPaints`). A colour here is the same as `color`.
150
159
  */
151
- paint?: PaintSource | string;
160
+ paint?: PaintSource | PaintEffectPaint | string;
152
161
  /** Default the active brush. */
153
162
  brushId?: string;
154
163
  /** Changes to the brush for this stroke only. */
@@ -256,6 +265,13 @@ export declare class PaintEditorController {
256
265
  private secondaryColor;
257
266
  /** Gradient paint chosen with `setPaint` (`null`: the paint colour). */
258
267
  private gradient;
268
+ /** Effect paint chosen with `setEffectPaint` (rendered), and one still rendering. */
269
+ private effectPaint;
270
+ private effectPaintPending;
271
+ /** Changes whenever the paint is chosen, so an effect paint that finishes rendering late does not take over. */
272
+ private paintEpoch;
273
+ /** Rendered effect paints by `effectPaintKey` (most recently used last). */
274
+ private readonly effectPaintPixels;
259
275
  private mixerLoad;
260
276
  private view;
261
277
  private hand;
@@ -508,6 +524,41 @@ export declare class PaintEditorController {
508
524
  layerId: string;
509
525
  source: PaintEffectSource;
510
526
  }>;
527
+ /** At most this many rendered effect paints are kept (each is canvas-sized). */
528
+ private static readonly EFFECT_PAINT_CACHE;
529
+ /** The effect paint strokes use (or the one rendering), or `null`. */
530
+ getEffectPaint(): PaintEffectPaint | null;
531
+ /**
532
+ * Paints with a provider generator, overlay or title effect: it is rendered once at the canvas
533
+ * size, and brushes then take each pixel's colour (and alpha) from it, fixed to the canvas, as if
534
+ * painting a hidden picture into view. `setColor` and `setPaint` go back to colour. Editor state,
535
+ * not an undo step. Strokes that would paint with it throw while it renders. Returns the paint.
536
+ */
537
+ setEffectPaint(source: {
538
+ effect: string;
539
+ values?: Record<string, EffectValue | null>;
540
+ time?: number;
541
+ }): Promise<PaintEffectPaint>;
542
+ /** The rendered pixels of an effect paint at the current canvas size, or `null` when it has not been rendered. */
543
+ private effectPaintImage;
544
+ /** Renders an effect paint at the canvas size into the cache (nothing when it is there already). */
545
+ private renderEffectPaint;
546
+ /**
547
+ * Renders effect paints that are not rendered yet (strokes and replays need them rendered
548
+ * first, since strokes are synchronous). Throws naming the effect and provider when one cannot be.
549
+ */
550
+ prepareEffectPaints(paints: Iterable<PaintEffectPaint>): Promise<void>;
551
+ /** Renders the effect paints of recorded strokes (default all of them) before a replay. */
552
+ prepareStrokeEffects(strokeIds?: readonly string[]): Promise<void>;
553
+ /** A small preview of the effect paint (a PNG data URL `size` px wide), or `null` without a rendered one. */
554
+ effectPaintThumbnail(size?: number): string | null;
555
+ /**
556
+ * The effect paint a stroke paints with and its pixels, or `null`: the stroke's own effect
557
+ * `paint`, else (without its own `paint` or `color`, and with no brush gradient) the editor's.
558
+ * Throws while the editor's is still rendering, for an engine that cannot paint with it, or when
559
+ * its pixels are not rendered.
560
+ */
561
+ private strokeEffect;
511
562
  /**
512
563
  * Runs a filter effect (light, glow, colour grade …) on a layer's dried paint and bakes it in, at
513
564
  * `amount` strength (0..1, default 1). Transparent areas stay transparent; thick paint keeps its
@@ -19,6 +19,7 @@ import { type MixerLoad, type MixingModel, type PaintTileTarget, type RgbTriple
19
19
  import type { RasterRect } from '../raster/surface.cjs';
20
20
  import { type PaintGradientSource } from '../paint/gradient-paint.cjs';
21
21
  import type { MultiColorSettings, PaintBrush } from './brushes.cjs';
22
+ import { type EffectPaintPixels } from './effect-paint.cjs';
22
23
  import { type PenPoint, type StrokeCopy } from './engine.cjs';
23
24
  import { type PaperGrain } from './paper.cjs';
24
25
  export interface PaintDabStrokeOptions {
@@ -36,6 +37,8 @@ export interface PaintDabStrokeOptions {
36
37
  copies?: readonly StrokeCopy[];
37
38
  /** Gradient paint (resolved: no `paint` / `secondary` stops): each dab's colour comes from it. */
38
39
  paint?: PaintGradientSource | null;
40
+ /** Effect paint: each dab's colour (and flow, by alpha) is the effect's at the dab's centre. */
41
+ effect?: EffectPaintPixels | null;
39
42
  }
40
43
  /** Colours of a multi-colour brush, resolved against the paint and secondary colours. */
41
44
  export declare function multiColorPalette(mc: MultiColorSettings, color: RgbTriple, secondary: RgbTriple): RgbTriple[];
@@ -19,6 +19,7 @@ import { type MixerLoad, type MixingModel, type PaintTileTarget, type RgbTriple
19
19
  import type { RasterRect } from '../raster/surface.js';
20
20
  import { type PaintGradientSource } from '../paint/gradient-paint.js';
21
21
  import type { MultiColorSettings, PaintBrush } from './brushes.js';
22
+ import { type EffectPaintPixels } from './effect-paint.js';
22
23
  import { type PenPoint, type StrokeCopy } from './engine.js';
23
24
  import { type PaperGrain } from './paper.js';
24
25
  export interface PaintDabStrokeOptions {
@@ -36,6 +37,8 @@ export interface PaintDabStrokeOptions {
36
37
  copies?: readonly StrokeCopy[];
37
38
  /** Gradient paint (resolved: no `paint` / `secondary` stops): each dab's colour comes from it. */
38
39
  paint?: PaintGradientSource | null;
40
+ /** Effect paint: each dab's colour (and flow, by alpha) is the effect's at the dab's centre. */
41
+ effect?: EffectPaintPixels | null;
39
42
  }
40
43
  /** Colours of a multi-colour brush, resolved against the paint and secondary colours. */
41
44
  export declare function multiColorPalette(mc: MultiColorSettings, color: RgbTriple, secondary: RgbTriple): RgbTriple[];
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Effect paint: a provider generator, overlay or title effect that brushes paint with. The effect
3
+ * is rendered once at the canvas size when it is chosen; strokes then take each pixel's colour
4
+ * from that image, fixed to the canvas, as if painting a hidden picture into view. The effect's
5
+ * alpha multiplies the brush coverage, so a transparent part of an overlay paints nothing.
6
+ *
7
+ * Strokes are synchronous and effect renders are not, so the pixels are rendered (and cached by
8
+ * source) before a stroke can use them; a stroke records the source, and replays render any
9
+ * missing source before they paint.
10
+ *
11
+ * Kept out of the shared `PaintSource` union (`@pixerate/editor/paint`), which the image editor
12
+ * shares: only the paint editor paints with effects.
13
+ */
14
+ import type { EffectValue } from '../effects/types.cjs';
15
+ import type { RasterRect } from '../raster/surface.cjs';
16
+ /** What strokes paint with when they paint with a provider effect. */
17
+ export interface PaintEffectPaint {
18
+ type: 'effect';
19
+ /** The effect id (search_effects). */
20
+ effect: string;
21
+ /** The provider's id when it was chosen. */
22
+ provider: string;
23
+ /** Every control value. */
24
+ values: Record<string, EffectValue>;
25
+ /** Which moment of an animated effect, in ms. */
26
+ time: number;
27
+ }
28
+ /** Canvas-sized straight-alpha RGBA an effect paint was rendered to. */
29
+ export interface EffectPaintPixels {
30
+ width: number;
31
+ height: number;
32
+ data: ArrayLike<number>;
33
+ }
34
+ /** The cache key of an effect paint (the same source renders the same pixels). */
35
+ export declare function effectPaintKey(p: PaintEffectPaint): string;
36
+ /** Whether a value is an effect paint (`{ type: 'effect', effect, … }`). */
37
+ export declare function isPaintEffectPaint(raw: unknown): raw is PaintEffectPaint;
38
+ /** A saved effect paint, or `null` when it is not one. */
39
+ export declare function readPaintEffectPaint(raw: unknown): PaintEffectPaint | null;
40
+ /**
41
+ * Takes a dab's colours from the effect: fills `field` (sRGB 0..1, 3 per pixel of `rect`, a
42
+ * document rectangle) with the effect's colour at each pixel and multiplies `vals` by its alpha.
43
+ * Pixels off the canvas paint nothing.
44
+ */
45
+ export declare function sampleEffectField(img: EffectPaintPixels, rect: RasterRect, vals: Float32Array, field: Float32Array): void;
46
+ /** The effect's colour (sRGB 0..1 into `out`) at a document point; returns its alpha 0..1 (0 off the canvas). */
47
+ export declare function sampleEffectAt(img: EffectPaintPixels, x: number, y: number, out: [number, number, number]): number;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Effect paint: a provider generator, overlay or title effect that brushes paint with. The effect
3
+ * is rendered once at the canvas size when it is chosen; strokes then take each pixel's colour
4
+ * from that image, fixed to the canvas, as if painting a hidden picture into view. The effect's
5
+ * alpha multiplies the brush coverage, so a transparent part of an overlay paints nothing.
6
+ *
7
+ * Strokes are synchronous and effect renders are not, so the pixels are rendered (and cached by
8
+ * source) before a stroke can use them; a stroke records the source, and replays render any
9
+ * missing source before they paint.
10
+ *
11
+ * Kept out of the shared `PaintSource` union (`@pixerate/editor/paint`), which the image editor
12
+ * shares: only the paint editor paints with effects.
13
+ */
14
+ import type { EffectValue } from '../effects/types.js';
15
+ import type { RasterRect } from '../raster/surface.js';
16
+ /** What strokes paint with when they paint with a provider effect. */
17
+ export interface PaintEffectPaint {
18
+ type: 'effect';
19
+ /** The effect id (search_effects). */
20
+ effect: string;
21
+ /** The provider's id when it was chosen. */
22
+ provider: string;
23
+ /** Every control value. */
24
+ values: Record<string, EffectValue>;
25
+ /** Which moment of an animated effect, in ms. */
26
+ time: number;
27
+ }
28
+ /** Canvas-sized straight-alpha RGBA an effect paint was rendered to. */
29
+ export interface EffectPaintPixels {
30
+ width: number;
31
+ height: number;
32
+ data: ArrayLike<number>;
33
+ }
34
+ /** The cache key of an effect paint (the same source renders the same pixels). */
35
+ export declare function effectPaintKey(p: PaintEffectPaint): string;
36
+ /** Whether a value is an effect paint (`{ type: 'effect', effect, … }`). */
37
+ export declare function isPaintEffectPaint(raw: unknown): raw is PaintEffectPaint;
38
+ /** A saved effect paint, or `null` when it is not one. */
39
+ export declare function readPaintEffectPaint(raw: unknown): PaintEffectPaint | null;
40
+ /**
41
+ * Takes a dab's colours from the effect: fills `field` (sRGB 0..1, 3 per pixel of `rect`, a
42
+ * document rectangle) with the effect's colour at each pixel and multiplies `vals` by its alpha.
43
+ * Pixels off the canvas paint nothing.
44
+ */
45
+ export declare function sampleEffectField(img: EffectPaintPixels, rect: RasterRect, vals: Float32Array, field: Float32Array): void;
46
+ /** The effect's colour (sRGB 0..1 into `out`) at a document point; returns its alpha 0..1 (0 off the canvas). */
47
+ export declare function sampleEffectAt(img: EffectPaintPixels, x: number, y: number, out: [number, number, number]): number;
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Agent tools for provider effects in the paint editor: the shared effect tools, where
3
3
  * `apply_effect` runs a filter (light, glow, grade) on a layer's dried paint and bakes it in, and
4
- * the target `paper` is the effect paper; plus `set_paper_effect`, `add_effect_layer` and
5
- * `fill_layer_with_effect`.
4
+ * the target `paper` is the effect paper and the target `paint` the effect paint; plus
5
+ * `set_paper_effect`, `add_effect_layer`, `fill_layer_with_effect` and `set_effect_paint`.
6
6
  */
7
7
  import type { AgentToolProvider } from '../tools/registry.cjs';
8
8
  import type { PaintEditorController } from './controller.cjs';
@@ -21,5 +21,7 @@ export interface PaintEffectsToolProviderOptions {
21
21
  }
22
22
  /** The target id of the effect paper. */
23
23
  export declare const PAPER_TARGET = "paper";
24
+ /** The target id of the effect paint (what brushes paint with). */
25
+ export declare const PAINT_TARGET = "paint";
24
26
  /** The effect tools for a paint editor (see the module comment). */
25
27
  export declare function createPaintEffectsToolProvider(controller: PaintEditorController, options?: PaintEffectsToolProviderOptions): AgentToolProvider;
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Agent tools for provider effects in the paint editor: the shared effect tools, where
3
3
  * `apply_effect` runs a filter (light, glow, grade) on a layer's dried paint and bakes it in, and
4
- * the target `paper` is the effect paper; plus `set_paper_effect`, `add_effect_layer` and
5
- * `fill_layer_with_effect`.
4
+ * the target `paper` is the effect paper and the target `paint` the effect paint; plus
5
+ * `set_paper_effect`, `add_effect_layer`, `fill_layer_with_effect` and `set_effect_paint`.
6
6
  */
7
7
  import type { AgentToolProvider } from '../tools/registry.js';
8
8
  import type { PaintEditorController } from './controller.js';
@@ -21,5 +21,7 @@ export interface PaintEffectsToolProviderOptions {
21
21
  }
22
22
  /** The target id of the effect paper. */
23
23
  export declare const PAPER_TARGET = "paper";
24
+ /** The target id of the effect paint (what brushes paint with). */
25
+ export declare const PAINT_TARGET = "paint";
24
26
  /** The effect tools for a paint editor (see the module comment). */
25
27
  export declare function createPaintEffectsToolProvider(controller: PaintEditorController, options?: PaintEffectsToolProviderOptions): AgentToolProvider;
@@ -8,6 +8,7 @@
8
8
  * - **Effect fills**: a generator, overlay or title effect composited onto a layer's pixels.
9
9
  * - **Light on dried paint**: a filter effect (light, glow, grade) run on a layer's paint and baked
10
10
  * in. Wet paint is dried first, in the same undo step; thick paint keeps its relief.
11
+ * - **Effect paint**: a generator, overlay or title effect brushes paint with (see `effect-paint.ts`).
11
12
  *
12
13
  * Effects render asynchronously, so each change renders first and commits after (one undo step).
13
14
  */
@@ -22,6 +23,8 @@ export declare const PAINT_EFFECT_PLACES: {
22
23
  readonly fill: readonly ["generator", "overlay", "title"];
23
24
  /** Light (or any filter) on a layer's dried paint. */
24
25
  readonly light: readonly ["filter"];
26
+ /** Effect paint: brushes take each pixel's colour from it. */
27
+ readonly paint: readonly ["generator", "overlay", "title"];
25
28
  };
26
29
  export type PaintEffectPlace = keyof typeof PAINT_EFFECT_PLACES;
27
30
  /** Refuses an effect that cannot go in `place`, saying what to use instead. */
@@ -8,6 +8,7 @@
8
8
  * - **Effect fills**: a generator, overlay or title effect composited onto a layer's pixels.
9
9
  * - **Light on dried paint**: a filter effect (light, glow, grade) run on a layer's paint and baked
10
10
  * in. Wet paint is dried first, in the same undo step; thick paint keeps its relief.
11
+ * - **Effect paint**: a generator, overlay or title effect brushes paint with (see `effect-paint.ts`).
11
12
  *
12
13
  * Effects render asynchronously, so each change renders first and commits after (one undo step).
13
14
  */
@@ -22,6 +23,8 @@ export declare const PAINT_EFFECT_PLACES: {
22
23
  readonly fill: readonly ["generator", "overlay", "title"];
23
24
  /** Light (or any filter) on a layer's dried paint. */
24
25
  readonly light: readonly ["filter"];
26
+ /** Effect paint: brushes take each pixel's colour from it. */
27
+ readonly paint: readonly ["generator", "overlay", "title"];
25
28
  };
26
29
  export type PaintEffectPlace = keyof typeof PAINT_EFFECT_PLACES;
27
30
  /** Refuses an effect that cannot go in `place`, saying what to use instead. */
@@ -17,6 +17,7 @@
17
17
  import { CoverageMap, type BrushSettings, type Dab, type StrokePoint } from '../paint/brush.cjs';
18
18
  import type { RasterRect } from '../raster/surface.cjs';
19
19
  import type { PaintBrush } from './brushes.cjs';
20
+ import { type EffectPaintPixels } from './effect-paint.cjs';
20
21
  import { type PaperGrain } from './paper.cjs';
21
22
  /** One pen sample in document pixels. Every channel but x and y is optional. */
22
23
  export interface PenPoint {
@@ -123,6 +124,8 @@ export interface DryStrokeOptions {
123
124
  seed?: number;
124
125
  /** Copies of the stroke (symmetry); default one identity copy. */
125
126
  copies?: readonly StrokeCopy[];
127
+ /** Effect paint: each pixel takes its colour (and alpha) from these canvas-sized pixels. */
128
+ effect?: EffectPaintPixels | null;
126
129
  }
127
130
  /**
128
131
  * One dab-engine stroke (dab and eraser brushes): smoothing, the dab walk of every copy, grain and
@@ -138,6 +141,7 @@ export declare class DryStroke {
138
141
  private readonly copies;
139
142
  private readonly depth;
140
143
  private buf;
144
+ private field;
141
145
  private lastRaw;
142
146
  private lastFed;
143
147
  constructor(brush: PaintBrush, options: DryStrokeOptions);
@@ -17,6 +17,7 @@
17
17
  import { CoverageMap, type BrushSettings, type Dab, type StrokePoint } from '../paint/brush.js';
18
18
  import type { RasterRect } from '../raster/surface.js';
19
19
  import type { PaintBrush } from './brushes.js';
20
+ import { type EffectPaintPixels } from './effect-paint.js';
20
21
  import { type PaperGrain } from './paper.js';
21
22
  /** One pen sample in document pixels. Every channel but x and y is optional. */
22
23
  export interface PenPoint {
@@ -123,6 +124,8 @@ export interface DryStrokeOptions {
123
124
  seed?: number;
124
125
  /** Copies of the stroke (symmetry); default one identity copy. */
125
126
  copies?: readonly StrokeCopy[];
127
+ /** Effect paint: each pixel takes its colour (and alpha) from these canvas-sized pixels. */
128
+ effect?: EffectPaintPixels | null;
126
129
  }
127
130
  /**
128
131
  * One dab-engine stroke (dab and eraser brushes): smoothing, the dab walk of every copy, grain and
@@ -138,6 +141,7 @@ export declare class DryStroke {
138
141
  private readonly copies;
139
142
  private readonly depth;
140
143
  private buf;
144
+ private field;
141
145
  private lastRaw;
142
146
  private lastFed;
143
147
  constructor(brush: PaintBrush, options: DryStrokeOptions);