mudlet-map-renderer 0.41.1-konva → 0.42.0-konva

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/CullingManager.d.ts +7 -70
  2. package/dist/InteractionHandler.d.ts +11 -29
  3. package/dist/ScenePipeline.d.ts +97 -32
  4. package/dist/camera/Camera.d.ts +106 -0
  5. package/dist/coord/CoordFn.d.ts +13 -0
  6. package/dist/draw/DrawCommand.d.ts +104 -0
  7. package/dist/draw/DrawCommandBuilder.d.ts +19 -0
  8. package/dist/export/CanvasExporter.d.ts +12 -8
  9. package/dist/export/Exporter.d.ts +5 -4
  10. package/dist/export/SvgExporter.d.ts +10 -6
  11. package/dist/export/clipSceneToViewport.d.ts +48 -0
  12. package/dist/export/flushSceneShapes.d.ts +21 -0
  13. package/dist/export/sceneBounds.d.ts +24 -0
  14. package/dist/hit/HitTester.d.ts +101 -0
  15. package/dist/index.d.ts +20 -10
  16. package/dist/index.mjs +3192 -2272
  17. package/dist/index.mjs.map +1 -1
  18. package/dist/overlay/AmbientLightOverlay.d.ts +2 -2
  19. package/dist/overlay/LiveEffect.d.ts +1 -1
  20. package/dist/overlay/SceneOverlay.d.ts +16 -11
  21. package/dist/render/CanvasRenderer.d.ts +17 -0
  22. package/dist/render/RecordingLayer.d.ts +158 -0
  23. package/dist/render/SvgRenderer.d.ts +7 -0
  24. package/dist/render/shapeToRecording.d.ts +3 -0
  25. package/dist/rendering/KonvaRenderBackend.d.ts +42 -39
  26. package/dist/rendering/MapRenderer.d.ts +65 -35
  27. package/dist/rendering/SceneManager.d.ts +53 -0
  28. package/dist/scene/Shape.d.ts +151 -0
  29. package/dist/scene/elements/ExitLayout.d.ts +22 -0
  30. package/dist/scene/elements/GridLayout.d.ts +24 -0
  31. package/dist/scene/elements/LabelLayout.d.ts +11 -0
  32. package/dist/scene/elements/OverlayLayout.d.ts +14 -0
  33. package/dist/scene/elements/RoomLayout.d.ts +19 -0
  34. package/dist/scene/elements/SpecialExitLayout.d.ts +19 -0
  35. package/dist/scene/elements/StubLayout.d.ts +19 -0
  36. package/dist/style/Style.d.ts +60 -0
  37. package/dist/style/applyStyle.d.ts +3 -0
  38. package/dist/style/index.d.ts +11 -22
  39. package/dist/style/shape/BlueprintStyle.d.ts +11 -0
  40. package/dist/style/shape/ConstructionStyle.d.ts +17 -0
  41. package/dist/style/shape/IsometricStyle.d.ts +32 -0
  42. package/dist/style/shape/NeonStyle.d.ts +17 -0
  43. package/dist/style/shape/ParchmentStyle.d.ts +13 -0
  44. package/dist/style/shape/SciFiStyle.d.ts +16 -0
  45. package/dist/style/shape/SketchyStyle.d.ts +22 -0
  46. package/dist/style/shape/index.d.ts +25 -0
  47. package/dist/style/shape/paintMap.d.ts +25 -0
  48. package/dist/style/shape/wobble.d.ts +24 -0
  49. package/dist/types/Settings.d.ts +0 -16
  50. package/package.json +2 -1
  51. package/dist/GridRenderer.d.ts +0 -21
  52. package/dist/RoomShapeRenderer.d.ts +0 -16
  53. package/dist/Viewport.d.ts +0 -87
  54. package/dist/backend/CanvasBackend.d.ts +0 -131
  55. package/dist/backend/DrawingBackend.d.ts +0 -184
  56. package/dist/backend/KonvaBackend.d.ts +0 -45
  57. package/dist/backend/SvgBackend.d.ts +0 -53
  58. package/dist/scene/OverlayRenderer.d.ts +0 -35
  59. package/dist/style/BlueprintStyle.d.ts +0 -26
  60. package/dist/style/IsometricStyle.d.ts +0 -71
  61. package/dist/style/NeonStyle.d.ts +0 -25
  62. package/dist/style/ParchmentStyle.d.ts +0 -40
  63. package/dist/style/SketchyStyle.d.ts +0 -33
