@needle-tools/engine 4.12.0-next.ca2cebd → 4.12.0-next.dcaf2b0

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 (216) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/components.needle.json +1 -1
  3. package/dist/generateMeshBVH.worker-iyfPIK6R.js +21 -0
  4. package/dist/{gltf-progressive-DWcmTMCh.umd.cjs → gltf-progressive-Bfpfaz84.umd.cjs} +1 -1
  5. package/dist/{gltf-progressive-DgYz5BYa.js → gltf-progressive-DPunMlEM.js} +24 -24
  6. package/dist/{gltf-progressive-DZrY8VT6.min.js → gltf-progressive-hFPACYio.min.js} +2 -2
  7. package/dist/{loader.worker-Dip-PthR.js → loader.worker-DWzfDpAl.js} +4 -4
  8. package/dist/{needle-engine.bundle-CFkbGdL5.js → needle-engine.bundle-DTXsNmA-.js} +9789 -9421
  9. package/dist/needle-engine.bundle-HRGeyfKM.umd.cjs +1647 -0
  10. package/dist/needle-engine.bundle-OAD5_P8d.min.js +1647 -0
  11. package/dist/needle-engine.d.ts +105 -33
  12. package/dist/needle-engine.js +48 -48
  13. package/dist/needle-engine.min.js +1 -1
  14. package/dist/needle-engine.umd.cjs +1 -1
  15. package/dist/{postprocessing-CMgoN5t5.umd.cjs → postprocessing-BHQvwehB.umd.cjs} +81 -81
  16. package/dist/{postprocessing-DYDtB188.min.js → postprocessing-ClLv0reO.min.js} +54 -54
  17. package/dist/{postprocessing-BTW9pD_s.js → postprocessing-DLI2N3LL.js} +450 -441
  18. package/dist/{three-DfMvBzXi.js → three-BCCkyCA5.js} +1 -7
  19. package/dist/{three-qj71I7J3.umd.cjs → three-Bf2NBxAw.umd.cjs} +2 -2
  20. package/dist/{three-B7CT31Bt.min.js → three-W7zWTcfP.min.js} +1 -1
  21. package/dist/{three-examples-D1SK93ek.js → three-examples-D4rE49Ui.js} +12 -22
  22. package/dist/{three-examples-D1P7eEhn.min.js → three-examples-DB5Uoja4.min.js} +12 -12
  23. package/dist/{three-examples-CsW4_6LI.umd.cjs → three-examples-Djbk6WA4.umd.cjs} +6 -6
  24. package/dist/{three-mesh-ui-C_uSB5dD.js → three-mesh-ui-3nSSizT4.js} +1 -1
  25. package/dist/{three-mesh-ui-LQ44s0AL.min.js → three-mesh-ui-CIez6qJQ.min.js} +1 -1
  26. package/dist/{three-mesh-ui-DpATDXwU.umd.cjs → three-mesh-ui-zsOOA5Pq.umd.cjs} +1 -1
  27. package/dist/{vendor-D0zoswDa.js → vendor-DMZcbVO1.js} +3707 -3527
  28. package/dist/vendor-sURMCFSI.min.js +1116 -0
  29. package/dist/{vendor-UCpFAwt1.umd.cjs → vendor-tyBvnMF-.umd.cjs} +39 -39
  30. package/lib/engine/codegen/register_types.js +0 -2
  31. package/lib/engine/codegen/register_types.js.map +1 -1
  32. package/lib/engine/debug/debug_console.js +403 -1
  33. package/lib/engine/debug/debug_console.js.map +1 -1
  34. package/lib/engine/engine_components.js +3 -3
  35. package/lib/engine/engine_components.js.map +1 -1
  36. package/lib/engine/engine_context.js +2 -0
  37. package/lib/engine/engine_context.js.map +1 -1
  38. package/lib/engine/engine_input.d.ts +5 -0
  39. package/lib/engine/engine_input.js +6 -0
  40. package/lib/engine/engine_input.js.map +1 -1
  41. package/lib/engine/engine_license.d.ts +18 -0
  42. package/lib/engine/engine_license.js +163 -18
  43. package/lib/engine/engine_license.js.map +1 -1
  44. package/lib/engine/engine_networking.js +20 -5
  45. package/lib/engine/engine_networking.js.map +1 -1
  46. package/lib/engine/engine_physics.js.map +1 -1
  47. package/lib/engine/engine_physics_rapier.js +1 -1
  48. package/lib/engine/engine_physics_rapier.js.map +1 -1
  49. package/lib/engine/engine_serialization_builtin_serializer.js +1 -1
  50. package/lib/engine/engine_serialization_builtin_serializer.js.map +1 -1
  51. package/lib/engine/engine_three_utils.js +2 -2
  52. package/lib/engine/engine_three_utils.js.map +1 -1
  53. package/lib/engine/engine_utils.d.ts +4 -1
  54. package/lib/engine/engine_utils.js +28 -4
  55. package/lib/engine/engine_utils.js.map +1 -1
  56. package/lib/engine/extensions/extensions.d.ts +29 -7
  57. package/lib/engine/extensions/extensions.js.map +1 -1
  58. package/lib/engine/webcomponents/WebXRButtons.js +13 -5
  59. package/lib/engine/webcomponents/WebXRButtons.js.map +1 -1
  60. package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js +2 -1
  61. package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js.map +1 -1
  62. package/lib/engine/webcomponents/needle menu/needle-menu.d.ts +2 -0
  63. package/lib/engine/webcomponents/needle menu/needle-menu.js +37 -6
  64. package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
  65. package/lib/engine/webcomponents/needle-engine.ar-overlay.js +4 -0
  66. package/lib/engine/webcomponents/needle-engine.ar-overlay.js.map +1 -1
  67. package/lib/engine/webcomponents/needle-engine.js +1 -1
  68. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  69. package/lib/engine/xr/NeedleXRSession.d.ts +1 -1
  70. package/lib/engine/xr/NeedleXRSession.js +106 -22
  71. package/lib/engine/xr/NeedleXRSession.js.map +1 -1
  72. package/lib/engine/xr/TempXRContext.js +12 -2
  73. package/lib/engine/xr/TempXRContext.js.map +1 -1
  74. package/lib/engine/xr/usdz.js +6 -2
  75. package/lib/engine/xr/usdz.js.map +1 -1
  76. package/lib/engine-components/AlignmentConstraint.d.ts +1 -1
  77. package/lib/engine-components/AlignmentConstraint.js +1 -1
  78. package/lib/engine-components/Animation.d.ts +1 -1
  79. package/lib/engine-components/Animation.js +1 -1
  80. package/lib/engine-components/Animator.d.ts +1 -1
  81. package/lib/engine-components/Animator.js +1 -1
  82. package/lib/engine-components/AudioListener.d.ts +1 -1
  83. package/lib/engine-components/AudioListener.js +1 -1
  84. package/lib/engine-components/AudioSource.d.ts +1 -1
  85. package/lib/engine-components/AudioSource.js +1 -1
  86. package/lib/engine-components/Camera.d.ts +1 -1
  87. package/lib/engine-components/Camera.js +5 -2
  88. package/lib/engine-components/Camera.js.map +1 -1
  89. package/lib/engine-components/CharacterController.d.ts +6 -2
  90. package/lib/engine-components/CharacterController.js +6 -2
  91. package/lib/engine-components/CharacterController.js.map +1 -1
  92. package/lib/engine-components/Collider.d.ts +1 -1
  93. package/lib/engine-components/Collider.js.map +1 -1
  94. package/lib/engine-components/Component.d.ts +2 -1
  95. package/lib/engine-components/Component.js +3 -2
  96. package/lib/engine-components/Component.js.map +1 -1
  97. package/lib/engine-components/DragControls.js +4 -1
  98. package/lib/engine-components/DragControls.js.map +1 -1
  99. package/lib/engine-components/DropListener.d.ts +1 -0
  100. package/lib/engine-components/DropListener.js +26 -8
  101. package/lib/engine-components/DropListener.js.map +1 -1
  102. package/lib/engine-components/EventList.js +4 -1
  103. package/lib/engine-components/EventList.js.map +1 -1
  104. package/lib/engine-components/Joints.d.ts +14 -0
  105. package/lib/engine-components/Joints.js +14 -0
  106. package/lib/engine-components/Joints.js.map +1 -1
  107. package/lib/engine-components/LookAtConstraint.d.ts +1 -1
  108. package/lib/engine-components/LookAtConstraint.js +1 -1
  109. package/lib/engine-components/OrbitControls.d.ts +1 -1
  110. package/lib/engine-components/OrbitControls.js +1 -1
  111. package/lib/engine-components/Renderer.d.ts +6 -0
  112. package/lib/engine-components/Renderer.js +6 -0
  113. package/lib/engine-components/Renderer.js.map +1 -1
  114. package/lib/engine-components/RendererInstancing.js +5 -3
  115. package/lib/engine-components/RendererInstancing.js.map +1 -1
  116. package/lib/engine-components/SceneSwitcher.d.ts +3 -2
  117. package/lib/engine-components/SceneSwitcher.js +38 -25
  118. package/lib/engine-components/SceneSwitcher.js.map +1 -1
  119. package/lib/engine-components/SpectatorCamera.js +15 -7
  120. package/lib/engine-components/SpectatorCamera.js.map +1 -1
  121. package/lib/engine-components/SpriteRenderer.d.ts +2 -1
  122. package/lib/engine-components/SpriteRenderer.js +2 -1
  123. package/lib/engine-components/SpriteRenderer.js.map +1 -1
  124. package/lib/engine-components/api.d.ts +1 -0
  125. package/lib/engine-components/api.js +1 -0
  126. package/lib/engine-components/api.js.map +1 -1
  127. package/lib/engine-components/codegen/components.d.ts +0 -1
  128. package/lib/engine-components/codegen/components.js +0 -1
  129. package/lib/engine-components/codegen/components.js.map +1 -1
  130. package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.js +8 -0
  131. package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.js.map +1 -1
  132. package/lib/engine-components/timeline/SignalAsset.d.ts +1 -1
  133. package/lib/engine-components/timeline/SignalAsset.js +1 -1
  134. package/lib/engine-components/ui/Raycaster.d.ts +3 -2
  135. package/lib/engine-components/ui/Raycaster.js +3 -2
  136. package/lib/engine-components/ui/Raycaster.js.map +1 -1
  137. package/lib/engine-components/ui/RectTransform.d.ts +6 -0
  138. package/lib/engine-components/ui/RectTransform.js +6 -0
  139. package/lib/engine-components/ui/RectTransform.js.map +1 -1
  140. package/lib/engine-components/utils/LookAt.d.ts +2 -1
  141. package/lib/engine-components/utils/LookAt.js +2 -1
  142. package/lib/engine-components/utils/LookAt.js.map +1 -1
  143. package/lib/engine-components/web/CursorFollow.d.ts +1 -1
  144. package/lib/engine-components/web/CursorFollow.js +1 -1
  145. package/lib/engine-components/web/HoverAnimation.d.ts +1 -1
  146. package/lib/engine-components/web/HoverAnimation.js +1 -1
  147. package/lib/engine-components/web/ViewBox.d.ts +1 -1
  148. package/lib/engine-components/web/ViewBox.js +1 -1
  149. package/lib/engine-components/webxr/Avatar.js +2 -0
  150. package/lib/engine-components/webxr/Avatar.js.map +1 -1
  151. package/lib/engine-components/webxr/WebARSessionRoot.d.ts +5 -2
  152. package/lib/engine-components/webxr/WebARSessionRoot.js +5 -2
  153. package/lib/engine-components/webxr/WebARSessionRoot.js.map +1 -1
  154. package/lib/engine-components/webxr/WebXR.d.ts +3 -1
  155. package/lib/engine-components/webxr/WebXR.js +21 -13
  156. package/lib/engine-components/webxr/WebXR.js.map +1 -1
  157. package/package.json +6 -6
  158. package/plugins/vite/poster-client.js +8 -1
  159. package/src/engine/codegen/register_types.ts +0 -2
  160. package/src/engine/debug/debug_console.ts +449 -1
  161. package/src/engine/engine_components.ts +4 -4
  162. package/src/engine/engine_context.ts +2 -0
  163. package/src/engine/engine_input.ts +7 -0
  164. package/src/engine/engine_license.ts +180 -17
  165. package/src/engine/engine_networking.ts +20 -5
  166. package/src/engine/engine_physics.ts +3 -3
  167. package/src/engine/engine_physics_rapier.ts +1 -1
  168. package/src/engine/engine_serialization_builtin_serializer.ts +1 -1
  169. package/src/engine/engine_three_utils.ts +4 -2
  170. package/src/engine/engine_utils.ts +23 -4
  171. package/src/engine/extensions/extensions.ts +30 -6
  172. package/src/engine/webcomponents/WebXRButtons.ts +15 -5
  173. package/src/engine/webcomponents/needle menu/needle-menu-spatial.ts +2 -1
  174. package/src/engine/webcomponents/needle menu/needle-menu.ts +39 -7
  175. package/src/engine/webcomponents/needle-engine.ar-overlay.ts +6 -0
  176. package/src/engine/webcomponents/needle-engine.ts +2 -2
  177. package/src/engine/xr/NeedleXRSession.ts +120 -24
  178. package/src/engine/xr/TempXRContext.ts +12 -2
  179. package/src/engine/xr/usdz.ts +6 -1
  180. package/src/engine-components/AlignmentConstraint.ts +1 -1
  181. package/src/engine-components/Animation.ts +1 -1
  182. package/src/engine-components/Animator.ts +1 -1
  183. package/src/engine-components/AudioListener.ts +1 -1
  184. package/src/engine-components/AudioSource.ts +1 -1
  185. package/src/engine-components/Camera.ts +5 -2
  186. package/src/engine-components/CharacterController.ts +6 -2
  187. package/src/engine-components/Collider.ts +1 -1
  188. package/src/engine-components/Component.ts +5 -4
  189. package/src/engine-components/DragControls.ts +5 -1
  190. package/src/engine-components/DropListener.ts +29 -8
  191. package/src/engine-components/EventList.ts +5 -1
  192. package/src/engine-components/Joints.ts +14 -0
  193. package/src/engine-components/LookAtConstraint.ts +1 -1
  194. package/src/engine-components/OrbitControls.ts +1 -1
  195. package/src/engine-components/Renderer.ts +6 -0
  196. package/src/engine-components/RendererInstancing.ts +6 -3
  197. package/src/engine-components/SceneSwitcher.ts +40 -30
  198. package/src/engine-components/SpectatorCamera.ts +21 -10
  199. package/src/engine-components/SpriteRenderer.ts +2 -1
  200. package/src/engine-components/api.ts +2 -1
  201. package/src/engine-components/codegen/components.ts +0 -1
  202. package/src/engine-components/export/usdz/extensions/behavior/BehaviourComponents.ts +11 -0
  203. package/src/engine-components/timeline/SignalAsset.ts +1 -1
  204. package/src/engine-components/ui/Raycaster.ts +3 -2
  205. package/src/engine-components/ui/RectTransform.ts +6 -0
  206. package/src/engine-components/utils/LookAt.ts +2 -1
  207. package/src/engine-components/web/CursorFollow.ts +1 -1
  208. package/src/engine-components/web/HoverAnimation.ts +1 -1
  209. package/src/engine-components/web/ViewBox.ts +1 -1
  210. package/src/engine-components/webxr/Avatar.ts +4 -0
  211. package/src/engine-components/webxr/WebARSessionRoot.ts +7 -3
  212. package/src/engine-components/webxr/WebXR.ts +23 -13
  213. package/dist/generateMeshBVH.worker-mO20N_b8.js +0 -21
  214. package/dist/needle-engine.bundle-4A5NjznD.min.js +0 -1647
  215. package/dist/needle-engine.bundle-BJg4_HhU.umd.cjs +0 -1647
  216. package/dist/vendor-BKGa4GE0.min.js +0 -1116
