@selvajs/visualization 1.0.0-beta.0 → 1.0.0-beta.2

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 (43) hide show
  1. package/README.md +11 -10
  2. package/dist/gpu-dispose-Dkj-BKt4.js +2 -0
  3. package/dist/gpu-dispose-Dkj-BKt4.js.map +1 -0
  4. package/dist/gpu-dispose-DrN-ryj5.cjs +2 -0
  5. package/dist/gpu-dispose-DrN-ryj5.cjs.map +1 -0
  6. package/dist/index.cjs +0 -1
  7. package/dist/index.d.cts +1 -2
  8. package/dist/index.d.ts +1 -2
  9. package/dist/index.js +1 -1
  10. package/dist/parse.cjs +3 -3
  11. package/dist/parse.cjs.map +1 -1
  12. package/dist/parse.d.cts +135 -142
  13. package/dist/parse.d.ts +135 -142
  14. package/dist/parse.js +3 -3
  15. package/dist/parse.js.map +1 -1
  16. package/dist/render.cjs +8 -10
  17. package/dist/render.cjs.map +1 -1
  18. package/dist/render.d.cts +335 -333
  19. package/dist/render.d.ts +335 -333
  20. package/dist/render.js +8 -10
  21. package/dist/render.js.map +1 -1
  22. package/dist/rolldown-runtime-BocRIvOZ.cjs +1 -0
  23. package/dist/scene.cjs +1 -1
  24. package/dist/scene.cjs.map +1 -1
  25. package/dist/scene.d.cts +95 -95
  26. package/dist/scene.d.ts +95 -95
  27. package/dist/scene.js +1 -1
  28. package/dist/scene.js.map +1 -1
  29. package/dist/types-Di80Y609.d.cts +34 -0
  30. package/dist/types-Di80Y609.d.ts +34 -0
  31. package/package.json +14 -10
  32. package/dist/chunk-5XGN7UAV.js +0 -2
  33. package/dist/chunk-5XGN7UAV.js.map +0 -1
  34. package/dist/chunk-AQJPVUH3.cjs +0 -2
  35. package/dist/chunk-AQJPVUH3.cjs.map +0 -1
  36. package/dist/chunk-BYLIBOAU.cjs +0 -2
  37. package/dist/chunk-BYLIBOAU.cjs.map +0 -1
  38. package/dist/chunk-EXAI6IC5.js +0 -2
  39. package/dist/chunk-EXAI6IC5.js.map +0 -1
  40. package/dist/index.cjs.map +0 -1
  41. package/dist/index.js.map +0 -1
  42. package/dist/types-CdF9R3qA.d.cts +0 -41
  43. package/dist/types-CdF9R3qA.d.ts +0 -41
package/dist/render.d.cts CHANGED
@@ -1,50 +1,52 @@
1
- import * as THREE from 'three';
2
- import { L as Look, a as LookPreset, M as MaterialAppearanceOptions } from './types-CdF9R3qA.cjs';
3
- export { b as LOOKS } from './types-CdF9R3qA.cjs';
4
- import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
5
-
1
+ import { i as MaterialAppearanceOptions, n as Look, r as LookPreset, t as LOOKS } from "./types-Di80Y609.cjs";
2
+ import * as THREE from "three";
3
+ import { OrbitControls } from "three/addons/controls/OrbitControls.js";
4
+ import "three/addons/renderers/CSS2DRenderer.js";
5
+ //#region src/shared/errors.d.ts
6
6
  /**
7
7
  * Errors for the visualization package. Replaces `@selvajs/compute`'s `RhinoComputeError`, which
8
8
  * mis-named failures on paths (e.g. the plugin WebSocket) that never touch Rhino.Compute. `code`
9
9
  * values match compute's so existing catch-sites keep working.
10
10
  */
11
11
  declare const ErrorCodes: {
12
- /** Structural check failed: bad magic bytes, out-of-window index, malformed metadata. */
13
- readonly VALIDATION_ERROR: "VALIDATION_ERROR";
14
- readonly INVALID_STATE: "INVALID_STATE";
15
- /** No `DecompressionStream`, no WebGL context, etc. */
16
- readonly ENVIRONMENT_ERROR: "ENVIRONMENT_ERROR";
17
- readonly INVALID_CONFIG: "INVALID_CONFIG";
18
- /** Base64 input could not be decoded. */
19
- readonly ENCODING_ERROR: "ENCODING_ERROR";
20
- readonly UNKNOWN_ERROR: "UNKNOWN_ERROR";
12
+ /** Structural check failed: bad magic bytes, out-of-window index, malformed metadata. */
13
+ readonly VALIDATION_ERROR: "VALIDATION_ERROR";
14
+ readonly INVALID_STATE: "INVALID_STATE";
15
+ /** No `DecompressionStream`, no WebGL context, etc. */
16
+ readonly ENVIRONMENT_ERROR: "ENVIRONMENT_ERROR";
17
+ readonly INVALID_CONFIG: "INVALID_CONFIG";
18
+ /** Base64 input could not be decoded. */
19
+ readonly ENCODING_ERROR: "ENCODING_ERROR";
20
+ readonly UNKNOWN_ERROR: "UNKNOWN_ERROR";
21
21
  };
22
22
  type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];
