@needle-tools/engine 5.1.0-canary.c111c4f → 5.1.0-canary.cce79c8

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 (294) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/components.needle.json +1 -1
  3. package/dist/needle-engine.bundle-B1w7P037.min.js +1733 -0
  4. package/dist/needle-engine.bundle-C4w-9vec.umd.cjs +1733 -0
  5. package/dist/{needle-engine.bundle-BuaGvme0.js → needle-engine.bundle-CPbnC8NP.js} +15153 -14701
  6. package/dist/needle-engine.d.ts +898 -271
  7. package/dist/needle-engine.js +584 -582
  8. package/dist/needle-engine.min.js +1 -1
  9. package/dist/needle-engine.umd.cjs +1 -1
  10. package/dist/three-examples.js +3778 -4289
  11. package/dist/three-examples.min.js +14 -301
  12. package/dist/three-examples.umd.cjs +14 -301
  13. package/lib/engine/api.d.ts +5 -0
  14. package/lib/engine/api.js +4 -0
  15. package/lib/engine/api.js.map +1 -1
  16. package/lib/engine/codegen/register_types.js +2 -10
  17. package/lib/engine/codegen/register_types.js.map +1 -1
  18. package/lib/engine/debug/debug_spatial_console.d.ts +2 -0
  19. package/lib/engine/debug/debug_spatial_console.js +10 -7
  20. package/lib/engine/debug/debug_spatial_console.js.map +1 -1
  21. package/lib/engine/engine_addressables.d.ts +2 -0
  22. package/lib/engine/engine_addressables.js +6 -3
  23. package/lib/engine/engine_addressables.js.map +1 -1
  24. package/lib/engine/engine_audio.d.ts +68 -0
  25. package/lib/engine/engine_audio.js +172 -0
  26. package/lib/engine/engine_audio.js.map +1 -1
  27. package/lib/engine/engine_components.js +1 -1
  28. package/lib/engine/engine_components.js.map +1 -1
  29. package/lib/engine/engine_context.d.ts +17 -20
  30. package/lib/engine/engine_context.js +15 -17
  31. package/lib/engine/engine_context.js.map +1 -1
  32. package/lib/engine/engine_disposable.d.ts +172 -0
  33. package/lib/engine/engine_disposable.js +136 -0
  34. package/lib/engine/engine_disposable.js.map +1 -0
  35. package/lib/engine/engine_gameobject.d.ts +1 -10
  36. package/lib/engine/engine_gameobject.js +22 -120
  37. package/lib/engine/engine_gameobject.js.map +1 -1
  38. package/lib/engine/engine_gltf_builtin_components.js +7 -69
  39. package/lib/engine/engine_gltf_builtin_components.js.map +1 -1
  40. package/lib/engine/engine_init.js +13 -3
  41. package/lib/engine/engine_init.js.map +1 -1
  42. package/lib/engine/engine_input.d.ts +1 -1
  43. package/lib/engine/engine_input.js +1 -1
  44. package/lib/engine/engine_input.js.map +1 -1
  45. package/lib/engine/engine_instantiate_resolve.d.ts +42 -0
  46. package/lib/engine/engine_instantiate_resolve.js +372 -0
  47. package/lib/engine/engine_instantiate_resolve.js.map +1 -0
  48. package/lib/engine/engine_license.js +1 -1
  49. package/lib/engine/engine_license.js.map +1 -1
  50. package/lib/engine/engine_mainloop_utils.js +7 -4
  51. package/lib/engine/engine_mainloop_utils.js.map +1 -1
  52. package/lib/engine/engine_networking.d.ts +51 -37
  53. package/lib/engine/engine_networking.js +132 -82
  54. package/lib/engine/engine_networking.js.map +1 -1
  55. package/lib/engine/engine_networking.transport.websocket.d.ts +15 -0
  56. package/lib/engine/engine_networking.transport.websocket.js +38 -0
  57. package/lib/engine/engine_networking.transport.websocket.js.map +1 -0
  58. package/lib/engine/engine_networking_blob.js +1 -1
  59. package/lib/engine/engine_networking_blob.js.map +1 -1
  60. package/lib/engine/engine_networking_instantiate.js +2 -2
  61. package/lib/engine/engine_networking_instantiate.js.map +1 -1
  62. package/lib/engine/engine_networking_types.d.ts +39 -1
  63. package/lib/engine/engine_networking_types.js +7 -0
  64. package/lib/engine/engine_networking_types.js.map +1 -1
  65. package/lib/engine/engine_physics_rapier.d.ts +11 -3
  66. package/lib/engine/engine_physics_rapier.js +88 -25
  67. package/lib/engine/engine_physics_rapier.js.map +1 -1
  68. package/lib/engine/engine_scenedata.d.ts +5 -7
  69. package/lib/engine/engine_scenedata.js +16 -13
  70. package/lib/engine/engine_scenedata.js.map +1 -1
  71. package/lib/engine/engine_serialization_builtin_serializer.d.ts +10 -16
  72. package/lib/engine/engine_serialization_builtin_serializer.js +56 -46
  73. package/lib/engine/engine_serialization_builtin_serializer.js.map +1 -1
  74. package/lib/engine/engine_serialization_core.d.ts +1 -0
  75. package/lib/engine/engine_serialization_core.js +7 -0
  76. package/lib/engine/engine_serialization_core.js.map +1 -1
  77. package/lib/engine/engine_types.d.ts +19 -11
  78. package/lib/engine/engine_types.js +1 -1
  79. package/lib/engine/engine_types.js.map +1 -1
  80. package/lib/engine/engine_util_decorator.js +7 -2
  81. package/lib/engine/engine_util_decorator.js.map +1 -1
  82. package/lib/engine/engine_utils.d.ts +1 -1
  83. package/lib/engine/engine_utils.js +19 -5
  84. package/lib/engine/engine_utils.js.map +1 -1
  85. package/lib/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js +1 -1
  86. package/lib/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js.map +1 -1
  87. package/lib/engine/webcomponents/jsx.d.ts +51 -0
  88. package/lib/engine/webcomponents/logo-element.js.map +1 -1
  89. package/lib/engine/webcomponents/needle menu/needle-menu.d.ts +3 -4
  90. package/lib/engine/webcomponents/needle menu/needle-menu.js +1 -1
  91. package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
  92. package/lib/engine/webcomponents/needle-button.js.map +1 -1
  93. package/lib/engine/webcomponents/needle-engine.d.ts +10 -4
  94. package/lib/engine/webcomponents/needle-engine.js +1 -1
  95. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  96. package/lib/engine/xr/NeedleXRSession.d.ts +3 -2
  97. package/lib/engine/xr/NeedleXRSession.js +50 -14
  98. package/lib/engine/xr/NeedleXRSession.js.map +1 -1
  99. package/lib/engine/xr/events.d.ts +1 -1
  100. package/lib/engine/xr/events.js.map +1 -1
  101. package/lib/engine-components/Animation.js +17 -16
  102. package/lib/engine-components/Animation.js.map +1 -1
  103. package/lib/engine-components/Animator.d.ts +6 -0
  104. package/lib/engine-components/Animator.js +17 -12
  105. package/lib/engine-components/Animator.js.map +1 -1
  106. package/lib/engine-components/AnimatorController.builder.d.ts +113 -0
  107. package/lib/engine-components/AnimatorController.builder.js +195 -0
  108. package/lib/engine-components/AnimatorController.builder.js.map +1 -0
  109. package/lib/engine-components/AnimatorController.d.ts +4 -119
  110. package/lib/engine-components/AnimatorController.js +35 -233
  111. package/lib/engine-components/AnimatorController.js.map +1 -1
  112. package/lib/engine-components/AudioSource.d.ts +19 -3
  113. package/lib/engine-components/AudioSource.js +121 -68
  114. package/lib/engine-components/AudioSource.js.map +1 -1
  115. package/lib/engine-components/Collider.d.ts +18 -9
  116. package/lib/engine-components/Collider.js +61 -14
  117. package/lib/engine-components/Collider.js.map +1 -1
  118. package/lib/engine-components/Component.d.ts +72 -9
  119. package/lib/engine-components/Component.js +114 -10
  120. package/lib/engine-components/Component.js.map +1 -1
  121. package/lib/engine-components/DragControls.d.ts +7 -0
  122. package/lib/engine-components/DragControls.js +19 -7
  123. package/lib/engine-components/DragControls.js.map +1 -1
  124. package/lib/engine-components/EventList.d.ts +31 -9
  125. package/lib/engine-components/EventList.js +37 -76
  126. package/lib/engine-components/EventList.js.map +1 -1
  127. package/lib/engine-components/Joints.d.ts +4 -2
  128. package/lib/engine-components/Joints.js +19 -3
  129. package/lib/engine-components/Joints.js.map +1 -1
  130. package/lib/engine-components/Light.d.ts +0 -19
  131. package/lib/engine-components/Light.js +13 -97
  132. package/lib/engine-components/Light.js.map +1 -1
  133. package/lib/engine-components/Networking.d.ts +1 -1
  134. package/lib/engine-components/Networking.js +1 -1
  135. package/lib/engine-components/OrbitControls.js +16 -11
  136. package/lib/engine-components/OrbitControls.js.map +1 -1
  137. package/lib/engine-components/ReflectionProbe.js +2 -0
  138. package/lib/engine-components/ReflectionProbe.js.map +1 -1
  139. package/lib/engine-components/RigidBody.d.ts +12 -4
  140. package/lib/engine-components/RigidBody.js +18 -4
  141. package/lib/engine-components/RigidBody.js.map +1 -1
  142. package/lib/engine-components/SeeThrough.js +2 -2
  143. package/lib/engine-components/SeeThrough.js.map +1 -1
  144. package/lib/engine-components/api.d.ts +1 -1
  145. package/lib/engine-components/api.js +1 -1
  146. package/lib/engine-components/api.js.map +1 -1
  147. package/lib/engine-components/codegen/components.d.ts +3 -9
  148. package/lib/engine-components/codegen/components.js +3 -9
  149. package/lib/engine-components/codegen/components.js.map +1 -1
  150. package/lib/engine-components/postprocessing/Effects/Tonemapping.utils.d.ts +1 -1
  151. package/lib/engine-components/postprocessing/VolumeParameter.d.ts +2 -0
  152. package/lib/engine-components/postprocessing/VolumeParameter.js +4 -1
  153. package/lib/engine-components/postprocessing/VolumeParameter.js.map +1 -1
  154. package/lib/engine-components/timeline/PlayableDirector.d.ts +16 -6
  155. package/lib/engine-components/timeline/PlayableDirector.js +63 -61
  156. package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
  157. package/lib/engine-components/timeline/SignalAsset.d.ts +3 -1
  158. package/lib/engine-components/timeline/SignalAsset.js +1 -0
  159. package/lib/engine-components/timeline/SignalAsset.js.map +1 -1
  160. package/lib/engine-components/timeline/TimelineBuilder.d.ts +247 -0
  161. package/lib/engine-components/timeline/TimelineBuilder.js +400 -0
  162. package/lib/engine-components/timeline/TimelineBuilder.js.map +1 -0
  163. package/lib/engine-components/timeline/TimelineModels.d.ts +2 -1
  164. package/lib/engine-components/timeline/TimelineModels.js +3 -0
  165. package/lib/engine-components/timeline/TimelineModels.js.map +1 -1
  166. package/lib/engine-components/timeline/TimelineTracks.d.ts +23 -0
  167. package/lib/engine-components/timeline/TimelineTracks.js +71 -13
  168. package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
  169. package/lib/engine-components/timeline/index.d.ts +2 -1
  170. package/lib/engine-components/timeline/index.js +2 -0
  171. package/lib/engine-components/timeline/index.js.map +1 -1
  172. package/lib/engine-components/ui/Canvas.d.ts +1 -1
  173. package/lib/engine-components/ui/Canvas.js +2 -8
  174. package/lib/engine-components/ui/Canvas.js.map +1 -1
  175. package/lib/engine-components/ui/Text.d.ts +1 -0
  176. package/lib/engine-components/ui/Text.js +10 -7
  177. package/lib/engine-components/ui/Text.js.map +1 -1
  178. package/lib/engine-components/web/CursorFollow.js +21 -12
  179. package/lib/engine-components/web/CursorFollow.js.map +1 -1
  180. package/lib/engine-components/webxr/WebXRImageTracking.js +4 -0
  181. package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
  182. package/lib/needle-engine.d.ts +2 -0
  183. package/lib/needle-engine.js +1 -0
  184. package/lib/needle-engine.js.map +1 -1
  185. package/package.json +2 -83
  186. package/plugins/common/license.js +5 -2
  187. package/plugins/common/worker.js +9 -4
  188. package/plugins/dts-generator/dts.codegen.js +12 -6
  189. package/plugins/dts-generator/dts.writer.js +1 -1
  190. package/plugins/dts-generator/glb.extractor.js +12 -1
  191. package/plugins/dts-generator/glb.reader.js +42 -33
  192. package/plugins/types/userconfig.d.ts +12 -0
  193. package/plugins/vite/asap.js +17 -8
  194. package/plugins/vite/dependencies.js +29 -10
  195. package/plugins/vite/dependency-watcher.js +2 -2
  196. package/plugins/vite/dts-generator.d.ts +2 -2
  197. package/plugins/vite/dts-generator.js +6 -1
  198. package/plugins/vite/editor-connection.js +3 -3
  199. package/plugins/vite/local-files-core.js +3 -3
  200. package/plugins/vite/local-files-utils.d.ts +3 -1
  201. package/plugins/vite/local-files-utils.js +29 -5
  202. package/plugins/vite/reload.js +19 -18
  203. package/plugins/vite/server.js +2 -1
  204. package/src/engine/api.ts +7 -0
  205. package/src/engine/codegen/register_types.ts +2 -10
  206. package/src/engine/debug/debug_spatial_console.ts +10 -7
  207. package/src/engine/engine_addressables.ts +6 -3
  208. package/src/engine/engine_audio.ts +184 -0
  209. package/src/engine/engine_components.ts +1 -1
  210. package/src/engine/engine_context.ts +22 -23
  211. package/src/engine/engine_disposable.ts +214 -0
  212. package/src/engine/engine_gameobject.ts +54 -159
  213. package/src/engine/engine_gltf_builtin_components.ts +7 -76
  214. package/src/engine/engine_init.ts +13 -3
  215. package/src/engine/engine_input.ts +1 -1
  216. package/src/engine/engine_instantiate_resolve.ts +407 -0
  217. package/src/engine/engine_license.ts +1 -1
  218. package/src/engine/engine_mainloop_utils.ts +7 -4
  219. package/src/engine/engine_networking.transport.websocket.ts +45 -0
  220. package/src/engine/engine_networking.ts +161 -137
  221. package/src/engine/engine_networking_blob.ts +1 -1
  222. package/src/engine/engine_networking_instantiate.ts +2 -2
  223. package/src/engine/engine_networking_types.ts +41 -1
  224. package/src/engine/engine_physics_rapier.ts +82 -27
  225. package/src/engine/engine_scenedata.ts +16 -13
  226. package/src/engine/engine_serialization_builtin_serializer.ts +64 -52
  227. package/src/engine/engine_serialization_core.ts +9 -0
  228. package/src/engine/engine_types.ts +24 -15
  229. package/src/engine/engine_util_decorator.ts +7 -2
  230. package/src/engine/engine_utils.ts +16 -5
  231. package/src/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js +1 -1
  232. package/src/engine/webcomponents/jsx.d.ts +51 -0
  233. package/src/engine/webcomponents/logo-element.ts +1 -0
  234. package/src/engine/webcomponents/needle menu/needle-menu.ts +3 -2
  235. package/src/engine/webcomponents/needle-button.ts +1 -0
  236. package/src/engine/webcomponents/needle-engine.ts +11 -4
  237. package/src/engine/xr/NeedleXRSession.ts +48 -13
  238. package/src/engine/xr/events.ts +1 -1
  239. package/src/engine-components/Animation.ts +19 -16
  240. package/src/engine-components/Animator.ts +18 -11
  241. package/src/engine-components/AnimatorController.builder.ts +261 -0
  242. package/src/engine-components/AnimatorController.ts +23 -292
  243. package/src/engine-components/AudioSource.ts +130 -79
  244. package/src/engine-components/Collider.ts +66 -18
  245. package/src/engine-components/Component.ts +118 -20
  246. package/src/engine-components/DragControls.ts +18 -11
  247. package/src/engine-components/EventList.ts +45 -83
  248. package/src/engine-components/Joints.ts +20 -4
  249. package/src/engine-components/Light.ts +13 -96
  250. package/src/engine-components/Networking.ts +1 -1
  251. package/src/engine-components/OrbitControls.ts +18 -9
  252. package/src/engine-components/ReflectionProbe.ts +2 -0
  253. package/src/engine-components/RigidBody.ts +18 -4
  254. package/src/engine-components/SeeThrough.ts +2 -2
  255. package/src/engine-components/api.ts +1 -1
  256. package/src/engine-components/codegen/components.ts +3 -9
  257. package/src/engine-components/postprocessing/VolumeParameter.ts +4 -1
  258. package/src/engine-components/timeline/PlayableDirector.ts +61 -64
  259. package/src/engine-components/timeline/SignalAsset.ts +4 -1
  260. package/src/engine-components/timeline/TimelineBuilder.ts +565 -0
  261. package/src/engine-components/timeline/TimelineModels.ts +5 -1
  262. package/src/engine-components/timeline/TimelineTracks.ts +74 -13
  263. package/src/engine-components/timeline/index.ts +2 -1
  264. package/src/engine-components/ui/Canvas.ts +2 -8
  265. package/src/engine-components/ui/Text.ts +12 -8
  266. package/src/engine-components/web/CursorFollow.ts +21 -13
  267. package/src/engine-components/webxr/WebXRImageTracking.ts +2 -0
  268. package/src/needle-engine.ts +1 -0
  269. package/dist/needle-engine.bundle-CayCdkzK.min.js +0 -1732
  270. package/dist/needle-engine.bundle-DVhVGqQR.umd.cjs +0 -1732
  271. package/lib/engine-components/AvatarLoader.d.ts +0 -80
  272. package/lib/engine-components/AvatarLoader.js +0 -232
  273. package/lib/engine-components/AvatarLoader.js.map +0 -1
  274. package/lib/engine-components/avatar/AvatarBlink_Simple.d.ts +0 -11
  275. package/lib/engine-components/avatar/AvatarBlink_Simple.js +0 -77
  276. package/lib/engine-components/avatar/AvatarBlink_Simple.js.map +0 -1
  277. package/lib/engine-components/avatar/AvatarEyeLook_Rotation.d.ts +0 -14
  278. package/lib/engine-components/avatar/AvatarEyeLook_Rotation.js +0 -69
  279. package/lib/engine-components/avatar/AvatarEyeLook_Rotation.js.map +0 -1
  280. package/lib/engine-components/avatar/Avatar_Brain_LookAt.d.ts +0 -29
  281. package/lib/engine-components/avatar/Avatar_Brain_LookAt.js +0 -122
  282. package/lib/engine-components/avatar/Avatar_Brain_LookAt.js.map +0 -1
  283. package/lib/engine-components/avatar/Avatar_MouthShapes.d.ts +0 -15
  284. package/lib/engine-components/avatar/Avatar_MouthShapes.js +0 -80
  285. package/lib/engine-components/avatar/Avatar_MouthShapes.js.map +0 -1
  286. package/lib/engine-components/avatar/Avatar_MustacheShake.d.ts +0 -9
  287. package/lib/engine-components/avatar/Avatar_MustacheShake.js +0 -30
  288. package/lib/engine-components/avatar/Avatar_MustacheShake.js.map +0 -1
  289. package/src/engine-components/AvatarLoader.ts +0 -264
  290. package/src/engine-components/avatar/AvatarBlink_Simple.ts +0 -70
  291. package/src/engine-components/avatar/AvatarEyeLook_Rotation.ts +0 -64
  292. package/src/engine-components/avatar/Avatar_Brain_LookAt.ts +0 -140
  293. package/src/engine-components/avatar/Avatar_MouthShapes.ts +0 -84
  294. package/src/engine-components/avatar/Avatar_MustacheShake.ts +0 -32
