@pixerate/editor 0.183.0 → 0.185.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 (32) hide show
  1. package/dist/{chunk-UHMSMUHK.cjs → chunk-C6TRAAG4.cjs} +3 -1
  2. package/dist/{chunk-Y46OMERN.js → chunk-GYYSPMVU.js} +3 -1
  3. package/dist/image-editor/controller.d.cts +152 -8
  4. package/dist/image-editor/controller.d.ts +152 -8
  5. package/dist/image-editor/index.cjs +1986 -832
  6. package/dist/image-editor/index.js +1209 -55
  7. package/dist/image-editor/layers/panel.d.cts +23 -1
  8. package/dist/image-editor/layers/panel.d.ts +23 -1
  9. package/dist/image-editor/selection/gesture.d.cts +40 -2
  10. package/dist/image-editor/selection/gesture.d.ts +40 -2
  11. package/dist/image-editor/selection/index.d.cts +1 -0
  12. package/dist/image-editor/selection/index.d.ts +1 -0
  13. package/dist/image-editor/selection/modify.d.cts +3 -2
  14. package/dist/image-editor/selection/modify.d.ts +3 -2
  15. package/dist/image-editor/selection/stroke.d.cts +8 -0
  16. package/dist/image-editor/selection/stroke.d.ts +8 -0
  17. package/dist/image-editor/selection/tool-options.d.cts +12 -2
  18. package/dist/image-editor/selection/tool-options.d.ts +12 -2
  19. package/dist/image-editor/selection/wand.d.cts +37 -0
  20. package/dist/image-editor/selection/wand.d.ts +37 -0
  21. package/dist/image-editor/selection-tools.d.cts +8 -3
  22. package/dist/image-editor/selection-tools.d.ts +8 -3
  23. package/dist/image-editor/tools.d.cts +8 -2
  24. package/dist/image-editor/tools.d.ts +8 -2
  25. package/dist/image-editor/types.d.cts +2 -0
  26. package/dist/image-editor/types.d.ts +2 -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 +12 -21
  31. package/skills/pixerate-image-editor/references/free-transform.md +22 -0
  32. package/skills/pixerate-image-selection-masking/SKILL.md +23 -2
@@ -6,6 +6,28 @@
6
6
  import type { ImageEditorController } from '../controller.cjs';
7
7
  import { type ImageLayer, type SmartFilter } from './model.cjs';
8
8
  import type { LayerPlacement } from './ops.cjs';
