@pixerate/editor 0.121.0 → 0.122.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 (36) hide show
  1. package/THIRD_PARTY_NOTICES.md +1 -1
  2. package/dist/{chunk-GLOOH65Y.cjs → chunk-4PUPGALM.cjs} +196 -103
  3. package/dist/chunk-4PUPGALM.cjs.map +1 -0
  4. package/dist/{chunk-4I54JSJ6.js → chunk-CLTTLLWA.js} +1089 -981
  5. package/dist/chunk-CLTTLLWA.js.map +1 -0
  6. package/dist/{chunk-LL3RAN55.cjs → chunk-DFFBJV3U.cjs} +1839 -1731
  7. package/dist/chunk-DFFBJV3U.cjs.map +1 -0
  8. package/dist/{chunk-E6N5KLMA.js → chunk-IX3YKUVK.js} +96 -3
  9. package/dist/chunk-IX3YKUVK.js.map +1 -0
  10. package/dist/{render-B05K68_h.d.ts → deep-DLwKZDFr.d.ts} +143 -134
  11. package/dist/{render-DnAbIKcs.d.cts → deep-QS3ppbMX.d.cts} +143 -134
  12. package/dist/{export-D2D8hb_u.d.ts → export-VmTofKIk.d.ts} +11 -4
  13. package/dist/{export-fP2hZYjm.d.cts → export-jKKj8Fg8.d.cts} +11 -4
  14. package/dist/image-editor/index.cjs +678 -672
  15. package/dist/image-editor/index.cjs.map +1 -1
  16. package/dist/image-editor/index.d.cts +17 -5
  17. package/dist/image-editor/index.d.ts +17 -5
  18. package/dist/image-editor/index.js +8 -2
  19. package/dist/image-editor/index.js.map +1 -1
  20. package/dist/paint-editor/index.cjs +68 -68
  21. package/dist/paint-editor/index.d.cts +2 -2
  22. package/dist/paint-editor/index.d.ts +2 -2
  23. package/dist/paint-editor/index.js +2 -2
  24. package/dist/raster/index.cjs +2 -2
  25. package/dist/raster/index.d.cts +29 -7
  26. package/dist/raster/index.d.ts +29 -7
  27. package/dist/raster/index.js +1 -1
  28. package/package.json +1 -1
  29. package/skills/pixerate-canvas/SKILL.md +23 -1
  30. package/skills/pixerate-image-editor/SKILL.md +7 -1
  31. package/skills/pixerate-image-editor/references/photoshop-files.md +4 -3
  32. package/skills/pixerate-paint-editor/SKILL.md +32 -7
  33. package/dist/chunk-4I54JSJ6.js.map +0 -1
  34. package/dist/chunk-E6N5KLMA.js.map +0 -1
  35. package/dist/chunk-GLOOH65Y.cjs.map +0 -1
  36. package/dist/chunk-LL3RAN55.cjs.map +0 -1
@@ -1,7 +1,7 @@
1
1
  import { R as RasterRect } from '../surface-Cn30xIV6.cjs';
2
2
  export { B as BLEND_MODES, a as BlendMode, b as BlendModeInfo, M as MaskSurface, P as PAINTERLY_BLEND_MODES, c as PixelSurface, d as Rgb, e as Rgba, S as SHADOW_AMBIENT, f as SurfaceDraft, T as TILE, g as TILE_SHIFT, h as Tile, i as TileKey, j as TiledSurface, k as blendChannel, l as blendImageData, m as blendLum, n as blendPixel, o as blendRgb, p as canvasCompositeOperation, q as collectTiles, r as contentBounds, s as emptySurface, t as fillRect, u as finishTile, v as isBlendMode, w as isPainterlyBlendMode, x as isSeparableBlendMode, y as mixPigment8, z as mixPigmentRgb, A as normalizeBlendMode, C as packRgba, D as pigment8, E as readPixel, F as readRegion, G as setLum, H as solidSurface, I as standardBlendMode, J as surfaceBytes, K as surfaceFromPixels, L as surfacesEqual, N as tileCoord, O as tileKey, Q as tileRect, U as tilesInRect, V as translateSurface, W as uniformTile, X as writeRegion } from '../surface-Cn30xIV6.cjs';
