@needle-tools/engine 4.16.10 → 4.16.12

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 (90) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/SKILL.md +64 -4
  3. package/dist/gltf-progressive-DLDvZ8Xm.umd.cjs +10 -0
  4. package/dist/{gltf-progressive-CzxjNmG6.js → gltf-progressive-DMK8kKVB.js} +352 -346
  5. package/dist/gltf-progressive-RPgYR6rv.min.js +10 -0
  6. package/dist/{needle-engine.bundle-a0Pw5htf.js → needle-engine.bundle-BfsnYTeP.js} +7329 -7105
  7. package/dist/{needle-engine.bundle-D_nuVSFb.umd.cjs → needle-engine.bundle-COr8D1vc.umd.cjs} +132 -132
  8. package/dist/{needle-engine.bundle-DlyYXu9v.min.js → needle-engine.bundle-DG1sGkxn.min.js} +131 -131
  9. package/dist/needle-engine.d.ts +60 -3
  10. package/dist/needle-engine.js +3 -3
  11. package/dist/needle-engine.min.js +1 -1
  12. package/dist/needle-engine.umd.cjs +1 -1
  13. package/dist/three-examples.js +52 -52
  14. package/dist/three-examples.min.js +4 -4
  15. package/dist/three-examples.umd.cjs +2 -2
  16. package/lib/engine/api.d.ts +2 -1
  17. package/lib/engine/api.js +1 -6
  18. package/lib/engine/api.js.map +1 -1
  19. package/lib/engine/debug/debug_spector.js +1 -1
  20. package/lib/engine/debug/debug_spector.js.map +1 -1
  21. package/lib/engine/engine_addressables.d.ts +32 -1
  22. package/lib/engine/engine_addressables.js +71 -9
  23. package/lib/engine/engine_addressables.js.map +1 -1
  24. package/lib/engine/engine_application.d.ts +2 -0
  25. package/lib/engine/engine_application.js +7 -3
  26. package/lib/engine/engine_application.js.map +1 -1
  27. package/lib/engine/engine_audio.d.ts +30 -1
  28. package/lib/engine/engine_audio.js +57 -13
  29. package/lib/engine/engine_audio.js.map +1 -1
  30. package/lib/engine/engine_context.js +25 -1
  31. package/lib/engine/engine_context.js.map +1 -1
  32. package/lib/engine/engine_context_registry.js +1 -1
  33. package/lib/engine/engine_context_registry.js.map +1 -1
  34. package/lib/engine/engine_input.js +1 -1
  35. package/lib/engine/engine_input.js.map +1 -1
  36. package/lib/engine/engine_license.d.ts +1 -1
  37. package/lib/engine/engine_license.js +31 -5
  38. package/lib/engine/engine_license.js.map +1 -1
  39. package/lib/engine/engine_lifecycle_functions_internal.js +20 -2
  40. package/lib/engine/engine_lifecycle_functions_internal.js.map +1 -1
  41. package/lib/engine/engine_networking_streams.d.ts +5 -1
  42. package/lib/engine/engine_networking_streams.js +64 -17
  43. package/lib/engine/engine_networking_streams.js.map +1 -1
  44. package/lib/engine/engine_shims.js +1 -1
  45. package/lib/engine/engine_shims.js.map +1 -1
  46. package/lib/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js +5 -0
  47. package/lib/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js.map +1 -1
  48. package/lib/engine/webcomponents/fonts.d.ts +1 -1
  49. package/lib/engine/webcomponents/fonts.js +7 -0
  50. package/lib/engine/webcomponents/fonts.js.map +1 -1
  51. package/lib/engine/webcomponents/icons.js +8 -1
  52. package/lib/engine/webcomponents/icons.js.map +1 -1
  53. package/lib/engine/webcomponents/needle menu/needle-menu.d.ts +5 -0
  54. package/lib/engine/webcomponents/needle menu/needle-menu.js +31 -13
  55. package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
  56. package/lib/engine/webcomponents/needle-engine.d.ts +1 -0
  57. package/lib/engine/webcomponents/needle-engine.js +16 -4
  58. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  59. package/lib/engine/webcomponents/needle-engine.loading.d.ts +2 -0
  60. package/lib/engine/webcomponents/needle-engine.loading.js +10 -0
  61. package/lib/engine/webcomponents/needle-engine.loading.js.map +1 -1
  62. package/lib/engine-components/AudioSource.d.ts +49 -2
  63. package/lib/engine-components/AudioSource.js +261 -66
  64. package/lib/engine-components/AudioSource.js.map +1 -1
  65. package/lib/engine-components/CameraUtils.js +1 -1
  66. package/lib/engine-components/CameraUtils.js.map +1 -1
  67. package/lib/engine-components/postprocessing/Effects/Tonemapping.utils.d.ts +1 -1
  68. package/package.json +2 -2
  69. package/src/engine/api.ts +3 -1
  70. package/src/engine/debug/debug_spector.ts +1 -1
  71. package/src/engine/engine_addressables.ts +75 -9
  72. package/src/engine/engine_application.ts +7 -2
  73. package/src/engine/engine_audio.ts +68 -15
  74. package/src/engine/engine_context.ts +25 -1
  75. package/src/engine/engine_context_registry.ts +1 -1
  76. package/src/engine/engine_input.ts +2 -2
  77. package/src/engine/engine_license.ts +28 -5
  78. package/src/engine/engine_lifecycle_functions_internal.ts +21 -2
  79. package/src/engine/engine_networking_streams.ts +64 -19
  80. package/src/engine/engine_shims.ts +1 -1
  81. package/src/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js +8 -1
  82. package/src/engine/webcomponents/fonts.ts +6 -0
  83. package/src/engine/webcomponents/icons.ts +9 -2
  84. package/src/engine/webcomponents/needle menu/needle-menu.ts +30 -12
  85. package/src/engine/webcomponents/needle-engine.loading.ts +13 -1
  86. package/src/engine/webcomponents/needle-engine.ts +15 -5
  87. package/src/engine-components/AudioSource.ts +244 -63
  88. package/src/engine-components/CameraUtils.ts +1 -1
  89. package/dist/gltf-progressive-BacJPTD6.umd.cjs +0 -10
  90. package/dist/gltf-progressive-BmXoz_HR.min.js +0 -10
