@needle-tools/engine 5.0.4 → 5.0.6
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/CHANGELOG.md +16 -0
- package/components.needle.json +1 -1
- package/dist/{needle-engine.bundle-CX-SJZzp.min.js → needle-engine.bundle-BNqZHrmH.min.js} +142 -141
- package/dist/{needle-engine.bundle-CYrPktak.umd.cjs → needle-engine.bundle-BY1mZ1X_.umd.cjs} +140 -139
- package/dist/{needle-engine.bundle-B3Km2VZ4.js → needle-engine.bundle-BsFWwS-j.js} +8183 -7957
- package/dist/needle-engine.d.ts +139 -14
- package/dist/needle-engine.js +560 -557
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/dist/{vendor-vHLk8sXu.js → vendor-CAcsI0eU.js} +116 -115
- package/dist/{vendor-CntUvmJu.umd.cjs → vendor-CEM38hLE.umd.cjs} +2 -2
- package/dist/{vendor-DPbfJJ4d.min.js → vendor-HRlxIBga.min.js} +2 -2
- package/lib/engine/api.d.ts +2 -0
- package/lib/engine/api.js +2 -0
- package/lib/engine/api.js.map +1 -1
- package/lib/engine/debug/debug_spatial_console.d.ts +2 -0
- package/lib/engine/debug/debug_spatial_console.js +10 -7
- package/lib/engine/debug/debug_spatial_console.js.map +1 -1
- package/lib/engine/engine_addressables.d.ts +2 -0
- package/lib/engine/engine_addressables.js +6 -3
- package/lib/engine/engine_addressables.js.map +1 -1
- package/lib/engine/engine_audio.d.ts +68 -0
- package/lib/engine/engine_audio.js +172 -0
- package/lib/engine/engine_audio.js.map +1 -1
- package/lib/engine/engine_gameobject.js +2 -2
- package/lib/engine/engine_gameobject.js.map +1 -1
- package/lib/engine/engine_init.js +8 -0
- package/lib/engine/engine_init.js.map +1 -1
- package/lib/engine/engine_mainloop_utils.js +5 -2
- package/lib/engine/engine_mainloop_utils.js.map +1 -1
- package/lib/engine/engine_serialization_builtin_serializer.js +27 -0
- package/lib/engine/engine_serialization_builtin_serializer.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.d.ts +9 -3
- package/lib/engine/webcomponents/needle-engine.js.map +1 -1
- package/lib/engine/xr/NeedleXRSession.d.ts +3 -2
- package/lib/engine/xr/NeedleXRSession.js +50 -14
- package/lib/engine/xr/NeedleXRSession.js.map +1 -1
- package/lib/engine-components/Animation.js +17 -16
- package/lib/engine-components/Animation.js.map +1 -1
- package/lib/engine-components/AnimatorController.d.ts +2 -0
- package/lib/engine-components/AnimatorController.js +4 -1
- package/lib/engine-components/AnimatorController.js.map +1 -1
- package/lib/engine-components/AudioSource.d.ts +19 -3
- package/lib/engine-components/AudioSource.js +121 -68
- package/lib/engine-components/AudioSource.js.map +1 -1
- package/lib/engine-components/DragControls.d.ts +7 -0
- package/lib/engine-components/DragControls.js +19 -0
- package/lib/engine-components/DragControls.js.map +1 -1
- package/lib/engine-components/NestedGltf.d.ts +19 -3
- package/lib/engine-components/NestedGltf.js +19 -3
- package/lib/engine-components/NestedGltf.js.map +1 -1
- package/lib/engine-components/Networking.d.ts +1 -1
- package/lib/engine-components/Networking.js +1 -1
- package/lib/engine-components/OrbitControls.js +16 -11
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/postprocessing/VolumeParameter.d.ts +2 -0
- package/lib/engine-components/postprocessing/VolumeParameter.js +4 -1
- package/lib/engine-components/postprocessing/VolumeParameter.js.map +1 -1
- package/lib/engine-components/ui/Canvas.d.ts +1 -1
- package/lib/engine-components/ui/Canvas.js +2 -8
- package/lib/engine-components/ui/Canvas.js.map +1 -1
- package/lib/engine-components/ui/Text.d.ts +8 -1
- package/lib/engine-components/ui/Text.js +29 -14
- package/lib/engine-components/ui/Text.js.map +1 -1
- package/lib/engine-components/web/CursorFollow.js +21 -12
- package/lib/engine-components/web/CursorFollow.js.map +1 -1
- package/lib/engine-components/webxr/WebXRImageTracking.js +4 -0
- package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
- package/package.json +1 -1
- package/src/engine/api.ts +3 -0
- package/src/engine/debug/debug_spatial_console.ts +10 -7
- package/src/engine/engine_addressables.ts +6 -3
- package/src/engine/engine_audio.ts +184 -0
- package/src/engine/engine_gameobject.ts +2 -2
- package/src/engine/engine_init.ts +8 -0
- package/src/engine/engine_mainloop_utils.ts +5 -2
- package/src/engine/engine_serialization_builtin_serializer.ts +31 -3
- package/src/engine/webcomponents/needle-engine.ts +9 -3
- package/src/engine/xr/NeedleXRSession.ts +48 -13
- package/src/engine-components/Animation.ts +19 -16
- package/src/engine-components/AnimatorController.ts +4 -1
- package/src/engine-components/AudioSource.ts +130 -79
- package/src/engine-components/DragControls.ts +18 -2
- package/src/engine-components/NestedGltf.ts +20 -4
- package/src/engine-components/Networking.ts +1 -1
- package/src/engine-components/OrbitControls.ts +18 -9
- package/src/engine-components/postprocessing/VolumeParameter.ts +4 -1
- package/src/engine-components/ui/Canvas.ts +2 -8
- package/src/engine-components/ui/Text.ts +43 -18
- package/src/engine-components/web/CursorFollow.ts +21 -13
- package/src/engine-components/webxr/WebXRImageTracking.ts +2 -0
|
@@ -9,9 +9,9 @@ import { EventList } from "./EventList.js";
|
|
|
9
9
|
const debug = getParam("debugnestedgltf");
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* NestedGltf loads and instantiates a glTF file when the component starts.
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* NestedGltf loads and instantiates a glTF file when the component starts.
|
|
13
|
+
* This enables splitting a scene into multiple `.glb` files that are loaded on demand,
|
|
14
|
+
* keeping initial load times small and allowing parts of a scene to be reused across different contexts.
|
|
15
15
|
*
|
|
16
16
|
* 
|
|
17
17
|
*
|
|
@@ -23,6 +23,23 @@ const debug = getParam("debugnestedgltf");
|
|
|
23
23
|
* - Progress callbacks for loading UI
|
|
24
24
|
* - Preloading support for faster display
|
|
25
25
|
* - Event callback when loading completes
|
|
26
|
+
*
|
|
27
|
+
* **Limitations:**
|
|
28
|
+
* - Loads only once; there is no public API to unload and reload content
|
|
29
|
+
* - Requires a parent object — does nothing if the GameObject has no parent
|
|
30
|
+
* - Not intended to be added from code. For loading glTF assets at runtime,
|
|
31
|
+
* use {@link AssetReference.loadAsset} or {@link SceneSwitcher} instead
|
|
32
|
+
*
|
|
33
|
+
* **Unity Editor usage:**
|
|
34
|
+
* NestedGltf components are created automatically by the exporter when nesting GltfObject components:
|
|
35
|
+
* - A parent GameObject with a `GltfObject` component is exported as a `.glb` file
|
|
36
|
+
* - Any child GameObject that also has a `GltfObject` component is exported as a separate `.glb` file
|
|
37
|
+
* - The child's `GltfObject` is replaced with a `NestedGltf` reference pointing to that separate `.glb`
|
|
38
|
+
*
|
|
39
|
+
* ```
|
|
40
|
+
* Parent [GltfObject] → exported as parent.glb
|
|
41
|
+
* └─ Child [GltfObject] → exported as child.glb, replaced with NestedGltf in parent.glb
|
|
42
|
+
* ```
|
|
26
43
|
*
|
|
27
44
|
* @example Load a glTF when object becomes active
|
|
28
45
|
* ```ts
|
|
@@ -40,7 +57,6 @@ const debug = getParam("debugnestedgltf");
|
|
|
40
57
|
* // Later, when object becomes active, it displays instantly
|
|
41
58
|
* ```
|
|
42
59
|
*
|
|
43
|
-
* @summary Loads and instantiates a nested glTF file
|
|
44
60
|
* @category Asset Management
|
|
45
61
|
* @group Components
|
|
46
62
|
* @see {@link AssetReference} for asset loading utilities
|
|
@@ -37,7 +37,7 @@ const debug = getParam("debugnet");
|
|
|
37
37
|
* @see {@link RoomEvents} for room lifecycle events
|
|
38
38
|
* @see {@link isLocalNetwork} for local network detection
|
|
39
39
|
* @link https://engine.needle.tools/docs/how-to-guides/networking/
|
|
40
|
-
* @summary
|
|
40
|
+
* @summary Configures the websocket server URL for multiplayer networking
|
|
41
41
|
* @category Networking
|
|
42
42
|
* @group Components
|
|
43
43
|
*/
|
|
@@ -758,19 +758,26 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
758
758
|
|
|
759
759
|
if (this.targetBounds) {
|
|
760
760
|
// #region target bounds
|
|
761
|
-
const targetVector = this._controls.target;
|
|
762
761
|
const boundsCenter = this.targetBounds.worldPosition;
|
|
763
762
|
const boundsHalfSize = getTempVector(this.targetBounds.worldScale).multiplyScalar(0.5);
|
|
764
763
|
const min = getTempVector(boundsCenter).sub(boundsHalfSize);
|
|
765
764
|
const max = getTempVector(boundsCenter).add(boundsHalfSize);
|
|
766
|
-
|
|
767
|
-
const duration = .1;
|
|
768
|
-
if (duration <= 0) targetVector.copy(newTarget);
|
|
769
|
-
else targetVector.lerp(newTarget, this.context.time.deltaTime / duration);
|
|
765
|
+
|
|
770
766
|
if (this._lookTargetLerpActive) {
|
|
771
|
-
|
|
772
|
-
|
|
767
|
+
// During a programmatic transition (fitCamera / setLookTargetPosition with immediate: false),
|
|
768
|
+
// only clamp the destination. The look-target lerp (above) handles moving _controls.target
|
|
769
|
+
// towards the endpoint — we must not fight it by also lerping _controls.target here.
|
|
770
|
+
this._lookTargetEndPosition.clamp(min, max);
|
|
771
|
+
}
|
|
772
|
+
else {
|
|
773
|
+
// Interactive use (pan/orbit): smoothly push the target back into bounds
|
|
774
|
+
const targetVector = this._controls.target;
|
|
775
|
+
const newTarget = getTempVector(targetVector).clamp(min, max);
|
|
776
|
+
const duration = .1;
|
|
777
|
+
if (duration <= 0) targetVector.copy(newTarget);
|
|
778
|
+
else targetVector.lerp(newTarget, Math.min(1, this.context.time.deltaTime / duration));
|
|
773
779
|
}
|
|
780
|
+
|
|
774
781
|
if (debug) {
|
|
775
782
|
Gizmos.DrawWireBox(boundsCenter, boundsHalfSize.multiplyScalar(2), 0xffaa00);
|
|
776
783
|
}
|
|
@@ -847,7 +854,8 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
847
854
|
this._controls.update(this.context.time.deltaTime);
|
|
848
855
|
|
|
849
856
|
if (debug) {
|
|
850
|
-
|
|
857
|
+
const distance = this._controls.getDistance();
|
|
858
|
+
Gizmos.DrawWireSphere(this._controls.target, 0.01 * distance, 0x00ff00);
|
|
851
859
|
}
|
|
852
860
|
}
|
|
853
861
|
}
|
|
@@ -1022,7 +1030,8 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
1022
1030
|
|
|
1023
1031
|
if (debug) {
|
|
1024
1032
|
console.warn("OrbitControls: setLookTargetPosition", position, immediateOrDuration);
|
|
1025
|
-
|
|
1033
|
+
const distance = this._controls.getDistance();
|
|
1034
|
+
Gizmos.DrawWireSphere(this._lookTargetEndPosition, 0.01 * distance, 0xff5500, 2);
|
|
1026
1035
|
}
|
|
1027
1036
|
|
|
1028
1037
|
if (immediateOrDuration === true) {
|
|
@@ -4,7 +4,7 @@ import * as ThreeMeshUI from 'three-mesh-ui'
|
|
|
4
4
|
import { Mathf } from "../../engine/engine_math.js";
|
|
5
5
|
import { serializable } from "../../engine/engine_serialization_decorator.js";
|
|
6
6
|
import { FrameEvent } from "../../engine/engine_setup.js";
|
|
7
|
-
import {
|
|
7
|
+
import { getParam } from "../../engine/engine_utils.js";
|
|
8
8
|
import { type NeedleXREventArgs } from "../../engine/xr/api.js";
|
|
9
9
|
import { Camera } from "../Camera.js";
|
|
10
10
|
import { GameObject } from "../Component.js";
|
|
@@ -236,19 +236,13 @@ export class Canvas extends UIRootComponent implements ICanvas {
|
|
|
236
236
|
}
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
-
|
|
239
|
+
onEnterXR(args: NeedleXREventArgs) {
|
|
240
240
|
// workaround for https://linear.app/needle/issue/NE-4114
|
|
241
241
|
if (this.screenspace) {
|
|
242
242
|
if (args.xr.isVR || args.xr.isPassThrough) {
|
|
243
243
|
this.gameObject.visible = false;
|
|
244
244
|
}
|
|
245
245
|
}
|
|
246
|
-
else {
|
|
247
|
-
this.gameObject.visible = false;
|
|
248
|
-
await delayForFrames(1).then(()=>{
|
|
249
|
-
this.gameObject.visible = true;
|
|
250
|
-
});
|
|
251
|
-
}
|
|
252
246
|
}
|
|
253
247
|
onLeaveXR(args: NeedleXREventArgs): void {
|
|
254
248
|
if (this.screenspace) {
|
|
@@ -81,7 +81,24 @@ export class Text extends Graphic implements IHasAlphaFactor, ICanvasEventReceiv
|
|
|
81
81
|
@serializable()
|
|
82
82
|
supportRichText: boolean = false;
|
|
83
83
|
@serializable(URL)
|
|
84
|
-
font
|
|
84
|
+
set font(val: string | null) {
|
|
85
|
+
if (val !== this._font) {
|
|
86
|
+
this._font = val;
|
|
87
|
+
// If the font is assigned during deserialization it means the font URL MUST be resolved with the style suffix. If it's assigned at runtime by a user invocation and is absolute then we assume the user is prividing a full path to the font asset json or png
|
|
88
|
+
this._assignedAtRuntime = this.__didAwake;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
get font(): string | null {
|
|
92
|
+
return this._font;
|
|
93
|
+
}
|
|
94
|
+
private _font: string | null = null;
|
|
95
|
+
private _assignedAtRuntime: boolean = true;
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Whether to support basic rich text tags in the `text` property. Supported tags include `<b>`, `<i>`, and `<color=hex>`. For example: `Hello <b>World</b>` or `Score: <color=#ff0000>100</color>`
|
|
100
|
+
* @default false
|
|
101
|
+
*/
|
|
85
102
|
@serializable()
|
|
86
103
|
fontStyle: FontStyle = FontStyle.Normal;
|
|
87
104
|
|
|
@@ -224,8 +241,15 @@ export class Text extends Graphic implements IHasAlphaFactor, ICanvasEventReceiv
|
|
|
224
241
|
// fontSize /= this.canvas?.scaleFactor;
|
|
225
242
|
// }
|
|
226
243
|
|
|
227
|
-
|
|
228
|
-
|
|
244
|
+
const textOpts: {
|
|
245
|
+
color: Color,
|
|
246
|
+
fontOpacity: number,
|
|
247
|
+
fontSize: number,
|
|
248
|
+
fontKerning: string,
|
|
249
|
+
whiteSpace?: string,
|
|
250
|
+
overflow?: string,
|
|
251
|
+
lineHeight?: number
|
|
252
|
+
} = {
|
|
229
253
|
color: this.color,
|
|
230
254
|
fontOpacity: this.color.alpha,
|
|
231
255
|
fontSize: fontSize,
|
|
@@ -486,15 +510,16 @@ export class Text extends Graphic implements IHasAlphaFactor, ICanvasEventReceiv
|
|
|
486
510
|
* @private
|
|
487
511
|
*/
|
|
488
512
|
private setFont(opts: ThreeMeshUIEveryOptions, fontStyle: FontStyle) {
|
|
513
|
+
|
|
514
|
+
if (!this.font) {
|
|
515
|
+
if(debug) console.warn("No font set for Text component, skipping font setup");
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
489
518
|
|
|
490
|
-
// @TODO : THH could be useful to uniformize font family name :
|
|
491
|
-
// This would ease possible html/vr matching
|
|
492
|
-
// - Arial instead of assets/arial
|
|
493
|
-
// - Arial should stay Arial instead of arial
|
|
494
|
-
if (!this.font) return;
|
|
495
519
|
const fontName = this.font;
|
|
496
520
|
const familyName = this.getFamilyNameWithCorrectSuffix(fontName, fontStyle);
|
|
497
|
-
|
|
521
|
+
|
|
522
|
+
if (debug) console.log("Selected font family:" + familyName, this.font);
|
|
498
523
|
|
|
499
524
|
// ensure a font family is register under this name
|
|
500
525
|
let fontFamily = ThreeMeshUI.FontLibrary.getFontFamily(familyName as string);
|
|
@@ -527,9 +552,7 @@ export class Text extends Graphic implements IHasAlphaFactor, ICanvasEventReceiv
|
|
|
527
552
|
opts.fontWeight = 400;
|
|
528
553
|
}
|
|
529
554
|
|
|
530
|
-
|
|
531
555
|
// Ensure a fontVariant is registered
|
|
532
|
-
//@TODO: @swingingtom add type for fontWeight
|
|
533
556
|
let fontVariant = fontFamily.getVariant(opts.fontWeight as any as string, opts.fontStyle);
|
|
534
557
|
if (!fontVariant) {
|
|
535
558
|
let jsonPath = familyName;
|
|
@@ -550,13 +573,7 @@ export class Text extends Graphic implements IHasAlphaFactor, ICanvasEventReceiv
|
|
|
550
573
|
|
|
551
574
|
private getFamilyNameWithCorrectSuffix(familyName: string, style: FontStyle): string {
|
|
552
575
|
|
|
553
|
-
|
|
554
|
-
// the URL decorator resolves the URL to absolute URLs - we need to remove the domain part since we're only interested in the path
|
|
555
|
-
if (familyName.startsWith("https:") || familyName.startsWith("http:")) {
|
|
556
|
-
const url = new URL(familyName);
|
|
557
|
-
familyName = url.pathname;
|
|
558
|
-
}
|
|
559
|
-
|
|
576
|
+
const isAbsolute = familyName.startsWith("https:") || familyName.startsWith("http:");
|
|
560
577
|
|
|
561
578
|
// we can only change the style for the family if the name has a suffix (e.g. Arial-Bold)
|
|
562
579
|
const styleSeparator = familyName.lastIndexOf('-');
|
|
@@ -580,8 +597,16 @@ export class Text extends Graphic implements IHasAlphaFactor, ICanvasEventReceiv
|
|
|
580
597
|
}
|
|
581
598
|
const isUpperCase = fontBaseName[0] === fontBaseName[0].toUpperCase();
|
|
582
599
|
const fontNameWithoutSuffix = familyName.substring(0, styleSeparator > pathSeparatorIndex ? styleSeparator : familyName.length);
|
|
600
|
+
|
|
583
601
|
if (debug) console.log("Select font: ", familyName, FontStyle[style], fontBaseName, isUpperCase, fontNameWithoutSuffix);
|
|
584
602
|
|
|
603
|
+
/**
|
|
604
|
+
* If a user provides a font with an absolute URL AND the font name does not end with "-msdf.json" or ".png" (e.g. "https://example.com/fonts/Arial-Bold"), we will assume that the user is providing the full path to the font files and we will not try to modify the font name based on the style. This allows users to have more control over the font files they are using, especially if they are hosting their own fonts or using a custom font provider that does not follow the same naming conventions as our default fonts.
|
|
605
|
+
*/
|
|
606
|
+
if (isAbsolute && this._assignedAtRuntime && !(familyName.endsWith("-msdf.json") || familyName.endsWith(".png"))) {
|
|
607
|
+
return fontNameWithoutSuffix;
|
|
608
|
+
}
|
|
609
|
+
|
|
585
610
|
switch (style) {
|
|
586
611
|
case FontStyle.Normal:
|
|
587
612
|
if (isUpperCase) return fontNameWithoutSuffix + "-Regular";
|
|
@@ -289,20 +289,28 @@ export class CursorFollow extends Behaviour {
|
|
|
289
289
|
|
|
290
290
|
|
|
291
291
|
if (this.snapToSurface) {
|
|
292
|
-
ray.origin =
|
|
293
|
-
ray.direction = rayDirection
|
|
294
|
-
const hits = this.context.physics.raycastFromRay(ray
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
if (this.damping > 0) {
|
|
298
|
-
this.gameObject.worldPosition = _position.lerp(hit.point, this.context.time.deltaTime / this.damping);
|
|
299
|
-
}
|
|
300
|
-
else {
|
|
301
|
-
this.gameObject.worldPosition = hit.point;
|
|
292
|
+
ray.origin = cameraPosition;
|
|
293
|
+
ray.direction = rayDirection;
|
|
294
|
+
const hits = this.context.physics.raycastFromRay(ray, {
|
|
295
|
+
testObject: obj => {
|
|
296
|
+
return obj !== this.gameObject && !this.gameObject.contains(obj) ? true : false
|
|
302
297
|
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
298
|
+
});
|
|
299
|
+
if (hits?.length) {
|
|
300
|
+
// Get the first hit that is not a child of *this* object. Because we do not want to lerp to a surface that is part of the object itself, since that would result in *this* object moving closer and closer to the camera as it tries to snap to itself
|
|
301
|
+
const hit = hits[0];//.find(h => !this.gameObject.contains(h.object));
|
|
302
|
+
if (hit) {
|
|
303
|
+
if (this.damping > 0) {
|
|
304
|
+
this.gameObject.worldPosition = _position.lerp(hit.point, this.context.time.deltaTime / this.damping);
|
|
305
|
+
// this._distance = this.gameObject.worldPosition.distanceTo(cameraPosition);
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
this.gameObject.worldPosition = hit.point;
|
|
309
|
+
// this._distance = hit.point.distanceTo(cameraPosition);
|
|
310
|
+
}
|
|
311
|
+
if (debug) {
|
|
312
|
+
Gizmos.DrawLine(hit.point, hit.normal!.add(hit.point), 0x00FF00);
|
|
313
|
+
}
|
|
306
314
|
}
|
|
307
315
|
}
|
|
308
316
|
}
|
|
@@ -886,9 +886,11 @@ async function loadImage(url: string) {
|
|
|
886
886
|
}
|
|
887
887
|
const promise = new Promise<boolean>(res => {
|
|
888
888
|
_imageElements.set(url, null);
|
|
889
|
+
if(isDevEnvironment() || debug) console.debug(`[WebXRImageTracking] Start loading image for tracking: ${url}`);
|
|
889
890
|
const imageElement = document.createElement("img") as HTMLImageElement;
|
|
890
891
|
imageElement.src = url;
|
|
891
892
|
imageElement.addEventListener("load", async () => {
|
|
893
|
+
if(isDevEnvironment() || debug) console.debug(`[WebXRImageTracking] Loaded image for tracking: ${url}`);
|
|
892
894
|
const img = await createImageBitmap(imageElement);
|
|
893
895
|
_imageElements.set(url, img);
|
|
894
896
|
res(true);
|