@canvas-harness/core 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -71,6 +71,13 @@ type Style = {
71
71
  * per-keystroke).
72
72
  */
73
73
  autoFit?: boolean;
74
+ /**
75
+ * Color applied to SVG icons (`node.type === 'icon'`) — substitutes
76
+ * every `currentColor` occurrence in the SVG markup before
77
+ * rasterizing. The rasterizer caches by `(markup, iconColor, size)`
78
+ * so changing this re-keys without invalidating other variants.
79
+ */
80
+ iconColor?: string;
74
81
  };
75
82
  type EdgeStyle = Style & {
76
83
  sourceArrowhead?: Arrowhead;
@@ -126,6 +133,28 @@ type Node = {
126
133
  style?: Style;
127
134
  data?: unknown;
128
135
  };
136
+ /**
137
+ * `node.data` shape for `node.type === 'image'`. `src` is a self-
138
+ * contained data URI (we don't accept external URLs to keep scenes
139
+ * portable + CORS-free). `naturalW` / `naturalH` are the post-downscale
140
+ * dimensions used for aspect-ratio preservation on resize.
141
+ */
142
+ type ImageNodeData = {
143
+ src: string;
144
+ naturalW: number;
145
+ naturalH: number;
146
+ alt?: string;
147
+ };
148
+ /**
149
+ * `node.data` shape for `node.type === 'icon'`. `src` is sanitized
150
+ * SVG markup (scripts + event handlers stripped at add time). The
151
+ * recolor knob lives on `style.iconColor`, not here, so theming
152
+ * flows through the same channel as other style tokens.
153
+ */
154
+ type IconNodeData = {
155
+ src: string;
156
+ alt?: string;
157
+ };
129
158
 
130
159
  type PathStyle = 'straight' | 'bezier' | 'polyline';
131
160
  /**
@@ -198,6 +227,14 @@ type Scene = {
198
227
  groups: Record<GroupId, Group>;
199
228
  camera: CameraState;
200
229
  selection: (NodeId | EdgeId)[];
230
+ /**
231
+ * Presentation order for frame-typed nodes. Auto-maintained by the
232
+ * store on `node.add` / `node.remove`; explicitly mutated via
233
+ * `setFrameOrder` (which emits a `frame.reorder` op). Optional for
234
+ * backward compat — missing on older saved scenes is treated as [].
235
+ * See ARCHITECTURE.md §3.7 frames.
236
+ */
237
+ frameOrder?: NodeId[];
201
238
  };
202
239
  /**
203
240
  * On-the-wire serialized form. Arrays gzip smaller and have predictable iteration order.
@@ -210,6 +247,7 @@ type SerializedScene = {
210
247
  groups: Group[];
211
248
  camera: CameraState;
212
249
  selection: (NodeId | EdgeId)[];
250
+ frameOrder?: NodeId[];
213
251
  };
214
252
 
215
253
  /**
@@ -247,6 +285,10 @@ type Op = {
247
285
  } | {
248
286
  type: 'group.remove';
249
287
  group: Group;
288
+ } | {
289
+ type: 'frame.reorder';
290
+ ids: NodeId[];
291
+ prev: NodeId[];
250
292
  };
251
293
  /**
252
294
  * A batch is the atomic unit of mutation (also the unit of undo/redo and sync).
@@ -1475,6 +1517,55 @@ interface CanvasStore {
1475
1517
  * batch (so one undo restores the node + every edge that pointed to it).
1476
1518
  */
1477
1519
  removeNode(id: NodeId): void;
1520
+ /**
1521
+ * Adds a raster image node. Async because the input may need decoding
1522
+ * + downscaling before storage. Accepts `File` / `Blob` / data URI;
1523
+ * external URLs are rejected to keep scenes self-contained.
1524
+ *
1525
+ * PNG and JPEG only; up to 2 MB. Larger sources throw immediately
1526
+ * (caller should surface the error in UI).
1527
+ *
1528
+ * `w` / `h` default to the natural dimensions clamped to 400 px on
1529
+ * the longer side. Aspect ratio is preserved by default; the resize
1530
+ * gesture locks aspect for image nodes (shift to override).
1531
+ *
1532
+ * @example
1533
+ * const id = await store.addImage({ src: file, x: 100, y: 100 })
1534
+ */
1535
+ addImage(opts: {
1536
+ src: File | Blob | string;
1537
+ x: number;
1538
+ y: number;
1539
+ w?: number;
1540
+ h?: number;
1541
+ /** Longest-side cap after downscale. Default 2048. 0 disables. */
1542
+ maxDimension?: number;
1543
+ alt?: string;
1544
+ style?: Style;
1545
+ }): Promise<NodeId>;
1546
+ /**
1547
+ * Adds an SVG icon node. Markup is sanitized at add time (scripts +
1548
+ * event handlers stripped) and stored on `node.data.src`. The
1549
+ * `iconColor` style token substitutes `currentColor` at rasterize
1550
+ * time so the same SVG renders in multiple tints without re-storage.
1551
+ *
1552
+ * `w` / `h` default to the SVG's intrinsic size (width/height attrs
1553
+ * or viewBox); falls back to 24×24 if neither is present. Aspect
1554
+ * ratio is locked on resize by default.
1555
+ *
1556
+ * @example
1557
+ * const id = await store.addSvg({ src: '<svg ...>', x: 0, y: 0, color: '#3b82f6' })
1558
+ */
1559
+ addSvg(opts: {
1560
+ src: string;
1561
+ x: number;
1562
+ y: number;
1563
+ w?: number;
1564
+ h?: number;
1565
+ color?: string;
1566
+ alt?: string;
1567
+ style?: Style;
1568
+ }): Promise<NodeId>;
1478
1569
  /** Adds an edge. Returns its id. */
1479
1570
  addEdge(edge: Edge): EdgeId;
1480
1571
  /** Patches fields on an existing edge. */