23
23
  declare class VisualizationError extends Error {
24
- readonly code: ErrorCode;
25
- readonly context?: Record<string, unknown>;
26
- readonly originalError?: Error;
27
- constructor(message: string, code?: ErrorCode, options?: {
28
- context?: Record<string, unknown>;
29
- originalError?: Error;
30
- });
24
+ readonly code: ErrorCode;
25
+ readonly context?: Record<string, unknown>;
26
+ readonly originalError?: Error;
27
+ constructor(message: string, code?: ErrorCode, options?: {
28
+ context?: Record<string, unknown>;
29
+ originalError?: Error;
30
+ });
31
31
  }
32
-
32
+ //#endregion
33
+ //#region src/shared/logger.d.ts
33
34
  /**
34
35
  * Logging facility for the visualization package. Deliberately local rather than imported from
35
36
  * `@selvajs/compute` (logging isn't a compute concern). Mirrors compute's logger shape so a host
36
37
  * wanting one sink for both can call `setLogger(computeLogger.getLogger())`.
37
38
  */
38
39
  interface Logger {
39
- debug(message: string, ...args: unknown[]): void;
40
- info(message: string, ...args: unknown[]): void;
41
- warn(message: string, ...args: unknown[]): void;
42
- error(message: string, ...args: unknown[]): void;
40
+ debug(message: string, ...args: unknown[]): void;
41
+ info(message: string, ...args: unknown[]): void;
42
+ warn(message: string, ...args: unknown[]): void;
43
+ error(message: string, ...args: unknown[]): void;
43
44
  }
44
45
  declare function getLogger(): Logger;
45
46
  declare function setLogger(logger: Logger | Console | null): void;
46
47
  declare function enableDebugLogging(): void;
47
-
48
+ //#endregion
49
+ //#region src/shared/looks.d.ts
48
50
  /** The look applied when the caller passes no `look` option. */
49
51
  declare const DEFAULT_LOOK: Look;
50
52
  /**
@@ -57,209 +59,206 @@ declare const DEFAULT_LOOK: Look;
57
59
  declare const LOOK_PRESETS: Record<Look, LookPreset>;
58
60
  /** Baked at parse time (not toggleable at runtime). */
59
61
  declare function materialAppearanceForLook(look: Look): MaterialAppearanceOptions;
60
-
62
+ //#endregion
63
+ //#region src/render/types.d.ts
61
64
  type CameraConfig = {
62
- position?: THREE.Vector3;
63
- fov?: number;
64
- near?: number;
65
- far?: number;
66
- target?: THREE.Vector3;
67
- /**
68
- * Refit the near plane to the camera↔content gap every frame (default true) — recovers
69
- * depth-buffer precision when zoomed out, preventing distant z-fighting. `near` is only ever
70
- * raised, never lowered below the configured value.
71
- */
72
- dynamicNear?: boolean;
65
+ position?: THREE.Vector3;
66
+ fov?: number;
67
+ near?: number;
68
+ far?: number;
69
+ target?: THREE.Vector3;
70
+ /**
71
+ * Refit the near plane to the camera↔content gap every frame (default true) — recovers
72
+ * depth-buffer precision when zoomed out, preventing distant z-fighting. `near` is only ever
73
+ * raised, never lowered below the configured value.
74
+ */
75
+ dynamicNear?: boolean;
73
76
  };
74
77
  type LightingConfig = {
75
- enableSunlight?: boolean;
76
- sunlightIntensity?: number;
77
- sunlightPosition?: THREE.Vector3;
78
- ambientLightColor?: THREE.Color;
79
- ambientLightIntensity?: number;
80
- sunlightColor?: THREE.Color | number;
81
- /**
82
- * Direction-aware fill (sky color above, ground color below) so surfaces facing away from the
83
- * sun don't collapse to black under a dark HDR. Default false — enabling it shifts the look.
84
- */
85
- enableHemisphereLight?: boolean;
86
- /** Default white. */
87
- hemisphereSkyColor?: THREE.Color | number;
88
- /** Default a mid grey. */
89
- hemisphereGroundColor?: THREE.Color | number;
90
- /** Default 0.6. Only applies when {@link LightingConfig.enableHemisphereLight}. */
91
- hemisphereIntensity?: number;
78
+ enableSunlight?: boolean;
79
+ sunlightIntensity?: number;
80
+ sunlightPosition?: THREE.Vector3;
81
+ ambientLightColor?: THREE.Color;
82
+ ambientLightIntensity?: number;
83
+ sunlightColor?: THREE.Color | number;
84
+ /**
85
+ * Direction-aware fill (sky color above, ground color below) so surfaces facing away from the
86
+ * sun don't collapse to black under a dark HDR. Default false — enabling it shifts the look.
87
+ */
88
+ enableHemisphereLight?: boolean;
89
+ /** Default white. */
90
+ hemisphereSkyColor?: THREE.Color | number;
91
+ /** Default a mid grey. */
92
+ hemisphereGroundColor?: THREE.Color | number;
93
+ /** Default 0.6. Only applies when {@link LightingConfig.enableHemisphereLight}. */
94
+ hemisphereIntensity?: number;
92
95
  };