@@ -669,14 +669,17 @@ class InstancedMeshRenderer {
669
669
  private grow(geometry: BufferGeometry) {
670
670
  const id = ++this._growId;
671
671
  const growFactor = 2;
672
- const newSize = Math.ceil(this._maxInstanceCount * growFactor);
672
+
673
+ const growInstances = this.count >= this._maxInstanceCount;
674
+ const newSize = growInstances ? Math.ceil(this._maxInstanceCount * growFactor) : this._maxInstanceCount;
673
675
 
674
676
  // create a new BatchedMesh instance
675
677
  // TODO: we should keep track of how many instances for each geometry we have and consider that when estimating new space
676
678
  const estimatedSpace = this.tryEstimateVertexCountSize(newSize, [geometry]);// geometry.attributes.position.count;
677
679
  // const indices = geometry.index ? geometry.index.count : 0;
678
- const newMaxVertexCount = Math.max(this._maxVertexCount, estimatedSpace.vertexCount);
679
- const newMaxIndexCount = Math.max(this._maxIndexCount, estimatedSpace.indexCount);//, Math.ceil(this._maxVertexCount * growFactor));
680
+ const vertexGrowFactor = 1.25;
681
+ const newMaxVertexCount = Math.max(this._maxVertexCount, Math.ceil(estimatedSpace.vertexCount * vertexGrowFactor));
682
+ const newMaxIndexCount = Math.max(this._maxIndexCount, Math.ceil(estimatedSpace.indexCount * vertexGrowFactor));
680
683
 
681
684
  if (debugInstancing) {
682
685
  const geometryInfo = getMeshInformation(geometry);
@@ -1,7 +1,7 @@
1
1
  import { EquirectangularReflectionMapping, Object3D, Scene, Texture } from "three";
2
2
 
3
3
  import { AssetReference } from "../engine/engine_addressables.js";
4
- import { destroy } from "../engine/engine_gameobject.js";
4
+ import { destroy, instantiate } from "../engine/engine_gameobject.js";
5
5
  import { InputEvents } from "../engine/engine_input.js";
6
6
  import { isLocalNetwork } from "../engine/engine_networking_utils.js";
7
7
  import { serializable } from "../engine/engine_serialization.js";
@@ -247,21 +247,30 @@ export class SceneSwitcher extends Behaviour {
247
247
 
248
248
  private _currentIndex: number = -1;
249
249
  private _currentScene: AssetReference | undefined = undefined;
250
+ private _currentSceneAsset: Object3D | undefined = undefined;
250
251
  private _engineElementOverserver: MutationObserver | undefined = undefined;
251
252
 
252
253
  private _preloadScheduler?: PreLoadScheduler;
253
254
 
254
255
  private _menuButtons?: HTMLElement[];
255
256
 
257
+ // this is the scene that was requested last
258
+ private __lastSwitchScene?: AssetReference;
259
+ private __lastSwitchScenePromise?: Promise<boolean>;
260
+
256
261
  /** @internal */
257
262
  awake(): void {
263
+ this._currentScene = undefined;
264
+ this._lastLoadingScene = undefined;
265
+ this.__lastSwitchScenePromise = undefined;
266
+
258
267
  if (this.scenes === undefined) this.scenes = [];
259
268
  // remove all scenes from the url that are in the scenes array at startup
260
269
  for (const scene of this.scenes) {
261
270
  if (scene && !scene.hasUrl && scene.asset instanceof Object3D) {
262
271
  GameObject.remove(scene.asset);
263
272
  }
264
- else if(scene instanceof Object3D) {
273
+ else if (scene instanceof Object3D) {
265
274
  GameObject.remove(scene);
266
275
  }
267
276
  }
@@ -477,13 +486,13 @@ export class SceneSwitcher extends Behaviour {
477
486
  * @returns a promise that resolves to true if the scene was loaded successfully
478
487
  */
479
488
  select(index: number | string): Promise<boolean> {
480
- if (debug) console.log("select", index);
489
+ if (debug) console.log("[SceneSwitcher] select", index);
481
490
 
482
491
  if (typeof index === "object") {
483
492
  // If a user tries to reference a scene object in a UnityEvent and invoke select(obj)
484
493
  // Then the object will be serialized as a object { guid : ... } or with the index json pointer
485
494
  // This case is not supported right now. Object references in the editor must not be scene references
486
- console.warn("Switching to \"" + index + "\" might not work. Please either use an index or a AssetReference (not a scene reference)");
495
+ console.warn("[SceneSwitcher] Switching to \"" + index + "\" might not work. Please either use an index or a AssetReference (not a scene reference)");
487
496
  }
488
497
 
489
498
  if (typeof index === "string") {
@@ -538,10 +547,6 @@ export class SceneSwitcher extends Behaviour {
538
547
  return false;
539
548
  }
540
549
 
541
- // this is the scene that was requested last
542
- private __lastSwitchScene?: AssetReference;
543
- private __lastSwitchScenePromise?: Promise<boolean>;
544
-
545
550
  /**
546
551
  * Switch to a scene by its AssetReference.
547
552
  * If the scene is already loaded it will be unloaded and the new scene will be loaded.
@@ -595,20 +600,19 @@ export class SceneSwitcher extends Behaviour {
595
600
  const current = this._currentScene;
596
601
  this._currentScene = undefined;
597
602
  if (current) {
598
- if (debug) console.log("UNLOAD", current.url, "HasURL?: " + current.hasUrl)
603
+ if (debug) console.log("[SceneSwitcher] UNLOAD", current.url, "HasURL?: " + current.hasUrl)
599
604
  const sceneListener = this.tryGetSceneEventListener(current.asset as any as Object3D);
600
605
  if (sceneListener?.sceneClosing) {
601
606
  const res = sceneListener.sceneClosing();
602
607
  if (res instanceof Promise) await res;
603
608
  }
604
- // if the current scene has a URL (so it can be reloaded)
605
- // then we unload it
609
+
610
+ // // if the current scene has a URL (so it can be reloaded)
611
+ // // then we unload it
606
612
  if (current.hasUrl)
607
613
  current.unload();
608
- // otherwise if it's a regular Object3D we just remove it from the scene
609
- else if (current.asset instanceof Object3D) {
610
- GameObject.remove(current.asset as any as Object3D);
611
- }
614
+
615
+ if (this._currentSceneAsset) destroy(this._currentSceneAsset, true, false);
612
616
  }
613
617
  }
614
618
 
@@ -620,6 +624,7 @@ export class SceneSwitcher extends Behaviour {
620
624
  const index = this._currentIndex = this.scenes?.indexOf(scene) ?? -1;
621
625
 
622
626
  try {
627
+ if (debug) console.debug(`${Date.now()} [SceneSwitcher] Loading scene start: ${scene.url} (index: ${index})`);
623
628
  this._currentlyLoadingScene = scene;
624
629
  this._currentLoadingProgress = new ProgressEvent("progress", { loaded: 0, total: 1 });
625
630
 
@@ -632,7 +637,7 @@ export class SceneSwitcher extends Behaviour {
632
637
  if (debug) {
633
638
  const t01 = prog.loaded / prog.total;
634
639
  const progressBarString = "[" + "=".repeat(Math.floor(t01 * 20)) + "-".repeat(20 - Math.floor(t01 * 20)) + "]";
635
- console.debug(`[SceneSwitcher] Download ${(t01 * 100).toFixed(1)} % ${progressBarString}`, scene.url);
640
+ console.debug(`${Date.now()} [SceneSwitcher] Loading scene progress: ${(t01 * 100).toFixed(1)} % ${progressBarString}`, scene.url);
636
641
  }
637
642
  this._currentLoadingProgress = prog;
638
643
  this.dispatchEvent(prog);
@@ -646,18 +651,17 @@ export class SceneSwitcher extends Behaviour {
646
651
  this._currentlyLoadingScene = undefined;
647
652
 
648
653
  if (finishedEvt.defaultPrevented) {
649
- if (debug) console.warn("Adding loaded scene prevented:", scene, finishedEvt);
654
+ if (debug) console.warn("[SceneSwitcher] Adding loaded scene prevented:", scene, finishedEvt);
650
655
  return false;
651
656
  }
652
657
  if (!scene.asset) {
653
- if (debug) console.warn("Failed loading scene:", scene);
658
+ if (debug) console.warn("[SceneSwitcher] Failed loading scene:", scene);
654
659
  return false;
655
660
  }
656
661
  if (this._currentIndex === index) {
657
- if (debug) console.log("ADD", scene.url);
662
+ if (debug) console.log("[SceneSwitcher] ADD", scene.url);
658
663
  this._currentScene = scene;
659
664
 
660
-
661
665
  // Experimental: replace the whole content of the scene
662
666
  if (experimental_clearSceneOnLoad) {
663
667
  const camera = this.context.mainCameraComponent?.gameObject || this.context.mainCamera;
@@ -671,7 +675,14 @@ export class SceneSwitcher extends Behaviour {
671
675
  }
672
676
  }
673
677
 
674
- GameObject.add(scene.asset, this.gameObject);
678
+ // @TODO: if multiple scene switcher or scenes use this asset already it will be moved
679
+ if (!scene.asset.parent) {
680
+ this._currentSceneAsset = scene.asset;
681
+ GameObject.add(scene.asset, this.gameObject);
682
+ }
683
+ else {
684
+ this._currentSceneAsset = instantiate(scene.asset, { parent: this.gameObject });
685
+ }
675
686
 
676
687
  if (this.useSceneLighting)
677
688
  this.context.sceneLighting.enable(scene);
@@ -683,7 +694,7 @@ export class SceneSwitcher extends Behaviour {
683
694
  this.context.scene.background = skybox;
684
695
  }
685
696
  else if (debug) {
686
- console.warn("SceneSwitcher: Can't find skybox for scene " + scene.url);
697
+ console.warn("[SceneSwitcher] Can't find skybox for scene " + scene.url);
687
698
  }
688
699
  }
689
700
 
@@ -713,10 +724,9 @@ export class SceneSwitcher extends Behaviour {
713
724
  const res = sceneListener.sceneOpened(this);
714
725
  if (res instanceof Promise) await res;
715
726
  }
716
-
727
+ if (debug) console.debug(`${Date.now()} [SceneSwitcher] Loading scene finished: ${scene.url} (index: ${index})`);
717
728
  const openedEvt = new CustomEvent<LoadSceneEvent>("scene-opened", { detail: { scene: scene, switcher: this, index: index } });
718
729
  this.dispatchEvent(openedEvt);
719
-
720
730
  this.sceneLoaded?.invoke(this);
721
731
  return true;
722
732
  }
@@ -772,7 +782,7 @@ export class SceneSwitcher extends Behaviour {
772
782
  }
773
783
  }
774
784
 
775
- if (isLocalNetwork()) console.warn("Can not find scene: \"" + value + "\"", this)
785
+ if (isLocalNetwork()) console.warn("[SceneSwitcher] Can not find scene: \"" + value + "\"", this)
776
786
 
777
787
  return couldNotLoadScenePromise;
778
788
  }
@@ -913,7 +923,7 @@ class PreLoadScheduler {
913
923
  */
914
924
  begin(delay: number) {
915
925
  if (this._isRunning) return;
916
- if (debug) console.log("Preload begin", { delay })
926
+ if (debug) console.log("[SceneSwitcher] Preload scheduled", { delay });
917
927
  this._isRunning = true;
918
928
  let lastRoom: number = -10;
919
929
  let searchDistance: number;
@@ -923,7 +933,7 @@ class PreLoadScheduler {
923
933
  const interval = setInterval(() => {
924
934
  if (this.allLoaded()) {
925
935
  if (debug)
926
- console.log("All scenes (pre-)loaded");
936
+ console.log("[SceneSwitcher] All scenes (pre-)loaded");
927
937
  this.stop();
928
938
  }
929
939
  if (!this._isRunning) {
@@ -950,7 +960,7 @@ class PreLoadScheduler {
950
960
  if (roomIndex < 0 || roomIndex >= array.length) return;
951
961
  if (!this._loadTasks.some(t => t.index === roomIndex)) {
952
962
  const scene = array[roomIndex];
953
- if (debug) console.log("Preload scene", { roomIndex, searchForward, lastRoom, currentIndex: this._switcher.currentIndex, tasks: this._loadTasks.length }, scene?.url);
963
+ if (debug) console.log("[SceneSwitcher] Schedule preload scene", { roomIndex, searchForward, lastRoom, currentIndex: this._switcher.currentIndex, tasks: this._loadTasks.length }, scene?.url);
954
964
  new LoadTask(roomIndex, scene, this._loadTasks);
955
965
  }
956
966
  }, 200);
@@ -1019,10 +1029,10 @@ class LoadTask {
1019
1029
  private async awaitLoading() {
1020
1030
  if (this.asset && !this.asset.isLoaded()) {
1021
1031
  if (debug)
1022
- console.log("Preload start: " + this.asset.url, this.index);
1032
+ console.log("[SceneSwitcher] Preload start: " + this.asset.url, this.index);
1023
1033
  await this.asset.preload();
1024
1034
  if (debug)
1025
- console.log("Preload finished: " + this.asset.url, this.index);
1035
+ console.log("[SceneSwitcher] Preload finished: " + this.asset.url, this.index);
1026
1036
  }
1027
1037
 
1028
1038
  const i = this.tasks.indexOf(this);
@@ -8,7 +8,8 @@ import { PlayerView, ViewDevice } from "../engine/engine_playerview.js";
8
8
  import { serializable } from "../engine/engine_serialization.js";
9
9
  import { Context } from "../engine/engine_setup.js";
10
10
  import type { ICamera } from "../engine/engine_types.js";
11
- import { getParam } from "../engine/engine_utils.js";
11
+ import { DeviceUtilities, getParam } from "../engine/engine_utils.js";
12
+ import { PlayerState } from "../engine-components-experimental/networking/PlayerSync.js";
12
13
  import { Camera } from "./Camera.js";
13
14
  import { Behaviour, Component, GameObject } from "./Component.js";
14
15
  import { OrbitControls } from "./OrbitControls.js";
@@ -98,7 +99,7 @@ export class SpectatorCamera extends Behaviour {
98
99
  }
99
100
 
100
101
  /** Gets the local player's connection ID */
101
- private get localId() : string {
102
+ private get localId(): string {
102
103
  return this.context.connection.connectionId ?? "local";
103
104
  }
104
105
 
@@ -196,9 +197,8 @@ export class SpectatorCamera extends Behaviour {
196
197
  */
197
198
  private isSupportedPlatform() {
198
199
  const ua = window.navigator.userAgent;
199
- const standalone = /Windows|MacOS/.test(ua);
200
200
  const isHololens = /Windows NT/.test(ua) && /Edg/.test(ua) && !/Win64/.test(ua);
201
- return standalone && !isHololens;
201
+ return DeviceUtilities.isDesktop() && !DeviceUtilities.isMobileDevice() && !isHololens;
202
202
  }
203
203
 
204
204
  /**
@@ -268,11 +268,16 @@ export class SpectatorCamera extends Behaviour {
268
268
  const previousRenderTarget = renderer.getRenderTarget();
269
269
  let oldFramebuffer: WebGLFramebuffer | null = null;
270
270
 
271
+
271
272
  const webglState = renderer.state as WebGLState & { bindXRFramebuffer?: Function };
272
273
 
274
+
273
275
  // seems that in some cases, renderer.getRenderTarget returns null
274
276
  // even when we're rendering to a headset.
275
- if (!previousRenderTarget) {
277
+ if (!previousRenderTarget ||
278
+ // Prevent rendering if in XR - @TODO: check if we need to allow this for VR?
279
+ previousRenderTarget["isXRRenderTarget"] === true)
280
+ {
276
281
  if (!renderer.state.bindFramebuffer || !webglState.bindXRFramebuffer)
277
282
  return;
278
283
 
@@ -557,12 +562,18 @@ class SpectatorSelectionController {
557
562
  for (const hit of hits) {
558
563
  if (hit.distance < .2) continue;
559
564
  const obj = hit.object;
560
- const avatar = GameObject.getComponentInParent(obj, AvatarMarker);
561
- const id = avatar?.connectionId;
565
+ // For WebXR
566
+ const state = PlayerState.getFor(obj);
567
+ let id = state?.owner;
568
+ // for SpectatorCamera
569
+ if (!id) {
570
+ const avatar = GameObject.getComponentInParent(obj, AvatarMarker);
571
+ id = avatar?.connectionId;
572
+ }
562
573
  if (id) {
563
574
  const view = this.context.players.getPlayerView(id);
564
575
  this.spectator.target = view;
565
- if (debug) console.log("spectate", id, avatar);
576
+ if (debug) console.log("spectate", id, state);
566
577
  break;
567
578
  }
568
579
  }
@@ -633,7 +644,7 @@ class SpectatorCamNetworking {
633
644
  this.context.connection.beginListen("spectator-request-follow", this._requestFollowMethod);
634
645
  this.context.connection.beginListen(RoomEvents.JoinedRoom, this._joinedRoomMethod);
635
646
  this.context.domElement.addEventListener("keydown", evt => {
636
- if(!this.spectator.useKeys) return;
647
+ if (!this.spectator.useKeys) return;
637
648
  if (evt.key === "f") {
638
649
  this.onRequestFollowMe();
639
650
  }
@@ -767,7 +778,7 @@ class SpectatorCamNetworking {
767
778
  }
768
779
 
769
780
  private _enforceFollowInterval: any;
770
-
781
+
771
782
  /**
772
783
  * Periodically retries following a user if the initial attempt failed
773
784
  */
@@ -262,7 +262,8 @@ export class SpriteData {
262
262
  *
263
263
  * - Example: https://engine.needle.tools/samples/spritesheet-animation
264
264
  *
265
- * @category Sprites
265
+ * @summary Renders 2D images from a sprite sheet
266
+ * @category Rendering
266
267
  * @group Components
267
268
  */
268
269
  export class SpriteRenderer extends Behaviour {
@@ -35,7 +35,8 @@
35
35
  */
36
36
 
37
37
  export * from "./codegen/components.js";
38
- export { Behaviour, Component, GameObject } from "./Component.js"
38
+ export { Collider } from "./Collider.js"; // export abstract type
39
+ export { Behaviour, Component, GameObject } from "./Component.js";
39
40
 
40
41
  // We dont want to export everything in the extensions
41
42
  export { ClearFlags } from "./Camera.js"
@@ -23,7 +23,6 @@ export { BoxHelperComponent } from "../BoxHelperComponent.js";
23
23
  export { Camera } from "../Camera.js";
24
24
  export { CharacterController } from "../CharacterController.js";
25
25
  export { CharacterControllerInput } from "../CharacterController.js";
26
- export { Collider } from "../Collider.js";
27
26
  export { SphereCollider } from "../Collider.js";
28
27
  export { BoxCollider } from "../Collider.js";
29
28
  export { MeshCollider } from "../Collider.js";
@@ -11,6 +11,7 @@ import { Animation } from "../../../../Animation.js";
11
11
  import { Animator } from "../../../../Animator.js";
12
12
  import { AudioSource } from "../../../../AudioSource.js";
13
13
  import { Behaviour, GameObject } from "../../../../Component.js";
14
+ import { Rigidbody } from "../../../../RigidBody.js";
14
15
  import type { IPointerClickHandler, PointerEventData } from "../../../../ui/PointerEvents.js";
15
16
  import { ObjectRaycaster,Raycaster } from "../../../../ui/Raycaster.js";
16
17
  import { makeNameSafeForUSD,USDDocument, USDObject, USDZExporterContext } from "../../ThreeUSDZExporter.js";
@@ -68,6 +69,16 @@ export class ChangeTransformOnClick extends Behaviour implements IPointerClickHa
68
69
  }
69
70
 
70
71
  onPointerClick(args: PointerEventData) {
72
+
73
+ const rbs = this.object?.getComponentsInChildren(Rigidbody);
74
+
75
+ if (rbs){
76
+ for (const rb of rbs) {
77
+ rb.resetVelocities();
78
+ rb.resetForcesAndTorques();
79
+ }
80
+ }
81
+
71
82
  args.use();
72
83
  if (this.coroutine) this.stopCoroutine(this.coroutine);
73
84
  if (!this.relativeMotion)
@@ -30,7 +30,7 @@ export class SignalReceiverEvent {
30
30
  * Signals can be added to a signal track on a {@link PlayableDirector}
31
31
  *
32
32
  * @summary Receives signals and invokes reactions
33
- * @category Sequencing and Timelines
33
+ * @category Animation and Sequencing
34
34
  * @group Components
35
35
  */
36
36
  export class SignalReceiver extends Behaviour {
@@ -31,7 +31,7 @@ export abstract class Raycaster extends Behaviour {
31
31
  /**
32
32
  * A Raycaster that performs raycasting against its own GameObject.
33
33
  *
34
- * @category Interaction
34
+ * @category Interactivity
35
35
  * @group Components
36
36
  */
37
37
  export class ObjectRaycaster extends Raycaster {
@@ -75,7 +75,8 @@ export class ObjectRaycaster extends Raycaster {
75
75
  /**
76
76
  * A Raycaster that performs raycasting against UI elements (objects with a CanvasRenderer component).
77
77
  *
78
- * @category UI
78
+ * @summary Raycaster for UI elements
79
+ * @category User Interface
79
80
  * @group Components
80
81
  */
81
82
  export class GraphicRaycaster extends ObjectRaycaster {
@@ -29,6 +29,12 @@ const tempVec = new Vector3();
29
29
  const tempMatrix = new Matrix4();
30
30
  const tempQuaternion = new Quaternion();
31
31
 
32
+ /**
33
+ * RectTransform is a component that defines a rectangle for UI layout.
34
+ * @summary UI Rectangle Transform
35
+ * @category User Interface
36
+ * @group Components
37
+ */
32
38
  export class RectTransform extends BaseUIComponent implements IRectTransform, IRectTransformChangedReceiver {
33
39
 
34
40
  get parent() {
@@ -13,7 +13,8 @@ import { Behaviour } from "../Component.js";
13
13
  * It can also invert the forward direction and keep the up direction.
14
14
  *
15
15
  * @summary Makes the object look at a target object or the camera
16
- * @category Interactivity, Everywhere Actions
16
+ * @category Everywhere Actions
17
+ * @category Interactivity
17
18
  * @group Components
18
19
  */
19
20
  export class LookAt extends Behaviour implements UsdzBehaviour {
@@ -15,7 +15,7 @@ const debug = getParam("debugcursor");
15
15
  * - Example: [Look At Cursor sample](https://engine.needle.tools/samples/look-at-cursor-interactive-3d-header/). This sample combines the CursorFollow component with a LookAt component to create an interactive 3D header that looks at the cursor.
16
16
  *
17
17
  * @summary Makes the object follow the cursor position on screen
18
- * @category Web
18
+ * @category Interactivity
19
19
  * @group Components
20
20
  * @component
21
21
  */
@@ -14,7 +14,7 @@ import { Behaviour } from "../Component.js";
14
14
  * By default, a simple scale-up animation is used. You can customize the hover and idle animations by providing your own animation clips.
15
15
  *
16
16
  * @summary Hover Animation on Pointer Enter/Exit
17
- * @category Web
17
+ * @category Interactivity
18
18
  * @group Components
19
19
  */
20
20
  @registerType
@@ -32,7 +32,7 @@ export type ViewBoxMode = "continuous" | "once";
32
32
  * ```
33
33
 
34
34
  * @summary Automatically fits a box area into the camera view
35
- * @category Camera
35
+ * @category Camera and Controls
36
36
  * @group Components
37
37
  * @component
38
38
  */
@@ -2,6 +2,7 @@ import { Mesh, Object3D, Quaternion, Vector3 } from "three";
2
2
 
3
3
  import { AssetReference } from "../../engine/engine_addressables.js";
4
4
  import { ObjectUtils, PrimitiveType } from "../../engine/engine_create_objects.js";
5
+ import { ViewDevice } from "../../engine/engine_playerview.js";
5
6
  import { serializable } from "../../engine/engine_serialization_decorator.js";
6
7
  import type { IGameObject } from "../../engine/engine_types.js";
7
8
  import { getParam, PromiseAllWithErrors } from "../../engine/engine_utils.js";
@@ -55,10 +56,13 @@ export class Avatar extends Behaviour {
55
56
  const marker = this.gameObject.addComponent(AvatarMarker)!;
56
57
  marker.avatar = this.gameObject;
57
58
  marker.connectionId = playerstate.owner;
59
+
60
+ this.context.players.setPlayerView(playerstate.owner, this.head?.asset, ViewDevice.Headset);
58
61
  }
59
62
  else if (this.context.connection.isConnected) console.error("No player state found for avatar", this);
60
63
  // don't destroy the avatar when entering XR and not connected to a networking backend
61
64
  else if (playerstate && !this.context.connection.isConnected) playerstate.dontDestroy = true;
65
+
62
66
  }
63
67
 
64
68
  onLeaveXR(_args: NeedleXREventArgs): void {
@@ -10,6 +10,7 @@ import type { IComponent, IGameObject } from "../../engine/engine_types.js";
10
10
  import { DeviceUtilities, getParam } from "../../engine/engine_utils.js";
11
11
  import { NeedleXRController, type NeedleXREventArgs, type NeedleXRHitTestResult, NeedleXRSession } from "../../engine/engine_xr.js";
12
12
  import { Behaviour, GameObject } from "../Component.js";
13
+ import type { WebXR } from "./WebXR.js";
13
14
 
14
15
  // https://github.com/takahirox/takahirox.github.io/blob/master/js.mmdeditor/examples/js/controls/DeviceOrientationControls.js
15
16
 
@@ -20,14 +21,17 @@ const invertForwardMatrix = new Matrix4().makeRotationY(Math.PI);
20
21
 
21
22
  /**
22
23
  * The WebARSessionRoot is the root object for a WebAR session and used to place the scene in AR.
23
- * It is also responsible for scaling the user in AR and to define the center of the AR scene. If not present in the scene it will be created automatically by the WebXR component when entering an AR session.
24
+ * It is also responsible for scaling the user in AR and to define the center of the AR scene.
25
+ * If not present in the scene it will be created automatically by the WebXR component when entering an AR session.
24
26
  *
25
- * @example
27
+ * **Note**: If the WebXR component {@link WebXR.autoCenter} option is enabled the scene will be automatically centered based on the content in the scene.
28
+ *
29
+ * @example Callback when the scene has been placed in AR:
26
30
  * ```ts
27
31
  * WebARSessionRoot.onPlaced((args) => {
28
32
  * console.log("Scene has been placed in AR");
29
33
  * });
30
- * ```
34
+ * ```
31
35
  *
32
36
  * @summary Root object for WebAR sessions, managing scene placement and user scaling in AR.
33
37
  * @category XR
@@ -23,7 +23,7 @@ const debug = getParam("debugwebxr");
23
23
  const debugQuicklook = getParam("debugusdz");
24
24
 
25
25
  /**
26
- * Use the WebXR component to enable VR, AR and Quicklook on iOS in your scene.
26
+ * Use the WebXR component to enable VR and AR on iOS and Android in your scene. VisionOS support is also provided via QuickLook USDZ export.
27
27
  *
28
28
  * The WebXR component is a simple to use wrapper around the {@link NeedleXRSession} API and adds some additional features like creating buttons for AR, VR, enabling default movement behaviour ({@link XRControllerMovement}) and controller rendering ({@link XRControllerModel}), as well as handling AR placement and Quicklook USDZ export.
29
29
  *
@@ -146,7 +146,9 @@ export class WebXR extends Behaviour {
146
146
 
147
147
  /**
148
148
  * When enabled, the AR session root center will be automatically adjusted to place the center of the scene.
149
- * This helps ensure the scene is properly aligned with detected surfaces.
149
+ * This helps ensure the scene is properly aligned with detected surfaces.
150
+ *
151
+ * **Note**: This option overrides the placement of the {@link WebARSessionRoot} component if both are used.
150
152
  */
151
153
  @serializable()
152
154
  autoCenter: boolean = false;
@@ -210,17 +212,25 @@ export class WebXR extends Behaviour {
210
212
  showBalloonWarning("<a href=\"https://developer.mozilla.org/en-US/docs/Web/API/WebXR_Device_API\" target=\"_blank\">WebXR</a> only works on secure connections (https).");
211
213
  }
212
214
 
213
- if (this.useQuicklookExport) {
214
- const existingUSDZExporter = GameObject.findObjectOfType(USDZExporter);
215
- if (!existingUSDZExporter) {
216
- // if no USDZ Exporter is found we add one and assign the scene to be exported
217
- if (debug) console.log("WebXR: Adding USDZExporter");
218
- this._usdzExporter = GameObject.addComponent(this.gameObject, USDZExporter);
219
- this._usdzExporter.objectToExport = this.context.scene;
220
- this._usdzExporter.autoExportAnimations = true;
221
- this._usdzExporter.autoExportAudioSources = true;
215
+ // Showing the QuickLook button depends on whether we're on iOS or visionOS –
216
+ // on iOS we have AppClip support, so we don't need QuickLook button there,
217
+ // while on visionOS we use QuickLook for AR experiences for now (unless it happens to have WebXR support by then).
218
+ navigator.xr?.isSessionSupported("immersive-ar").catch(() => false).then((arSupported) => {
219
+
220
+ const isVisionOSFallback = DeviceUtilities.isVisionOS() && !arSupported;
221
+
222
+ if (this.useQuicklookExport || isVisionOSFallback) {
223
+ const existingUSDZExporter = GameObject.findObjectOfType(USDZExporter);
224
+ if (!existingUSDZExporter) {
225
+ // if no USDZ Exporter is found we add one and assign the scene to be exported
226
+ if (debug) console.log("WebXR: Adding USDZExporter");
227
+ this._usdzExporter = GameObject.addComponent(this.gameObject, USDZExporter);
228
+ this._usdzExporter.objectToExport = this.context.scene;
229
+ this._usdzExporter.autoExportAnimations = true;
230
+ this._usdzExporter.autoExportAudioSources = true;
231
+ }
222
232
  }
223
- }
233
+ });
224
234
 
225
235
  this.handleCreatingHTML();
226
236
  this.handleOfferSession();
@@ -360,7 +370,7 @@ export class WebXR extends Behaviour {
360
370
 
361
371
  // Handle AR session root
362
372
  if (args.xr.isAR) {
363
- let sessionroot = GameObject.findObjectOfType(WebARSessionRoot);
373
+ let sessionroot = GameObject.findObjectOfType(WebARSessionRoot, this.context, false);
364
374
  // Only create a WebARSessionRoot if none is in the scene already
365
375
  if (!sessionroot) {
366
376
  if (this.usePlacementReticle) {