@needle-tools/engine 4.11.5-next.753a642 → 4.11.5-next.a900688

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/CHANGELOG.md +7 -5
  2. package/components.needle.json +1 -1
  3. package/dist/{needle-engine.bundle-DVXwSz-d.js → needle-engine.bundle-Bwinyjsh.js} +3272 -3213
  4. package/dist/{needle-engine.bundle-OrbPGV3t.umd.cjs → needle-engine.bundle-Dsfd8BPk.umd.cjs} +109 -109
  5. package/dist/{needle-engine.bundle-CAKvhOvZ.min.js → needle-engine.bundle-vPWPv18K.min.js} +119 -119
  6. package/dist/needle-engine.d.ts +15 -15
  7. package/dist/needle-engine.js +2 -2
  8. package/dist/needle-engine.min.js +1 -1
  9. package/dist/needle-engine.umd.cjs +1 -1
  10. package/lib/engine/engine_assetdatabase.d.ts +6 -0
  11. package/lib/engine/engine_assetdatabase.js +15 -0
  12. package/lib/engine/engine_assetdatabase.js.map +1 -1
  13. package/lib/engine/engine_context.d.ts +14 -5
  14. package/lib/engine/engine_context.js +25 -4
  15. package/lib/engine/engine_context.js.map +1 -1
  16. package/lib/engine/engine_loaders.d.ts +0 -6
  17. package/lib/engine/engine_loaders.js +30 -29
  18. package/lib/engine/engine_loaders.js.map +1 -1
  19. package/lib/engine/engine_scenelighting.d.ts +12 -1
  20. package/lib/engine/engine_scenelighting.js +21 -1
  21. package/lib/engine/engine_scenelighting.js.map +1 -1
  22. package/lib/engine/extensions/NEEDLE_lightmaps.js +2 -2
  23. package/lib/engine/extensions/NEEDLE_lightmaps.js.map +1 -1
  24. package/lib/engine/extensions/extensions.d.ts +2 -2
  25. package/lib/engine/extensions/extensions.js +11 -5
  26. package/lib/engine/extensions/extensions.js.map +1 -1
  27. package/lib/engine/xr/NeedleXRSession.js +2 -1
  28. package/lib/engine/xr/NeedleXRSession.js.map +1 -1
  29. package/lib/engine-components/ReflectionProbe.js +16 -10
  30. package/lib/engine-components/ReflectionProbe.js.map +1 -1
  31. package/lib/engine-components/Renderer.js +2 -2
  32. package/lib/engine-components/Renderer.js.map +1 -1
  33. package/lib/engine-components/Skybox.d.ts +15 -5
  34. package/lib/engine-components/Skybox.js +37 -25
  35. package/lib/engine-components/Skybox.js.map +1 -1
  36. package/lib/engine-components/webxr/WebXR.js +4 -0
  37. package/lib/engine-components/webxr/WebXR.js.map +1 -1
  38. package/lib/engine-components/webxr/controllers/XRControllerModel.js +1 -1
  39. package/lib/engine-components/webxr/controllers/XRControllerModel.js.map +1 -1
  40. package/package.json +1 -1
  41. package/src/engine/engine_assetdatabase.ts +21 -0
  42. package/src/engine/engine_context.ts +36 -6
  43. package/src/engine/engine_loaders.ts +32 -30
  44. package/src/engine/engine_scenelighting.ts +30 -8
  45. package/src/engine/extensions/NEEDLE_lightmaps.ts +2 -2
  46. package/src/engine/extensions/extensions.ts +11 -5
  47. package/src/engine/xr/NeedleXRSession.ts +3 -1
  48. package/src/engine-components/ReflectionProbe.ts +18 -10
  49. package/src/engine-components/Renderer.ts +2 -2
  50. package/src/engine-components/Skybox.ts +47 -36
  51. package/src/engine-components/webxr/WebXR.ts +4 -0
  52. package/src/engine-components/webxr/controllers/XRControllerModel.ts +1 -1
@@ -1,4 +1,4 @@
1
- import { EquirectangularReflectionMapping, LightProbe, SphericalHarmonics3, SRGBColorSpace,Texture, Vector4, WebGLCubeRenderTarget } from "three";
1
+ import { EquirectangularReflectionMapping, LightProbe, Source, SphericalHarmonics3, SRGBColorSpace, Texture, Vector4, WebGLCubeRenderTarget } from "three";
2
2
 
3
3
  import { AssetReference } from "./engine_addressables.js";