93
96
  type EnvironmentConfig = {
94
- hdrPath?: string;
95
- backgroundColor?: THREE.Color | string;
96
- enableEnvironmentLighting?: boolean;
97
- /**
98
- * Defaults to `(0, 0, 1)` — Rhino's Z-up, not Three's native Y-up because geometry arrives in
99
- * Rhino's frame and is never rotated on ingress. Everything orientation-dependent derives from
100
- * this (view presets, default camera, sun, grid, floor, hemisphere light), but overriding it
101
- * reorients the viewer only — it does NOT rotate incoming geometry.
102
- */
103
- sceneUp?: THREE.Vector3;
104
- showEnvironment?: boolean;
105
- /**
106
- * Multiplier on the HDR's image-based lighting contribution — normalizes brightness across HDRs
107
- * of differing exposure. Default 1 (unchanged look).
108
- */
109
- environmentIntensity?: number;
97
+ hdrPath?: string;
98
+ backgroundColor?: THREE.Color | string;
99
+ enableEnvironmentLighting?: boolean;
100
+ /**
101
+ * Default `(0, 0, 1)` — Rhino's Z-up. Every orientation default derives from this (see `up-axis.ts`);
102
+ * overriding it reorients the viewer only, it does not rotate incoming geometry.
103
+ */
104
+ sceneUp?: THREE.Vector3;
105
+ showEnvironment?: boolean;
106
+ /**
107
+ * Multiplier on the HDR's image-based lighting contribution — normalizes brightness across HDRs
108
+ * of differing exposure. Default 1 (unchanged look).
109
+ */
110
+ environmentIntensity?: number;
110
111
  };
111
112
  type FloorConfig = {
112
- enabled?: boolean;
113
- size?: number;
114
- color?: THREE.Color | string;
115
- roughness?: number;
116
- metalness?: number;
117
- receiveShadow?: boolean;
113
+ enabled?: boolean;
114
+ size?: number;
115
+ color?: THREE.Color | string;
116
+ roughness?: number;
117
+ metalness?: number;
118
+ receiveShadow?: boolean;
118
119
  };
119
120
  type RenderConfig = {
120
- enableShadows?: boolean;
121
- shadowMapSize?: number;
122
- antialias?: boolean;
123
- pixelRatio?: number;
124
- toneMapping?: THREE.ToneMapping;
125
- toneMappingExposure?: number;
126
- preserveDrawingBuffer?: boolean;
127
- /** Default false — switches rendering from `renderer.render` to an EffectComposer, which costs more. */
128
- ambientOcclusion?: boolean;
129
- /** AO strength 0–1 when {@link RenderConfig.ambientOcclusion} is on. Default 1. */
130
- aoIntensity?: number;
131
- /**
132
- * DPR cap for AO buffers — AO is low-frequency, so sampling below display DPR is nearly invisible
133
- * but much cheaper (a DPR-2 display would otherwise push 4× the pixels through GTAO's per-pixel
134
- * sample loop). Default 1; only relevant when AO is enabled.
135
- */
136
- aoPixelRatio?: number;
137
- /**
138
- * Render only on change (camera motion, invalidate(), pointer input, resize) plus a ~500ms safety
139
- * repaint, instead of every frame. Default true — cuts idle GPU/battery use. Set false to restore
140
- * a continuous loop.
141
- */
142
- onDemand?: boolean;
121
+ enableShadows?: boolean;
122
+ shadowMapSize?: number;
123
+ antialias?: boolean;
124
+ pixelRatio?: number;
125
+ toneMapping?: THREE.ToneMapping;
126
+ toneMappingExposure?: number;
127
+ preserveDrawingBuffer?: boolean;
128
+ /** Default false — switches rendering from `renderer.render` to an EffectComposer, which costs more. */
129
+ ambientOcclusion?: boolean;
130
+ /** AO strength 0–1 when {@link RenderConfig.ambientOcclusion} is on. Default 1. */
131
+ aoIntensity?: number;
132
+ /**
133
+ * DPR cap for AO buffers — AO is low-frequency, so sampling below display DPR is nearly invisible
134
+ * but much cheaper (a DPR-2 display would otherwise push 4× the pixels through GTAO's per-pixel
135
+ * sample loop). Default 1; only relevant when AO is enabled.
136
+ */
137
+ aoPixelRatio?: number;
138
+ /**
139
+ * Render only on change (camera motion, invalidate(), pointer input, resize) plus a ~500ms safety
140
+ * repaint, instead of every frame. Default true — cuts idle GPU/battery use. Set false to restore
141
+ * a continuous loop.
142
+ */
143
+ onDemand?: boolean;
143
144
  };
144
-
145
- /** Crisp boundary/crease edge overlays on meshes. See `addEdges`. */
145
+ /** Crisp boundary/crease edge overlays on meshes. Field rationale: see `EdgeOptions` in `edges/options.ts`. */
146
146
  type EdgesConfig = {
147
- /** Default false (opt-in). */
148
- enabled?: boolean;
149
- /** Omit (default) to derive each mesh's edge color from its own surface material, darkened by `darken`. */
150
- color?: THREE.ColorRepresentation;
151
- /** 0–1, default 0.75. Ignored when `color` is set. */
152
- darken?: number;
153
- /** CSS px. Default 1.5. */
154
- width?: number;
155
- /** Crease angle in degrees: keep edges where faces differ by more than this. Default 44. */
156
- thresholdAngle?: number;
157
- /** Fade an overlay out as its mesh shrinks on screen. Default true. */
158
- distanceFade?: boolean;
159
- /** Skip overlay extraction for meshes above this triangle count. Default 4M. */
160
- maxTriangles?: number;
161
- /** Overlays above this segment count render opaque (no distance fade). Default 2M. */
162
- maxSegments?: number;
163
- /** Meshes skipped for exceeding `maxTriangles` fall back to the screen-space edge-detection pass
164
- * (constant cost regardless of triangle count). Default true. */
165
- screenSpaceFallback?: boolean;
147
+ /** Default false (opt-in). */
148
+ enabled?: boolean;
149
+ color?: THREE.ColorRepresentation;
150
+ /** 0–1, default 0.75. Ignored when `color` is set. */
151
+ darken?: number;
152
+ /** CSS px. Default 1.5. */
153
+ width?: number;
154
+ /** Degrees. Default 44. */
155
+ thresholdAngle?: number;
156
+ /** Default true. */
157
+ distanceFade?: boolean;
158
+ /** Default 4M. */
159
+ maxTriangles?: number;
160
+ /** Default 2M. */
161
+ maxSegments?: number;
162
+ /** Fall back to the screen-space edge-detection pass for meshes skipped by `maxTriangles`. Default true. */
163
+ screenSpaceFallback?: boolean;
166
164
  };
