@needle-tools/engine 5.1.0-canary.db0c38f → 5.1.0-canary.e6680fa

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 (381) hide show
  1. package/.needle/generated/needle-bindings.gen.d.ts +5 -0
  2. package/CHANGELOG.md +133 -1
  3. package/SKILL.md +4 -1
  4. package/components.needle.json +1 -1
  5. package/dist/needle-engine.bundle-Bl_hyH5G.umd.cjs +1734 -0
  6. package/dist/needle-engine.bundle-Cduc1gj6.min.js +1734 -0
  7. package/dist/{needle-engine.bundle-B29kieh0.js → needle-engine.bundle-DNcqT8nJ.js} +13770 -12741
  8. package/dist/needle-engine.d.ts +1628 -402
  9. package/dist/needle-engine.js +591 -586
  10. package/dist/needle-engine.min.js +1 -1
  11. package/dist/needle-engine.umd.cjs +1 -1
  12. package/dist/three.js +1 -0
  13. package/dist/three.min.js +21 -21
  14. package/dist/three.umd.cjs +16 -16
  15. package/lib/engine/api.d.ts +9 -2
  16. package/lib/engine/api.js +7 -1
  17. package/lib/engine/api.js.map +1 -1
  18. package/lib/engine/codegen/register_types.js +10 -18
  19. package/lib/engine/codegen/register_types.js.map +1 -1
  20. package/lib/engine/debug/debug_spatial_console.d.ts +2 -0
  21. package/lib/engine/debug/debug_spatial_console.js +10 -7
  22. package/lib/engine/debug/debug_spatial_console.js.map +1 -1
  23. package/lib/engine/engine_addressables.d.ts +2 -0
  24. package/lib/engine/engine_addressables.js +6 -3
  25. package/lib/engine/engine_addressables.js.map +1 -1
  26. package/lib/engine/engine_audio.d.ts +68 -0
  27. package/lib/engine/engine_audio.js +172 -0
  28. package/lib/engine/engine_audio.js.map +1 -1
  29. package/lib/engine/engine_camera.fit.js +16 -4
  30. package/lib/engine/engine_camera.fit.js.map +1 -1
  31. package/lib/engine/engine_components.js +1 -1
  32. package/lib/engine/engine_components.js.map +1 -1
  33. package/lib/engine/engine_context.d.ts +41 -27
  34. package/lib/engine/engine_context.js +71 -30
  35. package/lib/engine/engine_context.js.map +1 -1
  36. package/lib/engine/engine_context_eventbus.d.ts +47 -0
  37. package/lib/engine/engine_context_eventbus.js +47 -0
  38. package/lib/engine/engine_context_eventbus.js.map +1 -0
  39. package/lib/engine/engine_disposable.d.ts +172 -0
  40. package/lib/engine/engine_disposable.js +136 -0
  41. package/lib/engine/engine_disposable.js.map +1 -0
  42. package/lib/engine/engine_gameobject.d.ts +1 -10
  43. package/lib/engine/engine_gameobject.js +22 -120
  44. package/lib/engine/engine_gameobject.js.map +1 -1
  45. package/lib/engine/engine_gltf_builtin_components.js +7 -69
  46. package/lib/engine/engine_gltf_builtin_components.js.map +1 -1
  47. package/lib/engine/engine_init.js +16 -1
  48. package/lib/engine/engine_init.js.map +1 -1
  49. package/lib/engine/engine_input.d.ts +24 -5
  50. package/lib/engine/engine_input.js +3 -2
  51. package/lib/engine/engine_input.js.map +1 -1
  52. package/lib/engine/engine_instantiate_resolve.d.ts +42 -0
  53. package/lib/engine/engine_instantiate_resolve.js +372 -0
  54. package/lib/engine/engine_instantiate_resolve.js.map +1 -0
  55. package/lib/engine/engine_license.d.ts +8 -6
  56. package/lib/engine/engine_license.js +195 -59
  57. package/lib/engine/engine_license.js.map +1 -1
  58. package/lib/engine/engine_lifecycle_functions_internal.js +5 -0
  59. package/lib/engine/engine_lifecycle_functions_internal.js.map +1 -1
  60. package/lib/engine/engine_mainloop_utils.js +7 -4
  61. package/lib/engine/engine_mainloop_utils.js.map +1 -1
  62. package/lib/engine/engine_networking.d.ts +51 -37
  63. package/lib/engine/engine_networking.js +132 -82
  64. package/lib/engine/engine_networking.js.map +1 -1
  65. package/lib/engine/engine_networking.transport.websocket.d.ts +15 -0
  66. package/lib/engine/engine_networking.transport.websocket.js +38 -0
  67. package/lib/engine/engine_networking.transport.websocket.js.map +1 -0
  68. package/lib/engine/engine_networking_blob.js +4 -4
  69. package/lib/engine/engine_networking_blob.js.map +1 -1
  70. package/lib/engine/engine_networking_instantiate.js +2 -2
  71. package/lib/engine/engine_networking_instantiate.js.map +1 -1
  72. package/lib/engine/engine_networking_types.d.ts +39 -1
  73. package/lib/engine/engine_networking_types.js +7 -0
  74. package/lib/engine/engine_networking_types.js.map +1 -1
  75. package/lib/engine/engine_physics_rapier.d.ts +21 -3
  76. package/lib/engine/engine_physics_rapier.js +94 -25
  77. package/lib/engine/engine_physics_rapier.js.map +1 -1
  78. package/lib/engine/engine_pmrem.js +53 -5
  79. package/lib/engine/engine_pmrem.js.map +1 -1
  80. package/lib/engine/engine_scenedata.d.ts +13 -17
  81. package/lib/engine/engine_scenedata.js +58 -31
  82. package/lib/engine/engine_scenedata.js.map +1 -1
  83. package/lib/engine/engine_serialization_builtin_serializer.d.ts +10 -16
  84. package/lib/engine/engine_serialization_builtin_serializer.js +56 -46
  85. package/lib/engine/engine_serialization_builtin_serializer.js.map +1 -1
  86. package/lib/engine/engine_serialization_core.d.ts +1 -0
  87. package/lib/engine/engine_serialization_core.js +7 -0
  88. package/lib/engine/engine_serialization_core.js.map +1 -1
  89. package/lib/engine/engine_ssr.d.ts +2 -0
  90. package/lib/engine/engine_ssr.js +20 -0
  91. package/lib/engine/engine_ssr.js.map +1 -1
  92. package/lib/engine/engine_types.d.ts +31 -11
  93. package/lib/engine/engine_types.js +1 -1
  94. package/lib/engine/engine_types.js.map +1 -1
  95. package/lib/engine/engine_util_decorator.js +7 -2
  96. package/lib/engine/engine_util_decorator.js.map +1 -1
  97. package/lib/engine/engine_utils.d.ts +1 -1
  98. package/lib/engine/engine_utils.js +19 -5
  99. package/lib/engine/engine_utils.js.map +1 -1
  100. package/lib/engine/engine_utils_format.js +20 -14
  101. package/lib/engine/engine_utils_format.js.map +1 -1
  102. package/lib/engine/engine_utils_qrcode.js +2 -2
  103. package/lib/engine/engine_utils_qrcode.js.map +1 -1
  104. package/lib/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js +1 -1
  105. package/lib/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js.map +1 -1
  106. package/lib/engine/webcomponents/jsx.d.ts +51 -0
  107. package/lib/engine/webcomponents/logo-element.js.map +1 -1
  108. package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js +2 -2
  109. package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js.map +1 -1
  110. package/lib/engine/webcomponents/needle menu/needle-menu.d.ts +3 -4
  111. package/lib/engine/webcomponents/needle menu/needle-menu.js +6 -6
  112. package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
  113. package/lib/engine/webcomponents/needle-button.js.map +1 -1
  114. package/lib/engine/webcomponents/needle-engine.d.ts +10 -4
  115. package/lib/engine/webcomponents/needle-engine.js +3 -3
  116. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  117. package/lib/engine/webcomponents/needle-engine.loading.js +2 -2
  118. package/lib/engine/webcomponents/needle-engine.loading.js.map +1 -1
  119. package/lib/engine/xr/NeedleXRSession.d.ts +3 -2
  120. package/lib/engine/xr/NeedleXRSession.js +50 -14
  121. package/lib/engine/xr/NeedleXRSession.js.map +1 -1
  122. package/lib/engine/xr/TempXRContext.js +2 -2
  123. package/lib/engine/xr/TempXRContext.js.map +1 -1
  124. package/lib/engine/xr/events.d.ts +1 -1
  125. package/lib/engine/xr/events.js.map +1 -1
  126. package/lib/engine-components/Animation.js +17 -16
  127. package/lib/engine-components/Animation.js.map +1 -1
  128. package/lib/engine-components/AnimationBuilder.d.ts +158 -0
  129. package/lib/engine-components/AnimationBuilder.js +305 -0
  130. package/lib/engine-components/AnimationBuilder.js.map +1 -0
  131. package/lib/engine-components/Animator.d.ts +6 -0
  132. package/lib/engine-components/Animator.js +23 -13
  133. package/lib/engine-components/Animator.js.map +1 -1
  134. package/lib/engine-components/AnimatorController.builder.d.ts +191 -0
  135. package/lib/engine-components/AnimatorController.builder.js +263 -0
  136. package/lib/engine-components/AnimatorController.builder.js.map +1 -0
  137. package/lib/engine-components/AnimatorController.d.ts +4 -119
  138. package/lib/engine-components/AnimatorController.js +37 -233
  139. package/lib/engine-components/AnimatorController.js.map +1 -1
  140. package/lib/engine-components/AudioSource.d.ts +19 -3
  141. package/lib/engine-components/AudioSource.js +121 -68
  142. package/lib/engine-components/AudioSource.js.map +1 -1
  143. package/lib/engine-components/Camera.d.ts +6 -1
  144. package/lib/engine-components/Camera.js +16 -3
  145. package/lib/engine-components/Camera.js.map +1 -1
  146. package/lib/engine-components/CameraUtils.js +14 -6
  147. package/lib/engine-components/CameraUtils.js.map +1 -1
  148. package/lib/engine-components/Collider.d.ts +18 -9
  149. package/lib/engine-components/Collider.js +61 -14
  150. package/lib/engine-components/Collider.js.map +1 -1
  151. package/lib/engine-components/Component.d.ts +72 -9
  152. package/lib/engine-components/Component.js +114 -10
  153. package/lib/engine-components/Component.js.map +1 -1
  154. package/lib/engine-components/ContactShadows.d.ts +1 -0
  155. package/lib/engine-components/ContactShadows.js +14 -1
  156. package/lib/engine-components/ContactShadows.js.map +1 -1
  157. package/lib/engine-components/DragControls.d.ts +7 -0
  158. package/lib/engine-components/DragControls.js +19 -7
  159. package/lib/engine-components/DragControls.js.map +1 -1
  160. package/lib/engine-components/DropListener.js +4 -0
  161. package/lib/engine-components/DropListener.js.map +1 -1
  162. package/lib/engine-components/EventList.d.ts +31 -9
  163. package/lib/engine-components/EventList.js +37 -76
  164. package/lib/engine-components/EventList.js.map +1 -1
  165. package/lib/engine-components/Joints.d.ts +4 -2
  166. package/lib/engine-components/Joints.js +19 -3
  167. package/lib/engine-components/Joints.js.map +1 -1
  168. package/lib/engine-components/Light.d.ts +6 -8
  169. package/lib/engine-components/Light.js +48 -27
  170. package/lib/engine-components/Light.js.map +1 -1
  171. package/lib/engine-components/Networking.d.ts +1 -1
  172. package/lib/engine-components/Networking.js +1 -1
  173. package/lib/engine-components/OrbitControls.d.ts +1 -2
  174. package/lib/engine-components/OrbitControls.js +37 -14
  175. package/lib/engine-components/OrbitControls.js.map +1 -1
  176. package/lib/engine-components/ReflectionProbe.js +2 -0
  177. package/lib/engine-components/ReflectionProbe.js.map +1 -1
  178. package/lib/engine-components/RigidBody.d.ts +12 -4
  179. package/lib/engine-components/RigidBody.js +18 -4
  180. package/lib/engine-components/RigidBody.js.map +1 -1
  181. package/lib/engine-components/SceneSwitcher.js +3 -0
  182. package/lib/engine-components/SceneSwitcher.js.map +1 -1
  183. package/lib/engine-components/SeeThrough.js +2 -2
  184. package/lib/engine-components/SeeThrough.js.map +1 -1
  185. package/lib/engine-components/VideoPlayer.d.ts +8 -2
  186. package/lib/engine-components/VideoPlayer.js +42 -19
  187. package/lib/engine-components/VideoPlayer.js.map +1 -1
  188. package/lib/engine-components/Voip.d.ts +16 -7
  189. package/lib/engine-components/Voip.js +90 -53
  190. package/lib/engine-components/Voip.js.map +1 -1
  191. package/lib/engine-components/api.d.ts +3 -1
  192. package/lib/engine-components/api.js +3 -1
  193. package/lib/engine-components/api.js.map +1 -1
  194. package/lib/engine-components/codegen/components.d.ts +7 -13
  195. package/lib/engine-components/codegen/components.js +7 -13
  196. package/lib/engine-components/codegen/components.js.map +1 -1
  197. package/lib/engine-components/export/usdz/USDZExporter.js +4 -4
  198. package/lib/engine-components/export/usdz/USDZExporter.js.map +1 -1
  199. package/lib/engine-components/postprocessing/Effects/Tonemapping.utils.d.ts +1 -1
  200. package/lib/engine-components/postprocessing/VolumeParameter.d.ts +2 -0
  201. package/lib/engine-components/postprocessing/VolumeParameter.js +4 -1
  202. package/lib/engine-components/postprocessing/VolumeParameter.js.map +1 -1
  203. package/lib/engine-components/timeline/PlayableDirector.d.ts +21 -11
  204. package/lib/engine-components/timeline/PlayableDirector.js +75 -67
  205. package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
  206. package/lib/engine-components/timeline/SignalAsset.d.ts +3 -1
  207. package/lib/engine-components/timeline/SignalAsset.js +1 -0
  208. package/lib/engine-components/timeline/SignalAsset.js.map +1 -1
  209. package/lib/engine-components/timeline/TimelineBuilder.d.ts +413 -0
  210. package/lib/engine-components/timeline/TimelineBuilder.js +506 -0
  211. package/lib/engine-components/timeline/TimelineBuilder.js.map +1 -0
  212. package/lib/engine-components/timeline/TimelineModels.d.ts +2 -1
  213. package/lib/engine-components/timeline/TimelineModels.js +3 -0
  214. package/lib/engine-components/timeline/TimelineModels.js.map +1 -1
  215. package/lib/engine-components/timeline/TimelineTracks.d.ts +37 -6
  216. package/lib/engine-components/timeline/TimelineTracks.js +92 -26
  217. package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
  218. package/lib/engine-components/timeline/index.d.ts +2 -1
  219. package/lib/engine-components/timeline/index.js +2 -0
  220. package/lib/engine-components/timeline/index.js.map +1 -1
  221. package/lib/engine-components/ui/Canvas.d.ts +1 -1
  222. package/lib/engine-components/ui/Canvas.js +2 -8
  223. package/lib/engine-components/ui/Canvas.js.map +1 -1
  224. package/lib/engine-components/ui/Text.d.ts +1 -0
  225. package/lib/engine-components/ui/Text.js +10 -7
  226. package/lib/engine-components/ui/Text.js.map +1 -1
  227. package/lib/engine-components/web/CursorFollow.d.ts +0 -1
  228. package/lib/engine-components/web/CursorFollow.js +21 -13
  229. package/lib/engine-components/web/CursorFollow.js.map +1 -1
  230. package/lib/engine-components/webxr/WebXRImageTracking.d.ts +62 -1
  231. package/lib/engine-components/webxr/WebXRImageTracking.js +59 -2
  232. package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
  233. package/lib/needle-engine.d.ts +2 -0
  234. package/lib/needle-engine.js +2 -0
  235. package/lib/needle-engine.js.map +1 -1
  236. package/package.json +4 -84
  237. package/plugins/common/cloud.js +6 -1
  238. package/plugins/common/license.js +55 -12
  239. package/plugins/common/worker.js +9 -4
  240. package/plugins/dts-generator/dts.codegen.js +255 -50
  241. package/plugins/dts-generator/dts.scan.js +37 -9
  242. package/plugins/dts-generator/dts.writer.js +1 -1
  243. package/plugins/dts-generator/glb.discovery.js +140 -23
  244. package/plugins/dts-generator/glb.extractor.js +48 -8
  245. package/plugins/dts-generator/glb.reader.js +80 -27
  246. package/plugins/dts-generator/index.js +1 -1
  247. package/plugins/types/needle-bindings.d.ts +25 -14
  248. package/plugins/types/userconfig.d.ts +16 -1
  249. package/plugins/vite/asap.js +18 -9
  250. package/plugins/vite/build-pipeline.js +57 -20
  251. package/plugins/vite/dependencies.js +29 -10
  252. package/plugins/vite/dependency-watcher.d.ts +2 -2
  253. package/plugins/vite/dependency-watcher.js +5 -6
  254. package/plugins/vite/drop.d.ts +2 -2
  255. package/plugins/vite/drop.js +3 -4
  256. package/plugins/vite/dts-generator.d.ts +2 -2
  257. package/plugins/vite/dts-generator.js +43 -9
  258. package/plugins/vite/editor-connection.js +3 -3
  259. package/plugins/vite/index.d.ts +9 -3
  260. package/plugins/vite/index.js +23 -10
  261. package/plugins/vite/license.js +42 -7
  262. package/plugins/vite/local-files-core.js +3 -3
  263. package/plugins/vite/local-files-utils.d.ts +3 -1
  264. package/plugins/vite/local-files-utils.js +29 -5
  265. package/plugins/vite/meta.js +4 -2
  266. package/plugins/vite/poster.d.ts +2 -2
  267. package/plugins/vite/poster.js +3 -5
  268. package/plugins/vite/reload.d.ts +2 -2
  269. package/plugins/vite/reload.js +23 -23
  270. package/plugins/vite/server.js +2 -1
  271. package/src/engine/api.ts +12 -2
  272. package/src/engine/codegen/register_types.ts +10 -18
  273. package/src/engine/debug/debug_spatial_console.ts +10 -7
  274. package/src/engine/engine_addressables.ts +6 -3
  275. package/src/engine/engine_audio.ts +184 -0
  276. package/src/engine/engine_camera.fit.ts +15 -4
  277. package/src/engine/engine_components.ts +1 -1
  278. package/src/engine/engine_context.ts +85 -38
  279. package/src/engine/engine_context_eventbus.ts +73 -0
  280. package/src/engine/engine_disposable.ts +214 -0
  281. package/src/engine/engine_gameobject.ts +54 -159
  282. package/src/engine/engine_gltf_builtin_components.ts +7 -76
  283. package/src/engine/engine_init.ts +15 -1
  284. package/src/engine/engine_input.ts +28 -7
  285. package/src/engine/engine_instantiate_resolve.ts +407 -0
  286. package/src/engine/engine_license.ts +209 -61
  287. package/src/engine/engine_lifecycle_functions_internal.ts +7 -0
  288. package/src/engine/engine_mainloop_utils.ts +7 -4
  289. package/src/engine/engine_networking.transport.websocket.ts +45 -0
  290. package/src/engine/engine_networking.ts +161 -137
  291. package/src/engine/engine_networking_blob.ts +4 -4
  292. package/src/engine/engine_networking_instantiate.ts +2 -2
  293. package/src/engine/engine_networking_types.ts +41 -1
  294. package/src/engine/engine_physics_rapier.ts +102 -33
  295. package/src/engine/engine_pmrem.ts +56 -6
  296. package/src/engine/engine_scenedata.ts +56 -30
  297. package/src/engine/engine_serialization_builtin_serializer.ts +64 -52
  298. package/src/engine/engine_serialization_core.ts +9 -0
  299. package/src/engine/engine_ssr.ts +29 -3
  300. package/src/engine/engine_types.ts +48 -27
  301. package/src/engine/engine_util_decorator.ts +7 -2
  302. package/src/engine/engine_utils.ts +16 -5
  303. package/src/engine/engine_utils_format.ts +20 -14
  304. package/src/engine/engine_utils_qrcode.ts +2 -2
  305. package/src/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js +1 -1
  306. package/src/engine/webcomponents/jsx.d.ts +51 -0
  307. package/src/engine/webcomponents/logo-element.ts +1 -0
  308. package/src/engine/webcomponents/needle menu/needle-menu-spatial.ts +2 -2
  309. package/src/engine/webcomponents/needle menu/needle-menu.ts +8 -7
  310. package/src/engine/webcomponents/needle-button.ts +1 -0
  311. package/src/engine/webcomponents/needle-engine.loading.ts +6 -6
  312. package/src/engine/webcomponents/needle-engine.ts +13 -6
  313. package/src/engine/xr/NeedleXRSession.ts +48 -13
  314. package/src/engine/xr/TempXRContext.ts +2 -2
  315. package/src/engine/xr/events.ts +1 -1
  316. package/src/engine-components/Animation.ts +19 -16
  317. package/src/engine-components/AnimationBuilder.ts +472 -0
  318. package/src/engine-components/Animator.ts +24 -12
  319. package/src/engine-components/AnimatorController.builder.ts +387 -0
  320. package/src/engine-components/AnimatorController.ts +24 -292
  321. package/src/engine-components/AudioSource.ts +130 -79
  322. package/src/engine-components/Camera.ts +16 -3
  323. package/src/engine-components/CameraUtils.ts +12 -5
  324. package/src/engine-components/Collider.ts +66 -18
  325. package/src/engine-components/Component.ts +118 -20
  326. package/src/engine-components/ContactShadows.ts +15 -1
  327. package/src/engine-components/DragControls.ts +18 -11
  328. package/src/engine-components/DropListener.ts +4 -0
  329. package/src/engine-components/EventList.ts +45 -83
  330. package/src/engine-components/Joints.ts +20 -4
  331. package/src/engine-components/Light.ts +49 -27
  332. package/src/engine-components/Networking.ts +1 -1
  333. package/src/engine-components/OrbitControls.ts +42 -16
  334. package/src/engine-components/ReflectionProbe.ts +2 -0
  335. package/src/engine-components/RigidBody.ts +18 -4
  336. package/src/engine-components/SceneSwitcher.ts +3 -0
  337. package/src/engine-components/SeeThrough.ts +2 -2
  338. package/src/engine-components/VideoPlayer.ts +40 -17
  339. package/src/engine-components/Voip.ts +88 -53
  340. package/src/engine-components/api.ts +3 -1
  341. package/src/engine-components/codegen/components.ts +7 -13
  342. package/src/engine-components/export/usdz/USDZExporter.ts +4 -4
  343. package/src/engine-components/postprocessing/VolumeParameter.ts +4 -1
  344. package/src/engine-components/timeline/PlayableDirector.ts +83 -81
  345. package/src/engine-components/timeline/SignalAsset.ts +4 -1
  346. package/src/engine-components/timeline/TimelineBuilder.ts +824 -0
  347. package/src/engine-components/timeline/TimelineModels.ts +5 -1
  348. package/src/engine-components/timeline/TimelineTracks.ts +96 -27
  349. package/src/engine-components/timeline/index.ts +2 -1
  350. package/src/engine-components/ui/Canvas.ts +2 -8
  351. package/src/engine-components/ui/Text.ts +12 -8
  352. package/src/engine-components/web/CursorFollow.ts +21 -14
  353. package/src/engine-components/webxr/WebXRImageTracking.ts +79 -7
  354. package/src/needle-engine.ts +3 -0
  355. package/dist/needle-engine.bundle-Dq0Ly8fW.umd.cjs +0 -1732
  356. package/dist/needle-engine.bundle-YnpzzOPL.min.js +0 -1732
  357. package/lib/engine-components/AvatarLoader.d.ts +0 -80
  358. package/lib/engine-components/AvatarLoader.js +0 -232
  359. package/lib/engine-components/AvatarLoader.js.map +0 -1
  360. package/lib/engine-components/avatar/AvatarBlink_Simple.d.ts +0 -11
  361. package/lib/engine-components/avatar/AvatarBlink_Simple.js +0 -77
  362. package/lib/engine-components/avatar/AvatarBlink_Simple.js.map +0 -1
  363. package/lib/engine-components/avatar/AvatarEyeLook_Rotation.d.ts +0 -14
  364. package/lib/engine-components/avatar/AvatarEyeLook_Rotation.js +0 -69
  365. package/lib/engine-components/avatar/AvatarEyeLook_Rotation.js.map +0 -1
  366. package/lib/engine-components/avatar/Avatar_Brain_LookAt.d.ts +0 -29
  367. package/lib/engine-components/avatar/Avatar_Brain_LookAt.js +0 -122
  368. package/lib/engine-components/avatar/Avatar_Brain_LookAt.js.map +0 -1
  369. package/lib/engine-components/avatar/Avatar_MouthShapes.d.ts +0 -15
  370. package/lib/engine-components/avatar/Avatar_MouthShapes.js +0 -80
  371. package/lib/engine-components/avatar/Avatar_MouthShapes.js.map +0 -1
  372. package/lib/engine-components/avatar/Avatar_MustacheShake.d.ts +0 -9
  373. package/lib/engine-components/avatar/Avatar_MustacheShake.js +0 -30
  374. package/lib/engine-components/avatar/Avatar_MustacheShake.js.map +0 -1
  375. package/src/engine-components/AvatarLoader.ts +0 -264
  376. package/src/engine-components/avatar/AvatarBlink_Simple.ts +0 -70
  377. package/src/engine-components/avatar/AvatarEyeLook_Rotation.ts +0 -64
  378. package/src/engine-components/avatar/Avatar_Brain_LookAt.ts +0 -140
  379. package/src/engine-components/avatar/Avatar_MouthShapes.ts +0 -84
  380. package/src/engine-components/avatar/Avatar_MustacheShake.ts +0 -32
  381. package/src/vite-env.d.ts +0 -16