4
4
  import { Context } from "./engine_setup.js";
@@ -44,9 +44,16 @@ export class RendererData {
44
44
  this.context.pre_update_callbacks.push(this.preUpdate.bind(this))
45
45
  }
46
46
 
47
+ /**
48
+ * The id of the currently active scene light settings (source identifier).
49
+ */
47
50
  private _currentLightSettingsId?: SourceIdentifier;
48
51
  private _sceneLightSettings?: Map<SourceIdentifier, SceneLightSettings>;
49
52
 
53
+ get currentLightSettingsId(): SourceIdentifier | undefined {
54
+ return this._currentLightSettingsId;
55
+ }
56
+
50
57
  private preUpdate() {
51
58
  const time = this.context.time;
52
59
  this._timevec4.x = time.time;
@@ -82,11 +89,11 @@ export class RendererData {
82
89
 
83
90
  /** set the scene lighting from a specific scene. Will disable any previously enabled lighting settings */
84
91
  enable(sourceId: SourceIdentifier | AssetReference) {
85
- if(sourceId instanceof AssetReference)
92
+ if (sourceId instanceof AssetReference)
86
93
  sourceId = sourceId.url;
87
94
  const settings = this._sceneLightSettings?.get(sourceId);
88
95
  if (!settings) {
89
- if(debug) console.warn("No light settings found for", sourceId);
96
+ if (debug) console.warn("No light settings found for", sourceId);
90
97
  return false;
91
98
  }
92
99
  if (debug) console.log("Enable scene light settings", sourceId, settings);
@@ -100,7 +107,7 @@ export class RendererData {
100
107
 
101
108
  /** disable the lighting of a specific scene, will only have any effect if it is currently active */
102
109
  disable(sourceId: SourceIdentifier | AssetReference) {
103
- if(sourceId instanceof AssetReference)
110
+ if (sourceId instanceof AssetReference)
104
111
  sourceId = sourceId.url;
105
112
  if (sourceId === null || sourceId === undefined) return false;
106
113
  const settings = this._sceneLightSettings?.get(sourceId);
@@ -112,8 +119,22 @@ export class RendererData {
112
119
  return true;
113
120
  }
114
121
 
115
- /** Disables the currently active scene lighting (if any), returns the id of the previously active lighting */
116
- disableCurrent() : SourceIdentifier | null {
122
+ /**
123
+ * Enables the currently active scene lighting (if any), returns the id of the enabled lighting.
124
+ * @returns The id of the enabled lighting, or null if no lighting is currently active.
125
+ */
126
+ enableCurrent(): SourceIdentifier | null {
127
+ if (this._currentLightSettingsId) {
128
+ this.enable(this._currentLightSettingsId);
129
+ return this._currentLightSettingsId ?? null;
130
+ }
131
+ return null;
132
+ }
133
+
134
+ /** Disables the currently active scene lighting (if any), returns the id of the previously active lighting
135
+ * @returns The id of the previously active lighting, or null if no lighting was active.
136
+ */
137
+ disableCurrent(): SourceIdentifier | null {
117
138
  if (this._currentLightSettingsId) {
118
139
  const prev = this._currentLightSettingsId;
119
140
  this.disable(this._currentLightSettingsId);
@@ -162,7 +183,7 @@ export class RendererData {
162
183
  private __currentReflectionId: SourceIdentifier | null = null;
163
184
 
164
185
  /** @internal */
165
- internalEnableReflection(sourceId: SourceIdentifier) : Texture | null {
186
+ internalEnableReflection(sourceId: SourceIdentifier): Texture | null {
166
187
  this.__currentReflectionId = sourceId;
167
188
  const settings = this._sceneLightSettings?.get(sourceId);
168
189
 
@@ -181,6 +202,7 @@ export class RendererData {
181
202
  const tex = existing.Source;
182
203
  tex.mapping = EquirectangularReflectionMapping;
183
204
  scene.environment = tex;
205
+ scene.environmentIntensity = this.environmentIntensity || 1;
184
206
  return tex;
185
207
  }
186
208
  else if (debug) console.warn("Could not find reflection for source", sourceId);
@@ -216,7 +238,7 @@ export class RendererData {
216
238
  /** @internal */
217
239
  internalDisableReflection(sourceId?: SourceIdentifier) {
218
240
  if (sourceId && sourceId !== this.__currentReflectionId) {
219
- if(debug) console.log("Not disabling reflection for", sourceId, "because it is not the current light settings id", this.__currentReflectionId)
241
+ if (debug) console.log("Not disabling reflection for", sourceId, "because it is not the current light settings id", this.__currentReflectionId)
220
242
  return;
221
243
  }
222
244
  if (debug) console.log("Disable reflection", sourceId)
@@ -95,8 +95,8 @@ export class NEEDLE_lightmaps implements GLTFLoaderPlugin {
95
95
  }
96
96
  const results = await PromiseAllWithErrors(dependencies);
97
97
  if (results?.anyFailed) {
98
- if (isDevEnvironment())
99
- console.error("Failed to load lightmap extension", results);
98
+ if (isDevEnvironment() || debug)
99
+ console.error("[NEEDLE_lightmaps]Error during extension loading:", results);
100
100
  }
101
101
  resolve();
102
102
  });
@@ -92,18 +92,24 @@ class PointerResolver {
92
92
  }
93
93
  }
94
94
 
95
- export async function registerExtensions(loader: GLTFLoader, context: Context, url: string) {
95
+ export async function registerExtensions(loader: GLTFLoader, context: Context, url: string, sourceId: SourceIdentifier) {
96
96
 
97
97
  // Make sure to remove any url parameters from the sourceId (because the source id in the renderer does not have a ?v=xxx so it will not be able to register the resolved lightmap otherwise)
98
98
  const idEnd = url.indexOf("?");
99
99
  if (idEnd >= 0) url = url.substring(0, idEnd);
100
+ if (!sourceId) {
101
+ sourceId = url;
102
+ }
103
+ if (sourceId.startsWith("blob:") || sourceId.startsWith("data:")) {
104
+ console.debug("[GLTFLoader] Suspicious sourceId detected");
105
+ }
100
106
 
101
107
  loader.register(p => new NEEDLE_gameobject_data(p));
102
108
  loader.register(p => new NEEDLE_persistent_assets(p));
103
- loader.register(p => new NEEDLE_lightmaps(p, context.lightmaps, url));
104
- loader.register(p => new NEEDLE_lighting_settings(p, url, context));
105
- loader.register(p => new NEEDLE_techniques_webgl(p, url));
106
- loader.register(p => new NEEDLE_render_objects(p, url));
109
+ loader.register(p => new NEEDLE_lightmaps(p, context.lightmaps, sourceId));
110
+ loader.register(p => new NEEDLE_lighting_settings(p, sourceId, context));
111
+ loader.register(p => new NEEDLE_techniques_webgl(p, sourceId));
112
+ loader.register(p => new NEEDLE_render_objects(p, sourceId));
107
113
  loader.register(p => new NEEDLE_progressive(p));
108
114
  loader.register(p => new EXT_texture_exr(p));
109
115
  if (isResourceTrackingEnabled()) loader.register(p => new InternalUsageTrackerPlugin(p))
@@ -527,7 +527,9 @@ export class NeedleXRSession implements INeedleXRSession {
527
527
  else
528
528
  console.log("%c" + `Requesting ${mode} session`, "font-weight:bold;");
529
529
  for (const script of scripts) {
530
- if (script.onBeforeXR) script.onBeforeXR(mode, init);
530
+ if (script.onBeforeXR && script.activeAndEnabled && !script.destroyed) {
531
+ script.onBeforeXR(mode, init);
532
+ }
531
533
  }
532
534
  for (const listener of this._sessionRequestStartListeners) {
533
535
  listener({ mode, init });
@@ -1,4 +1,4 @@
1
- import { EquirectangularReflectionMapping, LinearSRGBColorSpace, Material, MeshBasicMaterial, Object3D, SRGBColorSpace, Texture, Vector3 } from "three";
1
+ import { CubeReflectionMapping, CubeTexture, EquirectangularReflectionMapping, LinearSRGBColorSpace, Material, MeshBasicMaterial, Object3D, SRGBColorSpace, Texture, Vector3 } from "three";
2
2
 
3
3
  import { isDevEnvironment, showBalloonWarning } from "../engine/debug/index.js";
4
4
  import { serializable } from "../engine/engine_serialization.js";
@@ -63,13 +63,19 @@ export class ReflectionProbe extends Behaviour {
63
63
 
64
64
  // @serializable(Texture)
65
65
  set texture(tex: Texture) {
66
- if (tex && !(tex instanceof Texture)) {
67
- console.error("ReflectionProbe.texture must be a Texture", tex);
68
- return;
69
- }
66
+
67
+ if (this._texture === tex) return;
70
68
  this._texture = tex;
69
+
70
+ if (debug) console.debug("[ReflectionProbe] Set reflection probe texture " + (tex?.name || "(removed)"));
71
+
71
72
  if (tex) {
72
- tex.mapping = EquirectangularReflectionMapping;
73
+ if (tex instanceof CubeTexture) {
74
+ // cube textures use CubeReflectionMapping by default
75
+ }
76
+ else if (tex.mapping !== EquirectangularReflectionMapping) {
77
+ tex.mapping = EquirectangularReflectionMapping;
78
+ }
73
79
  tex.colorSpace = LinearSRGBColorSpace;
74
80
  tex.needsUpdate = true;
75
81
  }
@@ -110,9 +116,8 @@ export class ReflectionProbe extends Behaviour {
110
116
  }
111
117
  }
112
118
  start(): void {
113
- if (!this._texture && isDevEnvironment()) {
119
+ if (!this._texture) {
114
120
  console.warn(`[ReflectionProbe] Missing texture. Please assign a custom cubemap texture. To use reflection probes assign them to your renderer's "anchor" property.`);
115
- showBalloonWarning("ReflectionProbe configuration hint: See browser console for details")
116
121
  }
117
122
  }
118
123
 
@@ -206,8 +211,11 @@ export class ReflectionProbe extends Behaviour {
206
211
  /** this is the material that we copied and that has the reflection probe */
207
212
  const copy = cached?.copy;
208
213
 
209
- // make sure the reflection probe is assigned
210
- copy["envMap"] = this.texture;
214
+ if ("envMap" in copy) {
215
+ // make sure the reflection probe is assigned
216
+ copy.envMap = this.texture;
217
+ copy.needsUpdate = true;
218
+ }
211
219
 
212
220
  _rend.sharedMaterials[i] = copy;
213
221
  }
@@ -702,7 +702,6 @@ export class Renderer extends Behaviour implements IRenderer {
702
702
  // If the material has a envMap and is NOT using a reflection probe we set the envMap to the scene environment
703
703
  if (mat && "envMap" in mat && "envMapIntensity" in mat && !ReflectionProbe.isUsingReflectionProbe(mat)) {
704
704
  mat.envMap = this.context.scene.environment;
705
- mat.envMapIntensity = this.context.scene.environmentIntensity;
706
705
  mat.envMapRotation = this.context.scene.environmentRotation;
707
706
  }
708
707
  }
@@ -713,8 +712,9 @@ export class Renderer extends Behaviour implements IRenderer {
713
712
  private onBeforeRenderThree = (_renderer, _scene, _camera, _geometry, material, _group) => {
714
713
  if (material.envMapIntensity !== undefined) {
715
714
  const factor = this.hasLightmap ? Math.PI : 1;
716
- const environmentIntensity = this.context.mainCameraComponent?.environmentIntensity ?? 1;
715
+ const environmentIntensity = this.context.scene.environmentIntensity;
717
716
  material.envMapIntensity = Math.max(0, environmentIntensity * this.context.sceneLighting.environmentIntensity / factor);
717
+ // console.log(this.context.sceneLighting.environmentIntensity);
718
718
  }
719
719
  if (this._lightmaps) {
720
720
  for (const lm of this._lightmaps) {
@@ -1,16 +1,14 @@
1
- import { CompressedCubeTexture, CubeRefractionMapping, CubeTexture, CubeUVReflectionMapping, EquirectangularRefractionMapping, SRGBColorSpace, Texture, TextureLoader } from "three"
2
- import { EXRLoader } from "three/examples/jsm/loaders/EXRLoader.js";
3
- import { KTX2Loader } from "three/examples/jsm/loaders/KTX2Loader.js";
4
- import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js';
1
+ import { CompressedCubeTexture, CubeTexture, CubeUVReflectionMapping, EquirectangularRefractionMapping, Texture } from "three"
2
+ import { isDevEnvironment } from "../engine/debug/debug.js";
5
3
 
6
4
  import { ContextEvent, ContextRegistry } from "../engine/engine_context_registry.js";
7
5
  import { syncField } from "../engine/engine_networking_auto.js";
8
6
  import { loadPMREM } from "../engine/engine_pmrem.js";
9
7
  import { serializable } from "../engine/engine_serialization_decorator.js";
10
8
  import { type IContext } from "../engine/engine_types.js";
11
- import { addAttributeChangeCallback, getParam, PromiseAllWithErrors, removeAttributeChangeCallback, toSourceId } from "../engine/engine_utils.js";
9
+ import { addAttributeChangeCallback, getParam, removeAttributeChangeCallback, toSourceId } from "../engine/engine_utils.js";
12
10
  import { registerObservableAttribute } from "../engine/webcomponents/needle-engine.extras.js";
13
- import { Camera, ClearFlags } from "./Camera.js";
11
+ import { Camera } from "./Camera.js";
14
12
  import { Behaviour, GameObject } from "./Component.js";
15
13
 
16
14
  const debug = getParam("debugskybox");
@@ -18,6 +16,29 @@ const debug = getParam("debugskybox");
18
16
  registerObservableAttribute("background-image");
19
17
  registerObservableAttribute("environment-image");
20
18
 
19
+
20
+ type MagicSkyboxName = "studio" | "blurred-skybox" | "quicklook-ar" | "quicklook";
21
+ const MagicSkyboxNames: Record<MagicSkyboxName, { url: string, url_low: string }> = {
22
+ "studio": {
23
+ url: "https://cdn.needle.tools/static/skybox/modelviewer-Neutral.pmrem4x4.ktx2?pmrem",
24
+ url_low: "https://cdn.needle.tools/static/skybox/modelviewer-Neutral-small.pmrem4x4.ktx2?pmrem"
25
+ },
26
+ "blurred-skybox": {
27
+ url: "https://cdn.needle.tools/static/skybox/blurred-skybox.pmrem4x4.ktx2?pmrem",
28
+ url_low: "https://cdn.needle.tools/static/skybox/blurred-skybox-small.pmrem4x4.ktx2?pmrem"
29
+ },
30
+ "quicklook-ar": {
31
+ url: "https://cdn.needle.tools/static/skybox/QuickLook-ARMode.pmrem4x4.ktx2?pmrem",
32
+ url_low: "https://cdn.needle.tools/static/skybox/QuickLook-ARMode-small.pmrem4x4.ktx2?pmrem"
33
+ },
34
+ "quicklook": {
35
+ url: "https://cdn.needle.tools/static/skybox/QuickLook-ObjectMode.pmrem4x4.ktx2?pmrem",
36
+ url_low: "https://cdn.needle.tools/static/skybox/QuickLook-ObjectMode-small.pmrem4x4.ktx2?pmrem"
37
+ }
38
+ } as const;
39
+ type AnyString = string & { _brand?: never };
40
+
41
+
21
42
  function createRemoteSkyboxComponent(context: IContext, url: string, skybox: boolean, environment: boolean, attribute: "background-image" | "environment-image") {
22
43
 
23
44
  // when the user sets the attribute to a color we can not handle it as a skybox url.
@@ -91,8 +112,9 @@ ContextRegistry.registerCallback(ContextEvent.ContextCreationStart, () => {
91
112
  });
92
113
 
93
114
 
115
+
94
116
  /**
95
- * RemoteSkybox is a component that allows you to set the skybox of a scene from a URL or a local file.
117
+ * RemoteSkybox is a component that allows you to set the skybox or environment texture of a scene from a URL, a local file or a static skybox name.
96
118
  * It supports .hdr, .exr, .jpg, .png files.
97
119
  *
98
120
  * ### Events
@@ -127,8 +149,13 @@ ContextRegistry.registerCallback(ContextEvent.ContextCreationStart, () => {
127
149
  export class RemoteSkybox extends Behaviour {
128
150
 
129
151
  /**
130
- * URL to a remote skybox. This value can also use a magic skybox name. Options are "quicklook", "quicklook-ar", "studio", "blurred-skybox".
131
- * To update the skybox/environment map use `setSkybox(url)`
152
+ * URL to a remote skybox.
153
+ * To update the skybox/environment map use `setSkybox(url)`.
154
+ *
155
+ * The url can also be set to a magic skybox name.
156
+ * Magic name options are: "quicklook", "quicklook-ar", "studio", "blurred-skybox".
157
+ * These will resolve to built-in skyboxes hosted on the Needle CDN that are static, optimized for the web and will never change.
158
+ *
132
159
  * @example
133
160
  * ```ts
134
161
  * skybox.url = "https://example.com/skybox.hdr";
@@ -136,7 +163,7 @@ export class RemoteSkybox extends Behaviour {
136
163
  */
137
164
  @syncField(RemoteSkybox.prototype.urlChangedSyncField)
138
165
  @serializable(URL)
139
- url?: string;
166
+ url: MagicSkyboxName | AnyString = "studio";
140
167
 
141
168
  /**
142
169
  * When enabled a user can drop a link to a skybox image on the scene to set the skybox.
@@ -208,7 +235,7 @@ export class RemoteSkybox extends Behaviour {
208
235
  * @param name Define name of the file with extension if it isn't apart of the url
209
236
  * @returns Whether the skybox was successfully set
210
237
  */
211
- async setSkybox(url: string | undefined | null, name?: string) {
238
+ async setSkybox(url: MagicSkyboxName | AnyString | undefined | null, name?: string) {
212
239
  if (!this.activeAndEnabled) return false;
213
240
 
214
241
  url = tryParseMagicSkyboxName(url, this.environment, this.background);
@@ -404,38 +431,22 @@ export class RemoteSkybox extends Behaviour {
404
431
 
405
432
 
406
433
 
407
-
408
434
  function tryParseMagicSkyboxName(str: string | null | undefined, environment: boolean, background: boolean): string | null {
409
435
 
410
436
  if (str === null || str === undefined) return null;
411
437
 
412
438
  const useLowRes = environment && !background;
413
439
 
414
- switch (str.toLowerCase()) {
415
- case "studio":
416
- if (useLowRes) {
417
- return "https://cdn.needle.tools/static/skybox/modelviewer-Neutral-small.pmrem4x4.ktx2?pmrem";
418
- }
419
- return "https://cdn.needle.tools/static/skybox/modelviewer-Neutral.pmrem4x4.ktx2?pmrem";
420
-
421
- case "blurred-skybox":
422
- if (useLowRes) {
423
- return "https://cdn.needle.tools/static/skybox/blurred-skybox-small.pmrem4x4.ktx2?pmrem";
424
- }
425
- return "https://cdn.needle.tools/static/skybox/blurred-skybox.pmrem4x4.ktx2?pmrem";
426
- case "quicklook-ar":
427
- if (useLowRes) {
428
- return "https://cdn.needle.tools/static/skybox/QuickLook-ARMode-small.pmrem4x4.ktx2?pmrem";
429
- }
430
- return "https://cdn.needle.tools/static/skybox/QuickLook-ARMode.pmrem4x4.ktx2?pmrem";
431
- case "quicklook":
432
- if (useLowRes) {
433
- return "https://cdn.needle.tools/static/skybox/QuickLook-ObjectMode-small.pmrem4x4.ktx2?pmrem";
434
- }
435
- return "https://cdn.needle.tools/static/skybox/QuickLook-ObjectMode.pmrem4x4.ktx2?pmrem";
440
+ const value = MagicSkyboxNames[str.toLowerCase() as MagicSkyboxName];
441
+ if (value) {
442
+ return useLowRes ? value.url_low : value.url;
443
+ }
444
+ else if (typeof str === "string" && str?.length && (isDevEnvironment() || debug)) {
445
+ const noUrlOrFile = !str.startsWith("http") && !str.startsWith("file:") && !str.startsWith("blob:") && !str.startsWith("data:");
446
+ if(noUrlOrFile) {
447
+ console.warn(`RemoteSkybox: Unknown magic skybox name "${str}". Valid names are: ${Object.keys(MagicSkyboxNames).map(n => `"${n}"`).join(", ")}`);
448
+ }
436
449
  }
437
-
438
-
439
450
 
440
451
  return str;
441
452
  }
@@ -331,6 +331,10 @@ export class WebXR extends Behaviour {
331
331
  console.warn(`WebXR: another WebXR component is already active (${WebXR.activeWebXRComponent?.name}). This is ignored: ${this.name}`);
332
332
  return;
333
333
  }
334
+ if (this.activeAndEnabled === false || this.destroyed) {
335
+ console.debug("[WebXR] onBeforeXR called on disabled or destroyed component");
336
+ return;
337
+ }
334
338
  WebXR.activeWebXRComponent = this;
335
339
 
336
340
  if (_mode == "immersive-ar" && this.useDepthSensing) {
@@ -284,7 +284,7 @@ export class XRControllerModel extends Behaviour {
284
284
 
285
285
  const loader = new GLTFLoader();
286
286
  addDracoAndKTX2Loaders(loader, context);
287
- await registerExtensions(loader, context, this.sourceId ?? "");
287
+ await registerExtensions(loader, context, this.sourceId ?? "", this.sourceId ?? "");
288
288
  const componentsExtension = registerComponentExtension(loader);
289
289
 
290
290
  let filename = "";