167
165
  type ControlsConfig = {
168
- enableDamping?: boolean;
169
- dampingFactor?: number;
170
- autoRotate?: boolean;
171
- autoRotateSpeed?: number;
172
- enableZoom?: boolean;
173
- enablePan?: boolean;
174
- minDistance?: number;
175
- maxDistance?: number;
166
+ enableDamping?: boolean;
167
+ dampingFactor?: number;
168
+ autoRotate?: boolean;
169
+ autoRotateSpeed?: number;
170
+ enableZoom?: boolean;
171
+ enablePan?: boolean;
172
+ minDistance?: number;
173
+ maxDistance?: number;
176
174
  };
177
175
  /** Infinite distance-fading reference grid. See `createGrid`. */
178
176
  type GridConfig = {
179
- /** Default false (opt-in). */
180
- enabled?: boolean;
181
- /** World units (meters). Default 1. */
182
- cellSize?: number;
183
- /** Minor cells per major line. Default 10. */
184
- majorEvery?: number;
185
- cellColor?: THREE.ColorRepresentation;
186
- majorColor?: THREE.ColorRepresentation;
187
- /** World radius at which the grid fully fades. Default 100. */
188
- fadeDistance?: number;
189
- /**
190
- * Axis the grid lies perpendicular to. Defaults to whichever axis `sceneUp` points along
191
- * (`'z'` unless `sceneUp` is overridden); set explicitly to force an orientation that ignores it.
192
- */
193
- plane?: 'x' | 'y' | 'z';
177
+ /** Default false (opt-in). */
178
+ enabled?: boolean;
179
+ /** World units (meters). Default 1. */
180
+ cellSize?: number;
181
+ /** Minor cells per major line. Default 10. */
182
+ majorEvery?: number;
183
+ cellColor?: THREE.ColorRepresentation;
184
+ majorColor?: THREE.ColorRepresentation;
185
+ /** World radius at which the grid fully fades. Default 100. */
186
+ fadeDistance?: number;
187
+ /**
188
+ * Axis the grid lies perpendicular to. Defaults to whichever axis `sceneUp` points along
189
+ * (`'z'` unless `sceneUp` is overridden); set explicitly to force an orientation that ignores it.
190
+ */
191
+ plane?: 'x' | 'y' | 'z';
194
192
  };
195
193
  /** Corner nav-cube/axis gizmo that snaps to preset views. See `createViewGizmo`. */
196
194
  type GizmoConfig = {
197
- /** Default false (opt-in). */
198
- enabled?: boolean;
195
+ /** Default false (opt-in). */
196
+ enabled?: boolean;
199
197
  };
200
198
  /** Two-click distance measurement tool. See `createMeasureTool`. */
201
199
  type MeasureConfig = {
202
- /** Default false. Only builds the tool; start measuring via `measureTool.setEnabled(true)` on the init result. */
203
- enabled?: boolean;
204
- /** Snap to a vertex within this many screen px. Default 12. */
205
- snapPixels?: number;
206
- /** Default yellow. */
207
- color?: THREE.ColorRepresentation;
208
- /** CSS class for the distance label. */
209
- labelClassName?: string;
210
- /** Scene is in meters; pass the response's `modelunits` to convert the label (e.g. "25.0 mm"). Default meters. Ignored if `format` is set. */
211
- displayUnit?: string;
212
- /** Receives the straight-line `distance` and per-axis `delta`. Default renders the total plus a Δx/Δy/Δz breakdown. */
213
- format?: (distance: number, delta: THREE.Vector3) => string;
200
+ /** Default false. Only builds the tool; start measuring via `measureTool.setEnabled(true)` on the init result. */
201
+ enabled?: boolean;
202
+ /** Snap to a vertex within this many screen px. Default 12. */
203
+ snapPixels?: number;
204
+ /** Default yellow. */
205
+ color?: THREE.ColorRepresentation;
206
+ /** CSS class for the distance label. */
207
+ labelClassName?: string;
208
+ /** Scene is in meters; pass the response's `modelunits` to convert the label (e.g. "25.0 mm"). Default meters. Ignored if `format` is set. */
209
+ displayUnit?: string;
210
+ /** Receives the straight-line `distance` and per-axis `delta`. Default renders the total plus a Δx/Δy/Δz breakdown. */
211
+ format?: (distance: number, delta: THREE.Vector3) => string;
214
212
  };
