@tresjs/core 5.9.3 → 5.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/tres.js CHANGED
@@ -1,2581 +1,9 @@
1
1
  /**
2
2
  * name: @tresjs/core
3
- * version: v5.9.3
3
+ * version: v5.10.1
4
4
  * (c) 2026
5
5
  * description: Declarative ThreeJS using Vue Components
6
6
  * author: Alvaro Saburido <hola@alvarosaburido.dev> (https://github.com/alvarosabu/)
7
7
  */
8
- import { Fragment, Teleport, computed, createBlock, createCommentVNode, createElementBlock, createRenderer, defineComponent, getCurrentInstance, h, isRef, mergeProps, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, onUnmounted, openBlock, provide, reactive, readonly, ref, renderSlot, shallowRef, toValue, triggerRef, unref, useSlots, watch, watchEffect, withCtx } from "vue";
9
- import * as THREE from "three";
10
- import { ACESFilmicToneMapping, ArrowHelper, BufferAttribute, Color, DirectionalLightHelper, DoubleSide, HemisphereLightHelper, Layers, Material, MathUtils, Mesh, MeshBasicMaterial, PCFShadowMap, PCFSoftShadowMap, PerspectiveCamera, PointLightHelper, REVISION, Scene, SpotLightHelper, Vector3, WebGLRenderer } from "three";
11
- import { createEventHook, createInjectionState, promiseTimeout, refDebounced, tryOnScopeDispose, unrefElement, useAsyncState, useDevicePixelRatio, useElementSize, useFps, useIntervalFn, useMemory, useRafFn, useTimeout, useWindowSize, whenever } from "@vueuse/core";
12
- import { camel, isEqual, isFunction, isNumber, isObject, isString, isUndefined } from "radashi";
13
- import { forwardHtmlEvents, getVoidObject } from "@pmndrs/pointer-events";
14
- import { setupDevtoolsPlugin } from "@vue/devtools-api";
15
- import { RectAreaLightHelper } from "three/examples/jsm/helpers/RectAreaLightHelper.js";
16
- //#region package.json
17
- var version = "5.9.3";
18
- //#endregion
19
- //#region src/utils/makeMap.ts
20
- /**
21
- * Make a map and return a function for checking if a key
22
- * is in that map.
23
- * IMPORTANT: all calls of this function must be prefixed with
24
- * \/\*#\_\_PURE\_\_\*\/
25
- * So that rollup can tree-shake them if necessary.
26
- */
27
- /*! #__NO_SIDE_EFFECTS__ */
28
- function makeMap(str) {
29
- const map = Object.create(null);
30
- for (const key of str.split(",")) map[key] = 1;
31
- return (val) => val in map;
32
- }
33
- const isHTMLTag = /* #__PURE__ */ makeMap("html,body,base,head,link,meta,style,title,address,article,aside,footer,header,hgroup,h1,h2,h3,h4,h5,h6,nav,section,div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,ruby,s,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,output,progress,select,textarea,details,dialog,menu,summary,template,blockquote,iframe,tfoot");
34
- //#endregion
35
- //#region src/utils/is/util.ts
36
- const createTypeGuard = (property) => (value) => isObject(value) && property in value && !!value[property];
37
- //#endregion
38
- //#region src/utils/is/three.ts
39
- /**
40
- * Type guard to check if a value is a Three.js Object3D
41
- * @param value - The value to check
42
- * @returns True if the value is a Three.js Object3D instance, false otherwise
43
- * @example
44
- * ```ts
45
- * const value = new THREE.Object3D()
46
- * if (isObject3D(value)) {
47
- * // TypeScript knows value is Object3D here
48
- * value.position // OK
49
- * value.rotation // OK
50
- * value.scale // OK
51
- * }
52
- * ```
53
- */
54
- const isObject3D = createTypeGuard("isObject3D");
55
- /**
56
- * Type guard to check if a value is a Three.js Mesh
57
- * @param value - The value to check
58
- * @returns True if the value is a Three.js Mesh instance, false otherwise
59
- * @example
60
- * ```ts
61
- * const value = new THREE.Mesh()
62
- * if (isMesh(value)) {
63
- * // TypeScript knows value is Mesh here
64
- * value.geometry // OK
65
- */
66
- const isMesh = createTypeGuard("isMesh");
67
- /**
68
- * Type guard to check if a value is a Three.js Camera
69
- * @param value - The value to check
70
- * @returns True if the value is a Three.js Camera instance, false otherwise
71
- * @example
72
- * ```ts
73
- * const value = new THREE.PerspectiveCamera()
74
- * if (isCamera(value)) {
75
- * // TypeScript knows value is Camera here
76
- * value.fov // OK
77
- * value.near // OK
78
- * value.far // OK
79
- * }
80
- * ```
81
- */
82
- const isCamera = createTypeGuard("isCamera");
83
- /**
84
- * Type guard to check if a value is a Three.js OrthographicCamera
85
- * @param value - The value to check
86
- * @returns True if the value is a Three.js OrthographicCamera instance, false otherwise
87
- */
88
- const isOrthographicCamera = createTypeGuard("isOrthographicCamera");
89
- /**
90
- * Type guard to check if a value is a Three.js PerspectiveCamera
91
- * @param value - The value to check
92
- * @returns True if the value is a Three.js PerspectiveCamera instance, false otherwise
93
- */
94
- const isPerspectiveCamera = createTypeGuard("isPerspectiveCamera");
95
- /**
96
- * Type guard to check if a value is a Three.js Color
97
- * @param value - The value to check
98
- * @returns True if the value is a Three.js Color instance, false otherwise
99
- */
100
- const isColor = createTypeGuard("isColor");
101
- /**
102
- * Type guard to check if a value is a Three.js ColorRepresentation
103
- * @param value - The value to check
104
- * @returns True if the value is a Three.js ColorRepresentation instance, false otherwise
105
- */
106
- const isColorRepresentation = (value) => isString(value) || isNumber(value) || isColor(value);
107
- /**
108
- * Type guard to check if a value is a Three.js Layers
109
- * @param value - The value to check
110
- * @returns True if the value is a Three.js Layers instance, false otherwise
111
- */
112
- const isLayers = (value) => value instanceof Layers;
113
- /**
114
- * Type guard to check if a value is a Three.js BufferGeometry
115
- * @param value - The value to check
116
- * @returns True if the value is a Three.js BufferGeometry instance, false otherwise
117
- * @example
118
- * ```ts
119
- * const value = new THREE.BufferGeometry()
120
- * if (isBufferGeometry(value)) {
121
- * // TypeScript knows value is BufferGeometry here
122
- * value.attributes // OK
123
- * value.index // OK
124
- * value.computeVertexNormals() // OK
125
- * }
126
- * ```
127
- */
128
- const isBufferGeometry = createTypeGuard("isBufferGeometry");
129
- /**
130
- * Type guard to check if a value is a Three.js Material
131
- * @param value - The value to check
132
- * @returns True if the value is a Three.js Material instance, false otherwise
133
- * @example
134
- * ```ts
135
- * const value = new THREE.MeshStandardMaterial()
136
- * if (isMaterial(value)) {
137
- * // TypeScript knows value is Material here
138
- * value.color // OK
139
- * value.metalness // OK
140
- * value.roughness // OK
141
- * }
142
- * ```
143
- */
144
- const isMaterial = createTypeGuard("isMaterial");
145
- /**
146
- * Type guard to check if a value is a Three.js Light
147
- * @param value - The value to check
148
- * @returns True if the value is a Three.js Light instance, false otherwise
149
- * @example
150
- * ```ts
151
- * const value = new THREE.DirectionalLight()
152
- * if (isLight(value)) {
153
- * // TypeScript knows value is Light here
154
- * value.intensity // OK
155
- * value.color // OK
156
- * value.position // OK
157
- * }
158
- * ```
159
- */
160
- const isLight = createTypeGuard("isLight");
161
- /**
162
- * Type guard to check if a value is a Three.js Fog
163
- * @param value - The value to check
164
- * @returns True if the value is a Three.js Fog instance, false otherwise
165
- * @example
166
- * ```ts
167
- * const value = new THREE.Fog(0x000000, 1, 1000)
168
- * if (isFog(value)) {
169
- * // TypeScript knows value is Fog here
170
- * value.color // OK
171
- * value.near // OK
172
- * value.far // OK
173
- * }
174
- * ```
175
- */
176
- const isFog = createTypeGuard("isFog");
177
- /**
178
- * Type guard to check if a value is a Three.js Scene
179
- * @param value - The value to check
180
- * @returns True if the value is a Three.js Scene instance, false otherwise
181
- * @example
182
- * ```ts
183
- * const value = new THREE.Scene()
184
- * if (isScene(value)) {
185
- * // TypeScript knows value is Scene here
186
- * value.children // OK
187
- * value.add(new THREE.Object3D()) // OK
188
- * value.remove(new THREE.Object3D()) // OK
189
- * }
190
- * ```
191
- */
192
- const isScene = createTypeGuard("isScene");
193
- /**
194
- * Type guard to check if a value is a Three.js Group
195
- * @param value - The value to check
196
- * @returns True if the value is a Three.js Group instance, false otherwise
197
- * ```
198
- */
199
- const isGroup = createTypeGuard("isGroup");
200
- //#endregion
201
- //#region src/utils/is/tres.ts
202
- const isVectorLike = (value) => value !== null && typeof value === "object" && "set" in value && typeof value.set === "function";
203
- const isCopyable = (value) => isVectorLike(value) && "copy" in value && typeof value.copy === "function";
204
- const isClassInstance = (object) => !!object?.constructor;
205
- /**
206
- * Type guard to check if a value is a TresCamera
207
- * @param value - The value to check
208
- * @returns True if the value is a TresCamera instance, false otherwise
209
- */
210
- const isTresCamera = (value) => isCamera(value) || isOrthographicCamera(value) || isPerspectiveCamera(value);
211
- /**
212
- * Type guard to check if a value is a TresObject
213
- * @param value - The value to check
214
- * @returns True if the value is a TresObject (Object3D | BufferGeometry | Material | Fog), false otherwise
215
- * @example
216
- * ```ts
217
- * const value = new THREE.Mesh()
218
- * if (isTresObject(value)) {
219
- * // TypeScript knows value is TresObject here
220
- * // You can use common properties and methods shared by all TresObjects
221
- * }
222
- * ```
223
- * @remarks
224
- * TresObject is a union type that represents the core Three.js objects that can be used in TresJS.
225
- * This includes Object3D, BufferGeometry, Material, and Fog instances.
226
- */
227
- const isTresObject = (value) => isObject3D(value) || isBufferGeometry(value) || isMaterial(value) || isFog(value);
228
- /**
229
- * Type guard to check if a value is a TresPrimitive
230
- * @param value - The value to check
231
- * @returns True if the value is a TresPrimitive instance, false otherwise
232
- * @example
233
- * ```ts
234
- * const value = { isPrimitive: true }
235
- * if (isTresPrimitive(value)) {
236
- * // TypeScript knows value is TresPrimitive here
237
- * // You can use properties and methods specific to TresPrimitives
238
- * }
239
- * ```
240
- * @remarks
241
- * TresPrimitive is a special type in TresJS that represents primitive objects
242
- * that can be used directly in the scene without needing to be wrapped in a Three.js object.
243
- */
244
- const isTresPrimitive = createTypeGuard("isPrimitive");
245
- /**
246
- * Type guard to check if a value is a TresInstance (has __tres property)
247
- * @param value - The value to check
248
- * @returns True if the value is a TresInstance (has __tres property), false otherwise
249
- * @example
250
- * ```ts
251
- * const value = new THREE.Mesh()
252
- * if (isTresInstance(value)) {
253
- * // TypeScript knows value is TresInstance here
254
- * // You can safely access value.__tres
255
- * }
256
- * ```
257
- */
258
- const isTresInstance = (value) => isTresObject(value) && "__tres" in value;
259
- /**
260
- * Type guard to check if a value is a Three.js WebGPU `Renderer`.
261
- *
262
- * Identifies the renderer *instance*, not the active backend: a `WebGPURenderer`
263
- * can run on a WebGPU **or** a WebGL2 fallback backend, and this returns `true`
264
- * for both. That is the right granularity for branching on capabilities —
265
- * `NodeMaterial` works on either backend, while a GLSL `ShaderMaterial` works on
266
- * neither under the WebGPU renderer.
267
- * @param value - The value to check
268
- * @returns True if the value is a WebGPU `Renderer` instance, false otherwise
269
- * @example
270
- * ```ts
271
- * const { renderer } = useTresContext()
272
- * if (isWebGPURenderer(renderer.instance)) {
273
- * // TypeScript knows renderer.instance is a WebGPU Renderer here
274
- * }
275
- * ```
276
- */
277
- const isWebGPURenderer = createTypeGuard("isRenderer");
278
- /**
279
- * Type guard to check if a value is a Three.js `WebGLRenderer`.
280
- * @param value - The value to check
281
- * @returns True if the value is a `WebGLRenderer` instance, false otherwise
282
- * @see {@link isWebGPURenderer}
283
- */
284
- const isWebGLRenderer = createTypeGuard("isWebGLRenderer");
285
- //#endregion
286
- //#region src/utils/array.ts
287
- /**
288
- * Like Array.filter, but modifies the array in place.
289
- * @param array - Array to modify
290
- * @param callbackFn - A function called for each element of the array. It should return a truthy value to keep the element in the array.
291
- */
292
- const filterInPlace = (array, callbackFn) => {
293
- let i = 0;
294
- for (let ii = 0; ii < array.length; ii++) if (callbackFn(array[ii], ii)) {
295
- array[i] = array[ii];
296
- i++;
297
- }
298
- array.length = i;
299
- return array;
300
- };
301
- //#endregion
302
- //#region src/utils/logger.ts
303
- /**
304
- * Logger utility for TresJS
305
- * @module logger
306
- */
307
- function resolveRuntimeMode() {
308
- try {
309
- const modeFromImportMeta = import.meta.env?.MODE;
310
- if (modeFromImportMeta) return modeFromImportMeta;
311
- } catch {}
312
- return typeof process !== "undefined" && process.env && process.env.NODE_ENV ? process.env.NODE_ENV : "production";
313
- }
314
- const isProd = resolveRuntimeMode() === "production";
315
- const logPrefix = "[TresJS ▲ ■ ●] ";
316
- /**
317
- * Logs an error message with the TresJS prefix
318
- * @param args - Arguments to log
319
- */
320
- function logError(...args) {
321
- if (typeof args[0] === "string") args[0] = logPrefix + args[0];
322
- else args.unshift(logPrefix);
323
- console.error(...args);
324
- }
325
- /**
326
- * Logs a warning message with the TresJS prefix
327
- * @param args - Arguments to log
328
- */
329
- function logWarning(...args) {
330
- if (typeof args[0] === "string") args[0] = logPrefix + args[0];
331
- else args.unshift(logPrefix);
332
- console.warn(...args);
333
- }
334
- /**
335
- * Logs a message with the TresJS prefix (only in development mode)
336
- * @param name - Name of the message
337
- * @param value - Value to log
338
- */
339
- function logMessage(name, value) {
340
- if (!isProd) console.log(`${logPrefix} - ${name}:`, value);
341
- }
342
- //#endregion
343
- //#region src/utils/index.ts
344
- function disposeMaterial(material) {
345
- const hasMap = (material) => "map" in material && !!material.map;
346
- if (hasMap(material)) material.map.dispose();
347
- material.dispose();
348
- }
349
- function disposeObject3D(object) {
350
- if (object.parent) object.removeFromParent?.();
351
- delete object.__tres;
352
- [...object.children].forEach((child) => disposeObject3D(child));
353
- if (object instanceof Scene) {} else {
354
- const mesh = object;
355
- if (object) object.dispose?.();
356
- if (mesh.geometry) mesh.geometry.dispose();
357
- if (Array.isArray(mesh.material)) mesh.material.forEach((material) => disposeMaterial(material));
358
- else if (mesh.material) disposeMaterial(mesh.material);
359
- }
360
- }
361
- function resolve(obj, key) {
362
- let target = obj;
363
- if (key.includes("-")) {
364
- const entries = key.split("-");
365
- let currKey = entries.shift();
366
- while (target && entries.length) if (!(currKey in target)) currKey = joinAsCamelCase(currKey, entries.shift());
367
- else {
368
- target = target[currKey];
369
- currKey = entries.shift();
370
- }
371
- return {
372
- target,
373
- key: joinAsCamelCase(currKey, ...entries)
374
- };
375
- } else return {
376
- target,
377
- key
378
- };
379
- }
380
- function joinAsCamelCase(...strings) {
381
- return strings.map((s, i) => i === 0 ? s : s.charAt(0).toUpperCase() + s.slice(1)).join("");
382
- }
383
- function attach(parent, child, type) {
384
- const INDEX_REGEX = /-\d+$/;
385
- if (isString(type)) {
386
- if (INDEX_REGEX.test(type)) {
387
- const { target, key } = resolve(parent, type.replace(INDEX_REGEX, ""));
388
- if (!Array.isArray(target[key])) {
389
- const previousAttach = target[key];
390
- const augmentedArray = [];
391
- augmentedArray.__tresDetach = () => {
392
- if (augmentedArray.every((v) => isUndefined(v))) target[key] = previousAttach;
393
- };
394
- target[key] = augmentedArray;
395
- }
396
- }
397
- const { target, key } = resolve(parent, type);
398
- child.__tres.previousAttach = target[key];
399
- target[key] = unboxTresPrimitive(child);
400
- } else child.__tres.previousAttach = type(parent, child);
401
- }
402
- function detach(parent, child, type) {
403
- if (isString(type)) {
404
- const { target, key } = resolve(parent, type);
405
- const previous = child.__tres.previousAttach;
406
- if (previous === void 0) delete target[key];
407
- else target[key] = previous;
408
- if ("__tresDetach" in target) target.__tresDetach();
409
- } else child.__tres?.previousAttach?.(parent, child);
410
- delete child.__tres?.previousAttach;
411
- }
412
- function prepareTresInstance(obj, state, context) {
413
- const instance = obj;
414
- instance.__tres = {
415
- type: "unknown",
416
- root: context,
417
- memoizedProps: {},
418
- objects: [],
419
- parent: null,
420
- previousAttach: null,
421
- ...state
422
- };
423
- if (!instance.__tres.attach) {
424
- if (isMaterial(instance)) instance.__tres.attach = "material";
425
- else if (isBufferGeometry(instance)) instance.__tres.attach = "geometry";
426
- else if (isFog(instance)) instance.__tres.attach = "fog";
427
- }
428
- return instance;
429
- }
430
- function invalidateInstance(instance) {
431
- const ctx = instance?.__tres?.root;
432
- if (!ctx?.renderer) return;
433
- if (ctx.renderer.canBeInvalidated.value) ctx.renderer.invalidate();
434
- }
435
- function setPrimitiveObject(newObject, primitive, setTarget, nodeOpsFns, context) {
436
- const objectsToAttach = [...primitive.__tres.objects];
437
- const oldObject = unboxTresPrimitive(primitive);
438
- newObject = unboxTresPrimitive(newObject);
439
- if (oldObject === newObject) return true;
440
- const newInstance = prepareTresInstance(newObject, primitive.__tres ?? {}, context);
441
- const parent = primitive.parent ?? primitive.__tres.parent ?? null;
442
- const propsToPatch = { ...primitive.__tres.memoizedProps };
443
- delete propsToPatch.object;
444
- for (const obj of objectsToAttach) {
445
- doRemoveDetach(obj, context);
446
- doRemoveDeregister(obj, context);
447
- }
448
- oldObject.__tres.objects = [];
449
- nodeOpsFns.remove(primitive);
450
- for (const [key, value] of Object.entries(propsToPatch)) nodeOpsFns.patchProp(newInstance, key, newInstance[key], value);
451
- setTarget(newObject);
452
- nodeOpsFns.insert(primitive, parent);
453
- for (const obj of objectsToAttach) nodeOpsFns.insert(obj, primitive);
454
- return true;
455
- }
456
- function unboxTresPrimitive(maybePrimitive) {
457
- if (isTresPrimitive(maybePrimitive)) {
458
- const primitive = maybePrimitive;
459
- primitive.object.__tres = primitive.__tres;
460
- return primitive.object;
461
- } else return maybePrimitive;
462
- }
463
- function doRemoveDetach(node, context) {
464
- const parent = node.__tres?.parent || context.scene.value;
465
- if (node.__tres) node.__tres.parent = null;
466
- if (parent && parent.__tres && "objects" in parent.__tres) filterInPlace(parent.__tres.objects, (obj) => obj !== node);
467
- if (node.__tres?.attach) detach(parent, node, node.__tres.attach);
468
- else {
469
- node.parent?.remove?.(unboxTresPrimitive(node));
470
- node.parent = null;
471
- }
472
- }
473
- function doRemoveDeregister(node, context) {
474
- node.traverse?.((child) => {
475
- if (isTresCamera(child)) context.camera.deregisterCamera(child);
476
- });
477
- if (isTresCamera(node)) context.camera.deregisterCamera(node);
478
- invalidateInstance(node);
479
- }
480
- //#endregion
481
- //#region src/composables/useLoader/index.ts
482
- /**
483
- * Vue composable for loading 3D models using Three.js loaders
484
- * @param Loader - The Three.js loader constructor
485
- * @param path - The path to the model file
486
- * @param options - Optional configuration for the loader
487
- * @returns UseAsyncState composable with the loaded model
488
- */
489
- function useLoader(Loader, path, options) {
490
- const proto = new Loader(options?.manager);
491
- const progress = reactive({
492
- loaded: 0,
493
- total: 0,
494
- percentage: 0
495
- });
496
- if (options?.extensions) options.extensions(proto);
497
- const initialPath = toValue(path);
498
- const result = useAsyncState((path) => new Promise((resolve, reject) => {
499
- const assetPath = path || initialPath || "";
500
- proto.load(assetPath, (result) => {
501
- resolve(result);
502
- }, (event) => {
503
- progress.loaded = event.loaded;
504
- progress.total = event.total;
505
- progress.percentage = progress.loaded / progress.total * 100;
506
- }, (err) => {
507
- reject(err);
508
- });
509
- }), options?.initialValue ?? null, {
510
- ...options?.asyncOptions,
511
- immediate: options?.asyncOptions?.immediate ?? true
512
- });
513
- const unsub = watch(() => toValue(path), (newPath) => {
514
- if (newPath) {
515
- const value = result.state.value;
516
- if (value && typeof value === "object" && "scene" in value && value.scene) disposeObject3D(value.scene);
517
- result.execute(0, newPath);
518
- }
519
- });
520
- onUnmounted(() => {
521
- unsub();
522
- const value = result.state.value;
523
- if (value && typeof value === "object" && "scene" in value && value.scene) disposeObject3D(value.scene);
524
- });
525
- return {
526
- ...result,
527
- load: (path) => {
528
- result.execute(0, path);
529
- },
530
- progress
531
- };
532
- }
533
- //#endregion
534
- //#region src/composables/useLoader/component.vue
535
- var component_default = /* @__PURE__ */ defineComponent({
536
- __name: "component",
537
- props: {
538
- loader: {
539
- type: null,
540
- required: true
541
- },
542
- path: {
543
- type: String,
544
- required: true
545
- },
546
- manager: {
547
- type: Object,
548
- required: false
549
- },
550
- extensions: {
551
- type: Function,
552
- required: false
553
- }
554
- },
555
- emits: ["loaded", "error"],
556
- setup(__props, { emit: __emit }) {
557
- const props = __props;
558
- const emit = __emit;
559
- const { state, isLoading, error } = useLoader(props.loader, props.path, {
560
- manager: props.manager,
561
- extensions: props.extensions
562
- });
563
- whenever(error, (err) => {
564
- if (err) emit("error", err);
565
- });
566
- whenever(state, (value) => {
567
- if (value) emit("loaded", value);
568
- });
569
- return (_ctx, _cache) => {
570
- return renderSlot(_ctx.$slots, "default", {
571
- state: unref(state),
572
- isLoading: unref(isLoading),
573
- error: unref(error)
574
- });
575
- };
576
- }
577
- });
578
- //#endregion
579
- //#region src/composables/useCamera/index.ts
580
- /**
581
- * Composable for managing cameras in a Three.js scene
582
- * @param params - The parameters for the composable
583
- * @param params.sizes - The sizes object containing window dimensions
584
- * @returns The camera management functions and state
585
- */
586
- const useCameraManager = ({ sizes }) => {
587
- const cameras = shallowRef([]);
588
- const activeCamera = computed(() => cameras.value[0]);
589
- /**
590
- * Set the active camera
591
- * @param cameraOrUuid - The camera or its UUID to set as active
592
- */
593
- const setActiveCamera = (cameraOrUuid) => {
594
- const camera = isCamera(cameraOrUuid) ? cameraOrUuid : cameras.value.find((camera) => camera.uuid === cameraOrUuid);
595
- if (!camera) return;
596
- const otherCameras = cameras.value.filter(({ uuid }) => uuid !== camera.uuid);
597
- cameras.value = [camera, ...otherCameras];
598
- };
599
- /**
600
- * Register a camera
601
- * @param camera - The camera to register
602
- * @param active - Whether to set the camera as active
603
- */
604
- const registerCamera = (camera, active = false) => {
605
- if (cameras.value.some(({ uuid }) => uuid === camera.uuid)) return;
606
- cameras.value.push(camera);
607
- triggerRef(cameras);
608
- if (active) setActiveCamera(camera.uuid);
609
- };
610
- /**
611
- * Deregister a camera
612
- * @param camera - The camera to deregister
613
- */
614
- const deregisterCamera = (camera) => {
615
- cameras.value = cameras.value.filter(({ uuid }) => uuid !== camera.uuid);
616
- };
617
- /**
618
- * Update camera aspect ratios when the window size changes
619
- */
620
- watchEffect(() => {
621
- if (sizes.aspectRatio.value) cameras.value.forEach((camera) => {
622
- if (isPerspectiveCamera(camera)) {
623
- camera.aspect = sizes.aspectRatio.value;
624
- camera.updateProjectionMatrix();
625
- }
626
- });
627
- });
628
- return {
629
- activeCamera,
630
- cameras,
631
- registerCamera,
632
- deregisterCamera,
633
- setActiveCamera
634
- };
635
- };
636
- //#endregion
637
- //#region src/utils/graph.ts
638
- function buildGraph(object) {
639
- const data = {
640
- nodes: {},
641
- materials: {},
642
- meshes: {}
643
- };
644
- if (object) object.traverse((obj) => {
645
- if (obj.name) data.nodes[obj.name] = obj;
646
- if (isMesh(obj)) {
647
- if (!data.meshes[obj.name]) data.meshes[obj.name] = obj;
648
- (Array.isArray(obj.material) ? obj.material : [obj.material]).forEach((material) => {
649
- if (material.name && !data.materials[material.name]) data.materials[material.name] = material;
650
- });
651
- }
652
- });
653
- return data;
654
- }
655
- //#endregion
656
- //#region src/composables/useGraph/index.ts
657
- const useGraph = (object) => {
658
- return computed(() => {
659
- const obj = toValue(object);
660
- if (!obj) return;
661
- return buildGraph(obj);
662
- });
663
- };
664
- //#endregion
665
- //#region src/utils/createPriorityEventHook.ts
666
- function createPriorityEventHook() {
667
- const eventToPriority = /* @__PURE__ */ new Map();
668
- const ascending = /* @__PURE__ */ new Set();
669
- let ADD_COUNT = 0;
670
- let dirty = false;
671
- const sort = () => {
672
- const sorted = Array.from(eventToPriority.entries()).sort((a, b) => {
673
- const priorityDiff = a[1].priority - b[1].priority;
674
- return priorityDiff === 0 ? a[1].addI - b[1].addI : priorityDiff;
675
- });
676
- ascending.clear();
677
- sorted.forEach((entry) => ascending.add(entry[0]));
678
- };
679
- const off = (fn) => {
680
- eventToPriority.delete(fn);
681
- ascending.delete(fn);
682
- };
683
- const on = (fn, priority = 0) => {
684
- eventToPriority.set(fn, {
685
- priority,
686
- addI: ADD_COUNT++
687
- });
688
- const offFn = () => off(fn);
689
- tryOnScopeDispose(offFn);
690
- dirty = true;
691
- return { off: offFn };
692
- };
693
- const trigger = (...args) => {
694
- if (dirty) {
695
- sort();
696
- dirty = false;
697
- }
698
- return Promise.all(Array.from(ascending).map((fn) => fn(...args)));
699
- };
700
- const dispose = () => {
701
- eventToPriority.clear();
702
- ascending.clear();
703
- };
704
- return {
705
- on,
706
- off,
707
- trigger,
708
- dispose,
709
- get count() {
710
- return eventToPriority.size;
711
- }
712
- };
713
- }
714
- //#endregion
715
- //#region src/core/catalogue.ts
716
- const catalogue = ref({});
717
- const extend = (objects) => Object.assign(catalogue.value, objects);
718
- //#endregion
719
- //#region src/composables/useRenderer/pixelRatio.ts
720
- const setPixelRatio = (renderer, systemDpr, userDpr) => {
721
- if (!isFunction(renderer.setPixelRatio)) return;
722
- let newDpr = 0;
723
- if (userDpr && Array.isArray(userDpr) && userDpr.length >= 2) {
724
- const [min, max] = userDpr;
725
- newDpr = MathUtils.clamp(systemDpr, min, max);
726
- } else if (isNumber(userDpr)) newDpr = userDpr;
727
- else newDpr = systemDpr;
728
- if (newDpr !== renderer.getPixelRatio?.()) renderer.setPixelRatio(newDpr);
729
- };
730
- //#endregion
731
- //#region src/core/revision.ts
732
- const revision = Number.parseInt(REVISION.replace("dev", ""));
733
- //#endregion
734
- //#region src/utils/createTimer.ts
735
- /**
736
- * Minimum Three.js revision that ships the `Timer` class.
737
- */
738
- const TIMER_MIN_REVISION = 179;
739
- /**
740
- * Creates a unified timer abstraction that uses `Timer` on Three.js r179+
741
- * and falls back to `Clock` on older versions.
742
- *
743
- * - On r179+: uses `Timer` with its Page Visibility API support (`connect`/`disconnect`).
744
- * - On older versions: uses `Clock` with `start`/`stop`.
745
- *
746
- */
747
- function createTimer() {
748
- if (revision >= TIMER_MIN_REVISION) {
749
- const timer = new THREE.Timer();
750
- return {
751
- getDelta: () => timer.getDelta(),
752
- getElapsed: () => timer.getElapsed(),
753
- update: () => timer.update(),
754
- start: () => {
755
- if (typeof document !== "undefined") timer.connect(document);
756
- },
757
- stop: () => timer.disconnect()
758
- };
759
- } else {
760
- const clock = new THREE.Clock();
761
- return {
762
- getDelta: () => clock.getDelta(),
763
- getElapsed: () => clock.elapsedTime,
764
- update: () => {},
765
- start: () => clock.start(),
766
- stop: () => clock.stop()
767
- };
768
- }
769
- }
770
- //#endregion
771
- //#region src/composables/useCreateRafLoop/index.ts
772
- /**
773
- * @param cycleFn the function that is called before the after event hook is triggered and after the before event hook is triggered.
774
- */
775
- const useCreateRafLoop = (cycleFn, { fpsLimit } = {}) => {
776
- const timer = createTimer();
777
- const eventHooks = {
778
- before: createEventHook(),
779
- after: createEventHook()
780
- };
781
- const { pause, resume, isActive } = useRafFn(() => {
782
- timer.update();
783
- const context = {
784
- delta: timer.getDelta(),
785
- elapsed: timer.getElapsed()
786
- };
787
- eventHooks.before.trigger(context);
788
- cycleFn();
789
- eventHooks.after.trigger(context);
790
- }, {
791
- immediate: false,
792
- fpsLimit
793
- });
794
- const start = () => {
795
- timer.start();
796
- resume();
797
- };
798
- const stop = () => {
799
- timer.stop();
800
- pause();
801
- };
802
- return {
803
- start,
804
- stop,
805
- isActive,
806
- onBeforeLoop: eventHooks.before.on,
807
- onLoop: eventHooks.after.on
808
- };
809
- };
810
- //#endregion
811
- //#region src/utils/error.ts
812
- var TresRendererError = class extends Error {
813
- code;
814
- name = "TresRendererError";
815
- constructor(message, code, options) {
816
- super(message, options);
817
- this.code = code;
818
- }
819
- };
820
- //#endregion
821
- //#region src/composables/useRenderer/useRendererManager.ts
822
- /**
823
- * Three.js revision where `WebGPURenderer` removed `PCFSoftShadowMap`.
824
- */
825
- const WEBGPU_PCF_SOFT_REMOVED_REVISION = 186;
826
- function useRendererManager({ scene, canvas, options, fpsLimit, contextParts: { sizes, camera } }) {
827
- const getRenderer = () => {
828
- if (isFunction(options.renderer)) return options.renderer({
829
- sizes,
830
- scene,
831
- camera,
832
- canvas
833
- });
834
- return new WebGLRenderer({
835
- ...options,
836
- canvas: unrefElement(canvas)
837
- });
838
- };
839
- const renderer = getRenderer();
840
- const frames = ref(toValue(options.renderMode) === "manual" ? 0 : 1);
841
- const maxFrames = 60;
842
- const canBeInvalidated = computed(() => toValue(options.renderMode) === "on-demand" && frames.value === 0);
843
- const forceMaterialUpdate = () => scene.value.traverse((child) => {
844
- if (child instanceof Mesh && child.material instanceof Material) child.material.needsUpdate = true;
845
- });
846
- /**
847
- * Invalidates the current frame when in on-demand render mode.
848
- */
849
- const invalidate = (amountOfFramesToInvalidate = 1) => {
850
- if (!canBeInvalidated.value) return;
851
- frames.value = Math.min(maxFrames, frames.value + amountOfFramesToInvalidate);
852
- };
853
- /**
854
- * Advances one frame when in manual render mode.
855
- */
856
- const advance = () => {
857
- if (toValue(options.renderMode) !== "manual") throw new Error("advance can only be called in manual render mode.");
858
- frames.value = 1;
859
- };
860
- const invalidateOnDemand = () => {
861
- if (toValue(options.renderMode) === "on-demand") invalidate();
862
- };
863
- const isModeAlways = computed(() => toValue(options.renderMode) === "always");
864
- const readyEventHook = createEventHook();
865
- const errorEventHook = createEventHook();
866
- let hasTriggeredReady = false;
867
- const isInitialized = ref(false);
868
- const error = ref(null);
869
- const initializeRenderer = async () => {
870
- try {
871
- if (isWebGPURenderer(renderer)) await renderer.init();
872
- isInitialized.value = true;
873
- } catch (e) {
874
- const rendererError = new TresRendererError(e instanceof Error ? e.message : "Unknown error", "INITIALIZATION_FAILED", { cause: e instanceof Error ? e : void 0 });
875
- error.value = rendererError;
876
- console.error(`[TresJS] Renderer initialization failed. This may occur if:
877
- - WebGPU is not supported by your browser
878
- - GPU is not available or lacks required features
879
- - GPU drivers are outdated
880
- Error details: ${rendererError.message}`, rendererError);
881
- errorEventHook.trigger(rendererError);
882
- }
883
- };
884
- const renderEventHook = createEventHook();
885
- const notifyFrameRendered = () => {
886
- frames.value = isModeAlways.value ? 1 : Math.max(0, frames.value - 1);
887
- renderEventHook.trigger(renderer);
888
- };
889
- let renderFunction = (_notifyFrameRendered) => {
890
- if (camera.activeCamera.value) {
891
- renderer.render(scene.value, camera.activeCamera.value);
892
- _notifyFrameRendered();
893
- }
894
- };
895
- const replaceRenderFunction = (fn) => {
896
- renderFunction = fn;
897
- };
898
- const loop = useCreateRafLoop(() => {
899
- if (frames.value) renderFunction(notifyFrameRendered);
900
- }, { fpsLimit });
901
- readyEventHook.on(() => {
902
- if (isInitialized.value) loop.start();
903
- });
904
- watch([
905
- sizes.width,
906
- sizes.height,
907
- isInitialized
908
- ], () => {
909
- if (!isInitialized.value) return;
910
- renderer.setSize(sizes.width.value, sizes.height.value);
911
- if (!hasTriggeredReady && renderer.domElement.width && renderer.domElement.height) {
912
- hasTriggeredReady = true;
913
- nextTick(() => {
914
- readyEventHook.trigger(renderer);
915
- });
916
- }
917
- invalidateOnDemand();
918
- }, { immediate: true });
919
- watchEffect(() => {
920
- if (!isInitialized.value) return;
921
- setPixelRatio(renderer, sizes.pixelRatio.value, toValue(options.dpr));
922
- });
923
- initializeRenderer();
924
- if (toValue(options.renderMode) === "on-demand") invalidate();
925
- if (toValue(options.renderMode) === "manual") useTimeout(100, { callback: advance });
926
- const clearColorAndAlpha = computed(() => {
927
- const clearColor = toValue(options.clearColor);
928
- const clearAlpha = toValue(options.clearAlpha);
929
- const isClearColorWithAlpha = typeof clearColor === "string" && clearColor.length === 9 && clearColor.startsWith("#");
930
- if (isClearColorWithAlpha && clearAlpha !== void 0) logWarning(`clearColor with alpha (e.g. ${clearColor}) and clearAlpha cannot both be set, using clearColor as source of truth`);
931
- if (isClearColorWithAlpha) return {
932
- alpha: Number.parseInt(clearColor.slice(7, 9), 16) / 255,
933
- color: clearColor.slice(0, 7)
934
- };
935
- return {
936
- alpha: clearAlpha,
937
- color: clearColor
938
- };
939
- });
940
- watchEffect(() => {
941
- if (!isInitialized.value) return;
942
- const value = clearColorAndAlpha.value;
943
- if (value.color === void 0 || value.alpha === void 0) return;
944
- renderer.setClearColor(value.color, value.alpha);
945
- });
946
- watchEffect(() => {
947
- if (!isInitialized.value) return;
948
- const value = options.toneMapping;
949
- if (value) renderer.toneMapping = value;
950
- });
951
- watchEffect(() => {
952
- if (!isInitialized.value) return;
953
- const value = options.toneMappingExposure;
954
- if (value) renderer.toneMappingExposure = value;
955
- });
956
- watchEffect(() => {
957
- if (!isInitialized.value) return;
958
- const value = options.outputColorSpace;
959
- if (value) renderer.outputColorSpace = value;
960
- });
961
- watchEffect(() => {
962
- if (!isInitialized.value) return;
963
- const value = options.shadows;
964
- if (value === void 0) return;
965
- renderer.shadowMap.enabled = value;
966
- forceMaterialUpdate();
967
- });
968
- watchEffect(() => {
969
- if (!isInitialized.value) return;
970
- const fallback = isWebGPURenderer(renderer) && revision < WEBGPU_PCF_SOFT_REMOVED_REVISION ? PCFSoftShadowMap : PCFShadowMap;
971
- renderer.shadowMap.type = options.shadowMapType ?? fallback;
972
- forceMaterialUpdate();
973
- });
974
- onUnmounted(() => {
975
- renderer.dispose();
976
- if ("forceContextLoss" in renderer) renderer.forceContextLoss();
977
- });
978
- return {
979
- loop,
980
- instance: renderer,
981
- advance,
982
- onReady: readyEventHook.on,
983
- onRender: renderEventHook.on,
984
- onError: errorEventHook.on,
985
- invalidate,
986
- canBeInvalidated,
987
- mode: toValue(options.renderMode),
988
- replaceRenderFunction,
989
- isInitialized,
990
- error
991
- };
992
- }
993
- //#endregion
994
- //#region src/composables/useSizes/index.ts
995
- function useSizes(windowSize, canvas, debounceMs = 10) {
996
- const { pixelRatio } = useDevicePixelRatio();
997
- const reactiveSize = toValue(windowSize) ? useWindowSize() : useElementSize(computed(() => toValue(canvas).parentElement));
998
- const debouncedReactiveWidth = readonly(refDebounced(reactiveSize.width, debounceMs));
999
- const debouncedReactiveHeight = readonly(refDebounced(reactiveSize.height, debounceMs));
1000
- return {
1001
- width: debouncedReactiveWidth,
1002
- height: debouncedReactiveHeight,
1003
- pixelRatio,
1004
- aspectRatio: computed(() => debouncedReactiveWidth.value / debouncedReactiveHeight.value)
1005
- };
1006
- }
1007
- //#endregion
1008
- //#region src/composables/useEventManager/index.ts
1009
- function useEventManager({ canvas, contextParts: { scene, camera, renderer } }) {
1010
- const { update, destroy } = forwardHtmlEvents(toValue(canvas), () => toValue(camera.activeCamera), scene.value);
1011
- const { off } = renderer.loop.onLoop(update);
1012
- onUnmounted(destroy);
1013
- onUnmounted(off);
1014
- const voidObject = getVoidObject(scene.value);
1015
- const pointerMissedEventHook = createEventHook();
1016
- voidObject.addEventListener("click", pointerMissedEventHook.trigger);
1017
- return { onPointerMissed: pointerMissedEventHook.on };
1018
- }
1019
- //#endregion
1020
- //#region src/composables/useTresContextProvider/index.ts
1021
- const INJECTION_KEY = "useTres";
1022
- const [useTresContextProvider, _useTresContext] = createInjectionState(({ scene, canvas, fpsLimit, windowSize, rendererOptions }) => {
1023
- const localScene = shallowRef(scene);
1024
- const sizes = useSizes(windowSize, canvas);
1025
- const camera = useCameraManager({ sizes });
1026
- const renderer = useRendererManager({
1027
- scene: localScene,
1028
- canvas,
1029
- options: rendererOptions,
1030
- fpsLimit,
1031
- contextParts: {
1032
- sizes,
1033
- camera
1034
- }
1035
- });
1036
- const events = useEventManager({
1037
- canvas,
1038
- contextParts: {
1039
- scene: localScene,
1040
- camera,
1041
- renderer
1042
- }
1043
- });
1044
- const ctx = {
1045
- sizes,
1046
- scene: localScene,
1047
- camera,
1048
- renderer,
1049
- isWebGPU: computed(() => isWebGPURenderer(renderer.instance)),
1050
- controls: ref(null),
1051
- extend,
1052
- events
1053
- };
1054
- ctx.scene.value.__tres = {
1055
- root: ctx,
1056
- objects: [],
1057
- isUnmounting: false
1058
- };
1059
- return ctx;
1060
- }, { injectionKey: "useTres" });
1061
- const useTresContext = () => {
1062
- const ctx = _useTresContext();
1063
- if (!ctx) throw new Error("useTresContext must be used together with useTresContextProvider.\n You probably tried to use it above or on the same level as a TresCanvas component.\n It should be used in child components of a TresCanvas instance.");
1064
- return ctx;
1065
- };
1066
- //#endregion
1067
- //#region src/composables/useTres/index.ts
1068
- function useTres() {
1069
- const { scene, renderer, camera, sizes, controls, extend, events, isWebGPU } = useTresContext();
1070
- return {
1071
- scene,
1072
- renderer: renderer.instance,
1073
- camera: camera.activeCamera,
1074
- sizes,
1075
- controls,
1076
- extend,
1077
- events,
1078
- isWebGPU,
1079
- invalidate: renderer.invalidate,
1080
- advance: renderer.advance
1081
- };
1082
- }
1083
- //#endregion
1084
- //#region src/composables/useLoop/index.ts
1085
- /**
1086
- * Composable that provides control over the render loop and animation lifecycle.
1087
- */
1088
- const useLoop = () => {
1089
- const tresContext = useTres();
1090
- const { renderer: rendererManager } = useTresContext();
1091
- const eventHookBeforeRender = createPriorityEventHook();
1092
- const eventHookAfterRender = createPriorityEventHook();
1093
- rendererManager.loop.onBeforeLoop((loopContext) => {
1094
- eventHookBeforeRender.trigger({
1095
- ...tresContext,
1096
- ...loopContext
1097
- });
1098
- });
1099
- rendererManager.loop.onLoop((loopContext) => {
1100
- eventHookAfterRender.trigger({
1101
- ...tresContext,
1102
- ...loopContext
1103
- });
1104
- });
1105
- const render = rendererManager.replaceRenderFunction;
1106
- return {
1107
- stop: rendererManager.loop.stop,
1108
- start: rendererManager.loop.start,
1109
- isActive: rendererManager.loop.isActive,
1110
- onBeforeRender: eventHookBeforeRender.on,
1111
- onRender: eventHookAfterRender.on,
1112
- render
1113
- };
1114
- };
1115
- //#endregion
1116
- //#region src/utils/primitive/createRetargetingProxy.ts
1117
- function createRetargetingProxy(target, getters = {}, setters = {}) {
1118
- let _target = target;
1119
- const setTarget = (newTarget) => {
1120
- _target = newTarget;
1121
- };
1122
- let proxy = new Proxy({}, {});
1123
- proxy = new Proxy({}, {
1124
- has(_, key) {
1125
- return key in getters || key in _target;
1126
- },
1127
- get(_, prop, __) {
1128
- if (prop in getters) return getters[prop](_target);
1129
- return _target[prop];
1130
- },
1131
- set(_, prop, val) {
1132
- if (setters[prop]) setters[prop](val, _target, proxy, setTarget);
1133
- else _target[prop] = val;
1134
- return true;
1135
- }
1136
- });
1137
- return proxy;
1138
- }
1139
- //#endregion
1140
- //#region src/utils/pointerEvents.ts
1141
- const supportedPointerEvents = [
1142
- "onClick",
1143
- "onContextmenu",
1144
- "onPointermove",
1145
- "onPointerenter",
1146
- "onPointerleave",
1147
- "onPointerover",
1148
- "onPointerout",
1149
- "onDblclick",
1150
- "onPointerdown",
1151
- "onPointerup",
1152
- "onPointercancel",
1153
- "onLostpointercapture",
1154
- "onWheel"
1155
- ];
1156
- const pointerEventsMapVueToThree = {
1157
- onClick: "click",
1158
- onContextmenu: "contextmenu",
1159
- onPointermove: "pointermove",
1160
- onPointerenter: "pointerenter",
1161
- onPointerleave: "pointerleave",
1162
- onPointerover: "pointerover",
1163
- onPointerout: "pointerout",
1164
- onDblclick: "dblclick",
1165
- onPointerdown: "pointerdown",
1166
- onPointerup: "pointerup",
1167
- onPointercancel: "pointercancel",
1168
- onLostpointercapture: "lostpointercapture",
1169
- onWheel: "wheel"
1170
- };
1171
- const isSupportedPointerEvent = (event) => supportedPointerEvents.includes(event);
1172
- //#endregion
1173
- //#region src/core/nodeOps.ts
1174
- const textNodeSymbol = Symbol("tresTextNode");
1175
- const commentNodeSymbol = Symbol("tresComment");
1176
- const nodeOps = ({ context, options = { primitivePrefix: "" } }) => {
1177
- const scene = context.scene.value;
1178
- const createTextNode = () => {
1179
- if (scene?.__tres?.isUnmounting) return;
1180
- return {
1181
- [textNodeSymbol]: true,
1182
- __tres: { parent: null }
1183
- };
1184
- };
1185
- const createCommentNode = () => ({
1186
- [commentNodeSymbol]: true,
1187
- __tres: { parent: null }
1188
- });
1189
- const isTextNode = (node) => !!node && typeof node === "object" && textNodeSymbol in node;
1190
- const isCommentNode = (node) => !!node && typeof node === "object" && commentNodeSymbol in node;
1191
- function createElement(tag, _namespace, _isCustomizedBuiltIn, props) {
1192
- if (!props) props = {};
1193
- if (!props.args) props.args = [];
1194
- if (isHTMLTag(tag)) return null;
1195
- if (tag.includes("-")) tag = tag.replace(/-([a-z])/g, (_, c) => c.toUpperCase()).replace(/^[a-z]/, (c) => c.toUpperCase());
1196
- let name = tag.replace("Tres", "");
1197
- let obj;
1198
- if (tag === `${options?.primitivePrefix ?? ""}primitive`) {
1199
- if (!isObject(props.object) || isRef(props.object)) logError("Tres primitives need an 'object' prop, whose value is an object or shallowRef<object>");
1200
- name = props.object.type;
1201
- const __tres = {};
1202
- obj = createRetargetingProxy(props.object, {
1203
- object: (t) => t,
1204
- isPrimitive: () => true,
1205
- __tres: () => __tres
1206
- }, {
1207
- object: (object, _, primitive, setTarget) => {
1208
- setPrimitiveObject(object, primitive, setTarget, {
1209
- patchProp,
1210
- remove,
1211
- insert
1212
- }, context);
1213
- },
1214
- __tres: (t) => {
1215
- Object.assign(__tres, t);
1216
- }
1217
- });
1218
- } else {
1219
- const target = catalogue.value[name];
1220
- if (!target) logError(`${name} is not defined on the THREE namespace. Use extend to add it to the catalog.`);
1221
- obj = new target(...props.args);
1222
- }
1223
- if (!obj) return null;
1224
- if (isTresCamera(obj)) {
1225
- if (!props?.position) obj.position.set(3, 3, 3);
1226
- if (!props?.lookAt) obj.lookAt(0, 0, 0);
1227
- }
1228
- obj = prepareTresInstance(obj, {
1229
- ...isTresInstance(obj) ? obj.__tres : {},
1230
- type: name,
1231
- memoizedProps: props,
1232
- primitive: tag === "primitive",
1233
- attach: props.attach
1234
- }, context);
1235
- return obj;
1236
- }
1237
- function insert(child, parent, anchor) {
1238
- if (!child) return;
1239
- parent = parent || scene;
1240
- if (isTextNode(child) || isCommentNode(child)) {
1241
- const parentInstance = parent.__tres ? parent : prepareTresInstance(parent, {}, context);
1242
- child.__tres.parent = parentInstance;
1243
- if (parentInstance.__tres.objects) {
1244
- const insertIndex = anchor ? parentInstance.__tres.objects.findIndex((obj) => obj === anchor) : -1;
1245
- if (insertIndex >= 0) parentInstance.__tres.objects.splice(insertIndex, 0, child);
1246
- else parentInstance.__tres.objects.push(child);
1247
- }
1248
- return;
1249
- }
1250
- const childInstance = child.__tres ? child : prepareTresInstance(child, {}, context);
1251
- const parentInstance = parent.__tres ? parent : prepareTresInstance(parent, {}, context);
1252
- child = unboxTresPrimitive(childInstance);
1253
- parent = unboxTresPrimitive(parentInstance);
1254
- if (isTresCamera(child)) context.camera?.registerCamera(child);
1255
- if (childInstance.__tres.attach) attach(parentInstance, childInstance, childInstance.__tres.attach);
1256
- else if (isObject3D(child) && isObject3D(parentInstance)) {
1257
- parentInstance.add(child);
1258
- child.dispatchEvent({ type: "added" });
1259
- }
1260
- childInstance.__tres.parent = parentInstance;
1261
- if (parentInstance.__tres.objects && !parentInstance.__tres.objects.includes(childInstance)) {
1262
- const insertIndex = anchor ? parentInstance.__tres.objects.findIndex((obj) => obj === anchor) : -1;
1263
- if (~insertIndex) parentInstance.__tres.objects.splice(insertIndex, 0, childInstance);
1264
- else parentInstance.__tres.objects.push(childInstance);
1265
- }
1266
- }
1267
- /**
1268
- * @param node – the node root to remove
1269
- * @param dispose – the disposal type
1270
- */
1271
- function remove(node, dispose) {
1272
- if (!node) return;
1273
- if (isTextNode(node) || isCommentNode(node)) {
1274
- const parent = node.__tres.parent;
1275
- if (parent?.__tres?.objects) filterInPlace(parent.__tres.objects, (obj) => obj !== node);
1276
- node.__tres.parent = null;
1277
- return;
1278
- }
1279
- dispose = isUndefined(dispose) ? "default" : dispose;
1280
- const userDispose = node.__tres?.dispose;
1281
- if (!isUndefined(userDispose)) {
1282
- if (userDispose === null) dispose = false;
1283
- else dispose = userDispose;
1284
- }
1285
- const isPrimitive = node.__tres?.primitive;
1286
- const shouldDispose = dispose === "default" ? !isPrimitive : !!dispose;
1287
- if (node.__tres && "objects" in node.__tres) [...node.__tres.objects].forEach((obj) => remove(obj, dispose));
1288
- if (shouldDispose) {
1289
- if (node.children) [...node.children].forEach((child) => remove(child, dispose));
1290
- }
1291
- doRemoveDetach(node, context);
1292
- doRemoveDeregister(node, context);
1293
- if (shouldDispose && !isScene(node)) {
1294
- if (isFunction(dispose)) dispose(node);
1295
- else if (isFunction(node.dispose)) try {
1296
- node.dispose();
1297
- } catch (e) {}
1298
- }
1299
- if ("__tres" in node) delete node.__tres;
1300
- }
1301
- function patchProp(node, prop, prevValue, nextValue) {
1302
- if (!node) return;
1303
- let root = node;
1304
- const key = prop;
1305
- if (node.__tres) node.__tres.memoizedProps[prop] = nextValue;
1306
- if (prop === "attach") {
1307
- const maybeParent = node.__tres?.parent || node.parent;
1308
- remove(node);
1309
- prepareTresInstance(node, { attach: nextValue }, context);
1310
- if (maybeParent) insert(node, maybeParent);
1311
- return;
1312
- }
1313
- if (prop === "dispose") {
1314
- if (!node.__tres) node = prepareTresInstance(node, {}, context);
1315
- node.__tres.dispose = nextValue;
1316
- return;
1317
- }
1318
- if (isSupportedPointerEvent(prop) && isFunction(nextValue)) node.addEventListener(pointerEventsMapVueToThree[prop], nextValue);
1319
- let finalKey = camel(key);
1320
- let target = root?.[finalKey];
1321
- if (key === "args") {
1322
- const prevNode = node;
1323
- const prevArgs = prevValue ?? [];
1324
- const args = nextValue ?? [];
1325
- const instanceName = node.__tres?.type || node.type;
1326
- if (instanceName && prevArgs.length && !isEqual(prevArgs, args)) {
1327
- const newInstance = new catalogue.value[instanceName](...nextValue);
1328
- const descriptors = Object.getOwnPropertyDescriptors(newInstance);
1329
- Object.entries(descriptors).forEach(([key, descriptor]) => {
1330
- if (!descriptor.writable && !descriptor.set) return;
1331
- if (key in prevNode) try {
1332
- prevNode[key] = newInstance[key];
1333
- } catch (e) {
1334
- console.warn(`Could not set property ${key} on ${instanceName}:`, e);
1335
- }
1336
- });
1337
- root = prevNode;
1338
- }
1339
- return;
1340
- }
1341
- if (root.type === "BufferGeometry") {
1342
- if (key === "args") return;
1343
- root.setAttribute(camel(key), new BufferAttribute(...nextValue));
1344
- return;
1345
- }
1346
- if (key.includes("-") && target === void 0) {
1347
- const resolved = resolve(root, key);
1348
- target = resolved.target;
1349
- root = resolved.target;
1350
- finalKey = resolved.key;
1351
- if (target && finalKey) {
1352
- target[finalKey] = nextValue;
1353
- if (isTresCamera(node)) node.updateProjectionMatrix();
1354
- invalidateInstance(node);
1355
- return;
1356
- }
1357
- }
1358
- let value = nextValue;
1359
- if (value === "") value = true;
1360
- if (isFunction(target)) {
1361
- if (!isSupportedPointerEvent(prop)) {
1362
- if (Array.isArray(value)) node[finalKey](...value);
1363
- else node[finalKey](value);
1364
- }
1365
- if (finalKey.startsWith("on") && isFunction(value)) root[finalKey] = value;
1366
- return;
1367
- }
1368
- if (isLayers(target) && isLayers(value)) target.mask = value.mask;
1369
- else if (isColor(target) && isColorRepresentation(value)) target.set(value);
1370
- else if (isCopyable(target) && isClassInstance(value) && target.constructor === value.constructor) target.copy(value);
1371
- else if (isVectorLike(target) && Array.isArray(value)) {
1372
- if ("fromArray" in target && typeof target.fromArray === "function") target.fromArray(value);
1373
- else target.set(...value);
1374
- } else if (isVectorLike(target) && typeof value === "number") {
1375
- if ("setScalar" in target && typeof target.setScalar === "function") target.setScalar(value);
1376
- else target.set(value);
1377
- } else root[finalKey] = value;
1378
- if (isTresCamera(node)) node.updateProjectionMatrix();
1379
- invalidateInstance(node);
1380
- }
1381
- function parentNode(node) {
1382
- return node?.__tres?.parent || null;
1383
- }
1384
- function nextSibling(node) {
1385
- if (!node || !("__tres" in node)) return null;
1386
- const siblings = parentNode(node)?.__tres?.objects || [];
1387
- const index = siblings.findIndex((sibling) => sibling === node);
1388
- if (index < 0 || index >= siblings.length - 1) return null;
1389
- return siblings[index + 1];
1390
- }
1391
- const noop = () => {};
1392
- return {
1393
- insert,
1394
- remove,
1395
- createElement,
1396
- patchProp,
1397
- parentNode,
1398
- createText: createTextNode,
1399
- createComment: createCommentNode,
1400
- setText: noop,
1401
- setElementText: noop,
1402
- nextSibling,
1403
- querySelector: noop,
1404
- setScopeId: noop,
1405
- cloneNode: noop,
1406
- insertStaticContent: noop
1407
- };
1408
- };
1409
- //#endregion
1410
- //#region src/core/roots.ts
1411
- const _roots = /* @__PURE__ */ new Map();
1412
- const getRoot = (canvas) => _roots.get(canvas);
1413
- const setRoot = (canvas, root) => {
1414
- _roots.set(canvas, root);
1415
- };
1416
- const deleteRoot = (canvas) => _roots.delete(canvas);
1417
- //#endregion
1418
- //#region src/devtools/DevtoolsMessenger.ts
1419
- const QUEUEABLE_MESSAGE_TYPES = ["asset-load"];
1420
- /**
1421
- * Messenger class for communicating with Tres DevTools
1422
- * This class will be attached to window.__TRES__DEVTOOLS__
1423
- */
1424
- var DevtoolsMessenger = class {
1425
- subscribers = /* @__PURE__ */ new Set();
1426
- messageQueue = [];
1427
- maxQueueSize = 100;
1428
- /**
1429
- * Send a message to devtools subscribers
1430
- * If no subscribers are available, only queueable message types are queued
1431
- */
1432
- send(type, data) {
1433
- const message = {
1434
- type,
1435
- data,
1436
- timestamp: Date.now()
1437
- };
1438
- if (this.subscribers.size > 0) this.subscribers.forEach((subscriber) => subscriber(message));
1439
- else if (QUEUEABLE_MESSAGE_TYPES.includes(type)) this.queueMessage(message);
1440
- }
1441
- /**
1442
- * Queue a message for later delivery
1443
- */
1444
- queueMessage(message) {
1445
- this.messageQueue.push(message);
1446
- if (this.messageQueue.length > this.maxQueueSize) this.messageQueue.shift();
1447
- }
1448
- /**
1449
- * Flush all queued messages to current subscribers
1450
- */
1451
- flushQueue() {
1452
- if (this.messageQueue.length === 0 || this.subscribers.size === 0) return;
1453
- this.messageQueue.forEach((message) => {
1454
- this.subscribers.forEach((subscriber) => subscriber(message));
1455
- });
1456
- this.messageQueue = [];
1457
- }
1458
- /**
1459
- * Subscribe to devtools messages
1460
- * When a new subscriber is added, all queued messages (asset-load events) are immediately delivered
1461
- */
1462
- subscribe(subscriber) {
1463
- this.subscribers.add(subscriber);
1464
- this.flushQueue();
1465
- return () => {
1466
- this.subscribers.delete(subscriber);
1467
- };
1468
- }
1469
- /**
1470
- * Check if there are any subscribers
1471
- */
1472
- get hasSubscribers() {
1473
- return this.subscribers.size > 0;
1474
- }
1475
- /**
1476
- * Get the current queue size
1477
- */
1478
- get queueSize() {
1479
- return this.messageQueue.length;
1480
- }
1481
- /**
1482
- * Clear all queued messages
1483
- */
1484
- clearQueue() {
1485
- this.messageQueue = [];
1486
- }
1487
- };
1488
- //#endregion
1489
- //#region src/devtools/utils.ts
1490
- /**
1491
- * Shows a toast or console.log
1492
- *
1493
- * @param message - message to log
1494
- * @param type - different color of the tooltip
1495
- */
1496
- function toastMessage(message, type) {
1497
- const tresMessage = `▲ ■ ●${message}`;
1498
- if (typeof __VUE_DEVTOOLS_TOAST__ === "function") __VUE_DEVTOOLS_TOAST__(tresMessage, type);
1499
- else if (type === "error") console.error(tresMessage);
1500
- else if (type === "warn") console.warn(tresMessage);
1501
- else console.log(tresMessage);
1502
- }
1503
- function __VUE_DEVTOOLS_TOAST__(tresMessage, type) {
1504
- throw new Error(tresMessage + type);
1505
- }
1506
- //#endregion
1507
- //#region src/utils/perf.ts
1508
- function calculateMemoryUsage(object) {
1509
- let totalMemory = 0;
1510
- object.traverse((node) => {
1511
- if (isMesh(node) && node.type !== "HightlightMesh") {
1512
- const geometry = node.geometry;
1513
- const verticesMemory = geometry.attributes.position.count * 3 * Float32Array.BYTES_PER_ELEMENT;
1514
- const facesMemory = geometry.index ? geometry.index.count * Uint32Array.BYTES_PER_ELEMENT : 0;
1515
- const normalsMemory = geometry.attributes.normal ? geometry.attributes.normal.count * 3 * Float32Array.BYTES_PER_ELEMENT : 0;
1516
- const uvsMemory = geometry.attributes.uv ? geometry.attributes.uv.count * 2 * Float32Array.BYTES_PER_ELEMENT : 0;
1517
- const geometryMemory = verticesMemory + facesMemory + normalsMemory + uvsMemory;
1518
- totalMemory += geometryMemory;
1519
- }
1520
- });
1521
- return totalMemory;
1522
- }
1523
- function boundedPush(arr, value, max) {
1524
- arr.push(value);
1525
- if (arr.length > max) arr.shift();
1526
- }
1527
- function bytesToKB(bytes) {
1528
- return (bytes / 1024).toFixed(2);
1529
- }
1530
- //#endregion
1531
- //#region src/devtools/setupDevtools.ts
1532
- function setupTresDevtools(ctx) {
1533
- if (!ctx) return;
1534
- if (typeof window !== "undefined" && !window.__TRES__DEVTOOLS__) window.__TRES__DEVTOOLS__ = new DevtoolsMessenger();
1535
- const performanceState = {
1536
- maxFrames: 160,
1537
- fps: {
1538
- value: 0,
1539
- accumulator: []
1540
- },
1541
- memory: {
1542
- currentMem: 0,
1543
- allocatedMem: 0,
1544
- accumulator: []
1545
- }
1546
- };
1547
- const updateInterval = 100;
1548
- const fps = useFps({ every: updateInterval });
1549
- const { isSupported, memory } = useMemory({ scheduler: (cb) => useIntervalFn(cb, updateInterval) });
1550
- const maxFrames = 160;
1551
- let lastUpdateTime = performance.now();
1552
- let accumulatedTime = 0;
1553
- const interval = 1;
1554
- const updatePerformanceData = ({ timestamp }) => {
1555
- if (ctx.scene.value) performanceState.memory.allocatedMem = calculateMemoryUsage(ctx.scene.value);
1556
- if (timestamp - lastUpdateTime >= updateInterval) {
1557
- lastUpdateTime = timestamp;
1558
- boundedPush(performanceState.fps.accumulator, fps.value, maxFrames);
1559
- performanceState.fps.value = fps.value;
1560
- if (isSupported.value && memory.value?.usedJSHeapSize) {
1561
- boundedPush(performanceState.memory.accumulator, memory.value.usedJSHeapSize / 1024 / 1024, maxFrames);
1562
- if (performanceState.memory.accumulator.length > 0) performanceState.memory.currentMem = performanceState.memory.accumulator.reduce((a, b) => a + b, 0) / performanceState.memory.accumulator.length;
1563
- }
1564
- }
1565
- };
1566
- const { pause } = useRafFn(({ delta }) => {
1567
- if (!window.__TRES__DEVTOOLS__) return;
1568
- updatePerformanceData({ timestamp: performance.now() });
1569
- accumulatedTime += delta;
1570
- if (accumulatedTime >= interval) {
1571
- window.__TRES__DEVTOOLS__.send("context", ctx);
1572
- window.__TRES__DEVTOOLS__.send("performance", performanceState);
1573
- accumulatedTime = 0;
1574
- }
1575
- }, { immediate: true });
1576
- onUnmounted(() => {
1577
- pause();
1578
- });
1579
- }
1580
- //#endregion
1581
- //#region src/utils/three.ts
1582
- /**
1583
- * Recursively searches for an Object3D with the specified UUID within a Three.js scene graph.
1584
- *
1585
- * @param node - The root Object3D to start searching from
1586
- * @param uuid - The unique identifier of the object to find
1587
- * @returns The Object3D with the matching UUID, or undefined if not found
1588
- */
1589
- const getObjectByUuid = (node, uuid) => {
1590
- if (node.uuid === uuid) return node;
1591
- for (const child of node.children) {
1592
- const found = getObjectByUuid(child, uuid);
1593
- if (found) return found;
1594
- }
1595
- };
1596
- //#endregion
1597
- //#region src/devtools/highlight.ts
1598
- var HightlightMesh = class extends THREE.Mesh {
1599
- type = "HightlightMesh";
1600
- createTime;
1601
- constructor(...args) {
1602
- super(...args);
1603
- this.createTime = Date.now();
1604
- }
1605
- onBeforeRender() {
1606
- const time = (Date.now() - this.createTime) / 1e3;
1607
- const scaleFactor = 1 + .07 * Math.sin(2.5 * time);
1608
- this.scale.set(scaleFactor, scaleFactor, scaleFactor);
1609
- }
1610
- };
1611
- //#endregion
1612
- //#region src/devtools/inspectorHandlers.ts
1613
- /**
1614
- * Creates a node representation of a Three.js object for the inspector tree
1615
- * @param object - The Three.js object to create a node for
1616
- * @returns A SceneGraphObject representing the Three.js object with relevant metadata
1617
- */
1618
- const createNode = (object) => {
1619
- const node = {
1620
- id: `scene-${object.uuid}`,
1621
- label: object.type,
1622
- children: [],
1623
- tags: []
1624
- };
1625
- if (object.name !== "") node.tags.push({
1626
- label: object.name,
1627
- textColor: 5750629,
1628
- backgroundColor: 15793395
1629
- });
1630
- const memory = calculateMemoryUsage(object);
1631
- if (memory > 0) node.tags.push({
1632
- label: `${bytesToKB(memory)} KB`,
1633
- textColor: 15707189,
1634
- backgroundColor: 16775644,
1635
- tooltip: "Memory usage"
1636
- });
1637
- if (object.type.includes("Light")) {
1638
- if (isLight(object)) node.tags.push({
1639
- label: `${object.intensity}`,
1640
- textColor: 9738662,
1641
- backgroundColor: 16316922,
1642
- tooltip: "Intensity"
1643
- });
1644
- node.tags.push({
1645
- label: `#${new Color(object.color).getHexString()}`,
1646
- textColor: 9738662,
1647
- backgroundColor: 16316922,
1648
- tooltip: "Color"
1649
- });
1650
- }
1651
- if (object.type.includes("Camera")) {
1652
- node.tags.push({
1653
- label: `${object.fov}°`,
1654
- textColor: 9738662,
1655
- backgroundColor: 16316922,
1656
- tooltip: "Field of view"
1657
- });
1658
- node.tags.push({
1659
- label: `x: ${Math.round(object.position.x)} y: ${Math.round(object.position.y)} z: ${Math.round(object.position.z)}`,
1660
- textColor: 9738662,
1661
- backgroundColor: 16316922,
1662
- tooltip: "Position"
1663
- });
1664
- }
1665
- return node;
1666
- };
1667
- /**
1668
- * Creates a context node for the inspector tree
1669
- * @param key - The key identifier for the context node
1670
- * @param uuid - The unique identifier for the context
1671
- * @param parentKey - Optional parent key for nested context nodes
1672
- * @returns A SceneGraphObject representing the context node
1673
- */
1674
- function createContextNode(key, uuid, parentKey = "") {
1675
- return {
1676
- id: `context-${uuid}-${parentKey ? `${parentKey}.${key}` : key}`,
1677
- label: key,
1678
- children: [],
1679
- tags: []
1680
- };
1681
- }
1682
- /**
1683
- * Recursively builds a graph representation of Three.js objects for the inspector
1684
- * @param object - The root Three.js object to build the graph from
1685
- * @param node - The current node in the graph being built
1686
- * @param filter - Optional filter string to filter objects by type or name
1687
- */
1688
- function buildGraph$1(object, node, filter = "") {
1689
- object.children.forEach((child) => {
1690
- if (child.type === "HightlightMesh") return;
1691
- if (filter && !child.type.includes(filter) && !child.name.includes(filter)) return;
1692
- const childNode = createNode(child);
1693
- node.children.push(childNode);
1694
- buildGraph$1(child, childNode, filter);
1695
- });
1696
- }
1697
- /**
1698
- * Recursively builds a graph representation of context objects for the inspector
1699
- * @param object - The root object to build the context graph from
1700
- * @param node - The current node in the graph being built
1701
- * @param visited - WeakSet to track visited objects and prevent circular references
1702
- * @param depth - Current depth in the object tree
1703
- * @param maxDepth - Maximum depth to traverse
1704
- * @param contextUuid - Optional UUID for the context
1705
- * @param parentKey - Optional parent key for nested objects
1706
- */
1707
- function buildContextGraph(object, node, visited = /* @__PURE__ */ new WeakSet(), depth = 0, maxDepth = 4, contextUuid, parentKey = "") {
1708
- if (depth >= maxDepth || !object || visited.has(object)) return;
1709
- const uuid = depth === 0 ? object?.scene?.value?.uuid || Math.random().toString(36).slice(2, 11) : contextUuid;
1710
- visited.add(object);
1711
- Object.entries(object).forEach(([key, value]) => {
1712
- if (key.startsWith("_") || typeof value === "function") return;
1713
- const chainedKey = parentKey ? `${parentKey}.${key}` : key;
1714
- const childNode = createContextNode(key, uuid, parentKey);
1715
- if (key === "scene") return;
1716
- if (isRef(value)) {
1717
- childNode.tags.push({
1718
- label: `Ref<${typeof value.value}>`,
1719
- textColor: 4372611,
1720
- backgroundColor: 15793395
1721
- });
1722
- if (value.value && typeof value.value === "object") buildContextGraph(value.value, childNode, visited, depth + 1, maxDepth, uuid, chainedKey);
1723
- else childNode.label = `${key}: ${JSON.stringify(value.value)}`;
1724
- } else if (value && typeof value === "object" && !Array.isArray(value)) {
1725
- if (Object.keys(value).length > 0) {
1726
- if (visited.has(value)) childNode.tags.push({
1727
- label: "Circular",
1728
- textColor: 16711680,
1729
- backgroundColor: 16773360
1730
- });
1731
- else buildContextGraph(value, childNode, visited, depth + 1, maxDepth, uuid, chainedKey);
1732
- } else childNode.label = `${key}: {}`;
1733
- } else if (Array.isArray(value)) {
1734
- childNode.label = `${key}: Array(${value.length})`;
1735
- childNode.tags.push({
1736
- label: `length: ${value.length}`,
1737
- textColor: 9738662,
1738
- backgroundColor: 16316922
1739
- });
1740
- } else childNode.label = `${key}: ${JSON.stringify(value)}`;
1741
- node.children.push(childNode);
1742
- });
1743
- }
1744
- /**
1745
- * Handler for inspector tree updates
1746
- * @param tres - The TresContext instance
1747
- * @returns A function that handles inspector tree payload updates
1748
- */
1749
- const inspectorTreeHandler = (tres) => (payload) => {
1750
- if (payload.inspectorId === "tres:inspector") {
1751
- const root = createNode(tres.scene.value);
1752
- buildGraph$1(tres.scene.value, root, payload.filter);
1753
- const rootContext = {
1754
- id: "context-root",
1755
- label: "Context",
1756
- children: [],
1757
- tags: []
1758
- };
1759
- buildContextGraph(tres, rootContext);
1760
- payload.rootNodes = [root, rootContext];
1761
- }
1762
- };
1763
- /**
1764
- * Handler for inspector state updates
1765
- * @param tres - The TresContext instance
1766
- * @param options - Options for the handler
1767
- * @param options.highlightMesh - The currently highlighted mesh
1768
- * @param options.prevInstance - The previously selected instance
1769
- * @returns A function that handles inspector state payload updates
1770
- */
1771
- const inspectorStateHandler = (tres, { highlightMesh, prevInstance }) => (payload) => {
1772
- if (payload.inspectorId !== "tres:inspector") return;
1773
- const highlightMaterial = new MeshBasicMaterial({
1774
- color: 11003607,
1775
- transparent: true,
1776
- opacity: .2,
1777
- depthTest: false,
1778
- side: DoubleSide
1779
- });
1780
- if (payload.nodeId.includes("scene")) {
1781
- const match = payload.nodeId.match(/^scene-(.+)$/);
1782
- const uuid = match ? match[1] : null;
1783
- if (!uuid) return;
1784
- const [instance] = tres.scene.value.getObjectsByProperty("uuid", uuid);
1785
- if (!instance) return;
1786
- if (prevInstance && highlightMesh && highlightMesh.parent) prevInstance.remove(highlightMesh);
1787
- if (isMesh(instance)) {
1788
- const newHighlightMesh = new HightlightMesh(instance.geometry.clone(), highlightMaterial);
1789
- instance.add(newHighlightMesh);
1790
- highlightMesh = newHighlightMesh;
1791
- prevInstance = instance;
1792
- }
1793
- payload.state = { object: Object.entries(instance).map(([key, value]) => {
1794
- if (key === "children") return {
1795
- key,
1796
- value: value.filter((child) => child.type !== "HightlightMesh")
1797
- };
1798
- return {
1799
- key,
1800
- value,
1801
- editable: true
1802
- };
1803
- }).filter(({ key }) => {
1804
- return key !== "parent";
1805
- }) };
1806
- if (isScene(instance)) {
1807
- const sceneState = {
1808
- ...payload.state,
1809
- state: [{
1810
- key: "Scene Info",
1811
- value: {
1812
- objects: instance.children.length,
1813
- memory: calculateMemoryUsage(instance),
1814
- calls: tres.renderer.instance.info.render.calls,
1815
- triangles: tres.renderer.instance.info.render.triangles,
1816
- points: tres.renderer.instance.info.render.points,
1817
- lines: tres.renderer.instance.info.render.lines
1818
- }
1819
- }]
1820
- };
1821
- if ("programs" in tres.renderer.instance.info) sceneState.state.push({
1822
- key: "Programs",
1823
- value: tres.renderer.instance.info.programs?.map((program) => ({
1824
- ...program,
1825
- programName: program.name
1826
- }))
1827
- });
1828
- payload.state = sceneState;
1829
- }
1830
- } else if (payload.nodeId.includes("context")) {
1831
- const match = payload.nodeId.match(/^context-([^-]+(?:-[^-]+)*)-(.+)$/);
1832
- const chainedKey = match ? match[2] : "context";
1833
- if (!chainedKey || chainedKey === "context") {
1834
- payload.state = { object: Object.entries(tres).filter(([key]) => !key.startsWith("_") && key !== "parent").map(([key, value]) => ({
1835
- key,
1836
- value: isRef(value) ? value.value : value,
1837
- editable: false
1838
- })) };
1839
- return;
1840
- }
1841
- const parts = chainedKey.split(".");
1842
- let value = tres;
1843
- for (const part of parts) {
1844
- if (!value || typeof value !== "object") break;
1845
- value = isRef(value[part]) ? value[part].value : value[part];
1846
- }
1847
- if (value !== void 0) payload.state = { object: Object.entries(value).filter(([key]) => !key.startsWith("_") && key !== "parent").map(([key, val]) => {
1848
- if (isRef(val)) return {
1849
- key,
1850
- value: val.value,
1851
- editable: false
1852
- };
1853
- if (typeof val === "function") return {
1854
- key,
1855
- value: "ƒ()",
1856
- editable: false
1857
- };
1858
- if (val && typeof val === "object") return {
1859
- key,
1860
- value: Array.isArray(val) ? `Array(${val.length})` : "Object",
1861
- editable: false
1862
- };
1863
- return {
1864
- key,
1865
- value: val,
1866
- editable: false
1867
- };
1868
- }) };
1869
- }
1870
- };
1871
- const editSceneObject = (scene, objectUuid, propertyPath, value) => {
1872
- const targetObject = getObjectByUuid(scene, objectUuid);
1873
- if (!targetObject) {
1874
- console.warn("Object with UUID not found in the scene.");
1875
- return;
1876
- }
1877
- let currentProperty = targetObject;
1878
- for (let i = 0; i < propertyPath.length - 1; i++) if (currentProperty[propertyPath[i]] !== void 0) currentProperty = currentProperty[propertyPath[i]];
1879
- else {
1880
- console.warn(`Property path is not valid: ${propertyPath.join(".")}`);
1881
- return;
1882
- }
1883
- const lastProperty = propertyPath[propertyPath.length - 1];
1884
- if (currentProperty[lastProperty] !== void 0) currentProperty[lastProperty] = value;
1885
- else console.warn(`Property path is not valid: ${propertyPath.join(".")}`);
1886
- };
1887
- /**
1888
- * Handler for inspector state edits
1889
- * @param tres - The TresContext instance
1890
- * @returns A function that handles inspector state edit payload updates
1891
- */
1892
- const inspectorEditStateHandler = (tres) => (payload) => {
1893
- if (payload.inspectorId === "tres:inspector") {
1894
- if (payload.nodeId.includes("scene")) {
1895
- const match = payload.nodeId.match(/^scene-(.+)$/);
1896
- const uuid = match ? match[1] : null;
1897
- if (!uuid) return;
1898
- editSceneObject(tres.scene.value, uuid, payload.path, payload.state.value);
1899
- }
1900
- }
1901
- };
1902
- //#endregion
1903
- //#region src/devtools/plugin.ts
1904
- const INSPECTOR_ID = "tres:inspector";
1905
- function registerTresDevtools(app, tres) {
1906
- const pluginDescriptor = {
1907
- id: "dev.esm.tres",
1908
- label: "TresJS 🪐",
1909
- logo: "https://raw.githubusercontent.com/Tresjs/tres/main/public/favicon.svg",
1910
- packageName: "tresjs",
1911
- homepage: "https://docs.tresjs.org",
1912
- app
1913
- };
1914
- const highlightMesh = null;
1915
- const prevInstance = null;
1916
- setupTresDevtools(tres);
1917
- setupDevtoolsPlugin(pluginDescriptor, (api) => {
1918
- if (typeof api.now !== "function") toastMessage("You seem to be using an outdated version of Vue Devtools. Are you still using the Beta release instead of the stable one? You can find the links at https://devtools.vuejs.org/guide/installation.html.");
1919
- api.addInspector({
1920
- id: INSPECTOR_ID,
1921
- label: "TresJS 🪐",
1922
- icon: "account_tree",
1923
- treeFilterPlaceholder: "Search instances"
1924
- });
1925
- setInterval(() => {
1926
- api.sendInspectorTree(INSPECTOR_ID);
1927
- }, 1e3);
1928
- setInterval(() => {
1929
- api.notifyComponentUpdate();
1930
- }, 5e3);
1931
- api.on.getInspectorTree(inspectorTreeHandler(tres));
1932
- api.on.getInspectorState(inspectorStateHandler(tres, {
1933
- highlightMesh,
1934
- prevInstance
1935
- }));
1936
- api.on.editInspectorState(inspectorEditStateHandler(tres));
1937
- });
1938
- }
1939
- //#endregion
1940
- //#region src/components/Context.vue
1941
- var Context_default = /* @__PURE__ */ defineComponent({
1942
- __name: "Context",
1943
- props: {
1944
- camera: {
1945
- type: null,
1946
- required: false
1947
- },
1948
- windowSize: {
1949
- type: Boolean,
1950
- required: false
1951
- },
1952
- fpsLimit: {
1953
- type: Number,
1954
- required: false
1955
- },
1956
- enableProvideBridge: {
1957
- type: Boolean,
1958
- required: false
1959
- },
1960
- customRendererOptions: {
1961
- type: Object,
1962
- required: false
1963
- },
1964
- antialias: {
1965
- type: Boolean,
1966
- required: false
1967
- },
1968
- stencil: {
1969
- type: Boolean,
1970
- required: false
1971
- },
1972
- depth: {
1973
- type: Boolean,
1974
- required: false
1975
- },
1976
- precision: {
1977
- type: String,
1978
- required: false
1979
- },
1980
- logarithmicDepthBuffer: {
1981
- type: Boolean,
1982
- required: false
1983
- },
1984
- preserveDrawingBuffer: {
1985
- type: Boolean,
1986
- required: false
1987
- },
1988
- powerPreference: {
1989
- type: null,
1990
- required: false
1991
- },
1992
- alpha: {
1993
- type: Boolean,
1994
- required: false
1995
- },
1996
- premultipliedAlpha: {
1997
- type: Boolean,
1998
- required: false
1999
- },
2000
- failIfMajorPerformanceCaveat: {
2001
- type: Boolean,
2002
- required: false
2003
- },
2004
- clearColor: {
2005
- type: [
2006
- Object,
2007
- String,
2008
- Number
2009
- ],
2010
- required: false
2011
- },
2012
- clearAlpha: {
2013
- type: Number,
2014
- required: false
2015
- },
2016
- shadows: {
2017
- type: Boolean,
2018
- required: false
2019
- },
2020
- toneMapping: {
2021
- type: null,
2022
- required: false
2023
- },
2024
- shadowMapType: {
2025
- type: null,
2026
- required: false
2027
- },
2028
- useLegacyLights: {
2029
- type: Boolean,
2030
- required: false
2031
- },
2032
- outputColorSpace: {
2033
- type: null,
2034
- required: false
2035
- },
2036
- toneMappingExposure: {
2037
- type: Number,
2038
- required: false
2039
- },
2040
- renderMode: {
2041
- type: String,
2042
- required: false
2043
- },
2044
- dpr: {
2045
- type: [Number, Array],
2046
- required: false
2047
- },
2048
- renderer: {
2049
- type: Function,
2050
- required: false
2051
- },
2052
- canvas: {
2053
- type: null,
2054
- required: true
2055
- }
2056
- },
2057
- emits: [
2058
- "ready",
2059
- "error",
2060
- "pointermissed",
2061
- "render",
2062
- "beforeLoop",
2063
- "loop",
2064
- "click",
2065
- "contextmenu",
2066
- "pointermove",
2067
- "pointerenter",
2068
- "pointerleave",
2069
- "pointerover",
2070
- "pointerout",
2071
- "dblclick",
2072
- "pointerdown",
2073
- "pointerup",
2074
- "pointercancel",
2075
- "lostpointercapture",
2076
- "wheel"
2077
- ],
2078
- setup(__props, { expose: __expose, emit: __emit }) {
2079
- const props = __props;
2080
- const emit = __emit;
2081
- const slots = useSlots();
2082
- const scene = shallowRef(new Scene());
2083
- const instance = getCurrentInstance();
2084
- extend(THREE);
2085
- const createInternalComponent = (context, hmrTick) => defineComponent({ setup() {
2086
- const ctx = getCurrentInstance()?.appContext;
2087
- if (ctx) ctx.app = instance?.appContext.app;
2088
- const provides = {};
2089
- function mergeProvides(currentInstance) {
2090
- if (!currentInstance) return;
2091
- if (currentInstance.parent) mergeProvides(currentInstance.parent);
2092
- if (currentInstance.provides) Object.assign(provides, currentInstance.provides);
2093
- }
2094
- if (instance?.parent && props.enableProvideBridge) {
2095
- mergeProvides(instance.parent);
2096
- Reflect.ownKeys(provides).forEach((key) => {
2097
- provide(key, provides[key]);
2098
- });
2099
- }
2100
- provide(INJECTION_KEY, context);
2101
- provide("extend", extend);
2102
- if (typeof window !== "undefined" && ctx?.app) registerTresDevtools(ctx?.app, context);
2103
- return () => {
2104
- hmrTick.value;
2105
- return h(Fragment, null, slots.default?.() ?? []);
2106
- };
2107
- } });
2108
- const mountCustomRenderer = (context) => {
2109
- const canvas = props.canvas;
2110
- if (getRoot(canvas)) return;
2111
- const hmrTick = ref(0);
2112
- const internalComponent = createInternalComponent(context, hmrTick);
2113
- const renderer = createRenderer(nodeOps({
2114
- context,
2115
- options: props.customRendererOptions
2116
- }));
2117
- renderer.render(h(internalComponent), scene.value);
2118
- setRoot(canvas, {
2119
- renderer,
2120
- internalComponent,
2121
- hmrTick,
2122
- context
2123
- });
2124
- };
2125
- const dispose = (context, force = false) => {
2126
- disposeObject3D(context.scene.value);
2127
- if (force) {
2128
- context.renderer.instance.dispose();
2129
- if (context.renderer.instance instanceof WebGLRenderer) {
2130
- context.renderer.instance.renderLists.dispose();
2131
- context.renderer.instance.forceContextLoss();
2132
- }
2133
- }
2134
- scene.value.__tres = {
2135
- root: context,
2136
- objects: [],
2137
- isUnmounting: true
2138
- };
2139
- };
2140
- const context = shallowRef(useTresContextProvider({
2141
- scene: scene.value,
2142
- canvas: props.canvas,
2143
- fpsLimit: () => props.fpsLimit ?? Infinity,
2144
- windowSize: props.windowSize ?? false,
2145
- rendererOptions: props
2146
- }));
2147
- __expose({
2148
- context,
2149
- dispose: () => dispose(context.value, true)
2150
- });
2151
- const handleHMR = () => {
2152
- const root = getRoot(props.canvas);
2153
- if (root) root.hmrTick.value++;
2154
- };
2155
- const unmountCanvas = () => {
2156
- const root = getRoot(props.canvas);
2157
- if (!root) return;
2158
- const isTresScene = (value) => isScene(value) && "__tres" in value;
2159
- if (isTresScene(scene.value)) scene.value.__tres.isUnmounting = true;
2160
- root.renderer.render(null, scene.value);
2161
- dispose(context.value);
2162
- deleteRoot(props.canvas);
2163
- };
2164
- const { camera, renderer } = context.value;
2165
- const { registerCamera, cameras, activeCamera, deregisterCamera } = camera;
2166
- const addDefaultCamera = () => {
2167
- const camera = new PerspectiveCamera(45, window.innerWidth / window.innerHeight, .1, 1e3);
2168
- camera.position.set(3, 3, 3);
2169
- camera.lookAt(0, 0, 0);
2170
- registerCamera(camera);
2171
- const unwatch = watchEffect(() => {
2172
- if (cameras.value.length >= 2) {
2173
- camera.removeFromParent();
2174
- deregisterCamera(camera);
2175
- unwatch?.();
2176
- }
2177
- });
2178
- };
2179
- context.value.events.onPointerMissed((event) => {
2180
- emit("pointermissed", event);
2181
- });
2182
- watch(() => props.camera, (newCamera, oldCamera) => {
2183
- if (newCamera) registerCamera(toValue(newCamera), true);
2184
- if (oldCamera) {
2185
- toValue(oldCamera).removeFromParent();
2186
- deregisterCamera(toValue(oldCamera));
2187
- }
2188
- }, { immediate: true });
2189
- renderer.onRender(() => {
2190
- if (context.value) emit("render", context.value);
2191
- });
2192
- renderer.loop.onLoop((loopContext) => {
2193
- if (context.value) emit("loop", {
2194
- ...context.value,
2195
- ...loopContext
2196
- });
2197
- });
2198
- renderer.loop.onBeforeLoop((loopContext) => {
2199
- if (context.value) emit("beforeLoop", {
2200
- ...context.value,
2201
- ...loopContext
2202
- });
2203
- });
2204
- renderer.onReady(() => {
2205
- mountCustomRenderer(context.value);
2206
- emit("ready", context.value);
2207
- if (!activeCamera.value) addDefaultCamera();
2208
- });
2209
- renderer.onError((error) => {
2210
- emit("error", error);
2211
- });
2212
- if (import.meta.hot) {
2213
- const hmrHandler = () => handleHMR();
2214
- import.meta.hot.on("vite:afterUpdate", hmrHandler);
2215
- onBeforeUnmount(() => {
2216
- import.meta.hot?.off?.("vite:afterUpdate", hmrHandler);
2217
- });
2218
- }
2219
- onMounted(async () => {
2220
- await promiseTimeout(3e3);
2221
- if (!context.value.sizes.width || !context.value.sizes.height.value) console.warn(`TresCanvas: The canvas has no area, so nothing can be rendered. Set it manually on the parent element or use the prop windowSize.`);
2222
- });
2223
- onUnmounted(unmountCanvas);
2224
- return () => {};
2225
- }
2226
- });
2227
- //#endregion
2228
- //#region src/components/TresCanvas.vue?vue&type=script&setup=true&lang.ts
2229
- const _hoisted_1 = ["data-scene", "data-tres"];
2230
- //#endregion
2231
- //#region src/components/TresCanvas.vue
2232
- var TresCanvas_default = /* @__PURE__ */ defineComponent({
2233
- __name: "TresCanvas",
2234
- props: {
2235
- camera: {
2236
- type: null,
2237
- required: false
2238
- },
2239
- windowSize: {
2240
- type: Boolean,
2241
- required: false,
2242
- default: void 0
2243
- },
2244
- fpsLimit: {
2245
- type: Number,
2246
- required: false
2247
- },
2248
- enableProvideBridge: {
2249
- type: Boolean,
2250
- required: false,
2251
- default: true
2252
- },
2253
- customRendererOptions: {
2254
- type: Object,
2255
- required: false,
2256
- default: () => ({ primitivePrefix: "" })
2257
- },
2258
- antialias: {
2259
- type: Boolean,
2260
- required: false,
2261
- default: true
2262
- },
2263
- stencil: {
2264
- type: Boolean,
2265
- required: false,
2266
- default: void 0
2267
- },
2268
- depth: {
2269
- type: Boolean,
2270
- required: false,
2271
- default: void 0
2272
- },
2273
- precision: {
2274
- type: String,
2275
- required: false
2276
- },
2277
- logarithmicDepthBuffer: {
2278
- type: Boolean,
2279
- required: false,
2280
- default: void 0
2281
- },
2282
- preserveDrawingBuffer: {
2283
- type: Boolean,
2284
- required: false,
2285
- default: void 0
2286
- },
2287
- powerPreference: {
2288
- type: null,
2289
- required: false
2290
- },
2291
- alpha: {
2292
- type: Boolean,
2293
- required: false,
2294
- default: void 0
2295
- },
2296
- premultipliedAlpha: {
2297
- type: Boolean,
2298
- required: false
2299
- },
2300
- failIfMajorPerformanceCaveat: {
2301
- type: Boolean,
2302
- required: false,
2303
- default: void 0
2304
- },
2305
- clearColor: {
2306
- type: [
2307
- Object,
2308
- String,
2309
- Number
2310
- ],
2311
- required: false,
2312
- default: "#000000"
2313
- },
2314
- clearAlpha: {
2315
- type: Number,
2316
- required: false,
2317
- default: 1
2318
- },
2319
- shadows: {
2320
- type: Boolean,
2321
- required: false,
2322
- default: void 0
2323
- },
2324
- toneMapping: {
2325
- type: null,
2326
- required: false,
2327
- default: ACESFilmicToneMapping
2328
- },
2329
- shadowMapType: {
2330
- type: null,
2331
- required: false,
2332
- default: void 0
2333
- },
2334
- useLegacyLights: {
2335
- type: Boolean,
2336
- required: false,
2337
- default: void 0
2338
- },
2339
- outputColorSpace: {
2340
- type: null,
2341
- required: false
2342
- },
2343
- toneMappingExposure: {
2344
- type: Number,
2345
- required: false
2346
- },
2347
- renderMode: {
2348
- type: String,
2349
- required: false,
2350
- default: "always"
2351
- },
2352
- dpr: {
2353
- type: [Number, Array],
2354
- required: false
2355
- },
2356
- renderer: {
2357
- type: Function,
2358
- required: false
2359
- }
2360
- },
2361
- emits: [
2362
- "ready",
2363
- "error",
2364
- "pointermissed",
2365
- "render",
2366
- "beforeLoop",
2367
- "loop",
2368
- "click",
2369
- "contextmenu",
2370
- "pointermove",
2371
- "pointerenter",
2372
- "pointerleave",
2373
- "pointerover",
2374
- "pointerout",
2375
- "dblclick",
2376
- "pointerdown",
2377
- "pointerup",
2378
- "pointercancel",
2379
- "lostpointercapture",
2380
- "wheel"
2381
- ],
2382
- setup(__props, { expose: __expose, emit: __emit }) {
2383
- const props = __props;
2384
- const emit = __emit;
2385
- const canvasRef = ref();
2386
- const contextRef = shallowRef();
2387
- __expose({
2388
- get context() {
2389
- return contextRef.value?.context;
2390
- },
2391
- dispose: () => contextRef.value?.dispose()
2392
- });
2393
- return (_ctx, _cache) => {
2394
- return openBlock(), createElementBlock("canvas", {
2395
- ref_key: "canvasRef",
2396
- ref: canvasRef,
2397
- "data-scene": contextRef.value?.context?.scene.value.uuid,
2398
- class: normalizeClass(_ctx.$attrs.class),
2399
- "data-tres": `tresjs ${unref(version)}`,
2400
- style: normalizeStyle({
2401
- display: "block",
2402
- width: "100%",
2403
- height: "100%",
2404
- position: __props.windowSize ? "fixed" : "relative",
2405
- top: 0,
2406
- left: 0,
2407
- pointerEvents: "auto",
2408
- touchAction: "none",
2409
- ..._ctx.$attrs.style
2410
- })
2411
- }, [canvasRef.value ? (openBlock(), createBlock(Context_default, mergeProps({
2412
- key: 0,
2413
- ref_key: "contextRef",
2414
- ref: contextRef,
2415
- canvas: canvasRef.value
2416
- }, props, {
2417
- onReady: _cache[0] || (_cache[0] = ($event) => emit("ready", $event)),
2418
- onError: _cache[1] || (_cache[1] = ($event) => emit("error", $event)),
2419
- onPointermissed: _cache[2] || (_cache[2] = ($event) => emit("pointermissed", $event)),
2420
- onRender: _cache[3] || (_cache[3] = ($event) => emit("render", $event)),
2421
- onBeforeLoop: _cache[4] || (_cache[4] = ($event) => emit("beforeLoop", $event)),
2422
- onLoop: _cache[5] || (_cache[5] = ($event) => emit("loop", $event)),
2423
- onClick: _cache[6] || (_cache[6] = ($event) => emit("click", $event)),
2424
- onContextmenu: _cache[7] || (_cache[7] = ($event) => emit("contextmenu", $event)),
2425
- onPointermove: _cache[8] || (_cache[8] = ($event) => emit("pointermove", $event)),
2426
- onPointerenter: _cache[9] || (_cache[9] = ($event) => emit("pointerenter", $event)),
2427
- onPointerleave: _cache[10] || (_cache[10] = ($event) => emit("pointerleave", $event)),
2428
- onPointerover: _cache[11] || (_cache[11] = ($event) => emit("pointerover", $event)),
2429
- onPointerout: _cache[12] || (_cache[12] = ($event) => emit("pointerout", $event)),
2430
- onDblclick: _cache[13] || (_cache[13] = ($event) => emit("dblclick", $event)),
2431
- onPointerdown: _cache[14] || (_cache[14] = ($event) => emit("pointerdown", $event)),
2432
- onPointerup: _cache[15] || (_cache[15] = ($event) => emit("pointerup", $event)),
2433
- onPointercancel: _cache[16] || (_cache[16] = ($event) => emit("pointercancel", $event)),
2434
- onLostpointercapture: _cache[17] || (_cache[17] = ($event) => emit("lostpointercapture", $event)),
2435
- onWheel: _cache[18] || (_cache[18] = ($event) => emit("wheel", $event))
2436
- }), {
2437
- default: withCtx(() => [renderSlot(_ctx.$slots, "default")]),
2438
- _: 3
2439
- }, 16, ["canvas"])) : createCommentVNode("v-if", true)], 14, _hoisted_1);
2440
- };
2441
- }
2442
- });
2443
- //#endregion
2444
- //#region src/utils/normalize.ts
2445
- function normalizeVectorFlexibleParam(value) {
2446
- if (typeof value === "number") return [
2447
- value,
2448
- value,
2449
- value
2450
- ];
2451
- if (value instanceof Vector3) return [
2452
- value.x,
2453
- value.y,
2454
- value.z
2455
- ];
2456
- return value;
2457
- }
2458
- function normalizeColor(value) {
2459
- if (value instanceof Color) return value;
2460
- if (Array.isArray(value)) return new Color(...value);
2461
- return new Color(value);
2462
- }
2463
- //#endregion
2464
- //#region src/utils/template-compiler-options.ts
2465
- const whitelist = [
2466
- "TresCanvas",
2467
- "TresCanvasContext",
2468
- "TresLeches",
2469
- "TresScene",
2470
- "TresPortal"
2471
- ];
2472
- const templateCompilerOptions = { template: { compilerOptions: { isCustomElement: (tag) => (/^Tres[A-Z]/.test(tag) || tag.startsWith("tres-")) && !whitelist.includes(tag) || tag === "primitive" } } };
2473
- //#endregion
2474
- //#region src/components/TresPortal.vue
2475
- var TresPortal_default = /* @__PURE__ */ defineComponent({
2476
- __name: "TresPortal",
2477
- props: {
2478
- to: {
2479
- type: Object,
2480
- required: true
2481
- },
2482
- disabled: {
2483
- type: Boolean,
2484
- required: false
2485
- }
2486
- },
2487
- setup(__props) {
2488
- return (_ctx, _cache) => {
2489
- return openBlock(), createBlock(Teleport, {
2490
- to: __props.to,
2491
- disabled: __props.disabled
2492
- }, [renderSlot(_ctx.$slots, "default")], 8, ["to", "disabled"]);
2493
- };
2494
- }
2495
- });
2496
- //#endregion
2497
- //#region src/directives/vDistanceTo.ts
2498
- let arrowHelper = null;
2499
- const vDistanceTo = {
2500
- updated: (el, binding) => {
2501
- const extractBindingPosition = (binding) => {
2502
- let observer = binding.value;
2503
- if (binding.value && isMesh(binding.value)) observer = binding.value.position;
2504
- if (Array.isArray(binding.value)) observer = new Vector3(...observer);
2505
- return observer;
2506
- };
2507
- const observer = extractBindingPosition(binding);
2508
- if (!observer) {
2509
- logWarning(`v-distance-to: problem with binding value: ${binding.value}`);
2510
- return;
2511
- }
2512
- if (arrowHelper) {
2513
- arrowHelper.dispose();
2514
- el.parent.remove(arrowHelper);
2515
- }
2516
- const dir = observer.clone().sub(el.position);
2517
- dir.normalize();
2518
- arrowHelper = new ArrowHelper(dir, el.position, el.position.distanceTo(observer), 16776960);
2519
- el.parent.add(arrowHelper);
2520
- console.table([
2521
- ["Distance:", el.position.distanceTo(observer)],
2522
- [`origin: ${el.name || el.type}`, `x:${el.position.x}, y:${el.position.y}, z:${el.position?.z}`],
2523
- [`Destiny: ${el.name || el.type}`, `x:${observer.x}, y:${observer.y}, z:${observer?.z}`]
2524
- ]);
2525
- },
2526
- unmounted: (el) => {
2527
- arrowHelper?.dispose();
2528
- if (el.parent) el.parent.remove(arrowHelper);
2529
- }
2530
- };
2531
- //#endregion
2532
- //#region src/directives/vLightHelper.ts
2533
- let CurrentHelper;
2534
- let currentInstance;
2535
- const helpers = {
2536
- DirectionalLight: DirectionalLightHelper,
2537
- PointLight: PointLightHelper,
2538
- SpotLight: SpotLightHelper,
2539
- HemisphereLight: HemisphereLightHelper,
2540
- RectAreaLight: RectAreaLightHelper
2541
- };
2542
- const vLightHelper = {
2543
- mounted: (el) => {
2544
- if (!isLight(el)) {
2545
- logWarning(`${el.type} is not a light`);
2546
- return;
2547
- }
2548
- CurrentHelper = helpers[el.type];
2549
- el.parent?.add(new CurrentHelper(el, 1, el.color.getHex()));
2550
- },
2551
- updated: (el) => {
2552
- currentInstance = el.parent?.children.find((child) => child instanceof CurrentHelper);
2553
- if (currentInstance instanceof RectAreaLightHelper) return;
2554
- currentInstance.update();
2555
- },
2556
- unmounted: (el) => {
2557
- if (!el.isLight) {
2558
- logWarning(`${el.type} is not a light`);
2559
- return;
2560
- }
2561
- currentInstance = el.parent?.children.find((child) => child instanceof CurrentHelper);
2562
- if (currentInstance && currentInstance.dispose) currentInstance.dispose();
2563
- if (el.parent) el.parent.remove(currentInstance);
2564
- }
2565
- };
2566
- //#endregion
2567
- //#region src/directives/vLog.ts
2568
- const vLog = { mounted: (el, binding) => {
2569
- if (binding.arg) {
2570
- console.log(`v-log:${binding.arg}`, el[binding.arg]);
2571
- return;
2572
- }
2573
- console.log("v-log", el);
2574
- } };
2575
- //#endregion
2576
- //#region src/index.ts
2577
- const plugin = { install(app) {
2578
- app.component("TresCanvas", TresCanvas_default);
2579
- } };
2580
- //#endregion
2581
- export { DevtoolsMessenger, INJECTION_KEY, TresCanvas_default as TresCanvas, Context_default as TresCanvasContext, TresPortal_default as TresPortal, TresRendererError, component_default as UseLoader, buildGraph, catalogue, createTimer, plugin as default, disposeObject3D as dispose, extend, isBufferGeometry, isCamera, isClassInstance, isColor, isColorRepresentation, isCopyable, isFog, isGroup, isLayers, isLight, isMaterial, isMesh, isObject3D, isOrthographicCamera, isPerspectiveCamera, isProd, isScene, isTresCamera, isTresInstance, isTresObject, isTresPrimitive, isVectorLike, isWebGLRenderer, isWebGPURenderer, logError, logMessage, logWarning, normalizeColor, normalizeVectorFlexibleParam, registerTresDevtools, templateCompilerOptions, useCameraManager, useGraph, useLoader, useLoop, useRendererManager, useTres, useTresContext, useTresContextProvider, vDistanceTo, vLightHelper, vLog };
8
+ import { $ as isGroup, A as catalogue, B as isCopyable, C as disposeObject3D, E as INJECTION_KEY, F as isProd, G as isVectorLike, H as isTresInstance, I as logError, J as isBufferGeometry, K as isWebGLRenderer, L as logMessage, N as TresRendererError, O as useTresContext, P as createTimer, Q as isFog, R as logWarning, S as DevtoolsMessenger, T as useTresContextProvider, U as isTresObject, V as isTresCamera, W as isTresPrimitive, X as isColor, Y as isCamera, Z as isColorRepresentation, a as useLoop, at as isNodeMaterial, c as buildGraph, ct as isPerspectiveCamera, d as TresPortal_default, et as isLayers, f as WebGLContext_default, g as TresCanvas_default, h as normalizeVectorFlexibleParam, i as vDistanceTo, it as isNode, j as extend, k as useCameraManager, l as component_default, lt as isScene, m as normalizeColor, n as vLog, nt as isMaterial, o as useTres, ot as isObject3D, p as templateCompilerOptions, q as isWebGPURenderer, r as vLightHelper, rt as isMesh, s as useGraph, st as isOrthographicCamera, t as plugin, tt as isLight, u as useLoader, w as useRendererManager, x as registerTresDevtools, z as isClassInstance } from "./src-D_6lJnFs.js";
9
+ export { DevtoolsMessenger, INJECTION_KEY, TresCanvas_default as TresCanvas, WebGLContext_default as TresCanvasContext, TresPortal_default as TresPortal, TresRendererError, component_default as UseLoader, buildGraph, catalogue, createTimer, plugin as default, disposeObject3D as dispose, extend, isBufferGeometry, isCamera, isClassInstance, isColor, isColorRepresentation, isCopyable, isFog, isGroup, isLayers, isLight, isMaterial, isMesh, isNode, isNodeMaterial, isObject3D, isOrthographicCamera, isPerspectiveCamera, isProd, isScene, isTresCamera, isTresInstance, isTresObject, isTresPrimitive, isVectorLike, isWebGLRenderer, isWebGPURenderer, logError, logMessage, logWarning, normalizeColor, normalizeVectorFlexibleParam, registerTresDevtools, templateCompilerOptions, useCameraManager, useGraph, useLoader, useLoop, useRendererManager, useTres, useTresContext, useTresContextProvider, vDistanceTo, vLightHelper, vLog };