@pixerate/editor 0.242.0 → 0.243.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 (45) hide show
  1. package/dist/animation-editor/index.cjs +59 -59
  2. package/dist/animation-editor/index.js +3 -3
  3. package/dist/{brushstrokeRender-MOYGEXOC.js → brushstrokeRender-274HGNZR.js} +3 -3
  4. package/dist/{brushstrokeRender-UKADOV5D.cjs → brushstrokeRender-C7RJZPMC.cjs} +5 -5
  5. package/dist/canvas/index.cjs +8 -8
  6. package/dist/canvas/index.js +1 -1
  7. package/dist/{chunk-KCMV2534.cjs → chunk-3WOZEBXZ.cjs} +2 -2
  8. package/dist/{chunk-ZDPLZDTT.js → chunk-4ZHXLFXS.js} +1 -1
  9. package/dist/{chunk-5BR7LC24.cjs → chunk-5FZS7J7C.cjs} +50 -4
  10. package/dist/{chunk-ILM6GYAX.js → chunk-6L3WWIDW.js} +1 -1
  11. package/dist/{chunk-UDBDYZET.js → chunk-H4Z72Z4Z.js} +1 -1
  12. package/dist/{chunk-XBZK47LV.js → chunk-HQZHOPNE.js} +49 -3
  13. package/dist/{chunk-QP2B3MID.js → chunk-IXI5KATU.js} +1 -1
  14. package/dist/{chunk-HGGJ36HR.cjs → chunk-KK2FWMA2.cjs} +1 -1
  15. package/dist/{chunk-AFLMXITL.cjs → chunk-OONFIFEU.cjs} +23 -23
  16. package/dist/{chunk-HW72ABGR.cjs → chunk-R2FVAKFH.cjs} +86 -86
  17. package/dist/{chunk-NE6OOKWJ.js → chunk-SRXWDOUI.js} +1 -1
  18. package/dist/{chunk-7F4G74UQ.cjs → chunk-UV7OOZJQ.cjs} +35 -35
  19. package/dist/image-editor/index.cjs +775 -775
  20. package/dist/image-editor/index.js +4 -4
  21. package/dist/paint-editor/brushes.d.cts +18 -2
  22. package/dist/paint-editor/brushes.d.ts +18 -2
  23. package/dist/paint-editor/controller.d.cts +28 -0
  24. package/dist/paint-editor/controller.d.ts +28 -0
  25. package/dist/paint-editor/document.d.cts +3 -0
  26. package/dist/paint-editor/document.d.ts +3 -0
  27. package/dist/paint-editor/index.cjs +1011 -493
  28. package/dist/paint-editor/index.js +560 -42
  29. package/dist/paint-editor/light.d.cts +74 -0
  30. package/dist/paint-editor/light.d.ts +74 -0
  31. package/dist/paint-editor/stroke.d.cts +14 -0
  32. package/dist/paint-editor/stroke.d.ts +14 -0
  33. package/dist/paint-editor/thick-tools.d.cts +2 -2
  34. package/dist/paint-editor/thick-tools.d.ts +2 -2
  35. package/dist/paint-editor/thick.d.cts +5 -1
  36. package/dist/paint-editor/thick.d.ts +5 -1
  37. package/dist/paint-editor/ui.d.cts +2 -0
  38. package/dist/paint-editor/ui.d.ts +2 -0
  39. package/dist/vector/index.cjs +962 -962
  40. package/dist/vector/index.js +4 -4
  41. package/package.json +1 -1
  42. package/skills/pixerate-paint-editor/SKILL.md +9 -9
  43. package/skills/pixerate-paint-editor/references/canvas-hosted.md +8 -0
  44. package/skills/pixerate-paint-editor/references/light-paint.md +31 -0
  45. package/skills/pixerate-paint-oil-impasto/SKILL.md +1 -0
@@ -8,7 +8,7 @@ import {
8
8
  parseOpenTypeFont,
9
9
  removeAnchorsKeepingShape,
10
10
  traceField
11
- } from "../chunk-UDBDYZET.js";
11
+ } from "../chunk-H4Z72Z4Z.js";
12
12
  import {
13
13
  ColorGmm,
14
14
  GAMMA,
@@ -410,7 +410,7 @@ import {
410
410
  writePsd,
411
411
  xyToTempTint,
412
412
  xyToUv
413
- } from "../chunk-NE6OOKWJ.js";
413
+ } from "../chunk-SRXWDOUI.js";
414
414
  import {
415
415
  parseCssColor
416
416
  } from "../chunk-3CI7FRMK.js";