215
213
  type ThreeInitializerOptions = {
216
- sceneScale?: 'mm' | 'cm' | 'm' | 'inches' | 'feet';
217
- /**
218
- * Seeds lighting/material defaults (tone mapping, AO, IBL strength, hemisphere fill); explicit
219
- * `lighting`/`environment`/`render` options still win. Does NOT touch edges/grid. Default
220
- * 'technical'. Re-apply later via the init result's `setLook`.
221
- */
222
- look?: Look;
223
- camera?: CameraConfig;
224
- lighting?: LightingConfig;
225
- environment?: EnvironmentConfig;
226
- floor?: FloorConfig;
227
- render?: RenderConfig;
228
- controls?: ControlsConfig;
229
- grid?: GridConfig;
230
- gizmo?: GizmoConfig;
231
- edges?: EdgesConfig;
232
- measure?: MeasureConfig;
233
- events?: EventConfig;
234
- /**
235
- * Called once at init with the GPU's max anisotropy. **Not needed for sharp textures**the
236
- * parse layer's texture cache subscribes to this value itself via a shared sink. This hook is
237
- * only for hosts doing their own texture work on top.
238
- */
239
- onMaxAnisotropy?: (value: number) => void;
214
+ sceneScale?: 'mm' | 'cm' | 'm' | 'inches' | 'feet';
215
+ /**
216
+ * Seeds lighting/material defaults (tone mapping, AO, IBL strength, hemisphere fill); explicit
217
+ * `lighting`/`environment`/`render` options still win. Does NOT touch edges/grid. Default
218
+ * 'technical'. Re-apply later via the init result's `setLook`.
219
+ */
220
+ look?: Look;
221
+ camera?: CameraConfig;
222
+ lighting?: LightingConfig;
223
+ environment?: EnvironmentConfig;
224
+ floor?: FloorConfig;
225
+ render?: RenderConfig;
226
+ controls?: ControlsConfig;
227
+ grid?: GridConfig;
228
+ gizmo?: GizmoConfig;
229
+ edges?: EdgesConfig;
230
+ measure?: MeasureConfig;
231
+ events?: EventConfig;
232
+ /**
233
+ * Called once at init with the GPU's max anisotropy. Not needed for sharp textures — `parse/`'s
234
+ * texture cache subscribes to this value on its own (see README's render↔parse seam). Only for
235
+ * hosts doing their own texture work.
236
+ */
237
+ onMaxAnisotropy?: (value: number) => void;
240
238
  };
241
239
  type EventConfig = {
242
- onBackgroundClicked?: (event: {
243
- x: number;
244
- y: number;
245
- }) => void;
246
- onObjectSelected?: (object: THREE.Object3D) => void;
247
- /** Receives the clicked mesh's `userData`; only fires for meshes with non-empty `userData`. */
248
- onMeshMetadataClicked?: (metadata: Record<string, unknown>) => void;
249
- onMeshDoubleClicked?: (object: THREE.Object3D) => void;
250
- /** Default red (#ff0000). */
251
- selectionColor?: THREE.Color | string;
252
- /** Enable all event handlers (click/selection/metadata). Default true. */
253
- enableEventHandlers?: boolean;
254
- enableKeyboardControls?: boolean;
255
- enableClickToFocus?: boolean;
256
- /** Default true. */
257
- enableDoubleClickZoom?: boolean;
258
- onReady?: () => void;
259
- /** Fires every animation frame, after controls update and before render. */
260
- onFrame?: (delta: number) => void;
240
+ onBackgroundClicked?: (event: {
241
+ x: number;
242
+ y: number;
243
+ }) => void;
244
+ onObjectSelected?: (object: THREE.Object3D) => void;
245
+ /** Receives the clicked mesh's `userData`; only fires for meshes with non-empty `userData`. */
246
+ onMeshMetadataClicked?: (metadata: Record<string, unknown>) => void;
247
+ onMeshDoubleClicked?: (object: THREE.Object3D) => void;
248
+ /** Default red (#ff0000). */
249
+ selectionColor?: THREE.Color | string;
250
+ /** Enable all event handlers (click/selection/metadata). Default true. */
251
+ enableEventHandlers?: boolean;
252
+ enableKeyboardControls?: boolean;
253
+ enableClickToFocus?: boolean;
254
+ /** Default true. */
255
+ enableDoubleClickZoom?: boolean;
256
+ onReady?: () => void;
257
+ /** Fires every animation frame, after controls update and before render. */
258
+ onFrame?: (delta: number) => void;
261
259
  };
262
-
260
+ //#endregion
261
+ //#region src/render/camera-controller.d.ts
263
262
  /**
264
263
  * Runtime camera control: preset views, perspective⇄orthographic toggle, rotate lock.
265
264
  *
@@ -267,164 +266,167 @@ type EventConfig = {
267
266
  * render loop renders, resize reshapes, and the raycaster picks with — {@link getActiveCamera} is
268
267
  * the one source of truth for all four call sites.
269
268
  *
270
- * Orthographic shadows perspective (same position/target, frustum derived from perspective FOV +
271
- * distance) so switching doesn't visually jump.
269
+ * Orthographic mirrors perspective's position/target with a frustum derived from perspective's FOV
270
+ * and distance, so switching projections doesn't visually jump.
272
271
  */
273
272
  type ViewPreset = 'top' | 'bottom' | 'front' | 'back' | 'left' | 'right' | 'iso';
274
273
  type CameraProjection = 'perspective' | 'orthographic';
