@pixerate/editor 0.210.0 → 0.212.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 (30) hide show
  1. package/dist/{chunk-QE7D7TZR.cjs → chunk-H65IBXFI.cjs} +74 -25
  2. package/dist/{chunk-KFIOEOCQ.js → chunk-W3TOZTL7.js} +55 -6
  3. package/dist/image-editor/content-aware-fill-session.d.cts +17 -5
  4. package/dist/image-editor/content-aware-fill-session.d.ts +17 -5
  5. package/dist/image-editor/controller.d.cts +60 -4
  6. package/dist/image-editor/controller.d.ts +60 -4
  7. package/dist/image-editor/index.cjs +1522 -1013
  8. package/dist/image-editor/index.d.cts +1 -0
  9. package/dist/image-editor/index.d.ts +1 -0
  10. package/dist/image-editor/index.js +532 -23
  11. package/dist/image-editor/layers/serialize.d.cts +5 -8
  12. package/dist/image-editor/layers/serialize.d.ts +5 -8
  13. package/dist/image-editor/paths.d.cts +41 -0
  14. package/dist/image-editor/paths.d.ts +41 -0
  15. package/dist/image-editor/psd/export.d.cts +8 -1
  16. package/dist/image-editor/psd/export.d.ts +8 -1
  17. package/dist/image-editor/psd/import.d.cts +7 -0
  18. package/dist/image-editor/psd/import.d.ts +7 -0
  19. package/dist/image-editor/psd/paths.d.cts +11 -0
  20. package/dist/image-editor/psd/paths.d.ts +11 -0
  21. package/dist/image-editor/selection/gesture.d.cts +10 -2
  22. package/dist/image-editor/selection/gesture.d.ts +10 -2
  23. package/dist/image-editor/selection/select-and-mask.d.cts +5 -0
  24. package/dist/image-editor/selection/select-and-mask.d.ts +5 -0
  25. package/dist/image-editor/types.d.cts +12 -0
  26. package/dist/image-editor/types.d.ts +12 -0
  27. package/dist/paint-editor/index.cjs +6 -6
  28. package/dist/paint-editor/index.js +1 -1
  29. package/package.json +1 -1
  30. package/skills/pixerate-image-editor/SKILL.md +1 -1
@@ -1,11 +1,4 @@
1
- /**
2
- * Schema version 3 of the image editor document: the layer tree, with pixel layers and painted
3
- * masks stored as PNG assets (cropped to their content and placed by position), plus the
4
- * document-level crop, transform, output opacity, migrated blur and selection.
5
- *
6
- * Encoding is synchronous and exact (see `png.ts`). Each surface's encoding is memoised, so
7
- * saving an unchanged layer again costs nothing.
8
- */
1
+ import type { SerializedDocumentPath } from '../paths.cjs';
9
2
  import type { Annotation, CropBox, DepthMaskOptions, ImageTransform } from '../types.cjs';
10
3
  import type { SerializedSelection } from '../selection/mask.cjs';
11
4
  import type { SerializedAlphaChannel } from '../selection/channels.cjs';