@@ -729,8 +729,8 @@ import {
729
729
  warpMeshParamAt,
730
730
  warpMeshRows,
731
731
  warpPresetMesh
732
- } from "../chunk-ILM6GYAX.js";
733
- import "../chunk-XBZK47LV.js";
732
+ } from "../chunk-6L3WWIDW.js";
733
+ import "../chunk-HQZHOPNE.js";
734
734
  import "../chunk-M6DNZNVY.js";
735
735
  import {
736
736
  bezierPathToSvg,
@@ -18,7 +18,7 @@ import { type BristleSettings, type ParticleSettings } from './procedural.cjs';
18
18
  */
19
19
  export type PaintBrushEngine = 'dab' | 'eraser' | 'mixer' | 'blender' | 'smudge' | 'wet' | 'impasto' | 'particle' | 'bristle' | 'sticker';
20
20
  export declare const PAINT_BRUSH_ENGINES: readonly PaintBrushEngine[];
21
- export type PaintBrushCategory = 'pencil' | 'pastel' | 'charcoal' | 'airbrush' | 'marker' | 'ink' | 'paint' | 'eraser' | 'blender' | 'smudge' | 'mixer' | 'watercolor' | 'wet-tool' | 'oil' | 'impasto' | 'procedural' | 'bristle' | 'sticker' | 'custom';
21
+ 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
22
  export declare const PAINT_BRUSH_CATEGORIES: readonly PaintBrushCategory[];
23
23
  /**
24
24
  * What a wet brush does to the wet layer: `paint` (water and pigment), `water` (clear water;
@@ -81,8 +81,21 @@ export interface ImpastoSettings {
81
81
  thinner: number;
82
82
  /** Knife and brush: how much of the paint under the tool is dragged along (0..1). */
83
83
  drag: number;
84
+ /** Light paint: the bead's light is stronger where its surface turns away, as on backlit glass (0..1, default 0). */
85
+ rim: number;
86
+ /** Light paint: the middle of a bead lets the layers below show through, its edges stay solid (0..1, default 0). */
87
+ clarity: number;
84
88
  }
85
89
  export declare const DEFAULT_IMPASTO: Readonly<ImpastoSettings>;
90
+ /** Light paint: how much light a brush lays with its colour (see `doc.light`). */
91
+ export interface LightSettings {
92
+ /** Light each dab lays, scaled by its coverage and flow (0..1, default 0: none). */
93
+ amount: number;
94
+ /** Pressure scales the light (default false). */
95
+ pressure: boolean;
96
+ }
97
+ export declare const DEFAULT_LIGHT: Readonly<LightSettings>;
98
+ export declare function normalizeLight(raw?: Partial<LightSettings>, base?: LightSettings): LightSettings;
86
99
  export declare function normalizeImpasto(raw?: Partial<ImpastoSettings>, base?: ImpastoSettings): ImpastoSettings;
87
100
  /** Multi-coloured brush: `tip` lays the colours across the tip, `dab` changes colour from dab to dab. */
88
101
  export type MultiColorMode = 'off' | 'tip' | 'dab';