275
274
  interface CameraController {
276
- /** Swaps identity on {@link setProjection}. */
277
- getActiveCamera(): THREE.Camera;
278
- getProjection(): CameraProjection;
279
- setProjection(projection: CameraProjection): void;
280
- toggleProjection(): CameraProjection;
281
- setView(preset: ViewPreset, animate?: boolean): void;
282
- /**
283
- * Frame current content from an explicit world-space direction (target → camera) instead of a
284
- * named preset — used by the nav-cube, whose clicked axis is a world axis.
285
- */
286
- setViewDirection(direction: THREE.Vector3, animate?: boolean): void;
287
- /** Frame a world-space box from the current view direction. No-op on an empty box. */
288
- frameBounds(box: THREE.Box3, animate?: boolean): void;
289
- setRotateEnabled(enabled: boolean): void;
290
- isRotateEnabled(): boolean;
291
- updateAspect(width: number, height: number): void;
292
- /** Cancel any in-flight camera tween. Call on viewer teardown so ticks can't touch disposed controls. */
293
- dispose(): void;
275
+ /** Swaps identity on {@link setProjection}. */
276
+ getActiveCamera(): THREE.Camera;
277
+ getProjection(): CameraProjection;
278
+ setProjection(projection: CameraProjection): void;
279
+ toggleProjection(): CameraProjection;
280
+ setView(preset: ViewPreset, animate?: boolean): void;
281
+ /**
282
+ * Frame current content from an explicit world-space direction (target → camera) instead of a
283
+ * named preset — used by the nav-cube, whose clicked axis is a world axis.
284
+ */
285
+ setViewDirection(direction: THREE.Vector3, animate?: boolean): void;
286
+ /** Frame a world-space box from the current view direction. No-op on an empty box. */
287
+ frameBounds(box: THREE.Box3, animate?: boolean): void;
288
+ setRotateEnabled(enabled: boolean): void;
289
+ isRotateEnabled(): boolean;
290
+ updateAspect(width: number, height: number): void;
291
+ /** Cancel any in-flight camera tween. Call on viewer teardown so ticks can't touch disposed controls. */
292
+ dispose(): void;
294
293
  }
295
-
294
+ //#endregion
295
+ //#region src/render/grid.d.ts
296
296
  interface Grid {
297
- /** Tagged `userData.id = 'grid'` so pick/fit code skips it. */
298
- readonly object: THREE.Mesh;
299
- /** Re-centers the fade on the camera so the grid feels infinite as you move. Call per frame. */
300
- update(cameraPosition: THREE.Vector3): void;
301
- /**
302
- * Rescales cell spacing and fade radius to the content's extent, so a 3-unit or 3000-unit part
303
- * both get sensible cells. No-op for empty/degenerate bounds.
304
- */
305
- fitToContent(bounds: THREE.Box3): void;
306
- setVisible(visible: boolean): void;
307
- dispose(): void;
297
+ /** Tagged `userData.id = 'grid'` so pick/fit code skips it. */
298
+ readonly object: THREE.Mesh;
299
+ /** Re-centers the fade on the camera so the grid feels infinite as you move. Call per frame. */
300
+ update(cameraPosition: THREE.Vector3): void;
301
+ /**
302
+ * Rescales cell spacing and fade radius to the content's extent, so a 3-unit or 3000-unit part
303
+ * both get sensible cells. No-op for empty/degenerate bounds.
304
+ */
305
+ fitToContent(bounds: THREE.Box3): void;
306
+ setVisible(visible: boolean): void;
307
+ dispose(): void;
308
308
  }
309
-
309
+ //#endregion
310
+ //#region src/render/measure.d.ts
310
311
  /**
311
312
  * Two-click distance measurement. Click a point, click a second, read the distance off a label on
312
313
  * the connecting line; a third click starts fresh.
313
314
  *
314
- * Picking snaps to the nearest vertex of the struck triangle within {@link MeasureOptions.snapPixels}
315
- * so measurements land exactly on vertices rather than wherever the ray happened to hit — a cheap
316
- * local snap (three candidate vertices, no spatial index).
315
+ * Picking snaps to the nearest vertex within {@link MeasureOptions.snapPixels} so measurements
316
+ * land exactly on vertices rather than wherever the ray happened to hit — a cheap local snap
317
+ * against the struck primitive's own vertices, no spatial index.
317
318
  *
318
319
  * Dormant until {@link MeasureTool.setEnabled}(true). While enabled it intercepts clicks (caller
319
320
  * forwards them and swallows the event when {@link MeasureTool.handleClick} returns true) so
320
321
  * measuring doesn't also select objects.
321
322
  */
322
323
  interface MeasureTool {
323
- setEnabled(enabled: boolean): void;
324
- isEnabled(): boolean;
325
- /** Returns true if the tool consumed the click (caller should not also select). */
326
- handleClick(event: MouseEvent): boolean;
327
- /** Preview the next snap point via a ghost marker. No-op when disabled; never consumes the event. */
328
- handleMove(event: MouseEvent): void;
329
- clear(): void;
330
- dispose(): void;
324
+ setEnabled(enabled: boolean): void;
325
+ isEnabled(): boolean;
326
+ /** Returns true if the tool consumed the click (caller should not also select). */
327
+ handleClick(event: MouseEvent): boolean;
328
+ /** Preview the next snap point via a ghost marker. No-op when disabled; never consumes the event. */
329
+ handleMove(event: MouseEvent): void;
330
+ clear(): void;
331
+ dispose(): void;
331
332
  }
