@pixerate/editor 0.272.1 → 0.274.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 (42) hide show
  1. package/dist/chunk-2A5IKZMU.js +557 -0
  2. package/dist/chunk-YH6SKC7P.cjs +557 -0
  3. package/dist/paint-editor/collaboration.d.cts +6 -1
  4. package/dist/paint-editor/collaboration.d.ts +6 -1
  5. package/dist/paint-editor/controller.d.cts +117 -0
  6. package/dist/paint-editor/controller.d.ts +117 -0
  7. package/dist/paint-editor/document.d.cts +1 -1
  8. package/dist/paint-editor/document.d.ts +1 -1
  9. package/dist/paint-editor/evolution-tools.d.cts +48 -0
  10. package/dist/paint-editor/evolution-tools.d.ts +48 -0
  11. package/dist/paint-editor/evolution.d.cts +175 -0
  12. package/dist/paint-editor/evolution.d.ts +175 -0
  13. package/dist/paint-editor/index.cjs +8500 -7258
  14. package/dist/paint-editor/index.d.cts +3 -0
  15. package/dist/paint-editor/index.d.ts +3 -0
  16. package/dist/paint-editor/index.js +8481 -7239
  17. package/dist/paint-editor/presence.d.cts +5 -1
  18. package/dist/paint-editor/presence.d.ts +5 -1
  19. package/dist/paint-editor/ui.d.cts +7 -2
  20. package/dist/paint-editor/ui.d.ts +7 -2
  21. package/dist/raster/fill.d.cts +85 -0
  22. package/dist/raster/fill.d.ts +85 -0
  23. package/dist/raster/index.cjs +9 -1
  24. package/dist/raster/index.d.cts +1 -0
  25. package/dist/raster/index.d.ts +1 -0
  26. package/dist/raster/index.js +8 -0
  27. package/package.json +1 -1
  28. package/skills/README.md +1 -0
  29. package/skills/pixerate-brushes/SKILL.md +3 -0
  30. package/skills/pixerate-paint-editor/SKILL.md +55 -96
  31. package/skills/pixerate-paint-editor/references/brush-facets.md +3 -0
  32. package/skills/pixerate-paint-editor/references/evolution.md +27 -0
  33. package/skills/pixerate-paint-editor/references/mutation.md +25 -0
  34. package/skills/pixerate-paint-editor/references/oils.md +8 -1
  35. package/skills/pixerate-paint-editor/references/smart-inks.md +51 -0
  36. package/skills/pixerate-paint-mutation/SKILL.md +76 -0
  37. package/skills/pixerate-paint-mutation/evals/decline-unanswered.json +58 -0
  38. package/skills/pixerate-paint-mutation/evals/dry-ink-answer.json +74 -0
  39. package/skills/pixerate-paint-mutation/evals/wet-wash-answer.json +76 -0
  40. package/skills/pixerate-paint-oil-impasto/SKILL.md +2 -1
  41. package/skills/pixerate-paint-sketch-to-finish/SKILL.md +16 -5
  42. package/skills/pixerate-paint-sketch-to-finish/evals/flats-under-ink.json +2 -3
@@ -18,6 +18,7 @@ import { type LayerLocks } from '../raster/layers.cjs';
18
18
  import { type LayerEffect, type LayerEffectKind, type LayerEffects } from '../raster/effects/model.cjs';
19
19
  import type { EffectPattern } from '../raster/effects/patterns.cjs';
20
20
  import { TiledSurface, type RasterRect, type Tile } from '../raster/surface.cjs';
21
+ import { type FillRegionPoint, type FillRegionSummary, type UnfilledRegion } from '../raster/fill.cjs';
21
22
  import { type PaintBrushInput, type PaintBrush } from './brushes.cjs';
22
23
  import { type BrushLibrary, type BrushLibraryFile } from '../brushes/library.cjs';
23
24
  import { type BrushPatch, type UnsettableBrushFacet } from '../brushes/patch.cjs';
@@ -55,6 +56,8 @@ import type { EffectDescription, EffectProvider, EffectValue } from '../effects/
55
56
  import { type PaintEffectPaint } from './effect-paint.cjs';
56
57
  import { type PaintEffectPlace, type PaintEffectSource, type PaintPaperEffect, type PaperEffectBlend } from './effects.cjs';
57
58
  import { type PaintLighting } from './thick.cjs';
59
+ import { type PaintProposals } from './collaboration.cjs';
60
+ import { type BreedStrokesResult, type ProposalGenomeResult, type StrokeMutationRates } from './evolution.cjs';
58
61
  export declare class PaintEditorError extends Error {
59
62
  constructor(message: string);
60
63
  }
