@pixerate/editor 0.272.0 → 0.273.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.
- package/dist/agent/index.cjs +34 -32
- package/dist/agent/index.js +10 -8
- package/dist/chart/contract.d.cts +95 -0
- package/dist/chart/contract.d.ts +95 -0
- package/dist/chart/controller.d.cts +4 -0
- package/dist/chart/controller.d.ts +4 -0
- package/dist/chart/index.cjs +492 -26
- package/dist/chart/index.d.cts +1 -0
- package/dist/chart/index.d.ts +1 -0
- package/dist/chart/index.js +476 -10
- package/dist/chart/tools.d.cts +3 -0
- package/dist/chart/tools.d.ts +3 -0
- package/dist/chart-maps/index.cjs +4 -64
- package/dist/chart-maps/index.js +3 -63
- package/dist/chunk-2A5IKZMU.js +557 -0
- package/dist/{chunk-NMZQMPFZ.js → chunk-4LZQO5Y7.js} +2 -0
- package/dist/chunk-5UGRMVNE.js +328 -0
- package/dist/{chunk-X4FTNFIA.js → chunk-7MGPW2OV.js} +1 -1
- package/dist/{chunk-DGITFN73.cjs → chunk-BWJBZAUE.cjs} +8 -8
- package/dist/chunk-CHZYVNXZ.js +336 -0
- package/dist/chunk-DRMZ5R3S.cjs +67 -0
- package/dist/chunk-EI5GFTKG.js +67 -0
- package/dist/chunk-JV7DKLMX.js +1073 -0
- package/dist/chunk-MFBUQC67.cjs +328 -0
- package/dist/{chunk-IBXEQOGI.js → chunk-PYHB2EHE.js} +2 -324
- package/dist/chunk-QEUI6OGE.cjs +336 -0
- package/dist/{chunk-6ZSFRRJI.js → chunk-RSF6BT34.js} +1 -1
- package/dist/chunk-T2HUQBRC.cjs +1073 -0
- package/dist/{chunk-GSLOH2IN.cjs → chunk-VF6ODSYX.cjs} +2 -0
- package/dist/{chunk-NQUKTRKN.cjs → chunk-WZLNNGG3.cjs} +45 -45
- package/dist/{chunk-NRBGAEFI.cjs → chunk-Y3RUYOOW.cjs} +8 -330
- package/dist/chunk-YH6SKC7P.cjs +557 -0
- package/dist/commands/index.cjs +7 -323
- package/dist/commands/index.js +5 -321
- package/dist/extensions/index.cjs +4 -4
- package/dist/extensions/index.js +3 -3
- package/dist/index.cjs +9 -9
- package/dist/index.js +3 -3
- package/dist/paint-editor/controller.d.cts +86 -0
- package/dist/paint-editor/controller.d.ts +86 -0
- package/dist/paint-editor/document.d.cts +1 -1
- package/dist/paint-editor/document.d.ts +1 -1
- package/dist/paint-editor/index.cjs +559 -166
- package/dist/paint-editor/index.d.cts +1 -0
- package/dist/paint-editor/index.d.ts +1 -0
- package/dist/paint-editor/index.js +397 -4
- package/dist/paint-editor/presence.d.cts +5 -1
- package/dist/paint-editor/presence.d.ts +5 -1
- package/dist/paint-editor/ui.d.cts +5 -2
- package/dist/paint-editor/ui.d.ts +5 -2
- package/dist/persistence/index.cjs +24 -1042
- package/dist/persistence/index.js +22 -1040
- package/dist/raster/fill.d.cts +85 -0
- package/dist/raster/fill.d.ts +85 -0
- package/dist/raster/index.cjs +9 -1
- package/dist/raster/index.d.cts +1 -0
- package/dist/raster/index.d.ts +1 -0
- package/dist/raster/index.js +8 -0
- package/dist/tools/index.cjs +5 -3
- package/dist/tools/index.js +8 -6
- package/package.json +1 -1
- package/skills/pixerate-paint-editor/SKILL.md +19 -43
- package/skills/pixerate-paint-editor/references/evolution.md +27 -0
- package/skills/pixerate-paint-sketch-to-finish/SKILL.md +16 -5
- package/skills/pixerate-paint-sketch-to-finish/evals/flats-under-ink.json +2 -3
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { RasterRect } from './surface.cjs';
|
|
2
|
+
export interface FillRegionPoint {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
}
|
|
6
|
+
export interface FillRegionSummary {
|
|
7
|
+
point: {
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
};
|
|
11
|
+
bounds: RasterRect | null;
|
|
12
|
+
pixelCount: number;
|
|
13
|
+
leaked: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface FillRegionMaskOptions {
|
|
16
|
+
/** Seed points in pixel coordinates. */
|
|
17
|
+
points: ReadonlyArray<FillRegionPoint>;
|
|
18
|
+
/** Per-channel RGBA tolerance 0..255 (default 32). */
|
|
19
|
+
tolerance?: number;
|
|
20
|
+
/** Close gaps in line art up to this width in pixels, 0..32 (default 0). */
|
|
21
|
+
closeGap?: number;
|
|
22
|
+
/** Expand (> 0, bleed under lines) or contract (< 0) the filled region in pixels, -16..16 (default 0). */
|
|
23
|
+
expand?: number;
|
|
24
|
+
/** Soften 1 px boundary edges (default true). */
|
|
25
|
+
antialias?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface FillRegionMaskResult {
|
|
28
|
+
/** Per-pixel coverage 0..1 (`width * height`). */
|
|
29
|
+
mask: Float32Array;
|
|
30
|
+
/** Bounding box of all filled pixels, or null if nothing was filled. */
|
|
31
|
+
bounds: RasterRect | null;
|
|
32
|
+
/** Total number of filled pixels (`mask[i] > 0`). */
|
|
33
|
+
pixelCount: number;
|
|
34
|
+
/** True when the filled region touches the canvas edge (`x === 0`, `y === 0`, `x === width - 1`, or `y === height - 1`). */
|
|
35
|
+
leaked: boolean;
|
|
36
|
+
/** Per-seed summary in the order `points` were given. */
|
|
37
|
+
regions: FillRegionSummary[];
|
|
38
|
+
}
|
|
39
|
+
export interface UnfilledRegion {
|
|
40
|
+
/** Interior seed point guaranteed to lie inside the region (deepest interior point / pole of inaccessibility). */
|
|
41
|
+
point: {
|
|
42
|
+
x: number;
|
|
43
|
+
y: number;
|
|
44
|
+
};
|
|
45
|
+
/** Area-weighted centroid rounded to integer pixel coordinates. */
|
|
46
|
+
centroid: {
|
|
47
|
+
x: number;
|
|
48
|
+
y: number;
|
|
49
|
+
};
|
|
50
|
+
/** Tight bounding box of the region. */
|
|
51
|
+
bounds: RasterRect;
|
|
52
|
+
/** Area of the region in pixels. */
|
|
53
|
+
pixelCount: number;
|
|
54
|
+
/** True when the region touches the canvas edge. */
|
|
55
|
+
touchesEdge: boolean;
|
|
56
|
+
}
|
|
57
|
+
export interface FindUnfilledRegionsMaskOptions {
|
|
58
|
+
/** Optional target layer RGBA (`width * height * 4`). Pixels already painted on the target layer count as filled. */
|
|
59
|
+
target?: Uint8ClampedArray | Uint8Array;
|
|
60
|
+
/** Alpha/colour threshold 0..255 above which a reference pixel is treated as a barrier (default 32). */
|
|
61
|
+
tolerance?: number;
|
|
62
|
+
/** Close gaps in line art up to this width in pixels, 0..32 (default 0). */
|
|
63
|
+
closeGap?: number;
|
|
64
|
+
/** Ignore regions smaller than this many pixels (default 16). */
|
|
65
|
+
minArea?: number;
|
|
66
|
+
/** Include regions that touch the canvas border (default false: only enclosed shapes). */
|
|
67
|
+
includeEdge?: boolean;
|
|
68
|
+
/** Maximum number of regions to return, sorted largest first (default 100). */
|
|
69
|
+
maxRegions?: number;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Exact 2D squared Euclidean distance transform (Felzenszwalb & Huttenlocher, O(w * h)).
|
|
73
|
+
* Returns for each pixel the squared distance `(dx^2 + dy^2)` to the nearest `0` in `binary`.
|
|
74
|
+
*/
|
|
75
|
+
export declare function squaredDistanceTransform(binary: Uint8Array, w: number, h: number): Float64Array;
|
|
76
|
+
/**
|
|
77
|
+
* Flood-fills one or more seed points against a reference RGBA buffer (`width * height * 4`),
|
|
78
|
+
* closing line-art gaps up to `closeGap` px and expanding/contracting the filled mask by `expand` px.
|
|
79
|
+
*/
|
|
80
|
+
export declare function fillRegionMask(reference: Uint8ClampedArray | Uint8Array, width: number, height: number, options: FillRegionMaskOptions): FillRegionMaskResult;
|
|
81
|
+
/**
|
|
82
|
+
* Finds enclosed unfilled regions in a reference RGBA buffer (`width * height * 4`),
|
|
83
|
+
* closing gaps up to `closeGap` px and excluding areas already painted on `options.target`.
|
|
84
|
+
*/
|
|
85
|
+
export declare function findUnfilledRegionsMask(reference: Uint8ClampedArray | Uint8Array, width: number, height: number, options?: FindUnfilledRegionsMaskOptions): UnfilledRegion[];
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { RasterRect } from './surface.js';
|
|
2
|
+
export interface FillRegionPoint {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
}
|
|
6
|
+
export interface FillRegionSummary {
|
|
7
|
+
point: {
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
};
|
|
11
|
+
bounds: RasterRect | null;
|
|
12
|
+
pixelCount: number;
|
|
13
|
+
leaked: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface FillRegionMaskOptions {
|
|
16
|
+
/** Seed points in pixel coordinates. */
|
|
17
|
+
points: ReadonlyArray<FillRegionPoint>;
|
|
18
|
+
/** Per-channel RGBA tolerance 0..255 (default 32). */
|
|
19
|
+
tolerance?: number;
|
|
20
|
+
/** Close gaps in line art up to this width in pixels, 0..32 (default 0). */
|
|
21
|
+
closeGap?: number;
|
|
22
|
+
/** Expand (> 0, bleed under lines) or contract (< 0) the filled region in pixels, -16..16 (default 0). */
|
|
23
|
+
expand?: number;
|
|
24
|
+
/** Soften 1 px boundary edges (default true). */
|
|
25
|
+
antialias?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface FillRegionMaskResult {
|
|
28
|
+
/** Per-pixel coverage 0..1 (`width * height`). */
|
|
29
|
+
mask: Float32Array;
|
|
30
|
+
/** Bounding box of all filled pixels, or null if nothing was filled. */
|
|
31
|
+
bounds: RasterRect | null;
|
|
32
|
+
/** Total number of filled pixels (`mask[i] > 0`). */
|
|
33
|
+
pixelCount: number;
|
|
34
|
+
/** True when the filled region touches the canvas edge (`x === 0`, `y === 0`, `x === width - 1`, or `y === height - 1`). */
|
|
35
|
+
leaked: boolean;
|
|
36
|
+
/** Per-seed summary in the order `points` were given. */
|
|
37
|
+
regions: FillRegionSummary[];
|
|
38
|
+
}
|
|
39
|
+
export interface UnfilledRegion {
|
|
40
|
+
/** Interior seed point guaranteed to lie inside the region (deepest interior point / pole of inaccessibility). */
|
|
41
|
+
point: {
|
|
42
|
+
x: number;
|
|
43
|
+
y: number;
|
|
44
|
+
};
|
|
45
|
+
/** Area-weighted centroid rounded to integer pixel coordinates. */
|
|
46
|
+
centroid: {
|
|
47
|
+
x: number;
|
|
48
|
+
y: number;
|
|
49
|
+
};
|
|
50
|
+
/** Tight bounding box of the region. */
|
|
51
|
+
bounds: RasterRect;
|
|
52
|
+
/** Area of the region in pixels. */
|
|
53
|
+
pixelCount: number;
|
|
54
|
+
/** True when the region touches the canvas edge. */
|
|
55
|
+
touchesEdge: boolean;
|
|
56
|
+
}
|
|
57
|
+
export interface FindUnfilledRegionsMaskOptions {
|
|
58
|
+
/** Optional target layer RGBA (`width * height * 4`). Pixels already painted on the target layer count as filled. */
|
|
59
|
+
target?: Uint8ClampedArray | Uint8Array;
|
|
60
|
+
/** Alpha/colour threshold 0..255 above which a reference pixel is treated as a barrier (default 32). */
|
|
61
|
+
tolerance?: number;
|
|
62
|
+
/** Close gaps in line art up to this width in pixels, 0..32 (default 0). */
|
|
63
|
+
closeGap?: number;
|
|
64
|
+
/** Ignore regions smaller than this many pixels (default 16). */
|
|
65
|
+
minArea?: number;
|
|
66
|
+
/** Include regions that touch the canvas border (default false: only enclosed shapes). */
|
|
67
|
+
includeEdge?: boolean;
|
|
68
|
+
/** Maximum number of regions to return, sorted largest first (default 100). */
|
|
69
|
+
maxRegions?: number;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Exact 2D squared Euclidean distance transform (Felzenszwalb & Huttenlocher, O(w * h)).
|
|
73
|
+
* Returns for each pixel the squared distance `(dx^2 + dy^2)` to the nearest `0` in `binary`.
|
|
74
|
+
*/
|
|
75
|
+
export declare function squaredDistanceTransform(binary: Uint8Array, w: number, h: number): Float64Array;
|
|
76
|
+
/**
|
|
77
|
+
* Flood-fills one or more seed points against a reference RGBA buffer (`width * height * 4`),
|
|
78
|
+
* closing line-art gaps up to `closeGap` px and expanding/contracting the filled mask by `expand` px.
|
|
79
|
+
*/
|
|
80
|
+
export declare function fillRegionMask(reference: Uint8ClampedArray | Uint8Array, width: number, height: number, options: FillRegionMaskOptions): FillRegionMaskResult;
|
|
81
|
+
/**
|
|
82
|
+
* Finds enclosed unfilled regions in a reference RGBA buffer (`width * height * 4`),
|
|
83
|
+
* closing gaps up to `closeGap` px and excluding areas already painted on `options.target`.
|
|
84
|
+
*/
|
|
85
|
+
export declare function findUnfilledRegionsMask(reference: Uint8ClampedArray | Uint8Array, width: number, height: number, options?: FindUnfilledRegionsMaskOptions): UnfilledRegion[];
|
package/dist/raster/index.cjs
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
var _chunkYH6SKC7Pcjs = require('../chunk-YH6SKC7P.cjs');
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
5
10
|
|
|
6
11
|
|
|
7
12
|
|
|
@@ -528,4 +533,7 @@ function drawSurfaceToViewport(ctx, surface, mapping, view, options) {
|
|
|
528
533
|
|
|
529
534
|
|
|
530
535
|
|
|
531
|
-
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
exports.BIT_DEPTHS = _chunk2VX55NFMcjs.BIT_DEPTHS; exports.BLEND_MODES = _chunk2VX55NFMcjs.BLEND_MODES; exports.CURVE_LUT_SIZE = _chunkPVJMTLPJcjs.CURVE_LUT_SIZE; exports.DEFAULT_GLOBAL_LIGHT = _chunkPVJMTLPJcjs.DEFAULT_GLOBAL_LIGHT; exports.DIRECT_GAUSSIAN_MAX_SIGMA = _chunkK6PXS6DOcjs.DIRECT_GAUSSIAN_MAX_SIGMA; exports.DeepCompositor = _chunkPVJMTLPJcjs.DeepCompositor; exports.INTERPOLATIONS = _chunkPVJMTLPJcjs.INTERPOLATIONS; exports.LAYER_EFFECT_KINDS = _chunkPVJMTLPJcjs.LAYER_EFFECT_KINDS; exports.LAYER_EFFECT_MENU = _chunkPVJMTLPJcjs.LAYER_EFFECT_MENU; exports.LayerEffectError = _chunkPVJMTLPJcjs.LayerEffectError; exports.MAX_EFFECT_REACH = _chunkPVJMTLPJcjs.MAX_EFFECT_REACH; exports.MAX_TRANSFORM_PIXELS = _chunkPVJMTLPJcjs.MAX_TRANSFORM_PIXELS; exports.PAINTERLY_BLEND_MODES = _chunk2VX55NFMcjs.PAINTERLY_BLEND_MODES; exports.PatternPlacement = _chunkPVJMTLPJcjs.PatternPlacement; exports.PatternTile = _chunkPVJMTLPJcjs.PatternTile; exports.RasterCompositor = _chunkPVJMTLPJcjs.RasterCompositor; exports.SHADOW_AMBIENT = _chunk2VX55NFMcjs.SHADOW_AMBIENT; exports.STROKE_CHAMFER_MAX = _chunkPVJMTLPJcjs.STROKE_CHAMFER_MAX; exports.SurfaceDraft = _chunk474IQG74cjs.SurfaceDraft; exports.SurfaceViewportRenderer = SurfaceViewportRenderer; exports.TILE = _chunk474IQG74cjs.TILE; exports.TILE_SHIFT = _chunk474IQG74cjs.TILE_SHIFT; exports.TiledSurface = _chunk474IQG74cjs.TiledSurface; exports.TransformTooLargeError = _chunkPVJMTLPJcjs.TransformTooLargeError; exports.ZlibError = _chunkXFM3OCHUcjs.ZlibError; exports.activeEffectItems = _chunkPVJMTLPJcjs.activeEffectItems; exports.adler32 = _chunkXFM3OCHUcjs.adler32; exports.applyEdgeAmbient = _chunkPVJMTLPJcjs.applyEdgeAmbient; exports.base64ToBytes = _chunkW5M3J7PVcjs.base64ToBytes; exports.blendChannel = _chunk2VX55NFMcjs.blendChannel; exports.blendImageData = _chunk2VX55NFMcjs.blendImageData; exports.blendLum = _chunk2VX55NFMcjs.blendLum; exports.blendPixel = _chunk2VX55NFMcjs.blendPixel; exports.blendRgb = _chunk2VX55NFMcjs.blendRgb; exports.blendTile = _chunkPVJMTLPJcjs.blendTile; exports.buildEffectMaps = _chunkPVJMTLPJcjs.buildEffectMaps; exports.builtinPattern = _chunkPVJMTLPJcjs.builtinPattern; exports.builtinPatternIds = _chunkPVJMTLPJcjs.builtinPatternIds; exports.bytesToBase64 = _chunkW5M3J7PVcjs.bytesToBase64; exports.canvasCompositeOperation = _chunk2VX55NFMcjs.canvasCompositeOperation; exports.changedTiles = _chunkPVJMTLPJcjs.changedTiles; exports.collectTiles = _chunk474IQG74cjs.collectTiles; exports.compositeLayerEffects = _chunkPVJMTLPJcjs.compositeLayerEffects; exports.compositeSurfaceOver = _chunkPVJMTLPJcjs.compositeSurfaceOver; exports.contentBounds = _chunk474IQG74cjs.contentBounds; exports.contourLut = _chunkPVJMTLPJcjs.contourLut; exports.convertSurfaceDepth = _chunk2VX55NFMcjs.convertSurfaceDepth; exports.curveLut = _chunkPVJMTLPJcjs.curveLut; exports.decodePng = _chunkW5M3J7PVcjs.decodePng; exports.deepBytes = _chunk2VX55NFMcjs.deepBytes; exports.deepTile = _chunk2VX55NFMcjs.deepTile; exports.defaultEffectGradient = _chunkPVJMTLPJcjs.defaultEffectGradient; exports.defaultLayerEffect = _chunkPVJMTLPJcjs.defaultLayerEffect; exports.deflate = _chunkXFM3OCHUcjs.deflate; exports.deflateRaw = _chunkXFM3OCHUcjs.deflateRaw; exports.depthOf = _chunk2VX55NFMcjs.depthOf; exports.drawSurfaceToViewport = drawSurfaceToViewport; exports.effectColorHex = _chunkPVJMTLPJcjs.effectColorHex; exports.effectControlChange = _chunkPVJMTLPJcjs.effectControlChange; exports.effectFillColors = _chunkPVJMTLPJcjs.effectFillColors; exports.effectReach = _chunkPVJMTLPJcjs.effectReach; exports.effectsAreLocal = _chunkPVJMTLPJcjs.effectsAreLocal; exports.effectsFingerprint = _chunkPVJMTLPJcjs.effectsFingerprint; exports.effectsMargin = _chunkPVJMTLPJcjs.effectsMargin; exports.effectsScale = _chunkPVJMTLPJcjs.effectsScale; exports.emptySurface = _chunk474IQG74cjs.emptySurface; exports.encodePng = _chunkW5M3J7PVcjs.encodePng; exports.fillRect = _chunk474IQG74cjs.fillRect; exports.fillRegionMask = _chunkYH6SKC7Pcjs.fillRegionMask; exports.findLayer = _chunkPVJMTLPJcjs.findLayer; exports.findUnfilledRegionsMask = _chunkYH6SKC7Pcjs.findUnfilledRegionsMask; exports.finishTile = _chunk474IQG74cjs.finishTile; exports.flattenLayers = _chunkPVJMTLPJcjs.flattenLayers; exports.gaussianBlur = _chunkK6PXS6DOcjs.gaussianBlur; exports.gradientT = _chunkPVJMTLPJcjs.gradientT; exports.hasActiveEffects = _chunkPVJMTLPJcjs.hasActiveEffects; exports.hashNoise = _chunkPVJMTLPJcjs.hashNoise; exports.inflate = _chunkXFM3OCHUcjs.inflate; exports.inflateRaw = _chunkXFM3OCHUcjs.inflateRaw; exports.insertLayer = _chunkPVJMTLPJcjs.insertLayer; exports.isBitDepth = _chunk2VX55NFMcjs.isBitDepth; exports.isBlendMode = _chunk2VX55NFMcjs.isBlendMode; exports.isInterpolation = _chunkPVJMTLPJcjs.isInterpolation; exports.isLayerEffectKind = _chunkPVJMTLPJcjs.isLayerEffectKind; exports.isLayerLocked = _chunkPVJMTLPJcjs.isLayerLocked; exports.isPainterlyBlendMode = _chunk2VX55NFMcjs.isPainterlyBlendMode; exports.isPng = _chunkW5M3J7PVcjs.isPng; exports.isSeparableBlendMode = _chunk2VX55NFMcjs.isSeparableBlendMode; exports.keepDeepSamples = _chunk2VX55NFMcjs.keepDeepSamples; exports.keysWeight = _chunkPVJMTLPJcjs.keysWeight; exports.layerEffectControls = _chunkPVJMTLPJcjs.layerEffectControls; exports.layerEffectFields = _chunkPVJMTLPJcjs.layerEffectFields; exports.layerEffectLabel = _chunkPVJMTLPJcjs.layerEffectLabel; exports.layerEffectsBadge = _chunkPVJMTLPJcjs.layerEffectsBadge; exports.layerEffectsPanel = _chunkPVJMTLPJcjs.layerEffectsPanel; exports.mapLayer = _chunkPVJMTLPJcjs.mapLayer; exports.mergeLayerEffect = _chunkPVJMTLPJcjs.mergeLayerEffect; exports.mixPigment8 = _chunk2VX55NFMcjs.mixPigment8; exports.mixPigmentRgb = _chunk2VX55NFMcjs.mixPigmentRgb; exports.newEffectId = _chunkPVJMTLPJcjs.newEffectId; exports.normalizeBlendMode = _chunk2VX55NFMcjs.normalizeBlendMode; exports.normalizeLayerEffects = _chunkPVJMTLPJcjs.normalizeLayerEffects; exports.packRgba = _chunk474IQG74cjs.packRgba; exports.parseDataUrl = _chunkW5M3J7PVcjs.parseDataUrl; exports.parseEffectColor = _chunkPVJMTLPJcjs.parseEffectColor; exports.patchEffectMaps = _chunkPVJMTLPJcjs.patchEffectMaps; exports.pigment8 = _chunk2VX55NFMcjs.pigment8; exports.pngDataUrl = _chunkW5M3J7PVcjs.pngDataUrl; exports.proxyOf = _chunk2VX55NFMcjs.proxyOf; exports.readDeepRegion = _chunk2VX55NFMcjs.readDeepRegion; exports.readPixel = _chunk474IQG74cjs.readPixel; exports.readRegion = _chunk474IQG74cjs.readRegion; exports.reduceSurface = _chunkPVJMTLPJcjs.reduceSurface; exports.renderLayerEffects = _chunkPVJMTLPJcjs.renderLayerEffects; exports.scaleLayerEffect = _chunkPVJMTLPJcjs.scaleLayerEffect; exports.screenToWorld = screenToWorld; exports.setLum = _chunk2VX55NFMcjs.setLum; exports.solidSurface = _chunk474IQG74cjs.solidSurface; exports.squaredDistanceTransform = _chunkYH6SKC7Pcjs.squaredDistanceTransform; exports.srgbDecode = _chunk2VX55NFMcjs.srgbDecode; exports.srgbEncode = _chunk2VX55NFMcjs.srgbEncode; exports.standardBlendMode = _chunk2VX55NFMcjs.standardBlendMode; exports.surfaceBytes = _chunk474IQG74cjs.surfaceBytes; exports.surfaceDepth = _chunk2VX55NFMcjs.surfaceDepth; exports.surfaceFromDeepPixels = _chunk2VX55NFMcjs.surfaceFromDeepPixels; exports.surfaceFromPixels = _chunk474IQG74cjs.surfaceFromPixels; exports.surfaceMipLevel = surfaceMipLevel; exports.surfaceResolutionForZoom = surfaceResolutionForZoom; exports.surfaceToWorld = surfaceToWorld; exports.surfacesEqual = _chunk474IQG74cjs.surfacesEqual; exports.tileCoord = _chunk474IQG74cjs.tileCoord; exports.tileKey = _chunk474IQG74cjs.tileKey; exports.tileRect = _chunk474IQG74cjs.tileRect; exports.tileSamples = _chunk2VX55NFMcjs.tileSamples; exports.tileSamples16 = _chunk2VX55NFMcjs.tileSamples16; exports.tileSamples32 = _chunk2VX55NFMcjs.tileSamples32; exports.tilesInRect = _chunk474IQG74cjs.tilesInRect; exports.to16From32 = _chunk2VX55NFMcjs.to16From32; exports.to16From8 = _chunk2VX55NFMcjs.to16From8; exports.to32From16 = _chunk2VX55NFMcjs.to32From16; exports.to32From8 = _chunk2VX55NFMcjs.to32From8; exports.to8From16 = _chunk2VX55NFMcjs.to8From16; exports.to8From32 = _chunk2VX55NFMcjs.to8From32; exports.transformSurface = _chunkPVJMTLPJcjs.transformSurface; exports.transformedBounds = _chunkPVJMTLPJcjs.transformedBounds; exports.translateSurface = _chunk474IQG74cjs.translateSurface; exports.uniformTile = _chunk474IQG74cjs.uniformTile; exports.validateEffectGradient = _chunkPVJMTLPJcjs.validateEffectGradient; exports.validateLayerEffect = _chunkPVJMTLPJcjs.validateLayerEffect; exports.validateLayerEffects = _chunkPVJMTLPJcjs.validateLayerEffects; exports.visibleSurfaceRect = visibleSurfaceRect; exports.visibleWorldRect = visibleWorldRect; exports.warpSurface = _chunkPVJMTLPJcjs.warpSurface; exports.workingToSamples = _chunkPVJMTLPJcjs.workingToSamples; exports.worldRectToSurface = worldRectToSurface; exports.worldToSurface = worldToSurface; exports.writeDeepRegion = _chunk2VX55NFMcjs.writeDeepRegion; exports.writeRegion = _chunk474IQG74cjs.writeRegion;
|
package/dist/raster/index.d.cts
CHANGED
|
@@ -23,3 +23,4 @@ export { activeEffectItems, buildEffectMaps, compositeLayerEffects, contourLut,
|
|
|
23
23
|
export { encodePng, decodePng, isPng, bytesToBase64, base64ToBytes, parseDataUrl, pngDataUrl, type DecodedPng } from './png.cjs';
|
|
24
24
|
export { inflate, inflateRaw, deflate, deflateRaw, adler32, ZlibError } from './zlib.cjs';
|
|
25
25
|
export * from './viewport.cjs';
|
|
26
|
+
export * from './fill.cjs';
|
package/dist/raster/index.d.ts
CHANGED
|
@@ -23,3 +23,4 @@ export { activeEffectItems, buildEffectMaps, compositeLayerEffects, contourLut,
|
|
|
23
23
|
export { encodePng, decodePng, isPng, bytesToBase64, base64ToBytes, parseDataUrl, pngDataUrl, type DecodedPng } from './png.js';
|
|
24
24
|
export { inflate, inflateRaw, deflate, deflateRaw, adler32, ZlibError } from './zlib.js';
|
|
25
25
|
export * from './viewport.js';
|
|
26
|
+
export * from './fill.js';
|
package/dist/raster/index.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
fillRegionMask,
|
|
3
|
+
findUnfilledRegionsMask,
|
|
4
|
+
squaredDistanceTransform
|
|
5
|
+
} from "../chunk-2A5IKZMU.js";
|
|
1
6
|
import {
|
|
2
7
|
CURVE_LUT_SIZE,
|
|
3
8
|
DEFAULT_GLOBAL_LIGHT,
|
|
@@ -441,7 +446,9 @@ export {
|
|
|
441
446
|
emptySurface,
|
|
442
447
|
encodePng,
|
|
443
448
|
fillRect,
|
|
449
|
+
fillRegionMask,
|
|
444
450
|
findLayer,
|
|
451
|
+
findUnfilledRegionsMask,
|
|
445
452
|
finishTile,
|
|
446
453
|
flattenLayers,
|
|
447
454
|
gaussianBlur,
|
|
@@ -489,6 +496,7 @@ export {
|
|
|
489
496
|
screenToWorld,
|
|
490
497
|
setLum,
|
|
491
498
|
solidSurface,
|
|
499
|
+
squaredDistanceTransform,
|
|
492
500
|
srgbDecode,
|
|
493
501
|
srgbEncode,
|
|
494
502
|
standardBlendMode,
|
package/dist/tools/index.cjs
CHANGED
|
@@ -18,21 +18,23 @@
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
|
|
21
|
+
var _chunkY3RUYOOWcjs = require('../chunk-Y3RUYOOW.cjs');
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
|
|
26
|
-
var _chunkNRBGAEFIcjs = require('../chunk-NRBGAEFI.cjs');
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
|
|
30
|
+
var _chunkZEKI6EPIcjs = require('../chunk-ZEKI6EPI.cjs');
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
|
|
37
|
+
var _chunkMFBUQC67cjs = require('../chunk-MFBUQC67.cjs');
|
|
36
38
|
|
|
37
39
|
|
|
38
40
|
|
|
@@ -221,4 +223,4 @@ var _chunk2BSBFBOAcjs = require('../chunk-2BSBFBOA.cjs');
|
|
|
221
223
|
|
|
222
224
|
|
|
223
225
|
|
|
224
|
-
exports.AgentPlayback = _chunk3SLBXKAWcjs.AgentPlayback; exports.CAPTURE_EXCLUDE_SELECTOR = _chunkSVFEVKLFcjs.CAPTURE_EXCLUDE_SELECTOR; exports.CAPTURE_OVERLAY_SELECTORS = _chunkSVFEVKLFcjs.CAPTURE_OVERLAY_SELECTORS; exports.CONFORMANCE_BINARY_MIN_LENGTH =
|
|
226
|
+
exports.AgentPlayback = _chunk3SLBXKAWcjs.AgentPlayback; exports.CAPTURE_EXCLUDE_SELECTOR = _chunkSVFEVKLFcjs.CAPTURE_EXCLUDE_SELECTOR; exports.CAPTURE_OVERLAY_SELECTORS = _chunkSVFEVKLFcjs.CAPTURE_OVERLAY_SELECTORS; exports.CONFORMANCE_BINARY_MIN_LENGTH = _chunkY3RUYOOWcjs.CONFORMANCE_BINARY_MIN_LENGTH; exports.CONFORMANCE_NUMBER_TOLERANCE = _chunkY3RUYOOWcjs.CONFORMANCE_NUMBER_TOLERANCE; exports.ConformanceIds = _chunkY3RUYOOWcjs.ConformanceIds; exports.EDITOR_CANVAS_TOOLS = _chunkSVFEVKLFcjs.EDITOR_CANVAS_TOOLS; exports.EDITOR_MCP_TOOLS = _chunkSVFEVKLFcjs.EDITOR_MCP_TOOLS; exports.EDITOR_PROMPT_TOOLS = _chunkSVFEVKLFcjs.EDITOR_PROMPT_TOOLS; exports.EDIT_OPERATION_REQUIRED_ARGUMENTS = _chunkSVFEVKLFcjs.EDIT_OPERATION_REQUIRED_ARGUMENTS; exports.EXPORT_EXCLUDED_SELECTORS = _chunkSVFEVKLFcjs.EXPORT_EXCLUDED_SELECTORS; exports.JSON_RPC_ERRORS = _chunkZEKI6EPIcjs.JSON_RPC_ERRORS; exports.MCP_PROTOCOL_VERSIONS = _chunkZEKI6EPIcjs.MCP_PROTOCOL_VERSIONS; exports.MCP_TOOL_CANVAS_ADD_NODE = _chunkSVFEVKLFcjs.MCP_TOOL_CANVAS_ADD_NODE; exports.MCP_TOOL_CANVAS_CONNECT = _chunkSVFEVKLFcjs.MCP_TOOL_CANVAS_CONNECT; exports.MCP_TOOL_CANVAS_HIGHLIGHT = _chunkSVFEVKLFcjs.MCP_TOOL_CANVAS_HIGHLIGHT; exports.MCP_TOOL_CANVAS_LAYOUT = _chunkSVFEVKLFcjs.MCP_TOOL_CANVAS_LAYOUT; exports.MCP_TOOL_CANVAS_REMOVE_NODES = _chunkSVFEVKLFcjs.MCP_TOOL_CANVAS_REMOVE_NODES; exports.MCP_TOOL_CANVAS_SELECT = _chunkSVFEVKLFcjs.MCP_TOOL_CANVAS_SELECT; exports.MCP_TOOL_CANVAS_UPDATE_NODE = _chunkSVFEVKLFcjs.MCP_TOOL_CANVAS_UPDATE_NODE; exports.MCP_TOOL_EDIT_CANVAS = _chunkSVFEVKLFcjs.MCP_TOOL_EDIT_CANVAS; exports.MCP_TOOL_EDIT_PROMPT = _chunkSVFEVKLFcjs.MCP_TOOL_EDIT_PROMPT; exports.MCP_TOOL_GET_EDITOR_STATE = _chunkSVFEVKLFcjs.MCP_TOOL_GET_EDITOR_STATE; exports.MCP_TOOL_PROMPT_INSERT_TEXT = _chunkSVFEVKLFcjs.MCP_TOOL_PROMPT_INSERT_TEXT; exports.MCP_TOOL_PROMPT_REPLACE_RANGE = _chunkSVFEVKLFcjs.MCP_TOOL_PROMPT_REPLACE_RANGE; exports.MCP_TOOL_PROMPT_SELECT = _chunkSVFEVKLFcjs.MCP_TOOL_PROMPT_SELECT; exports.MCP_TOOL_PROMPT_SET_VARIABLE = _chunkSVFEVKLFcjs.MCP_TOOL_PROMPT_SET_VARIABLE; exports.MCP_TOOL_VIEW_EDITOR = _chunkSVFEVKLFcjs.MCP_TOOL_VIEW_EDITOR; exports.PRESENCE_COLORS = _chunkK7ENM55Pcjs.PRESENCE_COLORS; exports.PerformanceQueue = _chunkK7ENM55Pcjs.PerformanceQueue; exports.PresenceStore = _chunkK7ENM55Pcjs.PresenceStore; exports.TOOL_BRIDGE_DEFAULT_PORT = _chunkZEKI6EPIcjs.TOOL_BRIDGE_DEFAULT_PORT; exports.TOOL_BRIDGE_PROTOCOL = _chunkZEKI6EPIcjs.TOOL_BRIDGE_PROTOCOL; exports.TOOL_DISCOVERY_TOOLS = _chunk7TD63DZPcjs.TOOL_DISCOVERY_TOOLS; exports.TOOL_NAMESPACE_SEPARATOR = _chunk7TD63DZPcjs.TOOL_NAMESPACE_SEPARATOR; exports.ToolRegistry = _chunk7TD63DZPcjs.ToolRegistry; exports.ToolRegistryError = _chunk7TD63DZPcjs.ToolRegistryError; exports.ToolRegistryView = _chunk7TD63DZPcjs.ToolRegistryView; exports.UNSAFE_JSON_KEYS = _chunk2BSBFBOAcjs.UNSAFE_JSON_KEYS; exports.baseToolName = _chunk7TD63DZPcjs.baseToolName; exports.callEvalTool = _chunkY3RUYOOWcjs.callEvalTool; exports.captureInputSchema = _chunkN2FGYZ4Qcjs.captureInputSchema; exports.captureOutputSize = _chunkN2FGYZ4Qcjs.captureOutputSize; exports.cloneElementWithStyles = _chunkSVFEVKLFcjs.cloneElementWithStyles; exports.conformanceResult = _chunkY3RUYOOWcjs.conformanceResult; exports.conformanceValuesMatch = _chunkY3RUYOOWcjs.conformanceValuesMatch; exports.connectToolBridge = _chunkZEKI6EPIcjs.connectToolBridge; exports.createAgentPlayback = _chunk3SLBXKAWcjs.createAgentPlayback; exports.createCaptureTool = _chunkN2FGYZ4Qcjs.createCaptureTool; exports.createCaptureToolProvider = _chunkN2FGYZ4Qcjs.createCaptureToolProvider; exports.createElementCaptureSurface = _chunkSVFEVKLFcjs.createElementCaptureSurface; exports.createInstantPresenceClock = _chunkK7ENM55Pcjs.createInstantPresenceClock; exports.createMcpServer = _chunkZEKI6EPIcjs.createMcpServer; exports.createOriginMiddleware = _chunkY3RUYOOWcjs.createOriginMiddleware; exports.createPlaybackToolProvider = _chunk3SLBXKAWcjs.createPlaybackToolProvider; exports.createStyleResolver = _chunkMFBUQC67cjs.createStyleResolver; exports.createStyleToolProvider = _chunkY3RUYOOWcjs.createStyleToolProvider; exports.createToolRegistry = _chunk7TD63DZPcjs.createToolRegistry; exports.derivePlaybackSteps = _chunk3SLBXKAWcjs.derivePlaybackSteps; exports.elementToSvg = _chunkSVFEVKLFcjs.elementToSvg; exports.errorResult = _chunk7TD63DZPcjs.errorResult; exports.failedEvalChecks = _chunkY3RUYOOWcjs.failedEvalChecks; exports.imageEvalFixturePixels = _chunkY3RUYOOWcjs.imageEvalFixturePixels; exports.isUnsafeJsonKey = _chunk2BSBFBOAcjs.isUnsafeJsonKey; exports.listSkillEvals = _chunkY3RUYOOWcjs.listSkillEvals; exports.listSkills = _chunk7TD63DZPcjs.listSkills; exports.locatePlaybackChrome = _chunk3SLBXKAWcjs.locatePlaybackChrome; exports.matchesEvalExpectation = _chunkY3RUYOOWcjs.matchesEvalExpectation; exports.memoryStyleStore = _chunkMFBUQC67cjs.memoryStyleStore; exports.normalizeConformanceValue = _chunkY3RUYOOWcjs.normalizeConformanceValue; exports.omitConformancePaths = _chunkY3RUYOOWcjs.omitConformancePaths; exports.parseSkillFrontmatter = _chunk7TD63DZPcjs.parseSkillFrontmatter; exports.parseStyleDomains = _chunkMFBUQC67cjs.parseStyleDomains; exports.playbackRectFromClient = _chunk3SLBXKAWcjs.playbackRectFromClient; exports.playbackRefsFromArgs = _chunk3SLBXKAWcjs.playbackRefsFromArgs; exports.playbackRefsFromResult = _chunk3SLBXKAWcjs.playbackRefsFromResult; exports.rasterizeElement = _chunkSVFEVKLFcjs.rasterizeElement; exports.readSkillFile = _chunk7TD63DZPcjs.readSkillFile; exports.readingTime = _chunk3SLBXKAWcjs.readingTime; exports.realPresenceClock = _chunkK7ENM55Pcjs.realPresenceClock; exports.renderStyle = _chunkMFBUQC67cjs.renderStyle; exports.resolveCaptureRequest = _chunkN2FGYZ4Qcjs.resolveCaptureRequest; exports.resolveConformanceArguments = _chunkY3RUYOOWcjs.resolveConformanceArguments; exports.runConformanceScenario = _chunkY3RUYOOWcjs.runConformanceScenario; exports.runStyleChecks = _chunkMFBUQC67cjs.runStyleChecks; exports.runToolScript = _chunkY3RUYOOWcjs.runToolScript; exports.searchTokens = _chunk7TD63DZPcjs.searchTokens; exports.searchTools = _chunk7TD63DZPcjs.searchTools; exports.stripPrototypeKeys = _chunk2BSBFBOAcjs.stripPrototypeKeys; exports.summarize = _chunk7TD63DZPcjs.summarize; exports.toCapturedImageData = _chunkN2FGYZ4Qcjs.toCapturedImageData; exports.toToolResult = _chunk7TD63DZPcjs.toToolResult; exports.toolResultError = _chunkY3RUYOOWcjs.toolResultError; exports.toolResultValue = _chunkY3RUYOOWcjs.toolResultValue; exports.toolsetInstructions = _chunkZEKI6EPIcjs.toolsetInstructions; exports.toolsetName = _chunk7TD63DZPcjs.toolsetName; exports.trackPresenceDrag = _chunkK7ENM55Pcjs.trackPresenceDrag; exports.tweenPresenceCursor = _chunkK7ENM55Pcjs.tweenPresenceCursor; exports.unionCaptureRects = _chunkN2FGYZ4Qcjs.unionCaptureRects; exports.unionRects = _chunk3SLBXKAWcjs.unionRects; exports.unknownToolMessage = _chunk7TD63DZPcjs.unknownToolMessage; exports.validateJsonSchema = _chunkWOFXZ3XUcjs.validateJsonSchema;
|
package/dist/tools/index.js
CHANGED
|
@@ -6,24 +6,19 @@ import {
|
|
|
6
6
|
conformanceResult,
|
|
7
7
|
conformanceValuesMatch,
|
|
8
8
|
createOriginMiddleware,
|
|
9
|
-
createStyleResolver,
|
|
10
9
|
createStyleToolProvider,
|
|
11
10
|
failedEvalChecks,
|
|
12
11
|
imageEvalFixturePixels,
|
|
13
12
|
listSkillEvals,
|
|
14
13
|
matchesEvalExpectation,
|
|
15
|
-
memoryStyleStore,
|
|
16
14
|
normalizeConformanceValue,
|
|
17
15
|
omitConformancePaths,
|
|
18
|
-
parseStyleDomains,
|
|
19
|
-
renderStyle,
|
|
20
16
|
resolveConformanceArguments,
|
|
21
17
|
runConformanceScenario,
|
|
22
|
-
runStyleChecks,
|
|
23
18
|
runToolScript,
|
|
24
19
|
toolResultError,
|
|
25
20
|
toolResultValue
|
|
26
|
-
} from "../chunk-
|
|
21
|
+
} from "../chunk-PYHB2EHE.js";
|
|
27
22
|
import {
|
|
28
23
|
JSON_RPC_ERRORS,
|
|
29
24
|
MCP_PROTOCOL_VERSIONS,
|
|
@@ -33,6 +28,13 @@ import {
|
|
|
33
28
|
createMcpServer,
|
|
34
29
|
toolsetInstructions
|
|
35
30
|
} from "../chunk-SYEOA5MS.js";
|
|
31
|
+
import {
|
|
32
|
+
createStyleResolver,
|
|
33
|
+
memoryStyleStore,
|
|
34
|
+
parseStyleDomains,
|
|
35
|
+
renderStyle,
|
|
36
|
+
runStyleChecks
|
|
37
|
+
} from "../chunk-5UGRMVNE.js";
|
|
36
38
|
import {
|
|
37
39
|
TOOL_DISCOVERY_TOOLS,
|
|
38
40
|
TOOL_NAMESPACE_SEPARATOR,
|
package/package.json
CHANGED
|
@@ -77,36 +77,14 @@ the pitfalls, and uses the tools below.
|
|
|
77
77
|
`new_canvas` with `paper`): cold pressed or rough for broken, sparkling texture, sanded pastel
|
|
78
78
|
paper for pastel, charcoal paper for charcoal, cotton canvas or gesso for painterly work,
|
|
79
79
|
smooth bristol for ink. Set `depth` for how much texture you want.
|
|
80
|
-
3. **Block in big shapes first.** Put each pass on its own layer (`add_layer` with a name).
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
in given parts look like (Kubelka-Munk: blue and yellow make green, white tints rather than
|
|
87
|
-
greys); the mixing pad (`mixing_pad_stroke`, `pick_mixing_pad_color`) mixes by hand with a
|
|
88
|
-
palette knife. Keep chosen colours as swatches (`add_swatch`). Use the result as the stroke
|
|
89
|
-
`color`; `set_color` makes it the default.
|
|
90
|
-
5. **Refine** with smaller brushes on new layers: pencil and ink for line, charcoal for value.
|
|
91
|
-
**Blend** on the layer that holds the paint: `blender` to melt neighbouring colours together
|
|
92
|
-
(pigment mixing, so blue next to yellow goes green), `smudge` / `wet-smudge` to drag paint
|
|
93
|
-
into soft edges and streaks, `mixer-brush` to paint wet into wet, `dirty-round` to paint with
|
|
94
|
-
a brush that picks up and carries colour, `multicolor-flat` for strokes loaded with several
|
|
95
|
-
colours. Glaze with a `watercolor` layer, warm or cool with `tint`, light with `highlight`,
|
|
96
|
-
shade with `shadow`.
|
|
97
|
-
6. **Let the guides multiply your marks.** `set_symmetry` (mirror for faces and vases,
|
|
98
|
-
kaleidoscope for mandalas and ornaments) paints every copy from one stroke;
|
|
99
|
-
`set_perspective_guide` plus `paint_stroke` with `snapToPerspective` lays converging lines for
|
|
100
|
-
buildings and roads. To copy an image's composition and colours, `set_tracing_image` with
|
|
101
|
-
`sampleColors` and paint over it.
|
|
102
|
-
7. **Repeat and vary instead of drawing every mark.** Paint one good stroke, then
|
|
103
|
-
`replay_strokes` it with `dx` / `dy`, `rotate`, `scale`, `flipX`, `color`, `brushId` and
|
|
104
|
-
`repeat` for hatching, grass, foliage, rows, fans or spirals, in one undo step.
|
|
105
|
-
8. **Check** with `render_preview` after each block of work, not after each stroke.
|
|
106
|
-
`pick_color` reads exact values. Undo what made it worse.
|
|
80
|
+
3. **Block in big shapes first.** Put each pass on its own layer (`add_layer` with a name). `fill_layer` gives a ground colour (flat) or a tonal layer that catches the grain (`grain` 0.6..1, `pressure` 0.2..0.6). For line art, call `find_unfilled_regions` against the ink layer (`reference: inkLayerId`, `closeGap: 4..8`) to list enclosed shapes and their interior seed points, then `fill_region` on a flats layer below the ink (`reference: inkLayerId`, `closeGap: 4..8`, `expand: 1..2` so no halo shows at anti-aliased line edges, or `wet: true` to pour a watercolour wash into the region). For unoutlined masses, paint with a big soft pastel or airbrush in a few long `paint_stroke`s rather than many small ones.
|
|
81
|
+
4. **Plan and mix colours before painting.** `color_harmony` gives a palette around a key colour (on the painter's red-yellow-blue wheel by default). `mix_colors` predicts what paints mixed in given parts look like (Kubelka-Munk: blue and yellow make green, white tints rather than greys); the mixing pad (`mixing_pad_stroke`, `pick_mixing_pad_color`) mixes by hand with a palette knife. Keep chosen colours as swatches (`add_swatch`). Use the result as the stroke `color`; `set_color` makes it the default.
|
|
82
|
+
5. **Refine** with smaller brushes on new layers: pencil and ink for line, charcoal for value. **Blend** on the layer that holds the paint: `blender` to melt neighbouring colours together (pigment mixing, so blue next to yellow goes green), `smudge` / `wet-smudge` to drag paint into soft edges and streaks, `mixer-brush` to paint wet into wet, `dirty-round` to paint with a brush that picks up and carries colour, `multicolor-flat` for strokes loaded with several colours. Glaze with a `watercolor` layer, warm or cool with `tint`, light with `highlight`, shade with `shadow`.
|
|
83
|
+
6. **Let the guides multiply your marks.** `set_symmetry` (mirror for faces and vases, kaleidoscope for mandalas and ornaments) paints every copy from one stroke; `set_perspective_guide` plus `paint_stroke` with `snapToPerspective` lays converging lines for buildings and roads. To copy an image's composition and colours, `set_tracing_image` with `sampleColors` and paint over it.
|
|
84
|
+
7. **Repeat and vary instead of drawing every mark.** Paint one good stroke, then `replay_strokes` it with `dx` / `dy`, `rotate`, `scale`, `flipX`, `color`, `brushId` and `repeat` for hatching, grass, foliage, rows, fans or spirals, in one undo step.
|
|
85
|
+
8. **Check** with `render_preview` after each block of work, not after each stroke. `pick_color` reads exact values. Undo what made it worse.
|
|
107
86
|
9. **Watercolour** is its own way of working: see "Wet media" below.
|
|
108
|
-
10. **Deliver**: `export_image` (PNG, or JPEG / WebP in a browser), `export_psd` for Photoshop,
|
|
109
|
-
`save_paint_document` to keep the painting with its strokes (when the host has storage).
|
|
87
|
+
10. **Deliver**: `export_image` (PNG, or JPEG / WebP in a browser), `export_psd` for Photoshop, `save_paint_document` to keep the painting with its strokes (when the host has storage).
|
|
110
88
|
|
|
111
89
|
## Best practices
|
|
112
90
|
|
|
@@ -283,6 +261,8 @@ Contributing while the user paints: suggest, don't paint. Read [references/paint
|
|
|
283
261
|
| `move_layer` | Reorder: `index` among siblings (0 = bottom), optionally into `parentId` (or `null` for the top level). |
|
|
284
262
|
| `merge_layer_down` | Merge a pixel layer into the pixel layer directly below (which keeps its settings). |
|
|
285
263
|
| `fill_layer` | Fill a pixel layer with `color` at `opacity`: flat, or with `grain` 0..1 following the paper grain (`pressure` 0..1 decides how far into the valleys, default 0.5). The fastest way to lay a ground or a textured tone. Returns the bounds. |
|
|
264
|
+
| `fill_region` | Flood-fill one or more enclosed regions on a pixel layer (`x`, `y` or `points: [{x, y}]`). Set `reference` to an ink layer id (or `"all"` / `"composite"`, or `"layer"`), `closeGap` (0..32 px) to bridge small gaps in line art without leaking, `expand` (-16..16 px, e.g. 1..2 px) to bleed under anti-aliased lines so no halo shows, `grain` (0..1) for paper texture, or `wet: true` to pour a watercolour wash into the region on the wet layer. One undo step. Returns `layerId`, `bounds`, `pixelCount`, `regions`, and `leaked` (`true` when the fill touched the canvas border). |
|
|
265
|
+
| `find_unfilled_regions` | Find enclosed unfilled regions from a reference line-art layer (`reference: inkLayerId`) or `"all"` / `"composite"`, closing gaps up to `closeGap` px and excluding areas already painted on `layerId`. Changes nothing. Returns `regions` sorted largest first with an interior seed `point` (`{x, y}`) ready for `fill_region`, `centroid`, `bounds`, `pixelCount`, and `touchesEdge`. |
|
|
286
266
|
| `clear_layer` | Remove every pixel of a layer. Returns the bounds that were cleared. |
|
|
287
267
|
|
|
288
268
|
### Brushes
|
|
@@ -335,6 +315,9 @@ Listing, saving, sharing and previewing brushes are the brush library's tools (`
|
|
|
335
315
|
| `convert_to_stroke_layer` | Make an empty pixel layer a stroke layer. Returns the layer. |
|
|
336
316
|
| `rasterize_stroke_layer` | Turn a stroke layer into a plain pixel layer with the same pixels (strokes no longer editable). Do it before erasing, smudging or filling on it. |
|
|
337
317
|
| `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. |
|
|
318
|
+
| `breed_strokes` | Breed `count` (2..12, default 4) mutated variants from recorded `strokeIds` (1..16) as ghost paint proposals: `mutation` (`geometry`, `color`, `brush`, `seed`, each 0..1), `seed`. Returns `proposalIds` and each variant's `diff` and `bounds`. Read [references/evolution.md](references/evolution.md). |
|
|
319
|
+
| `breed_proposal` | Breed `count` (2..12, default 4) next-generation variants from `proposalIds` (1 id mutates it; 2 ids cross their points and brush facets over, then mutate), with `mutation` and `seed`. Returns `proposalIds` and `proposals`. |
|
|
320
|
+
| `get_proposal_genome` | Read a pending proposal's stroke genome (`proposalId`): `strokes` with full brush facets, points, colour and seed. |
|
|
338
321
|
| `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. |
|
|
339
322
|
| `redo_paint` | Redo the step just undone. |
|
|
340
323
|
|
|
@@ -442,20 +425,13 @@ The host may add the shared document tools (see `pixerate-agent-tools`). A paint
|
|
|
442
425
|
## Pitfalls
|
|
443
426
|
|
|
444
427
|
- With agent playback on, strokes, fills and replays are painted live by the director, and other writes open their panel (Colour, Wet, Paper, Layers, Effects) and point at the control. Results are unchanged.
|
|
445
|
-
- **Stroke-by-stroke drawing is slow and expensive.** Do not draw a detailed picture point by
|
|
446
|
-
|
|
447
|
-
- **
|
|
448
|
-
|
|
449
|
-
- **
|
|
450
|
-
|
|
451
|
-
- **
|
|
452
|
-
and two strokes on the same spot catch the same peaks.
|
|
453
|
-
- **Blending tools need paint to blend.** Blender and smudge only move what is on the target
|
|
454
|
-
layer: blend on the layer you painted, not on an empty one above it.
|
|
455
|
-
- **A dirty brush stays dirty** across strokes and colour changes until `clean_mixer_brush`.
|
|
456
|
-
Pick-up lifts only paint on the target layer: the paper and other layers lift nothing.
|
|
457
|
-
- **Replays use the recorded load**: a replayed pick-up stroke starts with what the brush carried
|
|
458
|
-
when it was painted, not with the current load.
|
|
428
|
+
- **Stroke-by-stroke drawing is slow and expensive.** Do not draw a detailed picture point by point. Block in with fills and big strokes, then replay and vary a few good strokes.
|
|
429
|
+
- **A hidden or locked layer refuses paint**: show it (`update_layer visible true`) or unlock it. `transparency` lock is not an error: paint only lands where the layer already has paint.
|
|
430
|
+
- **Depth 0 means no grain** whatever the brush; grainy media then look smooth. Smooth bristol has depth 0.
|
|
431
|
+
- **Grain is fixed to the document**, not to the layer: moving content does not move the grain, and two strokes on the same spot catch the same peaks.
|
|
432
|
+
- **Blending tools need paint to blend.** Blender and smudge only move what is on the target layer: blend on the layer you painted, not on an empty one above it.
|
|
433
|
+
- **A dirty brush stays dirty** across strokes and colour changes until `clean_mixer_brush`. Pick-up lifts only paint on the target layer: the paper and other layers lift nothing.
|
|
434
|
+
- **Replays use the recorded load**: a replayed pick-up stroke starts with what the brush carried when it was painted, not with the current load.
|
|
459
435
|
- **Big soft brushes at full flow look flat.** Lower `flow` (airbrush 0.05..0.15) and build up.
|
|
460
436
|
- **JPEG and WebP need a browser**; in Node use PNG. Exports never upscale (`scale` ≤ 1).
|
|
461
437
|
- **Symmetry stays on until you turn it off.** Set `mode: "off"` after the symmetric part, or
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Evolutionary strokes: breeding and mutating variants
|
|
2
|
+
|
|
3
|
+
Every dry stroke painted in the editor is recorded as a `RecordedStroke` genome: its raw points (with pressure, timing and tilt), its brush facets (`tip`, `dynamics`, `behaviour`, `marks`, `motion`, `colour`), its paint colour and its deterministic `seed`.
|
|
4
|
+
|
|
5
|
+
Rather than guessing facet knobs by hand, you can **breed** a batch of variants from one or more painted strokes, compare their ghost previews and diff summaries, cross two favourites over, or accept one onto a new layer in a single undo step.
|
|
6
|
+
|
|
7
|
+
## Workflow
|
|
8
|
+
|
|
9
|
+
1. **Pick parent strokes.** Call `list_strokes` (or use the `strokeId` returned by `paint_stroke` / `stroke_path`). Only dry strokes that `liveStrokeRefusal` permits can be bred — wet, impasto, sticker, eraser, blender, smudge, light and pick-up brushes are refused with the reason.
|
|
10
|
+
2. **Breed a generation.** Call `breed_strokes` with `strokeIds` (`1..16`), `count` (`2..12`, default `4`), optional `mutation` rates (`geometry`, `color`, `brush`, `seed`, each `0..1`) and an optional deterministic `seed`.
|
|
11
|
+
- Each variant is added as a pending paint proposal (`kind: "strokes"`) rendered through `previewPaint` one after another.
|
|
12
|
+
- The result lists `proposalIds` and `proposals`, each with `proposalId`, `title`, `seed`, `bounds`, a human-readable `diff` summary (`"geometry ±4.2px, scale 0.96×; colour ΔL -0.03, Δh +8°; brush tip.size=18.4, tip.hardness=0.62; seed → 1849201"`) and `changes` tags.
|
|
13
|
+
3. **Evolve further or cross over.** Call `breed_proposal` with `proposalIds`:
|
|
14
|
+
- **1 proposal id**: mutates that proposal's genome into `count` offspring.
|
|
15
|
+
- **2 proposal ids**: crosses the two parent genomes over — resampling corresponding stroke point paths and mixing their OKLCH colours and numeric brush facets — then mutates each child.
|
|
16
|
+
4. **Inspect or accept.**
|
|
17
|
+
- Call `get_proposal_genome` with `proposalId` to read the full stroke records (`brush`, `color`, `points`, `seed`) if you want to save the mutated brush with `create_brush`.
|
|
18
|
+
- Call `accept_paint_proposal` to paint the chosen variant onto a new layer as a single undo step, or `reject_paint_proposal` to dismiss variants you don't want.
|
|
19
|
+
|
|
20
|
+
## Mutation channels (`mutation`)
|
|
21
|
+
|
|
22
|
+
| Channel | Default | What it mutates |
|
|
23
|
+
| --- | --- | --- |
|
|
24
|
+
| `geometry` | `0.35` | Seeded `varyStroke` transform (small offset, rotation, scale and pressure scaling) plus smoothed 3-tap point jitter and pressure drift. Set to `0` to keep the exact path. |
|
|
25
|
+
| `color` | `0.25` | Perceptual drift in OKLCH (`L` ±0.18, `C` ±0.08, `h` ±45° at rate `1.0`), clamped to gamut. Set to `0` to keep the exact colour. |
|
|
26
|
+
| `brush` | `0.3` | Drifts numeric brush facets present on the stroke within their schema bounds (`tip.size`, `tip.hardness`, `tip.spacing`, `tip.roundness`, `tip.angle`, `tip.opacity`, `tip.flow`, `dynamics.sizeJitter`, `dynamics.opacityJitter`, `dynamics.scatter`, `dynamics.angleJitter`, `behaviour.grain`, plus active `marks` particle/bristle/chalk fields). Set to `0` to keep the brush unchanged. |
|
|
27
|
+
| `seed` | `0.5` | Probability of rerolling each stroke's deterministic RNG `seed` so grain, scatter and bristle/particle marks vary even when `geometry`, `color` and `brush` are `0`. |
|
|
@@ -46,9 +46,15 @@ This skill is the method. `pixerate-paint-editor` has the full tool reference.
|
|
|
46
46
|
4. **Hide the sketch.** `update_layer` the Sketch layer `visible: false` (or lower its `opacity`
|
|
47
47
|
while inking, then hide it).
|
|
48
48
|
**Check:** `list_layers` shows it hidden.
|
|
49
|
-
5. **Flats.** `add_layer` "Flats", then `move_layer` it below the Ink layer
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
5. **Flats.** `add_layer` "Flats", then `move_layer` it below the Ink layer. Call
|
|
50
|
+
`find_unfilled_regions` (`reference` set to the Ink layer id or `"all"`, `layerId` set to the
|
|
51
|
+
Flats layer, `closeGap: 4..8`) to get each enclosed shape's interior seed `point` and `bounds`.
|
|
52
|
+
Fill each shape in one call with `fill_region` (`x`, `y` or `points` for same-coloured shapes,
|
|
53
|
+
`reference` set to the Ink layer id or `"all"`, `closeGap: 4..8` to bridge small line gaps,
|
|
54
|
+
`expand: 1..2` to bleed under anti-aliased ink edges so no white halo shows, or `wet: true` for a
|
|
55
|
+
watercolour wash). Check `leaked`: if `true`, undo (`undo_paint`) and raise `closeGap` or close
|
|
56
|
+
the open line. Use `fill_layer` for a full-canvas ground.
|
|
57
|
+
**Check:** `pick_color` inside a shape is the flat colour; on a line still the ink; `leaked` is `false`.
|
|
52
58
|
6. **Shading and light.** `add_layer` "Shading" directly above the flats, `update_layer`
|
|
53
59
|
`blend: "multiply"` (or `shadow`) and `clipped: true`; paint shadows on the side away from the
|
|
54
60
|
light. A "Light" layer the same way with `highlight` or `screen`.
|
|
@@ -64,7 +70,8 @@ This skill is the method. `pixerate-paint-editor` has the full tool reference.
|
|
|
64
70
|
| Sketch | `pencil-hb`, light colour, own layer, hidden at the end |
|
|
65
71
|
| Line art | `ink-pen` (even), `brush-pen` (swelling); own layer on top |
|
|
66
72
|
| Clean geometric lines (curves, circles, borders) | `stroke_path` with SVG path data and a `pressure` taper, on the Ink layer |
|
|
67
|
-
| Flats | `
|
|
73
|
+
| Flats inside line art | `find_unfilled_regions` then `fill_region` (`reference` = Ink layer id or `"all"`, `closeGap: 4..8`, `expand: 1..2`) on a Flats layer under the ink |
|
|
74
|
+
| Watercolour wash inside line art | `fill_region` with `wet: true`, `reference` = Ink layer id, `closeGap: 4..8`, `expand: 1` |
|
|
68
75
|
| Patterned or textured flats (sky, gradient, galaxy) | `set_effect_paint` with a provider generator, then a flat dry brush on the Flats layer; `set_color` after |
|
|
69
76
|
| Textured passes (dry brush, sponge, foliage) | A brush with `tip.grain` (`set_brush` `{ tip: { grain: { source: "sanded", depth: 0.6 } } }`) or an image tip from the brush library, with `dynamics.angleJitter` and `flip` so repeats don't show |
|
|
70
77
|
| Shadows | Clipped layer, `multiply` or `shadow`, a cool colour |
|
|
@@ -75,7 +82,10 @@ This skill is the method. `pixerate-paint-editor` has the full tool reference.
|
|
|
75
82
|
## Recipes
|
|
76
83
|
|
|
77
84
|
**Flats under ink.** `add_layer` "Flats" → `move_layer` with the new layer's id and `index` below
|
|
78
|
-
the Ink layer → `
|
|
85
|
+
the Ink layer → `find_unfilled_regions` `{ reference: inkLayerId, layerId: flatsLayerId, closeGap: 4 }`
|
|
86
|
+
→ `fill_region` `{ x, y, color, reference: inkLayerId, closeGap: 4, expand: 1 }` (or pass `points`
|
|
87
|
+
to fill multiple regions of the same colour in one undo step). If `leaked: true`, `undo_paint` and
|
|
88
|
+
increase `closeGap`.
|
|
79
89
|
|
|
80
90
|
**Effect flats.** With an effects provider: `search_effects` (`use` generator) → `describe_effect`
|
|
81
91
|
→ `set_effect_paint` → `marker` strokes inside the shape on the Flats layer (the effect shows
|
|
@@ -100,6 +110,7 @@ clipped: true }` → `set_brush` `airbrush` → paint the shadow side.
|
|
|
100
110
|
|
|
101
111
|
- `get_canvas_info`, `list_layers`, `list_strokes`, `pick_color`, `render_preview`: read and check
|
|
102
112
|
- `set_paper`, `fill_layer`: the ground and backgrounds
|
|
113
|
+
- `find_unfilled_regions`, `fill_region`: inspect enclosed line-art shapes and fill flats under the ink with gap closing and edge expansion
|
|
103
114
|
- `add_layer`, `update_layer`, `move_layer`, `remove_layer`: one layer per pass; hide, clip, blend
|
|
104
115
|
- `set_brush`, `set_color`, `paint_stroke`, `replay_strokes`: sketch, ink, flats and shading
|
|
105
116
|
- `stroke_path`: clean geometric line art from SVG path data
|
|
@@ -20,8 +20,7 @@
|
|
|
20
20
|
"solution": [
|
|
21
21
|
{ "tool": "add_layer", "args": { "name": "Flats" } },
|
|
22
22
|
{ "tool": "move_layer", "args": { "layerId": { "$read": "list_layers", "path": "layers.0.id" }, "index": 0 } },
|
|
23
|
-
{ "tool": "
|
|
24
|
-
{ "tool": "
|
|
25
|
-
{ "tool": "paint_stroke", "args": { "points": [{ "x": 14, "y": 16 }, { "x": 50, "y": 16 }, { "x": 50, "y": 24 }, { "x": 14, "y": 24 }, { "x": 14, "y": 32 }, { "x": 50, "y": 32 }, { "x": 50, "y": 40 }, { "x": 14, "y": 40 }, { "x": 14, "y": 48 }, { "x": 50, "y": 48 }] } }
|
|
23
|
+
{ "tool": "find_unfilled_regions", "args": { "reference": "all", "closeGap": 4 } },
|
|
24
|
+
{ "tool": "fill_region", "args": { "x": 32, "y": 32, "color": "#f2c14e", "reference": "all", "closeGap": 4, "expand": 1 } }
|
|
26
25
|
]
|
|
27
26
|
}
|