@@ -27,6 +27,12 @@ export function loadFont(url: string, opts?: LoadFontOptions) {
27
27
  }
28
28
  }
29
29
  }
30
+ // The link lives in document.head and can outlive the component using this callback.
31
+ return () => {
32
+ if (opts?.loadedCallback) {
33
+ for (const link of elements) link.removeEventListener("load", opts.loadedCallback);
34
+ }
35
+ };
30
36
  }
31
37
 
32
38
 
@@ -20,7 +20,15 @@ export function getIconElement(str: string): HTMLElement {
20
20
  span.setAttribute("role", "img");
21
21
  span.setAttribute("aria-label", str + " icon");
22
22
  span.setAttribute("aria-hidden", "true");
23
+ updateIconWhenFontReady(new WeakRef(span), str);
24
+ return span;
25
+ }
26
+
27
+ // Pending font loads must not retain detached menu trees.
28
+ function updateIconWhenFontReady(reference: WeakRef<HTMLSpanElement>, str: string) {
23
29
  fontReady(fontname).then(res => {
30
+ const span = reference.deref();
31
+ if (!span) return;
24
32
  if (res) span.style.visibility = "";
25
33
  else {
26
34
  if (str === "more_vert") {
@@ -31,8 +39,7 @@ export function getIconElement(str: string): HTMLElement {
31
39
  span.style.display = "none";
32
40
  }
33
41
  }
34
- })
35
- return span;
42
+ });
36
43
  }
37
44
 
38
45
  /**@returns true if the element is an needle engine icon element */
@@ -3,7 +3,7 @@ import type { Context } from "../../engine_context.js";
3
3
  import { hasCommercialLicense, onLicenseCheckResultChanged, Telemetry } from "../../engine_license.js";
4
4
  import { isLocalNetwork } from "../../engine_networking_utils.js";