@@ -21,4 +21,188 @@ export function ensureAudioContextIsResumed() {
21
21
  }, 500);
22
22
  });
23
23
  });
24
+ }
25
+
26
+
27
+ /**
28
+ * Represents an audio clip that can be loaded and played independently.
29
+ * The AudioClip class encapsulates the URL of the audio resource and provides
30
+ * methods for playback control (play, pause, stop) and querying duration.
31
+ */
32
+ export class AudioClip {
33
+
34
+ /**
35
+ * Creates a new AudioClip instance with the specified URL.
36
+ * @param url The URL of the audio resource to load. This can be a path to an audio file or a MediaStream URL.
37
+ */
38
+ constructor(public readonly url: string) {
39
+ }
40
+
41
+ /** Whether the clip is currently playing.
42
+ * @returns `true` if the clip is actively playing audio.
43
+ */
44
+ get isPlaying(): boolean {
45
+ return this._audioElement !== undefined
46
+ && !this._audioElement.paused
47
+ && !this._audioElement.ended;
48
+ }
49
+
50
+ /**
51
+ * The total duration of the audio clip in seconds.
52
+ * Loads the audio metadata if not already available.
53
+ * @returns A promise that resolves with the duration in seconds.
54
+ */
55
+ getDuration(): Promise<number> {
56
+ if (this._duration !== undefined) {
57
+ return Promise.resolve(this._duration);
58
+ }
59
+ return this.ensureAudioElement().then(audio => {
60
+ this._duration = audio.duration;
61
+ return audio.duration;
62
+ });
63
+ }
64
+
65
+ /**
66
+ * Plays the audio clip from the current position.
67
+ * @returns A promise that resolves when playback finishes, or rejects on error.
68
+ * If the clip is looping, the promise will never resolve on its own – call {@link stop} or {@link pause} to end playback.
69
+ */
70
+ // #region Play
71
+ play(): Promise<void> {
72
+ return this.ensureAudioElement().then(audio => {
73
+ return new Promise<void>((resolve, reject) => {
74
+ const onEnded = () => {
75
+ cleanup();
76
+ resolve();
77
+ };
78
+ const onError = () => {
79
+ cleanup();
80
+ reject(new Error(`Playback error for ${this.url}`));
81
+ };
82
+ const onPause = () => {
83
+ // pause/stop also resolve the promise
84
+ cleanup();
85
+ resolve();
86
+ };
87
+ const cleanup = () => {
88
+ audio.removeEventListener("ended", onEnded);
89
+ audio.removeEventListener("error", onError);
90
+ audio.removeEventListener("pause", onPause);
91
+ };
92
+ audio.addEventListener("ended", onEnded);
93
+ audio.addEventListener("error", onError);
94
+ audio.addEventListener("pause", onPause);
95
+ audio.play().catch(err => {
96
+ cleanup();
97
+ reject(err);
98
+ });
99
+ });
100
+ });
101
+ }
102
+
103
+ /**
104
+ * Pauses playback at the current position.
105
+ * Call {@link play} to resume.
106
+ */
107
+ // #region Pause/Stop
108
+ pause(): void {
109
+ this._audioElement?.pause();
110
+ }
111
+
112
+ /**
113
+ * Stops playback and resets the position to the beginning.
114
+ */
115
+ stop(): void {
116
+ if (this._audioElement) {
117
+ this._audioElement.pause();
118
+ this._audioElement.currentTime = 0;
119
+ }
120
+ }
121
+
122
+ /** Whether the clip should loop when reaching the end. */
123
+ get loop(): boolean { return this._loop; }
124
+ set loop(value: boolean) {
125
+ this._loop = value;
126
+ if (this._audioElement) this._audioElement.loop = value;
127
+ }
128
+
129
+ /** Playback volume from 0 (silent) to 1 (full). */
130
+ get volume(): number { return this._volume; }
131
+ set volume(value: number) {
132
+ this._volume = value;
133
+ if (this._audioElement) this._audioElement.volume = value;
134
+ }
135
+
136
+ /** Current playback position in seconds. */
137
+ get currentTime(): number { return this._audioElement?.currentTime ?? 0; }
138
+ set currentTime(value: number) {
139
+ if (this._audioElement) this._audioElement.currentTime = value;
140
+ }
141
+
142
+ /** Normalized playback progress from 0 to 1.
143
+ * @returns The current playback position as a value between 0 and 1, or 0 if the duration is unknown.
144
+ */
145
+ get progress(): number {
146
+ if (!this._audioElement || !this._duration) return 0;
147
+ return this._audioElement.currentTime / this._duration;
148
+ }
149
+
150
+ /**
151
+ * Seeks to a normalized position (0–1) in the clip.
152
+ * @param position A value between 0 (start) and 1 (end).
153
+ */
154
+ // #region Seek
155
+ seek(position: number): void {
156
+ if (this._audioElement && this._duration) {
157
+ this._audioElement.currentTime = Math.max(0, Math.min(1, position)) * this._duration;
158
+ }
159
+ }
160
+
161
+ /** The underlying HTMLAudioElement, or `undefined` if not yet created.
162
+ * Use this to connect the element to the Web Audio API via `createMediaElementSource()`.
163
+ * @returns The HTMLAudioElement if the clip has been loaded or played, otherwise `undefined`.
164
+ */
165
+ get audioElement(): HTMLAudioElement | undefined { return this._audioElement; }
166
+
167
+ private _audioElement?: HTMLAudioElement;
168
+ private _duration?: number;
169
+ private _loadPromise?: Promise<HTMLAudioElement>;
170
+ private _loop: boolean = false;
171
+ private _volume: number = 1;
172
+
173
+ /** Lazily creates and loads the shared HTMLAudioElement. */
174
+ private ensureAudioElement(): Promise<HTMLAudioElement> {
175
+ if (this._audioElement && this._loadPromise) {
176
+ return this._loadPromise;
177
+ }
178
+ const audio = this._audioElement ?? new Audio(this.url);
179
+ this._audioElement = audio;
180
+ audio.loop = this._loop;
181
+ audio.volume = this._volume;
182
+
183
+ if (audio.readyState >= HTMLMediaElement.HAVE_METADATA) {
184
+ this._duration = audio.duration;
185
+ this._loadPromise = Promise.resolve(audio);
186
+ return this._loadPromise;
187
+ }
188
+
189
+ this._loadPromise = new Promise<HTMLAudioElement>((resolve, reject) => {
190
+ const onLoaded = () => {
191
+ cleanup();
192
+ this._duration = audio.duration;
193
+ resolve(audio);
194
+ };
195
+ const onError = (e: Event) => {
196
+ cleanup();
197
+ reject(new Error(`Failed to load audio clip from ${this.url}: ${e}`));
198
+ };
199
+ const cleanup = () => {
200
+ audio.removeEventListener("loadedmetadata", onLoaded);
201
+ audio.removeEventListener("error", onError);
202
+ };
203
+ audio.addEventListener("loadedmetadata", onLoaded);
204
+ audio.addEventListener("error", onError);
205
+ });
206
+ return this._loadPromise;
207
+ }
24
208
  }