3
- import { C as CompositorLayer, R as RasterSources, a as RasterCompositor, b as CompositorProfile } from '../render-DnAbIKcs.cjs';
4
- export { B as BIT_DEPTHS, c as BevelContour, d as BevelEmbossEffect, e as BevelStyle, f as BevelTechnique, g as BevelTexture, h as BitDepth, i as ColorOverlayEffect, j as CompositeCallOptions, k as CompositeStats, l as CompositorOptions, m as ContourPoint, D as DEFAULT_GLOBAL_LIGHT, n as DeepSamples, o as DropShadowEffect, E as EffectCompositeInput, p as EffectContext, q as EffectContour, r as EffectFill, s as EffectGradient, t as EffectMaps, u as EffectPattern, v as EffectPatternRef, w as EffectRect, G as GlobalLight, x as GlowTechnique, y as GradientColorStop, z as GradientOpacityStop, A as GradientOverlayEffect, F as GradientStyle, H as GroupBlendMode, I as GroupIn, J as INTERPOLATIONS, K as InnerGlowEffect, L as InnerShadowEffect, M as Interpolation, N as LAYER_EFFECT_KINDS, O as LayerEffect, P as LayerEffectError, Q as LayerEffectKind, S as LayerEffects, T as LayerLocation, U as LayerLocks, V as MAX_EFFECT_REACH, W as MAX_TRANSFORM_PIXELS, X as OuterGlowEffect, Y as PatternOverlayEffect, Z as PatternPlacement, _ as PatternTile, $ as PixelFilterSpec, a0 as RasterGroupLayer, a1 as RasterLayer, a2 as RasterLayerBase, a3 as RasterMask, a4 as RasterNode, a5 as RasterPixelLayer, a6 as ResampleOptions, a7 as STROKE_CHAMFER_MAX, a8 as SatinEffect, a9 as StrokeEffect, aa as StrokePosition, ab as TransformTooLargeError, ac as activeEffectItems, ad as blendTile, ae as buildEffectMaps, af as builtinPattern, ag as builtinPatternIds, ah as changedTiles, ai as compositeLayerEffects, aj as compositeSurfaceOver, ak as contourLut, al as convertSurfaceDepth, am as deepBytes, an as deepTile, ao as defaultEffectGradient, ap as defaultLayerEffect, aq as depthOf, ar as effectColorHex, as as effectFillColors, at as effectReach, au as effectsAreLocal, av as effectsFingerprint, aw as effectsMargin, ax as effectsScale, ay as findLayer, az as flattenLayers, aA as gradientT, aB as hasActiveEffects, aC as hashNoise, aD as insertLayer, aE as isBitDepth, aF as isInterpolation, aG as isLayerEffectKind, aH as isLayerLocked, aI as keepDeepSamples, aJ as keysWeight, aK as layerEffectFields, aL as layerEffectLabel, aM as mapLayer, aN as mergeLayerEffect, aO as newEffectId, aP as normalizeLayerEffects, aQ as parseEffectColor, aR as patchEffectMaps, aS as proxyOf, aT as readDeepRegion, aU as reduceSurface, aV as renderLayerEffects, aW as scaleLayerEffect, aX as srgbDecode, aY as srgbEncode, aZ as surfaceDepth, a_ as surfaceFromDeepPixels, a$ as tileSamples, b0 as tileSamples16, b1 as tileSamples32, b2 as to16From32, b3 as to16From8, b4 as to32From16, b5 as to32From8, b6 as to8From16, b7 as to8From32, b8 as transformSurface, b9 as transformedBounds, ba as validateEffectGradient, bb as validateLayerEffect, bc as validateLayerEffects, bd as warpSurface, be as writeDeepRegion } from '../render-DnAbIKcs.cjs';
3
+ import { C as CompositorLayer, R as RasterSources, a as RasterCompositor, b as CompositorProfile } from '../deep-QS3ppbMX.cjs';
4
+ export { B as BIT_DEPTHS, c as BevelContour, d as BevelEmbossEffect, e as BevelStyle, f as BevelTechnique, g as BevelTexture, h as BitDepth, i as ColorOverlayEffect, j as CompositeCallOptions, k as CompositeStats, l as CompositorOptions, m as ContourPoint, D as DEFAULT_GLOBAL_LIGHT, n as DeepSamples, o as DropShadowEffect, E as EffectCompositeInput, p as EffectContext, q as EffectContour, r as EffectFill, s as EffectGradient, t as EffectMaps, u as EffectPattern, v as EffectPatternRef, w as EffectRect, G as GlobalLight, x as GlowTechnique, y as GradientColorStop, z as GradientOpacityStop, A as GradientOverlayEffect, F as GradientStyle, H as GroupBlendMode, I as GroupIn, J as INTERPOLATIONS, K as InnerGlowEffect, L as InnerShadowEffect, M as Interpolation, N as LAYER_EFFECT_KINDS, O as LayerEffect, P as LayerEffectError, Q as LayerEffectKind, S as LayerEffects, T as LayerLocation, U as LayerLocks, V as MAX_EFFECT_REACH, W as MAX_TRANSFORM_PIXELS, X as OuterGlowEffect, Y as PatternOverlayEffect, Z as PatternPlacement, _ as PatternTile, $ as PixelFilterSpec, a0 as RasterGroupLayer, a1 as RasterLayer, a2 as RasterLayerBase, a3 as RasterMask, a4 as RasterNode, a5 as RasterPixelLayer, a6 as ResampleOptions, a7 as STROKE_CHAMFER_MAX, a8 as SatinEffect, a9 as StrokeEffect, aa as StrokePosition, ab as TransformTooLargeError, ac as activeEffectItems, ad as blendTile, ae as buildEffectMaps, af as builtinPattern, ag as builtinPatternIds, ah as changedTiles, ai as compositeLayerEffects, aj as compositeSurfaceOver, ak as contourLut, al as convertSurfaceDepth, am as deepBytes, an as deepTile, ao as defaultEffectGradient, ap as defaultLayerEffect, aq as depthOf, ar as effectColorHex, as as effectFillColors, at as effectReach, au as effectsAreLocal, av as effectsFingerprint, aw as effectsMargin, ax as effectsScale, ay as findLayer, az as flattenLayers, aA as gradientT, aB as hasActiveEffects, aC as hashNoise, aD as insertLayer, aE as isBitDepth, aF as isInterpolation, aG as isLayerEffectKind, aH as isLayerLocked, aI as keepDeepSamples, aJ as keysWeight, aK as layerEffectFields, aL as layerEffectLabel, aM as mapLayer, aN as mergeLayerEffect, aO as newEffectId, aP as normalizeLayerEffects, aQ as parseEffectColor, aR as patchEffectMaps, aS as proxyOf, aT as readDeepRegion, aU as reduceSurface, aV as renderLayerEffects, aW as scaleLayerEffect, aX as srgbDecode, aY as srgbEncode, aZ as surfaceDepth, a_ as surfaceFromDeepPixels, a$ as tileSamples, b0 as tileSamples16, b1 as tileSamples32, b2 as to16From32, b3 as to16From8, b4 as to32From16, b5 as to32From8, b6 as to8From16, b7 as to8From32, b8 as transformSurface, b9 as transformedBounds, ba as validateEffectGradient, bb as validateLayerEffect, bc as validateLayerEffects, bd as warpSurface, be as writeDeepRegion } from '../deep-QS3ppbMX.cjs';
5
5
  export { B as BlurEdge, C as CURVE_LUT_SIZE, D as DIRECT_GAUSSIAN_MAX_SIGMA, a as DecodedPng, Z as ZlibError, b as adler32, c as base64ToBytes, d as bytesToBase64, e as curveLut, f as decodePng, g as deflate, h as deflateRaw, i as encodePng, j as gaussianBlur, k as inflate, l as inflateRaw, m as isPng, p as parseDataUrl, n as pngDataUrl } from '../zlib-dxQdgHyN.cjs';
6
6
  import '../types-CwMPoRMU.cjs';
7
7
 
@@ -16,11 +16,13 @@ import '../types-CwMPoRMU.cjs';
16
16
  * bits (as Photoshop blends in each mode). Results come back in that space.
17
17
  *
18
18
  * What it delegates to the 8-bit compositor it wraps:
