@pixerate/editor 0.107.0 → 0.108.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.
@@ -4,6 +4,7 @@ export { b as MAX_BRUSH_SIZE } from '../mixer-5ziHU8OS.cjs';
4
4
  import { R as RasterRect, a as TiledSurface, B as BlendMode, b as BlendModeInfo } from '../surface-CkKOHGPm.cjs';
5
5
  export { c as BLEND_MODES, d as PAINTERLY_BLEND_MODES, e as Tile, i as isBlendMode, f as isPainterlyBlendMode, s as standardBlendMode } from '../surface-CkKOHGPm.cjs';
6
6
  import { I as ImageEditorAssetStore, S as SerializedLayer, P as PsdExportResult } from '../export-JGWQEPJn.cjs';
7
+ import { g as PresenceStore, e as PresenceClock, d as PresenceActorInfo, c as PresenceActor, f as PresenceState } from '../presence-Cb6WhcrQ.cjs';
7
8
  import { a as AgentToolProvider } from '../registry-BqA1AZt0.cjs';
8
9
  import '../types-CwMPoRMU.cjs';
9
10
  import '../warp-D5jz_tN7.cjs';
@@ -1385,7 +1386,8 @@ declare class PaintEditorController {
1385
1386
  paintStroke(init: PaintStrokeInit & {
1386
1387
  points: readonly PenPoint[];
1387
1388
  }): PaintStrokeResult;
1388
- private checkPoints;
1389
+ /** Checks stroke samples (finite x and y, pressure 0..1) and returns them; throws a sentence naming the bad point. */
1390
+ checkPoints(points: readonly PenPoint[]): PenPoint[];
1389
1391
  /** Every recorded stroke, oldest first. */
1390
1392
  getStrokes(): readonly RecordedStroke[];
1391
1393
  /**
@@ -1533,6 +1535,91 @@ declare class PaintEditorController {
1533
1535
  /** Largest tracing or reference image side, in pixels. */
1534
1536
  declare const MAX_IMAGE_SIDE = 8192;
1535
1537
 
1538
+ type PaintPresenceActor = PresenceActor;
1539
+ type PaintPresenceState = PresenceState;
1540
+ /** Cursor positions (document pixels) and notes of agents painting, for an overlay. */
1541
+ declare class PaintPresence extends PresenceStore {
1542
+ }
1543
+ /** What an agent asks for. Each command that paints commits as one undo step. */
1544
+ type PaintAgentCommand = {
1545
+ kind: 'stroke';
1546
+ stroke: PaintStrokeInit & {
1547
+ points: readonly PenPoint[];
1548
+ };
1549
+ note?: string;
1550
+ } | {
1551
+ kind: 'fill';
1552
+ fill: FillLayerOptions;
1553
+ note?: string;
1554
+ } | {
1555
+ kind: 'replay';
1556
+ replay: ReplayOptions;
1557
+ note?: string;
1558
+ } | {
1559
+ kind: 'point';
1560
+ at: {
1561
+ x: number;
1562
+ y: number;
1563
+ };
1564
+ note?: string;
1565
+ } | {
1566
+ kind: 'say';
1567
+ text: string;
1568
+ };
1569
+ type PaintPerformanceResult = {
1570
+ ok: true;
1571
+ command: PaintAgentCommand;
1572
+ result?: unknown;
1573
+ } | {
1574
+ ok: false;
1575
+ command: PaintAgentCommand;
1576
+ message: string;
1577
+ };
1578
+ interface PaintDirectorOptions {
1579
+ clock?: PresenceClock;
1580
+ /** 1 = natural speed; 2 = twice as fast. */
1581
+ speed?: number;
1582
+ /** Hide each actor's cursor this long after its last command (ms, default 1500; 0 keeps it). */
1583
+ linger?: number;
1584
+ /** Longest a stroke takes to paint at speed 1 (ms, default 1800); longer strokes are sped up. */
1585
+ maxStrokeMs?: number;
1586
+ }
1587
+ /** Where along a stroke each point is reached, 0..1: by its time `t` when the points have times, else by distance. */
1588
+ declare function strokeSchedule(points: readonly PenPoint[]): number[];
1589
+ /** How long a stroke takes to paint at speed 1 (ms): its recorded duration, else ~1.5 px/ms, between 250 ms and `max`. */
1590
+ declare function strokeDuration(points: readonly PenPoint[], max?: number): number;
1591
+ /** A zig-zag across `rect` (for a fill rubbed over the sheet), `rows` passes from the top. */
1592
+ declare function sweepPath(rect: RasterRect, rows?: number): Array<{
1593
+ x: number;
1594
+ y: number;
1595
+ }>;
1596
+ /**
1597
+ * Acts out agent commands on a paint canvas: the actor's cursor glides to the stroke's start and
1598
+ * paints it live along its points (paced by their times, or evenly), the stroke committing as
1599
+ * one undo step; fills are rubbed across the sheet first; replays start from the strokes they
1600
+ * copy and end on what they painted. Commands queue per actor. A command that cannot apply (an
1601
+ * unknown or locked layer, a stroke the user is still painting) fails with the controller's
1602
+ * sentence before anything is painted.
1603
+ */
1604
+ declare class PaintDirector {
1605
+ private readonly controller;
1606
+ readonly presence: PaintPresence;
1607
+ private readonly options;
1608
+ private readonly clock;
1609
+ private readonly queue;
1610
+ constructor(controller: PaintEditorController, presence: PaintPresence, options?: PaintDirectorOptions);
1611
+ /** Acts out `commands` in order for `actor`. Resolves with one result per command. */
1612
+ perform(actor: PresenceActorInfo, commands: readonly PaintAgentCommand[]): Promise<PaintPerformanceResult[]>;
1613
+ private ms;
1614
+ private where;
1615
+ /** Glides to `to`; an actor that just appeared starts there instead of the corner. */
1616
+ private glide;
1617
+ private say;
1618
+ private performOne;
1619
+ /** Paints a stroke live: begins it, pushes its points frame by frame as the cursor reaches them, then ends it (one undo step). */
1620
+ private stroke;
1621
+ }
1622
+
1536
1623
  /**
1537
1624
  * Agent tools for the paint editor (`createPaintEditorToolProvider`). Strict schemas, every
1538
1625
  * argument described, all four annotations. Each write is one undo step (or editor state, said so)
@@ -1545,6 +1632,13 @@ interface PaintEditorToolProviderOptions {
1545
1632
  id?: string;
1546
1633
  /** Always prefix tool names with `<namespace>__`. */
1547
1634
  namespace?: string;
1635
+ /**
1636
+ * Acts out strokes, fills and replays with an agent cursor on the canvas (see `PaintDirector`):
1637
+ * strokes paint live along their points. Each call is still one undo step. Without it, they apply at once.
1638
+ */
1639
+ director?: PaintDirector;
1640
+ /** The agent's cursor (default `{ id: 'agent', name: 'Agent' }`). */
1641
+ actor?: PresenceActorInfo;
1548
1642
  }