@@ -257,12 +257,23 @@ export function fitCamera(options?: FitCameraOptions): null | FitCameraReturnTyp
257
257
  else {
258
258
  direction.sub(camera.worldPosition);
259
259
  }
260
- if (centerCamera === "y")
261
- direction.y = 0;
260
+ if (centerCamera === "y") {
261
+ // Preserve the camera's current elevation angle when it's already above the center,
262
+ // but clamp to a minimum elevation to prevent the camera from ending up at or below
263
+ // the scene center (which causes a "looking up from below" effect).
264
+ // direction points FROM camera TO center, so negative Y = camera is above center.
265
+ const horizontalLen = Math.sqrt(direction.x * direction.x + direction.z * direction.z);
266
+ if (horizontalLen > 0.0001) {
267
+ const minY = -horizontalLen * verticalOffset * 4;
268
+ if (direction.y > minY) direction.y = minY;
269
+ }
270
+ else {
271
+ // Camera is directly above/below center — pick a default slight angle from +Z
272
+ direction.set(0, -verticalOffset * 4, 1);
273
+ }
274
+ }
262
275
  direction.normalize();
263
276
  direction.multiplyScalar(distance);
264
- if (centerCamera === "y")
265
- direction.y += -verticalOffset * 4 * distance;
266
277
 