19
- * - mask coverage (density, feather and parametric masks), which is coverage, not colour;
20
- * - layers with layer effects or pixel filters, and content layers the editor draws itself
21
- * (annotations): each is rendered alone at 8 bits, converted, and blended in float with its
22
- * blend mode and opacity. Such layers keep 8-bit precision (and an effect's own blend mode sees
23
- * a transparent backdrop); everything else keeps the samples' full depth.
19
+ * - mask coverage (density, feather and parametric masks: deep masks are read at depth);
20
+ * - the effect maps of layers with effects (built from the 8-bit shape); the effects themselves
21
+ * composite in float over the deep content (`runEffects`), and pixel filters run in float when
22
+ * the profile gives `pixelFiltersDeep`;
23
+ * - groups with effects, filters it cannot run in float, and content layers the editor draws
24
+ * itself (annotations): each is rendered alone at 8 bits, converted, and blended in float with
25
+ * its blend mode and opacity.
24
26
  */
25
27
 
26
28
  /** Float hooks of an editor's own layer kinds (see `CompositorProfile`). */
@@ -31,6 +33,15 @@ interface DeepCompositorProfile<L extends CompositorLayer, S extends RasterSourc
31
33
  * Missing: filter layers run at 8 bits.
32
34
  */
33
35
  applyFilterRunDeep?(layers: L[], acc: Float32Array, r: RasterRect, coverage: Map<string, Float32Array> | undefined, sources: S): void;
36
+ /**
37
+ * A pixel layer's filters in float (`null`: none, or none it can run): `apply` filters float
38
+ * RGBA in the working space (`linear` at 32 bits) in place; `reach` is how many pixels each
39
+ * side they read (0 for per-pixel filters). Missing: filtered layers are drawn at 8 bits.
40
+ */
41
+ pixelFiltersDeep?(layer: L): {
42
+ reach: number;
43
+ apply(data: Float32Array, width: number, height: number, linear: boolean): void;
44
+ } | null;
34
45
  }
