@needle-tools/engine 4.16.4-next.25d6ead → 4.16.4-next.2cea5b7

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 (68) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/dist/{gltf-progressive-LOFTyzy4.umd.cjs → gltf-progressive-BacJPTD6.umd.cjs} +8 -8
  3. package/dist/{gltf-progressive-DQa78GTA.min.js → gltf-progressive-BmXoz_HR.min.js} +8 -8
  4. package/dist/{gltf-progressive-_wvokUUu.js → gltf-progressive-CzxjNmG6.js} +116 -107
  5. package/dist/{needle-engine.bundle-CAIr8Hz9.umd.cjs → needle-engine.bundle-9ZlmXJ92.umd.cjs} +141 -141
  6. package/dist/{needle-engine.bundle-CC-oMhHW.js → needle-engine.bundle-B48_Odba.js} +5912 -5898
  7. package/dist/{needle-engine.bundle-Cmi3snfO.min.js → needle-engine.bundle-BLua7xvv.min.js} +142 -142
  8. package/dist/needle-engine.d.ts +15 -4
  9. package/dist/needle-engine.js +3 -3
  10. package/dist/needle-engine.min.js +1 -1
  11. package/dist/needle-engine.umd.cjs +1 -1
  12. package/lib/engine/debug/debug.d.ts +4 -1
  13. package/lib/engine/debug/debug.js +25 -1
  14. package/lib/engine/debug/debug.js.map +1 -1
  15. package/lib/engine/debug/debug_spatial_console.js +1 -1
  16. package/lib/engine/debug/debug_spatial_console.js.map +1 -1
  17. package/lib/engine/engine_components.js +3 -6
  18. package/lib/engine/engine_components.js.map +1 -1
  19. package/lib/engine/engine_lods.d.ts +9 -1
  20. package/lib/engine/engine_lods.js +9 -1
  21. package/lib/engine/engine_lods.js.map +1 -1
  22. package/lib/engine/engine_mainloop_utils.js +49 -60
  23. package/lib/engine/engine_mainloop_utils.js.map +1 -1
  24. package/lib/engine/engine_three_utils.js +7 -13
  25. package/lib/engine/engine_three_utils.js.map +1 -1
  26. package/lib/engine/extensions/NEEDLE_animator_controller_model.d.ts +1 -1
  27. package/lib/engine/webcomponents/WebXRButtons.js +13 -11
  28. package/lib/engine/webcomponents/WebXRButtons.js.map +1 -1
  29. package/lib/engine/webcomponents/buttons.js +4 -4
  30. package/lib/engine/webcomponents/buttons.js.map +1 -1
  31. package/lib/engine/webcomponents/needle menu/needle-menu.js +8 -3
  32. package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
  33. package/lib/engine/webcomponents/needle-engine.d.ts +6 -2
  34. package/lib/engine/webcomponents/needle-engine.js +56 -41
  35. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  36. package/lib/engine-components/AnimatorController.d.ts +1 -1
  37. package/lib/engine-components/export/usdz/USDZExporter.js +0 -7
  38. package/lib/engine-components/export/usdz/USDZExporter.js.map +1 -1
  39. package/lib/engine-components/timeline/TimelineTracks.d.ts +1 -1
  40. package/lib/engine-components/timeline/TimelineTracks.js +2 -4
  41. package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
  42. package/package.json +4 -6
  43. package/src/engine/debug/debug.ts +26 -1
  44. package/src/engine/debug/debug_spatial_console.ts +1 -1
  45. package/src/engine/engine_components.ts +3 -6
  46. package/src/engine/engine_lods.ts +10 -2
  47. package/src/engine/engine_mainloop_utils.ts +54 -62
  48. package/src/engine/engine_three_utils.ts +7 -15
  49. package/src/engine/extensions/NEEDLE_animator_controller_model.ts +1 -1
  50. package/src/engine/webcomponents/WebXRButtons.ts +13 -12
  51. package/src/engine/webcomponents/buttons.ts +4 -4
  52. package/src/engine/webcomponents/needle menu/needle-menu.ts +7 -3
  53. package/src/engine/webcomponents/needle-engine.ts +62 -47
  54. package/src/engine-components/AnimatorController.ts +1 -1
  55. package/src/engine-components/export/usdz/USDZExporter.ts +0 -8
  56. package/src/engine-components/timeline/TimelineTracks.ts +2 -6
  57. package/lib/engine/debug/debug_environment.d.ts +0 -4
  58. package/lib/engine/debug/debug_environment.js +0 -26
  59. package/lib/engine/debug/debug_environment.js.map +0 -1
  60. package/lib/engine/webcomponents/needle menu/menu-priority.d.ts +0 -10
  61. package/lib/engine/webcomponents/needle menu/menu-priority.js +0 -21
  62. package/lib/engine/webcomponents/needle menu/menu-priority.js.map +0 -1
  63. package/lib/engine/webcomponents/quicklook-handler.d.ts +0 -29
  64. package/lib/engine/webcomponents/quicklook-handler.js +0 -21
  65. package/lib/engine/webcomponents/quicklook-handler.js.map +0 -1
  66. package/src/engine/debug/debug_environment.ts +0 -26
  67. package/src/engine/webcomponents/needle menu/menu-priority.ts +0 -20
  68. package/src/engine/webcomponents/quicklook-handler.ts +0 -37