@@ -1566,6 +1657,26 @@ interface CanvasStore {
1566
1657
  getEdgeCount(): number;
1567
1658
  /** O(1) count. */
1568
1659
  getGroupCount(): number;
1660
+ /**
1661
+ * Returns frame nodes (`type === 'frame'`) in presentation order.
1662
+ * Order is auto-maintained on add/remove and can be explicitly
1663
+ * mutated via {@link CanvasStore.setFrameOrder}. Used by present
1664
+ * mode + export to drive slide sequencing.
1665
+ */
1666
+ getFrames(): Node[];
1667
+ /**
1668
+ * Replace the presentation order of frames. `ids` must be a
1669
+ * permutation of the current frame ids (any unknown ids are
1670
+ * dropped; missing frames are appended to preserve invariants).
1671
+ * Emits a `frame.reorder` op; undoable, syncs over collab.
1672
+ */
1673
+ setFrameOrder(ids: NodeId[]): void;
1674
+ /**
1675
+ * Geometric containment query: returns all non-frame nodes whose
1676
+ * AABB is fully inside the given frame's AABB. Used to compute
1677
+ * "what's on this slide". Cheap — backed by the spatial index.
1678
+ */
1679
+ getNodesInFrame(id: NodeId): Node[];
1569
1680
  /**
1570
1681
  * Spatial query — ids of nodes + edges that intersect a rect or
1571
1682
  * contain a point. Backed by a uniform grid for sub-millisecond
@@ -1944,6 +2055,16 @@ type RendererOptions = {
1944
2055
  * the synced scene). Update at runtime via `Renderer.setBackground`.
1945
2056
  */
1946
2057
  background?: CanvasBackground;
2058
+ /**
2059
+ * Color for all selection chrome: selection outlines, resize +
2060
+ * rotate handles, edge endpoint + midpoint handles, marquee rect,
2061
+ * and the drag-create preview. Defaults to `#3b82f6` (the standard
2062
+ * canvas-app blue). Update at runtime via `Renderer.setSelectionColor`.
2063
+ *
2064
+ * Accepts any CSS color literal (hex, rgb(), named). The marquee
2065
+ * fill tints via globalAlpha — no parsing needed.
2066
+ */
2067
+ selectionColor?: string;
1947
2068
  /**
1948
2069
  * Fires when the set of custom nodes that should be rendered in the DOM
1949
2070
  * overlay changes. Consumers use this to mount/unmount React subtrees
@@ -1965,6 +2086,14 @@ type Renderer = {
1965
2086
  setSize(cssW: number, cssH: number): void;
1966
2087
  /** Update the page background / pattern. Triggers a static repaint. */
1967
2088
  setBackground(bg: CanvasBackground | undefined): void;
2089
+ /** Update the selection chrome color. Triggers an interactive repaint. */
2090
+ setSelectionColor(color: string): void;
2091
+ /**
2092
+ * Toggle frame-node paint. Use during a presentation flow to drop
2093
+ * the slide border + label so only the frame contents are visible.
2094
+ * Triggers a static repaint.
2095
+ */
2096
+ setHideFrames(hidden: boolean): void;
1968
2097
  /** Per-frame timing (FPS, lastMs, avgMs, frames). */
1969
2098
  stats(): FrameStats;
1970
2099
  /** Number of items the most recent paint actually drew. */
@@ -2946,6 +3075,102 @@ type AnthropicToolDef = {
2946
3075
  */
2947
3076
  declare const opSchemasAsAnthropicTools: () => AnthropicToolDef[];
2948
3077
 
3078
+ /**
3079
+ * Raster image utilities used by `store.addImage` and the renderer's
3080
+ * asset cache.
3081
+ *
3082
+ * Inputs accepted: `File`, `Blob`, or a `data:image/(png|jpeg)` URI.
3083
+ * External URLs are rejected — scenes must be self-contained (no
3084
+ * out-of-document references, no CORS surprises).
3085
+ *
3086
+ * Anything larger than `MAX_IMAGE_BYTES` or not PNG/JPEG is rejected
3087
+ * up front with a clear error so consumers can show a useful message.
3088
+ */
3089
+ declare const MAX_IMAGE_BYTES: number;
3090
+ /**
3091
+ * Validates that the input is a PNG/JPEG within the size cap. Throws
3092
+ * on rejection — meant for the synchronous prologue of an async
3093
+ * `addImage` call so consumers see the failure immediately, not after
3094
+ * an in-flight load.
3095
+ */
3096
+ declare const validateImageInput: (input: File | Blob | string) => void;
3097
+ /** Normalize any accepted `addImage` input to a `Blob`. */
3098
+ declare const toImageBlob: (input: File | Blob | string) => Promise<Blob>;
3099
+ /**
3100
+ * Downscales a blob's image if its longer side exceeds `maxDim`. Returns
3101
+ * the original blob unchanged when no downscale is needed. The output
3102
+ * MIME mirrors the input (PNG stays PNG to preserve alpha; JPEG stays
3103
+ * JPEG with q=0.9).
3104
+ *
3105
+ * `maxDim <= 0` disables downscaling entirely — useful when the caller
3106
+ * wants the original bytes (e.g. they're going to do their own
3107
+ * processing or they need full fidelity).
3108
+ */
3109
+ declare const downscaleImageBlob: (blob: Blob, maxDim: number) => Promise<{
3110
+ blob: Blob;
3111
+ naturalW: number;
3112
+ naturalH: number;
3113
+ }>;
3114
+ /**
3115
+ * Encodes a blob as a `data:` URI. The store persists this string on
3116
+ * `node.data.src` so the node round-trips through serialize/restore
3117
+ * without needing an external asset store.
3118
+ */
3119
+ declare const blobToDataUri: (blob: Blob) => Promise<string>;
3120
+
3121
+ /**
3122
+ * SVG utilities used by `store.addSvg` and the renderer's asset cache.
3123
+ *
3124
+ * SVG is XML — it can carry `<script>` tags, `on*` event handlers, and
3125
+ * `javascript:` hrefs that execute when the markup is inlined into the
3126
+ * DOM. We rasterize SVGs (so the DOM is never asked to live-render
3127
+ * them as elements), but a defense-in-depth sanitize still runs since
3128
+ * the rasterization itself goes through `<img src=blob:>` and a stray
3129
+ * embedded `<foreignObject>` could host arbitrary HTML.
3130
+ */
3131
+ declare const MAX_SVG_BYTES: number;
3132
+ /**
3133
+ * Cheap "is this plausibly SVG markup?" check + size cap. Throws on
3134
+ * rejection so consumers see the error immediately.
3135
+ */
3136
+ declare const validateSvgMarkup: (markup: string) => void;
3137
+ /**
3138
+ * Removes attack surfaces from SVG markup:
3139
+ * - `<script>` and `<foreignObject>` elements entirely
3140
+ * - `on*` event-handler attributes
3141
+ * - `href` / `xlink:href` / `src` attributes whose value starts with
3142
+ * `javascript:` (case-insensitive)
3143
+ * - External entity references (`<!DOCTYPE` / `<!ENTITY`) by parsing
3144
+ * in SVG mode (DOMParser ignores DTDs in SVG context)
3145
+ *
3146
+ * Returns the cleaned markup. Throws if the parser can't make sense
3147
+ * of the input.
3148
+ */
3149
+ declare const sanitizeSvg: (markup: string) => string;
3150
+ /**
3151
+ * Resolves intended display dimensions for an SVG. Order of preference:
3152
+ * 1. explicit `width` + `height` attributes (numeric, units stripped)
3153
+ * 2. `viewBox` width/height
3154
+ * 3. fallback 24×24
3155
+ *
3156
+ * The result is the SVG's "natural size" — what `addSvg` uses as the
3157
+ * default node dimensions when caller omits `w`/`h`.
3158
+ */
3159
+ declare const extractSvgDimensions: (markup: string) => {
3160
+ w: number;
3161
+ h: number;
3162
+ };
3163
+ /**
3164
+ * Substitutes every `currentColor` occurrence in the markup with the
3165
+ * given color literal. Case-insensitive. Used by the rasterizer cache
3166
+ * to bake the icon's tint into the rendered bitmap.
3167
+ *
3168
+ * Single-color recoloring covers ~95% of real icon libraries (Lucide,
3169
+ * Heroicons, Phosphor, Tabler, etc.) which are designed monochromatic.
3170
+ * Two-tone icons can pre-color their markup and skip this step.
3171
+ */
3172
+ declare const applySvgColor: (markup: string, color: string) => string;
3173
+
2949
3174
  /**
2950
3175
  * Extension system — see ARCHITECTURE.md §13.9.
2951
3176
  *
@@ -3027,4 +3252,4 @@ declare const installedExtensions: (store: CanvasStore) => string[];
3027
3252
  */
3028
3253
  declare const VERSION = "0.0.0";
3029
3254
 
3030
- export { type AnthropicToolDef, type Arrowhead, BEZIER_SEGMENTS, type BatchId, type BitmapCacheEntry, type BitmapCacheRequest, type BuiltInNodeType, CODE_BG_COLOR, CODE_BLOCK_MARGIN_Y, CODE_BLOCK_PADDING_X, CONTENT_HEIGHT_BUFFER, CONTENT_PADDING, type CameraState, type CanvasBackground, type CanvasBackgroundPattern, type CanvasStore, type CanvasSurface, type ClientId, type ClipResult, type ConflictRecord, type ContextEdge, type ContextNode, DEFAULT_BACKGROUND, DEFAULT_CAMERA, DEFAULT_HIGHLIGHT_COLOR, DEFAULT_HIGHLIGHT_COLOR_DARK, DEFAULT_MINIMAP_MAX_NODES, DEFAULT_STYLE, DEFAULT_TEXT_COLOR, type DeserializeOptions, type DragOriginal, type DrawTextOptions, EDGE_HANDLE_SLOP_PX, EDGE_HIT_SLOP_PX, type Edge, type EdgeEnd, type EdgeGeometry, EdgeGeometryCache, type EdgeHit, type EdgeId, type EdgeStyle, type EditorAdapter, type EditorAdapterFactory, type EditorAdapterMountOptions, type EstimateOptions, type ExportOptions, type Extension, type ExtensionApi, FONT_FAMILY_MAP, FONT_SIZE_MAP, type FontFamily, type FontSize, type FrameLoop, type FrameStats, type GetContextOptions, type Group, type GroupId, type Hit, type IdGenerator, type InlineType, type InteractionMode, type InteractionState, LINE_HEIGHT_MAP, LINK_COLOR, type LayoutLine, type LayoutOptions, MAX_ZOOM, MIN_ZOOM, type Migrator, type MinimapContentOptions, type Node, type NodeHit, type NodeId, type NodeType, type NodeTypeDef, type NodeTypeDefOptions, type Op, type OpBatch, type OpOrigin, PALM_REJECTION_GRACE_MS, type PalmRejectionState, type PathStyle, type PointerInfo, type PresenceEvent, type PresencePatch, type PresenceSlice, type PresenceState, type PrimitiveType, RESIZE_HANDLES, RESIZE_HANDLE_SIZE_PX, ROTATE_HANDLE_OFFSET_PX, ROTATE_HANDLE_RADIUS_PX, type RenderEnv, type Renderer, type RendererOptions, type ResizeHandle, SCHEMA_VERSION, type Scene, type SceneContextJson, type SchemaVersion, type SerializedClipboard, type SerializedScene, type Side, type SnapshotEnv, type SpatialId, type SpatialQuery, type SpatialResult, type StoreEventHandler, type StoreEventName, type StoreEvents, type StoreOptions, type StrokeStyle, type Style, type StyledRun, type SvgExportOptions, type SyncAdapter, type SyncAdapterCapabilities, type TextAlign, type TextStyle, type ThemeResolver, type Token, type Transform, UniformGrid, type Unsubscribe, VERSION, type Vec2, type WorldRect, applyCameraTransform, arrowheadLength, asBatchId, asClientId, asEdgeId, asGroupId, asNodeId, attachSync, autoRouteControls, clampEffectiveScale, clampZoom, clearMeasureCache, clearSurface, clearTextBitmapCache, clipSamples, computeAutoFitHeight, computeEdgeGeometry, copy, createCanvasStore, createDefaultTextareaEditor, createFrameLoop, createPalmRejectionState, createRenderer, cubicBezier, cubicBezierTangent, cut, defineExtension, defineNode, deserializeClipboard, detectConflicts, drawArrowhead, drawEdge, drawMinimapViewport, drawShape, drawTextToCanvas, drawWithNodeTransform, edgeAABBFromSamples, edgeLabelBoundsWorld, emptyPresenceState, estimateMarkdownContentHeight, exportSelection, exportSelectionSvg, exportViewport, fromSerialized, fullVisibleClipResult, getCanvasFont, getContentHeight, getContext, getDpr, getFontEpoch, getMarkdownLineHeightPx, getOrRenderTextBitmap, getPointAndTangentAtArcLength, getTextBitmapCacheSize, handleEnter, handleWorldPositions, hitTestAny, hitTestEdge, hitTestHandles, hitTestPoint, hitTestRotateHandle, idleInteractionState, inflateRect, insertLink, installExtension, installedExtensions, inverseBatch, inverseOp, isAttached, isCanvasHarnessClipboard, isDrawablePrimitive, isMoving, isNodeRemoteEditing, layoutTokens, makeIdGenerator, marqueeNodes, measureText, midpointToCubicControls, minimapScreenToWorld, nodeAABB, nodeIntersectsRect, nodeLocalToWorld, notePenActive, notePenInactive, opSchemas, opSchemasAsAnthropicTools, paintBackground, panByScreen, paste, pointInNode, projectEndToWorld, projectToNodeBoundary, quantizeDpr, quantizeZoom, randomClientId, rectContainsPoint, rectFromPoints, rectsIntersect, registerMigrator, renderMinimapContent, resolveColor, resolveOpacity, resolveRenderScale, resolveStrokeWidth, rotateHandleWorldPosition, rotateVecByAngle, sampleBezier, sampleSelfLoop, samplesFor, sceneBounds, screenToWorld, selfLoopGeometry, serializeSelection, setupSurface, shouldAutoFit, shouldRejectTouch, sideNormalLocal, sideOf, sizeSurface, storeToJSON, subscribeFontEpoch, tangentAtArcLength, toSerialized, toggleBold, toggleCode, toggleItalic, toggleStrike, toggleUnderline, tokenize, unionRects, viewportWorldRect, withAutoFitHeight, worldToNodeLocal, worldToScreen, worldViewport, worldViewportFromCamera, zoomAtScreenPoint };
3255
+ export { type AnthropicToolDef, type Arrowhead, BEZIER_SEGMENTS, type BatchId, type BitmapCacheEntry, type BitmapCacheRequest, type BuiltInNodeType, CODE_BG_COLOR, CODE_BLOCK_MARGIN_Y, CODE_BLOCK_PADDING_X, CONTENT_HEIGHT_BUFFER, CONTENT_PADDING, type CameraState, type CanvasBackground, type CanvasBackgroundPattern, type CanvasStore, type CanvasSurface, type ClientId, type ClipResult, type ConflictRecord, type ContextEdge, type ContextNode, DEFAULT_BACKGROUND, DEFAULT_CAMERA, DEFAULT_HIGHLIGHT_COLOR, DEFAULT_HIGHLIGHT_COLOR_DARK, DEFAULT_MINIMAP_MAX_NODES, DEFAULT_STYLE, DEFAULT_TEXT_COLOR, type DeserializeOptions, type DragOriginal, type DrawTextOptions, EDGE_HANDLE_SLOP_PX, EDGE_HIT_SLOP_PX, type Edge, type EdgeEnd, type EdgeGeometry, EdgeGeometryCache, type EdgeHit, type EdgeId, type EdgeStyle, type EditorAdapter, type EditorAdapterFactory, type EditorAdapterMountOptions, type EstimateOptions, type ExportOptions, type Extension, type ExtensionApi, FONT_FAMILY_MAP, FONT_SIZE_MAP, type FontFamily, type FontSize, type FrameLoop, type FrameStats, type GetContextOptions, type Group, type GroupId, type Hit, type IconNodeData, type IdGenerator, type ImageNodeData, type InlineType, type InteractionMode, type InteractionState, LINE_HEIGHT_MAP, LINK_COLOR, type LayoutLine, type LayoutOptions, MAX_IMAGE_BYTES, MAX_SVG_BYTES, MAX_ZOOM, MIN_ZOOM, type Migrator, type MinimapContentOptions, type Node, type NodeHit, type NodeId, type NodeType, type NodeTypeDef, type NodeTypeDefOptions, type Op, type OpBatch, type OpOrigin, PALM_REJECTION_GRACE_MS, type PalmRejectionState, type PathStyle, type PointerInfo, type PresenceEvent, type PresencePatch, type PresenceSlice, type PresenceState, type PrimitiveType, RESIZE_HANDLES, RESIZE_HANDLE_SIZE_PX, ROTATE_HANDLE_OFFSET_PX, ROTATE_HANDLE_RADIUS_PX, type RenderEnv, type Renderer, type RendererOptions, type ResizeHandle, SCHEMA_VERSION, type Scene, type SceneContextJson, type SchemaVersion, type SerializedClipboard, type SerializedScene, type Side, type SnapshotEnv, type SpatialId, type SpatialQuery, type SpatialResult, type StoreEventHandler, type StoreEventName, type StoreEvents, type StoreOptions, type StrokeStyle, type Style, type StyledRun, type SvgExportOptions, type SyncAdapter, type SyncAdapterCapabilities, type TextAlign, type TextStyle, type ThemeResolver, type Token, type Transform, UniformGrid, type Unsubscribe, VERSION, type Vec2, type WorldRect, applyCameraTransform, applySvgColor, arrowheadLength, asBatchId, asClientId, asEdgeId, asGroupId, asNodeId, attachSync, autoRouteControls, blobToDataUri, clampEffectiveScale, clampZoom, clearMeasureCache, clearSurface, clearTextBitmapCache, clipSamples, computeAutoFitHeight, computeEdgeGeometry, copy, createCanvasStore, createDefaultTextareaEditor, createFrameLoop, createPalmRejectionState, createRenderer, cubicBezier, cubicBezierTangent, cut, defineExtension, defineNode, deserializeClipboard, detectConflicts, downscaleImageBlob, drawArrowhead, drawEdge, drawMinimapViewport, drawShape, drawTextToCanvas, drawWithNodeTransform, edgeAABBFromSamples, edgeLabelBoundsWorld, emptyPresenceState, estimateMarkdownContentHeight, exportSelection, exportSelectionSvg, exportViewport, extractSvgDimensions, fromSerialized, fullVisibleClipResult, getCanvasFont, getContentHeight, getContext, getDpr, getFontEpoch, getMarkdownLineHeightPx, getOrRenderTextBitmap, getPointAndTangentAtArcLength, getTextBitmapCacheSize, handleEnter, handleWorldPositions, hitTestAny, hitTestEdge, hitTestHandles, hitTestPoint, hitTestRotateHandle, idleInteractionState, inflateRect, insertLink, installExtension, installedExtensions, inverseBatch, inverseOp, isAttached, isCanvasHarnessClipboard, isDrawablePrimitive, isMoving, isNodeRemoteEditing, layoutTokens, makeIdGenerator, marqueeNodes, measureText, midpointToCubicControls, minimapScreenToWorld, nodeAABB, nodeIntersectsRect, nodeLocalToWorld, notePenActive, notePenInactive, opSchemas, opSchemasAsAnthropicTools, paintBackground, panByScreen, paste, pointInNode, projectEndToWorld, projectToNodeBoundary, quantizeDpr, quantizeZoom, randomClientId, rectContainsPoint, rectFromPoints, rectsIntersect, registerMigrator, renderMinimapContent, resolveColor, resolveOpacity, resolveRenderScale, resolveStrokeWidth, rotateHandleWorldPosition, rotateVecByAngle, sampleBezier, sampleSelfLoop, samplesFor, sanitizeSvg, sceneBounds, screenToWorld, selfLoopGeometry, serializeSelection, setupSurface, shouldAutoFit, shouldRejectTouch, sideNormalLocal, sideOf, sizeSurface, storeToJSON, subscribeFontEpoch, tangentAtArcLength, toImageBlob, toSerialized, toggleBold, toggleCode, toggleItalic, toggleStrike, toggleUnderline, tokenize, unionRects, validateImageInput, validateSvgMarkup, viewportWorldRect, withAutoFitHeight, worldToNodeLocal, worldToScreen, worldViewport, worldViewportFromCamera, zoomAtScreenPoint };
package/dist/index.d.ts CHANGED
@@ -71,6 +71,13 @@ type Style = {
71
71
  * per-keystroke).
72
72
  */
73
73
  autoFit?: boolean;
74
+ /**
75
+ * Color applied to SVG icons (`node.type === 'icon'`) — substitutes
76
+ * every `currentColor` occurrence in the SVG markup before
77
+ * rasterizing. The rasterizer caches by `(markup, iconColor, size)`
78
+ * so changing this re-keys without invalidating other variants.
79
+ */
80
+ iconColor?: string;
74
81
  };
75
82
  type EdgeStyle = Style & {
76
83
  sourceArrowhead?: Arrowhead;
@@ -126,6 +133,28 @@ type Node = {
126
133
  style?: Style;
127
134
  data?: unknown;
128
135
  };
136
+ /**
137
+ * `node.data` shape for `node.type === 'image'`. `src` is a self-
138
+ * contained data URI (we don't accept external URLs to keep scenes
139
+ * portable + CORS-free). `naturalW` / `naturalH` are the post-downscale
140
+ * dimensions used for aspect-ratio preservation on resize.
141
+ */
142
+ type ImageNodeData = {
143
+ src: string;
144
+ naturalW: number;
145
+ naturalH: number;
146
+ alt?: string;
147
+ };
148
+ /**
149
+ * `node.data` shape for `node.type === 'icon'`. `src` is sanitized
150
+ * SVG markup (scripts + event handlers stripped at add time). The
151
+ * recolor knob lives on `style.iconColor`, not here, so theming
152
+ * flows through the same channel as other style tokens.
153
+ */
154
+ type IconNodeData = {
155
+ src: string;
156
+ alt?: string;
157
+ };
129
158
 
130
159
  type PathStyle = 'straight' | 'bezier' | 'polyline';
131
160
  /**
@@ -198,6 +227,14 @@ type Scene = {
198
227
  groups: Record<GroupId, Group>;
199
228
  camera: CameraState;
200
229
  selection: (NodeId | EdgeId)[];
230
+ /**
231
+ * Presentation order for frame-typed nodes. Auto-maintained by the
232
+ * store on `node.add` / `node.remove`; explicitly mutated via
233
+ * `setFrameOrder` (which emits a `frame.reorder` op). Optional for
234
+ * backward compat — missing on older saved scenes is treated as [].
235
+ * See ARCHITECTURE.md §3.7 frames.
236
+ */
237
+ frameOrder?: NodeId[];
201
238
  };
202
239
  /**
203
240
  * On-the-wire serialized form. Arrays gzip smaller and have predictable iteration order.
@@ -210,6 +247,7 @@ type SerializedScene = {
210
247
  groups: Group[];
211
248
  camera: CameraState;
212
249
  selection: (NodeId | EdgeId)[];
250
+ frameOrder?: NodeId[];
213
251
  };
214
252
 
215
253
  /**
@@ -247,6 +285,10 @@ type Op = {
247
285
  } | {
248
286
  type: 'group.remove';
249
287
  group: Group;
288
+ } | {
289
+ type: 'frame.reorder';
290
+ ids: NodeId[];
291
+ prev: NodeId[];
250
292
  };
251
293
  /**
252
294
  * A batch is the atomic unit of mutation (also the unit of undo/redo and sync).
@@ -1475,6 +1517,55 @@ interface CanvasStore {
1475
1517
  * batch (so one undo restores the node + every edge that pointed to it).
1476
1518
  */
1477
1519
  removeNode(id: NodeId): void;
1520
+ /**
1521
+ * Adds a raster image node. Async because the input may need decoding
1522
+ * + downscaling before storage. Accepts `File` / `Blob` / data URI;
1523
+ * external URLs are rejected to keep scenes self-contained.
1524
+ *
1525
+ * PNG and JPEG only; up to 2 MB. Larger sources throw immediately
1526
+ * (caller should surface the error in UI).
1527
+ *
1528
+ * `w` / `h` default to the natural dimensions clamped to 400 px on
1529
+ * the longer side. Aspect ratio is preserved by default; the resize
1530
+ * gesture locks aspect for image nodes (shift to override).
1531
+ *
1532
+ * @example
1533
+ * const id = await store.addImage({ src: file, x: 100, y: 100 })
1534
+ */
1535
+ addImage(opts: {
1536
+ src: File | Blob | string;
1537
+ x: number;
1538
+ y: number;
1539
+ w?: number;
1540
+ h?: number;
1541
+ /** Longest-side cap after downscale. Default 2048. 0 disables. */
1542
+ maxDimension?: number;
1543
+ alt?: string;
1544
+ style?: Style;
1545
+ }): Promise<NodeId>;
1546
+ /**
1547
+ * Adds an SVG icon node. Markup is sanitized at add time (scripts +
1548
+ * event handlers stripped) and stored on `node.data.src`. The
1549
+ * `iconColor` style token substitutes `currentColor` at rasterize
1550
+ * time so the same SVG renders in multiple tints without re-storage.
1551
+ *
1552
+ * `w` / `h` default to the SVG's intrinsic size (width/height attrs
1553
+ * or viewBox); falls back to 24×24 if neither is present. Aspect
1554
+ * ratio is locked on resize by default.
1555
+ *
1556
+ * @example
1557
+ * const id = await store.addSvg({ src: '<svg ...>', x: 0, y: 0, color: '#3b82f6' })
1558
+ */
1559
+ addSvg(opts: {
1560
+ src: string;
1561
+ x: number;
1562
+ y: number;
1563
+ w?: number;
1564
+ h?: number;
1565
+ color?: string;
1566
+ alt?: string;
1567
+ style?: Style;
1568
+ }): Promise<NodeId>;
1478
1569
  /** Adds an edge. Returns its id. */
1479
1570
  addEdge(edge: Edge): EdgeId;
1480
1571
  /** Patches fields on an existing edge. */
@@ -1566,6 +1657,26 @@ interface CanvasStore {
1566
1657
  getEdgeCount(): number;
1567
1658
  /** O(1) count. */
1568
1659
  getGroupCount(): number;
1660
+ /**
1661
+ * Returns frame nodes (`type === 'frame'`) in presentation order.
1662
+ * Order is auto-maintained on add/remove and can be explicitly
1663
+ * mutated via {@link CanvasStore.setFrameOrder}. Used by present
1664
+ * mode + export to drive slide sequencing.
1665
+ */
1666
+ getFrames(): Node[];
1667
+ /**
1668
+ * Replace the presentation order of frames. `ids` must be a
1669
+ * permutation of the current frame ids (any unknown ids are
1670
+ * dropped; missing frames are appended to preserve invariants).
1671
+ * Emits a `frame.reorder` op; undoable, syncs over collab.
1672
+ */
1673
+ setFrameOrder(ids: NodeId[]): void;
1674
+ /**
1675
+ * Geometric containment query: returns all non-frame nodes whose
1676
+ * AABB is fully inside the given frame's AABB. Used to compute
1677
+ * "what's on this slide". Cheap — backed by the spatial index.
1678
+ */
1679
+ getNodesInFrame(id: NodeId): Node[];
1569
1680
  /**
1570
1681
  * Spatial query — ids of nodes + edges that intersect a rect or
1571
1682
  * contain a point. Backed by a uniform grid for sub-millisecond
@@ -1944,6 +2055,16 @@ type RendererOptions = {
1944
2055
  * the synced scene). Update at runtime via `Renderer.setBackground`.
1945
2056
  */
1946
2057
  background?: CanvasBackground;
2058
+ /**
2059
+ * Color for all selection chrome: selection outlines, resize +
2060
+ * rotate handles, edge endpoint + midpoint handles, marquee rect,
2061
+ * and the drag-create preview. Defaults to `#3b82f6` (the standard
2062
+ * canvas-app blue). Update at runtime via `Renderer.setSelectionColor`.
2063
+ *
2064
+ * Accepts any CSS color literal (hex, rgb(), named). The marquee
2065
+ * fill tints via globalAlpha — no parsing needed.
2066
+ */
2067
+ selectionColor?: string;
1947
2068
  /**
1948
2069
  * Fires when the set of custom nodes that should be rendered in the DOM
1949
2070
  * overlay changes. Consumers use this to mount/unmount React subtrees
@@ -1965,6 +2086,14 @@ type Renderer = {
1965
2086
  setSize(cssW: number, cssH: number): void;
1966
2087
  /** Update the page background / pattern. Triggers a static repaint. */
1967
2088
  setBackground(bg: CanvasBackground | undefined): void;
2089
+ /** Update the selection chrome color. Triggers an interactive repaint. */
2090
+ setSelectionColor(color: string): void;
2091
+ /**
2092
+ * Toggle frame-node paint. Use during a presentation flow to drop
2093
+ * the slide border + label so only the frame contents are visible.
2094
+ * Triggers a static repaint.
2095
+ */
2096
+ setHideFrames(hidden: boolean): void;
1968
2097
  /** Per-frame timing (FPS, lastMs, avgMs, frames). */
1969
2098
  stats(): FrameStats;
1970
2099
  /** Number of items the most recent paint actually drew. */
@@ -2946,6 +3075,102 @@ type AnthropicToolDef = {
2946
3075
  */
2947
3076
  declare const opSchemasAsAnthropicTools: () => AnthropicToolDef[];
2948
3077
 
3078
+ /**
3079
+ * Raster image utilities used by `store.addImage` and the renderer's
3080
+ * asset cache.
3081
+ *
3082
+ * Inputs accepted: `File`, `Blob`, or a `data:image/(png|jpeg)` URI.
3083
+ * External URLs are rejected — scenes must be self-contained (no
3084
+ * out-of-document references, no CORS surprises).
3085
+ *
3086
+ * Anything larger than `MAX_IMAGE_BYTES` or not PNG/JPEG is rejected
3087
+ * up front with a clear error so consumers can show a useful message.
3088
+ */
3089
+ declare const MAX_IMAGE_BYTES: number;
3090
+ /**
3091
+ * Validates that the input is a PNG/JPEG within the size cap. Throws
3092
+ * on rejection — meant for the synchronous prologue of an async
3093
+ * `addImage` call so consumers see the failure immediately, not after
3094
+ * an in-flight load.
3095
+ */
3096
+ declare const validateImageInput: (input: File | Blob | string) => void;
3097
+ /** Normalize any accepted `addImage` input to a `Blob`. */
3098
+ declare const toImageBlob: (input: File | Blob | string) => Promise<Blob>;
3099
+ /**
3100
+ * Downscales a blob's image if its longer side exceeds `maxDim`. Returns
3101
+ * the original blob unchanged when no downscale is needed. The output
3102
+ * MIME mirrors the input (PNG stays PNG to preserve alpha; JPEG stays
3103
+ * JPEG with q=0.9).
3104
+ *
3105
+ * `maxDim <= 0` disables downscaling entirely — useful when the caller
3106
+ * wants the original bytes (e.g. they're going to do their own
3107
+ * processing or they need full fidelity).
3108
+ */
3109
+ declare const downscaleImageBlob: (blob: Blob, maxDim: number) => Promise<{
3110
+ blob: Blob;
3111
+ naturalW: number;
3112
+ naturalH: number;
3113
+ }>;
3114
+ /**
3115
+ * Encodes a blob as a `data:` URI. The store persists this string on
3116
+ * `node.data.src` so the node round-trips through serialize/restore
3117
+ * without needing an external asset store.
3118
+ */
3119
+ declare const blobToDataUri: (blob: Blob) => Promise<string>;
3120
+
3121
+ /**
3122
+ * SVG utilities used by `store.addSvg` and the renderer's asset cache.
3123
+ *
3124
+ * SVG is XML — it can carry `<script>` tags, `on*` event handlers, and
3125
+ * `javascript:` hrefs that execute when the markup is inlined into the
3126
+ * DOM. We rasterize SVGs (so the DOM is never asked to live-render
3127
+ * them as elements), but a defense-in-depth sanitize still runs since
3128
+ * the rasterization itself goes through `<img src=blob:>` and a stray
3129
+ * embedded `<foreignObject>` could host arbitrary HTML.
3130
+ */
3131
+ declare const MAX_SVG_BYTES: number;
3132
+ /**
3133
+ * Cheap "is this plausibly SVG markup?" check + size cap. Throws on
3134
+ * rejection so consumers see the error immediately.
3135
+ */
3136
+ declare const validateSvgMarkup: (markup: string) => void;
3137
+ /**
3138
+ * Removes attack surfaces from SVG markup:
3139
+ * - `<script>` and `<foreignObject>` elements entirely
3140
+ * - `on*` event-handler attributes
3141
+ * - `href` / `xlink:href` / `src` attributes whose value starts with
3142
+ * `javascript:` (case-insensitive)
3143
+ * - External entity references (`<!DOCTYPE` / `<!ENTITY`) by parsing
3144
+ * in SVG mode (DOMParser ignores DTDs in SVG context)
3145
+ *
3146
+ * Returns the cleaned markup. Throws if the parser can't make sense
3147
+ * of the input.
3148
+ */
3149
+ declare const sanitizeSvg: (markup: string) => string;
3150
+ /**
3151
+ * Resolves intended display dimensions for an SVG. Order of preference:
3152
+ * 1. explicit `width` + `height` attributes (numeric, units stripped)
3153
+ * 2. `viewBox` width/height
3154
+ * 3. fallback 24×24
3155
+ *
3156
+ * The result is the SVG's "natural size" — what `addSvg` uses as the
3157
+ * default node dimensions when caller omits `w`/`h`.
3158
+ */
3159
+ declare const extractSvgDimensions: (markup: string) => {
3160
+ w: number;
3161
+ h: number;
3162
+ };
3163
+ /**
3164
+ * Substitutes every `currentColor` occurrence in the markup with the
3165
+ * given color literal. Case-insensitive. Used by the rasterizer cache
3166
+ * to bake the icon's tint into the rendered bitmap.
3167
+ *
3168
+ * Single-color recoloring covers ~95% of real icon libraries (Lucide,
3169
+ * Heroicons, Phosphor, Tabler, etc.) which are designed monochromatic.
3170
+ * Two-tone icons can pre-color their markup and skip this step.
3171
+ */
3172
+ declare const applySvgColor: (markup: string, color: string) => string;
3173
+
2949
3174
  /**
2950
3175
  * Extension system — see ARCHITECTURE.md §13.9.
2951
3176
  *
@@ -3027,4 +3252,4 @@ declare const installedExtensions: (store: CanvasStore) => string[];
3027
3252
  */
3028
3253
  declare const VERSION = "0.0.0";
3029
3254
 
3030
- export { type AnthropicToolDef, type Arrowhead, BEZIER_SEGMENTS, type BatchId, type BitmapCacheEntry, type BitmapCacheRequest, type BuiltInNodeType, CODE_BG_COLOR, CODE_BLOCK_MARGIN_Y, CODE_BLOCK_PADDING_X, CONTENT_HEIGHT_BUFFER, CONTENT_PADDING, type CameraState, type CanvasBackground, type CanvasBackgroundPattern, type CanvasStore, type CanvasSurface, type ClientId, type ClipResult, type ConflictRecord, type ContextEdge, type ContextNode, DEFAULT_BACKGROUND, DEFAULT_CAMERA, DEFAULT_HIGHLIGHT_COLOR, DEFAULT_HIGHLIGHT_COLOR_DARK, DEFAULT_MINIMAP_MAX_NODES, DEFAULT_STYLE, DEFAULT_TEXT_COLOR, type DeserializeOptions, type DragOriginal, type DrawTextOptions, EDGE_HANDLE_SLOP_PX, EDGE_HIT_SLOP_PX, type Edge, type EdgeEnd, type EdgeGeometry, EdgeGeometryCache, type EdgeHit, type EdgeId, type EdgeStyle, type EditorAdapter, type EditorAdapterFactory, type EditorAdapterMountOptions, type EstimateOptions, type ExportOptions, type Extension, type ExtensionApi, FONT_FAMILY_MAP, FONT_SIZE_MAP, type FontFamily, type FontSize, type FrameLoop, type FrameStats, type GetContextOptions, type Group, type GroupId, type Hit, type IdGenerator, type InlineType, type InteractionMode, type InteractionState, LINE_HEIGHT_MAP, LINK_COLOR, type LayoutLine, type LayoutOptions, MAX_ZOOM, MIN_ZOOM, type Migrator, type MinimapContentOptions, type Node, type NodeHit, type NodeId, type NodeType, type NodeTypeDef, type NodeTypeDefOptions, type Op, type OpBatch, type OpOrigin, PALM_REJECTION_GRACE_MS, type PalmRejectionState, type PathStyle, type PointerInfo, type PresenceEvent, type PresencePatch, type PresenceSlice, type PresenceState, type PrimitiveType, RESIZE_HANDLES, RESIZE_HANDLE_SIZE_PX, ROTATE_HANDLE_OFFSET_PX, ROTATE_HANDLE_RADIUS_PX, type RenderEnv, type Renderer, type RendererOptions, type ResizeHandle, SCHEMA_VERSION, type Scene, type SceneContextJson, type SchemaVersion, type SerializedClipboard, type SerializedScene, type Side, type SnapshotEnv, type SpatialId, type SpatialQuery, type SpatialResult, type StoreEventHandler, type StoreEventName, type StoreEvents, type StoreOptions, type StrokeStyle, type Style, type StyledRun, type SvgExportOptions, type SyncAdapter, type SyncAdapterCapabilities, type TextAlign, type TextStyle, type ThemeResolver, type Token, type Transform, UniformGrid, type Unsubscribe, VERSION, type Vec2, type WorldRect, applyCameraTransform, arrowheadLength, asBatchId, asClientId, asEdgeId, asGroupId, asNodeId, attachSync, autoRouteControls, clampEffectiveScale, clampZoom, clearMeasureCache, clearSurface, clearTextBitmapCache, clipSamples, computeAutoFitHeight, computeEdgeGeometry, copy, createCanvasStore, createDefaultTextareaEditor, createFrameLoop, createPalmRejectionState, createRenderer, cubicBezier, cubicBezierTangent, cut, defineExtension, defineNode, deserializeClipboard, detectConflicts, drawArrowhead, drawEdge, drawMinimapViewport, drawShape, drawTextToCanvas, drawWithNodeTransform, edgeAABBFromSamples, edgeLabelBoundsWorld, emptyPresenceState, estimateMarkdownContentHeight, exportSelection, exportSelectionSvg, exportViewport, fromSerialized, fullVisibleClipResult, getCanvasFont, getContentHeight, getContext, getDpr, getFontEpoch, getMarkdownLineHeightPx, getOrRenderTextBitmap, getPointAndTangentAtArcLength, getTextBitmapCacheSize, handleEnter, handleWorldPositions, hitTestAny, hitTestEdge, hitTestHandles, hitTestPoint, hitTestRotateHandle, idleInteractionState, inflateRect, insertLink, installExtension, installedExtensions, inverseBatch, inverseOp, isAttached, isCanvasHarnessClipboard, isDrawablePrimitive, isMoving, isNodeRemoteEditing, layoutTokens, makeIdGenerator, marqueeNodes, measureText, midpointToCubicControls, minimapScreenToWorld, nodeAABB, nodeIntersectsRect, nodeLocalToWorld, notePenActive, notePenInactive, opSchemas, opSchemasAsAnthropicTools, paintBackground, panByScreen, paste, pointInNode, projectEndToWorld, projectToNodeBoundary, quantizeDpr, quantizeZoom, randomClientId, rectContainsPoint, rectFromPoints, rectsIntersect, registerMigrator, renderMinimapContent, resolveColor, resolveOpacity, resolveRenderScale, resolveStrokeWidth, rotateHandleWorldPosition, rotateVecByAngle, sampleBezier, sampleSelfLoop, samplesFor, sceneBounds, screenToWorld, selfLoopGeometry, serializeSelection, setupSurface, shouldAutoFit, shouldRejectTouch, sideNormalLocal, sideOf, sizeSurface, storeToJSON, subscribeFontEpoch, tangentAtArcLength, toSerialized, toggleBold, toggleCode, toggleItalic, toggleStrike, toggleUnderline, tokenize, unionRects, viewportWorldRect, withAutoFitHeight, worldToNodeLocal, worldToScreen, worldViewport, worldViewportFromCamera, zoomAtScreenPoint };
3255
+ export { type AnthropicToolDef, type Arrowhead, BEZIER_SEGMENTS, type BatchId, type BitmapCacheEntry, type BitmapCacheRequest, type BuiltInNodeType, CODE_BG_COLOR, CODE_BLOCK_MARGIN_Y, CODE_BLOCK_PADDING_X, CONTENT_HEIGHT_BUFFER, CONTENT_PADDING, type CameraState, type CanvasBackground, type CanvasBackgroundPattern, type CanvasStore, type CanvasSurface, type ClientId, type ClipResult, type ConflictRecord, type ContextEdge, type ContextNode, DEFAULT_BACKGROUND, DEFAULT_CAMERA, DEFAULT_HIGHLIGHT_COLOR, DEFAULT_HIGHLIGHT_COLOR_DARK, DEFAULT_MINIMAP_MAX_NODES, DEFAULT_STYLE, DEFAULT_TEXT_COLOR, type DeserializeOptions, type DragOriginal, type DrawTextOptions, EDGE_HANDLE_SLOP_PX, EDGE_HIT_SLOP_PX, type Edge, type EdgeEnd, type EdgeGeometry, EdgeGeometryCache, type EdgeHit, type EdgeId, type EdgeStyle, type EditorAdapter, type EditorAdapterFactory, type EditorAdapterMountOptions, type EstimateOptions, type ExportOptions, type Extension, type ExtensionApi, FONT_FAMILY_MAP, FONT_SIZE_MAP, type FontFamily, type FontSize, type FrameLoop, type FrameStats, type GetContextOptions, type Group, type GroupId, type Hit, type IconNodeData, type IdGenerator, type ImageNodeData, type InlineType, type InteractionMode, type InteractionState, LINE_HEIGHT_MAP, LINK_COLOR, type LayoutLine, type LayoutOptions, MAX_IMAGE_BYTES, MAX_SVG_BYTES, MAX_ZOOM, MIN_ZOOM, type Migrator, type MinimapContentOptions, type Node, type NodeHit, type NodeId, type NodeType, type NodeTypeDef, type NodeTypeDefOptions, type Op, type OpBatch, type OpOrigin, PALM_REJECTION_GRACE_MS, type PalmRejectionState, type PathStyle, type PointerInfo, type PresenceEvent, type PresencePatch, type PresenceSlice, type PresenceState, type PrimitiveType, RESIZE_HANDLES, RESIZE_HANDLE_SIZE_PX, ROTATE_HANDLE_OFFSET_PX, ROTATE_HANDLE_RADIUS_PX, type RenderEnv, type Renderer, type RendererOptions, type ResizeHandle, SCHEMA_VERSION, type Scene, type SceneContextJson, type SchemaVersion, type SerializedClipboard, type SerializedScene, type Side, type SnapshotEnv, type SpatialId, type SpatialQuery, type SpatialResult, type StoreEventHandler, type StoreEventName, type StoreEvents, type StoreOptions, type StrokeStyle, type Style, type StyledRun, type SvgExportOptions, type SyncAdapter, type SyncAdapterCapabilities, type TextAlign, type TextStyle, type ThemeResolver, type Token, type Transform, UniformGrid, type Unsubscribe, VERSION, type Vec2, type WorldRect, applyCameraTransform, applySvgColor, arrowheadLength, asBatchId, asClientId, asEdgeId, asGroupId, asNodeId, attachSync, autoRouteControls, blobToDataUri, clampEffectiveScale, clampZoom, clearMeasureCache, clearSurface, clearTextBitmapCache, clipSamples, computeAutoFitHeight, computeEdgeGeometry, copy, createCanvasStore, createDefaultTextareaEditor, createFrameLoop, createPalmRejectionState, createRenderer, cubicBezier, cubicBezierTangent, cut, defineExtension, defineNode, deserializeClipboard, detectConflicts, downscaleImageBlob, drawArrowhead, drawEdge, drawMinimapViewport, drawShape, drawTextToCanvas, drawWithNodeTransform, edgeAABBFromSamples, edgeLabelBoundsWorld, emptyPresenceState, estimateMarkdownContentHeight, exportSelection, exportSelectionSvg, exportViewport, extractSvgDimensions, fromSerialized, fullVisibleClipResult, getCanvasFont, getContentHeight, getContext, getDpr, getFontEpoch, getMarkdownLineHeightPx, getOrRenderTextBitmap, getPointAndTangentAtArcLength, getTextBitmapCacheSize, handleEnter, handleWorldPositions, hitTestAny, hitTestEdge, hitTestHandles, hitTestPoint, hitTestRotateHandle, idleInteractionState, inflateRect, insertLink, installExtension, installedExtensions, inverseBatch, inverseOp, isAttached, isCanvasHarnessClipboard, isDrawablePrimitive, isMoving, isNodeRemoteEditing, layoutTokens, makeIdGenerator, marqueeNodes, measureText, midpointToCubicControls, minimapScreenToWorld, nodeAABB, nodeIntersectsRect, nodeLocalToWorld, notePenActive, notePenInactive, opSchemas, opSchemasAsAnthropicTools, paintBackground, panByScreen, paste, pointInNode, projectEndToWorld, projectToNodeBoundary, quantizeDpr, quantizeZoom, randomClientId, rectContainsPoint, rectFromPoints, rectsIntersect, registerMigrator, renderMinimapContent, resolveColor, resolveOpacity, resolveRenderScale, resolveStrokeWidth, rotateHandleWorldPosition, rotateVecByAngle, sampleBezier, sampleSelfLoop, samplesFor, sanitizeSvg, sceneBounds, screenToWorld, selfLoopGeometry, serializeSelection, setupSurface, shouldAutoFit, shouldRejectTouch, sideNormalLocal, sideOf, sizeSurface, storeToJSON, subscribeFontEpoch, tangentAtArcLength, toImageBlob, toSerialized, toggleBold, toggleCode, toggleItalic, toggleStrike, toggleUnderline, tokenize, unionRects, validateImageInput, validateSvgMarkup, viewportWorldRect, withAutoFitHeight, worldToNodeLocal, worldToScreen, worldViewport, worldViewportFromCamera, zoomAtScreenPoint };