5
5
  import { DeviceUtilities, getParam } from "../../engine_utils.js";
6
- import { onXRSessionStart, XRSessionEventArgs } from "../../xr/events.js";
6
+ import { offXRSessionStart, onXRSessionStart, XRSessionEventArgs } from "../../xr/events.js";
7
7
  import { ButtonsFactory } from "../buttons.js";
8
8
  import { ensureFonts, iconFontUrl, loadFont } from "../fonts.js";
9
9
  import { getIconElement } from "../icons.js";
@@ -138,7 +138,9 @@ export class NeedleMenu {
138
138
 
139
139
  /** @ignore internal method */
140
140
  onDestroy() {
141
+ offXRSessionStart(this.onStartXR);
141
142
  window.removeEventListener("message", this.onPostMessage);
143
+ this._menu.dispose();
142
144
  this._menu.remove();
143
145
  this._spatialMenu.onDestroy();
144
146
  }
@@ -338,6 +340,19 @@ export class NeedleMenuElement extends HTMLElement {
338
340
 
339
341
  private _domElement: HTMLElement | null = null;
340
342
  private _context: Context | null = null;
343
+ private _unsubscribeFont?: () => void;
344
+ private _licenseFrame?: number;
345
+ private _unsubscribeLicense?: () => void;
346
+
347
+ /** @internal Release font and license subscriptions when the owning context is destroyed. */
348
+ dispose() {
349
+ this._unsubscribeFont?.();
350
+ this._unsubscribeFont = undefined;
351
+ if (this._licenseFrame !== undefined) window.cancelAnimationFrame(this._licenseFrame);
352
+ this._licenseFrame = undefined;
353
+ this._unsubscribeLicense?.();
354
+ this._unsubscribeLicense = undefined;
355
+ }
341
356
  private _didInitialize = false;
342
357
 
343
358
  constructor() {
@@ -748,7 +763,7 @@ export class NeedleMenuElement extends HTMLElement {
748
763
  // we need to add the icons to both the shadow dom as well as the HEAD to work
749
764
  // https://github.com/google/material-design-icons/issues/1165
750
765
  ensureFonts();
751
- loadFont(iconFontUrl, { loadedCallback: () => { this.handleSizeChange() } });
766
+ this._unsubscribeFont = loadFont(iconFontUrl, { loadedCallback: () => { this.handleSizeChange() } });
752
767
  loadFont(iconFontUrl, { element: shadow });
753
768
 
754
769
  const content = template.content.cloneNode(true) as DocumentFragment;
@@ -777,16 +792,19 @@ export class NeedleMenuElement extends HTMLElement {
777
792
  try {
778
793
  // if the user has a license then we CAN hide the needle logo
779
794
  // calling this method immediately will cause an issue with vite bundling tho
780
- window.requestAnimationFrame(() => onLicenseCheckResultChanged(res => {
781
- if (res == true && hasCommercialLicense() && !debugNonCommercial) {
782
- let visible = this._userRequestedLogoVisible;
783
- if (visible === undefined) visible = false;
784
- this.___onSetLogoVisible(visible);
785
- }
786
- else {
787
- this.___onSetLogoVisible(true);
788
- }
789
- }));
795
+ this._licenseFrame = window.requestAnimationFrame(() => {
796
+ this._licenseFrame = undefined;
797
+ this._unsubscribeLicense = onLicenseCheckResultChanged(res => {
798
+ if (res == true && hasCommercialLicense() && !debugNonCommercial) {
799
+ let visible = this._userRequestedLogoVisible;
800
+ if (visible === undefined) visible = false;
801
+ this.___onSetLogoVisible(visible);
802
+ }
803
+ else {
804
+ this.___onSetLogoVisible(true);
805
+ }
806
+ });
807
+ });
790
808
  } catch (e) {
791
809
  console.error("[Needle Menu] License check failed.", e);
792
810
  }
@@ -19,6 +19,7 @@ export class LoadingElementOptions {
19
19
 
20
20
  /** @internal */
21
21
  export interface ILoadingViewHandler {
22
+ dispose?(): void;
22
23
  onLoadingBegin(message?: string)
23
24
  onLoadingUpdate(progress: LoadingProgressArgs | number, message?: string);
24
25
  onLoadingFinished(message?: string);
@@ -79,6 +80,17 @@ export class EngineLoadingView implements ILoadingViewHandler {
79
80
  this._loadingElementOptions = opts;
80
81
  }
81
82
 
83
+ dispose() {
84
+ // Removal can happen before ready stops the progress interval.
85
+ clearInterval(this._progressLoop);
86
+ this._progressLoop = null;
87
+ this._loadingElement?.remove();
88
+ this._loadingElement = undefined;
89
+ this._loadingTextContainer = null;
90
+ this._loadingBar = null;
91
+ this._messageContainer = null;
92
+ }
93
+
82
94
  async onLoadingBegin(message?: string) {
83
95
  const _element = this._element.shadowRoot || this._element;
84
96
  if (debug) console.warn("Begin Loading")
@@ -402,4 +414,4 @@ export class EngineLoadingView implements ILoadingViewHandler {
402
414
  // nonCommercialContainer.style.transition = "opacity .5s ease-in-out";
403
415
  // nonCommercialContainer.style.opacity = "1";
404
416
  // }
405
- }
417
+ }
@@ -172,6 +172,7 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
172
172
  private _overlay_ar!: AROverlayHandler;
173
173
  private _loadingProgress01: number = 0;
174
174
  private _loadingView?: ILoadingViewHandler;
175
+ private _cancelLoadingBlur?: () => void;
175
176
  private _previousSrc: string | null | string[] = null;
176
177
  /** @private set to true after <needle-engine> did load completely at least once. Set to false when < to false when <needle-engine> is removed from the document removed from the document */
177
178
  private _didFullyLoad: boolean = false;
@@ -335,6 +336,9 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
335
336
  const dispose = keepAlive == undefined || (keepAlive?.length > 0 && keepAlive !== "true" && keepAlive !== "1");
336
337
  if (debug) console.warn("<needle-engine> disconnected, keep-alive: \"" + keepAlive + "\"", typeof keepAlive, "Dispose=", dispose);
337
338
  if (dispose) {
339
+ this._cancelLoadingBlur?.();
340
+ this._cancelLoadingBlur = undefined;
341
+ this._loadingView?.dispose?.();
338
342
  if (debug)
339
343
  console.warn("<needle-engine> dispose");
340
344
  this._context?.dispose();
@@ -583,7 +587,8 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
583
587
 
584
588
 
585
589
  // Experimental loading blur
586
- handleLoadingBlur(this);
590
+ this._cancelLoadingBlur?.();
591
+ this._cancelLoadingBlur = handleLoadingBlur(this);
587
592
 
588
593
  const currentHash = this.getAttribute("hash");
589
594
  if (currentHash !== null && currentHash !== undefined)
@@ -1243,8 +1248,12 @@ function getDisplayName(str: string) {
1243
1248
 
1244
1249
 
1245
1250
  function handleLoadingBlur(needleEngineElement: NeedleEngineWebComponent) {
1246
- onStart((ctx) => {
1247
- const userBlurSetting = needleEngineElement.getAttribute("loading-blur");
1251
+ const userBlurSetting = needleEngineElement.getAttribute("loading-blur");
1252
+ if (userBlurSetting === null || userBlurSetting === "0") return undefined;
1253
+ const unregister = onStart((ctx) => {
1254
+ // A different context starting must not consume this element's callback.
1255
+ if (ctx.domElement !== needleEngineElement) return;
1256
+ unregister();
1248
1257
  if (userBlurSetting !== null && userBlurSetting !== "0") {
1249
1258
  if (ctx.domElement === needleEngineElement) {
1250
1259
 
@@ -1297,5 +1306,6 @@ function handleLoadingBlur(needleEngineElement: NeedleEngineWebComponent) {
1297
1306
  }
1298
1307
  }
1299
1308
  }
1300
- }, { once: true });
1301
- }
1309
+ });
1310
+ return unregister;
1311
+ }