@@ -586,17 +586,12 @@ export class Graphics {
586
586
  this.scene.children.length = 0;
587
587
  this.scene.add(mesh);
588
588
 
589
- // Save state
590
589
  const renderTarget = renderer.getRenderTarget();
591
- const gl = renderer.getContext();
592
- const depthTestEnabled = gl.getParameter(gl.DEPTH_TEST);
593
- const depthWriteMask = gl.getParameter(gl.DEPTH_WRITEMASK);
594
- const depthFunc = gl.getParameter(gl.DEPTH_FUNC);
595
-
596
590
 
597
591
  // Set state
598
- if (depthTest) renderer.getContext().enable(renderer.getContext().DEPTH_TEST);
599
- else renderer.getContext().disable(renderer.getContext().DEPTH_TEST);
592
+ const gl = renderer.getContext();
593
+ if (depthTest) gl.enable(gl.DEPTH_TEST);
594
+ else gl.disable(gl.DEPTH_TEST);
600
595
  renderer.state.buffers.depth.setMask(depthWrite);
601
596
 
602
597
  renderer.setClearColor(new Color(0, 0, 0), 0);
@@ -608,13 +603,10 @@ export class Graphics {
608
603
  renderer.clear();
609
604
  renderer.render(this.scene, this.perspectiveCam);
610
605
 
611
-
612
- // Restore state
613
- renderer.setRenderTarget(renderTarget); // reset render target
614
- const depthBuffer = renderer.state.buffers.depth;
615
- depthBuffer.setTest(depthTestEnabled);
616
- depthBuffer.setMask(depthWriteMask);
617
- depthBuffer.setFunc(depthFunc);
606
+ // Restore defaults (not using gl.getParameter to save/restore — it causes a synchronous GPU-CPU stall)
607
+ renderer.setRenderTarget(renderTarget);
608
+ gl.enable(gl.DEPTH_TEST);
609
+ renderer.state.buffers.depth.setMask(true);
618
610
  }
619
611
 
620
612
  /**
@@ -1,7 +1,7 @@
1
1
  import { AnimationAction, AnimationClip, MathUtils, Object3D } from "three"
2
2
 
3
3
  import { InstantiateIdProvider } from "../../engine/engine_networking_instantiate.js";
4
- import type { Animator } from "../../engine-components/Animator.js";
4
+ import { Animator } from "../../engine-components/Animator.js";
5
5
  import { Context } from "../engine_setup.js";
6
6
 
7
7
 
@@ -1,4 +1,6 @@
1
+ import { USDZExporter } from "../../engine-components/export/usdz/USDZExporter.js";
1
2
  import { isDevEnvironment, showBalloonMessage } from "../debug/index.js";
3
+ import { findObjectOfType } from "../engine_components.js";
2
4
  import { Context } from "../engine_setup.js";
3
5
  import { DeviceUtilities } from "../engine_utils.js";
4
6
  import { NeedleXRSession } from "../engine_xr.js";
@@ -6,7 +8,6 @@ import { onXRSessionEnd, onXRSessionStart } from "../xr/events.js";
6
8
  import { ButtonsFactory } from "./buttons.js";
7
9
  import { getIconElement } from "./icons.js";
8
10
  import { NeedleMenu } from "./needle menu/needle-menu.js";
9
- import { getOrCreateQuicklookHandler,type IQuicklookHandler } from "./quicklook-handler.js";
10
11
 
11
12
  // TODO: move these buttons into their own web components so their logic is encapsulated (e.g. the CSS animation when a xr session is requested)
12
13
 
@@ -75,22 +76,22 @@ export class WebXRButtonFactory {
75
76
  NeedleMenu.setElementPriority(button, quicklookButtonPriority);
76
77
 
77
78
  let createdExporter = false;
78
- let quicklookHandler: IQuicklookHandler | null = null;
79
+ let usdzExporter: USDZExporter | null = null;
79
80
  button.addEventListener("click", () => {
80
- const result = getOrCreateQuicklookHandler();
81
+ usdzExporter = findObjectOfType(USDZExporter);
81
82
 
82
- if (result) {
83
- quicklookHandler = result.handler;
84
- createdExporter = result.created;
83
+ // if the scene doesnt have an USDZExporter component, create one
84
+ if (!usdzExporter) {
85
+ createdExporter = true;
86
+ usdzExporter = new USDZExporter();
85
87
  }
88
+ // if we have created a USDZExporter
89
+ if (createdExporter)
90
+ usdzExporter.objectToExport = Context.Current.scene;
86
91
 
87
- // if we have created a handler
88
- if (createdExporter && quicklookHandler)
89
- quicklookHandler.objectToExport = Context.Current.scene;
90
-
91
- if (quicklookHandler) {
92
+ if (usdzExporter) {
92
93
  button.classList.add("this-mode-is-requested");
93
- quicklookHandler.exportAndOpen().then(() => {
94
+ usdzExporter.exportAndOpen().then(() => {
94
95
  button.classList.remove("this-mode-is-requested");
95
96
  }).catch(err => {
96
97
  button.classList.remove("this-mode-is-requested");
@@ -3,7 +3,7 @@ import { IContext } from "../engine_types.js";
3
3
  import { generateQRCode } from "../engine_utils_qrcode.js";
4
4
  import { onXRSessionEnd, onXRSessionStart } from "../xr/events.js";
5
5
  import { getIconElement } from "./icons.js";
6
- import { setElementPriority } from "./needle menu/menu-priority.js";
6
+ import { NeedleMenu } from "./needle menu/needle-menu.js";
7
7
 
8
8
  /**
9
9
  * Use the ButtonsFactory to create buttons with icons and functionality
@@ -67,7 +67,7 @@ export class ButtonsFactory {
67
67
  this._fullscreenButton = button;
68
68
  button.classList.add("fullscreen-button");
69
69
  button.title = "Click to enter fullscreen mode";
70
- setElementPriority(button, 3);
70
+ NeedleMenu.setElementPriority(button, 3);
71
71
  const enterFullscreenIcon = getIconElement("fullscreen");
72
72
  const exitFullscreenIcon = getIconElement("fullscreen_exit");
73
73
  button.appendChild(enterFullscreenIcon);
@@ -119,7 +119,7 @@ export class ButtonsFactory {
119
119
  const muteIcon = getIconElement("volume_off");
120
120
  const unmuteIcon = getIconElement("volume_up");
121
121
 
122
- setElementPriority(button, 1);
122
+ NeedleMenu.setElementPriority(button, 1);
123
123
 
124
124
  // save state in session storage (this needs consent)
125
125
  // if (sessionStorage.getItem("muted") === "true") {
@@ -191,7 +191,7 @@ export class ButtonsFactory {
191
191
  qrCodeButton.prepend(getIconElement("qr_code"));
192
192
  qrCodeButton.title = "Scan this QR code with your phone to open this page";
193
193
  this.hideElementDuringXRSession(qrCodeButton);
194
- setElementPriority(this._qrButton, 20);
194
+ NeedleMenu.setElementPriority(this._qrButton, 20);
195
195
 
196
196
  const qrCodeContainer = document.createElement("div");
197
197
  qrCodeContainer.style.cssText = `
@@ -8,7 +8,6 @@ import { ButtonsFactory } from "../buttons.js";
8
8
  import { ensureFonts, iconFontUrl, loadFont } from "../fonts.js";
9
9
  import { getIconElement } from "../icons.js";
10
10
  import { NeedleLogoElement } from "../logo-element.js";
11
- import { getElementPriority, setElementPriority as _setElementPriority } from "./menu-priority.js";
12
11
  import { NeedleSpatialMenu } from "./needle-menu-spatial.js";
13
12
 
14
13
  declare global {
@@ -112,11 +111,16 @@ export declare type ButtonInfo = {
112
111
  export class NeedleMenu {
113
112
 
114
113
  static setElementPriority(button: HTMLElement, priority: number) {
115
- _setElementPriority(button, priority);
114
+ button.setAttribute("priority", String(priority));
116
115
  }
117
116
 
118
117
  static getElementPriority(button: HTMLElement): number | undefined {
119
- return getElementPriority(button);
118
+ const priority = button.getAttribute("priority");
119
+ if (priority) {
120
+ const val = Number.parseFloat(priority);
121
+ if (!Number.isNaN(val)) return val;
122
+ }
123
+ return undefined;
120
124
  }
121
125
 
122
126
  private readonly _context: Context;
@@ -168,7 +168,7 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
168
168
  */
169
169
  public get context() { return this._context; }
170
170
 
171
- private _context!: Context;
171
+ private _context?: Context;
172
172
  private _overlay_ar!: AROverlayHandler;
173
173
  private _loadingProgress01: number = 0;
174
174
  private _loadingView?: ILoadingViewHandler;
@@ -298,12 +298,10 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
298
298
 
299
299
 
300
300
  this._overlay_ar = new AROverlayHandler();
301
- this._context ??= new Context({ domElement: this }); // we might have one already if onLoad is running
301
+ this.getOrCreateContext();
302
302
  this.addEventListener("xr-session-started", this.onXRSessionStarted);
303
303
  this.onSetupDesktop();
304
304
 
305
-
306
-
307
305
  if (!this.getAttribute("src")) {
308
306
  const global = (globalThis as any)["needle:codegen_files"] as unknown as string;
309
307
  if (debug) console.log("src is null, trying to load from globalThis[\"needle:codegen_files\"]", global);
@@ -418,18 +416,23 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
418
416
  case "focus-rect":
419
417
  {
420
418
  const focus_rect = this.getAttribute("focus-rect") as HTMLElement | string | null;
421
- if (focus_rect && this._context) {
419
+ if (focus_rect) {
420
+ const context = this.getOrCreateContext();
421
+
422
422
  if (focus_rect === null) {
423
- this._context.setCameraFocusRect(null);
423
+ context.setCameraFocusRect(null);
424
424
  }
425
425
  else if (typeof focus_rect === "string" && focus_rect.length > 0) {
426
426
  const element = document.querySelector(focus_rect);
427
- this._context.setCameraFocusRect(element instanceof HTMLElement ? element : null);
427
+ if (!element) console.warn(`No element found for focus-rect selector: ${focus_rect}`);
428
+ context.setCameraFocusRect(element instanceof HTMLElement ? element : null);
428
429
  }
429
430
  else if (focus_rect instanceof HTMLElement) {
430
- this._context.setCameraFocusRect(focus_rect);
431
+ context.setCameraFocusRect(focus_rect);
432
+ }
433
+ else {
434
+ console.warn("Invalid focus-rect value. Expected a CSS selector string or an HTMLElement.", focus_rect);
431
435
  }
432
-
433
436
  }
434
437
  }
435
438
  break;
@@ -447,19 +450,22 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
447
450
  private _lastSourceFiles: Array<string> | null = null;
448
451
  private _createContextPromise: Promise<boolean> | null = null;
449
452
 
450
- private async onLoad() {
451
-
452
- if (!this.isConnected) return;
453
-
453
+ /**
454
+ * Check if we have a context. If not a new one is created.
455
+ */
456
+ private getOrCreateContext() {
454
457
  if (!this._context) {
455
458
  if (debug) console.warn("Create new context");
456
459
  this._context = new Context({ domElement: this });
457
460
  }
461
+ return this._context;
462
+ }
458
463
 
459
- if (!this._context) {
460
- console.error("Needle Engine: Context not initialized");
461
- return;
462
- }
464
+ private async onLoad() {
465
+
466
+ if (!this.isConnected) return;
467
+
468
+ const context = this.getOrCreateContext();
463
469
 
464
470
  const filesToLoad = this.getSourceFiles();
465
471
  if (!this.checkIfSourceHasChanged(filesToLoad, this._lastSourceFiles)) {
@@ -477,7 +483,7 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
477
483
 
478
484
  if (filesToLoad === null || filesToLoad === undefined || filesToLoad.length <= 0) {
479
485
  if (debug) console.warn("Clear scene", filesToLoad);
480
- this._context.clear();
486
+ context.clear();
481
487
  if (loadId !== this._loadId) return;
482
488
  }
483
489
 
@@ -491,7 +497,7 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
491
497
  this.ensureLoadStartIsRegistered();
492
498
  let useDefaultLoading = this.dispatchEvent(new CustomEvent("loadstart", {
493
499
  detail: {
494
- context: this._context,
500
+ context: context,
495
501
  alias: alias
496
502
  },
497
503
  cancelable: true
@@ -581,9 +587,9 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
581
587
 
582
588
  const currentHash = this.getAttribute("hash");
583
589
  if (currentHash !== null && currentHash !== undefined)
584
- this._context.hash = currentHash;
585
- this._context.alias = alias;
586
- this._createContextPromise = this._context.create(args);
590
+ context.hash = currentHash;
591
+ context.alias = alias;
592
+ this._createContextPromise = context.create(args);
587
593
  const success = await this._createContextPromise;
588
594
  this.applyAttributes();
589
595
 
@@ -615,42 +621,45 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
615
621
 
616
622
  // #region applyAttributes
617
623
  private applyAttributes() {
624
+
625
+ const context = this.getOrCreateContext();
626
+
618
627
  // set tonemapping if configured
619
- if (this._context?.renderer) {
628
+ if (context.renderer) {
620
629
  const threeTonemapping = nameToThreeTonemapping(this.toneMapping);
621
630
  if (threeTonemapping !== undefined) {
622
- this._context.renderer.toneMapping = threeTonemapping;
631
+ context.renderer.toneMapping = threeTonemapping;
623
632
  }
624
633
  const exposure = this.getAttribute("tone-mapping-exposure");
625
634
  if (exposure !== null && exposure !== undefined) {
626
635
  const value = parseFloat(exposure);
627
636
  if (!isNaN(value))
628
- this._context.renderer.toneMappingExposure = value;
637
+ context.renderer.toneMappingExposure = value;
629
638
  }
630
639
  }
631
640
 
632
641
  const backgroundBlurriness = this.getAttribute("background-blurriness");
633
642
  if (backgroundBlurriness !== null && backgroundBlurriness !== undefined) {
634
643
  const value = parseFloat(backgroundBlurriness);
635
- if (!isNaN(value) && this._context) {
636
- this._context.scene.backgroundBlurriness = value;
644
+ if (!isNaN(value)) {
645
+ context.scene.backgroundBlurriness = value;
637
646
  }
638
647
  }
639
648
 
640
649
  const environmentIntensity = this.getAttribute("environment-intensity");
641
- if (environmentIntensity != undefined && this._context) {
650
+ if (environmentIntensity != undefined) {
642
651
  const value = parseFloat(environmentIntensity);
643
- if (!isNaN(value) && this._context)
644
- this._context.scene.environmentIntensity = value;
652
+ if (!isNaN(value))
653
+ context.scene.environmentIntensity = value;
645
654
  }
646
655
 
647
656
  const backgroundColor = this.getAttribute("background-color");
648
- if (this._context?.renderer) {
657
+ if (context.renderer) {
649
658
  if (typeof backgroundColor === "string" && backgroundColor.length > 0) {
650
659
  const rgbaColor = RGBAColor.fromColorRepresentation(backgroundColor);
651
660
  if (debug) console.debug("<needle-engine> background-color changed, str:", backgroundColor, "→", rgbaColor)
652
- this._context.renderer.setClearColor(rgbaColor, rgbaColor.alpha);
653
- this.context.scene.background = null;
661
+ context.renderer.setClearColor(rgbaColor, rgbaColor.alpha);
662
+ context.scene.background = null;
654
663
  }
655
664
  // HACK: if we set background-color to a color and then back to null we want the background-image attribute to re-apply
656
665
  else if (this.getAttribute("background-image")) {
@@ -660,19 +669,21 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
660
669
  }
661
670
 
662
671
  private onXRSessionStarted = () => {
663
- const xrSessionMode = this.context.xrSessionMode;
672
+ const context = this.getOrCreateContext();
673
+
674
+ const xrSessionMode = context.xrSessionMode;
664
675
  if (xrSessionMode === "immersive-ar")
665
- this.onEnterAR(this.context.xrSession!);
676
+ this.onEnterAR(context.xrSession!);
666
677
  else if (xrSessionMode === "immersive-vr")
667
- this.onEnterVR(this.context.xrSession!);
678
+ this.onEnterVR(context.xrSession!);
668
679
 
669
680
  // handle session end:
670
- this.context.xrSession?.addEventListener("end", () => {
671
- this.dispatchEvent(new CustomEvent("xr-session-ended", { detail: { session: this.context.xrSession, context: this._context, sessionMode: xrSessionMode } }));
681
+ context.xrSession?.addEventListener("end", () => {
682
+ this.dispatchEvent(new CustomEvent("xr-session-ended", { detail: { session: context.xrSession, context: this._context, sessionMode: xrSessionMode } }));
672
683
  if (xrSessionMode === "immersive-ar")
673
- this.onExitAR(this.context.xrSession!);
684
+ this.onExitAR(context.xrSession!);
674
685
  else if (xrSessionMode === "immersive-vr")
675
- this.onExitVR(this.context.xrSession!);
686
+ this.onExitVR(context.xrSession!);
676
687
  });
677
688
  };
678
689
 
@@ -741,7 +752,7 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
741
752
  if (typeof fn === "function") {
742
753
  this._previouslyRegisteredMap.set(eventName, fn);
743
754
  // @ts-ignore // not sure how to type this properly
744
- this.addEventListener(eventName, evt => fn?.call(globalThis, this._context, evt));
755
+ this.addEventListener(eventName, evt => fn?.call(globalThis, this.getOrCreateContext(), evt));
745
756
  }
746
757
  }
747
758
  catch (err) {
@@ -783,35 +794,39 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
783
794
  * @internal
784
795
  */
785
796
  onEnterAR(session: XRSession) {
797
+ const context = this.getOrCreateContext();
786
798
  this.onSetupAR();
787
799
  const overlayContainer = this.getAROverlayContainer();
788
- this._overlay_ar.onBegin(this._context!, overlayContainer, session);
789
- this.dispatchEvent(new CustomEvent("enter-ar", { detail: { session: session, context: this._context, htmlContainer: this._overlay_ar?.ARContainer } }));
800
+ this._overlay_ar.onBegin(context, overlayContainer, session);
801
+ this.dispatchEvent(new CustomEvent("enter-ar", { detail: { session: session, context: context, htmlContainer: this._overlay_ar?.ARContainer } }));
790
802
  }
791
803
 
792
804
  /**
793
805
  * @internal
794
806
  */
795
807
  onExitAR(session: XRSession) {
796
- this._overlay_ar.onEnd(this._context!);
808
+ const context = this.getOrCreateContext();
809
+ this._overlay_ar.onEnd(context);
797
810
  this.onSetupDesktop();
798
- this.dispatchEvent(new CustomEvent("exit-ar", { detail: { session: session, context: this._context, htmlContainer: this._overlay_ar?.ARContainer } }));
811
+ this.dispatchEvent(new CustomEvent("exit-ar", { detail: { session: session, context: context, htmlContainer: this._overlay_ar?.ARContainer } }));
799
812
  }
800
813
 
801
814
  /**
802
815
  * @internal
803
816
  */
804
817
  onEnterVR(session: XRSession) {
818
+ const context = this.getOrCreateContext();
805
819
  this.onSetupVR();
806
- this.dispatchEvent(new CustomEvent("enter-vr", { detail: { session: session, context: this._context } }));
820
+ this.dispatchEvent(new CustomEvent("enter-vr", { detail: { session: session, context: context } }));
807
821
  }
808
822
 
809
823
  /**
810
824
  * @internal
811
825
  */
812
826
  onExitVR(session: XRSession) {
827
+ const context = this.getOrCreateContext();
813
828
  this.onSetupDesktop();
814
- this.dispatchEvent(new CustomEvent("exit-vr", { detail: { session: session, context: this._context } }));
829
+ this.dispatchEvent(new CustomEvent("exit-vr", { detail: { session: session, context: context } }));
815
830
  }
816
831
 
817
832
  private onSetupAR() {
@@ -11,7 +11,7 @@ import { TypeStore } from "../engine/engine_typestore.js";
11
11
  import { deepClone, getParam } from "../engine/engine_utils.js";
12
12
  import type { AnimatorControllerModel, Condition, State, Transition } from "../engine/extensions/NEEDLE_animator_controller_model.js";
13
13
  import { AnimatorConditionMode, AnimatorControllerParameterType, AnimatorStateInfo, createMotion, StateMachineBehaviour } from "../engine/extensions/NEEDLE_animator_controller_model.js";
14
- import type { Animator } from "./Animator.js";
14
+ import { Animator } from "./Animator.js";
15
15
 
16
16
  const debug = getParam("debuganimatorcontroller");
17
17
  const debugRootMotion = getParam("debugrootmotion");
@@ -6,7 +6,6 @@ import { hasProLicense } from "../../../engine/engine_license.js";
6
6
  import { serializable } from "../../../engine/engine_serialization.js";
7
7
  import { getFormattedDate, Progress } from "../../../engine/engine_time_utils.js";
8
8
  import { DeviceUtilities, getParam } from "../../../engine/engine_utils.js";
9
- import { registerQuicklookHandlerFactory } from "../../../engine/webcomponents/quicklook-handler.js";
10
9
  import { WebXRButtonFactory } from "../../../engine/webcomponents/WebXRButtons.js";
11
10
  import { InternalUSDZRegistry } from "../../../engine/xr/usdz.js"
12
11
  import { InstancingHandler } from "../../../engine-components/RendererInstancing.js";
@@ -794,10 +793,3 @@ export class USDZExporter extends Behaviour {
794
793
  return button;
795
794
  }
796
795
  }
797
-
798
- // Register USDZExporter as the quicklook handler so that WebXRButtons
799
- // can create/find exporters without a direct import (avoids circular dependency).
800
- registerQuicklookHandlerFactory({
801
- find: () => GameObject.findObjectOfType(USDZExporter),
802
- create: () => new USDZExporter(),
803
- });
@@ -2,13 +2,12 @@ import { AnimationAction, AnimationClip, AnimationMixer, Audio, AudioListener, A
2
2
 
3
3
  import { isDevEnvironment } from "../../engine/debug/index.js";
4
4
  import { Context } from "../../engine/engine_setup.js";
5
- import type { Constructor } from "../../engine/engine_types.js";
6
5
  import { getParam, resolveUrl } from "../../engine/engine_utils.js";
7
6
  import { setObjectAnimated } from "../AnimationUtils.js";
8
7
  import { Animator } from "../Animator.js"
9
8
  import { AudioSource } from "../AudioSource.js";
10
9
  import { GameObject } from "../Component.js";
11
- import type { PlayableDirector } from "./PlayableDirector.js";
10
+ import { PlayableDirector } from "./PlayableDirector.js";
12
11
  import { SignalReceiver } from "./SignalAsset.js";
13
12
  import * as Models from "./TimelineModels.js";
14
13
 
@@ -941,10 +940,7 @@ export class ControlTrackHandler extends TrackHandler {
941
940
  continue;
942
941
  }
943
942
  else {
944
- // Use the director's constructor to get the PlayableDirector class reference
945
- // without a runtime import, avoiding a circular dependency.
946
- const DirectorType = this.director.constructor as Constructor<PlayableDirector>;
947
- const timeline = GameObject.getComponent(asset.sourceObject, DirectorType)!;
943
+ const timeline = GameObject.getComponent(asset.sourceObject, PlayableDirector)!;
948
944
  // always add it to keep size of timelines and models in sync (index of model is index of timeline)
949
945
  this.timelines.push(timeline);
950
946
  if (timeline) {
@@ -1,4 +0,0 @@
1
- /** True when the application runs on a local url */
2
- export declare function isDevEnvironment(): boolean;
3
- /** Enforce the dev environment flag to be true or false */
4
- export declare function setDevEnvironment(val: boolean): void;
@@ -1,26 +0,0 @@
1
- import { isLocalNetwork } from "../engine_networking_utils.js";
2
- import { getParam } from "../engine_utils.js";
3
- const noDevLogs = getParam("nodevlogs");
4
- let _manuallySetDevEnvironment;
5
- let _cachedDevEnvironment;
6
- /** True when the application runs on a local url */
7
- export function isDevEnvironment() {
8
- if (noDevLogs)
9
- return false;
10
- if (_manuallySetDevEnvironment !== undefined)
11
- return _manuallySetDevEnvironment;
12
- if (_cachedDevEnvironment !== undefined)
13
- return _cachedDevEnvironment;
14
- let res = isLocalNetwork();
15
- if (!res) {
16
- // is stackblitz?
17
- res = window.location.hostname.endsWith(".local-credentialless.webcontainer.io");
18
- }
19
- _cachedDevEnvironment = res;
20
- return res;
21
- }
22
- /** Enforce the dev environment flag to be true or false */
23
- export function setDevEnvironment(val) {
24
- _manuallySetDevEnvironment = val;
25
- }
26
- //# sourceMappingURL=debug_environment.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"debug_environment.js","sourceRoot":"","sources":["../../../src/engine/debug/debug_environment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,MAAM,SAAS,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;AAExC,IAAI,0BAA+C,CAAC;AACpD,IAAI,qBAA0C,CAAC;AAE/C,oDAAoD;AACpD,MAAM,UAAU,gBAAgB;IAC5B,IAAI,SAAS;QAAE,OAAO,KAAK,CAAC;IAC5B,IAAI,0BAA0B,KAAK,SAAS;QAAE,OAAO,0BAA0B,CAAC;IAChF,IAAI,qBAAqB,KAAK,SAAS;QAAE,OAAO,qBAAqB,CAAC;IAEtE,IAAI,GAAG,GAAG,cAAc,EAAE,CAAC;IAC3B,IAAI,CAAC,GAAG,EAAE,CAAC;QACP,iBAAiB;QACjB,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,uCAAuC,CAAC,CAAC;IACrF,CAAC;IACD,qBAAqB,GAAG,GAAG,CAAC;IAC5B,OAAO,GAAG,CAAC;AACf,CAAC;AACD,2DAA2D;AAC3D,MAAM,UAAU,iBAAiB,CAAC,GAAY;IAC1C,0BAA0B,GAAG,GAAG,CAAC;AACrC,CAAC"}
@@ -1,10 +0,0 @@
1
- /**
2
- * Sets the priority attribute on a menu element, determining its position in the menu.
3
- * Lower priority elements appear on the left, higher priority on the right.
4
- */
5
- export declare function setElementPriority(button: HTMLElement, priority: number): void;
6
- /**
7
- * Gets the priority attribute from a menu element.
8
- * @returns The priority value, or undefined if not set or not a valid number.
9
- */
10
- export declare function getElementPriority(button: HTMLElement): number | undefined;
@@ -1,21 +0,0 @@
1
- /**
2
- * Sets the priority attribute on a menu element, determining its position in the menu.
3
- * Lower priority elements appear on the left, higher priority on the right.
4
- */
5
- export function setElementPriority(button, priority) {
6
- button.setAttribute("priority", String(priority));
7
- }
8
- /**
9
- * Gets the priority attribute from a menu element.
10
- * @returns The priority value, or undefined if not set or not a valid number.
11
- */
12
- export function getElementPriority(button) {
13
- const priority = button.getAttribute("priority");
14
- if (priority) {
15
- const val = Number.parseFloat(priority);
16
- if (!Number.isNaN(val))
17
- return val;
18
- }
19
- return undefined;
20
- }
21
- //# sourceMappingURL=menu-priority.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"menu-priority.js","sourceRoot":"","sources":["../../../../src/engine/webcomponents/needle menu/menu-priority.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAmB,EAAE,QAAgB;IACpE,MAAM,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;AACtD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAmB;IAClD,MAAM,QAAQ,GAAG,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;IACjD,IAAI,QAAQ,EAAE,CAAC;QACX,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QACxC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC;YAAE,OAAO,GAAG,CAAC;IACvC,CAAC;IACD,OAAO,SAAS,CAAC;AACrB,CAAC"}
@@ -1,29 +0,0 @@
1
- /**
2
- * Interface for a quicklook handler that can export and open a USDZ file.
3
- * Used as an abstraction layer to break the circular dependency between
4
- * WebXRButtons and USDZExporter.
5
- */
6
- export interface IQuicklookHandler {
7
- objectToExport: any;
8
- exportAndOpen(): Promise<any>;
9
- }
10
- type QuicklookHandlerFactory = {
11
- /** Find an existing quicklook handler in the scene */
12
- find(): IQuicklookHandler | null;
13
- /** Create a new quicklook handler instance */
14
- create(): IQuicklookHandler;
15
- };
16
- /**
17
- * Register a factory for creating quicklook handlers.
18
- * Called by USDZExporter to register itself as the handler.
19
- */
20
- export declare function registerQuicklookHandlerFactory(factory: QuicklookHandlerFactory): void;
21
- /**
22
- * Find an existing quicklook handler in the scene, or create a new one if none exists.
23
- * @returns A quicklook handler, or null if no factory has been registered.
24
- */
25
- export declare function getOrCreateQuicklookHandler(): {
26
- handler: IQuicklookHandler;
27
- created: boolean;
28
- } | null;
29
- export {};
@@ -1,21 +0,0 @@
1
- let _factory;
2
- /**
3
- * Register a factory for creating quicklook handlers.
4
- * Called by USDZExporter to register itself as the handler.
5
- */
6
- export function registerQuicklookHandlerFactory(factory) {
7
- _factory = factory;
8
- }
9
- /**
10
- * Find an existing quicklook handler in the scene, or create a new one if none exists.
11
- * @returns A quicklook handler, or null if no factory has been registered.
12
- */
13
- export function getOrCreateQuicklookHandler() {
14
- if (!_factory)
15
- return null;
16
- const existing = _factory.find();
17
- if (existing)
18
- return { handler: existing, created: false };
19
- return { handler: _factory.create(), created: true };
20
- }
21
- //# sourceMappingURL=quicklook-handler.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"quicklook-handler.js","sourceRoot":"","sources":["../../../src/engine/webcomponents/quicklook-handler.ts"],"names":[],"mappings":"AAiBA,IAAI,QAA6C,CAAC;AAElD;;;GAGG;AACH,MAAM,UAAU,+BAA+B,CAAC,OAAgC;IAC5E,QAAQ,GAAG,OAAO,CAAC;AACvB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,2BAA2B;IACvC,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3B,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;IACjC,IAAI,QAAQ;QAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC3D,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACzD,CAAC"}
@@ -1,26 +0,0 @@
1
- import { isLocalNetwork } from "../engine_networking_utils.js";
2
- import { getParam } from "../engine_utils.js";
3
-
4
- const noDevLogs = getParam("nodevlogs");
5
-
6
- let _manuallySetDevEnvironment: boolean | undefined;
7
- let _cachedDevEnvironment: boolean | undefined;
8
-
9
- /** True when the application runs on a local url */
10
- export function isDevEnvironment(): boolean {
11
- if (noDevLogs) return false;
12
- if (_manuallySetDevEnvironment !== undefined) return _manuallySetDevEnvironment;
13
- if (_cachedDevEnvironment !== undefined) return _cachedDevEnvironment;
14
-
15
- let res = isLocalNetwork();
16
- if (!res) {
17
- // is stackblitz?
18
- res = window.location.hostname.endsWith(".local-credentialless.webcontainer.io");
19
- }
20
- _cachedDevEnvironment = res;
21
- return res;
22
- }
23
- /** Enforce the dev environment flag to be true or false */
24
- export function setDevEnvironment(val: boolean): void {
25
- _manuallySetDevEnvironment = val;
26
- }