@pixerate/editor 0.188.0 → 0.189.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.
@@ -140,7 +140,8 @@ export interface ShortcutEvent {
140
140
  * Applies a paint shortcut. Returns true when it was one (the caller then prevents the default).
141
141
  * B / Shift+B (Mixer Brush) / E / V choose the tool; [ and ] change the size, with Shift the hardness by 25 %; 1..9 set the
142
142
  * opacity to 10..90 % and 0 to 100 %; D resets the colours to black and white; X swaps them; Q
143
- * toggles Quick Mask mode (painting then edits the selection).
143
+ * toggles Quick Mask mode (painting then edits the selection); the backslash key shows the active
144
+ * layer's mask as a red overlay.
144
145
  */
145
146
  export declare function handlePaintShortcut(controller: ImageEditorController, e: ShortcutEvent): boolean;
146
147
  /** One pointer sample in document pixels. */
@@ -140,7 +140,8 @@ export interface ShortcutEvent {
140
140
  * Applies a paint shortcut. Returns true when it was one (the caller then prevents the default).
141
141
  * B / Shift+B (Mixer Brush) / E / V choose the tool; [ and ] change the size, with Shift the hardness by 25 %; 1..9 set the
142
142
  * opacity to 10..90 % and 0 to 100 %; D resets the colours to black and white; X swaps them; Q
143
- * toggles Quick Mask mode (painting then edits the selection).
143
+ * toggles Quick Mask mode (painting then edits the selection); the backslash key shows the active
144
+ * layer's mask as a red overlay.
144
145
  */
145
146
  export declare function handlePaintShortcut(controller: ImageEditorController, e: ShortcutEvent): boolean;
146
147
  /** One pointer sample in document pixels. */
@@ -8,8 +8,9 @@ import { type ImageLayer, type SmartFilter } from './model.cjs';
8
8
  import type { LayerPlacement } from './ops.cjs';
9
9
  /**
10
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.
11
+ * selection (with Shift adding, Alt subtracting, both intersecting), Alt-click shows the mask
12
+ * alone in grey (Alt+Shift-click as a red overlay; again to go back to the image), Shift-click
13
+ * turns the mask on or off, and a plain click makes the mask the paint target.
13
14
  */
14
15
  export declare function maskThumbnailClick(controller: ImageEditorController, layer: ImageLayer, e: {
15
16
  ctrlKey?: boolean;
@@ -8,8 +8,9 @@ import { type ImageLayer, type SmartFilter } from './model.js';
8
8
  import type { LayerPlacement } from './ops.js';
9
9
  /**
10
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.
11
+ * selection (with Shift adding, Alt subtracting, both intersecting), Alt-click shows the mask
12
+ * alone in grey (Alt+Shift-click as a red overlay; again to go back to the image), Shift-click
13
+ * turns the mask on or off, and a plain click makes the mask the paint target.
13
14
  */
14
15
  export declare function maskThumbnailClick(controller: ImageEditorController, layer: ImageLayer, e: {
15
16
  ctrlKey?: boolean;
@@ -178,6 +178,12 @@ export declare class ImageEditorRenderer {
178
178
  /** An empty selection of the image's size (Quick Mask mode with nothing selected). */
179
179
  private emptyMask;
180
180
  private overlayCache;
181
+ private maskViewCache;
182
+ private grayCache;
183
+ /** A layer's mask as canvas-sized coverage for its mask view, kept while the mask is unchanged. */
184
+ private maskViewSelection;
185
+ /** A mask alone in grey (white = revealed), opaque, drawn in natural image space. */
186
+ private drawMaskGray;
181
187
  /** A channel's tint (colour, opacity, masked or selected area), drawn in natural image space. */
182
188
  private drawMaskOverlay;
183
189
  /** Rubylith over the unselected area, drawn in natural image space. */
@@ -178,6 +178,12 @@ export declare class ImageEditorRenderer {
178
178
  /** An empty selection of the image's size (Quick Mask mode with nothing selected). */
179
179
  private emptyMask;
180
180
  private overlayCache;
181
+ private maskViewCache;
182
+ private grayCache;
183
+ /** A layer's mask as canvas-sized coverage for its mask view, kept while the mask is unchanged. */
184
+ private maskViewSelection;
185
+ /** A mask alone in grey (white = revealed), opaque, drawn in natural image space. */
186
+ private drawMaskGray;
181
187
  /** A channel's tint (colour, opacity, masked or selected area), drawn in natural image space. */
182
188
  private drawMaskOverlay;
183
189
  /** Rubylith over the unselected area, drawn in natural image space. */
@@ -76,6 +76,16 @@ export declare function handleSelectionShortcut(controller: ImageEditorControlle
76
76
  shiftKey?: boolean;
77
77
  altKey?: boolean;
78
78
  }, onError?: (message: string) => void): boolean;
79
+ /**
80
+ * The backslash key (no modifiers) shows or hides the active layer's mask as a red overlay; it
81
+ * does nothing when the layer has no painted mask. Returns true when the key was used.
82
+ */
83
+ export declare function handleMaskViewKey(controller: ImageEditorController, e: {
84
+ key: string;
85
+ ctrlKey?: boolean;
86
+ metaKey?: boolean;
87
+ altKey?: boolean;
88
+ }): boolean;
79
89
  /** Q (no modifiers) toggles Quick Mask mode. Returns true when the key was used. */
80
90
  export declare function handleQuickMaskKey(controller: ImageEditorController, e: {
81
91
  key: string;
@@ -76,6 +76,16 @@ export declare function handleSelectionShortcut(controller: ImageEditorControlle
76
76
  shiftKey?: boolean;
77
77
  altKey?: boolean;
78
78
  }, onError?: (message: string) => void): boolean;
79
+ /**
80
+ * The backslash key (no modifiers) shows or hides the active layer's mask as a red overlay; it
81
+ * does nothing when the layer has no painted mask. Returns true when the key was used.
82
+ */
83
+ export declare function handleMaskViewKey(controller: ImageEditorController, e: {
84
+ key: string;
85
+ ctrlKey?: boolean;
86
+ metaKey?: boolean;
87
+ altKey?: boolean;
88
+ }): boolean;
79
89
  /** Q (no modifiers) toggles Quick Mask mode. Returns true when the key was used. */
80
90
  export declare function handleQuickMaskKey(controller: ImageEditorController, e: {
81
91
  key: string;
@@ -1,6 +1,12 @@
1
1
  import type { AdjustmentLayer, AdjustmentLayerMask } from '../types.cjs';
2
2
  import { type ImageProjection } from '../geometry.cjs';
3
3
  import { type SelectionMask } from './mask.cjs';
4
+ import type { ImageLayer } from '../layers/model.cjs';
5
+ /**
6
+ * A layer's painted mask over the `width × height` canvas as coverage (white = revealed), its
7
+ * pixels before density and feather; `null` without one (a depth mask is computed, not painted).
8
+ */
9
+ export declare function layerMaskSelection(layer: ImageLayer, width: number, height: number): SelectionMask | null;
4
10
  /** Properties of a layer mask that leave its pixels intact (Photoshop's Properties › Masks). */
5
11
  export interface LayerMaskProps {
6
12
  /** 0..1 (default 1): at 0.5 the masked-out areas still get half of the adjustment. */
@@ -1,6 +1,12 @@
1
1
  import type { AdjustmentLayer, AdjustmentLayerMask } from '../types.js';
2
2
  import { type ImageProjection } from '../geometry.js';
3
3
  import { type SelectionMask } from './mask.js';
4
+ import type { ImageLayer } from '../layers/model.js';
5
+ /**
6
+ * A layer's painted mask over the `width × height` canvas as coverage (white = revealed), its
7
+ * pixels before density and feather; `null` without one (a depth mask is computed, not painted).
8
+ */
9
+ export declare function layerMaskSelection(layer: ImageLayer, width: number, height: number): SelectionMask | null;
4
10
  /** Properties of a layer mask that leave its pixels intact (Photoshop's Properties › Masks). */
5
11
  export interface LayerMaskProps {
6
12
  /** 0..1 (default 1): at 0.5 the masked-out areas still get half of the adjustment. */
@@ -314,6 +314,14 @@ export interface ImageEditorState {
314
314
  quickMask?: boolean;
315
315
  /** How the canvas shows the selection (view state; `quickMask` mirrors `'quickMask'`). */
316
316
  selectionDisplay?: 'ants' | 'quickMask' | 'none';
317
+ /**
318
+ * A layer mask shown on the canvas (view state, not saved): `gray` shows the mask alone in
319
+ * grey (Alt-click its thumbnail), `overlay` tints what it hides in red over the image (the \ key).
320
+ */
321
+ maskView?: {
322
+ layerId: string;
323
+ mode: 'gray' | 'overlay';
324
+ } | null;
317
325
  /**
318
326
  * Quick Mask mode: painting and fills without a layer edit the selection itself (white
319
327
  * selects, black deselects), shown as a tint. View state; the edits are undo steps.
@@ -314,6 +314,14 @@ export interface ImageEditorState {
314
314
  quickMask?: boolean;
315
315
  /** How the canvas shows the selection (view state; `quickMask` mirrors `'quickMask'`). */
316
316
  selectionDisplay?: 'ants' | 'quickMask' | 'none';
317
+ /**
318
+ * A layer mask shown on the canvas (view state, not saved): `gray` shows the mask alone in
319
+ * grey (Alt-click its thumbnail), `overlay` tints what it hides in red over the image (the \ key).
320
+ */
321
+ maskView?: {
322
+ layerId: string;
323
+ mode: 'gray' | 'overlay';
324
+ } | null;
317
325
  /**
318
326
  * Quick Mask mode: painting and fills without a layer edit the selection itself (white
319
327
  * selects, black deselects), shown as a tint. View state; the edits are undo steps.
@@ -7,7 +7,7 @@ var _chunkZ64NRDEHcjs = require('../chunk-Z64NRDEH.cjs');
7
7
 
8
8
 
9
9
 
10
- var _chunkJYV4R62Mcjs = require('../chunk-JYV4R62M.cjs');
10
+ var _chunkED4L4UD6cjs = require('../chunk-ED4L4UD6.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 } = _chunkJYV4R62Mcjs.serializeLayers.call(void 0, state.layers);
1656
+ const { layers, assets } = _chunkED4L4UD6cjs.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 _chunkJYV4R62Mcjs.serializeLayersExternal.call(void 0, state.layers, store);
1660
+ const { layers, assets } = await _chunkED4L4UD6cjs.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(_chunkJYV4R62Mcjs.deserializeLayers.call(void 0, r.layers, { assets, problems }), problems);
1697
+ const layers = paintLayersOnly(_chunkED4L4UD6cjs.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 _chunkJYV4R62Mcjs.resolveExternalAssets.call(void 0, _nullishCoalesce(r.assets, () => ( {})), store, problems);
1713
+ const assets = await _chunkED4L4UD6cjs.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 = _chunkJYV4R62Mcjs.exportPsd.call(void 0, { width, height, layers: [paperLayer, ...layers], merged, resolution: dpi });
5412
+ const result = _chunkED4L4UD6cjs.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-IGMNJM2H.js";
10
+ } from "../chunk-ZEHTUR7Z.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.188.0",
3
+ "version": "0.189.0",
4
4
  "description": "UI-agnostic rich text and media editing core library",
5
5
  "author": "Pixerate",
6
6
  "license": "MIT",
@@ -297,6 +297,7 @@ in the source frame at the document's bit depth, colour mode and profile. Read
297
297
  | `add_layer_mask` | Mask any layer `from` `reveal-all`, `hide-all`, `selection`, `hide-selection` (its inverse) or `transparency` (the layer's own alpha), with optional `density` / `feather`. Replaces an existing mask. Returns the mask summary. |
298
298
  | `set_layer_mask_properties` | Change any layer mask's `density`, `feather`, `enabled` or `linked` (false: the mask stays put when the layer moves or transforms) without touching its pixels. |
299
299
  | `apply_layer_mask` | Bake a pixel layer's mask into its alpha and remove it. Destructive. |
300
+ | `set_mask_view` | Show a layer's mask to check it (`view` `gray` alone, `overlay` red tint over what it hides, `off`; `layerId`, default active). View state only; look with `capture_view` `includeOverlays: true`, then `off`. Returns `{view, layerId}`. |
300
301
  | `remove_layer_mask` | Delete a mask without applying it; disable it instead to keep it. |
301
302
  | `layer_via_copy` | Copy the selected pixels of a pixel layer (default the active one) to a new layer above it; `cut: true` removes them from the source. Needs a selection. Returns the new layer. |
302
303
  | `rasterize_layer` | Turn a shape layer into a pixel layer showing the same pixels (same id, mask, effects, opacity, blend; the paths are gone), an annotation layer into pixels (browser only), a smart object into a pixel layer (as `rasterize_smart_object`), or bake a pixel layer's develop / blur filters into its pixels. Do it before painting over a shape or annotation, or when the user wants the filters fixed. Destructive. |
@@ -82,7 +82,9 @@ This skill is the method. `pixerate-image-editor` has the full tool reference.
82
82
  `load_selection_from_image`).
83
83
  7. **Verify.** `render_preview` at 1024 px or more, and `capture_view` on the edge at 2–8×.
84
84
  **Check:** no fringe of the old background colour, no stair-steps, no visible line where an
85
- adjustment ends. Fix by loading the mask back (`load_selection_from_mask`), refining, and
85
+ adjustment ends. To judge a layer mask itself, `set_mask_view` `gray` (or `overlay`) and
86
+ `capture_view` with `includeOverlays: true`; holes and stray grey show plainly there. Set it
87
+ back to `off` afterwards. Fix by loading the mask back (`load_selection_from_mask`), refining, and
86
88
  masking again.
87
89
 
88
90
  ## Decision table
@@ -192,6 +194,7 @@ This skill is the method. `pixerate-image-editor` has the full tool reference.
192
194
  - `load_selection_from_image`: AI or saved mattes
193
195
  - `load_selection_from_mask`: a layer mask back to a selection
194
196
  - `set_selection_display`: ants, Quick Mask tint or hidden
197
+ - `set_mask_view`: a layer mask alone in grey or as a red overlay, to check it
195
198
  - `modify_selection`: expand, contract, feather, border, smooth
196
199
  - `refine_selection`: snap the edge to the image
197
200
  - `transform_selection`: move or scale the outline only