@@ -181,6 +194,8 @@ export interface PaintBrush {
181
194
  bristle: BristleSettings;
182
195
  /** Sticker engine only: the stamps and how they are sprayed. */
183
196
  sticker: StickerSettings;
197
+ /** Light paint: the light it lays with its colour (amount 0: none). */
198
+ light: LightSettings;
184
199
  /**
185
200
  * The brush's own gradient paint (`@pixerate/editor/paint` `PaintGradientSource`), used instead
186
201
  * of the editor's paint; `null` (default): the editor's paint. Stops may be `paint` / `secondary`
@@ -199,7 +214,8 @@ export type BrushBehaviorInput = Partial<Omit<BrushBehavior, 'multicolor'>> & {
199
214
  };
200
215
  export declare function normalizeBehavior(raw?: BrushBehaviorInput, base?: BrushBehavior): BrushBehavior;
201
216
  /** Brush settings to change or read: any subset of a brush and of its blocks. */
202
- export type PaintBrushInput = Partial<Omit<PaintBrush, 'tip' | 'dynamics' | 'mixer' | 'behavior' | 'blender' | 'smudge' | 'wet' | 'impasto' | 'particle' | 'bristle' | 'sticker' | 'paint'>> & {
217
+ export type PaintBrushInput = Partial<Omit<PaintBrush, 'tip' | 'dynamics' | 'mixer' | 'behavior' | 'blender' | 'smudge' | 'wet' | 'impasto' | 'particle' | 'bristle' | 'sticker' | 'paint' | 'light'>> & {
218
+ light?: Partial<LightSettings>;
203
219
  /** A gradient (or `null` for the editor's paint); a plain colour source clears it. */
204
220
  paint?: PaintSource | null;
205
221
  tip?: Partial<BrushSettings>;
@@ -18,7 +18,7 @@ import { type BristleSettings, type ParticleSettings } from './procedural.js';
18
18
  */
19
19
  export type PaintBrushEngine = 'dab' | 'eraser' | 'mixer' | 'blender' | 'smudge' | 'wet' | 'impasto' | 'particle' | 'bristle' | 'sticker';
20
20
  export declare const PAINT_BRUSH_ENGINES: readonly PaintBrushEngine[];
21
- export type PaintBrushCategory = 'pencil' | 'pastel' | 'charcoal' | 'airbrush' | 'marker' | 'ink' | 'paint' | 'eraser' | 'blender' | 'smudge' | 'mixer' | 'watercolor' | 'wet-tool' | 'oil' | 'impasto' | 'procedural' | 'bristle' | 'sticker' | 'custom';
21
+ 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
22
  export declare const PAINT_BRUSH_CATEGORIES: readonly PaintBrushCategory[];
23
23
  /**
24
24
  * What a wet brush does to the wet layer: `paint` (water and pigment), `water` (clear water;
@@ -81,8 +81,21 @@ export interface ImpastoSettings {
81
81
  thinner: number;
82
82
  /** Knife and brush: how much of the paint under the tool is dragged along (0..1). */
83
83
  drag: number;
84
+ /** Light paint: the bead's light is stronger where its surface turns away, as on backlit glass (0..1, default 0). */
85
+ rim: number;
86
+ /** Light paint: the middle of a bead lets the layers below show through, its edges stay solid (0..1, default 0). */
87
+ clarity: number;
84
88
  }
85
89
  export declare const DEFAULT_IMPASTO: Readonly<ImpastoSettings>;
90
+ /** Light paint: how much light a brush lays with its colour (see `doc.light`). */
91
+ export interface LightSettings {
92
+ /** Light each dab lays, scaled by its coverage and flow (0..1, default 0: none). */
93
+ amount: number;
94
+ /** Pressure scales the light (default false). */
95
+ pressure: boolean;
96
+ }
97
+ export declare const DEFAULT_LIGHT: Readonly<LightSettings>;
98
+ export declare function normalizeLight(raw?: Partial<LightSettings>, base?: LightSettings): LightSettings;
86
99
  export declare function normalizeImpasto(raw?: Partial<ImpastoSettings>, base?: ImpastoSettings): ImpastoSettings;
87
100
  /** Multi-coloured brush: `tip` lays the colours across the tip, `dab` changes colour from dab to dab. */
88
101
  export type MultiColorMode = 'off' | 'tip' | 'dab';
@@ -181,6 +194,8 @@ export interface PaintBrush {
181
194
  bristle: BristleSettings;
182
195
  /** Sticker engine only: the stamps and how they are sprayed. */
183
196
  sticker: StickerSettings;
197
+ /** Light paint: the light it lays with its colour (amount 0: none). */
198
+ light: LightSettings;
184
199
  /**
185
200
  * The brush's own gradient paint (`@pixerate/editor/paint` `PaintGradientSource`), used instead
186
201
  * of the editor's paint; `null` (default): the editor's paint. Stops may be `paint` / `secondary`
@@ -199,7 +214,8 @@ export type BrushBehaviorInput = Partial<Omit<BrushBehavior, 'multicolor'>> & {
199
214
  };
200
215
  export declare function normalizeBehavior(raw?: BrushBehaviorInput, base?: BrushBehavior): BrushBehavior;
201
216
  /** Brush settings to change or read: any subset of a brush and of its blocks. */
202
- export type PaintBrushInput = Partial<Omit<PaintBrush, 'tip' | 'dynamics' | 'mixer' | 'behavior' | 'blender' | 'smudge' | 'wet' | 'impasto' | 'particle' | 'bristle' | 'sticker' | 'paint'>> & {
217
+ export type PaintBrushInput = Partial<Omit<PaintBrush, 'tip' | 'dynamics' | 'mixer' | 'behavior' | 'blender' | 'smudge' | 'wet' | 'impasto' | 'particle' | 'bristle' | 'sticker' | 'paint' | 'light'>> & {
218
+ light?: Partial<LightSettings>;
203
219
  /** A gradient (or `null` for the editor's paint); a plain colour source clears it. */
204
220
  paint?: PaintSource | null;
205
221
  tip?: Partial<BrushSettings>;
@@ -32,6 +32,7 @@ import { type PaintGuides, type PerspectiveGuide, type ReferenceImage, type Symm
32
32
  import { MixingPad, type MixingPadTool, type PadMixOptions } from './mixing-pad.cjs';
33
33
  import { type Stencil, type StencilInput } from './stencils.cjs';
34
34
  import { type Sticker } from './stickers.cjs';
35
+ import { type LightSpill } from './light.cjs';
35
36
  import { type PaintView } from './view.cjs';
36
37
  import { PaintWetLayers, type PaintWetOptions, type WetEngineInfo, type WetGpuMode, type WetLayerInfo } from './wet.cjs';
37
38
  import { type WetParams, type WetTilt } from '../paint/wet/model.cjs';
@@ -314,6 +315,9 @@ export declare class PaintEditorController {
314
315
  private dirty;
315
316
  private seedCounter;
316
317
  private strokeCounter;
318
+ /** Light paint: each layer's spill settings (saved with the document, not undo steps; missing = the defaults). */
319
+ private lightSpills;
320
+ private readonly lightCaches;
317
321
  /** Live effect paint: playing and the frame rate cap (editor state), and the time the view shows. */
318
322
  private effectPlaybackState;
319
323
  private effectTime;
@@ -731,6 +735,24 @@ export declare class PaintEditorController {
731
735
  bounds: RasterRect | null;
732
736
  layerIds: string[];
733
737
  };
738
+ /** The document's `light` without these layers (as a spread: `{}` when unchanged). */
739
+ private lightWithout;
740
+ private lightSpillOf;
741
+ /** A layer's light paint: whether it has any, where (document pixels), its brightest value 0..255, and its spill. */
742
+ lightOf(layerId?: string): {
743
+ layerId: string;
744
+ hasLight: boolean;
745
+ bounds: RasterRect | null;
746
+ peak: number;
747
+ spill: LightSpill;
748
+ };
749
+ /** How far a layer's light spills (px; 0 turns it off) and how strongly (0..2). Saved with the document, not an undo step; nothing is repainted. */
750
+ setLightSpill(layerId: string | undefined, update: Partial<LightSpill>): LightSpill;
751
+ /** Takes a layer's light away; its paint keeps its colour. One undo step. Returns whether there was any. */
752
+ clearLight(layerId?: string): {
753
+ layerId: string;
754
+ cleared: boolean;
755
+ };
734
756
  /** The document's `thick` without these layers (as a spread: `{}` when unchanged). */
735
757
  private thickWithout;
736
758
  /** Where the light comes from for thick paint and metallic paper. */
@@ -889,6 +911,12 @@ export declare class PaintEditorController {
889
911
  private driedLayers;
890
912
  /** The layers with thick paint lit (each thick layer's pixels replaced by its lit tiles). */
891
913
  private litLayers;
914
+ /**
915
+ * Light paint over the (lit) layers: glow, rim and clarity in each layer's pixels, and its spill
916
+ * as a Linear Dodge (Add) layer directly above it (from the painting as committed, so a stroke in
917
+ * progress does not redraw the blur every frame).
918
+ */
919
+ private lightLayers;
892
920
  private renderLayers;
893
921
  /**
894
922
  * Composites the viewport stack (paper, view-only underlays, layers with the live stroke) tile by
@@ -32,6 +32,7 @@ import { type PaintGuides, type PerspectiveGuide, type ReferenceImage, type Symm
32
32
  import { MixingPad, type MixingPadTool, type PadMixOptions } from './mixing-pad.js';
33
33
  import { type Stencil, type StencilInput } from './stencils.js';
34
34
  import { type Sticker } from './stickers.js';
35
+ import { type LightSpill } from './light.js';
35
36
  import { type PaintView } from './view.js';
36
37
  import { PaintWetLayers, type PaintWetOptions, type WetEngineInfo, type WetGpuMode, type WetLayerInfo } from './wet.js';
37
38
  import { type WetParams, type WetTilt } from '../paint/wet/model.js';
@@ -314,6 +315,9 @@ export declare class PaintEditorController {
314
315
  private dirty;
315
316
  private seedCounter;
316
317
  private strokeCounter;
318
+ /** Light paint: each layer's spill settings (saved with the document, not undo steps; missing = the defaults). */
319
+ private lightSpills;
320
+ private readonly lightCaches;
317
321
  /** Live effect paint: playing and the frame rate cap (editor state), and the time the view shows. */
318
322
  private effectPlaybackState;
319
323
  private effectTime;
@@ -731,6 +735,24 @@ export declare class PaintEditorController {
731
735
  bounds: RasterRect | null;
732
736
  layerIds: string[];
733
737
  };
738
+ /** The document's `light` without these layers (as a spread: `{}` when unchanged). */
739
+ private lightWithout;
740
+ private lightSpillOf;
741
+ /** A layer's light paint: whether it has any, where (document pixels), its brightest value 0..255, and its spill. */
742
+ lightOf(layerId?: string): {
743
+ layerId: string;
744
+ hasLight: boolean;
745
+ bounds: RasterRect | null;
746
+ peak: number;
747
+ spill: LightSpill;
748
+ };
749
+ /** How far a layer's light spills (px; 0 turns it off) and how strongly (0..2). Saved with the document, not an undo step; nothing is repainted. */
750
+ setLightSpill(layerId: string | undefined, update: Partial<LightSpill>): LightSpill;
751
+ /** Takes a layer's light away; its paint keeps its colour. One undo step. Returns whether there was any. */
752
+ clearLight(layerId?: string): {
753
+ layerId: string;
754
+ cleared: boolean;
755
+ };
734
756
  /** The document's `thick` without these layers (as a spread: `{}` when unchanged). */
735
757
  private thickWithout;
736
758
  /** Where the light comes from for thick paint and metallic paper. */
@@ -889,6 +911,12 @@ export declare class PaintEditorController {
889
911
  private driedLayers;
890
912
  /** The layers with thick paint lit (each thick layer's pixels replaced by its lit tiles). */
891
913
  private litLayers;
914
+ /**
915
+ * Light paint over the (lit) layers: glow, rim and clarity in each layer's pixels, and its spill
916
+ * as a Linear Dodge (Add) layer directly above it (from the painting as committed, so a stroke in
917
+ * progress does not redraw the blur every frame).
918
+ */
919
+ private lightLayers;
892
920
  private renderLayers;
893
921
  /**
894
922
  * Composites the viewport stack (paper, view-only underlays, layers with the live stroke) tile by
@@ -8,6 +8,7 @@
8
8
  * same layer tree loads in both editors), with the paper as plain settings.
9
9
  */
10
10
  import type { RasterGroupLayer, RasterLayer, RasterPixelLayer } from '../raster/layers.cjs';
11
+ import { type TiledSurface } from '../raster/surface.cjs';
11
12
  import { type PaperSettings } from './paper.cjs';
12
13
  import type { RecordedStroke } from './strokes.cjs';
13
14
  import type { WetEvent } from './wet.cjs';
@@ -48,6 +49,8 @@ export interface PaintDocumentState {
48
49
  * stroke's brush, colour and points stay editable (`updateStroke`).
49
50
  */
50
51
  liveStrokes?: Readonly<Record<string, RecordedStroke[]>>;
52
+ /** Light paint: each layer's light channel, 0..255 per pixel in layer space (layers without light are missing). See `light.ts`. */
53
+ light?: Readonly<Record<string, TiledSurface>>;
51
54
  /** Thick paint: each layer's height and material channels (layers without relief are missing). */
52
55
  thick?: Readonly<Record<string, ThickChannels>>;
53
56
  /** Effect layers: the provider effect each one is drawn from (layers that are gone are ignored). */
@@ -8,6 +8,7 @@
8
8
  * same layer tree loads in both editors), with the paper as plain settings.
9
9
  */
10
10
  import type { RasterGroupLayer, RasterLayer, RasterPixelLayer } from '../raster/layers.js';
11
+ import { type TiledSurface } from '../raster/surface.js';
11
12
  import { type PaperSettings } from './paper.js';
12
13
  import type { RecordedStroke } from './strokes.js';
13
14
  import type { WetEvent } from './wet.js';
@@ -48,6 +49,8 @@ export interface PaintDocumentState {
48
49
  * stroke's brush, colour and points stay editable (`updateStroke`).
49
50
  */
50
51
  liveStrokes?: Readonly<Record<string, RecordedStroke[]>>;
52
+ /** Light paint: each layer's light channel, 0..255 per pixel in layer space (layers without light are missing). See `light.ts`. */
53
+ light?: Readonly<Record<string, TiledSurface>>;
51
54
  /** Thick paint: each layer's height and material channels (layers without relief are missing). */
52
55
  thick?: Readonly<Record<string, ThickChannels>>;
53
56
  /** Effect layers: the provider effect each one is drawn from (layers that are gone are ignored). */