35
46
  declare class DeepCompositor<L extends CompositorLayer, S extends RasterSources> {
36
47
  /** The 8-bit compositor for masks and the layers it renders (see the module comment). */
@@ -50,13 +61,24 @@ declare class DeepCompositor<L extends CompositorLayer, S extends RasterSources>
50
61
  private buildSteps;
51
62
  private runSteps;
52
63
  private runStep;
64
+ /**
65
+ * A pixel layer with effects onto `acc` over `r`: its deep content (filters, mask, clipped
66
+ * layers) and the effects composited in float. Effect maps come from the 8-bit shape. At 32
67
+ * bits the effects composite in sRGB-encoded values (their colours and blends are defined
68
+ * there) and the result is decoded back. Returns whether anything was drawn.
69
+ */
70
+ private runEffects;
53
71
  private applyClipped;
54
72
  private applyFilterRun;
55
73
  /** Layers drawn by the 8-bit compositor alone (effects, pixel filters, content the editor draws). */
74
+ /** A pixel(-like) layer with effects: composited in float through `compositeLayerEffects`. */
75
+ private deepEffects;
56
76
  private renderedAlone;
57
77
  private blendOf;
58
78
  /** A layer's float RGBA over `r` (straight alpha, working space), or `null` when it has none there. */
59
79
  private content;
80
+ /** A surface's samples over `rect` (layer space) in the working space. */
81
+ private samples;
60
82
  /** 8-bit RGBA to the working space. */
61
83
  private from8;
62
84
  /** The working space to 8-bit RGBA. */
@@ -1,7 +1,7 @@
1
1
  import { R as RasterRect } from '../surface-Cn30xIV6.js';
2
2
  export { B as BLEND_MODES, a as BlendMode, b as BlendModeInfo, M as MaskSurface, P as PAINTERLY_BLEND_MODES, c as PixelSurface, d as Rgb, e as Rgba, S as SHADOW_AMBIENT, f as SurfaceDraft, T as TILE, g as TILE_SHIFT, h as Tile, i as TileKey, j as TiledSurface, k as blendChannel, l as blendImageData, m as blendLum, n as blendPixel, o as blendRgb, p as canvasCompositeOperation, q as collectTiles, r as contentBounds, s as emptySurface, t as fillRect, u as finishTile, v as isBlendMode, w as isPainterlyBlendMode, x as isSeparableBlendMode, y as mixPigment8, z as mixPigmentRgb, A as normalizeBlendMode, C as packRgba, D as pigment8, E as readPixel, F as readRegion, G as setLum, H as solidSurface, I as standardBlendMode, J as surfaceBytes, K as surfaceFromPixels, L as surfacesEqual, N as tileCoord, O as tileKey, Q as tileRect, U as tilesInRect, V as translateSurface, W as uniformTile, X as writeRegion } from '../surface-Cn30xIV6.js';
3
- import { C as CompositorLayer, R as RasterSources, a as RasterCompositor, b as CompositorProfile } from '../render-B05K68_h.js';
4
- export { B as BIT_DEPTHS, c as BevelContour, d as BevelEmbossEffect, e as BevelStyle, f as BevelTechnique, g as BevelTexture, h as BitDepth, i as ColorOverlayEffect, j as CompositeCallOptions, k as CompositeStats, l as CompositorOptions, m as ContourPoint, D as DEFAULT_GLOBAL_LIGHT, n as DeepSamples, o as DropShadowEffect, E as EffectCompositeInput, p as EffectContext, q as EffectContour, r as EffectFill, s as EffectGradient, t as EffectMaps, u as EffectPattern, v as EffectPatternRef, w as EffectRect, G as GlobalLight, x as GlowTechnique, y as GradientColorStop, z as GradientOpacityStop, A as GradientOverlayEffect, F as GradientStyle, H as GroupBlendMode, I as GroupIn, J as INTERPOLATIONS, K as InnerGlowEffect, L as InnerShadowEffect, M as Interpolation, N as LAYER_EFFECT_KINDS, O as LayerEffect, P as LayerEffectError, Q as LayerEffectKind, S as LayerEffects, T as LayerLocation, U as LayerLocks, V as MAX_EFFECT_REACH, W as MAX_TRANSFORM_PIXELS, X as OuterGlowEffect, Y as PatternOverlayEffect, Z as PatternPlacement, _ as PatternTile, $ as PixelFilterSpec, a0 as RasterGroupLayer, a1 as RasterLayer, a2 as RasterLayerBase, a3 as RasterMask, a4 as RasterNode, a5 as RasterPixelLayer, a6 as ResampleOptions, a7 as STROKE_CHAMFER_MAX, a8 as SatinEffect, a9 as StrokeEffect, aa as StrokePosition, ab as TransformTooLargeError, ac as activeEffectItems, ad as blendTile, ae as buildEffectMaps, af as builtinPattern, ag as builtinPatternIds, ah as changedTiles, ai as compositeLayerEffects, aj as compositeSurfaceOver, ak as contourLut, al as convertSurfaceDepth, am as deepBytes, an as deepTile, ao as defaultEffectGradient, ap as defaultLayerEffect, aq as depthOf, ar as effectColorHex, as as effectFillColors, at as effectReach, au as effectsAreLocal, av as effectsFingerprint, aw as effectsMargin, ax as effectsScale, ay as findLayer, az as flattenLayers, aA as gradientT, aB as hasActiveEffects, aC as hashNoise, aD as insertLayer, aE as isBitDepth, aF as isInterpolation, aG as isLayerEffectKind, aH as isLayerLocked, aI as keepDeepSamples, aJ as keysWeight, aK as layerEffectFields, aL as layerEffectLabel, aM as mapLayer, aN as mergeLayerEffect, aO as newEffectId, aP as normalizeLayerEffects, aQ as parseEffectColor, aR as patchEffectMaps, aS as proxyOf, aT as readDeepRegion, aU as reduceSurface, aV as renderLayerEffects, aW as scaleLayerEffect, aX as srgbDecode, aY as srgbEncode, aZ as surfaceDepth, a_ as surfaceFromDeepPixels, a$ as tileSamples, b0 as tileSamples16, b1 as tileSamples32, b2 as to16From32, b3 as to16From8, b4 as to32From16, b5 as to32From8, b6 as to8From16, b7 as to8From32, b8 as transformSurface, b9 as transformedBounds, ba as validateEffectGradient, bb as validateLayerEffect, bc as validateLayerEffects, bd as warpSurface, be as writeDeepRegion } from '../render-B05K68_h.js';
3
+ import { C as CompositorLayer, R as RasterSources, a as RasterCompositor, b as CompositorProfile } from '../deep-DLwKZDFr.js';
4
+ export { B as BIT_DEPTHS, c as BevelContour, d as BevelEmbossEffect, e as BevelStyle, f as BevelTechnique, g as BevelTexture, h as BitDepth, i as ColorOverlayEffect, j as CompositeCallOptions, k as CompositeStats, l as CompositorOptions, m as ContourPoint, D as DEFAULT_GLOBAL_LIGHT, n as DeepSamples, o as DropShadowEffect, E as EffectCompositeInput, p as EffectContext, q as EffectContour, r as EffectFill, s as EffectGradient, t as EffectMaps, u as EffectPattern, v as EffectPatternRef, w as EffectRect, G as GlobalLight, x as GlowTechnique, y as GradientColorStop, z as GradientOpacityStop, A as GradientOverlayEffect, F as GradientStyle, H as GroupBlendMode, I as GroupIn, J as INTERPOLATIONS, K as InnerGlowEffect, L as InnerShadowEffect, M as Interpolation, N as LAYER_EFFECT_KINDS, O as LayerEffect, P as LayerEffectError, Q as LayerEffectKind, S as LayerEffects, T as LayerLocation, U as LayerLocks, V as MAX_EFFECT_REACH, W as MAX_TRANSFORM_PIXELS, X as OuterGlowEffect, Y as PatternOverlayEffect, Z as PatternPlacement, _ as PatternTile, $ as PixelFilterSpec, a0 as RasterGroupLayer, a1 as RasterLayer, a2 as RasterLayerBase, a3 as RasterMask, a4 as RasterNode, a5 as RasterPixelLayer, a6 as ResampleOptions, a7 as STROKE_CHAMFER_MAX, a8 as SatinEffect, a9 as StrokeEffect, aa as StrokePosition, ab as TransformTooLargeError, ac as activeEffectItems, ad as blendTile, ae as buildEffectMaps, af as builtinPattern, ag as builtinPatternIds, ah as changedTiles, ai as compositeLayerEffects, aj as compositeSurfaceOver, ak as contourLut, al as convertSurfaceDepth, am as deepBytes, an as deepTile, ao as defaultEffectGradient, ap as defaultLayerEffect, aq as depthOf, ar as effectColorHex, as as effectFillColors, at as effectReach, au as effectsAreLocal, av as effectsFingerprint, aw as effectsMargin, ax as effectsScale, ay as findLayer, az as flattenLayers, aA as gradientT, aB as hasActiveEffects, aC as hashNoise, aD as insertLayer, aE as isBitDepth, aF as isInterpolation, aG as isLayerEffectKind, aH as isLayerLocked, aI as keepDeepSamples, aJ as keysWeight, aK as layerEffectFields, aL as layerEffectLabel, aM as mapLayer, aN as mergeLayerEffect, aO as newEffectId, aP as normalizeLayerEffects, aQ as parseEffectColor, aR as patchEffectMaps, aS as proxyOf, aT as readDeepRegion, aU as reduceSurface, aV as renderLayerEffects, aW as scaleLayerEffect, aX as srgbDecode, aY as srgbEncode, aZ as surfaceDepth, a_ as surfaceFromDeepPixels, a$ as tileSamples, b0 as tileSamples16, b1 as tileSamples32, b2 as to16From32, b3 as to16From8, b4 as to32From16, b5 as to32From8, b6 as to8From16, b7 as to8From32, b8 as transformSurface, b9 as transformedBounds, ba as validateEffectGradient, bb as validateLayerEffect, bc as validateLayerEffects, bd as warpSurface, be as writeDeepRegion } from '../deep-DLwKZDFr.js';
5
5
  export { B as BlurEdge, C as CURVE_LUT_SIZE, D as DIRECT_GAUSSIAN_MAX_SIGMA, a as DecodedPng, Z as ZlibError, b as adler32, c as base64ToBytes, d as bytesToBase64, e as curveLut, f as decodePng, g as deflate, h as deflateRaw, i as encodePng, j as gaussianBlur, k as inflate, l as inflateRaw, m as isPng, p as parseDataUrl, n as pngDataUrl } from '../zlib-dxQdgHyN.js';
6
6
  import '../types-CwMPoRMU.js';
7
7
 
@@ -16,11 +16,13 @@ import '../types-CwMPoRMU.js';
16
16
  * bits (as Photoshop blends in each mode). Results come back in that space.
17
17
  *
18
18
  * What it delegates to the 8-bit compositor it wraps:
19
- * - mask coverage (density, feather and parametric masks), which is coverage, not colour;
20
- * - layers with layer effects or pixel filters, and content layers the editor draws itself
21
- * (annotations): each is rendered alone at 8 bits, converted, and blended in float with its
22
- * blend mode and opacity. Such layers keep 8-bit precision (and an effect's own blend mode sees
23
- * a transparent backdrop); everything else keeps the samples' full depth.
19
+ * - mask coverage (density, feather and parametric masks: deep masks are read at depth);
20
+ * - the effect maps of layers with effects (built from the 8-bit shape); the effects themselves
21
+ * composite in float over the deep content (`runEffects`), and pixel filters run in float when
22
+ * the profile gives `pixelFiltersDeep`;
23
+ * - groups with effects, filters it cannot run in float, and content layers the editor draws
24
+ * itself (annotations): each is rendered alone at 8 bits, converted, and blended in float with
25
+ * its blend mode and opacity.
24
26
  */
25
27
 
26
28
  /** Float hooks of an editor's own layer kinds (see `CompositorProfile`). */
@@ -31,6 +33,15 @@ interface DeepCompositorProfile<L extends CompositorLayer, S extends RasterSourc
31
33
  * Missing: filter layers run at 8 bits.
32
34
  */
33
35
  applyFilterRunDeep?(layers: L[], acc: Float32Array, r: RasterRect, coverage: Map<string, Float32Array> | undefined, sources: S): void;
36
+ /**
37
+ * A pixel layer's filters in float (`null`: none, or none it can run): `apply` filters float
38
+ * RGBA in the working space (`linear` at 32 bits) in place; `reach` is how many pixels each
39
+ * side they read (0 for per-pixel filters). Missing: filtered layers are drawn at 8 bits.
40
+ */
41
+ pixelFiltersDeep?(layer: L): {
42
+ reach: number;
43
+ apply(data: Float32Array, width: number, height: number, linear: boolean): void;
44
+ } | null;
34
45
  }
