@fieldnotes/core 0.56.0 → 0.58.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -610,6 +610,7 @@ declare class Viewport {
610
610
  private contextMenu;
611
611
  private minimap;
612
612
  private readonly htmlRenderers;
613
+ private readonly resizeListeners;
613
614
  constructor(container: HTMLElement, options?: ViewportOptions);
614
615
  get ctx(): CanvasRenderingContext2D | null;
615
616
  get snapToGrid(): boolean;
@@ -617,6 +618,16 @@ declare class Viewport {
617
618
  get smartGuides(): boolean;
618
619
  setSmartGuides(enabled: boolean): void;
619
620
  fitToContent(padding?: number): void;
621
+ /** World-space rectangle currently visible through the canvas. */
622
+ getVisibleRect(): Bounds;
623
+ /** Centers the camera on a world point without changing zoom. */
624
+ centerCameraAt(world: Point): void;
625
+ /**
626
+ * Notifies after the host container resizes (ResizeObserver-driven). A resize
627
+ * changes the visible world rect without a camera event; overlays such as the
628
+ * minimap subscribe to stay current. Returns an idempotent unsubscribe.
629
+ */
630
+ onResize(listener: () => void): () => void;
620
631
  requestRender(): void;
621
632
  /**
622
633
  * Registers a world-space overlay drawn above elements on every frame,
@@ -986,6 +997,151 @@ declare class RemotePingOverlay {
986
997
  private renderPings;
987
998
  }
988
999
 
1000
+ interface MeasureToolOptions {
1001
+ feetPerCell?: number;
1002
+ color?: string;
1003
+ }
1004
+ interface Measurement {
1005
+ start: Point;
1006
+ end: Point;
1007
+ worldDistance: number;
1008
+ cells: number;
1009
+ feet: number;
1010
+ }
1011
+ /**
1012
+ * A raf-coalesced snapshot of the in-progress measurement — the outgoing
1013
+ * side of a shared live ruler. Emissions carry world coordinates, derived
1014
+ * distance, and the tool's current color so a host can forward them as
1015
+ * ephemeral presence without duplicating the tool's input handling.
1016
+ * Ephemeral by contract: presence only — never elements, history, or
1017
+ * persisted state.
1018
+ */
1019
+ interface MeasureEmission {
1020
+ readonly start: Point;
1021
+ readonly end: Point;
1022
+ readonly worldDistance: number;
1023
+ readonly cells: number;
1024
+ readonly feet: number;
1025
+ readonly color: string;
1026
+ }
1027
+ declare class MeasureTool implements Tool {
1028
+ readonly name = "measure";
1029
+ private start;
1030
+ private end;
1031
+ private gridSize;
1032
+ private gridType;
1033
+ private hexOrientation;
1034
+ private feetPerCell;
1035
+ private color;
1036
+ private optionListeners;
1037
+ private measurementListeners;
1038
+ private emissionRafId;
1039
+ constructor(options?: MeasureToolOptions);
1040
+ getOptions(): MeasureToolOptions;
1041
+ setOptions(options: MeasureToolOptions): void;
1042
+ onOptionsChange(listener: () => void): () => void;
1043
+ /**
1044
+ * Subscribes to raf-coalesced measurement snapshots. While a measurement is
1045
+ * in progress, listeners receive at most one snapshot per animation frame
1046
+ * carrying the latest state; `null` is delivered synchronously when the
1047
+ * measurement clears (pointer-up or deactivate). Emissions are ephemeral by
1048
+ * contract: presence only — never elements, history, or persisted state.
1049
+ */
1050
+ onMeasurement(listener: (emission: MeasureEmission | null) => void): () => void;
1051
+ onPointerDown(state: PointerState, ctx: ToolContext): void;
1052
+ onPointerMove(state: PointerState, ctx: ToolContext): void;
1053
+ onPointerUp(_state: PointerState, ctx: ToolContext): void;
1054
+ onDeactivate(_ctx: ToolContext): void;
1055
+ getMeasurement(): Measurement | null;
1056
+ renderOverlay(ctx: CanvasRenderingContext2D): void;
1057
+ private snapToGrid;
1058
+ private notifyOptionsChange;
1059
+ private scheduleEmission;
1060
+ private emitClear;
1061
+ private emit;
1062
+ }
1063
+
1064
+ /**
1065
+ * The wire shape of a shared-ruler presence payload. Presence data is untyped
1066
+ * on the wire, so hosts discriminate on `kind`; `isMeasurePresence` validates
1067
+ * a received payload before it reaches the overlay. Distance is
1068
+ * sender-authoritative: receivers render the payload's `feet`/`cells` and
1069
+ * never recompute from their own grid. Measurements are ephemeral by
1070
+ * contract: presence only — never elements, undo history, persisted canvas
1071
+ * state, or durable operations.
1072
+ */
1073
+ type MeasurePresence = {
1074
+ readonly kind: 'measure';
1075
+ readonly start: Point;
1076
+ readonly end: Point;
1077
+ readonly cells: number;
1078
+ readonly feet: number;
1079
+ readonly color?: string;
1080
+ } | {
1081
+ readonly kind: 'measure';
1082
+ readonly cleared: true;
1083
+ };
1084
+ declare const MEASURE_PRESENCE_KIND = "measure";
1085
+ declare function isMeasurePresence(data: unknown): data is MeasurePresence;
1086
+ /** Builds the presence payload for one local `MeasureTool` emission. */
1087
+ declare function toMeasurePresence(emission: MeasureEmission | null): MeasurePresence;
1088
+ /** The two viewport capabilities the overlay needs; `Viewport` satisfies it. */
1089
+ interface RemoteMeasureOverlayHost {
1090
+ registerOverlay(draw: OverlayRenderer): () => void;
1091
+ requestRender(): void;
1092
+ }
1093
+ interface RemoteMeasureOverlayOptions {
1094
+ /** Style fallback when a payload omits `color`. Default `'#FF5722'`. */
1095
+ color?: string;
1096
+ /** Full-opacity hold after a cleared payload. Default `1500`. */
1097
+ holdMs?: number;
1098
+ /** Linear fade to 0 after the hold. Default `400`. */
1099
+ fadeMs?: number;
1100
+ /** Stale active entries are treated as cleared after this. Default `30000`. */
1101
+ maxAgeMs?: number;
1102
+ }
1103
+ /**
1104
+ * Renders remote shared-ruler measurements through the viewport overlay
1105
+ * registration, independent of the viewer's active tool. Entries are stamped
1106
+ * with local receive time (remote clocks are never trusted). A cleared
1107
+ * payload holds the final measurement for `holdMs`, fades over `fadeMs`, and
1108
+ * deletes; presence-leave (`remove`) deletes immediately. An active entry not
1109
+ * updated for `maxAgeMs` is expired by a timer — an idle map never renders,
1110
+ * so expiry cannot ride on the draw path. The overlay never touches elements,
1111
+ * history, or persisted state, and never moves the viewer's camera.
1112
+ */
1113
+ declare class RemoteMeasureOverlay {
1114
+ private readonly host;
1115
+ private readonly color;
1116
+ private readonly holdMs;
1117
+ private readonly fadeMs;
1118
+ private readonly maxAgeMs;
1119
+ private readonly measurements;
1120
+ private unregister;
1121
+ private rafId;
1122
+ private disposed;
1123
+ constructor(host: RemoteMeasureOverlayHost, options?: RemoteMeasureOverlayOptions);
1124
+ private now;
1125
+ /**
1126
+ * Applies a presence payload from `sender` (any opaque per-sender key, e.g.
1127
+ * the envelope `from`). Non-measure or malformed payloads are ignored and
1128
+ * reported as `false`, so hosts can feed every presence frame through.
1129
+ */
1130
+ apply(sender: string, data: unknown): boolean;
1131
+ /** Removes a sender's ruler immediately (presence-leave/disconnect). */
1132
+ remove(sender: string): void;
1133
+ /** Removes every ruler immediately. */
1134
+ clear(): void;
1135
+ /** Number of senders with a visible (active or lingering) ruler. */
1136
+ get activeSenderCount(): number;
1137
+ /** Unregisters the overlay, cancels timers, stops animating. Idempotent. */
1138
+ dispose(): void;
1139
+ private beginLinger;
1140
+ private ensureAnimating;
1141
+ private tick;
1142
+ private renderMeasurements;
1143
+ }
1144
+
989
1145
  /**
990
1146
  * The one camera capability `PingInput` needs; `Camera` satisfies it. Screen
991
1147
  * coordinates are element-local (the same space `Camera.screenToWorld`
@@ -1100,6 +1256,74 @@ declare class PingInput {
1100
1256
  private emit;
1101
1257
  }
1102
1258
 
1259
+ interface MinimapControllerOptions {
1260
+ /** Minimap width in CSS pixels. Default `200`. */
1261
+ width?: number;
1262
+ /** Minimap height in CSS pixels. Default `140`. */
1263
+ height?: number;
1264
+ /** Content inset inside the minimap, in minimap pixels. Default `8`. */
1265
+ padding?: number;
1266
+ /** Backdrop fill behind the thumbnail. Default: none (transparent). */
1267
+ background?: string;
1268
+ /** Stroke color of the viewport rectangle. Default `'#3b82f6'`. */
1269
+ viewportStroke?: string;
1270
+ /** Trailing debounce for scene bitmap re-renders. Default `200`. */
1271
+ debounceMs?: number;
1272
+ /** Tap/drag-to-center navigation on the canvas. Default `true`. */
1273
+ interactive?: boolean;
1274
+ /** Frame scheduler; default `requestAnimationFrame`. Injected by tests. */
1275
+ requestFrame?: (cb: () => void) => number;
1276
+ /** Frame canceller; default `cancelAnimationFrame`. Injected by tests. */
1277
+ cancelFrame?: (id: number) => void;
1278
+ }
1279
+ /**
1280
+ * Thumbnail overview navigator: renders the scene (real element shapes,
1281
+ * downscaled images, per-layer opacity compositing) into a cached offscreen
1282
+ * bitmap, composites it with the live viewport rectangle each frame, and
1283
+ * centers the camera on tap/drag. The cached bitmap and its transform swap
1284
+ * atomically: camera motion never renders the scene, only re-composites.
1285
+ */
1286
+ declare class MinimapController {
1287
+ private readonly viewport;
1288
+ private readonly canvas;
1289
+ private width;
1290
+ private height;
1291
+ private readonly padding;
1292
+ private readonly background;
1293
+ private readonly viewportStroke;
1294
+ private readonly debounceMs;
1295
+ private readonly interactive;
1296
+ private readonly requestFrame;
1297
+ private readonly cancelFrame;
1298
+ private readonly renderer;
1299
+ private scene;
1300
+ private frameId;
1301
+ private debounceTimer;
1302
+ private dragging;
1303
+ private disposed;
1304
+ private readonly unsubs;
1305
+ constructor(viewport: Viewport, canvas: HTMLCanvasElement, options?: MinimapControllerOptions);
1306
+ setSize(width: number, height: number): void;
1307
+ requestDraw(): void;
1308
+ dispose(): void;
1309
+ private clearDebounce;
1310
+ private dpr;
1311
+ private applyCanvasSize;
1312
+ private sceneElements;
1313
+ private currentMapping;
1314
+ private onViewChanged;
1315
+ private markSceneDirty;
1316
+ private renderScene;
1317
+ private renderLayerElements;
1318
+ private draw;
1319
+ private navTransform;
1320
+ private navigateFromEvent;
1321
+ private onPointerDown;
1322
+ private onPointerMove;
1323
+ private onPointerUp;
1324
+ private onPointerEnd;
1325
+ }
1326
+
1103
1327
  interface ActiveFormats {
1104
1328
  bold: boolean;
1105
1329
  italic: boolean;
@@ -1460,39 +1684,6 @@ declare class ShapeTool implements Tool {
1460
1684
  private onKeyUp;
1461
1685
  }
1462
1686
 
1463
- interface MeasureToolOptions {
1464
- feetPerCell?: number;
1465
- }
1466
- interface Measurement {
1467
- start: Point;
1468
- end: Point;
1469
- worldDistance: number;
1470
- cells: number;
1471
- feet: number;
1472
- }
1473
- declare class MeasureTool implements Tool {
1474
- readonly name = "measure";
1475
- private start;
1476
- private end;
1477
- private gridSize;
1478
- private gridType;
1479
- private hexOrientation;
1480
- private feetPerCell;
1481
- private optionListeners;
1482
- constructor(options?: MeasureToolOptions);
1483
- getOptions(): MeasureToolOptions;
1484
- setOptions(options: MeasureToolOptions): void;
1485
- onOptionsChange(listener: () => void): () => void;
1486
- onPointerDown(state: PointerState, ctx: ToolContext): void;
1487
- onPointerMove(state: PointerState, ctx: ToolContext): void;
1488
- onPointerUp(_state: PointerState, ctx: ToolContext): void;
1489
- onDeactivate(_ctx: ToolContext): void;
1490
- getMeasurement(): Measurement | null;
1491
- renderOverlay(ctx: CanvasRenderingContext2D): void;
1492
- private snapToGrid;
1493
- private notifyOptionsChange;
1494
- }
1495
-
1496
1687
  interface TemplateToolOptions {
1497
1688
  templateShape?: TemplateShape;
1498
1689
  fillColor?: string;
@@ -1538,6 +1729,6 @@ declare class TemplateTool implements Tool {
1538
1729
  private notifyOptionsChange;
1539
1730
  }
1540
1731
 
1541
- declare const VERSION = "0.56.0";
1732
+ declare const VERSION = "0.58.0";
1542
1733
 
1543
- export { type ActiveFormats, type AlignEdge, type ArrowElement, type ArrowStrokeStyle, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, type BackgroundOptions, type BackgroundPattern, type Binding, type Bounds, Camera, type CameraChangeInfo, type CameraOptions, type CanvasElement, type CanvasState, type Command, DEFAULT_NOTE_FONT_SIZE, type DistributeAxis, type ElementChangeMeta, ElementStore, type ElementStyle, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, type ExportAssetError, type ExportAssetErrorReason, type ExportImageOptions, type ExportResourceOptions, type ExportSvgOptions, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryStack, type HistoryStackOptions, type HtmlElement, type HtmlExportError, type HtmlExportErrorReason, type HtmlExportOptions, type HtmlExportRenderer, type ImageElement, ImageTool, type ImageToolOptions, IndexedDBAdapter, type IndexedDBAdapterOptions, LASER_TRAIL_PRESENCE_KIND, LaserTool, type LaserToolOptions, type LaserTrailEmission, type LaserTrailPresence, type Layer, LayerManager, LocalStorageAdapter, MeasureTool, type MeasureToolOptions, type Measurement, MemoryAdapter, type NoteElement, NoteTool, type NoteToolOptions, type OverlayRenderer, PING_PRESENCE_KIND, PencilTool, type PencilToolOptions, type PingEmission, PingInput, type PingInputHost, type PingInputOptions, type PingPresence, PingTool, type PingToolOptions, type Point, type PointerState, RemoteLaserOverlay, type RemoteLaserOverlayHost, type RemoteLaserOverlayOptions, RemotePingOverlay, type RemotePingOverlayHost, type RemotePingOverlayOptions, type RenderStatsSnapshot, type RotateDirection, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type ShortcutBindings, type ShortcutOptions, type ShortcutsApi, type Size, type StorageAdapter, type StrokeElement, type StrokePoint, type TemplateElement, type TemplateRenderStyle, type TemplateShape, TemplateTool, type TemplateToolOptions, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, VERSION, Viewport, type ViewportOptions, boundsIntersect, createArrow, createGrid, createHtmlElement, createImage, createNote, createShape, createStroke, createTemplate, createText, drawHexPath, exportImage, exportSvg, getActiveFormats, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getElementBounds, getElementStyle, getElementsBoundingBox, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInRectangle, getHexCellsInSquare, getHexDistance, isLaserTrailPresence, isNearBezier, isPingPresence, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toLaserTrailPresence, toPingPresence, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };
1734
+ export { type ActiveFormats, type AlignEdge, type ArrowElement, type ArrowStrokeStyle, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, type BackgroundOptions, type BackgroundPattern, type Binding, type Bounds, Camera, type CameraChangeInfo, type CameraOptions, type CanvasElement, type CanvasState, type Command, DEFAULT_NOTE_FONT_SIZE, type DistributeAxis, type ElementChangeMeta, ElementStore, type ElementStyle, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, type ExportAssetError, type ExportAssetErrorReason, type ExportImageOptions, type ExportResourceOptions, type ExportSvgOptions, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryStack, type HistoryStackOptions, type HtmlElement, type HtmlExportError, type HtmlExportErrorReason, type HtmlExportOptions, type HtmlExportRenderer, type ImageElement, ImageTool, type ImageToolOptions, IndexedDBAdapter, type IndexedDBAdapterOptions, LASER_TRAIL_PRESENCE_KIND, LaserTool, type LaserToolOptions, type LaserTrailEmission, type LaserTrailPresence, type Layer, LayerManager, LocalStorageAdapter, MEASURE_PRESENCE_KIND, type MeasureEmission, type MeasurePresence, MeasureTool, type MeasureToolOptions, type Measurement, MemoryAdapter, MinimapController, type MinimapControllerOptions, type NoteElement, NoteTool, type NoteToolOptions, type OverlayRenderer, PING_PRESENCE_KIND, PencilTool, type PencilToolOptions, type PingEmission, PingInput, type PingInputHost, type PingInputOptions, type PingPresence, PingTool, type PingToolOptions, type Point, type PointerState, RemoteLaserOverlay, type RemoteLaserOverlayHost, type RemoteLaserOverlayOptions, RemoteMeasureOverlay, type RemoteMeasureOverlayHost, type RemoteMeasureOverlayOptions, RemotePingOverlay, type RemotePingOverlayHost, type RemotePingOverlayOptions, type RenderStatsSnapshot, type RotateDirection, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type ShortcutBindings, type ShortcutOptions, type ShortcutsApi, type Size, type StorageAdapter, type StrokeElement, type StrokePoint, type TemplateElement, type TemplateRenderStyle, type TemplateShape, TemplateTool, type TemplateToolOptions, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, VERSION, Viewport, type ViewportOptions, boundsIntersect, createArrow, createGrid, createHtmlElement, createImage, createNote, createShape, createStroke, createTemplate, createText, drawHexPath, exportImage, exportSvg, getActiveFormats, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getElementBounds, getElementStyle, getElementsBoundingBox, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInRectangle, getHexCellsInSquare, getHexDistance, isLaserTrailPresence, isMeasurePresence, isNearBezier, isPingPresence, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toLaserTrailPresence, toMeasurePresence, toPingPresence, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };
package/dist/index.d.ts CHANGED
@@ -610,6 +610,7 @@ declare class Viewport {
610
610
  private contextMenu;
611
611
  private minimap;
612
612
  private readonly htmlRenderers;
613
+ private readonly resizeListeners;
613
614
  constructor(container: HTMLElement, options?: ViewportOptions);
614
615
  get ctx(): CanvasRenderingContext2D | null;
615
616
  get snapToGrid(): boolean;
@@ -617,6 +618,16 @@ declare class Viewport {
617
618
  get smartGuides(): boolean;
618
619
  setSmartGuides(enabled: boolean): void;
619
620
  fitToContent(padding?: number): void;
621
+ /** World-space rectangle currently visible through the canvas. */
622
+ getVisibleRect(): Bounds;
623
+ /** Centers the camera on a world point without changing zoom. */
624
+ centerCameraAt(world: Point): void;
625
+ /**
626
+ * Notifies after the host container resizes (ResizeObserver-driven). A resize
627
+ * changes the visible world rect without a camera event; overlays such as the
628
+ * minimap subscribe to stay current. Returns an idempotent unsubscribe.
629
+ */
630
+ onResize(listener: () => void): () => void;
620
631
  requestRender(): void;
621
632
  /**
622
633
  * Registers a world-space overlay drawn above elements on every frame,
@@ -986,6 +997,151 @@ declare class RemotePingOverlay {
986
997
  private renderPings;
987
998
  }
988
999
 
1000
+ interface MeasureToolOptions {
1001
+ feetPerCell?: number;
1002
+ color?: string;
1003
+ }
1004
+ interface Measurement {
1005
+ start: Point;
1006
+ end: Point;
1007
+ worldDistance: number;
1008
+ cells: number;
1009
+ feet: number;
1010
+ }
1011
+ /**
1012
+ * A raf-coalesced snapshot of the in-progress measurement — the outgoing
1013
+ * side of a shared live ruler. Emissions carry world coordinates, derived
1014
+ * distance, and the tool's current color so a host can forward them as
1015
+ * ephemeral presence without duplicating the tool's input handling.
1016
+ * Ephemeral by contract: presence only — never elements, history, or
1017
+ * persisted state.
1018
+ */
1019
+ interface MeasureEmission {
1020
+ readonly start: Point;
1021
+ readonly end: Point;
1022
+ readonly worldDistance: number;
1023
+ readonly cells: number;
1024
+ readonly feet: number;
1025
+ readonly color: string;
1026
+ }
1027
+ declare class MeasureTool implements Tool {
1028
+ readonly name = "measure";
1029
+ private start;
1030
+ private end;
1031
+ private gridSize;
1032
+ private gridType;
1033
+ private hexOrientation;
1034
+ private feetPerCell;
1035
+ private color;
1036
+ private optionListeners;
1037
+ private measurementListeners;
1038
+ private emissionRafId;
1039
+ constructor(options?: MeasureToolOptions);
1040
+ getOptions(): MeasureToolOptions;
1041
+ setOptions(options: MeasureToolOptions): void;
1042
+ onOptionsChange(listener: () => void): () => void;
1043
+ /**
1044
+ * Subscribes to raf-coalesced measurement snapshots. While a measurement is
1045
+ * in progress, listeners receive at most one snapshot per animation frame
1046
+ * carrying the latest state; `null` is delivered synchronously when the
1047
+ * measurement clears (pointer-up or deactivate). Emissions are ephemeral by
1048
+ * contract: presence only — never elements, history, or persisted state.
1049
+ */
1050
+ onMeasurement(listener: (emission: MeasureEmission | null) => void): () => void;
1051
+ onPointerDown(state: PointerState, ctx: ToolContext): void;
1052
+ onPointerMove(state: PointerState, ctx: ToolContext): void;
1053
+ onPointerUp(_state: PointerState, ctx: ToolContext): void;
1054
+ onDeactivate(_ctx: ToolContext): void;
1055
+ getMeasurement(): Measurement | null;
1056
+ renderOverlay(ctx: CanvasRenderingContext2D): void;
1057
+ private snapToGrid;
1058
+ private notifyOptionsChange;
1059
+ private scheduleEmission;
1060
+ private emitClear;
1061
+ private emit;
1062
+ }
1063
+
1064
+ /**
1065
+ * The wire shape of a shared-ruler presence payload. Presence data is untyped
1066
+ * on the wire, so hosts discriminate on `kind`; `isMeasurePresence` validates
1067
+ * a received payload before it reaches the overlay. Distance is
1068
+ * sender-authoritative: receivers render the payload's `feet`/`cells` and
1069
+ * never recompute from their own grid. Measurements are ephemeral by
1070
+ * contract: presence only — never elements, undo history, persisted canvas
1071
+ * state, or durable operations.
1072
+ */
1073
+ type MeasurePresence = {
1074
+ readonly kind: 'measure';
1075
+ readonly start: Point;
1076
+ readonly end: Point;
1077
+ readonly cells: number;
1078
+ readonly feet: number;
1079
+ readonly color?: string;
1080
+ } | {
1081
+ readonly kind: 'measure';
1082
+ readonly cleared: true;
1083
+ };
1084
+ declare const MEASURE_PRESENCE_KIND = "measure";
1085
+ declare function isMeasurePresence(data: unknown): data is MeasurePresence;
1086
+ /** Builds the presence payload for one local `MeasureTool` emission. */
1087
+ declare function toMeasurePresence(emission: MeasureEmission | null): MeasurePresence;
1088
+ /** The two viewport capabilities the overlay needs; `Viewport` satisfies it. */
1089
+ interface RemoteMeasureOverlayHost {
1090
+ registerOverlay(draw: OverlayRenderer): () => void;
1091
+ requestRender(): void;
1092
+ }
1093
+ interface RemoteMeasureOverlayOptions {
1094
+ /** Style fallback when a payload omits `color`. Default `'#FF5722'`. */
1095
+ color?: string;
1096
+ /** Full-opacity hold after a cleared payload. Default `1500`. */
1097
+ holdMs?: number;
1098
+ /** Linear fade to 0 after the hold. Default `400`. */
1099
+ fadeMs?: number;
1100
+ /** Stale active entries are treated as cleared after this. Default `30000`. */
1101
+ maxAgeMs?: number;
1102
+ }
1103
+ /**
1104
+ * Renders remote shared-ruler measurements through the viewport overlay
1105
+ * registration, independent of the viewer's active tool. Entries are stamped
1106
+ * with local receive time (remote clocks are never trusted). A cleared
1107
+ * payload holds the final measurement for `holdMs`, fades over `fadeMs`, and
1108
+ * deletes; presence-leave (`remove`) deletes immediately. An active entry not
1109
+ * updated for `maxAgeMs` is expired by a timer — an idle map never renders,
1110
+ * so expiry cannot ride on the draw path. The overlay never touches elements,
1111
+ * history, or persisted state, and never moves the viewer's camera.
1112
+ */
1113
+ declare class RemoteMeasureOverlay {
1114
+ private readonly host;
1115
+ private readonly color;
1116
+ private readonly holdMs;
1117
+ private readonly fadeMs;
1118
+ private readonly maxAgeMs;
1119
+ private readonly measurements;
1120
+ private unregister;
1121
+ private rafId;
1122
+ private disposed;
1123
+ constructor(host: RemoteMeasureOverlayHost, options?: RemoteMeasureOverlayOptions);
1124
+ private now;
1125
+ /**
1126
+ * Applies a presence payload from `sender` (any opaque per-sender key, e.g.
1127
+ * the envelope `from`). Non-measure or malformed payloads are ignored and
1128
+ * reported as `false`, so hosts can feed every presence frame through.
1129
+ */
1130
+ apply(sender: string, data: unknown): boolean;
1131
+ /** Removes a sender's ruler immediately (presence-leave/disconnect). */
1132
+ remove(sender: string): void;
1133
+ /** Removes every ruler immediately. */
1134
+ clear(): void;
1135
+ /** Number of senders with a visible (active or lingering) ruler. */
1136
+ get activeSenderCount(): number;
1137
+ /** Unregisters the overlay, cancels timers, stops animating. Idempotent. */
1138
+ dispose(): void;
1139
+ private beginLinger;
1140
+ private ensureAnimating;
1141
+ private tick;
1142
+ private renderMeasurements;
1143
+ }
1144
+
989
1145
  /**
990
1146
  * The one camera capability `PingInput` needs; `Camera` satisfies it. Screen
991
1147
  * coordinates are element-local (the same space `Camera.screenToWorld`
@@ -1100,6 +1256,74 @@ declare class PingInput {
1100
1256
  private emit;
1101
1257
  }
1102
1258
 
1259
+ interface MinimapControllerOptions {
1260
+ /** Minimap width in CSS pixels. Default `200`. */
1261
+ width?: number;
1262
+ /** Minimap height in CSS pixels. Default `140`. */
1263
+ height?: number;
1264
+ /** Content inset inside the minimap, in minimap pixels. Default `8`. */
1265
+ padding?: number;
1266
+ /** Backdrop fill behind the thumbnail. Default: none (transparent). */
1267
+ background?: string;
1268
+ /** Stroke color of the viewport rectangle. Default `'#3b82f6'`. */
1269
+ viewportStroke?: string;
1270
+ /** Trailing debounce for scene bitmap re-renders. Default `200`. */
1271
+ debounceMs?: number;
1272
+ /** Tap/drag-to-center navigation on the canvas. Default `true`. */
1273
+ interactive?: boolean;
1274
+ /** Frame scheduler; default `requestAnimationFrame`. Injected by tests. */
1275
+ requestFrame?: (cb: () => void) => number;
1276
+ /** Frame canceller; default `cancelAnimationFrame`. Injected by tests. */
1277
+ cancelFrame?: (id: number) => void;
1278
+ }
1279
+ /**
1280
+ * Thumbnail overview navigator: renders the scene (real element shapes,
1281
+ * downscaled images, per-layer opacity compositing) into a cached offscreen
1282
+ * bitmap, composites it with the live viewport rectangle each frame, and
1283
+ * centers the camera on tap/drag. The cached bitmap and its transform swap
1284
+ * atomically: camera motion never renders the scene, only re-composites.
1285
+ */
1286
+ declare class MinimapController {
1287
+ private readonly viewport;
1288
+ private readonly canvas;
1289
+ private width;
1290
+ private height;
1291
+ private readonly padding;
1292
+ private readonly background;
1293
+ private readonly viewportStroke;
1294
+ private readonly debounceMs;
1295
+ private readonly interactive;
1296
+ private readonly requestFrame;
1297
+ private readonly cancelFrame;
1298
+ private readonly renderer;
1299
+ private scene;
1300
+ private frameId;
1301
+ private debounceTimer;
1302
+ private dragging;
1303
+ private disposed;
1304
+ private readonly unsubs;
1305
+ constructor(viewport: Viewport, canvas: HTMLCanvasElement, options?: MinimapControllerOptions);
1306
+ setSize(width: number, height: number): void;
1307
+ requestDraw(): void;
1308
+ dispose(): void;
1309
+ private clearDebounce;
1310
+ private dpr;
1311
+ private applyCanvasSize;
1312
+ private sceneElements;
1313
+ private currentMapping;
1314
+ private onViewChanged;
1315
+ private markSceneDirty;
1316
+ private renderScene;
1317
+ private renderLayerElements;
1318
+ private draw;
1319
+ private navTransform;
1320
+ private navigateFromEvent;
1321
+ private onPointerDown;
1322
+ private onPointerMove;
1323
+ private onPointerUp;
1324
+ private onPointerEnd;
1325
+ }
1326
+
1103
1327
  interface ActiveFormats {
1104
1328
  bold: boolean;
1105
1329
  italic: boolean;
@@ -1460,39 +1684,6 @@ declare class ShapeTool implements Tool {
1460
1684
  private onKeyUp;
1461
1685
  }
1462
1686
 
1463
- interface MeasureToolOptions {
1464
- feetPerCell?: number;
1465
- }
1466
- interface Measurement {
1467
- start: Point;
1468
- end: Point;
1469
- worldDistance: number;
1470
- cells: number;
1471
- feet: number;
1472
- }
1473
- declare class MeasureTool implements Tool {
1474
- readonly name = "measure";
1475
- private start;
1476
- private end;
1477
- private gridSize;
1478
- private gridType;
1479
- private hexOrientation;
1480
- private feetPerCell;
1481
- private optionListeners;
1482
- constructor(options?: MeasureToolOptions);
1483
- getOptions(): MeasureToolOptions;
1484
- setOptions(options: MeasureToolOptions): void;
1485
- onOptionsChange(listener: () => void): () => void;
1486
- onPointerDown(state: PointerState, ctx: ToolContext): void;
1487
- onPointerMove(state: PointerState, ctx: ToolContext): void;
1488
- onPointerUp(_state: PointerState, ctx: ToolContext): void;
1489
- onDeactivate(_ctx: ToolContext): void;
1490
- getMeasurement(): Measurement | null;
1491
- renderOverlay(ctx: CanvasRenderingContext2D): void;
1492
- private snapToGrid;
1493
- private notifyOptionsChange;
1494
- }
1495
-
1496
1687
  interface TemplateToolOptions {
1497
1688
  templateShape?: TemplateShape;
1498
1689
  fillColor?: string;
@@ -1538,6 +1729,6 @@ declare class TemplateTool implements Tool {
1538
1729
  private notifyOptionsChange;
1539
1730
  }
1540
1731
 
1541
- declare const VERSION = "0.56.0";
1732
+ declare const VERSION = "0.58.0";
1542
1733
 
1543
- export { type ActiveFormats, type AlignEdge, type ArrowElement, type ArrowStrokeStyle, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, type BackgroundOptions, type BackgroundPattern, type Binding, type Bounds, Camera, type CameraChangeInfo, type CameraOptions, type CanvasElement, type CanvasState, type Command, DEFAULT_NOTE_FONT_SIZE, type DistributeAxis, type ElementChangeMeta, ElementStore, type ElementStyle, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, type ExportAssetError, type ExportAssetErrorReason, type ExportImageOptions, type ExportResourceOptions, type ExportSvgOptions, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryStack, type HistoryStackOptions, type HtmlElement, type HtmlExportError, type HtmlExportErrorReason, type HtmlExportOptions, type HtmlExportRenderer, type ImageElement, ImageTool, type ImageToolOptions, IndexedDBAdapter, type IndexedDBAdapterOptions, LASER_TRAIL_PRESENCE_KIND, LaserTool, type LaserToolOptions, type LaserTrailEmission, type LaserTrailPresence, type Layer, LayerManager, LocalStorageAdapter, MeasureTool, type MeasureToolOptions, type Measurement, MemoryAdapter, type NoteElement, NoteTool, type NoteToolOptions, type OverlayRenderer, PING_PRESENCE_KIND, PencilTool, type PencilToolOptions, type PingEmission, PingInput, type PingInputHost, type PingInputOptions, type PingPresence, PingTool, type PingToolOptions, type Point, type PointerState, RemoteLaserOverlay, type RemoteLaserOverlayHost, type RemoteLaserOverlayOptions, RemotePingOverlay, type RemotePingOverlayHost, type RemotePingOverlayOptions, type RenderStatsSnapshot, type RotateDirection, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type ShortcutBindings, type ShortcutOptions, type ShortcutsApi, type Size, type StorageAdapter, type StrokeElement, type StrokePoint, type TemplateElement, type TemplateRenderStyle, type TemplateShape, TemplateTool, type TemplateToolOptions, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, VERSION, Viewport, type ViewportOptions, boundsIntersect, createArrow, createGrid, createHtmlElement, createImage, createNote, createShape, createStroke, createTemplate, createText, drawHexPath, exportImage, exportSvg, getActiveFormats, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getElementBounds, getElementStyle, getElementsBoundingBox, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInRectangle, getHexCellsInSquare, getHexDistance, isLaserTrailPresence, isNearBezier, isPingPresence, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toLaserTrailPresence, toPingPresence, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };
1734
+ export { type ActiveFormats, type AlignEdge, type ArrowElement, type ArrowStrokeStyle, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, type BackgroundOptions, type BackgroundPattern, type Binding, type Bounds, Camera, type CameraChangeInfo, type CameraOptions, type CanvasElement, type CanvasState, type Command, DEFAULT_NOTE_FONT_SIZE, type DistributeAxis, type ElementChangeMeta, ElementStore, type ElementStyle, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, type ExportAssetError, type ExportAssetErrorReason, type ExportImageOptions, type ExportResourceOptions, type ExportSvgOptions, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryStack, type HistoryStackOptions, type HtmlElement, type HtmlExportError, type HtmlExportErrorReason, type HtmlExportOptions, type HtmlExportRenderer, type ImageElement, ImageTool, type ImageToolOptions, IndexedDBAdapter, type IndexedDBAdapterOptions, LASER_TRAIL_PRESENCE_KIND, LaserTool, type LaserToolOptions, type LaserTrailEmission, type LaserTrailPresence, type Layer, LayerManager, LocalStorageAdapter, MEASURE_PRESENCE_KIND, type MeasureEmission, type MeasurePresence, MeasureTool, type MeasureToolOptions, type Measurement, MemoryAdapter, MinimapController, type MinimapControllerOptions, type NoteElement, NoteTool, type NoteToolOptions, type OverlayRenderer, PING_PRESENCE_KIND, PencilTool, type PencilToolOptions, type PingEmission, PingInput, type PingInputHost, type PingInputOptions, type PingPresence, PingTool, type PingToolOptions, type Point, type PointerState, RemoteLaserOverlay, type RemoteLaserOverlayHost, type RemoteLaserOverlayOptions, RemoteMeasureOverlay, type RemoteMeasureOverlayHost, type RemoteMeasureOverlayOptions, RemotePingOverlay, type RemotePingOverlayHost, type RemotePingOverlayOptions, type RenderStatsSnapshot, type RotateDirection, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type ShortcutBindings, type ShortcutOptions, type ShortcutsApi, type Size, type StorageAdapter, type StrokeElement, type StrokePoint, type TemplateElement, type TemplateRenderStyle, type TemplateShape, TemplateTool, type TemplateToolOptions, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, VERSION, Viewport, type ViewportOptions, boundsIntersect, createArrow, createGrid, createHtmlElement, createImage, createNote, createShape, createStroke, createTemplate, createText, drawHexPath, exportImage, exportSvg, getActiveFormats, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getElementBounds, getElementStyle, getElementsBoundingBox, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInRectangle, getHexCellsInSquare, getHexDistance, isLaserTrailPresence, isMeasurePresence, isNearBezier, isPingPresence, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toLaserTrailPresence, toMeasurePresence, toPingPresence, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };