@expofp/renderer 1.2.1 → 1.3.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.
Files changed (3) hide show
  1. package/dist/index.d.ts +385 -138
  2. package/dist/index.js +746 -238
  3. package/package.json +4 -2
package/dist/index.d.ts CHANGED
@@ -1,25 +1,123 @@
1
+ import { Camera } from 'three';
1
2
  import { default as default_2 } from 'stats-gl';
2
3
  import { default as default_3 } from 'camera-controls';
3
4
  import { EventManager } from 'mjolnir.js';
5
+ import { Intersection } from 'three';
6
+ import { Object3D } from 'three';
7
+ import { Object3DEventMap } from 'three';
8
+ import { PerspectiveCamera } from 'three';
9
+ import { Scene } from 'three';
4
10
  import { Vector2 } from 'three';
5
11
  import { Vector2Like } from 'three';
6
12
  import { Vector2Tuple } from 'three';
7
13
  import { WebGLRenderer } from 'three';
8
14
 
15
+ /** Camera controller. Manages the camera, it's controls and smooth updates. */
16
+ declare class CameraController extends default_3 {
17
+ private renderer;
18
+ /**
19
+ * @param camera {@link PerspectiveCamera} instance
20
+ * @param renderer {@link Renderer} instance
21
+ */
22
+ constructor(camera: PerspectiveCamera, renderer: Renderer);
23
+ update(delta: number): boolean;
24
+ }
25
+
9
26
  export declare type ColorInput = string | number;
10
27
 
11
- /**
12
- * Options for the CameraControls class.
13
- */
14
- declare interface ControlsOptions {
15
- /** Whether the camera controls are enabled */
16
- enabled: boolean;
17
- /** Time for zooming transitions (in seconds) */
28
+ /** Options for the {@link ControlsAPI.configure} method. */
29
+ export declare interface ConfigureOptions {
30
+ /** Smooth time for zoom operations in seconds.*/
18
31
  zoomTime: number;
19
- /** Options for the camera roll controller - see {@link RollOptions} */
20
- roll: RollOptions;
21
- /** Options for the camera inertia - see {@link InertiaOptions} */
22
- inertia: InertiaOptions;
32
+ /** Smooth time for pan operations in seconds. */
33
+ panTime: number;
34
+ /** Smooth time for roll operations in seconds. */
35
+ rollTime: number;
36
+ /** Smooth time for pitch operations in seconds. */
37
+ pitchTime: number;
38
+ }
39
+
40
+ /** Controls system public API. */
41
+ export declare interface ControlsAPI {
42
+ /** Gesture handlers for camera controls. */
43
+ handlers: Readonly<Handlers>;
44
+ /**
45
+ * Zooms the camera by the given factor.
46
+ * @param zoom Zoom factor to apply (e.g., 1.5 for 50% zoom in, 0.5 for 50% zoom out)
47
+ * @param immediate If true, applies the change immediately without animation
48
+ * @returns Promise that resolves when the zoom animation completes
49
+ */
50
+ zoomBy(zoom: number, immediate?: boolean): Promise<void>;
51
+ /**
52
+ * Zooms the camera to fit the given rectangle.
53
+ * @param rect Rectangle to zoom to in SVG coordinates
54
+ * @param options Optional zoom configuration
55
+ * @param immediate If true, applies the change immediately without animation
56
+ * @returns Promise that resolves when the zoom animation completes
57
+ */
58
+ zoomTo(rect: Rect, options?: Partial<ZoomToOptions>, immediate?: boolean): Promise<void>;
59
+ /**
60
+ * Pans the camera by the given offset in SVG space.
61
+ * @param x X offset in SVG space
62
+ * @param y Y offset in SVG space
63
+ * @param immediate If true, applies the change immediately without animation
64
+ * @returns Promise that resolves when the pan animation completes
65
+ */
66
+ panBy(x: number, y: number, immediate?: boolean): Promise<void>;
67
+ /**
68
+ * Pans the camera to the given coordinates in SVG space.
69
+ * @param x X coordinate in SVG space
70
+ * @param y Y coordinate in SVG space
71
+ * @param immediate If true, applies the change immediately without animation
72
+ * @returns Promise that resolves when the pan animation completes
73
+ */
74
+ panTo(x: number, y: number, immediate?: boolean): Promise<void>;
75
+ /**
76
+ * Rolls the camera by the given angle in degrees.
77
+ * Note: This method won't work if {@link ControlsAPI.handlers | handlers.roll} is disabled.
78
+ * @param angle Angle in degrees to roll by
79
+ * @param immediate If true, applies the change immediately without animation
80
+ * @returns Promise that resolves when the roll animation completes
81
+ */
82
+ rollBy(angle: number, immediate?: boolean): Promise<void>;
83
+ /**
84
+ * Rolls the camera to the given angle in degrees.
85
+ * Note: This method won't work if {@link ControlsAPI.handlers | handlers.roll} is disabled.
86
+ * @param angle Target angle in degrees
87
+ * @param immediate If true, applies the change immediately without animation
88
+ * @returns Promise that resolves when the roll animation completes
89
+ */
90
+ rollTo(angle: number, immediate?: boolean): Promise<void>;
91
+ /**
92
+ * Pitches the camera by the given angle in degrees.
93
+ * Positive angles increase pitch, negative angles decrease pitch.
94
+ * Note: This method won't work if {@link ControlsAPI.handlers | handlers.pitch} is disabled.
95
+ * @param angle Angle in degrees to pitch by
96
+ * @param immediate If true, applies the change immediately without animation
97
+ * @returns Promise that resolves when the pitch animation completes
98
+ */
99
+ pitchBy(angle: number, immediate?: boolean): Promise<void>;
100
+ /**
101
+ * Pitches the camera to the given angle in degrees.
102
+ * The angle is clamped to the 0-90 degree range.
103
+ * Note: This method won't work if {@link ControlsAPI.handlers | handlers.pitch} is disabled.
104
+ * @param angle Target angle in degrees
105
+ * @param immediate If true, applies the change immediately without animation
106
+ * @returns Promise that resolves when the pitch animation completes
107
+ */
108
+ pitchTo(angle: number, immediate?: boolean): Promise<void>;
109
+ /**
110
+ * Resets the camera to the starting state.
111
+ * @param options Configuration for which handlers to reset
112
+ * @param immediate If true, applies the change immediately without animation
113
+ * @returns Promise that resolves when all reset animations complete
114
+ */
115
+ resetCamera(options?: Partial<ResetCameraOptions>, immediate?: boolean): Promise<void>;
116
+ /**
117
+ * Configures smooth time values for camera operations.
118
+ * @param options Partial configuration object with time values in seconds
119
+ */
120
+ configure(options: Partial<ConfigureOptions>): void;
23
121
  }
24
122
 
25
123
  /**
@@ -35,8 +133,6 @@ export declare function createVector2(vector2: IVector2): Vector2;
35
133
  export declare interface EngineEvents {
36
134
  /** Camera change */
37
135
  "navigation:change": void;
38
- /** Camera stop */
39
- "navigation:stop": void;
40
136
  /** Camera roll */
41
137
  "navigation:roll": number;
42
138
  /** Mouse move */
@@ -47,8 +143,6 @@ export declare interface EngineEvents {
47
143
  "pointer:click": MouseEventData;
48
144
  /** Viewport pixel to svg scale */
49
145
  "viewport:ptscale": number;
50
- /** Camera update */
51
- "camera:update": void;
52
146
  }
53
147
 
54
148
  export declare type EventHandler<Payload> = (payload: Payload) => void;
@@ -63,6 +157,41 @@ export declare interface EventsAPI {
63
157
  clear(): void;
64
158
  }
65
159
 
160
+ /**
161
+ * System for managing engine-wide events
162
+ */
163
+ declare class EventSystem implements EventsAPI {
164
+ private handlers;
165
+ /**
166
+ * Add an event listener for a specific event
167
+ * @param event - The event to listen for
168
+ * @param handler - The handler to call when the event is emitted
169
+ */
170
+ addEventListener<E extends keyof EngineEvents>(event: E, handler: EventHandler<EngineEvents[E]>): void;
171
+ /**
172
+ * Remove an event listener for a specific event
173
+ * @param event - The event to remove the listener for
174
+ * @param handler - The handler to remove
175
+ */
176
+ removeEventListener<E extends keyof EngineEvents>(event: E, handler: EventHandler<EngineEvents[E]>): void;
177
+ /**
178
+ * Check if there are any listeners for a specific event
179
+ * @param event - The event to check
180
+ * @returns true if there are listeners, false otherwise
181
+ */
182
+ hasListeners<E extends keyof EngineEvents>(event: E): boolean;
183
+ /**
184
+ * Emit an event with a specific payload
185
+ * @param event - The event to emit
186
+ * @param args - The payload to emit
187
+ */
188
+ emit<E extends keyof EngineEvents>(event: E, ...args: EngineEvents[E] extends void ? [] : [EngineEvents[E]]): void;
189
+ /**
190
+ * Clear all event listeners
191
+ */
192
+ clear(): void;
193
+ }
194
+
66
195
  /**
67
196
  * Abstract base class for all interaction handlers.
68
197
  * Provides common lifecycle management and access to camera controller, DOM element, and event manager.
@@ -83,7 +212,7 @@ export declare interface EventsAPI {
83
212
  * this.controller.mouseButtons.left = CameraController.ACTION.NONE;
84
213
  * }
85
214
  *
86
- * reset(): void {
215
+ * reset(enableTransition = true): Promise<void> {
87
216
  * // No custom state to reset
88
217
  * }
89
218
  * }
@@ -104,24 +233,26 @@ export declare interface EventsAPI {
104
233
  * this.rotating = false;
105
234
  * }
106
235
  *
107
- * reset(): void {
236
+ * reset(enableTransition = true): Promise<void> {
108
237
  * this.rotating = false;
109
238
  * }
110
239
  * }
111
240
  * ```
112
241
  */
113
242
  declare abstract class Handler<T = undefined> implements HandlerAPI<T> {
114
- protected controller: default_3;
243
+ protected viewportSystem: ViewportSystem;
115
244
  protected domElement: HTMLElement;
116
245
  protected eventManager: EventManager;
117
246
  /** Whether this handler is enabled */
118
247
  protected enabled: boolean;
248
+ /** The camera-controls instance for camera manipulation */
249
+ protected controller: CameraController;
119
250
  /**
120
- * @param controller The camera-controls instance for camera manipulation
251
+ * @param viewportSystem The viewport system instance
121
252
  * @param domElement The DOM element to attach event listeners to
122
253
  * @param eventManager Shared Mjolnir EventManager for gesture recognition
123
254
  */
124
- constructor(controller: default_3, domElement: HTMLElement, eventManager: EventManager);
255
+ constructor(viewportSystem: ViewportSystem, domElement: HTMLElement, eventManager: EventManager);
125
256
  /**
126
257
  * Per-frame update for this handler.
127
258
  * Called every frame in the render loop.
@@ -132,8 +263,10 @@ declare abstract class Handler<T = undefined> implements HandlerAPI<T> {
132
263
  update(delta: number): boolean;
133
264
  /**
134
265
  * Reset this handler to its initial state.
266
+ * @param enableTransition Whether to animate the transition (default: true)
267
+ * @returns Promise that resolves when the reset is complete
135
268
  */
136
- abstract reset(): void;
269
+ abstract reset(enableTransition?: boolean): Promise<void>;
137
270
  /**
138
271
  * Configure this handler with handler-specific options.
139
272
  * Does NOT handle enabled state - use enable()/disable() for that.
@@ -148,7 +281,7 @@ declare abstract class Handler<T = undefined> implements HandlerAPI<T> {
148
281
  enable(): void;
149
282
  /**
150
283
  * Disable this handler.
151
- * Calls onDisable() hook for subclass-specific disabling logic
284
+ * Resets to initial state without transition, then calls onDisable() hook for subclass-specific disabling logic
152
285
  */
153
286
  disable(): void;
154
287
  /**
@@ -179,7 +312,7 @@ declare abstract class Handler<T = undefined> implements HandlerAPI<T> {
179
312
  * Each handler implements this interface to provide consistent enable/disable/configure functionality.
180
313
  * @template T Handler-specific options type (can be undefined if handler has no options).
181
314
  */
182
- declare interface HandlerAPI<T = undefined> {
315
+ export declare interface HandlerAPI<T = undefined> {
183
316
  /**
184
317
  * Enable this handler
185
318
  */
@@ -201,19 +334,25 @@ declare interface HandlerAPI<T = undefined> {
201
334
  configure(options: T extends undefined ? never : Partial<T>): void;
202
335
  /**
203
336
  * Reset this handler to its initial state.
337
+ * @param enableTransition Whether to animate the transition (default: true)
338
+ * @returns Promise that resolves when the reset is complete
204
339
  */
205
- reset(): void;
340
+ reset(enableTransition?: boolean): Promise<void>;
206
341
  }
207
342
 
208
343
  /**
209
344
  * Gesture handlers - all fields are readonly to prevent reassignment
210
345
  */
211
- declare type Handlers = Readonly<{
346
+ declare interface Handlers {
212
347
  /** Pan handler */
213
348
  pan: PanHandler;
349
+ /** Zoom handler */
350
+ zoom: ZoomHandler;
214
351
  /** Roll handler */
215
352
  roll: RollHandler;
216
- }>;
353
+ /** Pitch handler */
354
+ pitch: PitchHandler;
355
+ }
217
356
 
218
357
  /** Image definition */
219
358
  export declare interface ImageDef extends SharedDef {
@@ -232,22 +371,6 @@ export declare type ImageSource = HTMLImageElement | HTMLCanvasElement | ImageBi
232
371
 
233
372
  export declare type Index = [number, number, number];
234
373
 
235
- /**
236
- * Options for the InertiaController class.
237
- */
238
- declare interface InertiaOptions {
239
- /** Whether the inertia controller is enabled */
240
- enabled?: boolean;
241
- /** Minimum time in milliseconds to sample backwards to determine inertia */
242
- minSampleMs?: number;
243
- /** Inertial movement duration in milliseconds */
244
- durationMs?: number;
245
- /** Speed threshold after which inertia is stopped (in world units per ms) */
246
- speedThreshold?: number;
247
- /** Easing function for the inertia movement. Maps interval [0, 1] to [0, 1], default exp-in-ish */
248
- ease?: (t: number) => number;
249
- }
250
-
251
374
  export declare function isImageDef(def: RenderableDef): def is ImageDef;
252
375
 
253
376
  export declare function isImageLayer(layer: LayerDef): layer is TypedLayerDef<ImageDef>;
@@ -302,25 +425,15 @@ export declare interface MouseEventData {
302
425
  defs: RenderableDef[];
303
426
  }
304
427
 
305
- /** Navigation system public API. */
306
- declare interface NavigationAPI {
307
- /** Zooms the camera by the given factor. */
308
- zoomBy(zoom: number): void;
309
- /** Zooms the camera to the given rectangle. */
310
- zoomTo(rect: Rect, options?: Partial<ZoomToOptions>): void;
311
- /** Resets the camera to the starting state. */
312
- resetCamera(options?: Partial<ResetCameraOptions>): void;
313
- /** Configures the camera controls. */
314
- configure(options: Partial<ControlsOptions>): void;
315
- }
316
-
317
428
  /**
318
429
  * Pan handler - wraps camera-controls TRUCK action.
319
430
  * Handles both mouse drag (left-click) and single-finger touch pan.
320
431
  * No custom event listeners needed - camera-controls handles everything
321
432
  */
322
433
  declare class PanHandler extends Handler {
323
- reset(): void;
434
+ private inertia;
435
+ reset(enableTransition?: boolean): Promise<void>;
436
+ update(delta: number): boolean;
324
437
  /**
325
438
  * Enable pan gestures.
326
439
  * Configures camera-controls to handle left-click drag and single-touch drag
@@ -333,6 +446,66 @@ declare class PanHandler extends Handler {
333
446
  protected onDisable(): void;
334
447
  }
335
448
 
449
+ /**
450
+ * Pitch handler - controls camera polar angle (vertical pitch).
451
+ * Configures camera-controls polar angle limits.
452
+ * No gesture recognition yet - only sets angle constraints.
453
+ */
454
+ declare class PitchHandler extends Handler<PitchHandlerOptions> {
455
+ private minPitch;
456
+ private maxPitch;
457
+ private isValid?;
458
+ private firstMove?;
459
+ private lastPoints?;
460
+ private prevTwoFingerAction?;
461
+ /**
462
+ * @param viewportSystem {@link ViewportSystem} instance
463
+ * @param domElement {@link HTMLElement} instance
464
+ * @param eventManager {@link EventManager} instance
465
+ */
466
+ constructor(viewportSystem: ViewportSystem, domElement: HTMLElement, eventManager: EventManager);
467
+ reset(enableTransition?: boolean): Promise<void>;
468
+ /**
469
+ * Configure pitch handler options
470
+ * @param options Partial options to update
471
+ */
472
+ configure(options: Partial<PitchHandlerOptions>): void;
473
+ /**
474
+ * Enable pitch.
475
+ * Configures camera-controls to allow polar angle changes within configured range
476
+ */
477
+ protected onEnable(): void;
478
+ /**
479
+ * Disable pitch.
480
+ */
481
+ protected onDisable(): void;
482
+ /**
483
+ * Update controller polar angles based on current configuration
484
+ */
485
+ private updatePolarAngles;
486
+ private onPitchStart;
487
+ private onPitchEnd;
488
+ private onPitch;
489
+ private gestureBeginsVertically;
490
+ private isVertical;
491
+ }
492
+
493
+ /**
494
+ * Configuration options for PitchHandler
495
+ */
496
+ declare interface PitchHandlerOptions {
497
+ /**
498
+ * Minimum pitch angle in degrees (0 = looking straight down at the map)
499
+ * @default 0
500
+ */
501
+ minPitch?: number;
502
+ /**
503
+ * Maximum pitch angle in degrees (90 = looking horizontally)
504
+ * @default 85
505
+ */
506
+ maxPitch?: number;
507
+ }
508
+
336
509
  /** Polygon shape instance. */
337
510
  export declare class Polygon {
338
511
  /** Array of polygon vertices. */
@@ -414,28 +587,26 @@ export declare class Renderer {
414
587
  /** {@link HTMLCanvasElement} that this renderer is rendering to */
415
588
  readonly canvas: HTMLCanvasElement;
416
589
  private ui?;
417
- private clock;
418
- private renderer;
590
+ private gl?;
419
591
  private eventSystem;
420
592
  private layerSystem;
421
593
  private viewportSystem;
422
594
  private interactionsSystem;
423
- private memoryInfoExtension;
424
- private memoryInfo;
595
+ private controlsSystem;
596
+ private clock;
597
+ private renderer;
425
598
  private viewport?;
426
599
  private needsRedraw;
427
- private isExternalMode;
600
+ private memoryInfoExtension;
601
+ private memoryInfo;
428
602
  /**
429
603
  * @param opts {@link RendererOptions}
430
604
  */
431
605
  constructor(opts: RendererOptions);
432
606
  /**
433
- * {@link NavigationAPI} instance for controlling the viewport
607
+ * {@link ControlsAPI} instance for controlling the viewport
434
608
  */
435
- get controls(): NavigationAPI & {
436
- handlers: Handlers;
437
- controller: default_3;
438
- };
609
+ get controls(): ControlsAPI;
439
610
  /**
440
611
  * {@link EventsAPI} instance for subscribing to internal events
441
612
  */
@@ -457,12 +628,12 @@ export declare class Renderer {
457
628
  * Sets the renderer to external mode, where parts of rendering process are not managed by the renderer (e.g. Mapbox GL JS).
458
629
  * @param staticTransformMatrix static transform matrix to apply to the scene
459
630
  */
460
- configureExternalMode(staticTransformMatrix: number[]): void;
631
+ setExternalTransform(staticTransformMatrix: number[]): void;
461
632
  /**
462
633
  * Update scene matrix from dynamic transform matrix.
463
634
  * @param dynamicTransformMatrix dynamic transform matrix (changes every frame)
464
635
  */
465
- updateExternalTransformMatrix(dynamicTransformMatrix: number[]): void;
636
+ updateExternalCamera(dynamicTransformMatrix: number[]): void;
466
637
  /**
467
638
  * Initialize the scene and start the rendering loop
468
639
  * @param sceneDef {@link SceneDef} to render
@@ -476,7 +647,7 @@ export declare class Renderer {
476
647
  update(...defs: RenderableDef[]): void;
477
648
  /**
478
649
  * Converts coordinates from canvas space to SVG space.
479
- * @param point point in canvas space (relative to the canvas's top left corner)
650
+ * @param point point in canvas space (relative to the canvas's top left corner), in css pixels
480
651
  * @returns point in SVG space
481
652
  */
482
653
  screenToSvg(point: Vector2Like): Vector2Like;
@@ -504,111 +675,89 @@ export declare interface RendererOptions {
504
675
  ui?: Partial<UI>;
505
676
  }
506
677
 
507
- /** Options for the {@link NavigationAPI.resetCamera} method. */
508
- declare interface ResetCameraOptions {
509
- /** Whether to reset the camera roll. */
510
- roll: boolean;
511
- /** Whether to reset the camera zoom. */
512
- zoom: boolean;
513
- }
678
+ /** Options for the {@link ControlsAPI.resetCamera} method. */
679
+ export declare type ResetCameraOptions = {
680
+ [Property in keyof Handlers]?: boolean;
681
+ };
514
682
 
515
683
  /**
516
684
  * Roll handler - implements custom two-finger rotation around arbitrary pivot point.
517
685
  * Handles mouse drag (right-click) via camera-controls and custom touch rotation.
518
- *
519
- * Touch rotation keeps world points under both fingers fixed in screen space by:
520
- * 1. Unprojecting finger midpoint to world plane
521
- * 2. Rotating camera (azimuth)
522
- * 3. Panning camera to compensate for midpoint movement
686
+ * Uses Mapbox-style threshold to prevent accidental rotations.
523
687
  */
524
- declare class RollHandler extends Handler {
525
- private rotating;
688
+ declare class RollHandler extends Handler<RollHandlerOptions> {
689
+ private isRolling;
690
+ private rotationThreshold;
526
691
  private startVector?;
527
692
  private vector?;
528
693
  private minDiameter;
529
- private startBearing;
530
- private raycaster;
694
+ private prevAngle;
531
695
  private pivotWorld;
532
- private tempVec2;
533
- private tempVec3;
534
- reset(): void;
696
+ private targetWorld;
697
+ private cameraPosition;
698
+ private cameraForward;
699
+ private rotationMatrix;
700
+ /**
701
+ * Get bearing angle between current camera orientation and true north (in radians).
702
+ * Angle is in range [0, 2π), going clockwise from north.
703
+ */
704
+ get bearing(): number;
705
+ reset(enableTransition?: boolean): Promise<void>;
706
+ /**
707
+ * Configure roll handler options
708
+ * @param options Partial options to update
709
+ */
710
+ configure(options: Partial<RollHandlerOptions>): void;
535
711
  /**
536
712
  * Enable roll gestures.
537
- * - Mobile: custom two-finger rotation with pivot compensation
713
+ * Configures camera-controls to allow any azimuth angle and two-finger touch rotate
538
714
  */
539
715
  protected onEnable(): void;
540
716
  /**
541
717
  * Disable roll gestures.
542
- * Restricts azimuth angle to zero and removes event listeners
543
718
  */
544
719
  protected onDisable(): void;
545
720
  private onRotateStart;
546
- private onRotate;
547
721
  private onRotateEnd;
722
+ private onRotate;
723
+ private setPivot;
548
724
  /**
549
725
  * Check if rotation is below threshold (Mapbox-style).
550
- * Threshold is in pixels along circumference, scaled by touch circle diameter.
726
+ * The threshold before a rotation actually happens is configured in
727
+ * pixels along the circumference of the circle formed by the two fingers.
728
+ * This makes the threshold in degrees larger when the fingers are close
729
+ * together and smaller when the fingers are far apart.
730
+ * Uses the smallest diameter from the whole gesture to reduce sensitivity
731
+ * when pinching in and out.
551
732
  * @param vector Current vector between fingers
552
733
  * @returns true if below threshold, false otherwise
553
734
  */
554
735
  private isBelowThreshold;
555
736
  /**
556
- * Get signed angle between two vectors in degrees
737
+ * Get signed angle between two vectors in degrees (Mapbox pattern)
557
738
  * @param a First vector
558
739
  * @param b Second vector
559
740
  * @returns Angle difference in degrees
560
741
  */
561
742
  private getBearingDelta;
562
743
  /**
563
- * Normalize screen pixel coordinates to NDC [-1, 1]
564
- * @param screenPos Screen position in pixels
565
- * @param out Output vector for NDC coordinates
566
- * @returns NDC coordinates
567
- */
568
- private normalizeScreenCoords;
569
- /**
570
- * Denormalize NDC coordinates to screen pixels
571
- * @param ndc NDC coordinates [-1, 1]
572
- * @param out Output vector for screen pixel coordinates
573
- * @returns Screen pixel coordinates
744
+ * Normalize angle to be between and π
745
+ * @param angle Angle in radians
746
+ * @returns Normalized angle in radians
574
747
  */
575
- private denormalizeScreenCoords;
576
- /**
577
- * Unproject screen NDC coordinates to world plane (Z=0)
578
- * @param ndc NDC coordinates [-1, 1]
579
- * @param out Output vector for world coordinates
580
- * @returns World coordinates on Z=0 plane
581
- */
582
- private unprojectToWorldPlane;
583
- /**
584
- * Project world point to screen NDC coordinates
585
- * @param worldPos World position
586
- * @param out Output vector for NDC coordinates
587
- * @returns NDC coordinates
588
- */
589
- private projectWorldToScreen;
590
- /**
591
- * Convert screen-space pixel delta to world-space translation.
592
- * For top-down view, this is a simple perspective calculation.
593
- * @param deltaX Screen delta X in pixels
594
- * @param deltaY Screen delta Y in pixels
595
- * @returns World-space translation vector
596
- */
597
- private screenDeltaToWorldDelta;
748
+ private normalizeAngle;
598
749
  }
599
750
 
600
751
  /**
601
- * Options for the RollController class.
752
+ * Configuration options for RollHandler
602
753
  */
603
- declare interface RollOptions {
604
- /** Whether the roll controller is enabled */
605
- enabled?: boolean;
606
- /** Speed in radians of arc length per pixel */
607
- speed?: number;
608
- /** Threshold in degrees for the roll gesture */
609
- angleThreshold?: number;
610
- /** Threshold in scale for the pinch gesture */
611
- pinchThreshold?: number;
754
+ declare interface RollHandlerOptions {
755
+ /**
756
+ * Rotation threshold in pixels along circumference of touch circle (Mapbox-style).
757
+ * Higher values require more movement before rotation starts.
758
+ * @default 25
759
+ */
760
+ rotationThreshold?: number;
612
761
  }
613
762
 
614
763
  /** Scene definition */
@@ -619,6 +768,8 @@ export declare interface SceneDef {
619
768
  background?: ColorInput;
620
769
  /** SVG viewbox */
621
770
  viewbox: Rect;
771
+ /** Scene's rectangle bounds in SVG coordinates. Essentially, the size of a largest layer */
772
+ bounds?: Rect;
622
773
  /** Textures memory limit in megabytes */
623
774
  memoryLimit?: number;
624
775
  }
@@ -641,6 +792,8 @@ export declare interface SharedDef {
641
792
  dim?: boolean;
642
793
  }
643
794
 
795
+ declare type Space = "svg" | "world";
796
+
644
797
  /** Text alignment */
645
798
  export declare interface TextAlignment {
646
799
  /** Horizontal alignment */
@@ -695,8 +848,102 @@ export declare interface UI {
695
848
  memoryInfoPanel: HTMLDivElement;
696
849
  }
697
850
 
698
- /** Options for the {@link NavigationAPI.zoomTo} method. */
699
- declare interface ZoomToOptions {
851
+ /** Viewport system. Manages the scene and camera. */
852
+ declare class ViewportSystem {
853
+ private renderer;
854
+ private eventSystem;
855
+ private sceneSystem;
856
+ private cameraSystem;
857
+ private raycaster;
858
+ private intersectionPoint;
859
+ private viewboxPlane;
860
+ private pxToSvgScaleThreshold;
861
+ private prevPxToSvgScale?;
862
+ private externalStaticTransformMatrix;
863
+ /**
864
+ * @param renderer {@link Renderer} instance
865
+ * @param eventSystem {@link EventSystem} instance
866
+ */
867
+ constructor(renderer: Renderer, eventSystem: EventSystem);
868
+ /** {@link Scene} instance */
869
+ get scene(): Scene;
870
+ /** Current {@link Camera} instance */
871
+ get camera(): Camera;
872
+ /** {@link CameraController} instance */
873
+ get cameraController(): CameraController;
874
+ /** Current camera zoom factor. */
875
+ get zoomFactor(): number;
876
+ /** Scene scale factor (SVG to pixel) */
877
+ get scaleFactor(): number;
878
+ /**
879
+ * Initializes the viewport and zoom bounds with the given scene definition.
880
+ * @param sceneDef {@link SceneDef} scene definition
881
+ */
882
+ initViewport(sceneDef: SceneDef): void;
883
+ /** Updates the viewport when the renderer size changes. */
884
+ updateViewport(): void;
885
+ /**
886
+ * Recalculates the svg to pixel scale factor and emits the event if necessary.
887
+ */
888
+ updatePtScale(): void;
889
+ /**
890
+ * Gets the objects intersected by the raycaster.
891
+ * @param normalizedCoords raycast point in NDC (normalized device coordinates
892
+ * @returns Array of {@link Intersection} instances
893
+ */
894
+ getIntersectedObjects(normalizedCoords: Vector2): Intersection<Object3D<Object3DEventMap>>[];
895
+ /**
896
+ * Converts a point from SVG coordinates to world coordinates.
897
+ * @param svgCoords Point in SVG coordinates
898
+ * @returns Point in world coordinates
899
+ */
900
+ svgToWorld(svgCoords: Vector2): Vector2;
901
+ /**
902
+ * Converts a point from screen coordinates to the given coordinate space.
903
+ * @param space Space to convert to (either "svg" or "world")
904
+ * @param normalizedCoords Point in NDC (normalized device coordinates)
905
+ * @returns Point in the given space
906
+ */
907
+ screenTo(space: Space, normalizedCoords: Vector2): Vector2Like;
908
+ /**
909
+ * Calculates the camera distance from the scene's plane for a given zoom factor.
910
+ * @param zoomFactor Zoom factor
911
+ * @returns Corresponding camera distance on the Z axis
912
+ */
913
+ zoomFactorToDistance(zoomFactor: number): number;
914
+ /**
915
+ * Sets the external transform matrix.
916
+ * @param staticTransformMatrix static transform matrix to apply to the scene
917
+ */
918
+ setExternalTransform(staticTransformMatrix: number[]): void;
919
+ /**
920
+ * Updates the external camera.
921
+ * @param dynamicTransformMatrix dynamic transform matrix to apply to the scene
922
+ */
923
+ updateExternalCamera(dynamicTransformMatrix: number[]): void;
924
+ }
925
+
926
+ /**
927
+ * Zoom handler - wraps camera-controls DOLLY action.
928
+ * Handles both mouse wheel and two-finger pinch gestures.
929
+ * No custom event listeners needed - camera-controls handles everything
930
+ */
931
+ declare class ZoomHandler extends Handler {
932
+ reset(enableTransition?: boolean): Promise<void>;
933
+ /**
934
+ * Enable zoom gestures.
935
+ * Configures camera-controls to handle mouse wheel and two-finger pinch
936
+ */
937
+ protected onEnable(): void;
938
+ /**
939
+ * Disable zoom gestures.
940
+ * Removes zoom actions from camera-controls
941
+ */
942
+ protected onDisable(): void;
943
+ }
944
+
945
+ /** Options for the {@link ControlsAPI.zoomTo} method. */
946
+ export declare interface ZoomToOptions {
700
947
  /** Maximum zoom factor. */
701
948
  maxZoom: number;
702
949
  /** Percentage of padding to add to the target rectangle. */