35
46
  declare class DeepCompositor<L extends CompositorLayer, S extends RasterSources> {
36
47
  /** The 8-bit compositor for masks and the layers it renders (see the module comment). */
@@ -50,13 +61,24 @@ declare class DeepCompositor<L extends CompositorLayer, S extends RasterSources>
50
61
  private buildSteps;
51
62
  private runSteps;
52
63
  private runStep;
64
+ /**
65
+ * A pixel layer with effects onto `acc` over `r`: its deep content (filters, mask, clipped
66
+ * layers) and the effects composited in float. Effect maps come from the 8-bit shape. At 32
67
+ * bits the effects composite in sRGB-encoded values (their colours and blends are defined
68
+ * there) and the result is decoded back. Returns whether anything was drawn.
69
+ */
70
+ private runEffects;
53
71
  private applyClipped;
54
72
  private applyFilterRun;
55
73
  /** Layers drawn by the 8-bit compositor alone (effects, pixel filters, content the editor draws). */
74
+ /** A pixel(-like) layer with effects: composited in float through `compositeLayerEffects`. */
75
+ private deepEffects;
56
76
  private renderedAlone;
57
77
  private blendOf;
58
78
  /** A layer's float RGBA over `r` (straight alpha, working space), or `null` when it has none there. */
59
79
  private content;
80
+ /** A surface's samples over `rect` (layer space) in the working space. */
81
+ private samples;
60
82
  /** 8-bit RGBA to the working space. */
61
83
  private from8;
62
84
  /** The working space to 8-bit RGBA. */
@@ -61,7 +61,7 @@ import {
61
61
  validateLayerEffects,
62
62
  warpSurface,
63
63
  workingToSamples
64
- } from "../chunk-4I54JSJ6.js";
64
+ } from "../chunk-CLTTLLWA.js";
65
65
  import "../chunk-GX332W2C.js";
66
66
  import {
67
67
  BIT_DEPTHS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixerate/editor",
3
- "version": "0.121.0",
3
+ "version": "0.122.0",
4
4
  "description": "UI-agnostic rich text and media editing core library",
5
5
  "author": "Pixerate",
6
6
  "license": "MIT",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: pixerate-canvas
3
- description: How to build and edit a Pixerate design canvas or node graph through its agent tools - adding, connecting, updating and laying out nodes (canvas_add_node, canvas_layout), reading state with get_editor_state and looking at it with view_editor, reusable components with variants, instances and overrides (create_component, add_variant, set_instance_properties), align, distribute, lock and layer order, shape boolean operations (unite, subtract, offset path, outline stroke), auto layout frames, and keyframe animation with easing and CSS export. Use when working on a canvas, whiteboard, flow chart, node graph, frame, design system, component library, button variants, layout, alignment, z-order or a canvas animation in a Pixerate editor.
3
+ description: How to build and edit a Pixerate design canvas or node graph through its agent tools - drawing freehand pen, highlighter and dry-brush strokes (canvas.drawFreehand), adding, connecting, updating and laying out nodes (canvas_add_node, canvas_layout), reading state with get_editor_state and looking at it with view_editor, reusable components with variants, instances and overrides (create_component, add_variant, set_instance_properties), align, distribute, lock and layer order, shape boolean operations (unite, subtract, offset path, outline stroke), auto layout frames, and keyframe animation with easing and CSS export. Use when working on a canvas, whiteboard, flow chart, node graph, frame, design system, component library, button variants, layout, alignment, z-order or a canvas animation in a Pixerate editor.
4
4
  ---
5
5
 
6
6
  # Pixerate canvas
@@ -71,6 +71,12 @@ batching and error codes.
71
71
  everything at once. Animate `opacity`, `x`, `y`, `scale` and `rotation`; colour tweens
72
72
  interpolate in OKLab.
73
73
 
74
+ - **Brushed strokes.** Use a brush when the user wants a hand-drawn look (sketching, ink,
75
+ pencil, marker); keep plain strokes for diagrams and UI. Send points every 2 to 8 canvas units
76
+ along a curve, and shape the line with a short `pressure` profile (tapered ends:
77
+ `[0.2, 0.9, 1, 0.9, 0.2]`) rather than many points of different widths. `width` is the brush
78
+ size.
79
+
74
80
  ## Tool reference
75
81
 
76
82
  ### Read
@@ -157,6 +163,17 @@ are kept exactly). They need unlocked shapes; other selected nodes are ignored.
157
163
  | `canvas.offsetPath` | Grow (`distance` > 0) or shrink (< 0) shapes by `distance` canvas units (default 10), with `join` `miter` (default), `round` or `bevel` and `miterLimit` (default 4). |