332
-
333
+ //#endregion
334
+ //#region src/render/view-gizmo.d.ts
333
335
  /**
334
- * Corner nav-cube/axis gizmo. Uses three's {@link ViewHelper} only as the rendered widget, NOT its
336
+ * Corner nav-cube/axis gizmo. Uses three's {@link ViewHelper} only as the rendered widget, not its
335
337
  * click→animate behavior: ViewHelper's snap assumes Y-up and animates straight onto the up axis,
336
- * which rolls the view and jitters the gizmo at the pole in our Z-up scene. Instead we hit-test the
337
- * axis sprites ourselves and drive the viewer's up-aware camera controller, which snaps instantly
338
- * with a pole nudge so the orbit basis never degenerates.
338
+ * which rolls the view and jitters the gizmo at the pole in a Z-up scene. Instead this hit-tests
339
+ * the axis sprites directly and drives the viewer's up-aware camera controller, which snaps
340
+ * instantly with a pole nudge so the orbit basis never degenerates.
339
341
  *
340
- * A click frames the current orbit target (not the world origin), and flips the viewer back to
341
- * perspective first if it's in orthographic mode (the cube is inherently a 3D-orientation tool).
342
+ * A click frames the current orbit target (not the world origin) and switches back to perspective
343
+ * first if orthographic the cube is a 3D-orientation tool.
342
344
  *
343
- * Caller contract (mirrors ViewHelper's own): call {@link ViewGizmo.render} *after* the main scene
345
+ * Caller contract (mirrors ViewHelper's own): call {@link ViewGizmo.render} after the main scene
344
346
  * render each frame, and forward pointer clicks to {@link ViewGizmo.handleClick}.
345
347
  */
346
348
  interface ViewGizmo {
347
- render(renderer: THREE.WebGLRenderer): void;
348
- /** Returns true if it hit the gizmo (and a view change started). */
349
- handleClick(event: MouseEvent): boolean;
350
- setVisible(visible: boolean): void;
351
- isVisible(): boolean;
352
- dispose(): void;
349
+ render(renderer: THREE.WebGLRenderer): void;
350
+ /** Returns true if it hit the gizmo (and a view change started). */
351
+ handleClick(event: MouseEvent): boolean;
352
+ setVisible(visible: boolean): void;
353
+ isVisible(): boolean;
354
+ dispose(): void;
353
355
  }
354
-
356
+ //#endregion
357
+ //#region src/render/scene-setup/viewer.d.ts
355
358
  interface ThreeViewer {
356
- scene: THREE.Scene;
357
- camera: THREE.PerspectiveCamera;
358
- controls: OrbitControls;
359
- renderer: THREE.WebGLRenderer;
360
- cameraController: CameraController;
361
- grid: Grid | null;
362
- gizmo: ViewGizmo | null;
363
- /** Null unless `measure.enabled`; `setEnabled(true)` to use. */
364
- measureTool: MeasureTool | null;
365
- /**
366
- * Attach edge overlays to meshes under `root` (no-op unless `edges.enabled`). Large-mesh
367
- * extraction runs off-thread, so overlays may attach a beat later; meshes over
368
- * `edges.maxTriangles` are skipped and (by default) covered by the screen-space edge fallback.
369
- */
370
- applyEdges: (root: THREE.Object3D) => void;
371
- /**
372
- * Prefer over calling `removeEdges` directly — also cancels in-flight async attaches and stands
373
- * down the screen-space fallback if active.
374
- */
375
- clearEdges: (root: THREE.Object3D) => void;
376
- /**
377
- * Request a repaint from the on-demand render loop. Built-in setters and input invalidate
378
- * automatically; call this after mutating the scene externally. No-op when `render.onDemand` is false.
379
- */
380
- invalidate: () => void;
381
- setAmbientOcclusion: (enabled: boolean) => void;
382
- /**
383
- * Retunes lighting/material only (tone mapping, fill, IBL, AO) — never edges/grid. Overwrites
384
- * any granular lighting dials set earlier.
385
- */
386
- setLook: (look: 'studio' | 'technical' | 'showcase') => void;
387
- /**
388
- * Raising `hemisphereIntensity` is the most effective way to lift shadowed/under-facing surfaces
389
- * a dark HDR leaves black; a positive value lazily creates the hemisphere light if the viewer was
390
- * built without one, `0` switches it off.
391
- */
392
- setFillLights: (opts: {
393
- hemisphereIntensity?: number;
394
- hemisphereSkyColor?: THREE.Color | number;
395
- hemisphereGroundColor?: THREE.Color | number;
396
- ambientIntensity?: number;
397
- }) => void;
398
- /**
399
- * Normalizes IBL brightness across HDRs of differing exposure. Applies even before the HDR
400
- * finishes decoding.
401
- */
402
- setEnvironmentIntensity: (intensity: number) => void;
403
- setToneMappingExposure: (exposure: number) => void;
404
- /** GTAO strength (0-1). No-op when ambient occlusion isn't active. */
405
- setAoIntensity: (intensity: number) => void;
406
- /** Feed into the batch parser's `material` option so freshly-loaded meshes match the active look. */
407
- getMaterialAppearance: () => MaterialAppearanceOptions;
408
- /** Call after loading or replacing geometry. No-op when sunlight/shadows are off. */
409
- updateShadowBounds: () => void;
410
- /** Call after loading or replacing geometry. No-op when the grid is off or empty. */
411
- updateGridScale: () => void;
412
- dispose: () => void;
413
- fitToView: () => void;
414
- clearSelection: () => void;
415
- /**
416
- * Tagged `userData.source = 'user'` so it survives `updateScene` solves instead of being cleared
417
- * with compute content, and counts as normal content for fit-to-view framing.
418
- */
419
- addUserGeometry: (object: THREE.Object3D) => void;
420
- removeUserGeometry: (object: THREE.Object3D) => void;
421
- /** Removes and disposes everything added via `addUserGeometry`. */
422
- clearUserGeometry: () => void;
359
+ scene: THREE.Scene;
360
+ camera: THREE.PerspectiveCamera;
361
+ controls: OrbitControls;
362
+ renderer: THREE.WebGLRenderer;
363
+ cameraController: CameraController;
364
+ grid: Grid | null;
365
+ gizmo: ViewGizmo | null;
366
+ /** Null unless `measure.enabled`. */
367
+ measureTool: MeasureTool | null;
368
+ /**
369
+ * No-op unless `edges.enabled`. Extraction runs off-thread for large meshes, so overlays can
370
+ * attach a beat later; meshes over `edges.maxTriangles` fall back to the screen-space edge shader.
371
+ */
372
+ applyEdges: (root: THREE.Object3D) => void;
373
+ /**
374
+ * Prefer over `removeEdges` directly — also cancels in-flight async attaches and stands down the
375
+ * screen-space edge fallback if active.
376
+ */
377
+ clearEdges: (root: THREE.Object3D) => void;
378
+ /**
379
+ * Request a repaint from the on-demand render loop. Built-in setters and input invalidate
380
+ * automatically; call this after mutating the scene externally. No-op when `render.onDemand` is false.
381
+ */
382
+ invalidate: () => void;
383
+ setAmbientOcclusion: (enabled: boolean) => void;
384
+ /**
385
+ * Retunes lighting/material (tone mapping, fill, IBL, AO) only — never edges/grid. Overwrites
386
+ * any granular lighting dials set earlier with the preset's values.
387
+ */
388
+ setLook: (look: 'studio' | 'technical' | 'showcase') => void;
389
+ /**
390
+ * Raising `hemisphereIntensity` is the most effective way to lift shadowed surfaces a dark HDR
391
+ * leaves black. Lazily creates the hemisphere light if the viewer was built without one; `0` turns
392
+ * it back off.
393
+ */
394
+ setFillLights: (opts: {
395
+ hemisphereIntensity?: number;
396
+ hemisphereSkyColor?: THREE.Color | number;
397
+ hemisphereGroundColor?: THREE.Color | number;
398
+ ambientIntensity?: number;
399
+ }) => void;
400
+ /**
401
+ * Normalizes IBL brightness across HDRs of differing exposure. Applies even before the HDR
402
+ * finishes decoding.
403
+ */
404
+ setEnvironmentIntensity: (intensity: number) => void;
405
+ setToneMappingExposure: (exposure: number) => void;
406
+ /** GTAO strength (0-1). No-op when ambient occlusion isn't active. */
407
+ setAoIntensity: (intensity: number) => void;
408
+ /** Feed into the batch parser's `material` option so freshly-loaded meshes match the active look. */
409
+ getMaterialAppearance: () => MaterialAppearanceOptions;
410
+ /** Call after loading or replacing geometry. No-op when sunlight/shadows are off. */
411
+ updateShadowBounds: () => void;
412
+ /** Call after loading or replacing geometry. No-op when the grid is off or empty. */
413
+ updateGridScale: () => void;
414
+ dispose: () => void;
415
+ fitToView: () => void;
416
+ clearSelection: () => void;
417
+ /** Tagged `userData.source = 'user'` so it survives `updateScene` solves and counts for fit-to-view. */
418
+ addUserGeometry: (object: THREE.Object3D) => void;
419
+ removeUserGeometry: (object: THREE.Object3D) => void;
420
+ /** Removes and disposes everything added via `addUserGeometry`. */
421
+ clearUserGeometry: () => void;
423
422
  }
