three-cad-viewer 4.3.5 → 4.3.7

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 (58) hide show
  1. package/dist/three-cad-viewer.esm.js +8 -5
  2. package/dist/three-cad-viewer.esm.js.map +1 -1
  3. package/dist/three-cad-viewer.esm.min.js +1 -1
  4. package/dist/three-cad-viewer.js +8 -5
  5. package/dist/three-cad-viewer.min.js +1 -1
  6. package/package.json +2 -3
  7. package/src/_version.ts +0 -1
  8. package/src/camera/camera.ts +0 -445
  9. package/src/camera/controls/CADOrbitControls.ts +0 -241
  10. package/src/camera/controls/CADTrackballControls.ts +0 -598
  11. package/src/camera/controls.ts +0 -380
  12. package/src/core/patches.ts +0 -16
  13. package/src/core/studio-manager.ts +0 -652
  14. package/src/core/types.ts +0 -892
  15. package/src/core/viewer-state.ts +0 -784
  16. package/src/core/viewer.ts +0 -4821
  17. package/src/index.ts +0 -151
  18. package/src/rendering/environment.ts +0 -840
  19. package/src/rendering/light-detection.ts +0 -327
  20. package/src/rendering/material-factory.ts +0 -735
  21. package/src/rendering/material-presets.ts +0 -289
  22. package/src/rendering/raycast.ts +0 -291
  23. package/src/rendering/room-environment.ts +0 -192
  24. package/src/rendering/studio-composer.ts +0 -577
  25. package/src/rendering/studio-floor.ts +0 -108
  26. package/src/rendering/texture-cache.ts +0 -324
  27. package/src/rendering/tree-model.ts +0 -542
  28. package/src/rendering/triplanar.ts +0 -329
  29. package/src/scene/animation.ts +0 -343
  30. package/src/scene/axes.ts +0 -108
  31. package/src/scene/bbox.ts +0 -223
  32. package/src/scene/clipping.ts +0 -650
  33. package/src/scene/grid.ts +0 -864
  34. package/src/scene/nestedgroup.ts +0 -1448
  35. package/src/scene/objectgroup.ts +0 -866
  36. package/src/scene/orientation.ts +0 -259
  37. package/src/scene/render-shape.ts +0 -634
  38. package/src/tools/cad_tools/measure.ts +0 -811
  39. package/src/tools/cad_tools/select.ts +0 -100
  40. package/src/tools/cad_tools/tools.ts +0 -231
  41. package/src/tools/cad_tools/ui.ts +0 -454
  42. package/src/tools/cad_tools/zebra.ts +0 -369
  43. package/src/types/html.d.ts +0 -5
  44. package/src/types/n8ao.d.ts +0 -28
  45. package/src/types/three-augmentation.d.ts +0 -60
  46. package/src/ui/display.ts +0 -3295
  47. package/src/ui/index.html +0 -505
  48. package/src/ui/info.ts +0 -177
  49. package/src/ui/slider.ts +0 -206
  50. package/src/ui/toolbar.ts +0 -347
  51. package/src/ui/treeview.ts +0 -945
  52. package/src/utils/decode-instances.ts +0 -233
  53. package/src/utils/font.ts +0 -60
  54. package/src/utils/gpu-tracker.ts +0 -265
  55. package/src/utils/logger.ts +0 -92
  56. package/src/utils/sizeof.ts +0 -116
  57. package/src/utils/timer.ts +0 -69
  58. package/src/utils/utils.ts +0 -446