9
+ /**
10
+ * A click on a layer's mask thumbnail, as in Photoshop: Ctrl/⌘-click loads the mask as the
11
+ * selection (with Shift adding, Alt subtracting, both intersecting), Shift-click turns the mask
12
+ * on or off, and a plain click makes the mask the paint target.
13
+ */
14
+ export declare function maskThumbnailClick(controller: ImageEditorController, layer: ImageLayer, e: {
15
+ ctrlKey?: boolean;
16
+ metaKey?: boolean;
17
+ shiftKey?: boolean;
18
+ altKey?: boolean;
19
+ }): void;
20
+ /**
21
+ * A click on a layer's pixel thumbnail: Ctrl/⌘-click loads the layer's transparency as the
22
+ * selection (Shift adds, Alt subtracts, both intersect) and returns true; other clicks are left
23
+ * to the row (false).
24
+ */
25
+ export declare function layerThumbnailClick(controller: ImageEditorController, layer: ImageLayer, e: {
26
+ ctrlKey?: boolean;
27
+ metaKey?: boolean;
28
+ shiftKey?: boolean;
29
+ altKey?: boolean;
30
+ }): boolean;
9
31
  export interface LayerPanelRow {
10
32
  layer: ImageLayer;
11
33
  /** Nesting depth (0 = top level). */
@@ -34,7 +56,7 @@ export type DropZone = 'above' | 'below' | 'inside';
34
56
  export declare function dropZone(fraction: number, isGroup: boolean): DropZone;
35
57
  /** The placement for `move_layer` when `dragId` is dropped on row `targetId` in `zone`, or `null` for a no-op. */
36
58
  export declare function dropPlacement(layers: readonly ImageLayer[], dragId: string, targetId: string, zone: DropZone): LayerPlacement | null;
37
- export type LayerMenuAction = 'new-layer' | 'new-group' | 'duplicate' | 'delete' | 'group-selected' | 'ungroup' | 'merge-down' | 'merge-visible' | 'flatten' | 'via-copy' | 'via-cut' | 'add-mask' | 'add-mask-selection' | 'apply-mask' | 'delete-mask' | 'toggle-mask' | 'toggle-mask-link' | 'toggle-clip' | 'rasterize' | 'convert-smart' | 'edit-contents' | 'smart-via-copy' | 'add-filter-mask';
59
+ export type LayerMenuAction = 'new-layer' | 'new-group' | 'duplicate' | 'delete' | 'group-selected' | 'ungroup' | 'merge-down' | 'merge-visible' | 'flatten' | 'via-copy' | 'via-cut' | 'add-mask' | 'add-mask-selection' | 'add-mask-hide-selection' | 'add-mask-transparency' | 'select-transparency' | 'apply-mask' | 'delete-mask' | 'toggle-mask' | 'toggle-mask-link' | 'toggle-clip' | 'rasterize' | 'convert-smart' | 'edit-contents' | 'smart-via-copy' | 'add-filter-mask';
38
60
  export interface LayerMenuItem {
39
61
  action: LayerMenuAction;
40
62
  label: string;
@@ -6,6 +6,28 @@
6
6
  import type { ImageEditorController } from '../controller.js';
7
7
  import { type ImageLayer, type SmartFilter } from './model.js';
8
8
  import type { LayerPlacement } from './ops.js';
9
+ /**
10
+ * A click on a layer's mask thumbnail, as in Photoshop: Ctrl/⌘-click loads the mask as the
11
+ * selection (with Shift adding, Alt subtracting, both intersecting), Shift-click turns the mask
12
+ * on or off, and a plain click makes the mask the paint target.
13
+ */
14
+ export declare function maskThumbnailClick(controller: ImageEditorController, layer: ImageLayer, e: {
15
+ ctrlKey?: boolean;
16
+ metaKey?: boolean;
17
+ shiftKey?: boolean;
18
+ altKey?: boolean;
19
+ }): void;
20
+ /**
21
+ * A click on a layer's pixel thumbnail: Ctrl/⌘-click loads the layer's transparency as the
22
+ * selection (Shift adds, Alt subtracts, both intersect) and returns true; other clicks are left
23
+ * to the row (false).
24
+ */
25
+ export declare function layerThumbnailClick(controller: ImageEditorController, layer: ImageLayer, e: {
26
+ ctrlKey?: boolean;
27
+ metaKey?: boolean;
28
+ shiftKey?: boolean;
29
+ altKey?: boolean;
30
+ }): boolean;
9
31
  export interface LayerPanelRow {
10
32
  layer: ImageLayer;
11
33
  /** Nesting depth (0 = top level). */
@@ -34,7 +56,7 @@ export type DropZone = 'above' | 'below' | 'inside';
34
56
  export declare function dropZone(fraction: number, isGroup: boolean): DropZone;
35
57
  /** The placement for `move_layer` when `dragId` is dropped on row `targetId` in `zone`, or `null` for a no-op. */
36
58
  export declare function dropPlacement(layers: readonly ImageLayer[], dragId: string, targetId: string, zone: DropZone): LayerPlacement | null;
37
- export type LayerMenuAction = 'new-layer' | 'new-group' | 'duplicate' | 'delete' | 'group-selected' | 'ungroup' | 'merge-down' | 'merge-visible' | 'flatten' | 'via-copy' | 'via-cut' | 'add-mask' | 'add-mask-selection' | 'apply-mask' | 'delete-mask' | 'toggle-mask' | 'toggle-mask-link' | 'toggle-clip' | 'rasterize' | 'convert-smart' | 'edit-contents' | 'smart-via-copy' | 'add-filter-mask';
59
+ export type LayerMenuAction = 'new-layer' | 'new-group' | 'duplicate' | 'delete' | 'group-selected' | 'ungroup' | 'merge-down' | 'merge-visible' | 'flatten' | 'via-copy' | 'via-cut' | 'add-mask' | 'add-mask-selection' | 'add-mask-hide-selection' | 'add-mask-transparency' | 'select-transparency' | 'apply-mask' | 'delete-mask' | 'toggle-mask' | 'toggle-mask-link' | 'toggle-clip' | 'rasterize' | 'convert-smart' | 'edit-contents' | 'smart-via-copy' | 'add-filter-mask';
38
60
  export interface LayerMenuItem {
39
61
  action: LayerMenuAction;
40
62
  label: string;
@@ -4,14 +4,26 @@ import { type SelectionToolOptions } from './tool-options.cjs';
4
4
  export interface GestureModifiers {
5
5
  shiftKey?: boolean;
6
6
  altKey?: boolean;
7
+ /** The click count of a mouse event (2 on a double-click). */
8
+ detail?: number;
7
9
  }
10
+ /** `point` moved onto the nearest 45° ray from `from` (Shift with the polygonal lasso). */
11
+ export declare function snapTo45(from: ImagePoint, point: ImagePoint): ImagePoint;
8
12
  /**
9
13
  * Pointer gestures of the selection tools, shared by the React and Svelte image editors: feed
10
14
  * it pointer positions in natural image pixels (`canvasToImagePoint(..., false)`).
11
15
  *
12
16
  * - Magic wand: selects on `begin` (async, as it may read pixels).
17
+ * - Color Range: on `begin`, samples the colour under the pointer and selects every similar pixel
18
+ * (with the modifiers, Shift-click adds a colour and Alt-click removes one, as the + and −
19
+ * eyedroppers).
13
20
  * - Rectangle / ellipse: drag a box; a click without a drag deselects (replace mode).
14
21
  * - Lasso: drag a free-hand path, closed on `end`.
22
+ * - Polygonal lasso: each click adds a corner (Shift: on a 45° ray from the last one), dragging
23
+ * adds a free-hand stretch; a double-click, a click on the first corner or Enter (`key`)
24
+ * closes it, Backspace removes the last corner and Escape cancels. It stays `active` between
25
+ * clicks, so feed it pointer moves without a button too.
26
+ * - Single row / column: a click selects a 1 px line across the image.
15
27
  *
16
28
  * Shift adds, Alt subtracts, both intersect (overriding the options bar mode). While dragging,
17
29
  * {@link draftPath} is the outline to show (`RenderOptions.draftSelectionPath`).
@@ -23,6 +35,12 @@ export declare class SelectionGesture {
23
35
  private points;
24
36
  private current;
25
37
  private modifiers;
38
+ /** Polygonal lasso corners while one is being drawn. */
39
+ private polygon;
40
+ private pressedAt;
41
+ private freehand;
42
+ /** A click this close to the first corner (natural pixels) closes a polygonal lasso. */
43
+ closeRadius: number;
26
44
  /** The last error (e.g. pixels unavailable for the wand), for the UI to show. */
27
45
  error: string | null;
28
46
  constructor(controller: ImageEditorController, getOptions: () => SelectionToolOptions);
@@ -32,9 +50,29 @@ export declare class SelectionGesture {
32
50
  /** Pointer down. Resolves once a wand click has been applied. */
33
51
  begin(point: ImagePoint, modifiers?: GestureModifiers): Promise<void>;
34
52
  /** Pointer move; returns true when the draft changed (re-render). */
35
- move(point: ImagePoint): boolean;
53
+ move(point: ImagePoint, modifiers?: GestureModifiers): boolean;
36
54
  /** Pointer up: commits the shape. Returns true when the selection changed. */
37
55
  end(point?: ImagePoint, modifiers?: GestureModifiers): boolean;
38
- /** Abandons a drag without changing the selection. */
56
+ /** Closes a polygonal lasso and selects it. Returns true when the selection changed. */
57
+ close(): boolean;
58
+ /**
59
+ * Keys for a polygonal lasso being drawn: Enter closes it, Escape cancels, Backspace / Delete
60
+ * removes the last corner. Returns true when the key was used (the host prevents its default).
61
+ */
62
+ key(key: string): boolean;
63
+ /** Abandons a drag (or a polygonal lasso) without changing the selection. */
39
64
  cancel(): void;
40
65
  }
66
+ /**
67
+ * Edit shortcuts in select mode, as in Photoshop: Ctrl/⌘+C copies (with Shift, Copy Merged),
68
+ * Ctrl/⌘+X cuts, Ctrl/⌘+V pastes (with Shift, in place; with Alt+Shift, into the selection),
69
+ * Ctrl/⌘+D deselects, Ctrl/⌘+Shift+D reselects and Ctrl/⌘+Shift+I inverts. Returns true when
70
+ * the key was used (the host prevents its default); errors go to `onError`.
71
+ */
72
+ export declare function handleSelectionShortcut(controller: ImageEditorController, e: {
73
+ key: string;
74
+ ctrlKey?: boolean;
75
+ metaKey?: boolean;
76
+ shiftKey?: boolean;
77
+ altKey?: boolean;
78
+ }, onError?: (message: string) => void): boolean;
@@ -4,14 +4,26 @@ import { type SelectionToolOptions } from './tool-options.js';
4
4
  export interface GestureModifiers {
5
5
  shiftKey?: boolean;
6
6
  altKey?: boolean;
7
+ /** The click count of a mouse event (2 on a double-click). */
8
+ detail?: number;
7
9
  }
10
+ /** `point` moved onto the nearest 45° ray from `from` (Shift with the polygonal lasso). */
11
+ export declare function snapTo45(from: ImagePoint, point: ImagePoint): ImagePoint;
8
12
  /**
9
13
  * Pointer gestures of the selection tools, shared by the React and Svelte image editors: feed
10
14
  * it pointer positions in natural image pixels (`canvasToImagePoint(..., false)`).
11
15
  *
12
16
  * - Magic wand: selects on `begin` (async, as it may read pixels).
17
+ * - Color Range: on `begin`, samples the colour under the pointer and selects every similar pixel
18
+ * (with the modifiers, Shift-click adds a colour and Alt-click removes one, as the + and −
19
+ * eyedroppers).
13
20
  * - Rectangle / ellipse: drag a box; a click without a drag deselects (replace mode).
14
21
  * - Lasso: drag a free-hand path, closed on `end`.
22
+ * - Polygonal lasso: each click adds a corner (Shift: on a 45° ray from the last one), dragging
23
+ * adds a free-hand stretch; a double-click, a click on the first corner or Enter (`key`)
24
+ * closes it, Backspace removes the last corner and Escape cancels. It stays `active` between
25
+ * clicks, so feed it pointer moves without a button too.
26
+ * - Single row / column: a click selects a 1 px line across the image.
15
27
  *
16
28
  * Shift adds, Alt subtracts, both intersect (overriding the options bar mode). While dragging,
17
29
  * {@link draftPath} is the outline to show (`RenderOptions.draftSelectionPath`).
@@ -23,6 +35,12 @@ export declare class SelectionGesture {
23
35
  private points;
24
36
  private current;
25
37
  private modifiers;
38
+ /** Polygonal lasso corners while one is being drawn. */
39
+ private polygon;
40
+ private pressedAt;
41
+ private freehand;
42
+ /** A click this close to the first corner (natural pixels) closes a polygonal lasso. */
43
+ closeRadius: number;
26
44
  /** The last error (e.g. pixels unavailable for the wand), for the UI to show. */
27
45
  error: string | null;
28
46
  constructor(controller: ImageEditorController, getOptions: () => SelectionToolOptions);
@@ -32,9 +50,29 @@ export declare class SelectionGesture {
32
50
  /** Pointer down. Resolves once a wand click has been applied. */
33
51
  begin(point: ImagePoint, modifiers?: GestureModifiers): Promise<void>;
34
52
  /** Pointer move; returns true when the draft changed (re-render). */
35
- move(point: ImagePoint): boolean;
53
+ move(point: ImagePoint, modifiers?: GestureModifiers): boolean;
36
54
  /** Pointer up: commits the shape. Returns true when the selection changed. */
37
55
  end(point?: ImagePoint, modifiers?: GestureModifiers): boolean;
38
- /** Abandons a drag without changing the selection. */
56
+ /** Closes a polygonal lasso and selects it. Returns true when the selection changed. */
57
+ close(): boolean;
58
+ /**
59
+ * Keys for a polygonal lasso being drawn: Enter closes it, Escape cancels, Backspace / Delete
60
+ * removes the last corner. Returns true when the key was used (the host prevents its default).
61
+ */
62
+ key(key: string): boolean;
63
+ /** Abandons a drag (or a polygonal lasso) without changing the selection. */
39
64
  cancel(): void;
40
65
  }
66
+ /**
67
+ * Edit shortcuts in select mode, as in Photoshop: Ctrl/⌘+C copies (with Shift, Copy Merged),
68
+ * Ctrl/⌘+X cuts, Ctrl/⌘+V pastes (with Shift, in place; with Alt+Shift, into the selection),
69
+ * Ctrl/⌘+D deselects, Ctrl/⌘+Shift+D reselects and Ctrl/⌘+Shift+I inverts. Returns true when
70
+ * the key was used (the host prevents its default); errors go to `onError`.
71
+ */
72
+ export declare function handleSelectionShortcut(controller: ImageEditorController, e: {
73
+ key: string;
74
+ ctrlKey?: boolean;
75
+ metaKey?: boolean;
76
+ shiftKey?: boolean;
77
+ altKey?: boolean;
78
+ }, onError?: (message: string) => void): boolean;
@@ -8,3 +8,4 @@ export * from './overlay.cjs';
8
8
  export * from './tool-options.cjs';
9
9
  export * from './gesture.cjs';
10
10
  export * from './segmentation.cjs';
11
+ export * from './stroke.cjs';
@@ -8,3 +8,4 @@ export * from './overlay.js';
8
8
  export * from './tool-options.js';
9
9
  export * from './gesture.js';
10
10
  export * from './segmentation.js';
11
+ export * from './stroke.js';
@@ -31,7 +31,8 @@ export declare function greyMorphology(src: ArrayLike<number>, w: number, h: num
31
31
  * use one morphology, the remainder blends with the next pixel, so 0.3 px differs from 1 px.
32
32
  */
33
33
  export declare function shiftCoverage(src: ArrayLike<number>, w: number, h: number, amount: number): Float32Array;
34
- export type SelectionModifyOp = 'grow' | 'shrink' | 'feather' | 'border' | 'smooth';
34
+ /** `expand` / `contract` are Photoshop's names; `grow` / `shrink` are the same operations, kept as aliases. */
35
+ export type SelectionModifyOp = 'expand' | 'contract' | 'grow' | 'shrink' | 'feather' | 'border' | 'smooth';
35
36
  export declare const SELECTION_MODIFY_OPS: readonly SelectionModifyOp[];
36
- /** Select › Modify (grow = Expand, shrink = Contract, feather, border, smooth) by `radius` pixels. */
37
+ /** Select › Modify (expand, contract, feather, border, smooth; grow and shrink are aliases) by `radius` pixels. */
37
38
  export declare function modifySelection(mask: SelectionMask, op: SelectionModifyOp, radius: number): SelectionMask;
@@ -31,7 +31,8 @@ export declare function greyMorphology(src: ArrayLike<number>, w: number, h: num
31
31
  * use one morphology, the remainder blends with the next pixel, so 0.3 px differs from 1 px.
32
32
  */
33
33
  export declare function shiftCoverage(src: ArrayLike<number>, w: number, h: number, amount: number): Float32Array;
34
- export type SelectionModifyOp = 'grow' | 'shrink' | 'feather' | 'border' | 'smooth';
34
+ /** `expand` / `contract` are Photoshop's names; `grow` / `shrink` are the same operations, kept as aliases. */
35
+ export type SelectionModifyOp = 'expand' | 'contract' | 'grow' | 'shrink' | 'feather' | 'border' | 'smooth';
35
36
  export declare const SELECTION_MODIFY_OPS: readonly SelectionModifyOp[];
36
- /** Select › Modify (grow = Expand, shrink = Contract, feather, border, smooth) by `radius` pixels. */
37
+ /** Select › Modify (expand, contract, feather, border, smooth; grow and shrink are aliases) by `radius` pixels. */
37
38
  export declare function modifySelection(mask: SelectionMask, op: SelectionModifyOp, radius: number): SelectionMask;
@@ -0,0 +1,8 @@
1
+ import { type SelectionMask } from './mask.cjs';
2
+ /**
3
+ * The band Edit › Stroke paints along a selection's edge, `width` pixels wide: `inside` is the
4
+ * selection minus the selection contracted by `width`, `outside` the selection expanded by
5
+ * `width` minus the selection, and `center` straddles the edge by `width / 2` each way. Built
6
+ * from the exact distance transform the Modify commands use, so the band keeps soft edges.
7
+ */
8
+ export declare function selectionRing(sel: SelectionMask, width: number, location: 'inside' | 'center' | 'outside'): SelectionMask;
@@ -0,0 +1,8 @@
1
+ import { type SelectionMask } from './mask.js';
2
+ /**
3
+ * The band Edit › Stroke paints along a selection's edge, `width` pixels wide: `inside` is the
4
+ * selection minus the selection contracted by `width`, `outside` the selection expanded by
5
+ * `width` minus the selection, and `center` straddles the edge by `width / 2` each way. Built
6
+ * from the exact distance transform the Modify commands use, so the band keeps soft edges.
7
+ */
8
+ export declare function selectionRing(sel: SelectionMask, width: number, location: 'inside' | 'center' | 'outside'): SelectionMask;
@@ -1,12 +1,14 @@
1
1
  import type { SelectionMask, SelectionMode } from './mask.cjs';
2
- import type { ColorDistance } from './wand.cjs';
2
+ import type { ColorDistance, ColorRangePreset } from './wand.cjs';
3
3
  import type { RefineEdgeParams } from './refine.cjs';
4
4
  /** Selection tools of the image editor UI. */
5
- export type SelectionToolKind = 'wand' | 'rect' | 'ellipse' | 'lasso';
5
+ export type SelectionToolKind = 'wand' | 'rect' | 'ellipse' | 'row' | 'column' | 'lasso' | 'polygon' | 'range';
6
6
  export declare const SELECTION_TOOLS: readonly {
7
7
  id: SelectionToolKind;
8
8
  label: string;
9
9
  }[];
10
+ /** Labels of the Color Range presets, in menu order. */
11
+ export declare const COLOR_RANGE_PRESET_LABELS: Record<ColorRangePreset, string>;
10
12
  export declare const SELECTION_MODE_LABELS: Record<SelectionMode, string>;
11
13
  /** The options bar of the selection tools (shared by the React and Svelte UIs). */
12
14
  export interface SelectionToolOptions {
@@ -21,6 +23,14 @@ export interface SelectionToolOptions {
21
23
  /** Sample the whole image (`composite`, default) or only the active pixel layer. */
22
24
  sample?: 'composite' | 'active-layer';
23
25
  distance: ColorDistance;
26
+ /** Feather new marquee, lasso, wand and Color Range selections by this many pixels (default 0). */
27
+ feather?: number;
28
+ /** Color Range: levels over which a sampled colour's coverage fades out (0..200, default 40). */
29
+ fuzziness?: number;
30
+ /** Color Range: limit each click to this radius in pixels (Localized Color Clusters; 0 = off). */
31
+ localized?: number;
32
+ /** Color Range: select everything except the sampled colours. */
33
+ rangeInvert?: boolean;
24
34
  }
25
35
  export declare const DEFAULT_SELECTION_TOOL_OPTIONS: SelectionToolOptions;
26
36
  /**
@@ -1,12 +1,14 @@
1
1
  import type { SelectionMask, SelectionMode } from './mask.js';
2
- import type { ColorDistance } from './wand.js';
2
+ import type { ColorDistance, ColorRangePreset } from './wand.js';
3
3
  import type { RefineEdgeParams } from './refine.js';
4
4
  /** Selection tools of the image editor UI. */
5
- export type SelectionToolKind = 'wand' | 'rect' | 'ellipse' | 'lasso';
5
+ export type SelectionToolKind = 'wand' | 'rect' | 'ellipse' | 'row' | 'column' | 'lasso' | 'polygon' | 'range';
6
6
  export declare const SELECTION_TOOLS: readonly {
7
7
  id: SelectionToolKind;
8
8
  label: string;
9
9
  }[];
10
+ /** Labels of the Color Range presets, in menu order. */
11
+ export declare const COLOR_RANGE_PRESET_LABELS: Record<ColorRangePreset, string>;
10
12
  export declare const SELECTION_MODE_LABELS: Record<SelectionMode, string>;
11
13
  /** The options bar of the selection tools (shared by the React and Svelte UIs). */
12
14
  export interface SelectionToolOptions {
@@ -21,6 +23,14 @@ export interface SelectionToolOptions {
21
23
  /** Sample the whole image (`composite`, default) or only the active pixel layer. */
22
24
  sample?: 'composite' | 'active-layer';
23
25
  distance: ColorDistance;
26
+ /** Feather new marquee, lasso, wand and Color Range selections by this many pixels (default 0). */
27
+ feather?: number;
28
+ /** Color Range: levels over which a sampled colour's coverage fades out (0..200, default 40). */
29
+ fuzziness?: number;
30
+ /** Color Range: limit each click to this radius in pixels (Localized Color Clusters; 0 = off). */
31
+ localized?: number;
32
+ /** Color Range: select everything except the sampled colours. */
33
+ rangeInvert?: boolean;
24
34
  }
25
35
  export declare const DEFAULT_SELECTION_TOOL_OPTIONS: SelectionToolOptions;
26
36
  /**
@@ -56,3 +56,40 @@ export declare function toneRange(pixels: PixelBuffer, range: ToneRangePreset |
56
56
  * the centre, none 60° away) × chroma × (2 − max), so neutrals are never selected.
57
57
  */
58
58
  export declare function hueRange(pixels: PixelBuffer, center: number): SelectionMask;
59
+ /** Hue centres (degrees) of the Color Range colour presets. */
60
+ export declare const HUE_RANGE_PRESETS: {
61
+ readonly reds: 0;
62
+ readonly yellows: 60;
63
+ readonly greens: 120;
64
+ readonly cyans: 180;
65
+ readonly blues: 240;
66
+ readonly magentas: 300;
67
+ };
68
+ /** Select › Color Range › Select menu: colours, tones and skin tones. */
69
+ export type ColorRangePreset = keyof typeof HUE_RANGE_PRESETS | ToneRangePreset | 'skinTones';
70
+ export declare const COLOR_RANGE_PRESETS: readonly ColorRangePreset[];
71
+ export declare function isColorRangePreset(v: unknown): v is ColorRangePreset;
72
+ /**
73
+ * Select › Color Range › Skin Tones: a heuristic over hue (full at 5–40°, none by 60° and −20°),
74
+ * HSV saturation (0.12–0.8) and value (above 0.3), so it covers light to dark skin and leaves
75
+ * out neutrals and saturated oranges. It also picks up skin-like wood, sand and leather.
76
+ */
77
+ export declare function skinToneRange(pixels: PixelBuffer): SelectionMask;
78
+ /**
79
+ * A Color Range preset: `reds` … `magentas` (`hueRange`), `highlights` / `midtones` / `shadows`
80
+ * (`toneRange`, with `falloff` levels, default 20) or `skinTones` (`skinToneRange`).
81
+ */
82
+ export declare function colorRangePreset(pixels: PixelBuffer, preset: ColorRangePreset, options?: {
83
+ falloff?: number;
84
+ }): SelectionMask;
85
+ export interface GrowSimilarOptions {
86
+ /** 0..255, the largest per-channel difference from a selected colour (default 32, as the wand). */
87
+ tolerance?: number;
88
+ }
89
+ /**
90
+ * Select › Grow: adds the pixels connected (4-neighbours) to the selection whose colour is
91
+ * within `tolerance` of a selected colour. Unlike Expand, it follows colour, not distance.
92
+ */
93
+ export declare function growSelection(pixels: PixelBuffer, sel: SelectionMask, options?: GrowSimilarOptions): SelectionMask;
94
+ /** Select › Similar: adds every pixel in the image whose colour is within `tolerance` of a selected colour. */
95
+ export declare function selectSimilar(pixels: PixelBuffer, sel: SelectionMask, options?: GrowSimilarOptions): SelectionMask;
@@ -56,3 +56,40 @@ export declare function toneRange(pixels: PixelBuffer, range: ToneRangePreset |
56
56
  * the centre, none 60° away) × chroma × (2 − max), so neutrals are never selected.
57
57
  */
58
58
  export declare function hueRange(pixels: PixelBuffer, center: number): SelectionMask;
59
+ /** Hue centres (degrees) of the Color Range colour presets. */
60
+ export declare const HUE_RANGE_PRESETS: {
61
+ readonly reds: 0;
62
+ readonly yellows: 60;
63
+ readonly greens: 120;
64
+ readonly cyans: 180;
65
+ readonly blues: 240;
66
+ readonly magentas: 300;
67
+ };
68
+ /** Select › Color Range › Select menu: colours, tones and skin tones. */
69
+ export type ColorRangePreset = keyof typeof HUE_RANGE_PRESETS | ToneRangePreset | 'skinTones';
70
+ export declare const COLOR_RANGE_PRESETS: readonly ColorRangePreset[];
71
+ export declare function isColorRangePreset(v: unknown): v is ColorRangePreset;
72
+ /**
73
+ * Select › Color Range › Skin Tones: a heuristic over hue (full at 5–40°, none by 60° and −20°),
74
+ * HSV saturation (0.12–0.8) and value (above 0.3), so it covers light to dark skin and leaves
75
+ * out neutrals and saturated oranges. It also picks up skin-like wood, sand and leather.
76
+ */
77
+ export declare function skinToneRange(pixels: PixelBuffer): SelectionMask;
78
+ /**
79
+ * A Color Range preset: `reds` … `magentas` (`hueRange`), `highlights` / `midtones` / `shadows`
80
+ * (`toneRange`, with `falloff` levels, default 20) or `skinTones` (`skinToneRange`).
81
+ */
82
+ export declare function colorRangePreset(pixels: PixelBuffer, preset: ColorRangePreset, options?: {
83
+ falloff?: number;
84
+ }): SelectionMask;
85
+ export interface GrowSimilarOptions {
86
+ /** 0..255, the largest per-channel difference from a selected colour (default 32, as the wand). */
87
+ tolerance?: number;
88
+ }
89
+ /**
90
+ * Select › Grow: adds the pixels connected (4-neighbours) to the selection whose colour is
91
+ * within `tolerance` of a selected colour. Unlike Expand, it follows colour, not distance.
92
+ */
93
+ export declare function growSelection(pixels: PixelBuffer, sel: SelectionMask, options?: GrowSimilarOptions): SelectionMask;
94
+ /** Select › Similar: adds every pixel in the image whose colour is within `tolerance` of a selected colour. */
95
+ export declare function selectSimilar(pixels: PixelBuffer, sel: SelectionMask, options?: GrowSimilarOptions): SelectionMask;
@@ -1,9 +1,14 @@
1
1
  import type { AgentTool, AgentToolProvider } from '../tools/registry.cjs';
2
2
  import type { ImageEditorController } from './controller.cjs';
3
3
  /**
4
- * Agent tools for selections and masks (part of `createImageEditorToolProvider`):
5
- * `get_selection`, `select_region`, `select_by_color`, `modify_selection`, `refine_selection`
6
- * and `apply_selection_as_mask`. Coordinates are natural pixels of the source image.
4
+ * Agent tools for selections and masks (part of `createImageEditorToolProvider`): reading
5
+ * (`get_selection`), selecting (`select_all`, `deselect`, `invert_selection`, `select_rect`,
6
+ * `select_ellipse`, `select_polygon`, `select_line`, `magic_wand`, `select_color_range`,
7
+ * `grow_selection`, `select_similar`, `reselect`), loading (`load_selection_from_image`,
8
+ * `load_selection_from_mask`, `select_layer_transparency`), the view
9
+ * (`set_selection_display`), editing (`modify_selection`, `refine_selection`) and masking
10
+ * (`apply_selection_as_mask`). `select_region` and `select_by_color` are deprecated aliases.
11
+ * Coordinates are natural pixels of the source image.
7
12
  */
8
13
  export declare function createImageSelectionTools(controller: ImageEditorController): AgentTool[];
9
14
  /** Options for `createImageSegmentationToolProvider`. */
@@ -1,9 +1,14 @@
1
1
  import type { AgentTool, AgentToolProvider } from '../tools/registry.js';
2
2
  import type { ImageEditorController } from './controller.js';
3
3
  /**
4
- * Agent tools for selections and masks (part of `createImageEditorToolProvider`):
5
- * `get_selection`, `select_region`, `select_by_color`, `modify_selection`, `refine_selection`
6
- * and `apply_selection_as_mask`. Coordinates are natural pixels of the source image.
4
+ * Agent tools for selections and masks (part of `createImageEditorToolProvider`): reading
5
+ * (`get_selection`), selecting (`select_all`, `deselect`, `invert_selection`, `select_rect`,
6
+ * `select_ellipse`, `select_polygon`, `select_line`, `magic_wand`, `select_color_range`,
7
+ * `grow_selection`, `select_similar`, `reselect`), loading (`load_selection_from_image`,
8
+ * `load_selection_from_mask`, `select_layer_transparency`), the view
9
+ * (`set_selection_display`), editing (`modify_selection`, `refine_selection`) and masking
10
+ * (`apply_selection_as_mask`). `select_region` and `select_by_color` are deprecated aliases.
11
+ * Coordinates are natural pixels of the source image.
7
12
  */
8
13
  export declare function createImageSelectionTools(controller: ImageEditorController): AgentTool[];
9
14
  /** Options for `createImageSegmentationToolProvider`. */
@@ -23,8 +23,14 @@ export interface ImageEditorToolProviderOptions {
23
23
  * - `render_preview {maxSide}`: the rendered image as a PNG, longest side at most `maxSide`.
24
24
  * - `capture_view {region, rect?, ...}`: a screenshot of the whole image, the selection or a rect in
25
25
  * natural pixels (up to 8× for close inspection), optionally with the selection shaded.
26
- * - Selections and masks: `get_selection`, `select_region`, `select_by_color`, `modify_selection`,
27
- * `refine_selection`, `apply_selection_as_mask` (see `createImageSelectionTools`).
26
+ * - Selections and masks: `get_selection`, `select_all`, `deselect`, `invert_selection`,
27
+ * `select_rect`, `select_ellipse`, `select_polygon`, `select_line`, `magic_wand`,
28
+ * `select_color_range`, `grow_selection`, `select_similar`, `reselect`,
29
+ * `select_layer_transparency`, `stroke_selection`, `crop_to_selection`, `content_aware_fill`,
30
+ * `copy_pixels`, `cut_pixels`, `paste_pixels`,
31
+ * `load_selection_from_image`, `load_selection_from_mask`, `set_selection_display`,
32
+ * `modify_selection`, `refine_selection`, `apply_selection_as_mask` and the deprecated
33
+ * `select_region` / `select_by_color` (see `createImageSelectionTools`).
28
34
  * - Layers, geometry and history: `get_image_info`, `get_histogram`, `update_adjustment_layer`,
29
35
  * `remove_adjustment_layer`, `move_adjustment_layer`, `set_crop`, `reset_crop`, `set_rotation`,
30
36
  * `flip_image`, `undo_image`, `redo_image` (see `createImageEditTools`).
@@ -23,8 +23,14 @@ export interface ImageEditorToolProviderOptions {
23
23
  * - `render_preview {maxSide}`: the rendered image as a PNG, longest side at most `maxSide`.
24
24
  * - `capture_view {region, rect?, ...}`: a screenshot of the whole image, the selection or a rect in
25
25
  * natural pixels (up to 8× for close inspection), optionally with the selection shaded.
26
- * - Selections and masks: `get_selection`, `select_region`, `select_by_color`, `modify_selection`,
27
- * `refine_selection`, `apply_selection_as_mask` (see `createImageSelectionTools`).
26
+ * - Selections and masks: `get_selection`, `select_all`, `deselect`, `invert_selection`,
27
+ * `select_rect`, `select_ellipse`, `select_polygon`, `select_line`, `magic_wand`,
28
+ * `select_color_range`, `grow_selection`, `select_similar`, `reselect`,
29
+ * `select_layer_transparency`, `stroke_selection`, `crop_to_selection`, `content_aware_fill`,
30
+ * `copy_pixels`, `cut_pixels`, `paste_pixels`,
31
+ * `load_selection_from_image`, `load_selection_from_mask`, `set_selection_display`,
32
+ * `modify_selection`, `refine_selection`, `apply_selection_as_mask` and the deprecated
33
+ * `select_region` / `select_by_color` (see `createImageSelectionTools`).
28
34
  * - Layers, geometry and history: `get_image_info`, `get_histogram`, `update_adjustment_layer`,
29
35
  * `remove_adjustment_layer`, `move_adjustment_layer`, `set_crop`, `reset_crop`, `set_rotation`,
30
36
  * `flip_image`, `undo_image`, `redo_image` (see `createImageEditTools`).
@@ -311,6 +311,8 @@ export interface ImageEditorState {
311
311
  selection?: SelectionMask | null;
312
312
  /** Quick Mask view: tint the unselected area instead of drawing marching ants (view state). */
313
313
  quickMask?: boolean;
314
+ /** How the canvas shows the selection (view state; `quickMask` mirrors `'quickMask'`). */
315
+ selectionDisplay?: 'ants' | 'quickMask' | 'none';
314
316
  /**
315
317
  * The layer stack, bottom to top. Opening an image gives one pixel layer, "Background", whose
316
318
  * pixels are the source image. Layers are immutable: compare them by identity.
@@ -311,6 +311,8 @@ export interface ImageEditorState {
311
311
  selection?: SelectionMask | null;
312
312
  /** Quick Mask view: tint the unselected area instead of drawing marching ants (view state). */
313
313
  quickMask?: boolean;
314
+ /** How the canvas shows the selection (view state; `quickMask` mirrors `'quickMask'`). */
315
+ selectionDisplay?: 'ants' | 'quickMask' | 'none';
314
316
  /**
315
317
  * The layer stack, bottom to top. Opening an image gives one pixel layer, "Background", whose
316
318
  * pixels are the source image. Layers are immutable: compare them by identity.
@@ -7,7 +7,7 @@ var _chunkZ64NRDEHcjs = require('../chunk-Z64NRDEH.cjs');
7
7
 
8
8
 
9
9
 
10
- var _chunkUHMSMUHKcjs = require('../chunk-UHMSMUHK.cjs');
10
+ var _chunkC6TRAAG4cjs = require('../chunk-C6TRAAG4.cjs');
11
11
  require('../chunk-A2IS7EHE.cjs');
12
12
 
13
13
 
@@ -1653,11 +1653,11 @@ function header(state, options) {
1653
1653
  return out;
1654
1654
  }
1655
1655
  function serializePaintDocument(state, options = {}) {
1656
- const { layers, assets } = _chunkUHMSMUHKcjs.serializeLayers.call(void 0, state.layers);
1656
+ const { layers, assets } = _chunkC6TRAAG4cjs.serializeLayers.call(void 0, state.layers);
1657
1657
  return { ...header(state, options), layers, assets };
1658
1658
  }
1659
1659
  async function serializePaintDocumentExternal(state, store, options = {}) {
1660
- const { layers, assets } = await _chunkUHMSMUHKcjs.serializeLayersExternal.call(void 0, state.layers, store);
1660
+ const { layers, assets } = await _chunkC6TRAAG4cjs.serializeLayersExternal.call(void 0, state.layers, store);
1661
1661
  return { ...header(state, options), layers, assets };
1662
1662
  }
1663
1663
  function paintLayersOnly(layers, problems) {
@@ -1694,7 +1694,7 @@ function deserializePaintDocument(raw) {
1694
1694
  const canvas = normalizeCanvas({ width: r.width, height: r.height, dpi: _nullishCoalesce(r.dpi, () => ( void 0)) });
1695
1695
  const paper = _chunkYQ5C5BVKcjs.normalizePaper.call(void 0, _nullishCoalesce(r.paper, () => ( {})));
1696
1696
  const assets = r.assets && typeof r.assets === "object" ? r.assets : {};
1697
- const layers = paintLayersOnly(_chunkUHMSMUHKcjs.deserializeLayers.call(void 0, r.layers, { assets, problems }), problems);
1697
+ const layers = paintLayersOnly(_chunkC6TRAAG4cjs.deserializeLayers.call(void 0, r.layers, { assets, problems }), problems);
1698
1698
  const wanted = typeof r.activeLayerId === "string" ? r.activeLayerId : null;
1699
1699
  const activeLayerId = wanted && _chunkHGTDMKNEcjs.findLayer.call(void 0, layers, wanted) ? wanted : _nullishCoalesce(_optionalChain([_chunkHGTDMKNEcjs.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));
1700
1700
  const wetEvents = Array.isArray(r.wetEvents) ? r.wetEvents.filter((e) => e && typeof e === "object" && Number.isInteger(e.clock) && typeof e.kind === "string") : [];
@@ -1710,7 +1710,7 @@ async function deserializePaintDocumentAsync(raw, store) {
1710
1710
  if (!raw || typeof raw !== "object") throw new Error("Not a paint document: expected a JSON object.");
1711
1711
  const r = raw;
1712
1712
  const problems = [];
1713
- const assets = await _chunkUHMSMUHKcjs.resolveExternalAssets.call(void 0, _nullishCoalesce(r.assets, () => ( {})), store, problems);
1713
+ const assets = await _chunkC6TRAAG4cjs.resolveExternalAssets.call(void 0, _nullishCoalesce(r.assets, () => ( {})), store, problems);
1714
1714
  const loaded = deserializePaintDocument({ ...r, assets });
1715
1715
  return { ...loaded, problems: [...problems, ...loaded.problems] };
1716
1716
  }
@@ -5409,7 +5409,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5409
5409
  return next.type === "group" ? { ...next, children: toStandard(next.children) } : next;
5410
5410
  });
5411
5411
  const layers = toStandard(dried);
5412
- const result = _chunkUHMSMUHKcjs.exportPsd.call(void 0, { width, height, layers: [paperLayer, ...layers], merged, resolution: dpi });
5412
+ const result = _chunkC6TRAAG4cjs.exportPsd.call(void 0, { width, height, layers: [paperLayer, ...layers], merged, resolution: dpi });
5413
5413
  for (const [mode, names] of changed) {
5414
5414
  const label = _nullishCoalesce(_optionalChain([_chunkCWM3CUUXcjs.BLEND_MODES, 'access', _271 => _271.find, 'call', _272 => _272((m) => m.id === mode), 'optionalAccess', _273 => _273.label]), () => ( mode));
5415
5415
  const std = _nullishCoalesce(_optionalChain([_chunkCWM3CUUXcjs.BLEND_MODES, 'access', _274 => _274.find, 'call', _275 => _275((m) => m.id === _chunkCWM3CUUXcjs.standardBlendMode.call(void 0, mode)), 'optionalAccess', _276 => _276.label]), () => ( _chunkCWM3CUUXcjs.standardBlendMode.call(void 0, mode)));
@@ -7,7 +7,7 @@ import {
7
7
  resolveExternalAssets,
8
8
  serializeLayers,
9
9
  serializeLayersExternal
10
- } from "../chunk-Y46OMERN.js";
10
+ } from "../chunk-GYYSPMVU.js";
11
11
  import "../chunk-3CI7FRMK.js";
12
12
  import {
13
13
  EffectRendererPool
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixerate/editor",
3
- "version": "0.183.0",
3
+ "version": "0.185.0",
4
4
  "description": "UI-agnostic rich text and media editing core library",
5
5
  "author": "Pixerate",
6
6
  "license": "MIT",