424
-
423
+ //#endregion
424
+ //#region src/render/scene-setup/init-three.d.ts
425
425
  declare const initThree: (canvas: HTMLCanvasElement, options?: ThreeInitializerOptions) => ThreeViewer;
426
-
426
+ //#endregion
427
+ //#region src/render/three-helpers.d.ts
427
428
  /** Replaces scene content with `meshes`, rescales the camera frustum to fit, and (first call only) positions the camera/controls. */
428
429
  declare function updateScene(scene: THREE.Scene, meshes: THREE.Object3D[], camera: THREE.PerspectiveCamera, controls: OrbitControls, initialPositionSet: boolean): void;
429
-
430
- export { type CameraConfig, type CameraController, type CameraProjection, type ControlsConfig, DEFAULT_LOOK, type EdgesConfig, type EnvironmentConfig, type ErrorCode, ErrorCodes, type EventConfig, type FloorConfig, type GizmoConfig, type Grid, type GridConfig, LOOK_PRESETS, type LightingConfig, type Logger, Look, LookPreset, MaterialAppearanceOptions, type MeasureConfig, type MeasureTool, type RenderConfig, type ThreeInitializerOptions, type ThreeViewer, type ViewGizmo, type ViewPreset, VisualizationError, enableDebugLogging, getLogger, initThree, materialAppearanceForLook, setLogger, updateScene };
430
+ //#endregion
431
+ export { type CameraConfig, type CameraController, type CameraProjection, type ControlsConfig, DEFAULT_LOOK, type EdgesConfig, type EnvironmentConfig, type ErrorCode, ErrorCodes, type EventConfig, type FloorConfig, type GizmoConfig, type Grid, type GridConfig, LOOKS, LOOK_PRESETS, type LightingConfig, type Logger, type Look, type LookPreset, type MaterialAppearanceOptions, type MeasureConfig, type MeasureTool, type RenderConfig, type ThreeInitializerOptions, type ThreeViewer, type ViewGizmo, type ViewPreset, VisualizationError, enableDebugLogging, getLogger, initThree, materialAppearanceForLook, setLogger, updateScene };
432
+ //# sourceMappingURL=render.d.cts.map