@pixerate/editor 0.273.0 → 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.
@@ -97,7 +97,12 @@ export interface PaintProposalEchoOp {
97
97
  /** Recolour (default each stroke's colour). */
98
98
  color?: string;
99
99
  }
100
- export type PaintProposalOp = PaintProposalStrokeOp | PaintProposalWashOp | PaintProposalEchoOp;
100
+ /** Full recorded strokes (`RecordedStroke[]`) to paint with their own brush, colour, points and seed. */
101
+ export interface PaintProposalStrokesOp {
102
+ kind: 'strokes';
103
+ strokes: readonly RecordedStroke[];
104
+ }
105
+ export type PaintProposalOp = PaintProposalStrokeOp | PaintProposalWashOp | PaintProposalEchoOp | PaintProposalStrokesOp;
101
106
  /** Where accepted paint goes: a new layer of its own (above a layer, on top, or at the bottom, behind everything). */
102
107
  export interface PaintProposalPlacement {
103
108
  /** Default `top`. `above` needs `layerId`. */
@@ -97,7 +97,12 @@ export interface PaintProposalEchoOp {
97
97
  /** Recolour (default each stroke's colour). */
98
98
  color?: string;
99
99
  }
100
- export type PaintProposalOp = PaintProposalStrokeOp | PaintProposalWashOp | PaintProposalEchoOp;
100
+ /** Full recorded strokes (`RecordedStroke[]`) to paint with their own brush, colour, points and seed. */
101
+ export interface PaintProposalStrokesOp {
102
+ kind: 'strokes';
103
+ strokes: readonly RecordedStroke[];
104
+ }
105
+ export type PaintProposalOp = PaintProposalStrokeOp | PaintProposalWashOp | PaintProposalEchoOp | PaintProposalStrokesOp;
101
106
  /** Where accepted paint goes: a new layer of its own (above a layer, on top, or at the bottom, behind everything). */
102
107
  export interface PaintProposalPlacement {
103
108
  /** Default `top`. `above` needs `layerId`. */
@@ -56,6 +56,8 @@ import type { EffectDescription, EffectProvider, EffectValue } from '../effects/
56
56
  import { type PaintEffectPaint } from './effect-paint.cjs';
57
57
  import { type PaintEffectPlace, type PaintEffectSource, type PaintPaperEffect, type PaperEffectBlend } from './effects.cjs';
58
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';
59
61
  export declare class PaintEditorError extends Error {
60
62
  constructor(message: string);
61
63
  }
@@ -1692,6 +1694,35 @@ export declare class PaintEditorController {
1692
1694
  private readMixingPad;
1693
1695
  /** A layer's tile surface (live while stroking), for thumbnails. */
1694
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;
1695
1726
  }
1696
1727
  export type { Tile };
1697
1728
  /** Largest tracing or reference image side, in pixels. */
@@ -56,6 +56,8 @@ import type { EffectDescription, EffectProvider, EffectValue } from '../effects/
56
56
  import { type PaintEffectPaint } from './effect-paint.js';
57
57
  import { type PaintEffectPlace, type PaintEffectSource, type PaintPaperEffect, type PaperEffectBlend } from './effects.js';
58
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';
59
61
  export declare class PaintEditorError extends Error {
60
62
  constructor(message: string);
61
63
  }
@@ -1692,6 +1694,35 @@ export declare class PaintEditorController {
1692
1694
  private readMixingPad;
1693
1695
  /** A layer's tile surface (live while stroking), for thumbnails. */
1694
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;
1695
1726
  }
1696
1727
  export type { Tile };
1697
1728
  /** Largest tracing or reference image side, in pixels. */
@@ -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 };
@@ -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.js';
14
+ import type { PaintBrush } from './brushes.js';
15
+ import type { PaintProposal } from './collaboration.js';
16
+ import type { PaintEditorController, PixelImage } from './controller.js';
17
+ import type { PenPoint } from './engine.js';
18
+ import { strokeToJSON, type RecordedStroke, type StrokeVariation } from './strokes.js';
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 };