@@ -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,
@@ -36,9 +37,8 @@ import * as looputils from './engine_mainloop_utils.js';
36
37
  import { NetworkConnection } from './engine_networking.js';
37
38
  import { Physics } from './engine_physics.js';
38
39
  import { PlayerViewManager } from './engine_playerview.js';
39
- import { RendererData as SceneLighting } from './engine_scenelighting.js';
40
40
  import { getSceneData } from './engine_scenedata.js';
41
- import type { SceneData } from 'needle-bindings';
41
+ import { RendererData as SceneLighting } from './engine_scenelighting.js';
42
42
  import { getTempColor, logHierarchy } from './engine_three_utils.js';
43
43
  import { Time } from './engine_time.js';
44
44
  import { patchTonemapping } from './engine_tonemapping.js';
@@ -478,13 +478,14 @@ export class Context implements IContext {
478
478
  * Use `setCurrentCamera` for updating the main camera.
479
479
  */
480
480
  /**
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.
481
+ * Access your scene's full hierarchy, objects, and components directly by name with full autocomplete.
482
+ * Types are generated automatically from your GLB files when the dev server starts.
483
+ *
484
+ * You can store references to objects or components for later use.
485
+ * Note that the scene hierarchy can change at runtime (e.g. when objects are added, removed, or re-parented),
486
+ * in which case stored references may become stale.
484
487
  *
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)`.
488
+ * @experimental This API may change in future versions.
488
489
  *
489
490
  * @example
490
491
  * // Toggle auto-rotate on the orbit camera
@@ -493,12 +494,6 @@ export class Context implements IContext {
493
494
  * @example
494
495
  * // Change the background color
495
496
  * 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
497
  */
503
498
  get sceneData(): SceneData {
504
499
  return getSceneData(this);
@@ -543,8 +538,10 @@ export class Context implements IContext {
543
538
  /** @deprecated AssetDatabase is deprecated */
544
539
  assets: AssetDatabase;
545
540
 
546
- /** All registered lights in the scene, maintained by the Light component */
547
- readonly lights: Set<ILight> = new Set();
541
+ /** All registered lights in the scene, maintained by the Light component.
542
+ * @see mainLight for accessing the main directional light in the scene
543
+ */
544
+ readonly lights = new Array<ILight>();
548
545
 
549
546
  /** The brightest registered directional light, or null if none are registered
550
547
  * @see lights
@@ -559,12 +556,13 @@ export class Context implements IContext {
559
556
  }
560
557
 
561
558
  /** @deprecated Use sceneLighting */
562
- get rendererData() { return this.sceneLighting }
559
+ private get rendererData() { return this.sceneLighting }
560
+
563
561
  /** Access the scene lighting manager to control lighting settings in the context */
564
- sceneLighting: SceneLighting;
565
- addressables: Addressables;
566
- lightmaps: ILightDataRegistry;
567
- players: PlayerViewManager;
562
+ readonly sceneLighting: SceneLighting;
563
+ readonly addressables: Addressables;
564
+ readonly lightmaps: ILightDataRegistry;
565
+ readonly players: PlayerViewManager;
568
566
 
569
567
  /** Access the LODs manager to control LOD behavior in the context */
570
568
  readonly lodsManager: LODsManager;
@@ -865,14 +863,14 @@ export class Context implements IContext {
865
863
  this.scene = new Scene();
866
864
  this.addressables?.dispose();
867
865
  this.lightmaps?.clear();
868
- this.physics?.engine?.clearCaches();
866
+ this.physics?.engine?.dispose();
869
867
  this.lodsManager.disable();
870
868
  this.accessibility?.clear();
871
869
 
872
870
  this._onBeforeRenderListeners.clear();
873
871
  this._onAfterRenderListeners.clear();
874
872
 
875
- this.lights.clear();
873
+ this.lights.length = 0;
876
874
 
877
875
  if (!this.isManagedExternally) {
878
876
  if (this.renderer) {
@@ -914,6 +912,7 @@ export class Context implements IContext {
914
912
  this.scene = null!;
915
913
  this.renderer = null!;
916
914
  this.input.dispose();
915
+ this.connection.dispose();
917
916
  this.menu.onDestroy();
918
917
  this.animations.onDestroy();
919
918
  for (const cb of this._disposeCallbacks) {
@@ -0,0 +1,214 @@
1
+ /** A function that performs cleanup when called */
2
+ export type DisposeFn = () => void;
3
+
4
+ /**
5
+ * Interface for objects that hold resources and can be disposed.
6
+ * Implement this interface on any object that needs deterministic cleanup.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * class MyResource implements IDisposable {
11
+ * dispose() { /* release resources *\/ }
12
+ * }
13
+ * ```
14
+ *
15
+ * @category Utilities
16
+ * @group Lifecycle
17
+ */
18
+ export interface IDisposable {
19
+ dispose(): void;
20
+ }
21
+
22
+ /**
23
+ * Type guard to check if an object implements {@link IDisposable}.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * if (isDisposable(obj)) {
28
+ * obj.dispose(); // safe to call
29
+ * }
30
+ * ```
31
+ */
32
+ export function isDisposable(value: unknown): value is IDisposable {
33
+ return value !== null
34
+ && typeof value === "object"
35
+ && "dispose" in (value as object)
36
+ && typeof (value as IDisposable).dispose === "function";
37
+ }
38
+
39
+ /**
40
+ * @experimental
41
+ * Subscribe to a DOM event on any {@link EventTarget} (window, document, HTML elements, etc.)
42
+ * and return an {@link IDisposable} that removes the listener when disposed.
43
+ *
44
+ * Provides full TypeScript event type inference — the callback parameter
45
+ * is automatically typed based on the event name (e.g. `"resize"` → `UIEvent`,
46
+ * `"click"` → `MouseEvent`).
47
+ *
48
+ * Use with {@link DisposableStore.add} for automatic lifecycle cleanup in components.
49
+ *
50
+ * @param target The EventTarget to listen on (window, document, an element, etc.)
51
+ * @param type The event name (e.g. `"resize"`, `"click"`, `"keydown"`)
52
+ * @param listener The event handler callback
53
+ * @param options Optional addEventListener options (passive, capture, once, signal)
54
+ * @returns An {@link IDisposable} that removes the event listener when disposed
55
+ *
56
+ * @example Standalone usage
57
+ * ```ts
58
+ * import { on } from "@needle-tools/engine";
59
+ *
60
+ * const sub = on(window, "resize", (ev) => {
61
+ * // ev is typed as UIEvent
62
+ * console.log("resized", ev.target);
63
+ * });
64
+ *
65
+ * // Later: clean up
66
+ * sub.dispose();
67
+ * ```
68
+ *
69
+ * @example With autoCleanup in a component
70
+ * ```ts
71
+ * import { Behaviour, on } from "@needle-tools/engine";
72
+ *
73
+ * export class MyComponent extends Behaviour {
74
+ * onEnable() {
75
+ * this.autoCleanup(on(window, "resize", (ev) => { /* UIEvent *\/ }));
76
+ * this.autoCleanup(on(document, "keydown", (ev) => { /* KeyboardEvent *\/ }));
77
+ * this.autoCleanup(on(this.context.domElement, "click", (ev) => { /* MouseEvent *\/ }));
78
+ * }
79
+ * // All listeners removed automatically on disable!
80
+ * }
81
+ * ```
82
+ *
83
+ * @category Utilities
84
+ * @group Lifecycle
85
+ */
86
+ // #region on
87
+ export function on<K extends keyof WindowEventMap>(target: Window, type: K, listener: (ev: WindowEventMap[K]) => void, options?: boolean | AddEventListenerOptions): IDisposable;
88
+ export function on<K extends keyof DocumentEventMap>(target: Document, type: K, listener: (ev: DocumentEventMap[K]) => void, options?: boolean | AddEventListenerOptions): IDisposable;
89
+ export function on<K extends keyof HTMLElementEventMap>(target: HTMLElement, type: K, listener: (ev: HTMLElementEventMap[K]) => void, options?: boolean | AddEventListenerOptions): IDisposable;
90
+ export function on(target: EventTarget, type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): IDisposable;
91
+ export function on(target: EventTarget, type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): IDisposable {
92
+ target.addEventListener(type, listener, options);
93
+ return {
94
+ dispose() {
95
+ target.removeEventListener(type, listener, options);
96
+ }
97
+ };
98
+ }
99
+
100
+
101
+ /**
102
+ * A store for managing disposable resources (event subscriptions, listeners, callbacks)
103
+ * that should be cleaned up together.
104
+ *
105
+ * DisposableStore collects disposables and disposes them all at once when
106
+ * {@link dispose} is called. After disposal, the store can be reused — new items
107
+ * can be added and a subsequent {@link dispose} call will clean those up.
108
+ *
109
+ * This is the same pattern used internally by VSCode for lifecycle-bound resource management.
110
+ *
111
+ * @example Basic usage
112
+ * ```ts
113
+ * import { DisposableStore, on } from "@needle-tools/engine";
114
+ *
115
+ * const store = new DisposableStore();
116
+ *
117
+ * // Register a DOM event listener (typed!)
118
+ * store.add(on(window, "resize", (ev) => console.log(ev)));
119
+ *
120
+ * // Register the return value of EventList.on()
121
+ * store.add(myEventList.on(data => console.log(data)));
122
+ *
123
+ * // Register a raw cleanup function
124
+ * store.add(() => someSDK.off("event", handler));
125
+ *
126
+ * // Later: dispose everything at once
127
+ * store.dispose();
128
+ * ```
129
+ *
130
+ * @example Use with Needle Engine components
131
+ * ```ts
132
+ * import { Behaviour, serializable, EventList, on } from "@needle-tools/engine";
133
+ *
134
+ * export class MyComponent extends Behaviour {
135
+ * @serializable(EventList)
136
+ * onClick?: EventList;
137
+ *
138
+ * onEnable() {
139
+ * // DOM events — fully typed
140
+ * this.autoCleanup(on(window, "resize", (ev) => this.onResize(ev)));
141
+ *
142
+ * // EventList — .on() returns a function, autoCleanup accepts it
143
+ * this.autoCleanup(this.onClick?.on(() => console.log("clicked!")));
144
+ * }
145
+ * // No onDisable needed — cleaned up automatically!
146
+ * }
147
+ * ```
148
+ *
149
+ * @category Utilities
150
+ * @group Lifecycle
151
+ */
152
+ // #region DisposableStore
153
+ export class DisposableStore implements IDisposable {
154
+
155
+ private _disposables: Array<DisposeFn> = [];
156
+
157
+ /** The number of registered disposables */
158
+ get size() { return this._disposables.length; }
159
+
160
+ /**
161
+ * Register a disposable resource. Accepts:
162
+ * - An {@link IDisposable} object (has a `dispose()` method) — e.g. from {@link on}
163
+ * - A cleanup function (e.g. return value of `EventList.on()`)
164
+ * - `null` or `undefined` (safe no-op for conditional subscriptions)
165
+ *
166
+ * When {@link dispose} is called, all registered resources are cleaned up.
167
+ *
168
+ * @param disposable The resource to register for disposal
169
+ *
170
+ * @example
171
+ * ```ts
172
+ * const store = new DisposableStore();
173
+ *
174
+ * // IDisposable object from on()
175
+ * store.add(on(window, "resize", handler));
176
+ *
177
+ * // Function returned by EventList.on()
178
+ * store.add(myEvent.on(handler));
179
+ *
180
+ * // Raw cleanup function
181
+ * store.add(() => connection.close());
182
+ *
183
+ * // Conditional — safe with undefined
184
+ * store.add(this.maybeEvent?.on(handler));
185
+ * ```
186
+ */
187
+ add(disposable: IDisposable | DisposeFn | Function | null | undefined): void {
188
+ if (!disposable) return;
189
+ if (typeof disposable === "function") {
190
+ this._disposables.push(disposable as DisposeFn);
191
+ }
192
+ else if (typeof disposable === "object" && "dispose" in disposable) {
193
+ this._disposables.push(() => disposable.dispose());
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Dispose all registered resources. Each registered disposable is cleaned up,
199
+ * then the internal list is cleared. The store can be reused after disposal.
200
+ *
201
+ * Called automatically by the engine when a component's `onDisable` lifecycle fires.
202
+ */
203
+ dispose(): void {
204
+ for (let i = this._disposables.length - 1; i >= 0; i--) {
205
+ try {
206
+ this._disposables[i]();
207
+ }
208
+ catch (err) {
209
+ console.error("Error disposing resource", err);
210
+ }
211
+ }
212
+ this._disposables.length = 0;
213
+ }
214
+ }
@@ -10,10 +10,11 @@ import { $isUsingInstancing, InstancingUtil } from "./engine_instancing.js";
10
10
  import { processNewScripts } from "./engine_mainloop_utils.js";
11
11
  import type { syncInstantiate } from "./engine_networking_instantiate.js";
12
12
  import { InstantiateIdProvider } from "./engine_networking_instantiate.js";
13
- import { assign, ISerializable } from "./engine_serialization_core.js";
13
+ import { resolveInstanceReferences, type InstantiateReferenceMap, type InstantiateContext, type ObjectCloneReference } from "./engine_instantiate_resolve.js";
14
+ import { assign } from "./engine_serialization_core.js";
14
15
  import { Context, registerComponent } from "./engine_setup.js";
15
16
  import { getTempQuaternion, logHierarchy, setWorldPosition, setWorldQuaternion } from "./engine_three_utils.js";
16
- import { type Constructor, type GuidsMap, type IComponent as Component, type IComponent, IEventList, type IGameObject as GameObject, type UIDProvider } from "./engine_types.js";
17
+ import { type Constructor, type GuidsMap, type IComponent as Component, type IComponent, type IGameObject as GameObject, type UIDProvider, isComponent } from "./engine_types.js";
17
18
  import { deepClone, getParam, tryFindObject } from "./engine_utils.js";
18
19
  import { apply } from "./js-extensions/index.js";
19
20
 
@@ -212,8 +213,8 @@ function internalDestroy(instance: Object3D | Component, recursive: boolean = tr
212
213
  if (comp[$isDontDestroy]) return;
213
214
  destroyed_components.push(comp);
214
215
  const go = comp.gameObject;
215
- comp.__internalDisable();
216
- comp.__internalDestroy();
216
+ comp.__internalDisable?.();
217
+ comp.__internalDestroy?.();
217
218
  comp.gameObject = go;
218
219
  return;
219
220
  }
@@ -324,19 +325,8 @@ function internalForEachComponent(instance: Object3D, cb: ForEachComponentCallba
324
325
 
325
326
  }
326
327
 
327
- declare type ObjectCloneReference = {
328
- readonly original: object;
329
- readonly clone: object;
330
- }
331
-
332
-
333
- declare type InstantiateReferenceMap = Record<string, ObjectCloneReference>;
334
- declare type NewObjectReferenceMap = Record<string, { target: object, key: string }>;
335
-
336
- /**
337
- * Provides access to the instantiated object and its clone
338
- */
339
- export declare type InstantiateContext = Readonly<InstantiateReferenceMap>;
328
+ // Re-export types from the unified resolution module
329
+ export type { InstantiateContext, InstantiateReferenceMap, ObjectCloneReference } from "./engine_instantiate_resolve.js";
340
330
 
341
331
  /**
342
332
  * Creates a copy (clone) of a GameObject or loads and instantiates an AssetReference.
@@ -410,7 +400,7 @@ export function instantiate(instance: AssetReference | GameObject | Object3D, op
410
400
  const clone = internalInstantiate(context, instance, options, components, referencemap, skinnedMeshes);
411
401
 
412
402
  if (clone) {
413
- resolveReferences(clone, referencemap);
403
+ resolveInstanceReferences(referencemap);
414
404
  resolveAndBindSkinnedMeshBones(skinnedMeshes, referencemap);
415
405
  }
416
406
 
@@ -420,6 +410,18 @@ export function instantiate(instance: AssetReference | GameObject | Object3D, op
420
410
  }
421
411
 
422
412
  const guidsMap: GuidsMap = {};
413
+
414
+ // Cloned object guids
415
+ for (const ref in referencemap) {
416
+ const val = referencemap[ref];
417
+ const original = val.original;
418
+ const clone = val.clone;
419
+ if (original instanceof Object3D && clone instanceof Object3D) {
420
+ guidsMap[original.guid || original.uuid] = clone.guid || clone.uuid;
421
+ }
422
+ }
423
+
424
+ // Cloned component guids (generate new guids for components that dont have one and add them to the map)
423
425
  if (options?.components !== false) {
424
426
  for (const i in components) {
425
427
  const copy = components[i];
@@ -427,8 +429,7 @@ export function instantiate(instance: AssetReference | GameObject | Object3D, op
427
429
  if (options && options.idProvider) {
428
430
  copy.guid = options.idProvider.generateUUID();
429
431
  guidsMap[oldGuid] = copy.guid;
430
- if (debug)
431
- console.log(copy.name, copy.guid)
432
+ if (debug) console.log(copy.name, copy.guid)
432
433
  }
433
434
  registerComponent(copy, context);
434
435
  if (copy.__internalNewInstanceCreated)
@@ -436,8 +437,6 @@ export function instantiate(instance: AssetReference | GameObject | Object3D, op
436
437
  }
437
438
  for (const i in components) {
438
439
  const copy = components[i];
439
- if (copy.resolveGuids)
440
- copy.resolveGuids(guidsMap);
441
440
  if (copy.enabled === false) continue;
442
441
  else copy.enabled = true;
443
442
  }
@@ -478,7 +477,12 @@ function internalInstantiate(
478
477
  instance.children = children;
479
478
 
480
479
  // make reference from old id to new object
481
- objectsMap[instance.uuid] = { original: instance, clone: clone };
480
+ const ref: ObjectCloneReference = { original: instance, clone: clone };
481
+ objectsMap[instance.uuid] = ref;
482
+ // Also key by guid so string guid references (e.g. PlayableDirector track.outputs) can be resolved
483
+ if ((instance).guid && (instance).guid !== instance.uuid) {
484
+ objectsMap[(instance).guid] = ref;
485
+ }
482
486
  if (debugInstantiate) console.log("ADD", instance, clone)
483
487
 
484
488
  if (instance.type === "SkinnedMesh") {
@@ -612,32 +616,32 @@ function internalInstantiate(
612
616
  function onAssignComponent(source: any, target: any, _newObjectsMap: InstantiateReferenceMap) {
613
617
  assign(target, source, undefined, {
614
618
  // onAssigned: (target, key, _oldValue, value) => {
615
- // if (value !== null && typeof value === "object") {
616
- // const serializable = target as ISerializable;
617
- // if (serializable?.$serializedTypes?.[key]) {
618
- // if (!(value instanceof Object3D)) {
619
- // // let clone = null;
620
- // // if ("clone" in value) {
621
- // // if (canClone(value)) clone = (value as any).clone();
622
- // // }
623
- // // else {
624
- // // clone = Object.assign(Object.create(Object.getPrototypeOf(value)), value);
625
- // // }
626
- // // if (clone) {
627
- // // console.debug(key, { target, value, clone })
628
- // // target[key] = clone;
629
- // // findNestedReferences(clone, objectsMap);
630
- // // }
631
- // // else console.debug("Could not clone value for key", key, value);
632
- // }
633
- // else {
634
- // console.log("ASSIGNED", value)
635
- // }
636
-
637
- // recursiveAssign(target, target[key], newObjectsMap);
638
- // }
639
-
640
- // }
619
+ // if (value !== null && typeof value === "object") {
620
+ // const serializable = target as ISerializable;
621
+ // if (serializable?.$serializedTypes?.[key]) {
622
+ // if (!(value instanceof Object3D)) {
623
+ // // let clone = null;
624
+ // // if ("clone" in value) {
625
+ // // if (canClone(value)) clone = (value as any).clone();
626
+ // // }
627
+ // // else {
628
+ // // clone = Object.assign(Object.create(Object.getPrototypeOf(value)), value);
629
+ // // }
630
+ // // if (clone) {
631
+ // // console.debug(key, { target, value, clone })
632
+ // // target[key] = clone;
633
+ // // findNestedReferences(clone, objectsMap);
634
+ // // }
635
+ // // else console.debug("Could not clone value for key", key, value);
636
+ // }
637
+ // else {
638
+ // console.log("ASSIGNED", value)
639
+ // }
640
+
641
+ // recursiveAssign(target, target[key], newObjectsMap);
642
+ // }
643
+
644
+ // }
641
645
  // }
642
646
  });
643
647
  }
@@ -742,113 +746,4 @@ function resolveAndBindSkinnedMeshBones(
742
746
 
743
747
  // }
744
748
 
745
- function resolveReferences(_newInstance: Object3D, newObjectsMap: InstantiateReferenceMap) {
746
- // for every object that is newly created we want to update references to their newly created counterparts
747
- // e.g. a collider instance referencing a rigidbody instance should be updated so that
748
- // the cloned collider does not reference the cloned rigidbody (instead of the original rigidbody)
749
- for (const key in newObjectsMap) {
750
- const val = newObjectsMap[key];
751
- const clone = val.clone as Object3D | null;
752
- // resolve references
753
- if (clone?.isObject3D && clone?.userData?.components) {
754
- for (let i = 0; i < clone.userData.components.length; i++) {
755
- const copy = clone.userData.components[i];
756
- // find referenced within a cloned gameobject
757
- const entries = Object.entries(copy);
758
- // console.log(copy, entries);
759
- for (const [key, value] of entries) {
760
- if (Array.isArray(value)) {
761
- const clonedArray: Array<any> = [];
762
- copy[key] = clonedArray;
763
- // console.log(copy, key, value, copy[key]);
764
- for (let i = 0; i < value.length; i++) {
765
- const entry = value[i];
766
- // push value types into new array
767
- if (typeof entry !== "object") {
768
- clonedArray.push(entry);
769
- continue;
770
- }
771
- const res: any = postProcessNewInstance(copy, key, entry, newObjectsMap);
772
- if (res !== undefined) {
773
- if (debugInstantiate) console.log("Found new instance for", key, entry, "->", res);
774
- clonedArray.push(res);
775
- }
776
- else {
777
- if (debugInstantiate) console.warn("Could not find new instance for", key, entry);
778
- clonedArray.push(entry);
779
- }
780
- }
781
- // console.log(copy[key])
782
- }
783
- else if (typeof value === "object") {
784
- const res = postProcessNewInstance(copy, key, value as IComponent | Object3D, newObjectsMap);
785
- if (res !== undefined) {
786
- copy[key] = res;
787
- }
788
- else {
789
- if (debugInstantiate) console.warn("Could not find new instance for", key, value);
790
- }
791
- }
792
- }
793
- }
794
- }
795
- }
796
-
797
- }
798
-
799
- function postProcessNewInstance(copy: Object3D, key: string, value: IComponent | Object3D | any, newObjectsMap: InstantiateReferenceMap) {
800
- if (value === null || value === undefined) return;
801
- if ((value as IComponent).isComponent === true) {
802
- const originalGameObjectReference = value["gameObject"];
803
- // console.log(key, value, originalGameObjectReference);
804
- if (originalGameObjectReference) {
805
- const id = originalGameObjectReference.uuid;
806
- const newGameObject = newObjectsMap[id]?.clone;
807
- if (!newGameObject) {
808
- // reference has not changed!
809
- if (debugInstantiate)
810
- console.log("reference did not change", key, copy, value);
811
- return;
812
- }
813
- const index = originalGameObjectReference.userData.components.indexOf(value);
814
- if (index >= 0 && (newGameObject as Object3D).isObject3D) {
815
- if (debugInstantiate)
816
- console.log(key, id);
817
- const found = (newGameObject as Object3D).userData.components[index];
818
- return found;
819
- }
820
- else {
821
- console.warn("could not find component", key, value);
822
- }
823
- }
824
- } else if ((value as Object3D).isObject3D === true) {
825
- // console.log(value);
826
- if (key === "gameObject") return;
827
- const originalGameObjectReference = value as Object3D;
828
- if (originalGameObjectReference) {
829
- const id = originalGameObjectReference.uuid;
830
- const newGameObject = newObjectsMap[id]?.clone;
831
- if (newGameObject) {
832
- if (debugInstantiate)
833
- console.log(key, "old", value, "new", newGameObject);
834
- return newGameObject;
835
- }
836
- }
837
- }
838
- else {
839
- // create new instances for some types that we know should usually not be shared and can safely be cloned
840
- if (value.isVector4 || value.isVector3 || value.isVector2 || value.isQuaternion || value.isEuler) {
841
- return value.clone();
842
- }
843
- else if (value.isColor === true) {
844
- return value.clone();
845
- }
846
- else if ((value as IEventList).isEventList === true) {
847
- // create a new instance of the object
848
- const copy = (value as IEventList).__internalOnInstantiate(newObjectsMap);
849
- return copy;
850
- }
851
- }
852
- }
853
-
854
- // const canClone = (value: any) => value.isVector4 || value.isVector3 || value.isVector2 || value.isQuaternion || value.isEuler || value.isColor === true;
749
+ // Reference resolution is now handled by the unified module: engine_instantiate_resolve.ts