158
164
  | `canvas.outlineStroke` | Turn shapes' strokes into filled shapes: `join` (default miter), `cap` `butt` (default), `round` or `square`, `miterLimit` (default 4). The fill stays as a separate shape below. |
159
165
 
166
+ ### Draw
167
+
168
+ Freehand strokes are `path` shape nodes, so they select, move, group, erase and export like any
169
+ shape. A stroke with `data.shape.brush` is painted with a dry paint brush instead of an SVG stroke
170
+ (the path stays the data; the paint is rendered from it).
171
+
172
+ | Command | Use it to |
173
+ | --- | --- |
174
+ | `canvas.drawFreehand` | Draw a pen or highlighter stroke through `points` (`[x, y]` pairs in canvas units, in drawing order; one undo step). `tool` picks the defaults (`pen`: blue, width 3; `highlighter`: yellow, width 24, opacity 0.35); `color`, `width`, `opacity` override them. Pass `brush` (a preset id from `canvas.listBrushes`, or tip settings) to paint it with a dry brush, plus `pressure` / `tiltX` / `tiltY` profiles spread along its length (`[0.2, 1, 0.3]` swells in the middle). Returns the node `id`, its `bounds` and the stored `brush`. |
175
+ | `canvas.listBrushes` | Read-only: the dry paint presets `canvas.drawFreehand` accepts as `brush` (`id`, `name`, `category`, the preset's own `size`). Call it before the first brushed stroke instead of guessing ids. |
176
+
160
177
  ### Components (command form)
161
178
 
162
179
  The same operations as the component tools, for command palettes and `run_commands` batches.
@@ -210,6 +227,11 @@ easing applies to the segment leaving a keyframe. Animatable properties: `x`, `y
210
227
 
211
228
  ## Pitfalls
212
229
 
230
+ - **Brushes are dry only.** Wet presets (watercolour, gouache, wet oils), mixer, blender, smudge and
231
+ eraser presets are refused: wet paint needs an area to flow in, and the others need paint under
232
+ them. `pressure` and tilt without a `brush` are refused too.
233
+ - **Shape operations drop the brush.** Unite, subtract, offset path and outline stroke turn
234
+ brushed strokes into plain filled or stroked paths.
213
235
  - `canvas_*` tools validate ids against the current state; an "Unknown node id" error means call
214
236
  `get_editor_state` again, not guess.
215
237
  - `canvas_add_node` with `nearNodeId` also adds an edge from that node. Pass an explicit
@@ -182,6 +182,10 @@ drawing or editing either.
182
182
  replays the same. To carry dirty paint from stroke to stroke, pass `mixer.loadEachStroke:
183
183
  false` and `cleanEachStroke: false`, start with `load_mixer_brush`, read the brush with
184
184
  `get_mixer_brush` when unsure, and reset it with `clean_mixer_brush`.
185
+ 8. **Gradient paint** (colour that changes as the stroke goes): `set_paint` with `{ type:
186
+ "gradient", stops, map }`, or `paint_stroke` `paint` for one stroke (brush only). `map.by`
187
+ `distance` (default 300 px, mirrored) for drag-it-out colour, `pressure`, `direction`,
188
+ `across-tip`, `random`; stops may be `"paint"` / `"secondary"` (foreground / background).
185
189
 
186
190
  ### Colour management
187
191
 
@@ -370,7 +374,9 @@ in the source frame at the document's bit depth, colour mode and profile. Read
370
374
  | `remove_layer_effect` | Delete one effect. To hide it and keep its settings, set `enabled: false` with `update_layer_effect` instead. Returns the remaining effects. |
371
375
  | `set_layer_effects_enabled` | Switch all of a layer's effects on or off (`enabled`) and optionally set Scale Effects (`scale`, 1 = 100 %, multiplies sizes, distances and pattern scales). Returns the effects. |
372
376
  | `set_global_light` | Set the document light (`angle`, `altitude` in degrees) that every shadow and bevel with `useGlobalLight` follows. Returns the light. |
373
- | `paint_stroke` | Paint (`tool` brush), blend with the Mixer Brush (`tool` mixer) or erase (`tool` eraser) along `points` in document px (optional `pressure` 0..1) on a pixel layer or its mask (`channel`; the mixer paints pixels only); `color` #rrggbb (on a mask: black hides, white reveals; for the mixer, the reservoir colour); `brush` `{size, hardness, spacing, angle, roundness, opacity, flow, smoothing, pressureSize, pressureOpacity, blend}`; `mixer` `{wet, load, mix, loadEachStroke, cleanEachStroke, mixing: rgb \| pigment}` (tool mixer only). The selection limits the paint. One undo step per call. Returns the layer, channel, changed `bounds`, dab count and, for the mixer, `mixerLoad` `{reservoir, amount, pickup}`. |
377
+ | `paint_stroke` | Paint (`tool` brush), blend with the Mixer Brush (`tool` mixer) or erase (`tool` eraser) along `points` in document px (optional `pressure` 0..1) on a pixel layer or its mask (`channel`; the mixer paints pixels only); `color` #rrggbb (on a mask: black hides, white reveals; for the mixer, the reservoir colour) or `paint` (brush only: a gradient for this stroke); `brush` `{size, hardness, spacing, angle, roundness, opacity, flow, smoothing, pressureSize, pressureOpacity, blend}`; `mixer` `{wet, load, mix, loadEachStroke, cleanEachStroke, mixing: rgb \| pigment}` (tool mixer only). The selection limits the paint. One undo step per call. Returns the layer, channel, changed `bounds`, dab count and, for the mixer, `mixerLoad` `{reservoir, amount, pickup}`. |
378
+ | `set_paint` | Set what the brush paints: one colour (it becomes the foreground) or gradient paint (`stops` sorted by offset, `space` pigment / oklab / srgb, `map`, `softness`). Errors say what is wrong. Returns `paint`, `foreground`, `background`, `brush`. |
379
+ | `get_paint` | Read-only. What the brush paints (`paint`), the foreground and background colours and the brush settings. |
374
380
  | `get_mixer_brush` | Read-only. The Mixer Brush settings and what it carries (`reservoir` #rrggbb or null, `amount` left 0..1, `pickup` #rrggbb or null). Call it before a mixer stroke with `loadEachStroke: false`. |
375
381
  | `load_mixer_brush` | Fill the Mixer Brush reservoir with `color` (default the foreground), amount 1; keeps the pickup. View state, not an undo step. Use before strokes with `loadEachStroke: false`. Returns the load. |
376
382
  | `clean_mixer_brush` | Empty the Mixer Brush pickup well (`emptyReservoir: true` also drops the loaded paint, so it only smears). View state, not an undo step. Returns the load. |
@@ -27,9 +27,10 @@
27
27
  (resampled at depth; whole-pixel moves exact) keep the depth (32-bit paint and resampling work
28
28
  in linear light). Layer masks keep the depth too: 16- and 32-bit masks open and save at depth,
29
29
  blend with their full precision, and the brush, eraser, `fill_pixels` and `clear_pixels` paint
30
- them at depth (retouching on a mask stays 8-bit). Layer filters and layer effects still
31
- compute in 8 bits: the pixels they change get 8-bit precision, every pixel they leave alone
32
- keeps its deep samples. Afterwards work with `list_layers` as
30
+ them at depth (retouching on a mask stays 8-bit). Layer filters (develop, blur) and layer
31
+ effects composite at depth in merges, `compositeDeepPixels` and the exported merged image (a
32
+ group's effects and legacy-process develop filters stay 8-bit). The viewport always shows
33
+ the 8-bit rendering. Afterwards work with `list_layers` as
33
34
  usual: there is no Background source image, every pixel comes from the layers.
34
35
  4. **Smart objects come in live**: embedded contents (a PSB opens as a nested document you can
35
36
  edit with `edit_smart_object_contents`, a PNG as raster contents), the placement and warp, the
@@ -187,6 +187,30 @@ is never part of a layer. Coordinates are document pixels, (0, 0) top-left, y do
187
187
  `get_relief` reads a layer's relief; `flatten_relief` removes it but keeps the colour.
188
188
  - **Metallic paper**: `set_paper` `metallic` 0..1 makes the grain sparkle under the light.
189
189
 
190
+ ## Gradient paint
191
+
192
+ Paint that changes colour as the stroke goes: give a gradient where a colour would go.
193
+
194
+ 1. **`set_paint`** with `{ type: "gradient", stops, map }` makes it the paint for every following
195
+ stroke (`set_color` goes back to one colour); `paint_stroke` `paint` overrides it for one stroke;
196
+ a brush can carry its own (`set_brush` `paint`, presets `gradient-round`, `pressure-ombre`,
197
+ `rainbow-marker`, `gradient-wash`).
198
+ 2. **Choose the mapping by what the stroke should do**: `distance` (default, 300 px then
199
+ `mirror` back) for "drag it out" colour; `pressure` for light-to-heavy shading in one stroke;
200
+ `direction` for strokes coloured by their heading; `across-tip` for a brush loaded with several
201
+ colours side by side; `random` (`every` dabs) for speckled or confetti colour; `time` and
202
+ `velocity` need timed points (`t`). Set `length` to about the stroke length you will paint.
203
+ 3. **Stops**: 2..16, sorted by `offset`; `"paint"` / `"secondary"` follow the two editor colours;
204
+ `opacity` multiplies flow (fade a stroke out); `midpoint` shifts where two colours meet;
205
+ `softness` 0 makes hard bands. `space` `pigment` (default) mixes like paint (blue to yellow
206
+ through green), `oklab` keeps rainbows bright.
207
+ 4. **It works with every colour engine**: dab, Mixer Brush (each dab reloads its reservoir),
208
+ watercolour and gouache (each deposit carries its pigment into the wet layer, which then flows
209
+ and mixes), oil and impasto (the colour varies along the relief), particles, bristles and
210
+ stickers. Erasers, blenders and smudges ignore it; the eyedropper picks one colour.
211
+ 5. Strokes record the gradient (with concrete colours), so replays, time-lapses, high-res
212
+ re-renders and drying are exact. `get_brush` `strokePaint` says what the next stroke paints.
213
+
190
214
  ## Procedural brushes, bristles, stickers and stencils
191
215
 
192
216
  - **Particle brushes** (category `procedural`): `hair-strands` (strings of masses dragged behind
@@ -240,9 +264,9 @@ is never part of a layer. Coordinates are document pixels, (0, 0) top-left, y do
240
264
 
241
265
  | Tool | Use |
242
266
  | --- | --- |
243
- | `list_brushes` | Read the library (built-in and saved): id, name, category, engine, size, grain response, rotation, `wetCapable`, `pickup`, `dirty`, `multicolor` mode, `builtin`; plus the active brush id and whether it is edited. |
244
- | `get_brush` | Read every setting of a brush, or of the active brush as edited (no `id`). Read before changing a brush you did not build. |
245
- | `set_brush` | Choose the active brush (`id`) and / or change it: `tip` (size px, hardness, spacing, angle, roundness, opacity, flow, smoothing, pressureSize, pressureOpacity, blend), `grain`, `pressureSmoothing`, `rotation`, `dynamics` (minSize, pressureFlow, tiltSize, tiltRoundness, tiltOpacity, velocitySize, velocityOpacity, jitters, scatter), `engine`, `mixer`, `loadsColor`, `behavior` (pickup, mix, dirty, mixing, multicolor: mode, colors, order, length, softness), `blender` (strength, distance, mixing), `smudge` (strength, length, mixing). Editor state. Returns the brush. |
267
+ | `list_brushes` | Read the library (built-in and saved): id, name, category, engine, size, grain response, rotation, `wetCapable`, `pickup`, `dirty`, `gradient` (has its own gradient paint), `multicolor` mode, `builtin`; plus the active brush id and whether it is edited. |
268
+ | `get_brush` | Read every setting of a brush, or of the active brush as edited (no `id`), including `paint` (its own gradient, or null) and `strokePaint` (what its next stroke paints). Read before changing a brush you did not build. |
269
+ | `set_brush` | Choose the active brush (`id`) and / or change it: `tip` (size px, hardness, spacing, angle, roundness, opacity, flow, smoothing, pressureSize, pressureOpacity, blend), `grain`, `pressureSmoothing`, `rotation`, `dynamics` (minSize, pressureFlow, tiltSize, tiltRoundness, tiltOpacity, velocitySize, velocityOpacity, jitters, scatter), `engine`, `mixer`, `loadsColor`, `behavior` (pickup, mix, dirty, mixing; multicolor is the older form of `paint`), `paint` (the brush's own gradient, or null for the editor's paint), `blender` (strength, distance, mixing), `smudge` (strength, length, mixing). Editor state. Returns the brush. |
246
270
  | `save_brush` | Store the active brush in the user library under `id` (lowercase, digits, dashes) and `name`. Built-in ids are refused. |
247
271
  | `remove_brush` | Delete a user brush. Built-in brushes cannot be removed. |
248
272
  | `export_brushes` | Get a brush library file (JSON) of `ids`, or of every user brush. |
@@ -254,14 +278,15 @@ is never part of a layer. Coordinates are document pixels, (0, 0) top-left, y do
254
278
  | Tool | Use |
255
279
  | --- | --- |
256
280
  | `mix_colors` | Predict a mix: `colors` with `weight` parts (and optional tinting `strength`), `model` `pigment` (default, Kubelka-Munk: what pigment blends, the Mixer Brush, pigment blending tools and the pad do) or `rgb` (what normal blending and rgb mixing do). Returns `mixed` by the model plus `pigment` and `rgbLerp` for comparison. Changes nothing. Use it to choose stroke colours. |
257
- | `set_color` | Set the default paint `color` (and `secondaryColor`). |
281
+ | `set_color` | Set the default paint `color` (and `secondaryColor`); back to one colour after gradient paint. |
282
+ | `set_paint` | Set the paint: one colour, or gradient paint (`stops`, `space`, `map`, `softness`; see Gradient paint). Errors say what is wrong (unsorted stops, a bad mapping). Returns `paint`, `color`, `secondaryColor`. |
258
283
  | `pick_color` | Read the colour at `x`, `y`: of the painting with its paper, or of one layer (with alpha). |
259
284
  | `get_mixer_brush` | Read what the brush carries: the Mixer Brush `reservoir` and `amount` left, and `pickup` (paint picked up, kept by dirty brushes). |
260
285
  | `load_mixer_brush` | Fill the Mixer Brush reservoir with a colour (keeps its pickup). |
261
286
  | `clean_mixer_brush` | Wipe the brush: drop the picked-up paint a dirty brush or the Mixer Brush carries (and with `emptyReservoir` the Mixer Brush paint). |
262
287
  | `color_harmony` | Get a harmony (`kind`: complementary, split-complementary, analogous, triadic, tetradic, square, monochromatic) around `color` (default the paint colour), on the `ryb` painter's wheel (default; red ↔ green) or the `rgb` wheel (red ↔ cyan), `spread` degrees for analogous and split. Changes nothing. |
263
- | `list_swatches` | Read the swatches (index, colour, name). |
264
- | `add_swatch` | Keep a colour as a swatch (saved with the document). |
288
+ | `list_swatches` | Read the swatches (index, colour, name, and `paint` for a gradient swatch). |
289
+ | `add_swatch` | Keep a colour (`color`) or a gradient (`paint`) as a swatch (saved with the document). |
265
290
  | `remove_swatch` | Remove a swatch by `index`. |
266
291
  | `mixing_pad_stroke` | Paint on the 360 × 220 mixing pad (pad px): `tool` paint lays `color` with a pigment Mixer Brush, `knife` smears what is there and mixes it as paint. Scratch space, not the painting, no undo. |
267
292
  | `pick_mixing_pad_color` | Read the mix on the pad at `x`, `y` (averaged over `radius`, default 3); `setColor` makes it the paint colour. Null where the pad is bare. |
@@ -277,7 +302,7 @@ is never part of a layer. Coordinates are document pixels, (0, 0) top-left, y do
277
302
 
278
303
  | Tool | Use |
279
304
  | --- | --- |
280
- | `paint_stroke` | Paint one stroke through `points` (document px; `pressure` 0..1, `t` ms, `tiltX` / `tiltY` or `altitude` / `azimuth`, `twist`) with `brushId` (default the active brush), optional per-stroke `brush` changes, `color`, `layerId`, `seed`, `snapToPerspective`. The symmetry guide adds its copies; a sampling tracing image supplies the colour when `color` is missing. Returns `layerId`, `bounds`, `dabs`, `strokeId` and, for brushes that pick up paint, `mixerLoad` (what the brush carries now). Refused on locked, hidden or group layers, with the fix in the message. |
305
+ | `paint_stroke` | Paint one stroke through `points` (document px; `pressure` 0..1, `t` ms, `tiltX` / `tiltY` or `altitude` / `azimuth`, `twist`) with `brushId` (default the active brush), optional per-stroke `brush` changes, `color` or `paint` (a gradient for this stroke), `layerId`, `seed`, `snapToPerspective`. The symmetry guide adds its copies; a sampling tracing image supplies the colour when `color` is missing. Returns `layerId`, `bounds`, `dabs`, `strokeId` and, for brushes that pick up paint, `mixerLoad` (what the brush carries now). Refused on locked, hidden or group layers, with the fix in the message. |
281
306
  | `list_strokes` | Read the recorded strokes, oldest first (default the last 100): id, layer, brush, colour, point count, seed, bounds. With `ids`, their points too. |
282
307
  | `replay_strokes` | Paint recorded `strokeIds` again: exactly, or varied by `dx` / `dy` (px), `rotate` (degrees clockwise), `scale` (brush size follows), `flipX`, `origin`, `pressureScale`, `color`, `brushId`, `layerId`, `repeat` (each copy applies the variation again). One undo step. Returns the new stroke ids, bounds and layers. |
283
308
  | `undo_paint` | Undo the last step (a wet stroke's undo puts the wet paint back as it was before it). Returns what was undone and what is next. |