@@ -1,78 +1,15 @@
1
1
  import { Settings } from './types/Settings';
2
- import { GroupNode, LayerNode } from './backend/DrawingBackend';
3
- export type CoordinateTransform = (x: number, y: number) => {
4
- x: number;
5
- y: number;
6
- };
7
- export type RoomNodeEntry = {
8
- room: MapData.Room;
9
- group: GroupNode;
10
- };
11
- type Bounds = {
12
- x: number;
13
- y: number;
14
- width: number;
15
- height: number;
16
- };
17
- export type StandaloneExitEntry = {
18
- group: GroupNode;
19
- bounds: Bounds;
20
- targetRoomId?: number;
21
- };
22
- export type StageInfo = {
23
- scaleX(): number;
24
- position(): {
25
- x: number;
26
- y: number;
27
- };
28
- width(): number;
29
- height(): number;
30
- };
31
- /**
32
- * Manages spatial indexing and viewport culling for rooms and exits.
33
- * Toggles node visibility based on what's in the viewport.
34
- * No direct Konva dependency.
35
- */
2
+ import { CoordFn } from './coord/CoordFn';
36
3
  export declare class CullingManager {
37
- private readonly stageInfo;
38
- private readonly roomLayer;
39
- private readonly linkLayer;
40
4
  private readonly settings;
41
- roomNodes: Map<number, RoomNodeEntry>;
42
- standaloneExitNodes: StandaloneExitEntry[];
43
- spatialBucketSize: number;
44
- private roomSpatialIndex;
45
- private exitSpatialIndex;
46
- private visibleRooms;
47
- private visibleStandaloneExitNodes;
48
- private bufferRoomSet;
49
- private bufferExitSet;
50
- private bufferRoomCandidates;
51
- private bufferExitCandidates;
52
- private standaloneExitBoundsRoomSize?;
5
+ private readonly onCullingNeeded;
53
6
  private cullingScheduled;
54
- private perfMonitor;
55
7
  private coordinateTransform;
56
- private lastGridMs;
57
- constructor(stageInfo: StageInfo, roomLayer: LayerNode, linkLayer: LayerNode, settings: Settings);
58
- setCoordinateTransform(fn: CoordinateTransform): void;
59
- recordGridMs(ms: number): void;
60
- private transformPoint;
61
- private transformBounds;
62
- computeBucketSize(): void;
63
- clear(): void;
64
- private getBucketKey;
65
- private forEachBucket;
66
- addRoomToSpatialIndex(entry: RoomNodeEntry): void;
67
- addStandaloneExitToSpatialIndex(entry: StandaloneExitEntry): void;
68
- findRoomAtMapPoint(mapX: number, mapY: number): MapData.Room | null;
69
- markExitBoundsStale(): void;
70
- setExitBoundsRoomSize(): void;
71
- private collectRoomCandidates;
72
- private collectStandaloneExitCandidates;
73
- private refreshStandaloneExitBoundsIfNeeded;
8
+ constructor(settings: Settings, onCullingNeeded: () => void);
9
+ setCoordinateTransform(fn: CoordFn): void;
10
+ getCoordinateTransform(): CoordFn;
11
+ /** Schedule a cull pass on the next animation frame (no-op if already scheduled). */
74
12
  scheduleCulling(): void;
13
+ /** Run a cull pass immediately (used when mode changes). */
75
14
  updateCulling(): void;
76
- private cullExits;
77
15
  }
78
- export {};
@@ -1,46 +1,30 @@
1
- import { Settings, RendererEventMap } from './types/Settings';
1
+ import { RendererEventMap } from './types/Settings';
2
2
  import { TypedEventEmitter } from './TypedEventEmitter';
3
- import { Viewport } from './Viewport';
3
+ import { Camera } from './camera/Camera';
4
4
  import { MapState } from './MapState';