1549
1643
  /** Agent tools for one paint editor. */
1550
1644
  declare function createPaintEditorToolProvider(controller: PaintEditorController, options?: PaintEditorToolProviderOptions): AgentToolProvider;
@@ -1688,4 +1782,4 @@ interface BlendMenuGroup {
1688
1782
  */
1689
1783
  declare const BLEND_MENU_GROUPS: readonly BlendMenuGroup[];
1690
1784
 
1691
- export { type Affine, BLEND_MENU_GROUPS, BRUSH_ID, BRUSH_ROTATIONS, BRUSH_SLIDERS, BUILTIN_BRUSHES, type BlendMenuGroup, BlendMode, BlendModeInfo, type BrushDynamics, type BrushLibraryFile, type BrushRotation, type BrushThumbnail, type ColorWheel, DEFAULT_BRUSH_ID, DEFAULT_DPI, DEFAULT_DYNAMICS, DEFAULT_PAPER, DEFAULT_SWATCHES, DEFAULT_VIEW, DryStroke, type DryStrokeOptions, type FillLayerOptions, GRAIN_PATTERNS, GRAIN_TILE, type GrainPattern, type GrainTuning, HARMONY_KINDS, type Hand, type HarmonyColor, type HarmonyKind, IDENTITY_AFFINE, IDENTITY_COPY, type ImageEncoder, type ImageFormat, type ImageNode, type LayerUpdate, type Linear2, type LoadedPaintDocument, MAX_CANVAS_SIDE, MAX_COORDINATE, MAX_IMAGE_SIDE, MAX_ZOOM, MIN_CANVAS_SIDE, MIN_ZOOM, MIXING_PAD_HEIGHT, MIXING_PAD_WIDTH, MixingPad, type MixingPadTool, PAINT_BRUSH_CATEGORIES, PAINT_BRUSH_ENGINES, PAINT_FORMAT, PAINT_SCHEMA_VERSION, PAINT_TOOLS, PAPER_FAMILIES, PAPER_LIBRARY, PAPER_NODE_ID, PAPER_SLIDERS, type Paint2DContext, type PaintAssetStore, type PaintBrush, type PaintBrushCategory, type PaintBrushEngine, type PaintBrushInput, type PaintCanvas, PaintCanvasPresenter, PaintDocumentError, type PaintDocumentExtensions, type PaintDocumentState, PaintEditorController, PaintEditorError, type PaintEditorOptions, type PaintEditorState, type PaintEditorToolProviderOptions, PaintGesture, type PaintGroupLayer, type PaintGuides, type PaintLayer, type PaintLayerInfo, type PaintPixelLayer, type PaintPointerEvent, type PaintStrokeInit, type PaintStrokeResult, PaintStrokeSession, type PaintTool, type PaintView, type PaperFamily, PaperGrain, type PaperNode, type PaperSettings, type PaperTiling, type PenDab, PenDabWalker, type PenPoint, PenSmoother, type PerspectiveGuide, PerspectiveSnapper, type PixelImage, type Point2, type PointerSample, type RecordedStroke, type ReferenceImage, type RenderOptions, type ReplayOptions, type Rgb255, SNAP_DECIDE_DISTANCE, SYMMETRY_MODES, type SerializeOptions, type SerializedPaintDocument, type SliderControl, type StrokeCopy, type StrokeSessionHost, type StrokeSessionInit, type StrokeVariation, type Swatch, type SymmetryGuide, type SymmetryMode, TRACING_NODE_ID, TileableNoise, type TracingImage, type ViewLayer, type ViewportBox, affineCopy, applyAffine, brushToJSON, clonePaper, colorHarmony, composeAffine, createPaintCompositor, createPaintDocument, createPaintEditorToolProvider, createPaintLayer, decodeImageBlob, defaultGuides, defaultImageEncoder, deserializePaintDocument, deserializePaintDocumentAsync, documentExtensions, documentToScreen, downloadBytes, downsampleRgba, fitZoom, grainCatch, grainHeights, guideOverlay, handlePaintShortcut, hash2, hexToRgb8, hslToRgb, hsvToRgb, hueToWheel, invertAffine, isPalmTouch, mapPenPoint, mix32, mixerLoadForStroke, mixerTip, newPaintLayerId, normalizeBrushStroke, normalizeCanvas, normalizeDynamics, normalizePaintBrush, normalizePaper, normalizePerspective, normalizeRotation, normalizeSymmetry, normalizeView, paperGrain, paperKey, paperNode, paperPreset, parseBrushLibrary, parseHexColor, patchPath, penOrientation, perspectiveDirections, perspectiveGuideLines, pointerToPenPoint, rand01, randSigned, readPath, renderBrushThumbnail, renderColorWheel, renderPaper, rgbToHexColor, rgbToHsl, rgbToHsv, samplePressure, screenToDocument, seedFromString, serializePaintDocument, serializePaintDocumentExternal, strokeBounds, symmetryAxisAngles, symmetryAxisSegments, symmetryCopies, thumbnailStroke, tiltToOrientation, toStrokePoint, variationAffine, varyStroke, viewCssTransform, viewMatrix, viewPenToDocument, wheelAngle, wheelPick, wheelPoint, wheelToHue };
1785
+ export { type Affine, BLEND_MENU_GROUPS, BRUSH_ID, BRUSH_ROTATIONS, BRUSH_SLIDERS, BUILTIN_BRUSHES, type BlendMenuGroup, BlendMode, BlendModeInfo, type BrushDynamics, type BrushLibraryFile, type BrushRotation, type BrushThumbnail, type ColorWheel, DEFAULT_BRUSH_ID, DEFAULT_DPI, DEFAULT_DYNAMICS, DEFAULT_PAPER, DEFAULT_SWATCHES, DEFAULT_VIEW, DryStroke, type DryStrokeOptions, type FillLayerOptions, GRAIN_PATTERNS, GRAIN_TILE, type GrainPattern, type GrainTuning, HARMONY_KINDS, type Hand, type HarmonyColor, type HarmonyKind, IDENTITY_AFFINE, IDENTITY_COPY, type ImageEncoder, type ImageFormat, type ImageNode, type LayerUpdate, type Linear2, type LoadedPaintDocument, MAX_CANVAS_SIDE, MAX_COORDINATE, MAX_IMAGE_SIDE, MAX_ZOOM, MIN_CANVAS_SIDE, MIN_ZOOM, MIXING_PAD_HEIGHT, MIXING_PAD_WIDTH, MixingPad, type MixingPadTool, PAINT_BRUSH_CATEGORIES, PAINT_BRUSH_ENGINES, PAINT_FORMAT, PAINT_SCHEMA_VERSION, PAINT_TOOLS, PAPER_FAMILIES, PAPER_LIBRARY, PAPER_NODE_ID, PAPER_SLIDERS, type Paint2DContext, type PaintAgentCommand, type PaintAssetStore, type PaintBrush, type PaintBrushCategory, type PaintBrushEngine, type PaintBrushInput, type PaintCanvas, PaintCanvasPresenter, PaintDirector, type PaintDirectorOptions, PaintDocumentError, type PaintDocumentExtensions, type PaintDocumentState, PaintEditorController, PaintEditorError, type PaintEditorOptions, type PaintEditorState, type PaintEditorToolProviderOptions, PaintGesture, type PaintGroupLayer, type PaintGuides, type PaintLayer, type PaintLayerInfo, type PaintPerformanceResult, type PaintPixelLayer, type PaintPointerEvent, PaintPresence, type PaintPresenceActor, type PaintPresenceState, type PaintStrokeInit, type PaintStrokeResult, PaintStrokeSession, type PaintTool, type PaintView, type PaperFamily, PaperGrain, type PaperNode, type PaperSettings, type PaperTiling, type PenDab, PenDabWalker, type PenPoint, PenSmoother, type PerspectiveGuide, PerspectiveSnapper, type PixelImage, type Point2, type PointerSample, type RecordedStroke, type ReferenceImage, type RenderOptions, type ReplayOptions, type Rgb255, SNAP_DECIDE_DISTANCE, SYMMETRY_MODES, type SerializeOptions, type SerializedPaintDocument, type SliderControl, type StrokeCopy, type StrokeSessionHost, type StrokeSessionInit, type StrokeVariation, type Swatch, type SymmetryGuide, type SymmetryMode, TRACING_NODE_ID, TileableNoise, type TracingImage, type ViewLayer, type ViewportBox, affineCopy, applyAffine, brushToJSON, clonePaper, colorHarmony, composeAffine, createPaintCompositor, createPaintDocument, createPaintEditorToolProvider, createPaintLayer, decodeImageBlob, defaultGuides, defaultImageEncoder, deserializePaintDocument, deserializePaintDocumentAsync, documentExtensions, documentToScreen, downloadBytes, downsampleRgba, fitZoom, grainCatch, grainHeights, guideOverlay, handlePaintShortcut, hash2, hexToRgb8, hslToRgb, hsvToRgb, hueToWheel, invertAffine, isPalmTouch, mapPenPoint, mix32, mixerLoadForStroke, mixerTip, newPaintLayerId, normalizeBrushStroke, normalizeCanvas, normalizeDynamics, normalizePaintBrush, normalizePaper, normalizePerspective, normalizeRotation, normalizeSymmetry, normalizeView, paperGrain, paperKey, paperNode, paperPreset, parseBrushLibrary, parseHexColor, patchPath, penOrientation, perspectiveDirections, perspectiveGuideLines, pointerToPenPoint, rand01, randSigned, readPath, renderBrushThumbnail, renderColorWheel, renderPaper, rgbToHexColor, rgbToHsl, rgbToHsv, samplePressure, screenToDocument, seedFromString, serializePaintDocument, serializePaintDocumentExternal, strokeBounds, strokeDuration, strokeSchedule, sweepPath, symmetryAxisAngles, symmetryAxisSegments, symmetryCopies, thumbnailStroke, tiltToOrientation, toStrokePoint, variationAffine, varyStroke, viewCssTransform, viewMatrix, viewPenToDocument, wheelAngle, wheelPick, wheelPoint, wheelToHue };
@@ -4,6 +4,7 @@ export { b as MAX_BRUSH_SIZE } from '../mixer-DNqiYXYQ.js';
4
4
  import { R as RasterRect, a as TiledSurface, B as BlendMode, b as BlendModeInfo } from '../surface-CkKOHGPm.js';
5
5
  export { c as BLEND_MODES, d as PAINTERLY_BLEND_MODES, e as Tile, i as isBlendMode, f as isPainterlyBlendMode, s as standardBlendMode } from '../surface-CkKOHGPm.js';
6
6
  import { I as ImageEditorAssetStore, S as SerializedLayer, P as PsdExportResult } from '../export-a9bnF7Cl.js';
7
+ import { g as PresenceStore, e as PresenceClock, d as PresenceActorInfo, c as PresenceActor, f as PresenceState } from '../presence-Cb6WhcrQ.js';
7
8
  import { a as AgentToolProvider } from '../registry-D-4fit9C.js';
8
9
  import '../types-CwMPoRMU.js';
9
10
  import '../warp-CWHZzE3x.js';
@@ -1385,7 +1386,8 @@ declare class PaintEditorController {
1385
1386
  paintStroke(init: PaintStrokeInit & {
1386
1387
  points: readonly PenPoint[];
1387
1388
  }): PaintStrokeResult;
1388
- private checkPoints;
1389
+ /** Checks stroke samples (finite x and y, pressure 0..1) and returns them; throws a sentence naming the bad point. */
1390
+ checkPoints(points: readonly PenPoint[]): PenPoint[];
1389
1391
  /** Every recorded stroke, oldest first. */
1390
1392
  getStrokes(): readonly RecordedStroke[];
1391
1393
  /**
@@ -1533,6 +1535,91 @@ declare class PaintEditorController {
1533
1535
  /** Largest tracing or reference image side, in pixels. */
1534
1536
  declare const MAX_IMAGE_SIDE = 8192;
1535
1537
 
1538
+ type PaintPresenceActor = PresenceActor;
1539
+ type PaintPresenceState = PresenceState;
1540
+ /** Cursor positions (document pixels) and notes of agents painting, for an overlay. */
1541
+ declare class PaintPresence extends PresenceStore {
1542
+ }
1543
+ /** What an agent asks for. Each command that paints commits as one undo step. */
1544
+ type PaintAgentCommand = {
1545
+ kind: 'stroke';
1546
+ stroke: PaintStrokeInit & {
1547
+ points: readonly PenPoint[];
1548
+ };
1549
+ note?: string;
1550
+ } | {
1551
+ kind: 'fill';
1552
+ fill: FillLayerOptions;
1553
+ note?: string;
1554
+ } | {
1555
+ kind: 'replay';
1556
+ replay: ReplayOptions;
1557
+ note?: string;
1558
+ } | {
1559
+ kind: 'point';
1560
+ at: {
1561
+ x: number;
1562
+ y: number;
1563
+ };
1564
+ note?: string;
1565
+ } | {
1566
+ kind: 'say';
1567
+ text: string;
1568
+ };
1569
+ type PaintPerformanceResult = {
1570
+ ok: true;
1571
+ command: PaintAgentCommand;
1572
+ result?: unknown;
1573
+ } | {
1574
+ ok: false;
1575
+ command: PaintAgentCommand;
1576
+ message: string;
1577
+ };
1578
+ interface PaintDirectorOptions {
1579
+ clock?: PresenceClock;
1580
+ /** 1 = natural speed; 2 = twice as fast. */
1581
+ speed?: number;
1582
+ /** Hide each actor's cursor this long after its last command (ms, default 1500; 0 keeps it). */
1583
+ linger?: number;
1584
+ /** Longest a stroke takes to paint at speed 1 (ms, default 1800); longer strokes are sped up. */
1585
+ maxStrokeMs?: number;
1586
+ }
1587
+ /** Where along a stroke each point is reached, 0..1: by its time `t` when the points have times, else by distance. */
1588
+ declare function strokeSchedule(points: readonly PenPoint[]): number[];
1589
+ /** How long a stroke takes to paint at speed 1 (ms): its recorded duration, else ~1.5 px/ms, between 250 ms and `max`. */
1590
+ declare function strokeDuration(points: readonly PenPoint[], max?: number): number;
1591
+ /** A zig-zag across `rect` (for a fill rubbed over the sheet), `rows` passes from the top. */
1592
+ declare function sweepPath(rect: RasterRect, rows?: number): Array<{
1593
+ x: number;
1594
+ y: number;
1595
+ }>;
1596
+ /**
1597
+ * Acts out agent commands on a paint canvas: the actor's cursor glides to the stroke's start and
1598
+ * paints it live along its points (paced by their times, or evenly), the stroke committing as
1599
+ * one undo step; fills are rubbed across the sheet first; replays start from the strokes they
1600
+ * copy and end on what they painted. Commands queue per actor. A command that cannot apply (an
1601
+ * unknown or locked layer, a stroke the user is still painting) fails with the controller's
1602
+ * sentence before anything is painted.
1603
+ */
1604
+ declare class PaintDirector {
1605
+ private readonly controller;
1606
+ readonly presence: PaintPresence;
1607
+ private readonly options;
1608
+ private readonly clock;
1609
+ private readonly queue;
1610
+ constructor(controller: PaintEditorController, presence: PaintPresence, options?: PaintDirectorOptions);
1611
+ /** Acts out `commands` in order for `actor`. Resolves with one result per command. */
1612
+ perform(actor: PresenceActorInfo, commands: readonly PaintAgentCommand[]): Promise<PaintPerformanceResult[]>;
1613
+ private ms;
1614
+ private where;
1615
+ /** Glides to `to`; an actor that just appeared starts there instead of the corner. */
1616
+ private glide;
1617
+ private say;
1618
+ private performOne;
1619
+ /** Paints a stroke live: begins it, pushes its points frame by frame as the cursor reaches them, then ends it (one undo step). */
1620
+ private stroke;
1621
+ }
1622
+
1536
1623
  /**
1537
1624
  * Agent tools for the paint editor (`createPaintEditorToolProvider`). Strict schemas, every
1538
1625
  * argument described, all four annotations. Each write is one undo step (or editor state, said so)
@@ -1545,6 +1632,13 @@ interface PaintEditorToolProviderOptions {
1545
1632
  id?: string;
1546
1633
  /** Always prefix tool names with `<namespace>__`. */
1547
1634
  namespace?: string;
1635
+ /**
1636
+ * Acts out strokes, fills and replays with an agent cursor on the canvas (see `PaintDirector`):
1637
+ * strokes paint live along their points. Each call is still one undo step. Without it, they apply at once.
1638
+ */
1639
+ director?: PaintDirector;
1640
+ /** The agent's cursor (default `{ id: 'agent', name: 'Agent' }`). */
1641
+ actor?: PresenceActorInfo;
1548
1642
  }
1549
1643
  /** Agent tools for one paint editor. */
1550
1644
  declare function createPaintEditorToolProvider(controller: PaintEditorController, options?: PaintEditorToolProviderOptions): AgentToolProvider;
@@ -1688,4 +1782,4 @@ interface BlendMenuGroup {
1688
1782
  */
1689
1783
  declare const BLEND_MENU_GROUPS: readonly BlendMenuGroup[];
1690
1784
 
1691
- export { type Affine, BLEND_MENU_GROUPS, BRUSH_ID, BRUSH_ROTATIONS, BRUSH_SLIDERS, BUILTIN_BRUSHES, type BlendMenuGroup, BlendMode, BlendModeInfo, type BrushDynamics, type BrushLibraryFile, type BrushRotation, type BrushThumbnail, type ColorWheel, DEFAULT_BRUSH_ID, DEFAULT_DPI, DEFAULT_DYNAMICS, DEFAULT_PAPER, DEFAULT_SWATCHES, DEFAULT_VIEW, DryStroke, type DryStrokeOptions, type FillLayerOptions, GRAIN_PATTERNS, GRAIN_TILE, type GrainPattern, type GrainTuning, HARMONY_KINDS, type Hand, type HarmonyColor, type HarmonyKind, IDENTITY_AFFINE, IDENTITY_COPY, type ImageEncoder, type ImageFormat, type ImageNode, type LayerUpdate, type Linear2, type LoadedPaintDocument, MAX_CANVAS_SIDE, MAX_COORDINATE, MAX_IMAGE_SIDE, MAX_ZOOM, MIN_CANVAS_SIDE, MIN_ZOOM, MIXING_PAD_HEIGHT, MIXING_PAD_WIDTH, MixingPad, type MixingPadTool, PAINT_BRUSH_CATEGORIES, PAINT_BRUSH_ENGINES, PAINT_FORMAT, PAINT_SCHEMA_VERSION, PAINT_TOOLS, PAPER_FAMILIES, PAPER_LIBRARY, PAPER_NODE_ID, PAPER_SLIDERS, type Paint2DContext, type PaintAssetStore, type PaintBrush, type PaintBrushCategory, type PaintBrushEngine, type PaintBrushInput, type PaintCanvas, PaintCanvasPresenter, PaintDocumentError, type PaintDocumentExtensions, type PaintDocumentState, PaintEditorController, PaintEditorError, type PaintEditorOptions, type PaintEditorState, type PaintEditorToolProviderOptions, PaintGesture, type PaintGroupLayer, type PaintGuides, type PaintLayer, type PaintLayerInfo, type PaintPixelLayer, type PaintPointerEvent, type PaintStrokeInit, type PaintStrokeResult, PaintStrokeSession, type PaintTool, type PaintView, type PaperFamily, PaperGrain, type PaperNode, type PaperSettings, type PaperTiling, type PenDab, PenDabWalker, type PenPoint, PenSmoother, type PerspectiveGuide, PerspectiveSnapper, type PixelImage, type Point2, type PointerSample, type RecordedStroke, type ReferenceImage, type RenderOptions, type ReplayOptions, type Rgb255, SNAP_DECIDE_DISTANCE, SYMMETRY_MODES, type SerializeOptions, type SerializedPaintDocument, type SliderControl, type StrokeCopy, type StrokeSessionHost, type StrokeSessionInit, type StrokeVariation, type Swatch, type SymmetryGuide, type SymmetryMode, TRACING_NODE_ID, TileableNoise, type TracingImage, type ViewLayer, type ViewportBox, affineCopy, applyAffine, brushToJSON, clonePaper, colorHarmony, composeAffine, createPaintCompositor, createPaintDocument, createPaintEditorToolProvider, createPaintLayer, decodeImageBlob, defaultGuides, defaultImageEncoder, deserializePaintDocument, deserializePaintDocumentAsync, documentExtensions, documentToScreen, downloadBytes, downsampleRgba, fitZoom, grainCatch, grainHeights, guideOverlay, handlePaintShortcut, hash2, hexToRgb8, hslToRgb, hsvToRgb, hueToWheel, invertAffine, isPalmTouch, mapPenPoint, mix32, mixerLoadForStroke, mixerTip, newPaintLayerId, normalizeBrushStroke, normalizeCanvas, normalizeDynamics, normalizePaintBrush, normalizePaper, normalizePerspective, normalizeRotation, normalizeSymmetry, normalizeView, paperGrain, paperKey, paperNode, paperPreset, parseBrushLibrary, parseHexColor, patchPath, penOrientation, perspectiveDirections, perspectiveGuideLines, pointerToPenPoint, rand01, randSigned, readPath, renderBrushThumbnail, renderColorWheel, renderPaper, rgbToHexColor, rgbToHsl, rgbToHsv, samplePressure, screenToDocument, seedFromString, serializePaintDocument, serializePaintDocumentExternal, strokeBounds, symmetryAxisAngles, symmetryAxisSegments, symmetryCopies, thumbnailStroke, tiltToOrientation, toStrokePoint, variationAffine, varyStroke, viewCssTransform, viewMatrix, viewPenToDocument, wheelAngle, wheelPick, wheelPoint, wheelToHue };
1785
+ export { type Affine, BLEND_MENU_GROUPS, BRUSH_ID, BRUSH_ROTATIONS, BRUSH_SLIDERS, BUILTIN_BRUSHES, type BlendMenuGroup, BlendMode, BlendModeInfo, type BrushDynamics, type BrushLibraryFile, type BrushRotation, type BrushThumbnail, type ColorWheel, DEFAULT_BRUSH_ID, DEFAULT_DPI, DEFAULT_DYNAMICS, DEFAULT_PAPER, DEFAULT_SWATCHES, DEFAULT_VIEW, DryStroke, type DryStrokeOptions, type FillLayerOptions, GRAIN_PATTERNS, GRAIN_TILE, type GrainPattern, type GrainTuning, HARMONY_KINDS, type Hand, type HarmonyColor, type HarmonyKind, IDENTITY_AFFINE, IDENTITY_COPY, type ImageEncoder, type ImageFormat, type ImageNode, type LayerUpdate, type Linear2, type LoadedPaintDocument, MAX_CANVAS_SIDE, MAX_COORDINATE, MAX_IMAGE_SIDE, MAX_ZOOM, MIN_CANVAS_SIDE, MIN_ZOOM, MIXING_PAD_HEIGHT, MIXING_PAD_WIDTH, MixingPad, type MixingPadTool, PAINT_BRUSH_CATEGORIES, PAINT_BRUSH_ENGINES, PAINT_FORMAT, PAINT_SCHEMA_VERSION, PAINT_TOOLS, PAPER_FAMILIES, PAPER_LIBRARY, PAPER_NODE_ID, PAPER_SLIDERS, type Paint2DContext, type PaintAgentCommand, type PaintAssetStore, type PaintBrush, type PaintBrushCategory, type PaintBrushEngine, type PaintBrushInput, type PaintCanvas, PaintCanvasPresenter, PaintDirector, type PaintDirectorOptions, PaintDocumentError, type PaintDocumentExtensions, type PaintDocumentState, PaintEditorController, PaintEditorError, type PaintEditorOptions, type PaintEditorState, type PaintEditorToolProviderOptions, PaintGesture, type PaintGroupLayer, type PaintGuides, type PaintLayer, type PaintLayerInfo, type PaintPerformanceResult, type PaintPixelLayer, type PaintPointerEvent, PaintPresence, type PaintPresenceActor, type PaintPresenceState, type PaintStrokeInit, type PaintStrokeResult, PaintStrokeSession, type PaintTool, type PaintView, type PaperFamily, PaperGrain, type PaperNode, type PaperSettings, type PaperTiling, type PenDab, PenDabWalker, type PenPoint, PenSmoother, type PerspectiveGuide, PerspectiveSnapper, type PixelImage, type Point2, type PointerSample, type RecordedStroke, type ReferenceImage, type RenderOptions, type ReplayOptions, type Rgb255, SNAP_DECIDE_DISTANCE, SYMMETRY_MODES, type SerializeOptions, type SerializedPaintDocument, type SliderControl, type StrokeCopy, type StrokeSessionHost, type StrokeSessionInit, type StrokeVariation, type Swatch, type SymmetryGuide, type SymmetryMode, TRACING_NODE_ID, TileableNoise, type TracingImage, type ViewLayer, type ViewportBox, affineCopy, applyAffine, brushToJSON, clonePaper, colorHarmony, composeAffine, createPaintCompositor, createPaintDocument, createPaintEditorToolProvider, createPaintLayer, decodeImageBlob, defaultGuides, defaultImageEncoder, deserializePaintDocument, deserializePaintDocumentAsync, documentExtensions, documentToScreen, downloadBytes, downsampleRgba, fitZoom, grainCatch, grainHeights, guideOverlay, handlePaintShortcut, hash2, hexToRgb8, hslToRgb, hsvToRgb, hueToWheel, invertAffine, isPalmTouch, mapPenPoint, mix32, mixerLoadForStroke, mixerTip, newPaintLayerId, normalizeBrushStroke, normalizeCanvas, normalizeDynamics, normalizePaintBrush, normalizePaper, normalizePerspective, normalizeRotation, normalizeSymmetry, normalizeView, paperGrain, paperKey, paperNode, paperPreset, parseBrushLibrary, parseHexColor, patchPath, penOrientation, perspectiveDirections, perspectiveGuideLines, pointerToPenPoint, rand01, randSigned, readPath, renderBrushThumbnail, renderColorWheel, renderPaper, rgbToHexColor, rgbToHsl, rgbToHsv, samplePressure, screenToDocument, seedFromString, serializePaintDocument, serializePaintDocumentExternal, strokeBounds, strokeDuration, strokeSchedule, sweepPath, symmetryAxisAngles, symmetryAxisSegments, symmetryCopies, thumbnailStroke, tiltToOrientation, toStrokePoint, variationAffine, varyStroke, viewCssTransform, viewMatrix, viewPenToDocument, wheelAngle, wheelPick, wheelPoint, wheelToHue };
@@ -54,6 +54,12 @@ import {
54
54
  tileKey,
55
55
  tilesInRect
56
56
  } from "../chunk-WMBIJCHA.js";
57
+ import {
58
+ PerformanceQueue,
59
+ PresenceStore,
60
+ realPresenceClock,
61
+ tweenPresenceCursor
62
+ } from "../chunk-B6DSIEXA.js";
57
63
  import "../chunk-KKREERP2.js";
58
64
 
59
65
  // src/paint-editor/noise.ts
@@ -2716,6 +2722,7 @@ var PaintEditorController = class {
2716
2722
  else this.emit([]);
2717
2723
  return result;
2718
2724
  }
2725
+ /** Checks stroke samples (finite x and y, pressure 0..1) and returns them; throws a sentence naming the bad point. */
2719
2726
  checkPoints(points) {
2720
2727
  if (!Array.isArray(points) || !points.length) throw new PaintEditorError("points is empty; give at least one {x, y} in document pixels.");
2721
2728
  const out = [];
@@ -3250,6 +3257,169 @@ function resampleInto(src, rect, width, height) {
3250
3257
  return { width, height, data: out };
3251
3258
  }
3252
3259
 
3260
+ // src/paint-editor/presence.ts
3261
+ var PaintPresence = class extends PresenceStore {
3262
+ };
3263
+ var FRAME = 16;
3264
+ function strokeSchedule(points) {
3265
+ if (points.length < 2) return points.map(() => 1);
3266
+ const t0 = points[0].t;
3267
+ const t1 = points[points.length - 1].t;
3268
+ if (points.every((p) => Number.isFinite(p.t)) && t1 > t0) {
3269
+ return points.map((p) => Math.min(1, Math.max(0, (p.t - t0) / (t1 - t0))));
3270
+ }
3271
+ const acc = [0];
3272
+ for (let i = 1; i < points.length; i++) acc.push(acc[i - 1] + Math.hypot(points[i].x - points[i - 1].x, points[i].y - points[i - 1].y));
3273
+ const total = acc[acc.length - 1];
3274
+ return total > 0 ? acc.map((d) => d / total) : points.map(() => 1);
3275
+ }
3276
+ function strokeDuration(points, max = 1800) {
3277
+ const t0 = points[0]?.t;
3278
+ const t1 = points[points.length - 1]?.t;
3279
+ let ms;
3280
+ if (points.every((p) => Number.isFinite(p.t)) && t1 > t0) ms = t1 - t0;
3281
+ else {
3282
+ let length = 0;
3283
+ for (let i = 1; i < points.length; i++) length += Math.hypot(points[i].x - points[i - 1].x, points[i].y - points[i - 1].y);
3284
+ ms = length / 1.5;
3285
+ }
3286
+ return Math.min(max, Math.max(250, ms));
3287
+ }
3288
+ function sweepPath(rect, rows = 4) {
3289
+ const inset = Math.min(rect.width, rect.height) * 0.08;
3290
+ const left = rect.x + inset;
3291
+ const right = rect.x + rect.width - inset;
3292
+ const out = [];
3293
+ for (let r = 0; r < rows; r++) {
3294
+ const y = rect.y + inset + (rect.height - 2 * inset) * (r + 0.5) / rows;
3295
+ out.push(r % 2 ? { x: right, y } : { x: left, y }, r % 2 ? { x: left, y } : { x: right, y });
3296
+ }
3297
+ return out;
3298
+ }
3299
+ var centre = (r) => ({ x: r.x + r.width / 2, y: r.y + r.height / 2 });
3300
+ var PaintDirector = class {
3301
+ constructor(controller, presence, options = {}) {
3302
+ this.controller = controller;
3303
+ this.presence = presence;
3304
+ this.options = options;
3305
+ this.clock = options.clock ?? realPresenceClock;
3306
+ this.queue = new PerformanceQueue(presence, { clock: this.clock, linger: options.linger });
3307
+ }
3308
+ controller;
3309
+ presence;
3310
+ options;
3311
+ clock;
3312
+ queue;
3313
+ /** Acts out `commands` in order for `actor`. Resolves with one result per command. */
3314
+ perform(actor, commands) {
3315
+ return this.queue.run(actor, async () => {
3316
+ const results = [];
3317
+ for (const command of commands) {
3318
+ try {
3319
+ results.push({ ok: true, command, result: await this.performOne(actor.id, command) });
3320
+ } catch (error) {
3321
+ results.push({ ok: false, command, message: error instanceof Error ? error.message : String(error) });
3322
+ }
3323
+ }
3324
+ return results;
3325
+ });
3326
+ }
3327
+ ms(n) {
3328
+ return Math.round(n / Math.max(0.1, this.options.speed ?? 1));
3329
+ }
3330
+ where(id) {
3331
+ const a = this.presence.get(id);
3332
+ return { x: a?.x ?? 0, y: a?.y ?? 0 };
3333
+ }
3334
+ /** Glides to `to`; an actor that just appeared starts there instead of the corner. */
3335
+ async glide(id, to, ms = 380) {
3336
+ const a = this.presence.get(id);
3337
+ if (!a || a.x === 0 && a.y === 0) {
3338
+ this.presence.set({ id, x: to.x, y: to.y });
3339
+ return;
3340
+ }
3341
+ await tweenPresenceCursor(this.presence, this.clock, id, this.where(id), to, this.ms(ms));
3342
+ }
3343
+ async say(id, text, ms) {
3344
+ if (!text) return;
3345
+ this.presence.set({ id, message: text });
3346
+ await this.clock.wait(this.ms(ms));
3347
+ }
3348
+ async performOne(id, command) {
3349
+ const c = this.controller;
3350
+ switch (command.kind) {
3351
+ case "say":
3352
+ await this.say(id, command.text, 900);
3353
+ return void 0;
3354
+ case "point":
3355
+ await this.say(id, command.note, 500);
3356
+ await this.glide(id, command.at);
3357
+ this.presence.set({ id, pressed: true });
3358
+ await this.clock.wait(this.ms(110));
3359
+ this.presence.set({ id, pressed: false });
3360
+ return void 0;
3361
+ case "stroke":
3362
+ await this.say(id, command.note, 500);
3363
+ return this.stroke(id, command.stroke);
3364
+ case "fill": {
3365
+ await this.say(id, command.note, 500);
3366
+ const { width, height } = c.getState().document.canvas;
3367
+ const path = sweepPath({ x: 0, y: 0, width, height });
3368
+ await this.glide(id, path[0]);
3369
+ this.presence.set({ id, pressed: true });
3370
+ try {
3371
+ for (let i = 1; i < path.length; i++) await tweenPresenceCursor(this.presence, this.clock, id, path[i - 1], path[i], this.ms(i % 2 ? 260 : 90));
3372
+ } finally {
3373
+ this.presence.set({ id, pressed: false });
3374
+ }
3375
+ return c.fillLayer(command.fill);
3376
+ }
3377
+ case "replay": {
3378
+ await this.say(id, command.note, 500);
3379
+ const source = c.getStrokes().filter((s) => command.replay.strokeIds?.includes(s.id));
3380
+ const first = source[0]?.points[0];
3381
+ if (first) await this.glide(id, first);
3382
+ const result = c.replayStrokes(command.replay);
3383
+ if (result.bounds) await this.glide(id, centre(result.bounds), 520);
3384
+ return result;
3385
+ }
3386
+ }
3387
+ }
3388
+ /** Paints a stroke live: begins it, pushes its points frame by frame as the cursor reaches them, then ends it (one undo step). */
3389
+ async stroke(id, init) {
3390
+ const c = this.controller;
3391
+ const points = c.checkPoints(init.points);
3392
+ const { points: _points, ...rest } = init;
3393
+ const session = c.beginStroke({ snapToPerspective: false, start: points[0], ...rest });
3394
+ try {
3395
+ await this.glide(id, points[0]);
3396
+ this.presence.set({ id, pressed: true });
3397
+ const at = strokeSchedule(points);
3398
+ const duration = this.ms(strokeDuration(points, this.options.maxStrokeMs));
3399
+ let next = 0;
3400
+ const frames = Math.max(1, Math.round(duration / FRAME));
3401
+ for (let f = 1; f <= frames; f++) {
3402
+ const t = f / frames;
3403
+ const from = next;
3404
+ while (next < points.length && at[next] <= t + 1e-9) next++;
3405
+ if (next > from) {
3406
+ session.push(points.slice(from, next));
3407
+ const p = points[next - 1];
3408
+ this.presence.set({ id, x: p.x, y: p.y });
3409
+ }
3410
+ if (f < frames) await this.clock.wait(duration / frames);
3411
+ }
3412
+ if (next < points.length) session.push(points.slice(next));
3413
+ this.presence.set({ id, pressed: false });
3414
+ return session.end();
3415
+ } catch (error) {
3416
+ if (c.activeStroke === session) session.cancel();
3417
+ this.presence.set({ id, pressed: false });
3418
+ throw error;
3419
+ }
3420
+ }
3421
+ };
3422
+
3253
3423
  // src/paint-editor/guide-tools.ts
3254
3424
  var READ = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
3255
3425
  var WRITE = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
@@ -3685,6 +3855,12 @@ function createPaintEditorToolProvider(controller, options = {}) {
3685
3855
  const c = controller;
3686
3856
  const tools = [];
3687
3857
  const add = (t) => tools.push(t);
3858
+ const act = async (command, direct) => {
3859
+ if (!options.director) return direct();
3860
+ const [r] = await options.director.perform(options.actor ?? { id: "agent", name: "Agent" }, [command]);
3861
+ if (!r || !r.ok) throw new Error(r && !r.ok ? r.message : "The director did not run the command.");
3862
+ return r.result;
3863
+ };
3688
3864
  add({
3689
3865
  name: "get_canvas_info",
3690
3866
  title: "Get the canvas",
@@ -3949,7 +4125,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
3949
4125
  additionalProperties: false
3950
4126
  },
3951
4127
  annotations: { title: "Fill a layer", ...WRITE2 },
3952
- handler: (a) => c.fillLayer(a)
4128
+ handler: (a) => act({ kind: "fill", fill: a }, () => c.fillLayer(a))
3953
4129
  });
3954
4130
  add({
3955
4131
  name: "clear_layer",
@@ -4132,7 +4308,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
4132
4308
  add({
4133
4309
  name: "paint_stroke",
4134
4310
  title: "Paint a brush stroke",
4135
- description: "Paints one stroke through points (document pixels, with optional pressure, time, tilt and barrel rotation) on a pixel layer with a library brush or the active one, optionally changed for this stroke. Grain-responsive brushes follow the paper; the mixer engine (mixer-brush, blender, smudge) picks up and moves paint already on the layer. The symmetry guide adds its mirror copies; with a tracing image that samples colours, a stroke without color takes the image colour at its first point. One undo step. Returns the layer id, changed bounds, dab count, the recorded strokeId (for replay_strokes) and, for the mixer, its load after the stroke.",
4311
+ description: "Paints one stroke through points (document pixels, with optional pressure, time, tilt and barrel rotation) on a pixel layer with a library brush or the active one, optionally changed for this stroke. Grain-responsive brushes follow the paper; the mixer engine (mixer-brush, blender, smudge) picks up and moves paint already on the layer. The symmetry guide adds its mirror copies; with a tracing image that samples colours, a stroke without color takes the image colour at its first point. With an agent cursor (a director), the stroke is painted live along the points at the pace of their times. One undo step. Returns the layer id, changed bounds, dab count, the recorded strokeId (for replay_strokes) and, for the mixer, its load after the stroke.",
4136
4312
  inputSchema: {
4137
4313
  type: "object",
4138
4314
  properties: {
@@ -4148,8 +4324,9 @@ function createPaintEditorToolProvider(controller, options = {}) {
4148
4324
  additionalProperties: false
4149
4325
  },
4150
4326
  annotations: { title: "Paint a brush stroke", ...WRITE2 },
4151
- handler: (a) => {
4152
- const r = c.paintStroke({ points: a.points, layerId: a.layerId, brushId: a.brushId, brush: a.brush, color: a.color, seed: a.seed, snapToPerspective: a.snapToPerspective });
4327
+ handler: async (a) => {
4328
+ const stroke = { points: a.points, layerId: a.layerId, brushId: a.brushId, brush: a.brush, color: a.color, seed: a.seed, snapToPerspective: a.snapToPerspective };
4329
+ const r = await act({ kind: "stroke", stroke }, () => c.paintStroke(stroke));
4153
4330
  return r.mixerLoad ? { ...r, mixerLoad: loadResult(r.mixerLoad) } : r;
4154
4331
  }
4155
4332
  });
@@ -4223,7 +4400,10 @@ function createPaintEditorToolProvider(controller, options = {}) {
4223
4400
  additionalProperties: false
4224
4401
  },
4225
4402
  annotations: { title: "Replay strokes, varied", ...WRITE2 },
4226
- handler: (a) => c.replayStrokes(a)
4403
+ handler: (a) => {
4404
+ const replay = a;
4405
+ return act({ kind: "replay", replay }, () => c.replayStrokes(replay));
4406
+ }
4227
4407
  });
4228
4408
  add({
4229
4409
  name: "set_view",
@@ -4675,10 +4855,12 @@ export {
4675
4855
  PAPER_NODE_ID,
4676
4856
  PAPER_SLIDERS,
4677
4857
  PaintCanvasPresenter,
4858
+ PaintDirector,
4678
4859
  PaintDocumentError,
4679
4860
  PaintEditorController,
4680
4861
  PaintEditorError,
4681
4862
  PaintGesture,
4863
+ PaintPresence,
4682
4864
  PaintStrokeSession,
4683
4865
  PaperGrain,
4684
4866
  PenDabWalker,
@@ -4762,6 +4944,9 @@ export {
4762
4944
  serializePaintDocumentExternal,
4763
4945
  standardBlendMode,
4764
4946
  strokeBounds,
4947
+ strokeDuration,
4948
+ strokeSchedule,
4949
+ sweepPath,
4765
4950
  symmetryAxisAngles,
4766
4951
  symmetryAxisSegments,
4767
4952
  symmetryCopies,