267
278
  let cameraLocalPosition = center.clone().sub(direction);
268
279
  if (options.cameraOffset) {
@@ -8,9 +8,9 @@ import { InstantiateIdProvider } from "./engine_networking_instantiate.js";
8
8
  import { Context, registerComponent } from "./engine_setup.js";
9
9
  import type { ComponentInit, Constructor, ConstructorConcrete, IComponent, IGameObject } from "./engine_types.js";
10
10
  import { $componentName } from "./engine_types.js";
11
+ import { TypeStore } from "./engine_typestore.js";
11
12
  import { getParam } from "./engine_utils.js";
12
13
  import { apply } from "./js-extensions/index.js";
13
- import { TypeStore } from "./engine_typestore.js";
14
14
 
15
15
  const COMPONENT_GUID_NAMESPACE = 'eff8ba80-635d-11ec-90d6-0242ac120003';
16
16
 
@@ -1,5 +1,6 @@
1
1
  import 'three/examples/jsm/renderers/webgl-legacy/nodes/WebGLNodes.js';
2
2
 
3
+ import type { SceneData } from 'needle-bindings';
3
4
  import type { EffectComposer } from "postprocessing";
4
5
  import {
5
6
  BufferGeometry, Camera, Color, DepthTexture, Group,
@@ -22,6 +23,7 @@ import { Application } from './engine_application.js';
22
23
  import { AssetDatabase } from './engine_assetdatabase.js';
23
24
  import { FocusRect, FocusRectSettings, updateCameraFocusRect } from './engine_camera.js';
24
25
  import { VERSION } from './engine_constants.js';
26
+ import { EventBus } from './engine_context_eventbus.js';
25
27
  import { ContextEvent, ContextRegistry } from './engine_context_registry.js';
26
28
  import { WaitForPromise } from './engine_coroutine.js';
27
29
  import { ObjectUtils } from "./engine_create_objects.js";
@@ -36,9 +38,8 @@ import * as looputils from './engine_mainloop_utils.js';
36
38
  import { NetworkConnection } from './engine_networking.js';
37
39
  import { Physics } from './engine_physics.js';
38
40
  import { PlayerViewManager } from './engine_playerview.js';
39
- import { RendererData as SceneLighting } from './engine_scenelighting.js';
40
41
  import { getSceneData } from './engine_scenedata.js';
41
- import type { SceneData } from 'needle:bindings';
42
+ import { RendererData as SceneLighting } from './engine_scenelighting.js';
42
43
  import { getTempColor, logHierarchy } from './engine_three_utils.js';
43
44
  import { Time } from './engine_time.js';
44
45
  import { patchTonemapping } from './engine_tonemapping.js';
@@ -151,7 +152,7 @@ export function registerComponent(script: IComponent, context?: Context) {
151
152
  }
152
153
 
153
154
  /**
154
- * The Needle Engine context is the main access point that holds all the data and state of a Needle Engine application.
155
+ * The Needle Engine context is the main access point that holds all the data and state of a Needle Engine application.
155
156
  * It can be used to access the {@link Context.scene}, {@link Context.renderer}, {@link Context.mainCamera}, {@link Context.input}, {@link Context.physics}, {@link Context.time}, {@link Context.connection} (networking), and more.
156
157
  *
157
158
  * The context is automatically created when using the `<needle-engine>` web component.
@@ -478,13 +479,14 @@ export class Context implements IContext {
478
479
  * Use `setCurrentCamera` for updating the main camera.
479
480
  */
480
481
  /**
481
- * Typed proxy providing direct access to scene components by node and component name.
482
- * Types are auto-generated from your GLB assets by the `needle:dts-generator` Vite plugin
483
- * and written to `src/generated/needle-bindings.d.ts` on every dev-server start and GLB change.
482
+ * Access your scene's full hierarchy, objects, and components directly by name with full autocomplete.
483
+ * Types are generated automatically from your GLB files when the dev server starts.
484
+ *
485
+ * You can store references to objects or components for later use.
486
+ * Note that the scene hierarchy can change at runtime (e.g. when objects are added, removed, or re-parented),
487
+ * in which case stored references may become stale.
484
488
  *
485
- * Each property access traverses the live scene graph on demand — no caching, always fresh.
486
- * This is a convenience shorthand for `getComponent` lookups; the same result can be
487
- * achieved manually via `scene.getObjectByName(name)` + `getComponent(node, Type)`.
489
+ * @experimental This API may change in future versions.
488
490
  *
489
491
  * @example
490
492
  * // Toggle auto-rotate on the orbit camera
@@ -493,12 +495,6 @@ export class Context implements IContext {
493
495
  * @example
494
496
  * // Change the background color
495
497
  * ctx.sceneData.Camera.Camera.backgroundColor = new RGBAColor(1, 0, 0, 1);
496
- *
497
- * @example
498
- * // Equivalent manual approach (without sceneData)
499
- * const node = ctx.scene.getObjectByName("Camera");
500
- * const orbit = getComponent(node, OrbitControls);
501
- * if (orbit) orbit.autoRotate = true;
502
498
  */
503
499
  get sceneData(): SceneData {
504
500
  return getSceneData(this);
@@ -516,6 +512,13 @@ export class Context implements IContext {
516
512
  }
517
513
  if (!this._fallbackCamera) {
518
514
  this._fallbackCamera = new PerspectiveCamera(75, this.domWidth / this.domHeight, 0.1, 1000);
515
+ // Put the fallback into the scene graph. Without this, callers who
516
+ // do `ctx.mainCamera.add(child)` end up parenting children to an
517
+ // orphan camera that the renderer never traverses (since
518
+ // `renderer.render(scene, camera)` walks `scene`, not `camera`).
519
+ // Safe because this branch only runs before a real main camera
520
+ // component exists, and the fallback is replaced once one does.
521
+ this.scene.add(this._fallbackCamera);
519
522
  }
520
523
  return this._fallbackCamera;
521
524
  }
@@ -527,30 +530,59 @@ export class Context implements IContext {
527
530
  private _fallbackCamera: PerspectiveCamera | null = null;
528
531
 
529
532
  /** access application state (e.g. if all audio should be muted) */
530
- application: Application;
533
+ get application(): Application { return this._application; }
534
+ private _application!: Application;
531
535
  /** access animation mixer used by components in the scene */
532
- animations: AnimationsRegistry;
536
+ get animations(): AnimationsRegistry { return this._animations; }
537
+ private _animations!: AnimationsRegistry;
533
538
  /** access timings (current frame number, deltaTime, timeScale, ...) */
534
- time: Time;
539
+ get time(): Time { return this._time; }
540
+ private _time!: Time;
535
541
  /** access input data (e.g. click or touch events) */
536
- input: Input;
542
+ get input(): Input { return this._input; }
543
+ private _input!: Input;
537
544
  /** access physics related methods (e.g. raycasting). To access the phyiscs engine use `context.physics.engine` */
538
- physics: Physics;
545
+ get physics(): Physics { return this._physics; }
546
+ private _physics!: Physics;
539
547
  /** access postprocessing effects stack. Add/remove effects and configure adaptive performance settings */
540
- postprocessing: PostProcessing;
548
+ get postprocessing(): PostProcessing { return this._postprocessing; }
549
+ private _postprocessing!: PostProcessing;
541
550
  /** access networking methods (use it to send or listen to messages or join a networking backend) */
542
- connection: NetworkConnection;
551
+ get connection(): NetworkConnection { return this._connection; }
552
+ private _connection!: NetworkConnection;
553
+ /** context-level event bus for decoupled component communication
554
+ * @see {@link ContextEventMap} for known event types
555
+ */
556
+ get events(): EventBus { return this._events; }
557
+ private _events = new EventBus();
543
558
  /** @deprecated AssetDatabase is deprecated */
544
559
  assets: AssetDatabase;
545
- /** The main light in the scene */
546
- mainLight: ILight | null = null;
560
+
561
+ /** All registered lights in the scene, maintained by the Light component.
562
+ * @see mainLight for accessing the main directional light in the scene
563
+ */
564
+ readonly lights = new Array<ILight>();
565
+
566
+ /** The brightest registered directional light, or null if none are registered
567
+ * @see lights
568
+ */
569
+ get mainLight(): ILight | null {
570
+ let best: ILight | null = null;
571
+ for (const light of this.lights) {
572
+ if (light.type !== "directional") continue;
573
+ if (!best || light.intensity > best.intensity) best = light;
574
+ }
575
+ return best;
576
+ }
577
+
547
578
  /** @deprecated Use sceneLighting */
548
- get rendererData() { return this.sceneLighting }
579
+ private get rendererData() { return this.sceneLighting }
580
+
549
581
  /** Access the scene lighting manager to control lighting settings in the context */
550
- sceneLighting: SceneLighting;
551
- addressables: Addressables;
552
- lightmaps: ILightDataRegistry;
553
- players: PlayerViewManager;
582
+ readonly sceneLighting: SceneLighting;
583
+ readonly addressables: Addressables;
584
+ readonly lightmaps: ILightDataRegistry;
585
+ readonly players: PlayerViewManager;
554
586
 
555
587
  /** Access the LODs manager to control LOD behavior in the context */
556
588
  readonly lodsManager: LODsManager;
@@ -594,12 +626,12 @@ export class Context implements IContext {
594
626
  else this.scene = new Scene();
595
627
  if (args?.camera) this._mainCamera = args.camera;
596
628
 
597
- this.application = new Application(this);
598
- this.time = new Time();
599
- this.input = new Input(this);
600
- this.physics = new Physics(this);
601
- this.postprocessing = new PostProcessing(this);
602
- this.connection = new NetworkConnection(this);
629
+ this._application = new Application(this);
630
+ this._time = new Time();
631
+ this._input = new Input(this);
632
+ this._physics = new Physics(this);
633
+ this._postprocessing = new PostProcessing(this);
634
+ this._connection = new NetworkConnection(this);
603
635
  // eslint-disable-next-line @typescript-eslint/no-deprecated
604
636
  this.assets = new AssetDatabase();
605
637
  this.sceneLighting = new SceneLighting(this);
@@ -608,7 +640,7 @@ export class Context implements IContext {
608
640
  this.players = new PlayerViewManager(this);
609
641
  this.menu = new NeedleMenu(this);
610
642
  this.lodsManager = new LODsManager(this);
611
- this.animations = new AnimationsRegistry(this);
643
+ this._animations = new AnimationsRegistry(this);
612
644
  this.accessibility = new AccessibilityManager(this);
613
645
 
614
646
 
@@ -851,12 +883,16 @@ export class Context implements IContext {
851
883
  this.scene = new Scene();
852
884
  this.addressables?.dispose();
853
885
  this.lightmaps?.clear();
854
- this.physics?.engine?.clearCaches();
886
+ this.physics?.engine?.dispose();
855
887
  this.lodsManager.disable();
856
888
  this.accessibility?.clear();
857
889
 
858
890
  this._onBeforeRenderListeners.clear();
859
891
  this._onAfterRenderListeners.clear();
892
+ this._events.clear();
893
+ this._events = new EventBus();
894
+
895
+ this.lights.length = 0;
860
896
 
861
897
  if (!this.isManagedExternally) {
862
898
  if (this.renderer) {
@@ -898,6 +934,7 @@ export class Context implements IContext {
898
934
  this.scene = null!;
899
935
  this.renderer = null!;
900
936
  this.input.dispose();
937
+ this.connection.dispose();
901
938
  this.menu.onDestroy();
902
939
  this.animations.onDestroy();
903
940
  for (const cb of this._disposeCallbacks) {
@@ -1778,6 +1815,7 @@ export class Context implements IContext {
1778
1815
  ? (`${((window.performance as any).memory.usedJSHeapSize / 1024 / 1024).toFixed(2)} MB`)
1779
1816
  : "n/a";
1780
1817
 
1818
+ const gl = this.renderer.getContext();
1781
1819
  console.log(this.renderer.info.render.calls + " DrawCalls", "\nRender:",
1782
1820
  {
1783
1821
  shaders: this.renderer.info.programs?.length,
@@ -1787,7 +1825,16 @@ export class Context implements IContext {
1787
1825
  {
1788
1826
  usedMemory: usedJSHeapSize,
1789
1827
  ...this.renderer.info.memory
1790
- }, "\nTarget Framerate: " + this.targetFrameRate);
1828
+ },
1829
+ "\nRenderer:",
1830
+ {
1831
+ dpr: this.renderer.getPixelRatio(),
1832
+ windowDpr: window.devicePixelRatio,
1833
+ antialias: gl.getContextAttributes()?.antialias,
1834
+ samples: gl.getParameter(gl.SAMPLES),
1835
+ resolution: `${this.renderer.domElement.width}x${this.renderer.domElement.height}`,
1836
+ },
1837
+ "\nTarget Framerate: " + this.targetFrameRate);
1791
1838
  }
1792
1839
  }
1793
1840
 
@@ -0,0 +1,73 @@
1
+ import type { Object3D } from "three";
2
+
3
+ import type { IComponent } from "./engine_types.js";
4
+
5
+ /** Typed event map for {@link Context.events}.
6
+ * Known events get full autocomplete; custom events can be typed at the call site via generic parameter.
7
+ */
8
+ export interface ContextEventMap {
9
+ "scene-content-changed": {
10
+ /** The component that triggered the change (e.g. SceneSwitcher, DropListener) */
11
+ readonly source: IComponent;
12
+ /** The root object that was added/loaded */
13
+ readonly object: Object3D;
14
+ };
15
+ }
16
+
17
+ /** Options for {@link EventBus.on}. */
18
+ export interface EventBusListenerOptions {
19
+ /** If true the listener is automatically removed after the first invocation. */
20
+ once?: boolean;
21
+ }
22
+
23
+ /** Typed event bus. Known {@link ContextEventMap} events get full autocomplete.
24
+ * Custom events can be typed at the call site via generic parameter.
25
+ * @example Known events
26
+ * ```ts
27
+ * context.events.on("scene-content-changed", e => e.object);
28
+ * ```
29
+ * @example Custom events — type at call site
30
+ * ```ts
31
+ * context.events.emit<{ pts: number }>("scored", { pts: 10 });
32
+ * context.events.on<{ pts: number }>("scored", e => e.pts);
33
+ * ```
34
+ * @example Once
35
+ * ```ts
36
+ * context.events.on("scene-content-changed", e => { ... }, { once: true });
37
+ * ```
38
+ */
39
+ export class EventBus {
40
+ private _listeners = new Map<string, Function[]>();
41
+
42
+ /** Emit a known {@link ContextEventMap} event */
43
+ emit<K extends keyof ContextEventMap & string>(type: K, detail?: ContextEventMap[K]): void;
44
+ /** Emit a custom event with user-provided type */
45
+ emit<T>(type: string, detail?: T): void;
46
+ emit(type: string, detail?: unknown): void {
47
+ const arr = this._listeners.get(type);
48
+ if (arr) for (const cb of [...arr]) cb(detail);
49
+ }
50
+
51
+ /** Subscribe to a known {@link ContextEventMap} event. Returns an unsubscribe function. */
52
+ on<K extends keyof ContextEventMap & string>(type: K, callback: (args: ContextEventMap[K]) => void, options?: EventBusListenerOptions): () => void;
53
+ /** Subscribe to a custom event with user-provided type. Returns an unsubscribe function. */
54
+ on<T>(type: string, callback: (args: T) => void, options?: EventBusListenerOptions): () => void;
55
+ on(type: string, callback: Function, options?: EventBusListenerOptions): () => void {
56
+ let arr = this._listeners.get(type);
57
+ if (!arr) { arr = []; this._listeners.set(type, arr); }
58
+ const unsub = () => {
59
+ const i = arr.indexOf(wrapped);
60
+ if (i >= 0) arr.splice(i, 1);
61
+ };
62
+ const wrapped = options?.once
63
+ ? (...args: unknown[]) => { unsub(); callback(...args); }
64
+ : callback;
65
+ arr.push(wrapped);
66
+ return unsub;
67
+ }
68
+
69
+ /** Remove all listeners. Called when the context is cleared or destroyed. */
70
+ clear(): void {
71
+ this._listeners.clear();
72
+ }
73
+ }