@@ -1,116 +0,0 @@
1
- /**
2
- * Options for memory size calculation.
3
- */
4
- interface MemorySizeOptions {
5
- excludeAttributes?: string[];
6
- visited?: WeakSet<object>;
7
- }
8
-
9
- function calculateObjectSize(obj: unknown, options: MemorySizeOptions = {}): number {
10
- const {
11
- excludeAttributes = ["parent", "context", "_parent", "__parent"],
12
- visited = new WeakSet(),
13
- } = options;
14
-
15
- // Prevent circular reference
16
- if (obj === null || obj === undefined) return 0;
17
-
18
- // Check for primitive types
19
- if (
20
- ["number", "string", "boolean", "symbol", "bigint"].includes(typeof obj)
21
- ) {
22
- return estimatePrimitiveSize(obj as string | number | boolean | symbol | bigint);
23
- }
24
-
25
- // Prevent circular references
26
- if (typeof obj === "object" && visited.has(obj)) return 0;
27
- if (typeof obj === "object") visited.add(obj);
28
-
29
- // Handle Arrays
30
- if (Array.isArray(obj)) {
31
- return obj.reduce(
32
- (total, item) =>
33
- total +
34
- calculateObjectSize(item, {
35
- excludeAttributes,
36
- visited,
37
- }),
38
- estimateArrayOverhead(obj),
39
- );
40
- }
41
-
42
- // Handle TypedArrays
43
- if (ArrayBuffer.isView(obj)) {
44
- return obj.byteLength + estimateTypedArrayOverhead();
45
- }
46
-
47
- // Handle Maps
48
- if (obj instanceof Map) {
49
- let mapSize = estimateMapOverhead(obj);
50
- for (const [key, value] of obj) {
51
- mapSize += calculateObjectSize(key, { excludeAttributes, visited });
52
- mapSize += calculateObjectSize(value, { excludeAttributes, visited });
53
- }
54
- return mapSize;
55
- }
56
-
57
- // Handle regular objects
58
- if (typeof obj === "object") {
59
- let objectSize = estimateObjectOverhead();
60
- for (const key in obj) {
61
- // Skip excluded attributes
62
- if (
63
- Object.prototype.hasOwnProperty.call(obj, key) &&
64
- !excludeAttributes.includes(key)
65
- ) {
66
- objectSize += calculateObjectSize(key, { excludeAttributes, visited });
67
- objectSize += calculateObjectSize((obj as Record<string, unknown>)[key], {
68
- excludeAttributes,
69
- visited,
70
- });
71
- }
72
- }
73
- return objectSize;
74
- }
75
-
76
- // For functions or unknown types
77
- return 0;
78
- }
79
-
80
- function estimatePrimitiveSize(primitive: string | number | boolean | symbol | bigint | null | undefined): number {
81
- if (primitive === null || primitive === undefined) return 0;
82
- switch (typeof primitive) {
83
- case "number":
84
- return 8; // 64-bit float
85
- case "string":
86
- return primitive.length * 2; // Assume UTF-16 encoding
87
- case "boolean":
88
- return 4;
89
- case "symbol":
90
- return 8;
91
- case "bigint":
92
- return 8;
93
- default:
94
- return 0;
95
- }
96
- }
97
-
98
- function estimateArrayOverhead(arr: unknown[]): number {
99
- return 24 + arr.length * 8; // Array header + pointer overhead
100
- }
101
-
102
- function estimateTypedArrayOverhead(): number {
103
- return 24; // Typical overhead for TypedArrays
104
- }
105
-
106
- function estimateMapOverhead(map: Map<unknown, unknown>): number {
107
- return 40 + map.size * 16; // Map header + entry overhead
108
- }
109
-
110
- function estimateObjectOverhead(): number {
111
- return 32; // Basic object overhead
112
- }
113
-
114
- export function sizeof(obj: unknown): number {
115
- return calculateObjectSize(obj);
116
- }
@@ -1,69 +0,0 @@
1
- /**
2
- * Performance timing utility for measuring execution time.
3
- *
4
- * @example
5
- * ```typescript
6
- * const timer = new Timer("render", true);
7
- * // ... do some work ...
8
- * timer.split("tessellation complete");
9
- * // ... do more work ...
10
- * timer.stop();
11
- * ```
12
- *
13
- * @public
14
- */
15
- class Timer {
16
- private prefix: string;
17
- private timeit: boolean;
18
- private start: number;
19
- private last: number;
20
-
21
- /**
22
- * Create a new Timer instance.
23
- *
24
- * @param prefix - Label prefix for log messages
25
- * @param timeit - If false, all timing operations are no-ops
26
- */
27
- constructor(prefix: string, timeit: boolean) {
28
- this.prefix = prefix;
29
- this.timeit = timeit;
30
- this.start = performance.now();
31
- this.last = this.start;
32
- if (timeit) {
33
- console.info(`three-cad-viewer: ${prefix}:timer start`);
34
- }
35
- }
36
-
37
- /**
38
- * Log a split time (time since last split or start).
39
- *
40
- * @param msg - Message to include in the log output
41
- */
42
- split(msg: string): void {
43
- if (this.timeit) {
44
- const t = performance.now();
45
- console.info(
46
- `three-cad-viewer: ${this.prefix}:${msg}:timer split ${(
47
- t - this.last
48
- ).toFixed(1)} ms`,
49
- );
50
- this.last = t;
51
- }
52
- }
53
-
54
- /**
55
- * Log total elapsed time and stop the timer.
56
- */
57
- stop(): void {
58
- if (this.timeit) {
59
- const t = performance.now();
60
- console.info(
61
- `three-cad-viewer: ${this.prefix}:timer stop ${(t - this.start).toFixed(
62
- 1,
63
- )} ms:`,
64
- );
65
- }
66
- }
67
- }
68
-
69
- export { Timer };
@@ -1,446 +0,0 @@
1
- import * as THREE from "three";
2
- import type { Vector3Tuple, QuaternionTuple } from "three";
3
- import type { LineSegments2 } from "three/examples/jsm/lines/LineSegments2.js";
4
- import type { Axis } from "../core/types.js";
5
- import { gpuTracker } from "./gpu-tracker.js";
6
-
7
- // =============================================================================
8
- // Constants
9
- // =============================================================================
10
-
11
- /** Unit vectors for each axis */
12
- export const AXIS_VECTORS: Readonly<Record<Axis, THREE.Vector3>> = {
13
- x: new THREE.Vector3(1, 0, 0),
14
- y: new THREE.Vector3(0, 1, 0),
15
- z: new THREE.Vector3(0, 0, 1),
16
- };
17
-
18
- // =============================================================================
19
- // Utility Functions
20
- // =============================================================================
21
-
22
- /**
23
- * Flatten a nested array of numbers to a 1D array.
24
- * The cast is necessary because TypeScript's flat() return type
25
- * is a complex union that doesn't simplify to number[].
26
- */
27
- function flatten(arr: number[][] | number[][][] | number[][][][], depth: number = 1): number[] {
28
- return arr.flat(depth) as number[];
29
- }
30
-
31
- /**
32
- * Convert an array to Vector3Tuple with validation.
33
- * Throws if the input is not a 3-element array.
34
- */
35
- function toVector3Tuple(arr: number[]): Vector3Tuple {
36
- if (!Array.isArray(arr) || arr.length !== 3) {
37
- throw new Error(`Expected array of length 3, got ${Array.isArray(arr) ? arr.length : typeof arr}`);
38
- }
39
- return arr as Vector3Tuple;
40
- }
41
-
42
- /**
43
- * Convert an array to QuaternionTuple with validation.
44
- * Throws if the input is not a 4-element array.
45
- */
46
- function toQuaternionTuple(arr: number[]): QuaternionTuple {
47
- if (!Array.isArray(arr) || arr.length !== 4) {
48
- throw new Error(`Expected array of length 4, got ${Array.isArray(arr) ? arr.length : typeof arr}`);
49
- }
50
- return arr as QuaternionTuple;
51
- }
52
-
53
- function isEqual(obj1: unknown, obj2: unknown, tol: number = 1e-9): boolean {
54
- if (Array.isArray(obj1) && Array.isArray(obj2)) {
55
- return (
56
- obj1.length === obj2.length && obj1.every((v, i) => isEqual(v, obj2[i], tol))
57
- );
58
- } else if (obj1 !== null && obj2 !== null && typeof obj1 === "object" && typeof obj2 === "object") {
59
- const rec1 = obj1 as Record<string, unknown>;
60
- const rec2 = obj2 as Record<string, unknown>;
61
- const keys1 = Object.keys(rec1);
62
- const keys2 = Object.keys(rec2);
63
-
64
- if (
65
- keys1.length === keys2.length &&
66
- keys1.every((key) => Object.prototype.hasOwnProperty.call(rec2, key))
67
- ) {
68
- return keys1.every((key) => isEqual(rec1[key], rec2[key], tol));
69
- } else {
70
- return false;
71
- }
72
- } else {
73
- if (typeof obj1 === "number" && typeof obj2 === "number") {
74
- return Math.abs(obj1 - obj2) < tol;
75
- }
76
- return obj1 === obj2;
77
- }
78
- }
79
-
80
- function sceneTraverse(obj: THREE.Object3D | null | undefined, fn: (obj: THREE.Object3D) => void): void {
81
- if (!obj) return;
82
-
83
- fn(obj);
84
-
85
- if (obj.children && obj.children.length > 0) {
86
- obj.children.forEach((o) => {
87
- sceneTraverse(o, fn);
88
- });
89
- }
90
- }
91
-
92
- interface GeometryLike {
93
- dispose: () => void;
94
- attributes: Record<string, unknown>;
95
- }
96
-
97
- function disposeGeometry(geometry: GeometryLike | null | undefined): void {
98
- if (geometry) {
99
- gpuTracker.untrack("geometry", geometry);
100
- geometry.dispose();
101
- for (const attr of Object.values(geometry.attributes)) {
102
- if (attr && typeof attr === "object" && "dispose" in attr && typeof attr.dispose === "function") {
103
- attr.dispose();
104
- }
105
- }
106
- }
107
- }
108
-
109
- interface Disposable {
110
- dispose: () => void;
111
- }
112
-
113
- interface MaterialLike {
114
- dispose: () => void;
115
- // MeshStandardMaterial texture maps
116
- map?: Disposable | null;
117
- normalMap?: Disposable | null;
118
- roughnessMap?: Disposable | null;
119
- metalnessMap?: Disposable | null;
120
- aoMap?: Disposable | null;
121
- emissiveMap?: Disposable | null;
122
- alphaMap?: Disposable | null;
123
- bumpMap?: Disposable | null;
124
- // MeshPhysicalMaterial additional texture maps
125
- transmissionMap?: Disposable | null;
126
- clearcoatMap?: Disposable | null;
127
- clearcoatRoughnessMap?: Disposable | null;
128
- clearcoatNormalMap?: Disposable | null;
129
- thicknessMap?: Disposable | null;
130
- specularIntensityMap?: Disposable | null;
131
- specularColorMap?: Disposable | null;
132
- sheenColorMap?: Disposable | null;
133
- sheenRoughnessMap?: Disposable | null;
134
- anisotropyMap?: Disposable | null;
135
- }
136
-
137
- /** All texture map property names on MaterialLike (for iteration) */
138
- const MATERIAL_TEXTURE_KEYS: readonly (keyof Omit<MaterialLike, "dispose">)[] = [
139
- // MeshStandardMaterial
140
- "map", "normalMap", "roughnessMap", "metalnessMap",
141
- "aoMap", "emissiveMap", "alphaMap", "bumpMap",
142
- // MeshPhysicalMaterial
143
- "transmissionMap", "clearcoatMap", "clearcoatRoughnessMap", "clearcoatNormalMap",
144
- "thicknessMap", "specularIntensityMap", "specularColorMap",
145
- "sheenColorMap", "sheenRoughnessMap", "anisotropyMap",
146
- ];
147
-
148
- /**
149
- * Dispose a material and detach its texture references.
150
- *
151
- * Texture GPU resources are NOT freed here -- TextureCache is the sole owner
152
- * of loaded textures and is responsible for calling texture.dispose().
153
- * This function only nulls out the material's texture map references to
154
- * break the association, then disposes the material itself.
155
- */
156
- function disposeMaterial(material: MaterialLike | null | undefined): void {
157
- if (!material) return;
158
-
159
- // Detach all texture references (do NOT dispose -- TextureCache owns them)
160
- for (const key of MATERIAL_TEXTURE_KEYS) {
161
- if (material[key]) {
162
- (material as unknown as Record<string, unknown>)[key] = null;
163
- }
164
- }
165
-
166
- gpuTracker.untrack("material", material);
167
- material.dispose();
168
- }
169
-
170
- interface MeshLike {
171
- geometry?: GeometryLike | null;
172
- material?: MaterialLike | MaterialLike[] | null;
173
- isMesh?: boolean;
174
- isLine?: boolean;
175
- isPoints?: boolean;
176
- }
177
-
178
- function disposeMesh(mesh: MeshLike): void {
179
- if (mesh.geometry) {
180
- disposeGeometry(mesh.geometry);
181
- }
182
-
183
- if (mesh.material) {
184
- if (Array.isArray(mesh.material)) {
185
- mesh.material.forEach(disposeMaterial);
186
- } else {
187
- disposeMaterial(mesh.material);
188
- }
189
- }
190
- }
191
-
192
- interface DisposableTree extends MeshLike {
193
- children?: DisposableTree[];
194
- dispose?: () => void;
195
- }
196
-
197
- function deepDispose(tree: DisposableTree | DisposableTree[] | null | undefined): void {
198
- if (!tree) {
199
- return;
200
- }
201
- if (Array.isArray(tree)) {
202
- tree.forEach(deepDispose);
203
- return;
204
- }
205
- if (Array.isArray(tree.children)) {
206
- tree.children.forEach(deepDispose);
207
- }
208
- if (tree.dispose) {
209
- tree.dispose();
210
- } else if (tree.isMesh || tree.isLine || tree.isPoints) {
211
- disposeMesh(tree);
212
- }
213
- }
214
-
215
- function format(v: number, b: number = 2, a: number = 2): string {
216
- const s = Math.abs(v).toFixed(a);
217
- let padding = "";
218
- const int = s.split(".")[0];
219
- for (let i = int.length; i < b; i++) padding += " ";
220
- padding += v < 0 ? "-" : " ";
221
- return padding + s;
222
- }
223
-
224
- function prettyPrintVector(v: number[], a: number, b: number): string {
225
- return `${format(v[0], a, b)}, ${format(v[1], a, b)}, ${format(v[2], a, b)}`;
226
- }
227
-
228
- // KeyEventLike matches MouseEvent, PointerEvent, KeyboardEvent etc.
229
- type KeyEventLike = {
230
- ctrlKey: boolean;
231
- shiftKey: boolean;
232
- altKey: boolean;
233
- metaKey: boolean;
234
- };
235
-
236
- type KeyEventKey = keyof KeyEventLike;
237
- type MappedKey = "shift" | "ctrl" | "meta" | "alt";
238
-
239
- interface KeyMappingConfig {
240
- shift: KeyEventKey;
241
- ctrl: KeyEventKey;
242
- meta: KeyEventKey;
243
- alt: KeyEventKey;
244
- }
245
-
246
- class _KeyMapper {
247
- private keyMapping: Record<MappedKey, KeyEventKey>;
248
- private actionShortcuts: Record<string, string>;
249
- private reverseActionShortcuts: Record<string, string>;
250
-
251
- constructor() {
252
- this.keyMapping = {
253
- shift: "ctrlKey",
254
- ctrl: "shiftKey",
255
- meta: "altKey",
256
- alt: "metaKey",
257
- };
258
- this.actionShortcuts = {};
259
- this.reverseActionShortcuts = {};
260
- }
261
-
262
- getshortcuts = (key: MappedKey): string => {
263
- return this.keyMapping[key].replace("Key", "");
264
- };
265
-
266
- get_config(): Record<MappedKey, KeyEventKey> {
267
- return Object.assign({}, this.keyMapping);
268
- }
269
-
270
- get = (event: KeyEventLike, key: MappedKey): boolean => {
271
- const prop = this.keyMapping[key];
272
- return event[prop];
273
- };
274
-
275
- set = (config: Partial<KeyMappingConfig>): void => {
276
- for (const key of Object.keys(config) as MappedKey[]) {
277
- const value = config[key];
278
- if (value !== undefined) {
279
- this.keyMapping[key] = value;
280
- }
281
- }
282
- };
283
-
284
- setActionShortcuts = (shortcuts: Record<string, string>): void => {
285
- this.actionShortcuts = { ...shortcuts };
286
- this.reverseActionShortcuts = {};
287
- for (const [action, key] of Object.entries(shortcuts)) {
288
- this.reverseActionShortcuts[key] = action;
289
- }
290
- };
291
-
292
- getActionForKey = (key: string): string | undefined => {
293
- return this.reverseActionShortcuts[key];
294
- };
295
-
296
- getShortcutForAction = (action: string): string | undefined => {
297
- return this.actionShortcuts[action];
298
- };
299
-
300
- getActionShortcuts = (): Record<string, string> => {
301
- return { ...this.actionShortcuts };
302
- };
303
- }
304
-
305
- // see https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733
306
- function scaleLight(intensity: number): number {
307
- return Math.round(Math.PI * intensity);
308
- }
309
-
310
- // =============================================================================
311
- // THREE.js Type Guards
312
- // =============================================================================
313
-
314
- /**
315
- * Type guard to check if an Object3D is a Mesh.
316
- */
317
- function isMesh(obj: THREE.Object3D): obj is THREE.Mesh {
318
- return "isMesh" in obj && obj.isMesh === true;
319
- }
320
-
321
- /**
322
- * Type guard to check if an Object3D is a Line.
323
- */
324
- function isLine(obj: THREE.Object3D): obj is THREE.Line {
325
- return "isLine" in obj && obj.isLine === true;
326
- }
327
-
328
- /**
329
- * Type guard to check if an Object3D is a Points.
330
- */
331
- function isPoints(obj: THREE.Object3D): obj is THREE.Points {
332
- return "isPoints" in obj && obj.isPoints === true;
333
- }
334
-
335
- /**
336
- * Type guard to check if an object is an OrthographicCamera.
337
- * Accepts Object3D to allow use in controls where camera type is broader.
338
- */
339
- function isOrthographicCamera(obj: THREE.Object3D): obj is THREE.OrthographicCamera {
340
- return "isOrthographicCamera" in obj && (obj as THREE.OrthographicCamera).isOrthographicCamera === true;
341
- }
342
-
343
- /**
344
- * Type guard to check if an object is a PerspectiveCamera.
345
- * Accepts Object3D to allow use in controls where camera type is broader.
346
- */
347
- function isPerspectiveCamera(obj: THREE.Object3D): obj is THREE.PerspectiveCamera {
348
- return "isPerspectiveCamera" in obj && (obj as THREE.PerspectiveCamera).isPerspectiveCamera === true;
349
- }
350
-
351
- /**
352
- * Type guard to check if an Object3D is a LineSegments2 (fat line).
353
- */
354
- function isLineSegments2(obj: THREE.Object3D): obj is LineSegments2 {
355
- return obj.type === "LineSegments2";
356
- }
357
-
358
- /**
359
- * Type guard to check if a material has a color property.
360
- */
361
- function hasColor(material: THREE.Material): material is THREE.Material & { color: THREE.Color } {
362
- return "color" in material;
363
- }
364
-
365
- /**
366
- * Type guard to check if a material has emissive property.
367
- */
368
- function hasEmissive(material: THREE.Material): material is THREE.Material & { emissive: THREE.Color } {
369
- return "emissive" in material;
370
- }
371
-
372
- /**
373
- * Type guard to check if a material is a MeshStandardMaterial.
374
- */
375
- function isMeshStandardMaterial(material: THREE.Material): material is THREE.MeshStandardMaterial {
376
- return "isMeshStandardMaterial" in material && material.isMeshStandardMaterial === true;
377
- }
378
-
379
- const KeyMapper = new _KeyMapper();
380
-
381
- interface EventListenerEntry {
382
- target: EventTarget;
383
- event: string;
384
- handler: EventListenerOrEventListenerObject;
385
- options: boolean | AddEventListenerOptions;
386
- }
387
-
388
- class EventListenerManager {
389
- private listeners: EventListenerEntry[];
390
-
391
- constructor() {
392
- this.listeners = [];
393
- }
394
-
395
- add = (
396
- target: EventTarget,
397
- event: string,
398
- handler: EventListenerOrEventListenerObject,
399
- options: boolean | AddEventListenerOptions = false
400
- ): void => {
401
- target.addEventListener(event, handler, options);
402
- this.listeners.push({
403
- target: target,
404
- event: event,
405
- handler: handler,
406
- options: options,
407
- });
408
- };
409
-
410
- dispose(): void {
411
- this.listeners.forEach(({ target, event, handler, options }) => {
412
- target.removeEventListener(event, handler, options);
413
- });
414
- this.listeners = [];
415
- }
416
- }
417
-
418
- export {
419
- flatten,
420
- isEqual,
421
- sceneTraverse,
422
- prettyPrintVector,
423
- KeyMapper,
424
- scaleLight,
425
- deepDispose,
426
- disposeGeometry,
427
- EventListenerManager,
428
- // Type guards
429
- isMesh,
430
- isLine,
431
- isPoints,
432
- isOrthographicCamera,
433
- isPerspectiveCamera,
434
- isLineSegments2,
435
- hasColor,
436
- hasEmissive,
437
- isMeshStandardMaterial,
438
- toVector3Tuple,
439
- toQuaternionTuple,
440
- };
441
-
442
- export type {
443
- KeyEventKey,
444
- KeyMappingConfig,
445
- DisposableTree,
446
- };