@@ -238,6 +231,8 @@ export interface SerializedLayeredImageEditorState {
238
231
  selection?: SerializedSelection;
239
232
  /** Alpha channels (saved selections), run-length encoded. */
240
233
  channels?: SerializedAlphaChannel[];
234
+ /** Document paths (the Paths panel). */
235
+ paths?: SerializedDocumentPath[];
241
236
  /** Global light for layer effects (missing = 120°, 30°). */
242
237
  globalLight?: GlobalLight;
243
238
  /** The document's patterns for pattern effects, each an RGBA PNG data URL. */
@@ -279,6 +274,8 @@ export interface SerializeContext {
279
274
  export declare function serializeEffects(effects: LayerEffects): SerializedLayerEffects;
280
275
  /** Reads stored effects (leniently: broken effects are dropped), or `undefined`. */
281
276
  export declare function deserializeEffects(raw: unknown): LayerEffects | undefined;
277
+ /** Restores stored shape components (a vector mask's or a document path's); throws on damaged ones. */
278
+ export declare function readShapeComponents(stored: unknown): ShapeComponent[];
282
279
  export declare function serializeLayer(layer: ImageLayer, ctx: SerializeContext): SerializedLayer;
283
280
  /** Writes one contents entry (nested layers add their own assets and contents to `ctx`). */
284
281
  export declare function serializeContents(c: SmartContents, ctx: SerializeContext): SerializedSmartContents;
@@ -1,11 +1,4 @@
1
- /**
2
- * Schema version 3 of the image editor document: the layer tree, with pixel layers and painted
3
- * masks stored as PNG assets (cropped to their content and placed by position), plus the
4
- * document-level crop, transform, output opacity, migrated blur and selection.
5
- *
6
- * Encoding is synchronous and exact (see `png.ts`). Each surface's encoding is memoised, so
7
- * saving an unchanged layer again costs nothing.
8
- */
1
+ import type { SerializedDocumentPath } from '../paths.js';
9
2
  import type { Annotation, CropBox, DepthMaskOptions, ImageTransform } from '../types.js';
10
3
  import type { SerializedSelection } from '../selection/mask.js';
11
4
  import type { SerializedAlphaChannel } from '../selection/channels.js';
@@ -238,6 +231,8 @@ export interface SerializedLayeredImageEditorState {
238
231
  selection?: SerializedSelection;
239
232
  /** Alpha channels (saved selections), run-length encoded. */
240
233
  channels?: SerializedAlphaChannel[];
234
+ /** Document paths (the Paths panel). */
235
+ paths?: SerializedDocumentPath[];
241
236
  /** Global light for layer effects (missing = 120°, 30°). */
242
237
  globalLight?: GlobalLight;
243
238
  /** The document's patterns for pattern effects, each an RGBA PNG data URL. */
@@ -279,6 +274,8 @@ export interface SerializeContext {
279
274
  export declare function serializeEffects(effects: LayerEffects): SerializedLayerEffects;
280
275
  /** Reads stored effects (leniently: broken effects are dropped), or `undefined`. */
281
276
  export declare function deserializeEffects(raw: unknown): LayerEffects | undefined;
277
+ /** Restores stored shape components (a vector mask's or a document path's); throws on damaged ones. */
278
+ export declare function readShapeComponents(stored: unknown): ShapeComponent[];
282
279
  export declare function serializeLayer(layer: ImageLayer, ctx: SerializeContext): SerializedLayer;
283
280
  /** Writes one contents entry (nested layers add their own assets and contents to `ctx`). */
284
281
  export declare function serializeContents(c: SmartContents, ctx: SerializeContext): SerializedSmartContents;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Document paths (Photoshop's Paths panel): vector outlines kept with the document but on no
3
+ * layer. The Work Path is the scratch path Make Work Path replaces; saved paths stay until
4
+ * deleted. A path can become a selection, a vector mask, a fill or a stroke.
5
+ */
6
+ import type { CropBox } from './types.cjs';
7
+ import type { ShapeComponent, ShapeFillRule } from './layers/model.cjs';
8
+ export interface DocumentPath {
9
+ id: string;
10
+ name: string;
11
+ /** In document pixels, combined by their operations (as a shape layer's). */
12
+ components: ShapeComponent[];
13
+ /** How overlapping subpaths fill (default nonzero; a traced selection's holes need evenodd). */
14
+ fillRule?: ShapeFillRule;
15
+ /** The Work Path: replaced by the next Make Work Path until it is saved (renamed). */
16
+ work?: boolean;
17
+ }
18
+ /** A path as stored in a document (`toJSON().paths`). */
19
+ export interface SerializedDocumentPath {
20
+ id: string;
21
+ name: string;
22
+ /** Components as a vector mask stores them. */
23
+ components: unknown[];
24
+ fillRule?: 'evenodd';
25
+ work?: boolean;
26
+ }
27
+ export declare const WORK_PATH_NAME = "Work Path";
28
+ /** A new, unique path id. */
29
+ export declare function newPathId(): string;
30
+ /** The path's outline as SVG path data in document pixels (for a thumbnail or `d` attribute). */
31
+ export declare function pathSvgData(path: DocumentPath): string;
32
+ /** The path's bounds in document pixels (of the curve itself, not its handles), or null when empty. */
33
+ export declare function pathBounds(path: DocumentPath): CropBox | null;
34
+ /** How many anchors the path has. */
35
+ export declare function pathAnchorCount(path: DocumentPath): number;
36
+ export declare function serializePaths(paths: readonly DocumentPath[]): SerializedDocumentPath[];
37
+ /**
38
+ * Restores stored paths, skipping damaged ones (listed in `problems`). At most one stays the Work
39
+ * Path; ids are made unique.
40
+ */
41
+ export declare function readPaths(stored: unknown, problems?: string[]): DocumentPath[];
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Document paths (Photoshop's Paths panel): vector outlines kept with the document but on no
3
+ * layer. The Work Path is the scratch path Make Work Path replaces; saved paths stay until
4
+ * deleted. A path can become a selection, a vector mask, a fill or a stroke.
5
+ */
6
+ import type { CropBox } from './types.js';
7
+ import type { ShapeComponent, ShapeFillRule } from './layers/model.js';
8
+ export interface DocumentPath {
9
+ id: string;
10
+ name: string;
11
+ /** In document pixels, combined by their operations (as a shape layer's). */
12
+ components: ShapeComponent[];
13
+ /** How overlapping subpaths fill (default nonzero; a traced selection's holes need evenodd). */
14
+ fillRule?: ShapeFillRule;
15
+ /** The Work Path: replaced by the next Make Work Path until it is saved (renamed). */
16
+ work?: boolean;
17
+ }
18
+ /** A path as stored in a document (`toJSON().paths`). */
19
+ export interface SerializedDocumentPath {
20
+ id: string;
21
+ name: string;
22
+ /** Components as a vector mask stores them. */
23
+ components: unknown[];
24
+ fillRule?: 'evenodd';
25
+ work?: boolean;
26
+ }
27
+ export declare const WORK_PATH_NAME = "Work Path";
28
+ /** A new, unique path id. */
29
+ export declare function newPathId(): string;
30
+ /** The path's outline as SVG path data in document pixels (for a thumbnail or `d` attribute). */
31
+ export declare function pathSvgData(path: DocumentPath): string;
32
+ /** The path's bounds in document pixels (of the curve itself, not its handles), or null when empty. */
33
+ export declare function pathBounds(path: DocumentPath): CropBox | null;
34
+ /** How many anchors the path has. */
35
+ export declare function pathAnchorCount(path: DocumentPath): number;
36
+ export declare function serializePaths(paths: readonly DocumentPath[]): SerializedDocumentPath[];
37
+ /**
38
+ * Restores stored paths, skipping damaged ones (listed in `problems`). At most one stays the Work
39
+ * Path; ids are made unique.
40
+ */
41
+ export declare function readPaths(stored: unknown, problems?: string[]): DocumentPath[];
@@ -1,4 +1,4 @@
1
- import { type ImageLayer, type SmartContents } from '../layers/model.cjs';
1
+ import { type ImageLayer, type ShapeComponent, type SmartContents } from '../layers/model.cjs';
2
2
  import { type PsdAlphaChannel } from './channels.cjs';
3
3
  import { type GlobalLight } from '../../raster/effects/model.cjs';
4
4
  import { type EffectPattern } from '../../raster/effects/patterns.cjs';
@@ -11,6 +11,13 @@ export interface PsdExportInput {
11
11
  merged: ArrayLike<number>;
12
12
  /** Alpha channels, written as extra merged planes with their names and display info. */
13
13
  alphaChannels?: readonly PsdAlphaChannel[];
14
+ /** Document paths: saved paths as image resources 2000 on, the Work Path as 1025. */
15
+ paths?: readonly {
16
+ name: string;
17
+ components: readonly ShapeComponent[];
18
+ work?: boolean;
19
+ fillRule?: 'nonzero' | 'evenodd';
20
+ }[];
14
21
  /** Pixels per inch (default 72). */
15
22
  resolution?: number;
16
23
  /** The document's patterns; those the effects use are embedded (built-in ones too). */
@@ -1,4 +1,4 @@
1
- import { type ImageLayer, type SmartContents } from '../layers/model.js';
1
+ import { type ImageLayer, type ShapeComponent, type SmartContents } from '../layers/model.js';
2
2
  import { type PsdAlphaChannel } from './channels.js';
3
3
  import { type GlobalLight } from '../../raster/effects/model.js';
4
4
  import { type EffectPattern } from '../../raster/effects/patterns.js';
@@ -11,6 +11,13 @@ export interface PsdExportInput {
11
11
  merged: ArrayLike<number>;
12
12
  /** Alpha channels, written as extra merged planes with their names and display info. */
13
13
  alphaChannels?: readonly PsdAlphaChannel[];
14
+ /** Document paths: saved paths as image resources 2000 on, the Work Path as 1025. */
15
+ paths?: readonly {
16
+ name: string;
17
+ components: readonly ShapeComponent[];
18
+ work?: boolean;
19
+ fillRule?: 'nonzero' | 'evenodd';
20
+ }[];
14
21
  /** Pixels per inch (default 72). */
15
22
  resolution?: number;
16
23
  /** The document's patterns; those the effects use are embedded (built-in ones too). */
@@ -1,3 +1,4 @@
1
+ import type { ShapeComponent } from '../layers/model.cjs';
1
2
  import { type PsdAlphaChannel } from './channels.cjs';
2
3
  import type { ImageLayer, LayerBlendMode } from '../layers/model.cjs';
3
4
  import { type PsdFile } from './file.cjs';
@@ -57,6 +58,12 @@ export interface PsdImportResult {
57
58
  bitDepth: 8 | 16 | 32;
58
59
  /** The file's alpha channels (saved selections), as 8-bit planes. */
59
60
  alphaChannels?: PsdAlphaChannel[];
61
+ /** The file's document paths (image resources 2000–2997 and the Work Path, 1025), in file order. */
62
+ paths?: {
63
+ name: string;
64
+ components: ShapeComponent[];
65
+ work?: boolean;
66
+ }[];
60
67
  }
61
68
  export interface PsdImportOptions {
62
69
  /** Makes layer ids (defaults to `psd-<n>`). */
@@ -1,3 +1,4 @@
1
+ import type { ShapeComponent } from '../layers/model.js';
1
2
  import { type PsdAlphaChannel } from './channels.js';
2
3
  import type { ImageLayer, LayerBlendMode } from '../layers/model.js';
3
4
  import { type PsdFile } from './file.js';
@@ -57,6 +58,12 @@ export interface PsdImportResult {
57
58
  bitDepth: 8 | 16 | 32;
58
59
  /** The file's alpha channels (saved selections), as 8-bit planes. */
59
60
  alphaChannels?: PsdAlphaChannel[];
61
+ /** The file's document paths (image resources 2000–2997 and the Work Path, 1025), in file order. */
62
+ paths?: {
63
+ name: string;
64
+ components: ShapeComponent[];
65
+ work?: boolean;
66
+ }[];
60
67
  }
61
68
  export interface PsdImportOptions {
62
69
  /** Makes layer ids (defaults to `psd-<n>`). */
@@ -54,3 +54,14 @@ export declare function componentsFromVectorBlock(data: Uint8Array, width: numbe
54
54
  } | null;
55
55
  /** A layer vector block for shape components (live corners cut; `inverted` as the invert flag). */
56
56
  export declare function vectorBlockForComponents(components: readonly ShapeComponent[], inverted: boolean, width: number, height: number, flags?: number): Uint8Array;
57
+ /** Image resource ids of document paths: the Work Path, and the range saved paths use. */
58
+ export declare const RESOURCE_WORK_PATH = 1025;
59
+ export declare const RESOURCE_PATH_FIRST = 2000;
60
+ export declare const RESOURCE_PATH_LAST = 2997;
61
+ /** Shape components from a path resource (the path records of a saved path or the Work Path). */
62
+ export declare function componentsFromPathResource(data: Uint8Array, width: number, height: number): {
63
+ components: ShapeComponent[];
64
+ inverted: boolean;
65
+ } | null;
66
+ /** A path resource's data for shape components. */
67
+ export declare function pathResourceForComponents(components: readonly ShapeComponent[], width: number, height: number): Uint8Array;
@@ -54,3 +54,14 @@ export declare function componentsFromVectorBlock(data: Uint8Array, width: numbe
54
54
  } | null;
55
55
  /** A layer vector block for shape components (live corners cut; `inverted` as the invert flag). */
56
56
  export declare function vectorBlockForComponents(components: readonly ShapeComponent[], inverted: boolean, width: number, height: number, flags?: number): Uint8Array;
57
+ /** Image resource ids of document paths: the Work Path, and the range saved paths use. */
58
+ export declare const RESOURCE_WORK_PATH = 1025;
59
+ export declare const RESOURCE_PATH_FIRST = 2000;
60
+ export declare const RESOURCE_PATH_LAST = 2997;
61
+ /** Shape components from a path resource (the path records of a saved path or the Work Path). */
62
+ export declare function componentsFromPathResource(data: Uint8Array, width: number, height: number): {
63
+ components: ShapeComponent[];
64
+ inverted: boolean;
65
+ } | null;
66
+ /** A path resource's data for shape components. */
67
+ export declare function pathResourceForComponents(components: readonly ShapeComponent[], width: number, height: number): Uint8Array;
@@ -27,8 +27,9 @@ export declare function snapTo45(from: ImagePoint, point: ImagePoint): ImagePoin
27
27
  * last anchor to the pointer (snapped to the strongest edge within the width) and places
28
28
  * anchors as it goes (frequency); a click adds one, and closing and the keys are as the
29
29
  * polygonal lasso's. The first click reads the pixels (async).
30
- * - Quick Selection: drag (or click) a brush stroke; on `end` it grows into the region painted on,
31
- * out to its edges (async: await {@link settled}). With the New mode and a selection already
30
+ * - Quick Selection: drag (or click) a brush stroke; the selection grows into the region painted
31
+ * on as the brush moves (shown with `setSelectionPreview`), and on `end` the stroke is applied
32
+ * as one undo step (async: await {@link settled}). With the New mode and a selection already
32
33
  * there, strokes add, as in Photoshop; Alt subtracts.
33
34
  * - Object Selection: drag a box around an object, or click on it; on `end` the object is
34
35
  * selected (async: await {@link settled}).
@@ -54,10 +55,17 @@ export declare class SelectionGesture {
54
55
  /** The last error (e.g. pixels unavailable for the wand), for the UI to show. */
55
56
  error: string | null;
56
57
  private pending;
58
+ /** Quick Selection while dragging: the selection before the stroke, how the stroke combines, the pixels. */
59
+ private quick;
60
+ private livePreviews;
57
61
  constructor(controller: ImageEditorController, getOptions: () => SelectionToolOptions);
58
62
  get active(): boolean;
59
63
  /** Resolves once a Quick Selection stroke or an Object Selection has been applied. */
60
64
  get settled(): Promise<void>;
65
+ /** Resolves once no live Quick Selection preview is being computed. */
66
+ get previewed(): Promise<void>;
67
+ /** Grows the Quick Selection preview to the stroke so far: one at a time, the newest points following. */
68
+ private growPreview;
61
69
  /** The anchors of a Magnetic Lasso being drawn (empty otherwise). */
62
70
  get magneticAnchors(): ImagePoint[];
63
71
  /** The outline of the shape being drawn, or `null`. */
@@ -27,8 +27,9 @@ export declare function snapTo45(from: ImagePoint, point: ImagePoint): ImagePoin
27
27
  * last anchor to the pointer (snapped to the strongest edge within the width) and places
28
28
  * anchors as it goes (frequency); a click adds one, and closing and the keys are as the
29
29
  * polygonal lasso's. The first click reads the pixels (async).
30
- * - Quick Selection: drag (or click) a brush stroke; on `end` it grows into the region painted on,
31
- * out to its edges (async: await {@link settled}). With the New mode and a selection already
30
+ * - Quick Selection: drag (or click) a brush stroke; the selection grows into the region painted
31
+ * on as the brush moves (shown with `setSelectionPreview`), and on `end` the stroke is applied
32
+ * as one undo step (async: await {@link settled}). With the New mode and a selection already
32
33
  * there, strokes add, as in Photoshop; Alt subtracts.
33
34
  * - Object Selection: drag a box around an object, or click on it; on `end` the object is
34
35
  * selected (async: await {@link settled}).
@@ -54,10 +55,17 @@ export declare class SelectionGesture {
54
55
  /** The last error (e.g. pixels unavailable for the wand), for the UI to show. */
55
56
  error: string | null;
56
57
  private pending;
58
+ /** Quick Selection while dragging: the selection before the stroke, how the stroke combines, the pixels. */
59
+ private quick;
60
+ private livePreviews;
57
61
  constructor(controller: ImageEditorController, getOptions: () => SelectionToolOptions);
58
62
  get active(): boolean;
59
63
  /** Resolves once a Quick Selection stroke or an Object Selection has been applied. */
60
64
  get settled(): Promise<void>;
65
+ /** Resolves once no live Quick Selection preview is being computed. */
66
+ get previewed(): Promise<void>;
67
+ /** Grows the Quick Selection preview to the stroke so far: one at a time, the newest points following. */
68
+ private growPreview;
61
69
  /** The anchors of a Magnetic Lasso being drawn (empty otherwise). */
62
70
  get magneticAnchors(): ImagePoint[];
63
71
  /** The outline of the shape being drawn, or `null`. */
@@ -63,6 +63,9 @@ export declare class SelectAndMaskSession {
63
63
  private dragStart;
64
64
  private pixels;
65
65
  private previewPixels;
66
+ /** The layers below the active one, composited (On Layers shows them where nothing is selected). */
67
+ private below;
68
+ private belowPreview;
66
69
  private base;
67
70
  private previewMask;
68
71
  private baseMask;
@@ -81,6 +84,8 @@ export declare class SelectAndMaskSession {
81
84
  get edits(): readonly RefineEdit[];
82
85
  /** Reads the image and makes the first preview. Resolves to false when the pixels are unavailable. */
83
86
  open(): Promise<boolean>;
87
+ /** The visible layers under the active one, composited at full size, or null when there are none. */
88
+ private layersBelow;
84
89
  subscribe(listener: () => void): () => void;
85
90
  private emit;
86
91
  /** Preview size and the scale from natural pixels to it. */
@@ -63,6 +63,9 @@ export declare class SelectAndMaskSession {
63
63
  private dragStart;
64
64
  private pixels;
65
65
  private previewPixels;
66
+ /** The layers below the active one, composited (On Layers shows them where nothing is selected). */
67
+ private below;
68
+ private belowPreview;
66
69
  private base;
67
70
  private previewMask;
68
71
  private baseMask;
@@ -81,6 +84,8 @@ export declare class SelectAndMaskSession {
81
84
  get edits(): readonly RefineEdit[];
82
85
  /** Reads the image and makes the first preview. Resolves to false when the pixels are unavailable. */
83
86
  open(): Promise<boolean>;
87
+ /** The visible layers under the active one, composited at full size, or null when there are none. */
88
+ private layersBelow;
84
89
  subscribe(listener: () => void): () => void;
85
90
  private emit;
86
91
  /** Preview size and the scale from natural pixels to it. */
@@ -1,3 +1,4 @@
1
+ import type { DocumentPath, SerializedDocumentPath } from './paths.cjs';
1
2
  import type { SelectionWorkerFactory } from './selection/worker.cjs';
2
3
  import type { GlobalLight } from '../raster/effects/model.cjs';
3
4
  import type { EffectPattern } from '../raster/effects/patterns.cjs';
@@ -311,6 +312,11 @@ export interface ImageEditorState {
311
312
  * selected. Recorded in undo history and saved as `selection` in `toJSON()`.
312
313
  */
313
314
  selection?: SelectionMask | null;
315
+ /**
316
+ * A selection shown in place of `selection` while a gesture is in progress (Quick Selection
317
+ * growing as the brush moves). View state: not an edit, not in history, not saved.
318
+ */
319
+ selectionPreview?: SelectionMask | null;
314
320
  /** Quick Mask view: tint the unselected area instead of drawing marching ants (view state). */
315
321
  quickMask?: boolean;
316
322
  /** How the canvas shows the selection (view state; `quickMask` mirrors `'quickMask'`). */
@@ -330,6 +336,10 @@ export interface ImageEditorState {
330
336
  quickMaskEditing?: boolean;
331
337
  /** Alpha channels: saved selections kept with the document, recorded in undo history. */
332
338
  channels?: AlphaChannel[];
339
+ /** Document paths (the Paths panel): the Work Path and saved paths. Recorded in undo history and saved. */
340
+ paths?: DocumentPath[];
341
+ /** The path selected in the Paths panel (view state). */
342
+ activePathId?: string | null;
333
343
  /**
334
344
  * The layer stack, bottom to top. Opening an image gives one pixel layer, "Background", whose
335
345
  * pixels are the source image. Layers are immutable: compare them by identity.
@@ -399,6 +409,8 @@ export interface LegacySerializedImageEditorState {
399
409
  selection?: SerializedSelection;
400
410
  /** Alpha channels (saved selections), run-length encoded. */
401
411
  channels?: SerializedAlphaChannel[];
412
+ /** Document paths (the Paths panel). */
413
+ paths?: SerializedDocumentPath[];
402
414
  }
403
415
  /**
404
416
  * A stored editor state: the document-level schema (v1 / v2) or the layered schema (v3, see
@@ -1,3 +1,4 @@
1
+ import type { DocumentPath, SerializedDocumentPath } from './paths.js';
1
2
  import type { SelectionWorkerFactory } from './selection/worker.js';
2
3
  import type { GlobalLight } from '../raster/effects/model.js';
3
4
  import type { EffectPattern } from '../raster/effects/patterns.js';
@@ -311,6 +312,11 @@ export interface ImageEditorState {
311
312
  * selected. Recorded in undo history and saved as `selection` in `toJSON()`.
312
313
  */
313
314
  selection?: SelectionMask | null;
315
+ /**
316
+ * A selection shown in place of `selection` while a gesture is in progress (Quick Selection
317
+ * growing as the brush moves). View state: not an edit, not in history, not saved.
318
+ */
319
+ selectionPreview?: SelectionMask | null;
314
320
  /** Quick Mask view: tint the unselected area instead of drawing marching ants (view state). */
315
321
  quickMask?: boolean;
316
322
  /** How the canvas shows the selection (view state; `quickMask` mirrors `'quickMask'`). */
@@ -330,6 +336,10 @@ export interface ImageEditorState {
330
336
  quickMaskEditing?: boolean;
331
337
  /** Alpha channels: saved selections kept with the document, recorded in undo history. */
332
338
  channels?: AlphaChannel[];
339
+ /** Document paths (the Paths panel): the Work Path and saved paths. Recorded in undo history and saved. */
340
+ paths?: DocumentPath[];
341
+ /** The path selected in the Paths panel (view state). */
342
+ activePathId?: string | null;
333
343
  /**
334
344
  * The layer stack, bottom to top. Opening an image gives one pixel layer, "Background", whose
335
345
  * pixels are the source image. Layers are immutable: compare them by identity.
@@ -399,6 +409,8 @@ export interface LegacySerializedImageEditorState {
399
409
  selection?: SerializedSelection;
400
410
  /** Alpha channels (saved selections), run-length encoded. */
401
411
  channels?: SerializedAlphaChannel[];
412
+ /** Document paths (the Paths panel). */
413
+ paths?: SerializedDocumentPath[];
402
414
  }
403
415
  /**
404
416
  * A stored editor state: the document-level schema (v1 / v2) or the layered schema (v3, see
@@ -7,7 +7,7 @@ var _chunkZ64NRDEHcjs = require('../chunk-Z64NRDEH.cjs');
7
7
 
8
8
 
9
9
 
10
- var _chunkQE7D7TZRcjs = require('../chunk-QE7D7TZR.cjs');
10
+ var _chunkH65IBXFIcjs = require('../chunk-H65IBXFI.cjs');
11
11
  require('../chunk-A2IS7EHE.cjs');
12
12
  require('../chunk-QYLWG22N.cjs');
13
13
 
@@ -1657,11 +1657,11 @@ function header(state, options) {
1657
1657
  return out;
1658
1658
  }
1659
1659
  function serializePaintDocument(state, options = {}) {
1660
- const { layers, assets } = _chunkQE7D7TZRcjs.serializeLayers.call(void 0, state.layers);
1660
+ const { layers, assets } = _chunkH65IBXFIcjs.serializeLayers.call(void 0, state.layers);
1661
1661
  return { ...header(state, options), layers, assets };
1662
1662
  }
1663
1663
  async function serializePaintDocumentExternal(state, store, options = {}) {
1664
- const { layers, assets } = await _chunkQE7D7TZRcjs.serializeLayersExternal.call(void 0, state.layers, store);
1664
+ const { layers, assets } = await _chunkH65IBXFIcjs.serializeLayersExternal.call(void 0, state.layers, store);
1665
1665
  return { ...header(state, options), layers, assets };
1666
1666
  }
1667
1667
  function paintLayersOnly(layers, problems) {
@@ -1698,7 +1698,7 @@ function deserializePaintDocument(raw) {
1698
1698
  const canvas = normalizeCanvas({ width: r.width, height: r.height, dpi: _nullishCoalesce(r.dpi, () => ( void 0)) });
1699
1699
  const paper = _chunkROVK6AXXcjs.normalizePaper.call(void 0, _nullishCoalesce(r.paper, () => ( {})));
1700
1700
  const assets = r.assets && typeof r.assets === "object" ? r.assets : {};
1701
- const layers = paintLayersOnly(_chunkQE7D7TZRcjs.deserializeLayers.call(void 0, r.layers, { assets, problems }), problems);
1701
+ const layers = paintLayersOnly(_chunkH65IBXFIcjs.deserializeLayers.call(void 0, r.layers, { assets, problems }), problems);
1702
1702
  const wanted = typeof r.activeLayerId === "string" ? r.activeLayerId : null;
1703
1703
  const activeLayerId = wanted && _chunkUOGKSVRQcjs.findLayer.call(void 0, layers, wanted) ? wanted : _nullishCoalesce(_optionalChain([_chunkUOGKSVRQcjs.flattenLayers.call(void 0, layers), 'access', _70 => _70.filter, 'call', _71 => _71((l) => l.type === "pixel"), 'access', _72 => _72.pop, 'call', _73 => _73(), 'optionalAccess', _74 => _74.id]), () => ( null));
1704
1704
  const wetEvents = Array.isArray(r.wetEvents) ? r.wetEvents.filter((e) => e && typeof e === "object" && Number.isInteger(e.clock) && typeof e.kind === "string") : [];
@@ -1714,7 +1714,7 @@ async function deserializePaintDocumentAsync(raw, store) {
1714
1714
  if (!raw || typeof raw !== "object") throw new Error("Not a paint document: expected a JSON object.");
1715
1715
  const r = raw;
1716
1716
  const problems = [];
1717
- const assets = await _chunkQE7D7TZRcjs.resolveExternalAssets.call(void 0, _nullishCoalesce(r.assets, () => ( {})), store, problems);
1717
+ const assets = await _chunkH65IBXFIcjs.resolveExternalAssets.call(void 0, _nullishCoalesce(r.assets, () => ( {})), store, problems);
1718
1718
  const loaded = deserializePaintDocument({ ...r, assets });
1719
1719
  return { ...loaded, problems: [...problems, ...loaded.problems] };
1720
1720
  }
@@ -5413,7 +5413,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5413
5413
  return next.type === "group" ? { ...next, children: toStandard(next.children) } : next;
5414
5414
  });
5415
5415
  const layers = toStandard(dried);
5416
- const result = _chunkQE7D7TZRcjs.exportPsd.call(void 0, { width, height, layers: [paperLayer, ...layers], merged, resolution: dpi });
5416
+ const result = _chunkH65IBXFIcjs.exportPsd.call(void 0, { width, height, layers: [paperLayer, ...layers], merged, resolution: dpi });
5417
5417
  for (const [mode, names] of changed) {
5418
5418
  const label = _nullishCoalesce(_optionalChain([_chunkOLNIPTB3cjs.BLEND_MODES, 'access', _271 => _271.find, 'call', _272 => _272((m) => m.id === mode), 'optionalAccess', _273 => _273.label]), () => ( mode));
5419
5419
  const std = _nullishCoalesce(_optionalChain([_chunkOLNIPTB3cjs.BLEND_MODES, 'access', _274 => _274.find, 'call', _275 => _275((m) => m.id === _chunkOLNIPTB3cjs.standardBlendMode.call(void 0, mode)), 'optionalAccess', _276 => _276.label]), () => ( _chunkOLNIPTB3cjs.standardBlendMode.call(void 0, mode)));
@@ -7,7 +7,7 @@ import {
7
7
  resolveExternalAssets,
8
8
  serializeLayers,
9
9
  serializeLayersExternal
10
- } from "../chunk-KFIOEOCQ.js";
10
+ } from "../chunk-W3TOZTL7.js";
11
11
  import "../chunk-3CI7FRMK.js";
12
12
  import "../chunk-L3G23N5Y.js";
13
13
  import {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixerate/editor",
3
- "version": "0.210.0",
3
+ "version": "0.212.0",
4
4
  "description": "UI-agnostic rich text and media editing core library",
5
5
  "author": "Pixerate",
6
6
  "license": "MIT",
@@ -384,7 +384,7 @@ in the source frame at the document's bit depth, colour mode and profile. Read
384
384
  | `apply_selection_as_mask` | Mask a layer with the current selection: pass `layerId` to mask an existing layer, or `kind` (plus optional `params`) to create a new masked layer in one step. `density` 0..1 and `feather` px soften the mask non-destructively. Returns `layerId`, kind, mask info and the selection summary. |
385
385
  | `stroke_selection` | Edit › Stroke: a band `width` px (≤ 250) `outside` (default), `inside` or `center` on the selection edge, with `color`, `opacity`, `blend`, on a layer's pixels or mask (`channel`). One undo step. Returns the changed `bounds`. |
386
386
  | `crop_to_selection` | Set the crop box to the selection's bounds (non-destructive; `reset_crop` undoes it). Returns the `crop`. |
387
- | `content_aware_fill` | Remove what is selected by synthesising texture from around it on a pixel layer; `output` `new-layer` (keeps the fill separate, recommended) or `current`; `sampleRadius`, `seed` (another seed, another fill); the sampling area with `sampleRects`, `samplingChannelId` and `excludeRects` (never copy from these). Select with a 2–4 px margin. 8-bit only. Returns `layerId` and `bounds`. |
387
+ | `content_aware_fill` | Remove what is selected by synthesising texture from around it on a pixel layer; `output` `new-layer` (keeps the fill separate, recommended), `current` or `duplicate-layer` (a filled copy); `sampleRadius`, `seed` (another seed, another fill); the sampling area with `sampleRects`, `samplingChannelId` and `excludeRects` (never copy from these). Select with a 2–4 px margin. 8-bit only. Returns `layerId` and `bounds`. |
388
388
  | `copy_pixels` | Copy the selected pixels of a layer (or with `merged` the visible image) to the editor clipboard, cropped to the selection with its soft edge. No undo step. Returns `width`, `height`, `x`, `y`. |
389
389
  | `cut_pixels` | Copy, then clear the selected pixels (one undo step). Returns the size and position. |
390
390
  | `paste_pixels` | Paste the clipboard as a new layer: `mode` `new-layer` (centred on the selection or canvas), `in-place`, `into` (masked by the selection) or `outside` (masked by its inverse). One undo step. Returns `layerId`, `bounds`, `masked`. |