@@ -297,6 +300,75 @@ export interface FillLayerOptions {
297
300
  pressure?: number;
298
301
  blend?: BlendMode;
299
302
  }
303
+ export type FillReference = 'layer' | 'all' | 'composite' | (string & {});
304
+ export interface FillRegionOptions {
305
+ /** Seed x in document pixels (pass `x` and `y`, or `points`). */
306
+ x?: number;
307
+ /** Seed y in document pixels (pass `x` and `y`, or `points`). */
308
+ y?: number;
309
+ /** Multiple seed points in document pixels (filled together as one undo step). */
310
+ points?: ReadonlyArray<FillRegionPoint>;
311
+ /** Target layer id from `listLayers` (default the active layer). */
312
+ layerId?: string;
313
+ /**
314
+ * Which pixels define the region boundaries:
315
+ * - `'layer'` (default): the target layer itself.
316
+ * - `'all'` or `'composite'`: all visible layers composited (without paper).
317
+ * - a layer id from `listLayers`: that layer (e.g. an ink line-art layer above a flats layer).
318
+ */
319
+ reference?: FillReference;
320
+ /** Fill colour #rrggbb (default the editor's paint colour). */
321
+ color?: string;
322
+ /** Opacity 0..1 (default 1). */
323
+ opacity?: number;
324
+ /** Blend mode (default `'normal'`). */
325
+ blend?: BlendMode;
326
+ /** Alias for `blend`. */
327
+ blendMode?: BlendMode;
328
+ /** Colour/alpha similarity tolerance 0..255 (default 32). */
329
+ tolerance?: number;
330
+ /** Close small gaps in line art up to this width in pixels, 0..32 (default 0). */
331
+ closeGap?: number;
332
+ /** Expand (> 0, bleed under lines) or contract (< 0) the filled region in pixels, -16..16 (default 0). */
333
+ expand?: number;
334
+ /** Soften boundary edges (default true). */
335
+ antialias?: boolean;
336
+ /** Paper grain response 0..1 (default 0: flat fill). */
337
+ grain?: number;
338
+ /** With grain: pressure 0..1, how far the fill reaches into the valleys (default 0.5). */
339
+ pressure?: number;
340
+ /** Pour a wet watercolour wash into the region on the layer's wet layer (default false). */
341
+ wet?: boolean;
342
+ }
343
+ export interface FillRegionResult {
344
+ layerId: string;
345
+ bounds: RasterRect | null;
346
+ pixelCount: number;
347
+ leaked: boolean;
348
+ regions: FillRegionSummary[];
349
+ wet?: boolean;
350
+ }
351
+ export interface FindUnfilledRegionsOptions {
352
+ /** Target layer id from `listLayers` (when given, regions already painted on it are excluded). */
353
+ layerId?: string;
354
+ /**
355
+ * Which pixels define the line-art barriers:
356
+ * - `'all'` or `'composite'` (default): all visible layers composited (without paper).
357
+ * - `'layer'`: the target (or active) layer itself.
358
+ * - a layer id from `listLayers`: that layer (e.g. an ink line-art layer).
359
+ */
360
+ reference?: FillReference;
361
+ /** Alpha/colour threshold 0..255 above which a reference pixel is treated as line art (default 32). */
362
+ tolerance?: number;
363
+ /** Close small gaps in line art up to this width in pixels, 0..32 (default 0). */
364
+ closeGap?: number;
365
+ /** Ignore regions smaller than this many pixels (default 16). */
366
+ minArea?: number;
367
+ /** Include regions that touch the canvas border (default false: only enclosed shapes). */
368
+ includeEdge?: boolean;
369
+ /** Maximum number of regions to return, sorted largest first (default 100). */
370
+ maxRegions?: number;
371
+ }
300
372
  /** Pixels to add on each side of the canvas (whole numbers, 0 or more; missing = 0). */
