@needle-tools/engine 4.15.0-next.f391a30 → 4.16.0-next.0798cbb

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 (393) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +92 -46
  3. package/SKILL.md +240 -0
  4. package/components.needle.json +1 -1
  5. package/dist/{gltf-progressive-DYL3SLVb.min.js → gltf-progressive-DQa78GTA.min.js} +1 -1
  6. package/dist/{gltf-progressive-CMwJPwEt.umd.cjs → gltf-progressive-LOFTyzy4.umd.cjs} +1 -1
  7. package/dist/{gltf-progressive-CTlvpS3A.js → gltf-progressive-_wvokUUu.js} +3 -3
  8. package/dist/{materialx-NDD0y4JY.umd.cjs → materialx-BrPdNmQT.umd.cjs} +1 -1
  9. package/dist/{materialx-4jJLLe9Q.js → materialx-CT8J50pg.js} +2 -2
  10. package/dist/{materialx-Bt9FHwco.min.js → materialx-D_ofN96q.min.js} +1 -1
  11. package/dist/{needle-engine.bundle-DsTdfmeb.min.js → needle-engine.bundle-D-KMaXfY.min.js} +109 -111
  12. package/dist/{needle-engine.bundle-C1BFRZDF.umd.cjs → needle-engine.bundle-DEWMFvfK.umd.cjs} +114 -116
  13. package/dist/{needle-engine.bundle-DB4kLWO_.js → needle-engine.bundle-Dz6Tag-6.js} +3209 -3206
  14. package/dist/needle-engine.d.ts +48 -320
  15. package/dist/needle-engine.js +4 -4
  16. package/dist/needle-engine.min.js +1 -1
  17. package/dist/needle-engine.umd.cjs +1 -1
  18. package/dist/{postprocessing-De9ZpJrk.js → postprocessing-C-WOZQC5.js} +2 -2
  19. package/dist/{postprocessing-DYmYOVm4.umd.cjs → postprocessing-CtXfLXvp.umd.cjs} +1 -1
  20. package/dist/{postprocessing-BN-f4viE.min.js → postprocessing-DXm8YKbQ.min.js} +1 -1
  21. package/dist/{three-examples-C0ZCCA_K.js → three-examples.js} +1 -1
  22. package/dist/{three-examples-DmTY8tGr.min.js → three-examples.min.js} +1 -1
  23. package/dist/{three-examples-BHqRVpO_.umd.cjs → three-examples.umd.cjs} +1 -1
  24. package/dist/{three-mesh-ui-BlakAItG.js → three-mesh-ui-B-lqrZWj.js} +1 -1
  25. package/dist/{three-mesh-ui-D828VbQp.umd.cjs → three-mesh-ui-Chib781Y.umd.cjs} +1 -1
  26. package/dist/{three-mesh-ui-5HVE2RV-.min.js → three-mesh-ui-n3JU4M2W.min.js} +1 -1
  27. package/dist/{three-BjYim-vL.umd.cjs → three.umd.cjs} +1 -1
  28. package/dist/{vendor-ixwD-vv2.js → vendor-BsRxp-FT.js} +1 -1
  29. package/dist/{vendor-CIDkyBaO.umd.cjs → vendor-BwxpsdCm.umd.cjs} +1 -1
  30. package/dist/{vendor-BxK0WKmT.min.js → vendor-DZ45lcA8.min.js} +1 -1
  31. package/lib/asap/needle-asap.js.map +1 -1
  32. package/lib/asap/sessiongranted.js.map +1 -1
  33. package/lib/engine/analytics/index.d.ts +1 -1
  34. package/lib/engine/analytics/lcp.js.map +1 -1
  35. package/lib/engine/assets/index.js.map +1 -1
  36. package/lib/engine/debug/debug.d.ts +4 -4
  37. package/lib/engine/debug/debug.js +6 -6
  38. package/lib/engine/debug/debug.js.map +1 -1
  39. package/lib/engine/debug/debug_console.js.map +1 -1
  40. package/lib/engine/debug/debug_overlay.d.ts +16 -1
  41. package/lib/engine/debug/debug_overlay.js +47 -10
  42. package/lib/engine/debug/debug_overlay.js.map +1 -1
  43. package/lib/engine/debug/debug_spatial_console.js.map +1 -1
  44. package/lib/engine/debug/debug_spector.js.map +1 -1
  45. package/lib/engine/engine_accessibility.js.map +1 -1
  46. package/lib/engine/engine_addressables.d.ts +6 -3
  47. package/lib/engine/engine_addressables.js +10 -3
  48. package/lib/engine/engine_addressables.js.map +1 -1
  49. package/lib/engine/engine_animation.js.map +1 -1
  50. package/lib/engine/engine_application.d.ts +0 -7
  51. package/lib/engine/engine_application.js.map +1 -1
  52. package/lib/engine/engine_assetdatabase.js.map +1 -1
  53. package/lib/engine/engine_audio.js.map +1 -1
  54. package/lib/engine/engine_camera.fit.js.map +1 -1
  55. package/lib/engine/engine_camera.js.map +1 -1
  56. package/lib/engine/engine_components.js.map +1 -1
  57. package/lib/engine/engine_components_internal.js.map +1 -1
  58. package/lib/engine/engine_constants.js.map +1 -1
  59. package/lib/engine/engine_context.d.ts +0 -1
  60. package/lib/engine/engine_context.js +1 -1
  61. package/lib/engine/engine_context.js.map +1 -1
  62. package/lib/engine/engine_context_registry.js.map +1 -1
  63. package/lib/engine/engine_coroutine.js.map +1 -1
  64. package/lib/engine/engine_create_objects.js.map +1 -1
  65. package/lib/engine/engine_editor-sync.d.ts +1 -1
  66. package/lib/engine/engine_gameobject.js.map +1 -1
  67. package/lib/engine/engine_generic_utils.js.map +1 -1
  68. package/lib/engine/engine_gizmos.js.map +1 -1
  69. package/lib/engine/engine_gltf.js.map +1 -1
  70. package/lib/engine/engine_gltf_builtin_components.js +2 -2
  71. package/lib/engine/engine_gltf_builtin_components.js.map +1 -1
  72. package/lib/engine/engine_hot_reload.js.map +1 -1
  73. package/lib/engine/engine_input.d.ts +0 -1
  74. package/lib/engine/engine_input.js.map +1 -1
  75. package/lib/engine/engine_instancing.js.map +1 -1
  76. package/lib/engine/engine_license.js.map +1 -1
  77. package/lib/engine/engine_lifecycle_functions_internal.js.map +1 -1
  78. package/lib/engine/engine_lightdata.js.map +1 -1
  79. package/lib/engine/engine_loaders.callbacks.js.map +1 -1
  80. package/lib/engine/engine_loaders.d.ts +7 -4
  81. package/lib/engine/engine_loaders.gltf.js.map +1 -1
  82. package/lib/engine/engine_loaders.js +7 -4
  83. package/lib/engine/engine_loaders.js.map +1 -1
  84. package/lib/engine/engine_lods.js.map +1 -1
  85. package/lib/engine/engine_mainloop_utils.d.ts +0 -1
  86. package/lib/engine/engine_mainloop_utils.js.map +1 -1
  87. package/lib/engine/engine_materialpropertyblock.js.map +1 -1
  88. package/lib/engine/engine_math.js.map +1 -1
  89. package/lib/engine/engine_networking.js.map +1 -1
  90. package/lib/engine/engine_networking_auto.js.map +1 -1
  91. package/lib/engine/engine_networking_blob.js.map +1 -1
  92. package/lib/engine/engine_networking_files.js.map +1 -1
  93. package/lib/engine/engine_networking_instantiate.js.map +1 -1
  94. package/lib/engine/engine_networking_peer.js.map +1 -1
  95. package/lib/engine/engine_networking_streams.js +2 -0
  96. package/lib/engine/engine_networking_streams.js.map +1 -1
  97. package/lib/engine/engine_patcher.js.map +1 -1
  98. package/lib/engine/engine_physics.d.ts +2 -2
  99. package/lib/engine/engine_physics.js.map +1 -1
  100. package/lib/engine/engine_physics_rapier.js.map +1 -1
  101. package/lib/engine/engine_playerview.js.map +1 -1
  102. package/lib/engine/engine_pmrem.js.map +1 -1
  103. package/lib/engine/engine_scenelighting.d.ts +1 -1
  104. package/lib/engine/engine_scenelighting.js.map +1 -1
  105. package/lib/engine/engine_serialization_builtin_serializer.js.map +1 -1
  106. package/lib/engine/engine_serialization_core.js.map +1 -1
  107. package/lib/engine/engine_serialization_decorator.d.ts +2 -2
  108. package/lib/engine/engine_serialization_decorator.js.map +1 -1
  109. package/lib/engine/engine_shaders.js.map +1 -1
  110. package/lib/engine/engine_shims.js.map +1 -1
  111. package/lib/engine/engine_texture.js.map +1 -1
  112. package/lib/engine/engine_three_utils.js.map +1 -1
  113. package/lib/engine/engine_time_utils.js.map +1 -1
  114. package/lib/engine/engine_tonemapping.js.map +1 -1
  115. package/lib/engine/engine_types.d.ts +0 -1
  116. package/lib/engine/engine_types.js.map +1 -1
  117. package/lib/engine/engine_typestore.js.map +1 -1
  118. package/lib/engine/engine_util_decorator.js +1 -1
  119. package/lib/engine/engine_util_decorator.js.map +1 -1
  120. package/lib/engine/engine_utils.js.map +1 -1
  121. package/lib/engine/engine_utils_attributes.js.map +1 -1
  122. package/lib/engine/engine_utils_format.js.map +1 -1
  123. package/lib/engine/engine_utils_qrcode.js.map +1 -1
  124. package/lib/engine/engine_utils_screenshot.js.map +1 -1
  125. package/lib/engine/engine_utils_screenshot.xr.js.map +1 -1
  126. package/lib/engine/export/gltf/EXT_mesh_gpu_instancing_exporter.js.map +1 -1
  127. package/lib/engine/export/gltf/Writers.js.map +1 -1
  128. package/lib/engine/export/gltf/index.js.map +1 -1
  129. package/lib/engine/export/state.js.map +1 -1
  130. package/lib/engine/extensions/EXT_texture_exr.js.map +1 -1
  131. package/lib/engine/extensions/NEEDLE_components.js.map +1 -1
  132. package/lib/engine/extensions/NEEDLE_gameobject_data.js.map +1 -1
  133. package/lib/engine/extensions/NEEDLE_lighting_settings.js.map +1 -1
  134. package/lib/engine/extensions/NEEDLE_lightmaps.js.map +1 -1
  135. package/lib/engine/extensions/NEEDLE_materialx.js.map +1 -1
  136. package/lib/engine/extensions/NEEDLE_persistent_assets.js.map +1 -1
  137. package/lib/engine/extensions/NEEDLE_render_objects.js.map +1 -1
  138. package/lib/engine/extensions/NEEDLE_techniques_webgl.js.map +1 -1
  139. package/lib/engine/extensions/extension_utils.js.map +1 -1
  140. package/lib/engine/extensions/extensions.js.map +1 -1
  141. package/lib/engine/extensions/usage_tracker.js.map +1 -1
  142. package/lib/engine/js-extensions/ExtensionUtils.js.map +1 -1
  143. package/lib/engine/js-extensions/Object3D.js.map +1 -1
  144. package/lib/engine/js-extensions/RGBAColor.js.map +1 -1
  145. package/lib/engine/js-extensions/Vector.js.map +1 -1
  146. package/lib/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js.map +1 -1
  147. package/lib/engine/shaders/shaderData.d.ts +6 -6
  148. package/lib/engine/tests/test_utils.js.map +1 -1
  149. package/lib/engine/webcomponents/WebXRButtons.d.ts +0 -1
  150. package/lib/engine/webcomponents/WebXRButtons.js.map +1 -1
  151. package/lib/engine/webcomponents/buttons.js.map +1 -1
  152. package/lib/engine/webcomponents/fonts.js.map +1 -1
  153. package/lib/engine/webcomponents/icons.js.map +1 -1
  154. package/lib/engine/webcomponents/logo-element.d.ts +3 -6
  155. package/lib/engine/webcomponents/logo-element.js +0 -18
  156. package/lib/engine/webcomponents/logo-element.js.map +1 -1
  157. package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js.map +1 -1
  158. package/lib/engine/webcomponents/needle menu/needle-menu.d.ts +7 -10
  159. package/lib/engine/webcomponents/needle menu/needle-menu.js +4 -16
  160. package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
  161. package/lib/engine/webcomponents/needle-button.js.map +1 -1
  162. package/lib/engine/webcomponents/needle-engine.ar-overlay.d.ts +0 -1
  163. package/lib/engine/webcomponents/needle-engine.ar-overlay.js.map +1 -1
  164. package/lib/engine/webcomponents/needle-engine.d.ts +0 -4
  165. package/lib/engine/webcomponents/needle-engine.js +1 -11
  166. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  167. package/lib/engine/webcomponents/needle-engine.loading.js.map +1 -1
  168. package/lib/engine/xr/NeedleXRController.d.ts +0 -1
  169. package/lib/engine/xr/NeedleXRController.js +1 -1
  170. package/lib/engine/xr/NeedleXRController.js.map +1 -1
  171. package/lib/engine/xr/NeedleXRSession.d.ts +0 -1
  172. package/lib/engine/xr/NeedleXRSession.js.map +1 -1
  173. package/lib/engine/xr/NeedleXRSync.d.ts +0 -1
  174. package/lib/engine/xr/NeedleXRSync.js.map +1 -1
  175. package/lib/engine/xr/SceneTransition.js.map +1 -1
  176. package/lib/engine/xr/TempXRContext.d.ts +0 -1
  177. package/lib/engine/xr/TempXRContext.js.map +1 -1
  178. package/lib/engine/xr/events.js.map +1 -1
  179. package/lib/engine/xr/internal.js.map +1 -1
  180. package/lib/engine/xr/usdz.js.map +1 -1
  181. package/lib/engine/xr/utils.js.map +1 -1
  182. package/lib/engine-components/AlignmentConstraint.js.map +1 -1
  183. package/lib/engine-components/Animation.js.map +1 -1
  184. package/lib/engine-components/AnimationCurve.js.map +1 -1
  185. package/lib/engine-components/AnimationUtils.js.map +1 -1
  186. package/lib/engine-components/AnimationUtilsAutoplay.js.map +1 -1
  187. package/lib/engine-components/Animator.js.map +1 -1
  188. package/lib/engine-components/AnimatorController.js +1 -1
  189. package/lib/engine-components/AnimatorController.js.map +1 -1
  190. package/lib/engine-components/AudioListener.js.map +1 -1
  191. package/lib/engine-components/AudioSource.js.map +1 -1
  192. package/lib/engine-components/AvatarLoader.js.map +1 -1
  193. package/lib/engine-components/AxesHelper.js.map +1 -1
  194. package/lib/engine-components/BoxHelperComponent.js.map +1 -1
  195. package/lib/engine-components/Camera.js.map +1 -1
  196. package/lib/engine-components/CameraUtils.js.map +1 -1
  197. package/lib/engine-components/CharacterController.js.map +1 -1
  198. package/lib/engine-components/Collider.js.map +1 -1
  199. package/lib/engine-components/Component.d.ts +0 -1
  200. package/lib/engine-components/Component.js.map +1 -1
  201. package/lib/engine-components/ContactShadows.d.ts +0 -1
  202. package/lib/engine-components/ContactShadows.js.map +1 -1
  203. package/lib/engine-components/DeleteBox.js.map +1 -1
  204. package/lib/engine-components/DeviceFlag.js.map +1 -1
  205. package/lib/engine-components/DragControls.js +10 -0
  206. package/lib/engine-components/DragControls.js.map +1 -1
  207. package/lib/engine-components/DropListener.js.map +1 -1
  208. package/lib/engine-components/Duplicatable.js +8 -1
  209. package/lib/engine-components/Duplicatable.js.map +1 -1
  210. package/lib/engine-components/EventList.js.map +1 -1
  211. package/lib/engine-components/EventTrigger.js.map +1 -1
  212. package/lib/engine-components/Gizmos.js.map +1 -1
  213. package/lib/engine-components/GridHelper.js.map +1 -1
  214. package/lib/engine-components/GroundProjection.js.map +1 -1
  215. package/lib/engine-components/Joints.js.map +1 -1
  216. package/lib/engine-components/LODGroup.js.map +1 -1
  217. package/lib/engine-components/Light.js.map +1 -1
  218. package/lib/engine-components/NeedleMenu.js.map +1 -1
  219. package/lib/engine-components/NestedGltf.js.map +1 -1
  220. package/lib/engine-components/Networking.js.map +1 -1
  221. package/lib/engine-components/OffsetConstraint.js.map +1 -1
  222. package/lib/engine-components/OrbitControls.js.map +1 -1
  223. package/lib/engine-components/PlayerColor.js.map +1 -1
  224. package/lib/engine-components/ReflectionProbe.js.map +1 -1
  225. package/lib/engine-components/Renderer.js +2 -1
  226. package/lib/engine-components/Renderer.js.map +1 -1
  227. package/lib/engine-components/RendererInstancing.js.map +1 -1
  228. package/lib/engine-components/RendererLightmap.js.map +1 -1
  229. package/lib/engine-components/RigidBody.js.map +1 -1
  230. package/lib/engine-components/SceneSwitcher.js.map +1 -1
  231. package/lib/engine-components/ScreenCapture.js.map +1 -1
  232. package/lib/engine-components/SeeThrough.js.map +1 -1
  233. package/lib/engine-components/ShadowCatcher.js.map +1 -1
  234. package/lib/engine-components/Skybox.js.map +1 -1
  235. package/lib/engine-components/SmoothFollow.js.map +1 -1
  236. package/lib/engine-components/SpatialTrigger.js.map +1 -1
  237. package/lib/engine-components/SpectatorCamera.js.map +1 -1
  238. package/lib/engine-components/SpriteRenderer.js.map +1 -1
  239. package/lib/engine-components/SyncedCamera.js.map +1 -1
  240. package/lib/engine-components/SyncedRoom.js +1 -1
  241. package/lib/engine-components/SyncedRoom.js.map +1 -1
  242. package/lib/engine-components/SyncedTransform.js.map +1 -1
  243. package/lib/engine-components/TestRunner.js.map +1 -1
  244. package/lib/engine-components/TransformGizmo.js.map +1 -1
  245. package/lib/engine-components/VideoPlayer.js.map +1 -1
  246. package/lib/engine-components/Voip.js.map +1 -1
  247. package/lib/engine-components/avatar/AvatarBlink_Simple.js.map +1 -1
  248. package/lib/engine-components/avatar/AvatarEyeLook_Rotation.js.map +1 -1
  249. package/lib/engine-components/avatar/Avatar_Brain_LookAt.js.map +1 -1
  250. package/lib/engine-components/avatar/Avatar_MouthShapes.js.map +1 -1
  251. package/lib/engine-components/avatar/Avatar_MustacheShake.js.map +1 -1
  252. package/lib/engine-components/debug/LogStats.js.map +1 -1
  253. package/lib/engine-components/export/gltf/GltfExport.js +1 -1
  254. package/lib/engine-components/export/gltf/GltfExport.js.map +1 -1
  255. package/lib/engine-components/export/usdz/ThreeUSDZExporter.d.ts +1 -1
  256. package/lib/engine-components/export/usdz/ThreeUSDZExporter.js +23 -23
  257. package/lib/engine-components/export/usdz/ThreeUSDZExporter.js.map +1 -1
  258. package/lib/engine-components/export/usdz/USDZExporter.js.map +1 -1
  259. package/lib/engine-components/export/usdz/extensions/Animation.d.ts +2 -2
  260. package/lib/engine-components/export/usdz/extensions/Animation.js.map +1 -1
  261. package/lib/engine-components/export/usdz/extensions/NodeMaterialConverter.js.map +1 -1
  262. package/lib/engine-components/export/usdz/extensions/USDZText.js.map +1 -1
  263. package/lib/engine-components/export/usdz/extensions/USDZUI.js.map +1 -1
  264. package/lib/engine-components/export/usdz/extensions/behavior/Actions.js.map +1 -1
  265. package/lib/engine-components/export/usdz/extensions/behavior/AudioExtension.js.map +1 -1
  266. package/lib/engine-components/export/usdz/extensions/behavior/Behaviour.js.map +1 -1
  267. package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.js.map +1 -1
  268. package/lib/engine-components/export/usdz/extensions/behavior/BehavioursBuilder.js.map +1 -1
  269. package/lib/engine-components/export/usdz/extensions/behavior/PhysicsExtension.js.map +1 -1
  270. package/lib/engine-components/export/usdz/utils/animationutils.js.map +1 -1
  271. package/lib/engine-components/export/usdz/utils/quicklook.js.map +1 -1
  272. package/lib/engine-components/particlesystem/ParticleSystem.js.map +1 -1
  273. package/lib/engine-components/particlesystem/ParticleSystemModules.js.map +1 -1
  274. package/lib/engine-components/particlesystem/ParticleSystemSubEmitter.js.map +1 -1
  275. package/lib/engine-components/postprocessing/Effects/Antialiasing.js.map +1 -1
  276. package/lib/engine-components/postprocessing/Effects/BloomEffect.js +2 -2
  277. package/lib/engine-components/postprocessing/Effects/BloomEffect.js.map +1 -1
  278. package/lib/engine-components/postprocessing/Effects/ChromaticAberration.js.map +1 -1
  279. package/lib/engine-components/postprocessing/Effects/ColorAdjustments.js.map +1 -1
  280. package/lib/engine-components/postprocessing/Effects/DepthOfField.js.map +1 -1
  281. package/lib/engine-components/postprocessing/Effects/Pixelation.js.map +1 -1
  282. package/lib/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusion.js +2 -2
  283. package/lib/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusion.js.map +1 -1
  284. package/lib/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusionN8.js.map +1 -1
  285. package/lib/engine-components/postprocessing/Effects/Tonemapping.js.map +1 -1
  286. package/lib/engine-components/postprocessing/Effects/Tonemapping.utils.d.ts +3 -3
  287. package/lib/engine-components/postprocessing/Effects/Tonemapping.utils.js.map +1 -1
  288. package/lib/engine-components/postprocessing/PostProcessingEffect.js.map +1 -1
  289. package/lib/engine-components/postprocessing/PostProcessingHandler.js.map +1 -1
  290. package/lib/engine-components/postprocessing/Volume.js.map +1 -1
  291. package/lib/engine-components/postprocessing/VolumeParameter.js.map +1 -1
  292. package/lib/engine-components/postprocessing/VolumeProfile.js.map +1 -1
  293. package/lib/engine-components/postprocessing/utils.js.map +1 -1
  294. package/lib/engine-components/splines/Spline.js.map +1 -1
  295. package/lib/engine-components/splines/SplineWalker.js.map +1 -1
  296. package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
  297. package/lib/engine-components/timeline/SignalAsset.js.map +1 -1
  298. package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
  299. package/lib/engine-components/ui/BaseUIComponent.js.map +1 -1
  300. package/lib/engine-components/ui/Button.js.map +1 -1
  301. package/lib/engine-components/ui/Canvas.js.map +1 -1
  302. package/lib/engine-components/ui/CanvasGroup.js.map +1 -1
  303. package/lib/engine-components/ui/EventSystem.js.map +1 -1
  304. package/lib/engine-components/ui/Graphic.js.map +1 -1
  305. package/lib/engine-components/ui/Image.js.map +1 -1
  306. package/lib/engine-components/ui/InputField.js.map +1 -1
  307. package/lib/engine-components/ui/Layout.js.map +1 -1
  308. package/lib/engine-components/ui/PointerEvents.d.ts +0 -1
  309. package/lib/engine-components/ui/PointerEvents.js.map +1 -1
  310. package/lib/engine-components/ui/RaycastUtils.js.map +1 -1
  311. package/lib/engine-components/ui/Raycaster.js.map +1 -1
  312. package/lib/engine-components/ui/RectTransform.js +2 -2
  313. package/lib/engine-components/ui/RectTransform.js.map +1 -1
  314. package/lib/engine-components/ui/SpatialHtml.js.map +1 -1
  315. package/lib/engine-components/ui/Text.js.map +1 -1
  316. package/lib/engine-components/ui/Utils.js.map +1 -1
  317. package/lib/engine-components/utils/EnvironmentScene.js.map +1 -1
  318. package/lib/engine-components/utils/LookAt.js.map +1 -1
  319. package/lib/engine-components/utils/OpenURL.js.map +1 -1
  320. package/lib/engine-components/web/Clickthrough.js.map +1 -1
  321. package/lib/engine-components/web/CursorFollow.js.map +1 -1
  322. package/lib/engine-components/web/HoverAnimation.js.map +1 -1
  323. package/lib/engine-components/web/ScrollFollow.js.map +1 -1
  324. package/lib/engine-components/web/ViewBox.js +2 -1
  325. package/lib/engine-components/web/ViewBox.js.map +1 -1
  326. package/lib/engine-components/webxr/Avatar.js.map +1 -1
  327. package/lib/engine-components/webxr/WebARCameraBackground.d.ts +0 -1
  328. package/lib/engine-components/webxr/WebARCameraBackground.js.map +1 -1
  329. package/lib/engine-components/webxr/WebARSessionRoot.d.ts +0 -1
  330. package/lib/engine-components/webxr/WebARSessionRoot.js.map +1 -1
  331. package/lib/engine-components/webxr/WebXR.d.ts +0 -1
  332. package/lib/engine-components/webxr/WebXR.js.map +1 -1
  333. package/lib/engine-components/webxr/WebXRImageTracking.d.ts +0 -1
  334. package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
  335. package/lib/engine-components/webxr/WebXRPlaneTracking.d.ts +2 -3
  336. package/lib/engine-components/webxr/WebXRPlaneTracking.js.map +1 -1
  337. package/lib/engine-components/webxr/WebXRRig.d.ts +0 -1
  338. package/lib/engine-components/webxr/WebXRRig.js.map +1 -1
  339. package/lib/engine-components/webxr/XRFlag.js.map +1 -1
  340. package/lib/engine-components/webxr/controllers/XRControllerFollow.d.ts +0 -1
  341. package/lib/engine-components/webxr/controllers/XRControllerFollow.js.map +1 -1
  342. package/lib/engine-components/webxr/controllers/XRControllerModel.d.ts +0 -1
  343. package/lib/engine-components/webxr/controllers/XRControllerModel.js.map +1 -1
  344. package/lib/engine-components/webxr/controllers/XRControllerMovement.js.map +1 -1
  345. package/lib/engine-components-experimental/Presentation.js.map +1 -1
  346. package/lib/engine-components-experimental/networking/PlayerSync.js.map +1 -1
  347. package/lib/engine-schemes/schemes.js.map +1 -1
  348. package/lib/needle-engine.js.map +1 -1
  349. package/package.json +7 -5
  350. package/plugins/common/buildinfo.js +1 -1
  351. package/plugins/common/license.js +5 -6
  352. package/plugins/common/logger.js +104 -14
  353. package/plugins/types/userconfig.d.ts +2 -0
  354. package/plugins/vite/ai.js +4 -18
  355. package/plugins/vite/alias.js +0 -13
  356. package/plugins/vite/asap.js +1 -1
  357. package/plugins/vite/build-pipeline.js +2 -5
  358. package/plugins/vite/buildinfo.js +9 -9
  359. package/plugins/vite/copyfiles.js +19 -16
  360. package/plugins/vite/custom-element-data.js +4 -4
  361. package/plugins/vite/dependencies.js +45 -18
  362. package/plugins/vite/dependency-watcher.js +10 -8
  363. package/plugins/vite/imports-logger.js +14 -12
  364. package/plugins/vite/local-files-analysis.js +10 -12
  365. package/plugins/vite/local-files-core.js +8 -8
  366. package/plugins/vite/local-files-types.d.ts +49 -11
  367. package/plugins/vite/local-files-utils.js +14 -10
  368. package/plugins/vite/logger.client.js +4 -4
  369. package/plugins/vite/logger.js +7 -7
  370. package/plugins/vite/logging.js +26 -3
  371. package/plugins/vite/pwa.js +6 -5
  372. package/plugins/vite/reload.js +27 -24
  373. package/src/asap/needle-asap.ts +1 -1
  374. package/src/engine/debug/debug.ts +8 -7
  375. package/src/engine/debug/debug_overlay.ts +66 -12
  376. package/src/engine/debug/debug_spector.ts +1 -1
  377. package/src/engine/engine_addressables.ts +11 -3
  378. package/src/engine/engine_application.ts +0 -7
  379. package/src/engine/engine_context.ts +1 -1
  380. package/src/engine/engine_gltf_builtin_components.ts +1 -1
  381. package/src/engine/engine_loaders.ts +7 -4
  382. package/src/engine/engine_networking_streams.ts +1 -0
  383. package/src/engine/engine_util_decorator.ts +2 -2
  384. package/src/engine/webcomponents/logo-element.ts +3 -20
  385. package/src/engine/webcomponents/needle menu/needle-menu.ts +11 -25
  386. package/src/engine/webcomponents/needle-engine.ts +1 -13
  387. package/src/engine-components/DragControls.ts +14 -0
  388. package/src/engine-components/Duplicatable.ts +9 -1
  389. package/src/engine-components/Renderer.ts +2 -1
  390. package/src/engine-components/SyncedRoom.ts +1 -1
  391. package/src/engine-components/export/usdz/USDZExporter.ts +1 -1
  392. /package/dist/{three-Bvk2VKbF.js → three.js} +0 -0
  393. /package/dist/{three-IG2qPafA.min.js → three.min.js} +0 -0