5
- type Bounds = {
6
- x: number;
7
- y: number;
8
- width: number;
9
- height: number;
10
- };
11
- type AreaExitHitZone = {
12
- bounds: Bounds;
13
- targetRoomId: number;
14
- };
5
+ import { HitResult } from './hit/HitTester';
15
6
  export type HitTestCallbacks = {
16
7
  clientToMapPoint: (clientX: number, clientY: number) => {
17
8
  x: number;
18
9
  y: number;
19
10
  } | null;
20
- findRoomAtPoint: (mapX: number, mapY: number) => MapData.Room | null;
21
- getAreaExitHitZones: () => AreaExitHitZone[];
22
11
  /**
23
- * Inverse of the drawing backend's coordinate transform — maps a point from
24
- * rendered space (what `clientToMapPoint` returns) back to untransformed map
25
- * space. Needed for hit tests that compare against map-space bounds (e.g.
26
- * area-exit hit zones) under decorators like IsometricStyle.
12
+ * Pick the topmost hit-annotated shape at a point in rendered space. The
13
+ * unified entry point for all DOM-level interaction rooms, area-exit
14
+ * labels, and any future pickable kinds all flow through one query.
27
15
  */
28
- renderedToMapPoint: (x: number, y: number) => {
29
- x: number;
30
- y: number;
31
- };
16
+ pickAtPoint: (renderedX: number, renderedY: number) => HitResult | null;
32
17
  };
33
18
  /**
34
19
  * Handles all DOM interaction on the map container:
35
- * - Viewport: drag (mouse + touch), wheel zoom, pinch zoom, resize
20
+ * - Camera: drag (mouse + touch), wheel zoom, pinch zoom, resize
36
21
  * - Map: hover cursor, click, right-click, long-press, area exit clicks
37
22
  *
38
23
  * No Konva dependency — works with any rendering backend.
39
24
  */