301
373
  export interface PaintCanvasExtension {
302
374
  left?: number;
@@ -653,6 +725,22 @@ export declare class PaintEditorController {
653
725
  layerId: string;
654
726
  bounds: RasterRect;
655
727
  };
728
+ /**
729
+ * Flood-fills one or more contiguous regions on a pixel layer (one undo step), sampling boundaries
730
+ * from the layer itself (`reference: 'layer'`), all visible layers (`'all'` / `'composite'`), or a
731
+ * specific reference layer id (e.g. an ink line-art layer above a flats layer). Closes line-art gaps
732
+ * up to `closeGap` px and expands (`> 0`, bleeding under lines) or contracts (`< 0`) by `expand` px.
733
+ * With `wet: true`, pours a watercolour wash into the region on the layer's wet layer.
734
+ */
735
+ fillRegion(options: FillRegionOptions): FillRegionResult;
736
+ /**
737
+ * Finds enclosed unfilled regions from a reference layer or the visible composite (without paper),
738
+ * closing line-art gaps up to `closeGap` px and returning each region's interior seed `point`,
739
+ * `centroid`, `bounds`, `pixelCount`, and `touchesEdge` flag.
740
+ */
741
+ findUnfilledRegions(options?: FindUnfilledRegionsOptions): {
742
+ regions: UnfilledRegion[];
743
+ };
656
744
  private applyCoverage;
657
745
  /** The registered effects provider, or `null`. */
658
746
  get effectsProvider(): EffectProvider | null;
@@ -1606,6 +1694,35 @@ export declare class PaintEditorController {
1606
1694
  private readMixingPad;
1607
1695
  /** A layer's tile surface (live while stroking), for thumbnails. */
1608
1696
  layerSurface(id: string): TiledSurface | null;
1697
+ private proposalsStore;
1698
+ /** The pending paint proposals store attached to this editor (created on demand). */
1699
+ get proposals(): PaintProposals;
1700
+ /** Attaches an external `PaintProposals` store so tools and panels share it. */
1701
+ attachProposals(store: PaintProposals): void;
1702
+ /**
1703
+ * Breeds `count` (`2..12`, default `4`) mutated variants from `1..16` recorded strokes as
1704
+ * pending paint proposals, generated one after another through `previewPaint`.
1705
+ */
1706
+ breedStrokes(options: {
1707
+ strokeIds: readonly string[];
1708
+ count?: number;
1709
+ mutation?: StrokeMutationRates;
1710
+ seed?: number;
1711
+ origin?: string;
1712
+ }): BreedStrokesResult;
1713
+ /**
1714
+ * Breeds `count` (`2..12`, default `4`) variants from `1` pending proposal (mutation) or `2`
1715
+ * pending proposals (crossover + mutation), generated one after another through `previewPaint`.
1716
+ */
1717
+ breedProposal(options: {
1718
+ proposalIds: readonly string[];
1719
+ count?: number;
1720
+ mutation?: StrokeMutationRates;
1721
+ seed?: number;
1722
+ origin?: string;
1723
+ }): BreedStrokesResult;
1724
+ /** Returns the full stroke genome records (`RecordedStrokeJSON[]`) of a pending paint proposal. */
1725
+ getProposalGenome(proposalId: string): ProposalGenomeResult;
1609
1726
  }
1610
1727
  export type { Tile };
1611
1728
  /** Largest tracing or reference image side, in pixels. */
@@ -18,6 +18,7 @@ import { type LayerLocks } from '../raster/layers.js';
18
18
  import { type LayerEffect, type LayerEffectKind, type LayerEffects } from '../raster/effects/model.js';
19
19
  import type { EffectPattern } from '../raster/effects/patterns.js';
20
20
  import { TiledSurface, type RasterRect, type Tile } from '../raster/surface.js';
21
+ import { type FillRegionPoint, type FillRegionSummary, type UnfilledRegion } from '../raster/fill.js';
21
22
  import { type PaintBrushInput, type PaintBrush } from './brushes.js';
22
23
  import { type BrushLibrary, type BrushLibraryFile } from '../brushes/library.js';
23
24
  import { type BrushPatch, type UnsettableBrushFacet } from '../brushes/patch.js';
@@ -55,6 +56,8 @@ import type { EffectDescription, EffectProvider, EffectValue } from '../effects/
55
56
  import { type PaintEffectPaint } from './effect-paint.js';
56
57
  import { type PaintEffectPlace, type PaintEffectSource, type PaintPaperEffect, type PaperEffectBlend } from './effects.js';
57
58
  import { type PaintLighting } from './thick.js';
59
+ import { type PaintProposals } from './collaboration.js';
60
+ import { type BreedStrokesResult, type ProposalGenomeResult, type StrokeMutationRates } from './evolution.js';
58
61
  export declare class PaintEditorError extends Error {
59
62
  constructor(message: string);
60
63
  }
@@ -297,6 +300,75 @@ export interface FillLayerOptions {
297
300
  pressure?: number;
298
301
  blend?: BlendMode;
299
302
  }
303
+ export type FillReference = 'layer' | 'all' | 'composite' | (string & {});
304
+ export interface FillRegionOptions {
305
+ /** Seed x in document pixels (pass `x` and `y`, or `points`). */
306
+ x?: number;
307
+ /** Seed y in document pixels (pass `x` and `y`, or `points`). */
308
+ y?: number;
309
+ /** Multiple seed points in document pixels (filled together as one undo step). */
310
+ points?: ReadonlyArray<FillRegionPoint>;
311
+ /** Target layer id from `listLayers` (default the active layer). */
312
+ layerId?: string;
313
+ /**
314
+ * Which pixels define the region boundaries:
315
+ * - `'layer'` (default): the target layer itself.
316
+ * - `'all'` or `'composite'`: all visible layers composited (without paper).
317
+ * - a layer id from `listLayers`: that layer (e.g. an ink line-art layer above a flats layer).
318
+ */
319
+ reference?: FillReference;
320
+ /** Fill colour #rrggbb (default the editor's paint colour). */
321
+ color?: string;
322
+ /** Opacity 0..1 (default 1). */
323
+ opacity?: number;
324
+ /** Blend mode (default `'normal'`). */
325
+ blend?: BlendMode;
326
+ /** Alias for `blend`. */
327
+ blendMode?: BlendMode;
328
+ /** Colour/alpha similarity tolerance 0..255 (default 32). */
329
+ tolerance?: number;
330
+ /** Close small gaps in line art up to this width in pixels, 0..32 (default 0). */
331
+ closeGap?: number;
332
+ /** Expand (> 0, bleed under lines) or contract (< 0) the filled region in pixels, -16..16 (default 0). */
333
+ expand?: number;
334
+ /** Soften boundary edges (default true). */
335
+ antialias?: boolean;
336
+ /** Paper grain response 0..1 (default 0: flat fill). */
337
+ grain?: number;
338
+ /** With grain: pressure 0..1, how far the fill reaches into the valleys (default 0.5). */
339
+ pressure?: number;
340
+ /** Pour a wet watercolour wash into the region on the layer's wet layer (default false). */
341
+ wet?: boolean;
342
+ }
343
+ export interface FillRegionResult {
344
+ layerId: string;
345
+ bounds: RasterRect | null;
346
+ pixelCount: number;
347
+ leaked: boolean;
348
+ regions: FillRegionSummary[];
349
+ wet?: boolean;
350
+ }
351
+ export interface FindUnfilledRegionsOptions {
352
+ /** Target layer id from `listLayers` (when given, regions already painted on it are excluded). */
353
+ layerId?: string;
354
+ /**
355
+ * Which pixels define the line-art barriers:
356
+ * - `'all'` or `'composite'` (default): all visible layers composited (without paper).
357
+ * - `'layer'`: the target (or active) layer itself.
358
+ * - a layer id from `listLayers`: that layer (e.g. an ink line-art layer).
359
+ */
360
+ reference?: FillReference;
361
+ /** Alpha/colour threshold 0..255 above which a reference pixel is treated as line art (default 32). */
362
+ tolerance?: number;
363
+ /** Close small gaps in line art up to this width in pixels, 0..32 (default 0). */
364
+ closeGap?: number;
365
+ /** Ignore regions smaller than this many pixels (default 16). */
366
+ minArea?: number;
367
+ /** Include regions that touch the canvas border (default false: only enclosed shapes). */
368
+ includeEdge?: boolean;
369
+ /** Maximum number of regions to return, sorted largest first (default 100). */
370
+ maxRegions?: number;
371
+ }
300
372
  /** Pixels to add on each side of the canvas (whole numbers, 0 or more; missing = 0). */
301
373
  export interface PaintCanvasExtension {
302
374
  left?: number;
@@ -653,6 +725,22 @@ export declare class PaintEditorController {
653
725
  layerId: string;
654
726
  bounds: RasterRect;
655
727
  };
728
+ /**
729
+ * Flood-fills one or more contiguous regions on a pixel layer (one undo step), sampling boundaries
730
+ * from the layer itself (`reference: 'layer'`), all visible layers (`'all'` / `'composite'`), or a
731
+ * specific reference layer id (e.g. an ink line-art layer above a flats layer). Closes line-art gaps
732
+ * up to `closeGap` px and expands (`> 0`, bleeding under lines) or contracts (`< 0`) by `expand` px.
733
+ * With `wet: true`, pours a watercolour wash into the region on the layer's wet layer.
734
+ */
735
+ fillRegion(options: FillRegionOptions): FillRegionResult;
736
+ /**
737
+ * Finds enclosed unfilled regions from a reference layer or the visible composite (without paper),
738
+ * closing line-art gaps up to `closeGap` px and returning each region's interior seed `point`,
739
+ * `centroid`, `bounds`, `pixelCount`, and `touchesEdge` flag.
740
+ */
741
+ findUnfilledRegions(options?: FindUnfilledRegionsOptions): {
742
+ regions: UnfilledRegion[];
743
+ };
656
744
  private applyCoverage;
657
745
  /** The registered effects provider, or `null`. */
658
746
  get effectsProvider(): EffectProvider | null;
@@ -1606,6 +1694,35 @@ export declare class PaintEditorController {
1606
1694
  private readMixingPad;
1607
1695
  /** A layer's tile surface (live while stroking), for thumbnails. */
1608
1696
  layerSurface(id: string): TiledSurface | null;
1697
+ private proposalsStore;
1698
+ /** The pending paint proposals store attached to this editor (created on demand). */
1699
+ get proposals(): PaintProposals;
1700
+ /** Attaches an external `PaintProposals` store so tools and panels share it. */
1701
+ attachProposals(store: PaintProposals): void;
1702
+ /**
1703
+ * Breeds `count` (`2..12`, default `4`) mutated variants from `1..16` recorded strokes as
1704
+ * pending paint proposals, generated one after another through `previewPaint`.
1705
+ */
1706
+ breedStrokes(options: {
1707
+ strokeIds: readonly string[];
1708
+ count?: number;
1709
+ mutation?: StrokeMutationRates;
1710
+ seed?: number;
1711
+ origin?: string;
1712
+ }): BreedStrokesResult;
1713
+ /**
1714
+ * Breeds `count` (`2..12`, default `4`) variants from `1` pending proposal (mutation) or `2`
1715
+ * pending proposals (crossover + mutation), generated one after another through `previewPaint`.
1716
+ */
1717
+ breedProposal(options: {
1718
+ proposalIds: readonly string[];
1719
+ count?: number;
1720
+ mutation?: StrokeMutationRates;
1721
+ seed?: number;
1722
+ origin?: string;
1723
+ }): BreedStrokesResult;
1724
+ /** Returns the full stroke genome records (`RecordedStrokeJSON[]`) of a pending paint proposal. */
1725
+ getProposalGenome(proposalId: string): ProposalGenomeResult;
1609
1726
  }
1610
1727
  export type { Tile };
1611
1728
  /** Largest tracing or reference image side, in pixels. */
@@ -69,7 +69,7 @@ export interface PaintDocumentState {
69
69
  /** A change a replay repeats besides strokes, recorded with how many strokes came before it. */
70
70
  export interface PaintEvent {
71
71
  at: number;
72
- kind: 'fill' | 'clear' | 'flatten' | 'stickers' | 'live-strokes';
72
+ kind: 'fill' | 'fill-region' | 'clear' | 'flatten' | 'stickers' | 'live-strokes';
73
73
  layerId: string;
74
74
  /** The fill's options (colour, opacity, grain, pressure, blend), or the layer's stickers or live strokes after an edit. */
75
75
  data?: Record<string, unknown>;
@@ -69,7 +69,7 @@ export interface PaintDocumentState {
69
69
  /** A change a replay repeats besides strokes, recorded with how many strokes came before it. */
70
70
  export interface PaintEvent {
71
71
  at: number;
72
- kind: 'fill' | 'clear' | 'flatten' | 'stickers' | 'live-strokes';
72
+ kind: 'fill' | 'fill-region' | 'clear' | 'flatten' | 'stickers' | 'live-strokes';
73
73
  layerId: string;
74
74
  /** The fill's options (colour, opacity, grain, pressure, blend), or the layer's stickers or live strokes after an edit. */
75
75
  data?: Record<string, unknown>;
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Agent tools for evolutionary strokes (`breed_strokes`, `breed_proposal`, `get_proposal_genome`).
3
+ * Accepting or dismissing bred variants reuses `accept_paint_proposal` and `reject_paint_proposal`.
4
+ */
5
+ import type { AgentToolProvider } from '../tools/registry.cjs';
6
+ import type { PaintEditorController } from './controller.cjs';
7
+ import type { PaintAgentTool } from './hosted.cjs';
8
+ export declare const EVOLUTION_MUTATION_SCHEMA: {
9
+ readonly type: "object";
10
+ readonly description: "How strongly each part of a stroke genome mutates (each 0..1; 0 keeps that part unchanged).";
11
+ readonly properties: {
12
+ readonly geometry: {
13
+ readonly type: "number";
14
+ readonly minimum: 0;
15
+ readonly maximum: 1;
16
+ readonly description: string;
17
+ };
18
+ readonly color: {
19
+ readonly type: "number";
20
+ readonly minimum: 0;
21
+ readonly maximum: 1;
22
+ readonly description: string;
23
+ };
24
+ readonly brush: {
25
+ readonly type: "number";
26
+ readonly minimum: 0;
27
+ readonly maximum: 1;
28
+ readonly description: string;
29
+ };
30
+ readonly seed: {
31
+ readonly type: "number";
32
+ readonly minimum: 0;
33
+ readonly maximum: 1;
34
+ readonly description: string;
35
+ };
36
+ };
37
+ readonly additionalProperties: false;
38
+ };
39
+ export declare function createPaintEvolutionTools(c: PaintEditorController): PaintAgentTool[];
40
+ export declare const createEvolutionTools: typeof createPaintEvolutionTools;
41
+ export interface PaintEvolutionToolProviderOptions {
42
+ /** Provider id (unique per registry). Default `paint-evolution`. */
43
+ id?: string;
44
+ /** Tool-name prefix (`<namespace>__<name>`); defaults to the provider id, `''` for bare names. */
45
+ namespace?: string;
46
+ }
47
+ /** Standalone tool provider for evolutionary strokes (also included in `createPaintEditorToolProvider`). */
48
+ export declare function createPaintEvolutionToolProvider(controller: PaintEditorController, options?: PaintEvolutionToolProviderOptions): AgentToolProvider;
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Agent tools for evolutionary strokes (`breed_strokes`, `breed_proposal`, `get_proposal_genome`).
3
+ * Accepting or dismissing bred variants reuses `accept_paint_proposal` and `reject_paint_proposal`.
4
+ */
5
+ import type { AgentToolProvider } from '../tools/registry.js';
6
+ import type { PaintEditorController } from './controller.js';
7
+ import type { PaintAgentTool } from './hosted.js';
8
+ export declare const EVOLUTION_MUTATION_SCHEMA: {
9
+ readonly type: "object";
10
+ readonly description: "How strongly each part of a stroke genome mutates (each 0..1; 0 keeps that part unchanged).";
11
+ readonly properties: {
12
+ readonly geometry: {
13
+ readonly type: "number";
14
+ readonly minimum: 0;
15
+ readonly maximum: 1;
16
+ readonly description: string;
17
+ };
18
+ readonly color: {
19
+ readonly type: "number";
20
+ readonly minimum: 0;
21
+ readonly maximum: 1;
22
+ readonly description: string;
23
+ };
24
+ readonly brush: {
25
+ readonly type: "number";
26
+ readonly minimum: 0;
27
+ readonly maximum: 1;
28
+ readonly description: string;
29
+ };
30
+ readonly seed: {
31
+ readonly type: "number";
32
+ readonly minimum: 0;
33
+ readonly maximum: 1;
34
+ readonly description: string;
35
+ };
36
+ };
37
+ readonly additionalProperties: false;
38
+ };
39
+ export declare function createPaintEvolutionTools(c: PaintEditorController): PaintAgentTool[];
40
+ export declare const createEvolutionTools: typeof createPaintEvolutionTools;
41
+ export interface PaintEvolutionToolProviderOptions {
42
+ /** Provider id (unique per registry). Default `paint-evolution`. */
43
+ id?: string;
44
+ /** Tool-name prefix (`<namespace>__<name>`); defaults to the provider id, `''` for bare names. */
45
+ namespace?: string;
46
+ }
47
+ /** Standalone tool provider for evolutionary strokes (also included in `createPaintEditorToolProvider`). */
48
+ export declare function createPaintEvolutionToolProvider(controller: PaintEditorController, options?: PaintEvolutionToolProviderOptions): AgentToolProvider;
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Evolutionary strokes: breed and mutate stroke variants (`RecordedStroke` genomes).
3
+ *
4
+ * - **Geometry mutation**: reuses `StrokeVariation` / `varyStroke` for whole-stroke affine drift
5
+ * (move, scale, rotate, pressure scale) plus seeded, smoothed point jitter along the path.
6
+ * - **Colour drift**: perceptual drift in OKLCH lightness, chroma and hue, gamut-mapped to sRGB.
7
+ * - **Brush facet drift**: drifts numeric brush facets within their schema ranges (`BRUSH_JSON_SCHEMA`)
8
+ * and resolves back to an engine `PaintBrush`.
9
+ * - **Seed reroll**: deterministic reroll of the stroke's dab/particle/bristle seed.
10
+ * - **Crossover**: resamples two parent stroke paths to a common point count, blends their points
11
+ * and colours in OKLab/OKLCH, and mixes their brush facets.
12
+ */
13
+ import type { RasterRect } from '../raster/surface.cjs';
14
+ import type { PaintBrush } from './brushes.cjs';
15
+ import type { PaintProposal } from './collaboration.cjs';
16
+ import type { PaintEditorController, PixelImage } from './controller.cjs';
17
+ import type { PenPoint } from './engine.cjs';
18
+ import { strokeToJSON, type RecordedStroke, type StrokeVariation } from './strokes.cjs';
19
+ export type RecordedStrokeJSON = ReturnType<typeof strokeToJSON>;
20
+ /** How strongly each part of a stroke genome mutates (`0..1`; `0` keeps that part unchanged). */
21
+ export interface StrokeMutationRates {
22
+ /** Path variation and smoothed point jitter, 0..1 (default 0.35). */
23
+ geometry?: number;
24
+ /** Colour drift in OKLCH lightness, chroma and hue, 0..1 (default 0.35). */
25
+ color?: number;
26
+ /** Brush facet drift within schema bounds, 0..1 (default 0.35). */
27
+ brush?: number;
28
+ /** Seed reroll rate, 0..1 (default 0.5; 0 keeps the stroke seed). */
29
+ seed?: number;
30
+ }
31
+ export type EvolutionMutationRates = StrokeMutationRates;
32
+ export interface ResolvedMutationRates {
33
+ geometry: number;
34
+ color: number;
35
+ brush: number;
36
+ seed: number;
37
+ }
38
+ export declare const DEFAULT_MUTATION_RATES: ResolvedMutationRates;
39
+ /** Validates and fills defaults for mutation rates (`0..1`). */
40
+ export declare function normalizeMutationRates(rates?: StrokeMutationRates): ResolvedMutationRates;
41
+ /** Numeric brush facet descriptor with its schema range and drift span. */
42
+ export interface EvolutionBrushFacet {
43
+ /** Dot-path in the facet `Brush`. */
44
+ facet: string;
45
+ /** Dot-path in the resolved `PaintBrush`. */
46
+ engine: string;
47
+ /** Engines that read this facet. */
48
+ engines: readonly PaintBrush['engine'][];
49
+ /** Minimum schema value. */
50
+ min: number;
51
+ /** Maximum schema value. */
52
+ max: number;
53
+ /** Maximum drift at `mutation.brush = 1` (relative fraction when `relative` is true, else additive). */
54
+ span: number;
55
+ /** Inverse of rounding step (`1`, `10`, `100`). */
56
+ scale: number;
57
+ /** True when `span` scales the current value multiplicatively. */
58
+ relative?: boolean;
59
+ /** Optional `tip.shape` filter. */
60
+ shapes?: readonly string[];
61
+ /** Optional `marks.kind` filter. */
62
+ marks?: readonly string[];
63
+ }
64
+ /** Ordered table of numeric brush facets drifted and crossed over within their schema ranges. */
65
+ export declare const EVOLUTION_BRUSH_FACETS: readonly EvolutionBrushFacet[];
66
+ /**
67
+ * Seeded, smoothed point jitter along a stroke path: combines two harmonic waves with a 3-point
68
+ * smoothed random displacement so mutated paths stay fluid rather than jagged.
69
+ */
70
+ export declare function jitterStrokePoints(points: readonly PenPoint[], amount: number, seed: number): PenPoint[];
71
+ /** Whole-stroke `StrokeVariation` derived from a seed and geometry mutation rate (`0..1`). */
72
+ export declare function seededStrokeVariation(amount: number, seed: number, index?: number): StrokeVariation;
73
+ /**
74
+ * Drifts a `#rrggbb` colour in OKLCH lightness (±0.22), chroma (±0.10) and hue (±90°) scaled by
75
+ * `amount` (`0..1`), reducing chroma when needed to stay inside the sRGB gamut.
76
+ */
77
+ export declare function driftColorOklch(hex: string, amount: number, seed: number, index?: number): string;
78
+ /** Mixes two `#rrggbb` colours perceptually in OKLab/OKLCH at weight `t` (`0..1`). */
79
+ export declare function mixColorOklch(hexA: string, hexB: string, t: number): string;
80
+ /**
81
+ * Drifts a brush's numeric facets within their schema ranges (`EVOLUTION_BRUSH_FACETS`), keeping
82
+ * the brush compatible with live strokes (`liveStrokeRefusal`).
83
+ */
84
+ export declare function driftBrushFacets(brush: PaintBrush, amount: number, seed: number, index?: number): PaintBrush;
85
+ /** Rerolls a stroke seed deterministically when `amount > 0`; keeps `strokeSeed` when `amount <= 0`. */
86
+ export declare function rerollStrokeSeed(strokeSeed: number, amount: number, seed: number, index?: number): number;
87
+ /** Resamples a stroke's points by arc length to `count` evenly spaced samples. */
88
+ export declare function resampleStrokePoints(points: readonly PenPoint[], count: number): PenPoint[];
89
+ /** Mixes two brushes by blending their applicable numeric facets onto a dominant parent's skeleton. */
90
+ export declare function crossoverBrushes(brushA: PaintBrush, brushB: PaintBrush, seed: number, index?: number): PaintBrush;
91
+ /**
92
+ * Crosses two parent strokes over: resamples their points to a common count, blends positions and
93
+ * pressures, mixes their colours in OKLab/OKLCH, mixes their brush facets and combines their seeds.
94
+ */
95
+ export declare function crossoverStrokes(a: RecordedStroke, b: RecordedStroke, seed: number, index?: number): RecordedStroke;
96
+ /**
97
+ * Mutates one stroke genome with `rates` (`geometry`, `color`, `brush`, `seed`). When `origin` and
98
+ * `variation` are given (for multi-stroke motifs), whole-stroke affine drift uses them so strokes
99
+ * in the same genome move and turn together while each stroke's path jitters on its own.
100
+ */
101
+ export declare function mutateStroke(stroke: RecordedStroke, rates: strokeMutationInput, seed: number, index?: number, group?: {
102
+ origin: {
103
+ x: number;
104
+ y: number;
105
+ };
106
+ variation: StrokeVariation;
107
+ }): RecordedStroke;
108
+ type strokeMutationInput = StrokeMutationRates | undefined;
109
+ export interface StrokeEvolutionChanges {
110
+ geometry: boolean;
111
+ colors: Array<{
112
+ from: string;
113
+ to: string;
114
+ }>;
115
+ facets: Record<string, {
116
+ from: number;
117
+ to: number;
118
+ }>;
119
+ seedChanged: boolean;
120
+ crossover: boolean;
121
+ }
122
+ /** Summarises what changed between a parent stroke genome and a bred child genome. */
123
+ export declare function describeGenomeDiff(parents: readonly RecordedStroke[], children: readonly RecordedStroke[], options?: {
124
+ crossover?: boolean;
125
+ }): {
126
+ diff: string;
127
+ changes: StrokeEvolutionChanges;
128
+ };
129
+ /** Mutates a multi-stroke genome at `variantSeed`. */
130
+ export declare function mutateGenome(strokes: readonly RecordedStroke[], rates: StrokeMutationRates | undefined, variantSeed: number): RecordedStroke[];
131
+ /** Crosses two stroke genomes over and mutates the offspring at `variantSeed`. */
132
+ export declare function crossoverGenomes(genomeA: readonly RecordedStroke[], genomeB: readonly RecordedStroke[], rates: StrokeMutationRates | undefined, variantSeed: number): RecordedStroke[];
133
+ /** Checks that every stroke in a genome can be bred and previewed (refuses brushes `liveStrokeRefusal` rejects). */
134
+ export declare function checkEvolutionStrokes(strokes: readonly RecordedStroke[]): void;
135
+ export interface BredProposalSummary {
136
+ proposalId: string;
137
+ title: string;
138
+ seed: number;
139
+ bounds: RasterRect | null;
140
+ diff: string;
141
+ changes: StrokeEvolutionChanges;
142
+ }
143
+ export interface BreedStrokesResult {
144
+ proposalIds: string[];
145
+ proposals: BredProposalSummary[];
146
+ }
147
+ export interface ProposalGenomeResult {
148
+ proposalId: string;
149
+ title: string;
150
+ bounds: RasterRect | null;
151
+ strokes: RecordedStrokeJSON[];
152
+ }
153
+ /** Extracts the stroke genome of a pending `PaintProposal`, or returns `[]` when it has none. */
154
+ export declare function proposalGenomeStrokes(first: PaintEditorController | PaintProposal, second?: PaintProposal): RecordedStroke[];
155
+ /**
156
+ * Renders a contact sheet (`replay.ts:contactSheet`) of pending proposals' ghosts composited over
157
+ * the current canvas, for grid export.
158
+ */
159
+ export declare function renderProposalContactSheet(controller: PaintEditorController, proposals: readonly PaintProposal[], options?: {
160
+ columns?: number;
161
+ cell?: number;
162
+ paper?: boolean;
163
+ }): PixelImage;
164
+ /** Encodes `renderProposalContactSheet` as a PNG byte array and base64 string. */
165
+ export declare function exportProposalContactSheetPng(controller: PaintEditorController, proposals: readonly PaintProposal[], options?: {
166
+ columns?: number;
167
+ cell?: number;
168
+ paper?: boolean;
169
+ }): {
170
+ width: number;
171
+ height: number;
172
+ bytes: Uint8Array;
173
+ base64: string;
174
+ };
175
+ export { strokeToJSON };