@@ -15,14 +15,14 @@ const filesUsingHotReload = new Set();
15
15
  let assetsDirectory = "";
16
16
 
17
17
  /**
18
- * @param {string} command
18
+ * @param {"build" | "serve"} command
19
19
  * @param {import('../types').userSettings | null} config
20
20
  * @param {import('../types').userSettings} userSettings
21
21
  */
22
22
  export const needleReload = (command, config, userSettings) => {
23
- if (command === "build") return;
23
+ if (command === "build") return undefined;
24
24
 
25
- if (userSettings?.noReload === true) return;
25
+ if (userSettings?.noReload === true) return undefined;
26
26
 
27
27
 
28
28
  let isUpdatingConfig = false;
@@ -31,7 +31,7 @@ export const needleReload = (command, config, userSettings) => {
31
31
  isUpdatingConfig = true;
32
32
  const res = await loadConfig();
33
33
  isUpdatingConfig = false;
34
- if (res) config = res;
34
+ if (res) config = /** @type {import('../types').userSettings} */ (res);
35
35
  }
36
36
 
37
37
  const projectConfig = tryLoadProjectConfig();
@@ -54,11 +54,12 @@ export const needleReload = (command, config, userSettings) => {
54
54
  config(config) {
55
55
  if (!config.server) config.server = { watch: { ignored: [] } };
56
56
  else if (!config.server.watch) config.server.watch = { ignored: [] };
57
- else if (!config.server.watch.ignored) config.server.watch.ignored = [];
57
+ else if (!config.server.watch?.ignored) config.server.watch.ignored = [];
58
58
  for (const pattern of ignorePatterns)
59
+ // @ts-ignore - watch.ignored is guaranteed to be string[] by the guards above
59
60
  config.server.watch.ignored.push(pattern);
60
- if (config?.debug === true || userSettings?.debug === true)
61
- setTimeout(() => needleLog("needle-reload", "Updated server ignore patterns: " + JSON.stringify(config.server.watch.ignored)), 100);
61
+ if (userSettings?.debug === true)
62
+ setTimeout(() => needleLog("needle-reload", "Updated server ignore patterns: " + JSON.stringify(config.server?.watch?.ignored)), 100);
62
63
  },
63
64
  /** @param {{file: string, server: import('vite').ViteDevServer, modules: unknown[], read: (file?: string) => Promise<string>, buildDirectory?: string}} args */
64
65
  handleHotUpdate(args) {
@@ -67,10 +68,10 @@ export const needleReload = (command, config, userSettings) => {
67
68
  },
68
69
  /** @param {string} src @param {string} id */
69
70
  transform(src, id) {
70
- if (!id.includes(".ts")) return;
71
+ if (!id.includes(".ts")) return undefined;
71
72
  updateConfig();
72
- if (config?.allowHotReload === false) return;
73
- if (userSettings?.allowHotReload === false) return;
73
+ if (config?.allowHotReload === false) return undefined;
74
+ if (userSettings?.allowHotReload === false) return undefined;
74
75
  src = insertScriptRegisterHotReloadCode(src, id);
75
76
  return insertScriptHotReloadCode(src, id);
76
77
  },
@@ -118,24 +119,25 @@ function notifyClientWillReload(server, file) {
118
119
 
119
120
  /**
120
121
  * @param {{file: string, server: import('vite').ViteDevServer, modules: unknown[], read: (file?: string) => Promise<string>, buildDirectory?: string}} param0
122
+ * @returns {Promise<any>}
121
123
  */
122
- async function handleReload({ file, server, modules, read, buildDirectory }) {
124
+ async function handleReload({ file, server, modules: _modules, read, buildDirectory }) {
123
125
 
124
126
  // dont reload the full page on css changes
125
127
  const isCss = file.endsWith(".css") || file.endsWith(".scss") || file.endsWith(".sass")
126
- if (isCss) return;
128
+ if (isCss) return null;
127
129
 
128
130
  // Dont reload the whole server when a file that is using hot reload changes
129
131
  if (filesUsingHotReload.has(file)) {
130
132
  console.log("File is using hot reload: " + file);
131
- return;
133
+ return null;
132
134
  }
133
135
 
134
136
  // the poster is generated after the server has started
135
137
  // we dont want to specifically handle the png or webp that gets generated
136
- if (file.includes(posterPath)) return;
138
+ if (file.includes(posterPath)) return null;
137
139
 
138
- if (file.endsWith("build.log")) return;
140
+ if (file.endsWith("build.log")) return null;
139
141
 
140
142
  // if (file.endsWith("/codegen/register_types.js" || file.endsWith("/generated/register_types.js"))) {
141
143
  // console.log("Ignore change in codegen file: " + file);
@@ -178,24 +180,25 @@ async function handleReload({ file, server, modules, read, buildDirectory }) {
178
180
  // these are known file types we export from integrations
179
181
  const knownExportFileTypes = [ ".glb", ".gltf", ".bin", "exr", ".ktx2", ".mp3", ".ogg", ".mp4", ".webm" ];
180
182
  if (!knownExportFileTypes.some((type) => file.endsWith(type)))
181
- return;
183
+ return null;
182
184
 
183
185
  // we only care about exports into "assets"
184
186
  if (!path.resolve(file).startsWith(assetsDirectory))
185
- return;
187
+ return null;
186
188
 
187
189
  if (file.endsWith(".svelte") || file.endsWith(".vue") || file.endsWith(".ts") || file.endsWith(".js") || file.endsWith(".jsx") || file.endsWith(".tsx"))
188
- return;
190
+ return null;
189
191
 
190
- if (file.endsWith(lockFileName)) return;
191
- let fileSize = "";
192
+ if (file.endsWith(lockFileName)) return null;
193
+ /** @type {number} */
194
+ let fileSize = 0;
192
195
  const isGlbOrGltfFile = file.endsWith(".glb") || file.endsWith(".bin");
193
196
  if (isGlbOrGltfFile && existsSync(file)) {
194
197
  fileSize = statSync(file).size;
195
198
  // the file is about to be created/written to
196
199
  if (fileSize <= 0) {
197
200
  // console.log("> File is changing: " + getFileNameLog(file));
198
- return;
201
+ return null;
199
202
  }
200
203
  }
201
204
 
@@ -307,8 +310,8 @@ const HOT_RELOAD_END_MARKER = "NEEDLE_HOT_RELOAD_END";
307
310
 
308
311
  /** @param {string} src @param {string} filePath @returns {{code: string, map: null} | undefined} */
309
312
  function insertScriptHotReloadCode(src, filePath) {
310
- if (filePath.includes("engine_hot_reload")) return;
311
- if (filePath.includes(".vite")) return;
313
+ if (filePath.includes("engine_hot_reload")) return undefined;
314
+ if (filePath.includes(".vite")) return undefined;
312
315
 
313
316
  const originalFilePath = filePath;
314
317
 
@@ -326,7 +329,7 @@ function insertScriptHotReloadCode(src, filePath) {
326
329
  if (filePath.includes("@needle-tools/engine")) {
327
330
  // only make engine components hot reloadable
328
331
  if (!filePath.includes("engine/engine-components"))
329
- return;
332
+ return undefined;
330
333
  // make import path from engine package
331
334
  const fullPathToHotReload = process.cwd() + "/node_modules/@needle-tools/engine/src/engine/engine_hot_reload.ts";
332
335
  // console.log(fullPathToHotReload);
@@ -15,7 +15,7 @@ let needleEngineElement: HTMLElement | null = null;
15
15
  startup();
16
16
  handleSessionGrantedASAP({ debug });
17
17
 
18
- function startup(iteration: number = 0): number | undefined {
18
+ function startup(iteration: number = 0): ReturnType<typeof setTimeout> | undefined {
19
19
 
20
20
 
21
21
  needleEngineElement = document.querySelector("needle-engine");
@@ -1,6 +1,6 @@
1
1
  import { isLocalNetwork } from "../engine_networking_utils.js";
2
2
  import { getParam } from "../engine_utils.js";
3
- import { addLog, clearMessages, LogType, setAllowBalloonMessages, setAllowOverlayMessages } from "./debug_overlay.js";
3
+ import { addLog, BalloonOptions, clearMessages, LogType, setAllowBalloonMessages, setAllowOverlayMessages } from "./debug_overlay.js";
4
4
 
5
5
  export {
6
6
  clearMessages as clearBalloonMessages,
@@ -15,18 +15,19 @@ export { enableSpatialConsole } from "./debug_spatial_console.js";
15
15
 
16
16
  const noDevLogs = getParam("nodevlogs");
17
17
 
18
+
18
19
  /** Displays a debug message on screen for a certain amount of time */
19
- export function showBalloonMessage(text: string, logType: LogType = LogType.Log): void {
20
- addLog(logType, text);
20
+ export function showBalloonMessage(text: string, options?: Partial<BalloonOptions>): void {
21
+ addLog(options?.type ?? LogType.Log, text, options);
21
22
  }
22
23
 
23
24
  /** Displays a warning message on screen for a certain amount of time */
24
- export function showBalloonWarning(text: string): void {
25
- showBalloonMessage(text, LogType.Warn);
25
+ export function showBalloonWarning(text: string, options?: Partial<BalloonOptions>): void {
26
+ showBalloonMessage(text, { ...options, type: LogType.Warn });
26
27
  }
27
28
  /** Displays an error message on screen for a certain amount of time */
28
- export function showBalloonError(text: string): void {
29
- showBalloonMessage(text, LogType.Error);
29
+ export function showBalloonError(text: string, options?: Partial<BalloonOptions>): void {
30
+ showBalloonMessage(text, { ...options, type: LogType.Error });
30
31
  }
31
32
 
32
33
  let _manuallySetDevEnvironment: boolean | undefined;
@@ -13,6 +13,21 @@ export enum LogType {
13
13
  Warn,
14
14
  Error
15
15
  }
16
+ export type BalloonOptions = {
17
+ type: LogType,
18
+ /**
19
+ * A key can be used to update an existing message instead of showing a new one.
20
+ */
21
+ key?: string,
22
+ /**
23
+ * If true, only show this message once. If the same message is logged again, it will be ignored. Note that messages are considered the same if their text is identical, so using this with dynamic values might lead to unexpected results.
24
+ */
25
+ once?: boolean,
26
+ /**
27
+ * Duration in seconds for how long the message should be shown. By default, messages will be shown for 10 seconds.
28
+ */
29
+ duration?: number,
30
+ }
16
31
 
17
32
  export function getErrorCount() {
18
33
  return _errorCount;
@@ -42,7 +57,7 @@ const originalConsoleError = console.error;
42
57
  const patchedConsoleError = function (...args: any[]) {
43
58
  originalConsoleError.apply(console, args);
44
59
  onParseError(args);
45
- addLog(LogType.Error, args, null, null);
60
+ addLog(LogType.Error, args, {}, null, null);
46
61
  onReceivedError(...args);
47
62
  }
48
63
 
@@ -74,14 +89,14 @@ export function makeErrorsVisibleForDevelopment() {
74
89
  console.warn("Received unknown error", event, event.target);
75
90
  return;
76
91
  }
77
- addLog(LogType.Error, message, event.filename, event.lineno);
92
+ addLog(LogType.Error, message, {}, event.filename, event.lineno);
78
93
  onReceivedError(event);
79
94
  }, true);
80
95
  window.addEventListener("unhandledrejection", (event) => {
81
96
  if (hide) return;
82
97
  if (!event) return;
83
98
  if (event.reason)
84
- addLog(LogType.Error, event.reason.message, event.reason.stack);
99
+ addLog(LogType.Error, event.reason.message, {}, event.reason.stack);
85
100
  else
86
101
  addLog(LogType.Error, "unhandled rejection");
87
102
  onReceivedError(event);
@@ -107,8 +122,30 @@ function onParseError(args: Array<any>) {
107
122
  }
108
123
  }
109
124
 
110
- export function addLog(type: LogType, message: string | any[], _file?: string | null, _line?: number | null) {
125
+ const seen = new Set<string>();
126
+
127
+ export function addLog(type: LogType, message: string | any[], opts: Omit<BalloonOptions, "type"> = {}, _file?: string | null, _line?: number | null) {
111
128
  if (hide) return;
129
+
130
+ if (opts.once === true) {
131
+ let key = "";
132
+ if (Array.isArray(message)) {
133
+ for (let i = 0; i < message.length; i++) {
134
+ let msgPart = message[i];
135
+ if (msgPart instanceof Error) {
136
+ msgPart = msgPart.message;
137
+ }
138
+ if (typeof msgPart === "object") continue;
139
+ if (i > 0) key += " ";
140
+ key += msgPart;
141
+ }
142
+ } else if (typeof message === "string") {
143
+ key = message;
144
+ }
145
+ if (seen.has(key)) return;
146
+ seen.add(key);
147
+ }
148
+
112
149
  const context = ContextRegistry.Current;
113
150
  let domElement = context?.domElement ?? document.querySelector("needle-engine");
114
151
  // check if we're in webxr dom overlay
@@ -130,7 +167,7 @@ export function addLog(type: LogType, message: string | any[], _file?: string |
130
167
  message = newMessage;
131
168
  }
132
169
  if (!message || message.length <= 0) return;
133
- showMessage(type, domElement, message);
170
+ showMessage(type, domElement, message, opts);
134
171
  }
135
172
 
136
173
  // function getLocation(err: Error): string {
@@ -147,10 +184,13 @@ export function addLog(type: LogType, message: string | any[], _file?: string |
147
184
  /**
148
185
  *
149
186
  */
150
- const currentMessages = new Map<string, Function>();
151
-
187
+ const currentMessages = new Map<string, {
188
+ update: (newText: string, opts: Omit<BalloonOptions, "type">) => void,
189
+ removeFunction: () => void,
190
+ }>();
191
+ const minDuration = .2; // minimum duration in seconds for messages to be shown, to prevent flicker
152
192
 
153
- function showMessage(type: LogType, element: HTMLElement, msg: string | null | undefined) {
193
+ function showMessage(type: LogType, element: HTMLElement, msg: string | null | undefined, opts: Omit<BalloonOptions, "type"> = {}) {
154
194
  if (msg === null || msg === undefined) return;
155
195
 
156
196
  const container = getLogsContainer(element);
@@ -161,9 +201,11 @@ function showMessage(type: LogType, element: HTMLElement, msg: string | null | u
161
201
  // truncate long messages before they go into the cache/set
162
202
  if (msg.length > 400) msg = msg.substring(0, 400) + "...";
163
203
 
164
- const key = msg;
204
+ const key = opts.key ?? msg;
165
205
 
166
206
  if (currentMessages.has(key)) {
207
+ const existing = currentMessages.get(key);
208
+ existing?.update(msg, opts);
167
209
  return;
168
210
  }
169
211
 
@@ -174,9 +216,21 @@ function showMessage(type: LogType, element: HTMLElement, msg: string | null | u
174
216
  currentMessages.delete(key);
175
217
  returnMessageContainer(msgcontainer);
176
218
  };
177
- currentMessages.set(key, removeFunction);
219
+
220
+ let timeout = setTimeout(removeFunction, (Math.max(minDuration, opts.duration ?? 10)) * 1000);
221
+
222
+ currentMessages.set(key, {
223
+ update: (newText, newOpts) => {
224
+ if (newText.length > 400) newText = newText.substring(0, 400) + "...";
225
+ msgcontainer.innerHTML = newText;
226
+ if (newOpts.duration) {
227
+ clearTimeout(timeout);
228
+ timeout = setTimeout(removeFunction, Math.max(minDuration, newOpts.duration) * 1000);
229
+ }
230
+ },
231
+ removeFunction
232
+ });
178
233
 
179
- setTimeout(removeFunction, 10_000);
180
234
  }
181
235
 
182
236
  /**
@@ -185,7 +239,7 @@ function showMessage(type: LogType, element: HTMLElement, msg: string | null | u
185
239
  export function clearMessages() {
186
240
  if (debug) console.log("Clearing messages");
187
241
  for (const cur of currentMessages.values()) {
188
- cur?.call(cur);
242
+ cur?.removeFunction.call(cur);
189
243
  }
190
244
  currentMessages.clear();
191
245
  }
@@ -29,7 +29,7 @@ export function initSpectorIfAvailable(_context: Context, canvas: HTMLCanvasElem
29
29
  waitForFrameAndCapture();
30
30
  return;
31
31
 
32
- function waitForFrameAndCapture() {
32
+ function waitForFrameAndCapture(): number | void {
33
33
  if (frame > _context.time.frame) return window.requestAnimationFrame(() => waitForFrameAndCapture());
34
34
  const res = spector.captureCanvas(canvas);
35
35
  if (res && res instanceof Promise) res.then(() => spector.displayUI());
@@ -328,12 +328,20 @@ export class AssetReference {
328
328
  }
329
329
 
330
330
  // TODO: we need a way to abort loading a resource
331
- /** Loads the asset and creates one instance (assigned to `asset`)
332
- * @returns the loaded asset
331
+ /** Loads the asset and returns a single shared instance (assigned to {@link asset}).
332
+ * Calling this multiple times will **not** create additional instances — it returns the same `Object3D`.
333
+ * To create a new independent clone, use {@link instantiate} instead.
334
+ * @param prog Optional progress callback invoked during download.
335
+ * @returns The loaded root `Object3D`, or `null` if loading fails.
333
336
  */
334
337
  async loadAssetAsync(prog?: ProgressCallback | null): Promise<Object3D | null> {
335
338
  if (debug) console.log("[AssetReference] loadAssetAsync", this.url);
336
- if (!this.mustLoad) return this.asset;
339
+ if (!this.mustLoad) {
340
+ if (this.asset?.parent) {
341
+ console.warn(`[AssetReference] "${this.urlName}" is already loaded and parented to "${this.asset.parent.name || "scene"}". loadAssetAsync() returns the same shared instance — use .instantiate() to create a new copy.`);
342
+ }
343
+ return this.asset;
344
+ }
337
345
 
338
346
  if (prog) this._progressListeners.push(prog);
339
347
 
@@ -29,13 +29,6 @@ document.addEventListener('touchend', internalOnUserInputRegistered);
29
29
  document.addEventListener('keydown', internalOnUserInputRegistered);
30
30
 
31
31
 
32
- declare global {
33
- interface Navigator {
34
- userActivation?: {
35
- isActive: boolean;
36
- };
37
- }
38
- }
39
32
  // User Activation should be available across browsers since November 2023 https://developer.mozilla.org/en-US/docs/Web/API/UserActivation
40
33
  if (typeof window !== "undefined" && "userActivation" in navigator && navigator.userActivation?.isActive) {
41
34
  if (isDevEnvironment()) console.debug("[Needle Engine] User input already active: Media playback is now allowed.");
@@ -1424,7 +1424,7 @@ export class Context implements IContext {
1424
1424
  catch (err) {
1425
1425
  this._renderlooperrors += 1;
1426
1426
  if ((isDevEnvironment() || debug) && (err instanceof Error || err instanceof TypeError))
1427
- showBalloonMessage(`Caught unhandled exception during render-loop - see console for details.`, LogType.Error);
1427
+ showBalloonMessage(`Caught unhandled exception during render-loop - see console for details.`, { type: LogType.Error });
1428
1428
  console.error("Frame #" + this.time.frame + "\n", err);
1429
1429
  if (this._renderlooperrors >= 3) {
1430
1430
  console.warn("Stopping render loop due to error")
@@ -280,7 +280,7 @@ async function onCreateBuiltinComponents(context: SerializationContext, obj: Obj
280
280
  console.warn(`Unknown components in scene: ${unknown}`);
281
281
  unknownComponentsBuffer.length = 0;
282
282
  if (isLocalNetwork())
283
- showBalloonMessage(`<strong>Unknown components in scene</strong>:\n\n${unknown}\n\nThis could mean you forgot to add a npmdef to your ExportInfo\n<a href="https://engine.needle.tools/docs/project_structure.html#creating-and-installing-a-npmdef" target="_blank">documentation</a>`, LogType.Warn);
283
+ showBalloonMessage(`<strong>Unknown components in scene</strong>:\n\n${unknown}\n\nThis could mean you forgot to add a npmdef to your ExportInfo\n<a href="https://engine.needle.tools/docs/project_structure.html#creating-and-installing-a-npmdef" target="_blank">documentation</a>`, { type: LogType.Warn });
284
284
  }
285
285
  }
286
286
 
@@ -102,10 +102,13 @@ async function onCreateLoader(url: string, context: Context, sourceId: SourceIde
102
102
  }
103
103
 
104
104
  /**
105
- * Load a 3D model file from a remote URL
106
- * @param url URL to glTF, FBX or OBJ file
107
- * @param options
108
- * @returns A promise that resolves to the loaded model or undefined if the loading failed
105
+ * Load a 3D model file from a URL (glTF, glb, FBX, OBJ, or any format with a registered loader).
106
+ * @param url URL to the model file.
107
+ * @param options Optional loading configuration.
108
+ * @param options.context The Needle Engine context to load into. Defaults to `Context.Current`.
109
+ * @param options.seed Seed for generating unique component IDs.
110
+ * @param options.onprogress Callback invoked with download progress events.
111
+ * @returns A promise that resolves to the loaded {@link Model} (`GLTF | FBX | OBJ | CustomModel`), or `undefined` if loading fails.
109
112
  */
110
113
  export function loadAsset(url: string, options?: { context?: Context, path?: string, seed?: number, onprogress?: (evt: ProgressEvent) => void }): Promise<Model | undefined> {
111
114
  return loadSync(options?.context || Context.Current, url, url, options?.seed || null, options?.onprogress);
@@ -616,6 +616,7 @@ export class NetworkedStreams extends EventDispatcher<any> {
616
616
  if (this.debug)
617
617
  console.log("PEER USER CONNECTED", user.guid, user, this._sendingStreams.size);
618
618
  const stream = this._sendingStreams.keys().next().value;
619
+ if (!stream) return;
619
620
 
620
621
  // check if we already have a call with this user
621
622
  // const existing = this._outgoingCalls.find(c => c.call.peer === peerId && c.stream === stream);
@@ -58,7 +58,7 @@ function createPropertyWrapper(target: IComponent | any, _propertyKey: string |
58
58
  // we currently only support validation of fields
59
59
  if (descriptor !== undefined) {
60
60
  console.error("Invalid usage of validate decorator. Only fields can be validated.", target, _propertyKey, descriptor);
61
- showBalloonMessage("Invalid usage of validate decorator. Only fields can be validated. Property: " + _propertyKey, LogType.Error);
61
+ showBalloonMessage("Invalid usage of validate decorator. Only fields can be validated. Property: " + _propertyKey, { type: LogType.Error });
62
62
  return;
63
63
  }
64
64
 
@@ -75,7 +75,7 @@ function createPropertyWrapper(target: IComponent | any, _propertyKey: string |
75
75
  target.__internalAwake = function () {
76
76
 
77
77
  if (!this.onValidate) {
78
- if(isDevEnvironment()) console.warn("Usage of @validate decorate detected but there is no onValidate method in your class: \"" + target.constructor?.name + "\"")
78
+ if (isDevEnvironment()) console.warn("Usage of @validate decorate detected but there is no onValidate method in your class: \"" + target.constructor?.name + "\"")
79
79
  return;
80
80
  }
81
81
 
@@ -20,13 +20,8 @@ export class NeedleLogoElement extends HTMLElement {
20
20
  return document.createElement(elementName) as NeedleLogoElement;
21
21
  }
22
22
 
23
- private _didInitialize = false;
24
-
25
23
  constructor() {
26
24
  super();
27
- }
28
-
29
- private initializeDom() {
30
25
  this._root = this.attachShadow({ mode: 'closed' });
31
26
  const template = document.createElement('template');
32
27
  template.innerHTML = `<style>
@@ -88,37 +83,25 @@ export class NeedleLogoElement extends HTMLElement {
88
83
  this.addEventListener("click", () => {
89
84
  globalThis.open("https://needle.tools", "_blank");
90
85
  });
91
- }
92
86
 
93
- ensureInitialized() {
94
- if (!this._didInitialize) {
95
- this._didInitialize = true;
96
- this.initializeDom();
97
- }
98
87
  }
99
88
 
100
89
  connectedCallback() {
101
- this.ensureInitialized();
102
- if (!this.wrapper) return;
103
90
  this.wrapper.setAttribute("title", "Made with Needle Engine");
104
91
  this.setAttribute("aria-label", "Needle Engine logo. Click to open the Needle Engine website.");
105
92
  }
106
93
 
107
- private _root!: ShadowRoot;
108
- private wrapper!: HTMLDivElement;
109
- private logoElement!: HTMLImageElement;
94
+ private readonly _root: ShadowRoot;
95
+ private readonly wrapper: HTMLDivElement;
96
+ private readonly logoElement: HTMLImageElement;
110
97
 
111
98
  /** Show or hide the logo element (used by the menu) */
112
99
  setLogoVisible(val: boolean) {
113
- this.ensureInitialized();
114
- if (!this.logoElement) return;
115
100
  this.logoElement.style.display = val ? "block" : "none";
116
101
  }
117
102
 
118
103
  /** Switch the logo between full and compact versions */
119
104
  setType(type: "full" | "compact") {
120
- this.ensureInitialized();
121
- if (!this.logoElement) return;
122
105
  if (type === "full") {
123
106
  this.logoElement.src = needleLogoSVG;
124
107
  this.logoElement.classList.remove("with-text");
@@ -129,7 +129,6 @@ export class NeedleMenu {
129
129
 
130
130
  constructor(context: Context) {
131
131
  this._menu = NeedleMenuElement.getOrCreate(context.domElement, context);
132
- this._menu.ensureInitialized();
133
132
  this._context = context;
134
133
  this._spatialMenu = new NeedleSpatialMenu(context, this._menu);
135
134
  window.addEventListener("message", this.onPostMessage);
@@ -310,6 +309,7 @@ export class NeedleMenu {
310
309
  export class NeedleMenuElement extends HTMLElement {
311
310
 
312
311
  static create() {
312
+ // https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement#is
313
313
  return document.createElement(elementName);
314
314
  }
315
315
 
@@ -337,13 +337,9 @@ export class NeedleMenuElement extends HTMLElement {
337
337
 
338
338
  private _domElement: HTMLElement | null = null;
339
339
  private _context: Context | null = null;
340
- private _didInitialize = false;
341
340
 
342
341
  constructor() {
343
342
  super();
344
- }
345
-
346
- private initializeDom() {
347
343
 
348
344
  const template = document.createElement('template');
349
345
  // TODO: make host full size again and move the buttons to a wrapper so that we can later easily open e.g. foldouts/dropdowns / use the whole canvas space
@@ -677,9 +673,6 @@ export class NeedleMenuElement extends HTMLElement {
677
673
  padding: .6em .5em;
678
674
  width: 100%;
679
675
  }
680
- .compact.has-options {
681
- padding-left: 1em;
682
- }
683
676
  .compact.has-options .logo {
684
677
  border: none;
685
678
  padding-left: 0;
@@ -700,6 +693,7 @@ export class NeedleMenuElement extends HTMLElement {
700
693
  display: flex;
701
694
  flex-basis: 100%;
702
695
  min-height: 3rem;
696
+ min-width: 3rem;
703
697
  }
704
698
  & > button.row2 {
705
699
  //border: 1px solid red !important;
@@ -799,7 +793,7 @@ export class NeedleMenuElement extends HTMLElement {
799
793
 
800
794
 
801
795
  let context = this._context;
802
- // we need to assign it in the timeout because the reference is set *after* the element is initialized
796
+ // we need to assign it in the timeout because the reference is set *after* the constructor did run
803
797
  setTimeout(() => context = this._context);
804
798
 
805
799
  // watch changes
@@ -868,21 +862,13 @@ export class NeedleMenuElement extends HTMLElement {
868
862
  }
869
863
  }
870
864
 
871
- ensureInitialized() {
872
- if (!this._didInitialize) {
873
- this._didInitialize = true;
874
- this.initializeDom();
875
- }
876
- }
877
-
878
865
  private _sizeChangeInterval;
879
866
 
880
867
  connectedCallback() {
881
- this.ensureInitialized();
882
868
  window.addEventListener("resize", this.handleSizeChange);
883
869
  this.handleMenuVisible();
884
870
  this._sizeChangeInterval = setInterval(() => this.handleSizeChange(undefined, false), 5000);
885
- // the dom element is set after initialization runs
871
+ // the dom element is set after the constructor runs
886
872
  setTimeout(() => {
887
873
  this._domElement?.addEventListener("resize", this.handleSizeChange);
888
874
  this._domElement?.addEventListener("click", this.#onClick);
@@ -970,19 +956,19 @@ export class NeedleMenuElement extends HTMLElement {
970
956
 
971
957
  // private _root: ShadowRoot | null = null;
972
958
  /** @private root container element inside shadow DOM */
973
- private root!: HTMLDivElement;
959
+ private readonly root: HTMLDivElement;
974
960
  /** @private wraps the whole content (internal layout) */
975
- private wrapper!: HTMLDivElement;
961
+ private readonly wrapper: HTMLDivElement;
976
962
  /** @private contains the buttons and dynamic elements */
977
- private options!: HTMLDivElement;
963
+ private readonly options: HTMLDivElement;
978
964
  /** @private contains options visible when in compact mode */
979
- private optionsCompactMode!: HTMLDivElement;
965
+ private readonly optionsCompactMode: HTMLDivElement;
980
966
  /** @private contains the needle-logo html element */
981
- private logoContainer!: HTMLDivElement;
967
+ private readonly logoContainer: HTMLDivElement;
982
968
  /** @private compact menu button element */
983
- private compactMenuButton!: HTMLButtonElement;
969
+ private readonly compactMenuButton: HTMLButtonElement;
984
970
  /** @private foldout container used in compact mode */
985
- private foldout!: HTMLDivElement;
971
+ private readonly foldout: HTMLDivElement;
986
972
 
987
973
 
988
974
  private readonly trackedElements: WeakSet<Node> = new WeakSet();
@@ -168,30 +168,19 @@ 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;
175
175
  private _previousSrc: string | null | string[] = null;
176
176
  /** @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
177
  private _didFullyLoad: boolean = false;
178
- private _didInitialize = false;
179
178
 
180
179
  constructor() {
181
180
  super();
182
181
  this._overlay_ar = new AROverlayHandler();
183
182
  // TODO: do we want to rename this event?
184
183
  this.addEventListener("ready", this.onReady);
185
- }
186
-
187
- private ensureInitialized() {
188
- if (!this._didInitialize) {
189
- this._didInitialize = true;
190
- this.initializeDom();
191
- }
192
- }
193
-
194
- private initializeDom() {
195
184
 
196
185
  ensureFonts();
197
186
 
@@ -292,7 +281,6 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
292
281
  * @internal
293
282
  */
294
283
  async connectedCallback() {
295
- this.ensureInitialized();
296
284
  if (debug) {
297
285
  console.log("<needle-engine> connected");
298
286
  }