40
25
  export declare class InteractionHandler {
41
26
  private readonly container;
42
- private readonly settings;
43
- private readonly viewport;
27
+ private readonly camera;
44
28
  private readonly state;
45
29
  private readonly hitTest;
46
30
  private readonly events;
@@ -49,17 +33,15 @@ export declare class InteractionHandler {
49
33
  private destroyed;
50
34
  /** Skip cursor changes when an external consumer (e.g. the editor) owns cursor management. */
51
35
  private setCursor;
52
- constructor(container: HTMLDivElement, viewport: Viewport, state: MapState, settings: Settings, hitTest: HitTestCallbacks, events: TypedEventEmitter<RendererEventMap>);
36
+ constructor(container: HTMLDivElement, camera: Camera, state: MapState, hitTest: HitTestCallbacks, events: TypedEventEmitter<RendererEventMap>);
53
37
  destroy(): void;
54
38
  private listen;
55
39
  private initViewportEvents;
56
40
  private handlePinch;
57
41
  private initMapEvents;
58
- private findRoomAtClientPoint;
59
- private findAreaExitAtClientPoint;
42
+ private pickAtClientPoint;
60
43
  private emitRoomClickEvent;
61
44
  private emitRoomContextEvent;
62
45
  private emitAreaExitClickEvent;
63
46
  private emitMapClickEvent;
64
47
  }
65
- export {};
@@ -1,23 +1,31 @@
1
1
  import { default as MapReader } from './reader/MapReader';
2
2
  import { default as Area } from './reader/Area';
3
3
  import { default as Plane } from './reader/Plane';
4
- import { Settings, ViewportBounds } from './types/Settings';
5
- import { DrawingBackend, GroupNode, LayerNode } from './backend/DrawingBackend';
6
- import { RoomShapeRenderer } from './RoomShapeRenderer';
7
- import { GridRenderer } from './GridRenderer';
4
+ import { Settings } from './types/Settings';
8
5
  import { default as ExitRenderer, ExitDrawData } from './ExitRenderer';
6
+ import { GroupShape, Shape } from './scene/Shape';
9
7
  type Bounds = {
10
8
  x: number;
11
9
  y: number;
12
10
  width: number;
13
11
  height: number;
14
12
  };
15
- export type RoomNodeEntry = {
13
+ /**
14
+ * Reference to one room's body shape inside the scene. Keyed by roomId so
15
+ * downstream consumers (cull index, hit-test bookkeeping) can find a room
16
+ * shape by id without re-walking the scene tree.
17
+ */
18
+ export type RoomShapeRef = {
16
19
  room: MapData.Room;
17
- group: GroupNode;
20
+ shape: GroupShape;
18
21
  };
19
- export type StandaloneExitEntry = {
20
- group: GroupNode;
22
+ /**
23
+ * Reference to one drawn link-exit shape, paired with its world-space bounds
24
+ * and (optional) cross-area target room. Used by the live renderer to hang
25
+ * cull entries on each exit.
26
+ */
27
+ export type StandaloneExitShapeRef = {
28
+ shape: GroupShape;
21
29
  bounds: Bounds;
22
30
  targetRoomId?: number;
23
31
  };
@@ -91,44 +99,99 @@ export type DrawnStubEntry = {
91
99
  readonly stroke: string;
92
100
  readonly strokeWidth: number;
93
101
  };
102
+ /**
103
+ * World-space shapes for each logical layer. Same content the backend layer
104
+ * nodes received, but as plain SceneIR data — consumed by exporters that drive
105
+ * {@link buildDrawCommands} → engine renderers without going through a
106
+ * {@link DrawingBackend}.
107
+ *
108
+ * Order within each list mirrors the order in which the corresponding layer
109
+ * node received its `addNode` calls: e.g. `link` is labels → link exits → for
110
+ * each room (special exits, stubs); `room` is rooms → area name → area-exit
111
+ * labels.
112
+ */
113
+ export type SceneShapesByLayer = {
114
+ grid: Shape[];
115
+ link: Shape[];
116
+ room: Shape[];
117
+ topLabel: Shape[];
118
+ };
119
+ /** User-defined label shape paired with its world-space bounds (for culling). */
120
+ export type LabelShapeRef = {
121
+ shape: GroupShape;
122
+ bounds: Bounds;
123
+ };
124
+ /** Custom-line (special-exit) shape paired with its world-space bounds (for culling). */
125
+ export type SpecialExitShapeRef = {
126
+ shape: GroupShape;
127
+ bounds: Bounds;
128
+ };
129
+ /** Stub shape paired with its world-space bounds (for culling). */
130
+ export type StubShapeRef = {
131
+ shape: GroupShape;
132
+ bounds: Bounds;
133
+ };
134
+ /** Area-exit label shape paired with its world-space bounds (for culling). */
135
+ export type AreaExitLabelShapeRef = {
136
+ shape: GroupShape;
137
+ bounds: Bounds;
138
+ };
94
139
  export type SceneBuildResult = {
95
- roomNodes: Map<number, RoomNodeEntry>;
96
- standaloneExitNodes: StandaloneExitEntry[];
140
+ /** Room body shapes keyed by roomId — for cull-entry construction. */
141
+ roomShapeRefs: Map<number, RoomShapeRef>;
142
+ /** Link-exit shapes paired with bounds and area-target metadata. */
143
+ standaloneExitShapeRefs: StandaloneExitShapeRef[];
144
+ /** Non-noScaling label shapes paired with world-space bounds (for culling). */
145
+ labelShapeRefs: LabelShapeRef[];
146
+ /** Custom-line special-exit shapes paired with world-space bounds (for culling). */
147
+ specialExitShapeRefs: SpecialExitShapeRef[];
148
+ /** Stub shapes paired with world-space bounds (for culling). */
149
+ stubShapeRefs: StubShapeRef[];
150
+ /** Area-exit label shapes paired with world-space bounds (for culling). */
151
+ areaExitLabelShapeRefs: AreaExitLabelShapeRef[];
97
152
  areaExitHitZones: AreaExitHitZone[];
98
153
  drawnExits: DrawnExitEntry[];
99
154
  drawnSpecialExits: DrawnSpecialExitEntry[];
100
155
  drawnStubs: DrawnStubEntry[];
156
+ /** World-space shapes carrying {@link HitInfo} annotations — fed to {@link HitTester}. */
157
+ hitShapes: Shape[];
158
+ /**
159
+ * Engine-agnostic shape lists per logical layer. Drives
160
+ * {@link buildDrawCommands} + a per-engine renderer.
161
+ */
162
+ sceneShapes: SceneShapesByLayer;
101
163
  };
102
164
  /**
103
- * Backend-agnostic scene composition pipeline.
104
- * Drives a DrawingBackend + LayerNode to render the full map scene.
165
+ * Engine-neutral scene composition pipeline.
166
+ *
167
+ * Walks a {@link MapData} area/plane and emits world-space {@link Shape}s per
168
+ * logical layer (grid / link / room / topLabel) plus the metadata downstream
169
+ * consumers need (cull entries, hit zones, drawn-geometry snapshots).
105
170
  *
106
- * Both the interactive KonvaRenderBackend and exporters (SvgExporter,
107
- * CanvasExporter, …) drive this pipeline with their respective DrawingBackend.
171
+ * The pipeline knows nothing about Konva, SVG, Canvas, or the
172
+ * {@link DrawCommandBuilder}: callers run the shape lists through whatever
173
+ * renderer fits their target. Both the interactive
174
+ * {@link KonvaRenderBackend} and the exporters consume the same
175
+ * {@link SceneBuildResult} this pipeline produces.
108
176
  */
109
177
  export declare class ScenePipeline {
110
178
  private readonly mapReader;
111
179
  private readonly settings;
112
- private readonly backend;
113
- readonly roomShapeRenderer: RoomShapeRenderer;
114
- readonly gridRenderer: GridRenderer;
115
180
  readonly exitRenderer: ExitRenderer;
116
- private readonly gridLayer;
117
- private readonly linkLayer;
118
- private readonly roomLayer;
119
- private readonly topLabelLayer;
120
- constructor(mapReader: MapReader, settings: Settings, backend: DrawingBackend, layers: {
121
- gridLayer: LayerNode;
122
- linkLayer: LayerNode;
123
- roomLayer: LayerNode;
124
- topLabelLayer?: LayerNode;
125
- });
181
+ private linkShapes;
182
+ private roomShapes;
183
+ private topLabelShapes;
184
+ private labelShapeRefs;
185
+ private specialExitShapeRefs;
186
+ private stubShapeRefs;
187
+ private areaExitLabelShapeRefs;
188
+ constructor(mapReader: MapReader, settings: Settings);
126
189
  /**
127
190
  * Build the full scene for an area/plane.
128
191
  * Clears layers, renders grid → labels → exits → rooms → area name.
129
192
  * Returns data for culling and interaction (room nodes, exit data, hit zones).
130
193
  */
131
- buildScene(area: Area, plane: Plane, zIndex: number, viewportBounds?: ViewportBounds): SceneBuildResult;
194
+ buildScene(area: Area, plane: Plane, zIndex: number): SceneBuildResult;
132
195
  getEffectiveBounds(area: Area, plane: Plane): {
133
196
  minX: number;
134
197
  maxX: number;
@@ -137,10 +200,12 @@ export declare class ScenePipeline {
137
200
  };
138
201
  private renderRooms;
139
202
  private renderLinkExits;
140
- /** Render ExitDrawData through the DrawingBackend. */
141
- renderExitData(data: ExitDrawData): GroupNode;
142
- private renderArrow;
143
- private targetLabelLayer;
203
+ /**
204
+ * Build the world-space shape tree for one inter-room exit. Used by the
205
+ * live renderer's current-room overlay path to recolour a single exit
206
+ * without rebuilding the whole scene.
207
+ */
208
+ buildExitShape(data: ExitDrawData): GroupShape;
144
209
  private renderLabels;
145
210
  private renderAreaExitLabels;
146
211
  private renderAreaName;
@@ -0,0 +1,106 @@
1
+ import { ViewportBounds } from '../types/Settings';
2
+ import { TypedEventEmitter } from '../TypedEventEmitter';
3
+ /** Pixels-per-world-unit at zoom = 1. Multiply by `Camera.zoom` for actual scale. */
4
+ export declare const BASE_SCALE = 75;
5
+ /** Events fired by {@link Camera}. */
6
+ export type CameraEventMap = {
7
+ /** Any state change: zoom, pan, size, animation tick. */
8
+ change: void;
9
+ };
10
+ /**
11
+ * Engine-agnostic camera — owns transform state, drag, and animation.
12
+ *
13
+ * Subscribers ({@link KonvaRenderer}, {@link CullingManager}, {@link HitTester},
14
+ * scene overlays) listen to the `change` event to react to view updates.
15
+ *
16
+ * No Konva, no DOM. Only dependency is requestAnimationFrame (with a
17
+ * setTimeout fallback for Node.js).
18
+ */
19
+ export declare class Camera extends TypedEventEmitter<CameraEventMap> {
20
+ zoom: number;
21
+ minZoom: number;
22
+ position: {
23
+ x: number;
24
+ y: number;
25
+ };
26
+ width: number;
27
+ height: number;
28
+ /** When true, resizing re-centers on the last panToMapPoint target. */
29
+ centerOnResize: boolean;
30
+ private dragging;
31
+ private dragStart;
32
+ private positionAtDragStart;
33
+ private animationId?;
34
+ constructor(width: number, height: number);
35
+ getScale(): number;
36
+ setZoom(zoom: number): boolean;
37
+ /** Zoom keeping the center of the viewport fixed. */
38
+ zoomToCenter(zoom: number): boolean;
39
+ /** Zoom keeping a specific screen point fixed (for mouse wheel zoom). */
40
+ zoomToPoint(zoom: number, screenX: number, screenY: number): boolean;
41
+ /** Bounds of the visible area in map space. */
42
+ getViewportBounds(): ViewportBounds;
43
+ /**
44
+ * Map-space bounds to use for culling. When `cullingBounds` is a
45
+ * screen-pixel sub-rect it is converted to map space via the current
46
+ * camera transform; otherwise the full viewport is returned.
47
+ */
48
+ getCullingViewport(cullingBounds?: {
49
+ x: number;
50
+ y: number;
51
+ width: number;
52
+ height: number;
53
+ } | null): ViewportBounds;
54
+ /**
55
+ * Create a Camera whose full viewport covers exactly the given world-space bounds.
56
+ * Used by headless exporters that need a Camera but have no real display.
57
+ */
58
+ static forMapBounds(minX: number, maxX: number, minY: number, maxY: number): Camera;
59
+ /**
60
+ * Create a Camera from an explicit render-camera transform (scale + offset).
61
+ * Used by {@link CanvasExporter} to derive culling bounds from the already-
62
+ * computed fitted transform without re-doing the letterbox math.
63
+ */
64
+ static forRenderCamera(width: number, height: number, scale: number, offsetX: number, offsetY: number): Camera;
65
+ /** Convert client/screen coordinates to map coordinates. */
66
+ clientToMapPoint(clientX: number, clientY: number, containerOffset?: {
67
+ left: number;
68
+ top: number;
69
+ }): {
70
+ x: number;
71
+ y: number;
72
+ } | null;
73
+ /** Center on a map coordinate, instantly. */
74
+ panToMapPoint(x: number, y: number): void;
75
+ /** Center on a map coordinate, with optional animation. */
76
+ panToMapPointAnimated(x: number, y: number, instant: boolean): void;
77
+ /**
78
+ * Compute the zoom level that would fit the given map bounds in the current
79
+ * viewport (with the same padding/insets as {@link fitToMapBounds}).
80
+ */
81
+ computeFitZoom(minX: number, maxX: number, minY: number, maxY: number, insets?: {
82
+ top?: number;
83
+ right?: number;
84
+ bottom?: number;
85
+ left?: number;
86
+ }): number;
87
+ /**
88
+ * Fit the camera to show the given map bounds with padding.
89
+ * Optional `insets` (screen pixels) reserve space at each edge.
90
+ */
91
+ fitToMapBounds(minX: number, maxX: number, minY: number, maxY: number, insets?: {
92
+ top?: number;
93
+ right?: number;
94
+ bottom?: number;
95
+ left?: number;
96
+ }): void;
97
+ setSize(width: number, height: number): void;
98
+ startDrag(screenX: number, screenY: number): void;
99
+ updateDrag(screenX: number, screenY: number): void;
100
+ endDrag(): void;
101
+ isDragging(): boolean;
102
+ private animate;
103
+ cancelAnimation(): void;
104
+ isAnimating(): boolean;
105
+ private notify;
106
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Forward / inverse 2D coordinate transform. Used by camera-aware code that
3
+ * needs to translate between world space (the map's flat XY) and scene space
4
+ * (whatever the active style projects into — e.g. an isometric diamond).
5
+ *
6
+ * `IDENTITY_TRANSFORM` returns the input unchanged; flat styles (Parchment,
7
+ * Sketchy, plain identity) use it for both the forward and inverse direction.
8
+ */
9
+ export type CoordFn = (x: number, y: number) => {
10
+ x: number;
11
+ y: number;
12
+ };
13
+ export declare const IDENTITY_TRANSFORM: CoordFn;
@@ -0,0 +1,104 @@
1
+ import { LayerId } from '../scene/Shape';
2
+ export interface RectCommand {
3
+ type: "rect";
4
+ x: number;
5
+ y: number;
6
+ w: number;
7
+ h: number;
8
+ fill?: string;
9
+ stroke?: string;
10
+ /** Stroke width in render units. */
11
+ sw: number;
12
+ /** Corner radius in render units. */
13
+ cr: number;
14
+ dash?: number[];
15
+ }
16
+ export interface CircleCommand {
17
+ type: "circle";
18
+ cx: number;
19
+ cy: number;
20
+ r: number;
21
+ fill?: string;
22
+ stroke?: string;
23
+ sw: number;
24
+ dash?: number[];
25
+ }
26
+ export interface LineCommand {
27
+ type: "line";
28
+ /** Flat list of [x0, y0, x1, y1, …] in render space. */
29
+ points: number[];
30
+ stroke?: string;
31
+ sw: number;
32
+ dash?: number[];
33
+ lineCap?: "butt" | "round" | "square";
34
+ lineJoin?: "miter" | "round" | "bevel";
35
+ /** 0..1 multiplier. */
36
+ alpha?: number;
37
+ }
38
+ export interface PolygonCommand {
39
+ type: "polygon";
40
+ vertices: number[];
41
+ fill?: string;
42
+ stroke?: string;
43
+ sw: number;
44
+ }
45
+ export interface TextCommand {
46
+ type: "text";
47
+ x: number;
48
+ y: number;
49
+ text: string;
50
+ fontSize: number;
51
+ fontFamily: string;
52
+ fontStyle: string;
53
+ fill: string;
54
+ stroke?: string;
55
+ /** Stroke width in render units (0 = no stroke). */
56
+ sw: number;
57
+ align: "left" | "center" | "right";
58
+ vAlign: "top" | "middle" | "bottom";
59
+ w: number;
60
+ h: number;
61
+ baselineRatio?: number;
62
+ konvaCorrectionRatio?: number;
63
+ transform?: [number, number, number, number, number, number];
64
+ }
65
+ export interface ImageCommand {
66
+ type: "image";
67
+ x: number;
68
+ y: number;
69
+ w: number;
70
+ h: number;
71
+ src: string;
72
+ transform?: [number, number, number, number, number, number];
73
+ }
74
+ /** Push an affine transform [a, b, c, d, e, f] onto the renderer's stack. */
75
+ export interface PushTransformCommand {
76
+ type: "pushTransform";
77
+ matrix: [number, number, number, number, number, number];
78
+ }
79
+ /** Pop the most recent transform. */
80
+ export interface PopTransformCommand {
81
+ type: "popTransform";
82
+ }
83
+ /** Push a clip rect; subsequent draws are clipped until matching pop. */
84
+ export interface PushClipCommand {
85
+ type: "pushClip";
86
+ x: number;
87
+ y: number;
88
+ w: number;
89
+ h: number;
90
+ }
91
+ export interface PopClipCommand {
92
+ type: "popClip";
93
+ }
94
+ export type PrimitiveDrawCommand = RectCommand | CircleCommand | LineCommand | PolygonCommand | TextCommand | ImageCommand;
95
+ export type StackDrawCommand = PushTransformCommand | PopTransformCommand | PushClipCommand | PopClipCommand;
96
+ export type DrawCommand = PrimitiveDrawCommand | StackDrawCommand;
97
+ /**
98
+ * A bundle of commands targeting one logical layer. Renderers iterate layers
99
+ * in z-order and flush commands per layer.
100
+ */
101
+ export interface DrawCommandBatch {
102
+ layer: LayerId;
103
+ commands: DrawCommand[];
104
+ }
@@ -0,0 +1,19 @@
1
+ import { DrawCommandBatch } from './DrawCommand';
2
+ import { Shape } from '../scene/Shape';
3
+ /** Camera state needed to project world coordinates into render space. */
4
+ export interface CameraTransform {
5
+ /** Pixels per world unit. */
6
+ scale: number;
7
+ /** Render-space origin in pixels. */
8
+ offsetX: number;
9
+ offsetY: number;
10
+ }
11
+ /**
12
+ * Build per-layer {@link DrawCommandBatch}es from a list of world-space shapes
13
+ * and an active camera transform.
14
+ *
15
+ * Layer order in the result follows first-appearance order; renderers iterate
16
+ * the array as-is (z-order is the caller's responsibility — typically scene
17
+ * layout uses the LayerId taxonomy to pre-sort).
18
+ */
19
+ export declare function buildDrawCommands(shapes: Shape[], camera: CameraTransform): DrawCommandBatch[];
@@ -24,20 +24,23 @@ export interface CanvasExportOptions {
24
24
  };
25
25
  }
26
26
  /**
27
- * Renders the current scene into a canvas at the requested width/height,
28
- * reframing the viewport to fit the area (or a specific room) with padding.
27
+ * Renders the current scene into a canvas at the requested width/height by
28
+ * driving {@link ScenePipeline} {@link buildDrawCommands}
29
+ * {@link renderToCanvas}.
29
30
  *
30
- * The returned {@link ExportCanvas} is the node-canvas-compatible object
31
- * produced by Konva. Serialize with `.toBuffer('image/png')` in Node or
32
- * `.toDataURL('image/png')` / `.toBlob(cb)` in the browser.
31
+ * Decoupled from the live Konva stage: the pipeline is rebuilt against the
32
+ * export bounds, shapes are projected through a fitted camera transform, and
33
+ * the result is rasterized onto a fresh 2D canvas. Background colour is
34
+ * filled before any draw commands replay, so PNG / JPEG output looks identical
35
+ * to the on-screen map.
33
36
  *
34
- * Unlike {@link PngExporter} (which rasterizes the current on-screen viewport),
35
- * `CanvasExporter` is the headless/programmatic path.
37
+ * Unlike {@link PngExporter} (which captures the on-screen viewport via the
38
+ * live Konva stage), `CanvasExporter` is fully headless and reproducible.
36
39
  */
37
40
  export declare class CanvasExporter implements Exporter<ExportCanvas | undefined> {
38
41
  private readonly options;
39
42
  constructor(options: CanvasExportOptions);
40
- render({ backend }: ExportContext): ExportCanvas | undefined;
43
+ render({ state, style, sceneOverlays }: ExportContext): ExportCanvas | undefined;
41
44
  }
42
45
  export interface PngBytesExportOptions extends CanvasExportOptions {
43
46
  /** MIME type to encode. Defaults to `'image/png'`. */
@@ -62,6 +65,7 @@ export interface PngBytesExportOptions extends CanvasExportOptions {
62
65
  */
63
66
  export declare class PngBytesExporter implements Exporter<Uint8Array | undefined> {
64
67
  private readonly options;
68
+ private readonly canvasExporter;
65
69
  constructor(options: PngBytesExportOptions);
66
70
  render(context: ExportContext): Uint8Array | undefined;
67
71
  }
@@ -1,5 +1,5 @@
1
1
  import { MapState } from '../MapState';
2
- import { Style } from '../backend/DrawingBackend';
2
+ import { Style } from '../style/Style';
3
3
  import { SceneOverlay } from '../overlay/SceneOverlay';
4
4
  import { InteractiveBackend } from '../rendering/MapRenderer';
5
5
  /**
@@ -31,9 +31,10 @@ export interface Exporter<T> {
31
31
  render(context: ExportContext): T;
32
32
  }
33
33
  /**
34
- * Canvas returned by {@link InteractiveBackend.toCanvas} and
35
- * {@link CanvasExporter}. Describes the portable surface common to the
36
- * browser `HTMLCanvasElement` and the `canvas` package's Node-side Canvas:
34
+ * Canvas returned by {@link CanvasExporter} and
35
+ * {@link InteractiveBackend.exportCanvas}. Describes the portable surface
36
+ * common to the browser `HTMLCanvasElement` and the `canvas` package's
37
+ * Node-side Canvas:
37
38
  *
38
39
  * - Portable: `width`, `height`, `getContext`, `toDataURL`.
39
40
  * - Browser: `toBlob(cb)` (optional here; use when serializing to a Blob).
@@ -1,15 +1,19 @@
1
1
  import { SvgExportOptions } from '../SvgTypes';
2
2
  import { Exporter, ExportContext } from './Exporter';
3
3
  /**
4
- * Renders the current scene as an SVG string through the shared
5
- * {@link ScenePipeline}. The context's style is applied so styled exports
6
- * match the on-screen canvas; {@link SceneOverlay}s from the context are
7
- * rendered into the SVG alongside the scene. `LiveEffect`s are intentionally
8
- * ignored by design.
4
+ * Renders the current scene as an SVG string by driving
5
+ * {@link ScenePipeline} {@link buildDrawCommands} {@link svgFromBatches}.
6
+ *
7
+ * The pipeline is rebuilt with bounded viewport bounds (so the grid layout
8
+ * matches the export region), then `sceneShapes` is flushed through the
9
+ * draw-command pipeline at scale 1 — coordinates land inside the SVG
10
+ * viewBox in world space, identical to the legacy SvgBackend output. Active
11
+ * {@link SceneOverlay}s are still rendered against an {@link SvgBackend}
12
+ * so user code that builds custom overlays via the DrawingBackend keeps
13
+ * working until the overlay API is migrated to shapes.
9
14
  */
10
15
  export declare class SvgExporter implements Exporter<string | undefined> {
11
16
  private readonly options;
12
17
  constructor(options?: SvgExportOptions);
13
18
  render({ state, style, sceneOverlays }: ExportContext): string | undefined;
14
- private renderBuiltInOverlays;
15
19
  }