@needle-tools/engine 5.1.0-alpha.2 → 5.1.0-alpha.4

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 (274) hide show
  1. package/CHANGELOG.md +74 -1
  2. package/SKILL.md +4 -1
  3. package/components.needle.json +1 -1
  4. package/dist/needle-engine.bundle-AjVIot3d.min.js +1733 -0
  5. package/dist/{needle-engine.bundle-dit3f1l5.js → needle-engine.bundle-B7cqsI4c.js} +12199 -11704
  6. package/dist/needle-engine.bundle-DQCuBTVp.umd.cjs +1733 -0
  7. package/dist/needle-engine.d.ts +879 -226
  8. package/dist/needle-engine.js +584 -582
  9. package/dist/needle-engine.min.js +1 -1
  10. package/dist/needle-engine.umd.cjs +1 -1
  11. package/lib/engine/api.d.ts +5 -0
  12. package/lib/engine/api.js +4 -0
  13. package/lib/engine/api.js.map +1 -1
  14. package/lib/engine/codegen/register_types.js +2 -10
  15. package/lib/engine/codegen/register_types.js.map +1 -1
  16. package/lib/engine/debug/debug_spatial_console.d.ts +2 -0
  17. package/lib/engine/debug/debug_spatial_console.js +10 -7
  18. package/lib/engine/debug/debug_spatial_console.js.map +1 -1
  19. package/lib/engine/engine_addressables.d.ts +2 -0
  20. package/lib/engine/engine_addressables.js +6 -3
  21. package/lib/engine/engine_addressables.js.map +1 -1
  22. package/lib/engine/engine_audio.d.ts +68 -0
  23. package/lib/engine/engine_audio.js +172 -0
  24. package/lib/engine/engine_audio.js.map +1 -1
  25. package/lib/engine/engine_components.js +1 -1
  26. package/lib/engine/engine_components.js.map +1 -1
  27. package/lib/engine/engine_context.d.ts +1 -1
  28. package/lib/engine/engine_context.js +3 -2
  29. package/lib/engine/engine_context.js.map +1 -1
  30. package/lib/engine/engine_disposable.d.ts +172 -0
  31. package/lib/engine/engine_disposable.js +136 -0
  32. package/lib/engine/engine_disposable.js.map +1 -0
  33. package/lib/engine/engine_gameobject.d.ts +1 -10
  34. package/lib/engine/engine_gameobject.js +22 -120
  35. package/lib/engine/engine_gameobject.js.map +1 -1
  36. package/lib/engine/engine_gltf_builtin_components.js +7 -69
  37. package/lib/engine/engine_gltf_builtin_components.js.map +1 -1
  38. package/lib/engine/engine_init.js +13 -3
  39. package/lib/engine/engine_init.js.map +1 -1
  40. package/lib/engine/engine_input.d.ts +1 -1
  41. package/lib/engine/engine_input.js +1 -1
  42. package/lib/engine/engine_input.js.map +1 -1
  43. package/lib/engine/engine_instantiate_resolve.d.ts +42 -0
  44. package/lib/engine/engine_instantiate_resolve.js +372 -0
  45. package/lib/engine/engine_instantiate_resolve.js.map +1 -0
  46. package/lib/engine/engine_license.js +1 -1
  47. package/lib/engine/engine_license.js.map +1 -1
  48. package/lib/engine/engine_mainloop_utils.js +7 -4
  49. package/lib/engine/engine_mainloop_utils.js.map +1 -1
  50. package/lib/engine/engine_networking.d.ts +51 -37
  51. package/lib/engine/engine_networking.js +132 -82
  52. package/lib/engine/engine_networking.js.map +1 -1
  53. package/lib/engine/engine_networking.transport.websocket.d.ts +15 -0
  54. package/lib/engine/engine_networking.transport.websocket.js +38 -0
  55. package/lib/engine/engine_networking.transport.websocket.js.map +1 -0
  56. package/lib/engine/engine_networking_blob.js +1 -1
  57. package/lib/engine/engine_networking_blob.js.map +1 -1
  58. package/lib/engine/engine_networking_instantiate.js +2 -2
  59. package/lib/engine/engine_networking_instantiate.js.map +1 -1
  60. package/lib/engine/engine_networking_types.d.ts +39 -1
  61. package/lib/engine/engine_networking_types.js +7 -0
  62. package/lib/engine/engine_networking_types.js.map +1 -1
  63. package/lib/engine/engine_physics_rapier.d.ts +11 -3
  64. package/lib/engine/engine_physics_rapier.js +88 -25
  65. package/lib/engine/engine_physics_rapier.js.map +1 -1
  66. package/lib/engine/engine_scenedata.d.ts +2 -0
  67. package/lib/engine/engine_scenedata.js +4 -2
  68. package/lib/engine/engine_scenedata.js.map +1 -1
  69. package/lib/engine/engine_serialization_builtin_serializer.d.ts +10 -16
  70. package/lib/engine/engine_serialization_builtin_serializer.js +56 -46
  71. package/lib/engine/engine_serialization_builtin_serializer.js.map +1 -1
  72. package/lib/engine/engine_serialization_core.d.ts +1 -0
  73. package/lib/engine/engine_serialization_core.js +7 -0
  74. package/lib/engine/engine_serialization_core.js.map +1 -1
  75. package/lib/engine/engine_types.d.ts +19 -11
  76. package/lib/engine/engine_types.js +1 -1
  77. package/lib/engine/engine_types.js.map +1 -1
  78. package/lib/engine/engine_util_decorator.js +7 -2
  79. package/lib/engine/engine_util_decorator.js.map +1 -1
  80. package/lib/engine/engine_utils.d.ts +1 -1
  81. package/lib/engine/engine_utils.js +19 -5
  82. package/lib/engine/engine_utils.js.map +1 -1
  83. package/lib/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js +1 -1
  84. package/lib/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js.map +1 -1
  85. package/lib/engine/webcomponents/needle menu/needle-menu.d.ts +1 -1
  86. package/lib/engine/webcomponents/needle menu/needle-menu.js +1 -1
  87. package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
  88. package/lib/engine/webcomponents/needle-engine.d.ts +10 -4
  89. package/lib/engine/webcomponents/needle-engine.js +1 -1
  90. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  91. package/lib/engine/xr/NeedleXRSession.d.ts +3 -2
  92. package/lib/engine/xr/NeedleXRSession.js +50 -14
  93. package/lib/engine/xr/NeedleXRSession.js.map +1 -1
  94. package/lib/engine/xr/events.d.ts +1 -1
  95. package/lib/engine/xr/events.js.map +1 -1
  96. package/lib/engine-components/Animation.js +17 -16
  97. package/lib/engine-components/Animation.js.map +1 -1
  98. package/lib/engine-components/Animator.d.ts +6 -0
  99. package/lib/engine-components/Animator.js +17 -12
  100. package/lib/engine-components/Animator.js.map +1 -1
  101. package/lib/engine-components/AnimatorController.builder.d.ts +113 -0
  102. package/lib/engine-components/AnimatorController.builder.js +195 -0
  103. package/lib/engine-components/AnimatorController.builder.js.map +1 -0
  104. package/lib/engine-components/AnimatorController.d.ts +4 -119
  105. package/lib/engine-components/AnimatorController.js +35 -233
  106. package/lib/engine-components/AnimatorController.js.map +1 -1
  107. package/lib/engine-components/AudioSource.d.ts +19 -3
  108. package/lib/engine-components/AudioSource.js +121 -68
  109. package/lib/engine-components/AudioSource.js.map +1 -1
  110. package/lib/engine-components/Collider.d.ts +18 -9
  111. package/lib/engine-components/Collider.js +61 -14
  112. package/lib/engine-components/Collider.js.map +1 -1
  113. package/lib/engine-components/Component.d.ts +72 -9
  114. package/lib/engine-components/Component.js +114 -10
  115. package/lib/engine-components/Component.js.map +1 -1
  116. package/lib/engine-components/DragControls.d.ts +7 -0
  117. package/lib/engine-components/DragControls.js +19 -7
  118. package/lib/engine-components/DragControls.js.map +1 -1
  119. package/lib/engine-components/EventList.d.ts +31 -9
  120. package/lib/engine-components/EventList.js +37 -76
  121. package/lib/engine-components/EventList.js.map +1 -1
  122. package/lib/engine-components/Joints.d.ts +4 -2
  123. package/lib/engine-components/Joints.js +19 -3
  124. package/lib/engine-components/Joints.js.map +1 -1
  125. package/lib/engine-components/Light.js +9 -1
  126. package/lib/engine-components/Light.js.map +1 -1
  127. package/lib/engine-components/Networking.d.ts +1 -1
  128. package/lib/engine-components/Networking.js +1 -1
  129. package/lib/engine-components/OrbitControls.js +16 -11
  130. package/lib/engine-components/OrbitControls.js.map +1 -1
  131. package/lib/engine-components/ReflectionProbe.js +2 -0
  132. package/lib/engine-components/ReflectionProbe.js.map +1 -1
  133. package/lib/engine-components/RigidBody.d.ts +12 -4
  134. package/lib/engine-components/RigidBody.js +18 -4
  135. package/lib/engine-components/RigidBody.js.map +1 -1
  136. package/lib/engine-components/SeeThrough.js +2 -2
  137. package/lib/engine-components/SeeThrough.js.map +1 -1
  138. package/lib/engine-components/api.d.ts +1 -1
  139. package/lib/engine-components/api.js +1 -1
  140. package/lib/engine-components/api.js.map +1 -1
  141. package/lib/engine-components/codegen/components.d.ts +3 -9
  142. package/lib/engine-components/codegen/components.js +3 -9
  143. package/lib/engine-components/codegen/components.js.map +1 -1
  144. package/lib/engine-components/postprocessing/Effects/Tonemapping.utils.d.ts +1 -1
  145. package/lib/engine-components/postprocessing/VolumeParameter.d.ts +2 -0
  146. package/lib/engine-components/postprocessing/VolumeParameter.js +4 -1
  147. package/lib/engine-components/postprocessing/VolumeParameter.js.map +1 -1
  148. package/lib/engine-components/timeline/PlayableDirector.d.ts +16 -6
  149. package/lib/engine-components/timeline/PlayableDirector.js +70 -62
  150. package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
  151. package/lib/engine-components/timeline/SignalAsset.d.ts +3 -1
  152. package/lib/engine-components/timeline/SignalAsset.js +1 -0
  153. package/lib/engine-components/timeline/SignalAsset.js.map +1 -1
  154. package/lib/engine-components/timeline/TimelineBuilder.d.ts +247 -0
  155. package/lib/engine-components/timeline/TimelineBuilder.js +400 -0
  156. package/lib/engine-components/timeline/TimelineBuilder.js.map +1 -0
  157. package/lib/engine-components/timeline/TimelineModels.d.ts +2 -1
  158. package/lib/engine-components/timeline/TimelineModels.js +3 -0
  159. package/lib/engine-components/timeline/TimelineModels.js.map +1 -1
  160. package/lib/engine-components/timeline/TimelineTracks.d.ts +23 -0
  161. package/lib/engine-components/timeline/TimelineTracks.js +71 -13
  162. package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
  163. package/lib/engine-components/timeline/index.d.ts +2 -1
  164. package/lib/engine-components/timeline/index.js +2 -0
  165. package/lib/engine-components/timeline/index.js.map +1 -1
  166. package/lib/engine-components/ui/Canvas.d.ts +1 -1
  167. package/lib/engine-components/ui/Canvas.js +2 -8
  168. package/lib/engine-components/ui/Canvas.js.map +1 -1
  169. package/lib/engine-components/ui/Text.d.ts +1 -0
  170. package/lib/engine-components/ui/Text.js +10 -7
  171. package/lib/engine-components/ui/Text.js.map +1 -1
  172. package/lib/engine-components/web/CursorFollow.js +21 -12
  173. package/lib/engine-components/web/CursorFollow.js.map +1 -1
  174. package/lib/engine-components/webxr/WebXRImageTracking.js +4 -0
  175. package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
  176. package/package.json +2 -83
  177. package/plugins/common/license.js +5 -2
  178. package/plugins/common/worker.js +9 -4
  179. package/plugins/vite/asap.js +17 -8
  180. package/plugins/vite/dependencies.js +29 -10
  181. package/plugins/vite/dependency-watcher.js +2 -2
  182. package/plugins/vite/editor-connection.js +3 -3
  183. package/plugins/vite/local-files-core.js +3 -3
  184. package/plugins/vite/local-files-utils.d.ts +3 -1
  185. package/plugins/vite/local-files-utils.js +29 -5
  186. package/plugins/vite/reload.js +1 -1
  187. package/plugins/vite/server.js +2 -1
  188. package/src/engine/api.ts +7 -0
  189. package/src/engine/codegen/register_types.ts +2 -10
  190. package/src/engine/debug/debug_spatial_console.ts +10 -7
  191. package/src/engine/engine_addressables.ts +6 -3
  192. package/src/engine/engine_audio.ts +184 -0
  193. package/src/engine/engine_components.ts +1 -1
  194. package/src/engine/engine_context.ts +4 -3
  195. package/src/engine/engine_disposable.ts +214 -0
  196. package/src/engine/engine_gameobject.ts +54 -159
  197. package/src/engine/engine_gltf_builtin_components.ts +7 -76
  198. package/src/engine/engine_init.ts +13 -3
  199. package/src/engine/engine_input.ts +1 -1
  200. package/src/engine/engine_instantiate_resolve.ts +407 -0
  201. package/src/engine/engine_license.ts +1 -1
  202. package/src/engine/engine_mainloop_utils.ts +7 -4
  203. package/src/engine/engine_networking.transport.websocket.ts +45 -0
  204. package/src/engine/engine_networking.ts +161 -137
  205. package/src/engine/engine_networking_blob.ts +1 -1
  206. package/src/engine/engine_networking_instantiate.ts +2 -2
  207. package/src/engine/engine_networking_types.ts +41 -1
  208. package/src/engine/engine_physics_rapier.ts +82 -27
  209. package/src/engine/engine_scenedata.ts +5 -3
  210. package/src/engine/engine_serialization_builtin_serializer.ts +64 -52
  211. package/src/engine/engine_serialization_core.ts +9 -0
  212. package/src/engine/engine_types.ts +24 -15
  213. package/src/engine/engine_util_decorator.ts +7 -2
  214. package/src/engine/engine_utils.ts +16 -5
  215. package/src/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js +1 -1
  216. package/src/engine/webcomponents/needle menu/needle-menu.ts +1 -1
  217. package/src/engine/webcomponents/needle-engine.ts +10 -4
  218. package/src/engine/xr/NeedleXRSession.ts +48 -13
  219. package/src/engine/xr/events.ts +1 -1
  220. package/src/engine-components/Animation.ts +19 -16
  221. package/src/engine-components/Animator.ts +18 -11
  222. package/src/engine-components/AnimatorController.builder.ts +261 -0
  223. package/src/engine-components/AnimatorController.ts +23 -292
  224. package/src/engine-components/AudioSource.ts +130 -79
  225. package/src/engine-components/Collider.ts +66 -18
  226. package/src/engine-components/Component.ts +118 -20
  227. package/src/engine-components/DragControls.ts +18 -11
  228. package/src/engine-components/EventList.ts +45 -83
  229. package/src/engine-components/Joints.ts +20 -4
  230. package/src/engine-components/Light.ts +10 -2
  231. package/src/engine-components/Networking.ts +1 -1
  232. package/src/engine-components/OrbitControls.ts +18 -9
  233. package/src/engine-components/ReflectionProbe.ts +2 -0
  234. package/src/engine-components/RigidBody.ts +18 -4
  235. package/src/engine-components/SeeThrough.ts +2 -2
  236. package/src/engine-components/api.ts +1 -1
  237. package/src/engine-components/codegen/components.ts +3 -9
  238. package/src/engine-components/postprocessing/VolumeParameter.ts +4 -1
  239. package/src/engine-components/timeline/PlayableDirector.ts +67 -65
  240. package/src/engine-components/timeline/SignalAsset.ts +4 -1
  241. package/src/engine-components/timeline/TimelineBuilder.ts +564 -0
  242. package/src/engine-components/timeline/TimelineModels.ts +5 -1
  243. package/src/engine-components/timeline/TimelineTracks.ts +74 -13
  244. package/src/engine-components/timeline/index.ts +2 -1
  245. package/src/engine-components/ui/Canvas.ts +2 -8
  246. package/src/engine-components/ui/Text.ts +12 -8
  247. package/src/engine-components/web/CursorFollow.ts +21 -13
  248. package/src/engine-components/webxr/WebXRImageTracking.ts +2 -0
  249. package/dist/needle-engine.bundle-B-5Q2CpC.min.js +0 -1732
  250. package/dist/needle-engine.bundle-qZfVf_v-.umd.cjs +0 -1732
  251. package/lib/engine-components/AvatarLoader.d.ts +0 -80
  252. package/lib/engine-components/AvatarLoader.js +0 -232
  253. package/lib/engine-components/AvatarLoader.js.map +0 -1
  254. package/lib/engine-components/avatar/AvatarBlink_Simple.d.ts +0 -11
  255. package/lib/engine-components/avatar/AvatarBlink_Simple.js +0 -77
  256. package/lib/engine-components/avatar/AvatarBlink_Simple.js.map +0 -1
  257. package/lib/engine-components/avatar/AvatarEyeLook_Rotation.d.ts +0 -14
  258. package/lib/engine-components/avatar/AvatarEyeLook_Rotation.js +0 -69
  259. package/lib/engine-components/avatar/AvatarEyeLook_Rotation.js.map +0 -1
  260. package/lib/engine-components/avatar/Avatar_Brain_LookAt.d.ts +0 -29
  261. package/lib/engine-components/avatar/Avatar_Brain_LookAt.js +0 -122
  262. package/lib/engine-components/avatar/Avatar_Brain_LookAt.js.map +0 -1
  263. package/lib/engine-components/avatar/Avatar_MouthShapes.d.ts +0 -15
  264. package/lib/engine-components/avatar/Avatar_MouthShapes.js +0 -80
  265. package/lib/engine-components/avatar/Avatar_MouthShapes.js.map +0 -1
  266. package/lib/engine-components/avatar/Avatar_MustacheShake.d.ts +0 -9
  267. package/lib/engine-components/avatar/Avatar_MustacheShake.js +0 -30
  268. package/lib/engine-components/avatar/Avatar_MustacheShake.js.map +0 -1
  269. package/src/engine-components/AvatarLoader.ts +0 -264
  270. package/src/engine-components/avatar/AvatarBlink_Simple.ts +0 -70
  271. package/src/engine-components/avatar/AvatarEyeLook_Rotation.ts +0 -64
  272. package/src/engine-components/avatar/Avatar_Brain_LookAt.ts +0 -140
  273. package/src/engine-components/avatar/Avatar_MouthShapes.ts +0 -84
  274. package/src/engine-components/avatar/Avatar_MustacheShake.ts +0 -32
@@ -40,6 +40,7 @@ import { GLTFLoader } from '../../../node_modules/@types/three/examples/jsm/load
40
40
  import { GLTFLoaderPlugin } from '../../../node_modules/@types/three/examples/jsm/loaders/GLTFLoader.js';
41
41
  import { GLTFParser } from '../../../node_modules/@types/three/examples/jsm/loaders/GLTFLoader.js';
42
42
  import { Group } from 'three';
43
+ import { ImpulseJoint } from '@dimforge/rapier3d-compat';
43
44
  import { InstancedMesh } from 'three';
44
45
  import { Intersection } from 'three';
45
46
  import { IParticleSystem as IParticleSystem_2 } from 'three.quarks';
@@ -254,6 +255,24 @@ export declare class ActionModel implements IBehaviorElement {
254
255
  writeTo(document: USDDocument, writer: USDWriter): void;
255
256
  }
256
257
 
258
+ /**
259
+ * Options for an activation clip in the timeline builder
260
+ */
261
+ export declare type ActivationClipOptions = {
262
+ /** Start time of the clip in seconds. If omitted, placed after the previous clip on this track. */
263
+ start?: number;
264
+ /** Duration of the clip in seconds (required) */
265
+ duration: number;
266
+ /** Ease-in duration in seconds (default: 0) */
267
+ easeIn?: number;
268
+ /** Ease-out duration in seconds (default: 0) */
269
+ easeOut?: number;
270
+ };
271
+
272
+ export declare class ActivationTrackHandler extends TrackHandler {
273
+ evaluate(time: number): void;
274
+ }
275
+
257
276
  export declare const activeInHierarchyFieldName = "needle_isActiveInHierarchy";
258
277
 
259
278
  /**
@@ -500,6 +519,34 @@ export declare type AnimationClipModel = {
500
519
  rotation?: Quat | Quaternion;
501
520
  };
502
521
 
522
+ /**
523
+ * Options for an animation clip in the timeline builder
524
+ */
525
+ export declare type AnimationClipOptions = {
526
+ /** Start time of the clip in seconds. If omitted, placed after the previous clip on this track. */
527
+ start?: number;
528
+ /** Duration of the clip in seconds. Defaults to the animation clip duration. */
529
+ duration?: number;
530
+ /** Playback speed multiplier (default: 1) */
531
+ speed?: number;
532
+ /** Whether the animation should loop within the clip (default: false) */
533
+ loop?: boolean;
534
+ /** Ease-in duration in seconds (default: 0) */
535
+ easeIn?: number;
536
+ /** Ease-out duration in seconds (default: 0) */
537
+ easeOut?: number;
538
+ /** Offset into the source animation clip in seconds (default: 0) */
539
+ clipIn?: number;
540
+ /** Whether to remove the start offset of the animation (default: false) */
541
+ removeStartOffset?: boolean;
542
+ /** Pre-extrapolation mode (default: None) */
543
+ preExtrapolation?: ClipExtrapolation;
544
+ /** Post-extrapolation mode (default: None) */
545
+ postExtrapolation?: ClipExtrapolation;
546
+ /** Play the clip in reverse */
547
+ reversed?: boolean;
548
+ };
549
+
503
550
  /**
504
551
  * AnimationCurve is a representation of a curve that can be used to animate values over time.
505
552
  *
@@ -726,6 +773,12 @@ export declare class Animator extends Component implements IAnimationComponent {
726
773
  * Identifies this component as an animation component in the engine
727
774
  */
728
775
  get isAnimationComponent(): boolean;
776
+ /**
777
+ * The current animator mixer, used for low-level control of animations. Owned by the AnimatorController
778
+ * @returns The current AnimationMixer, or null if no controller is assigned
779
+ * @see AnimatorController.mixer
780
+ */
781
+ get mixer(): AnimationMixer | null;
729
782
  /**
730
783
  * When enabled, animation will affect the root transform position and rotation
731
784
  */
@@ -1102,13 +1155,6 @@ export declare class AnimatorController {
1102
1155
  * @param animator - The animator to bind this controller to
1103
1156
  */
1104
1157
  bind(animator: Animator): void;
1105
- /**
1106
- * Creates a deep copy of this controller.
1107
- * Clones the model data but does not copy runtime state.
1108
- *
1109
- * @returns A new AnimatorController instance with the same configuration
1110
- */
1111
- clone(): AnimatorController | null;
1112
1158
  /**
1113
1159
  * Updates the controller's state machine and animations.
1114
1160
  * Called each frame by the animator component.
@@ -1472,6 +1518,75 @@ export declare class Attractor extends Component {
1472
1518
 
1473
1519
  declare type AttributeChangeCallback = (value: string | null) => void;
1474
1520
 
1521
+ /**
1522
+ * Represents an audio clip that can be loaded and played independently.
1523
+ * The AudioClip class encapsulates the URL of the audio resource and provides
1524
+ * methods for playback control (play, pause, stop) and querying duration.
1525
+ */
1526
+ export declare class AudioClip {
1527
+ readonly url: string;
1528
+ /**
1529
+ * Creates a new AudioClip instance with the specified URL.
1530
+ * @param url The URL of the audio resource to load. This can be a path to an audio file or a MediaStream URL.
1531
+ */
1532
+ constructor(url: string);
1533
+ /** Whether the clip is currently playing.
1534
+ * @returns `true` if the clip is actively playing audio.
1535
+ */
1536
+ get isPlaying(): boolean;
1537
+ /**
1538
+ * The total duration of the audio clip in seconds.
1539
+ * Loads the audio metadata if not already available.
1540
+ * @returns A promise that resolves with the duration in seconds.
1541
+ */
1542
+ getDuration(): Promise<number>;
1543
+ /**
1544
+ * Plays the audio clip from the current position.
1545
+ * @returns A promise that resolves when playback finishes, or rejects on error.
1546
+ * If the clip is looping, the promise will never resolve on its own – call {@link stop} or {@link pause} to end playback.
1547
+ */
1548
+ play(): Promise<void>;
1549
+ /**
1550
+ * Pauses playback at the current position.
1551
+ * Call {@link play} to resume.
1552
+ */
1553
+ pause(): void;
1554
+ /**
1555
+ * Stops playback and resets the position to the beginning.
1556
+ */
1557
+ stop(): void;
1558
+ /** Whether the clip should loop when reaching the end. */
1559
+ get loop(): boolean;
1560
+ set loop(value: boolean);
1561
+ /** Playback volume from 0 (silent) to 1 (full). */
1562
+ get volume(): number;
1563
+ set volume(value: number);
1564
+ /** Current playback position in seconds. */
1565
+ get currentTime(): number;
1566
+ set currentTime(value: number);
1567
+ /** Normalized playback progress from 0 to 1.
1568
+ * @returns The current playback position as a value between 0 and 1, or 0 if the duration is unknown.
1569
+ */
1570
+ get progress(): number;
1571
+ /**
1572
+ * Seeks to a normalized position (0–1) in the clip.
1573
+ * @param position A value between 0 (start) and 1 (end).
1574
+ */
1575
+ seek(position: number): void;
1576
+ /** The underlying HTMLAudioElement, or `undefined` if not yet created.
1577
+ * Use this to connect the element to the Web Audio API via `createMediaElementSource()`.
1578
+ * @returns The HTMLAudioElement if the clip has been loaded or played, otherwise `undefined`.
1579
+ */
1580
+ get audioElement(): HTMLAudioElement | undefined;
1581
+ private _audioElement?;
1582
+ private _duration?;
1583
+ private _loadPromise?;
1584
+ private _loop;
1585
+ private _volume;
1586
+ /** Lazily creates and loads the shared HTMLAudioElement. */
1587
+ private ensureAudioElement;
1588
+ }
1589
+
1475
1590
  /**
1476
1591
  * @category Animation and Sequencing
1477
1592
  * @see {@link PlayableDirector} for the main component to control timelines in Needle Engine.
@@ -1486,6 +1601,26 @@ declare type AudioClipModel_2 = Models.ClipModel & {
1486
1601
  _didTriggerPlay: boolean;
1487
1602
  };
1488
1603
 
1604
+ /**
1605
+ * Options for an audio clip in the timeline builder
1606
+ */
1607
+ export declare type AudioClipOptions = {
1608
+ /** Start time of the clip in seconds. If omitted, placed after the previous clip on this track. */
1609
+ start?: number;
1610
+ /** Duration of the clip in seconds (required for audio since we can't infer it) */
1611
+ duration: number;
1612
+ /** Playback speed multiplier (default: 1) */
1613
+ speed?: number;
1614
+ /** Volume multiplier for this clip (default: 1) */
1615
+ volume?: number;
1616
+ /** Whether the audio should loop within the clip (default: false) */
1617
+ loop?: boolean;
1618
+ /** Ease-in duration in seconds (default: 0) */
1619
+ easeIn?: number;
1620
+ /** Ease-out duration in seconds (default: 0) */
1621
+ easeOut?: number;
1622
+ };
1623
+
1489
1624
  export declare class AudioExtension implements IUSDExporterExtension {
1490
1625
  static getName(clip: string): string;
1491
1626
  get extensionName(): string;
@@ -1627,9 +1762,10 @@ export declare class AudioSource extends Component {
1627
1762
  */
1628
1763
  get isPlaying(): boolean;
1629
1764
  /**
1630
- * The total duration of the current audio clip in seconds.
1765
+ * The total duration of the currently loaded audio clip in seconds.
1631
1766
  *
1632
1767
  * @returns Duration in seconds or undefined if no clip is loaded
1768
+ * @remarks For MediaStream clips, duration is not directly available and will return undefined. If the audio clip has not started loading or is still loading, duration may also be undefined until the audio buffer is ready.
1633
1769
  */
1634
1770
  get duration(): number | undefined;
1635
1771
  /**
@@ -1654,7 +1790,8 @@ export declare class AudioSource extends Component {
1654
1790
  /**
1655
1791
  * Controls how the audio is positioned in space.
1656
1792
  * Values range from 0 (2D, non-positional) to 1 (fully 3D positioned).
1657
- * Note: 2D playback is not fully supported in the current implementation.
1793
+ * Internally uses a dual-path audio graph to crossfade between a spatialized (PannerNode)
1794
+ * and a non-spatialized (direct) signal path.
1658
1795
  */
1659
1796
  get spatialBlend(): number;
1660
1797
  set spatialBlend(val: number);
@@ -1702,7 +1839,11 @@ export declare class AudioSource extends Component {
1702
1839
  private audioLoader;
1703
1840
  private shouldPlay;
1704
1841
  private _lastClipStartedLoading;
1842
+ private _loadedClip;
1705
1843
  private _audioElement;
1844
+ private _entryNode;
1845
+ private _spatialGain;
1846
+ private _bypassGain;
1706
1847
  /**
1707
1848
  * Returns the underlying {@link PositionalAudio} object, creating it if necessary.
1708
1849
  * The audio source needs a user interaction to be initialized due to browser autoplay policies.
@@ -1730,6 +1871,15 @@ export declare class AudioSource extends Component {
1730
1871
  private onApplicationMuteChanged;
1731
1872
  private createAudio;
1732
1873
  private __onAllowAudioCallback;
1874
+ /**
1875
+ * Sets up the dual-path audio graph for spatial blend crossfading.
1876
+ * Creates two parallel signal paths from source to output:
1877
+ * - 3D path: entry → panner → spatialGain → gain (spatialized)
1878
+ * - 2D path: entry → bypassGain → gain (non-spatialized)
1879
+ */
1880
+ private setupSpatialBlendNodes;
1881
+ /** Updates the spatial/bypass gain values based on the current spatialBlend. */
1882
+ private updateSpatialBlendGains;
1733
1883
  private applySpatialDistanceSettings;
1734
1884
  private onNewClip;
1735
1885
  /**
@@ -1737,8 +1887,9 @@ export declare class AudioSource extends Component {
1737
1887
  * If no argument is provided, plays the currently assigned clip.
1738
1888
  *
1739
1889
  * @param clip - Optional audio clip or {@link MediaStream} to play
1890
+ * @returns A promise that resolves when playback starts successfully, or rejects on error
1740
1891
  */
1741
- play(clip?: string | MediaStream | undefined): void;
1892
+ play(clip?: string | MediaStream | undefined): Promise<boolean>;
1742
1893
  /**
1743
1894
  * Pauses audio playback while maintaining the current position.
1744
1895
  * Use play() to resume from the paused position.
@@ -1755,6 +1906,20 @@ export declare class AudioSource extends Component {
1755
1906
  /* Excluded from this release type: update */
1756
1907
  }
1757
1908
 
1909
+ /**
1910
+ * Handles audio playback for a timeline audio track.
1911
+ *
1912
+ * **Runtime mutation:** The track model is read fresh every frame during `evaluate()`.
1913
+ * You can mutate `track.volume`, `clip.start`, `clip.end`, `clip.asset.volume` etc.
1914
+ * at any time — changes take effect on the next frame without rebuilding the timeline.
1915
+ *
1916
+ * **Audio stopping:** Audio clips are automatically stopped when:
1917
+ * - Timeline time moves outside a clip's `[start, end]` range (e.g. jumping or normal playback advancing past a clip)
1918
+ * - The track is muted (via `muted = true`)
1919
+ * - The director is stopped (`director.stop()`)
1920
+ * - The director is paused (`director.pause()`)
1921
+ * - The director is disabled or destroyed
1922
+ */
1758
1923
  export declare class AudioTrackHandler extends TrackHandler {
1759
1924
  models: Array<AudioClipModel_2>;
1760
1925
  listener: AudioListener_3;
@@ -1762,6 +1927,9 @@ export declare class AudioTrackHandler extends TrackHandler {
1762
1927
  audioContextTimeOffset: Array<number>;
1763
1928
  lastTime: number;
1764
1929
  audioSource?: AudioSource;
1930
+ /** Track-level volume multiplier (0–1). Applied on top of per-clip volume each frame. */
1931
+ get volume(): number;
1932
+ set volume(val: number);
1765
1933
  private _audioLoader;
1766
1934
  private getAudioFilePath;
1767
1935
  onAllowAudioChanged(allow: boolean): void;
@@ -1811,69 +1979,6 @@ export declare class Avatar extends Component {
1811
1979
  private loadAvatarObjects;
1812
1980
  }
1813
1981
 
1814
- /* Excluded from this release type: Avatar_Brain_LookAt */
1815
-
1816
- /* Excluded from this release type: Avatar_MouthShapes */
1817
-
1818
- /* Excluded from this release type: Avatar_MustacheShake */
1819
-
1820
- /* Excluded from this release type: Avatar_POI */
1821
-
1822
- /* Excluded from this release type: AvatarBlink_Simple */
1823
-
1824
- /* Excluded from this release type: AvatarEyeLook_Rotation */
1825
-
1826
- /**
1827
- * Handles loading and instantiating avatar models from various sources.
1828
- * Provides functionality to find and extract important parts of an avatar (head, hands).
1829
- *
1830
- * Debug mode can be enabled with the URL parameter `?debugavatar`,
1831
- * which will log detailed information about avatar loading and configuration.
1832
- */
1833
- export declare class AvatarLoader {
1834
- private readonly avatarRegistryUrl;
1835
- /**
1836
- * Retrieves or creates a new avatar instance from an ID or existing Object3D.
1837
- * @param context The application context
1838
- * @param avatarId Either a string ID to load an avatar or an existing Object3D to use as avatar
1839
- * @returns Promise resolving to an AvatarModel if successful, or null if failed
1840
- */
1841
- getOrCreateNewAvatarInstance(context: Context, avatarId: string | Object3D): Promise<AvatarModel | null>;
1842
- /**
1843
- * Loads an avatar model from a file or registry using the provided ID.
1844
- * @param context The engine context
1845
- * @param avatarId The ID of the avatar to load
1846
- * @returns Promise resolving to the loaded avatar's Object3D, or null if failed
1847
- */
1848
- private loadAvatar;
1849
- /**
1850
- * Caches an avatar model for reuse.
1851
- * @param _id The ID to associate with the model
1852
- * @param _model The avatar model to cache
1853
- */
1854
- private cacheModel;
1855
- /**
1856
- * Analyzes an Object3D to find avatar parts (head, hands) based on naming conventions.
1857
- * @param obj The Object3D to search for avatar parts
1858
- * @returns A structured AvatarModel with references to found parts
1859
- */
1860
- private findAvatar;
1861
- /**
1862
- * Recursively searches for an avatar part by name within an Object3D hierarchy.
1863
- * @param obj The Object3D to search within
1864
- * @param searchString Array of strings that should all be present in the object name
1865
- * @returns The found Object3D part or null if not found
1866
- */
1867
- private findAvatarPart;
1868
- /**
1869
- * Handles HTTP response errors from avatar loading operations.
1870
- * @param response The fetch API response to check
1871
- * @returns The response if it was ok
1872
- * @throws Error with status text if response was not ok
1873
- */
1874
- private handleCustomAvatarErrors;
1875
- }
1876
-
1877
1982
  /**
1878
1983
  * Marks a GameObject as being controlled or owned by a player in networked XR sessions.
1879
1984
  * This is used internally by the networking system to identify player-controlled objects.
@@ -1934,35 +2039,6 @@ declare type AvatarMarkerEventArgs = {
1934
2039
  gameObject: Object3D;
1935
2040
  };
1936
2041
 
1937
- /**
1938
- * Represents an avatar model with head and hands references.
1939
- * Used for representing characters in 3D space.
1940
- */
1941
- export declare class AvatarModel {
1942
- /** The root object of the avatar model */
1943
- root: Object3D;
1944
- /** The head object of the avatar model */
1945
- head: Object3D;
1946
- /** The left hand object of the avatar model, if available */
1947
- leftHand: Object3D | null;
1948
- /** The right hand object of the avatar model, if available */
1949
- rigthHand: Object3D | null;
1950
- /**
1951
- * Checks if the avatar model has a valid configuration.
1952
- * An avatar is considered valid if it has a head.
1953
- * @returns Whether the avatar has a valid setup
1954
- */
1955
- get isValid(): boolean;
1956
- /**
1957
- * Creates a new avatar model.
1958
- * @param root The root object of the avatar
1959
- * @param head The head object of the avatar
1960
- * @param leftHand The left hand object of the avatar
1961
- * @param rigthHand The right hand object of the avatar
1962
- */
1963
- constructor(root: Object3D, head: Object3D, leftHand: Object3D | null, rigthHand: Object3D | null);
1964
- }
1965
-
1966
2042
  export declare enum Axes {
1967
2043
  None = 0,
1968
2044
  X = 2,
@@ -2326,7 +2402,6 @@ export declare class BoxCollider extends Collider implements IBoxCollider {
2326
2402
  center: Vector3;
2327
2403
  /* Excluded from this release type: onEnable */
2328
2404
  /* Excluded from this release type: onDisable */
2329
- /* Excluded from this release type: onValidate */
2330
2405
  /**
2331
2406
  * Automatically fits the collider to the geometry of the object.
2332
2407
  * Sets the size and center based on the object's bounding box.
@@ -2600,6 +2675,7 @@ declare class CallHandle extends EventDispatcher<any> {
2600
2675
  * CallInfo represents a single callback method that can be invoked by the {@link EventList}.
2601
2676
  */
2602
2677
  export declare class CallInfo {
2678
+ $serializedTypes: Record<string, any>;
2603
2679
  /**
2604
2680
  * When the CallInfo is enabled it will be invoked when the EventList is invoked
2605
2681
  */
@@ -2946,7 +3022,7 @@ export declare class Canvas extends UIRootComponent implements ICanvas {
2946
3022
  private _receivers;
2947
3023
  registerEventReceiver(receiver: ICanvasEventReceiver): void;
2948
3024
  unregisterEventReceiver(receiver: ICanvasEventReceiver): void;
2949
- onEnterXR(args: NeedleXREventArgs): Promise<void>;
3025
+ onEnterXR(args: NeedleXREventArgs): void;
2950
3026
  onLeaveXR(args: NeedleXREventArgs): void;
2951
3027
  onBeforeRenderRoutine: () => void;
2952
3028
  onAfterRenderRoutine: () => void;
@@ -3522,6 +3598,22 @@ export declare abstract class Collider extends Component implements ICollider {
3522
3598
  * The layers that this collider will interact with. Used for filtering collision detection.
3523
3599
  */
3524
3600
  filter?: number[];
3601
+ /**
3602
+ * The density of the collider, used for automatic mass calculation when the attached {@link Rigidbody} has `autoMass` enabled.
3603
+ * Rapier computes mass from density using the real-world formula: `mass = density × volume`.
3604
+ * The volume is derived from the collider shape (sphere, box, capsule, or convex hull).
3605
+ *
3606
+ * Reference values (relative to water = 1.0):
3607
+ * - Wood: 0.5–0.9
3608
+ * - Water: 1.0 (engine default)
3609
+ * - Rubber: 1.2
3610
+ * - Steel: 7.8
3611
+ *
3612
+ * @default undefined — uses the physics engine default of 1.0
3613
+ */
3614
+ density?: number;
3615
+ /* Excluded from this release type: _propertiesDirty */
3616
+ /* Excluded from this release type: onValidate */
3525
3617
  /* Excluded from this release type: awake */
3526
3618
  /* Excluded from this release type: start */
3527
3619
  /* Excluded from this release type: onEnable */
@@ -3623,7 +3715,7 @@ declare class ColorSerializer extends TypeSerializer {
3623
3715
  onSerialize(data: any): any | void;
3624
3716
  }
3625
3717
 
3626
- export declare const colorSerializer: ColorSerializer;
3718
+ export declare let colorSerializer: ColorSerializer;
3627
3719
 
3628
3720
  /**
3629
3721
  * Utility method to check if two materials were created from the same glTF material
@@ -3644,7 +3736,7 @@ export declare function compareAssociation<T extends Material>(obj1: T, obj2: T)
3644
3736
  * **Input event methods:**
3645
3737
  * {@link onPointerDown}, {@link onPointerUp}, {@link onPointerEnter}, {@link onPointerExit} and {@link onPointerMove}.
3646
3738
  *
3647
- * @example
3739
+ * @example Basic component
3648
3740
  * ```typescript
3649
3741
  * import { Behaviour } from "@needle-tools/engine";
3650
3742
  * export class MyComponent extends Behaviour {
@@ -3657,6 +3749,25 @@ export declare function compareAssociation<T extends Material>(obj1: T, obj2: T)
3657
3749
  * }
3658
3750
  * ```
3659
3751
  *
3752
+ * @example Automatic cleanup with autoCleanup
3753
+ * ```typescript
3754
+ * import { Behaviour, serializable, EventList } from "@needle-tools/engine";
3755
+ * export class ScoreTracker extends Behaviour {
3756
+ * @serializable(EventList)
3757
+ * onScoreChanged?: EventList<number>;
3758
+ *
3759
+ * start() {
3760
+ * // Registered during start → survives enable/disable, cleaned up on destroy
3761
+ * this.autoCleanup(this.onScoreChanged?.on(score => console.log("Score:", score)));
3762
+ * }
3763
+ *
3764
+ * onEnable() {
3765
+ * // Registered during onEnable → cleaned up on disable
3766
+ * this.autoCleanup(() => this.cleanupResources());
3767
+ * }
3768
+ * }
3769
+ * ```
3770
+ *
3660
3771
  * @group Components
3661
3772
  */
3662
3773
  declare abstract class Component implements IComponent, EventTarget, Partial<INeedleXRSessionEventReceiver>, Partial<IPointerEventHandler> {
@@ -3707,6 +3818,50 @@ declare abstract class Component implements IComponent, EventTarget, Partial<INe
3707
3818
  * @returns True if the component is enabled and all parent GameObjects are active
3708
3819
  */
3709
3820
  get activeAndEnabled(): boolean;
3821
+ private __disableCleanups?;
3822
+ private __destroyCleanups?;
3823
+ /**
3824
+ * @experimental
3825
+ * Register a resource for automatic cleanup tied to this component's lifecycle.
3826
+ * Accepts {@link IDisposable} objects, cleanup functions, or event unsubscribe functions.
3827
+ * `null` and `undefined` are safe no-ops (convenient for conditional subscriptions).
3828
+ *
3829
+ * **Lifecycle-aware:** The cleanup store is chosen automatically based on when `autoCleanup` is called:
3830
+ * - Called during {@link onEnable} → cleaned up on {@link onDisable} (and re-registered on re-enable)
3831
+ * - Called during {@link awake} or {@link start} → cleaned up on {@link onDestroy} (survives enable/disable cycles)
3832
+ * - Called at any other time (e.g. from update) → cleaned up on {@link onDisable}
3833
+ *
3834
+ * @param disposable An {@link IDisposable}, a cleanup/unsubscribe function, or `null`/`undefined`
3835
+ *
3836
+ * @example EventList subscriptions
3837
+ * ```ts
3838
+ * import { Behaviour, serializable, EventList } from "@needle-tools/engine";
3839
+ *
3840
+ * export class MyComponent extends Behaviour {
3841
+ * @serializable(EventList)
3842
+ * onScoreChanged?: EventList<number>;
3843
+ *
3844
+ * onEnable() {
3845
+ * this.autoCleanup(this.onScoreChanged?.on(score => {
3846
+ * console.log("Score:", score);
3847
+ * }));
3848
+ * }
3849
+ * }
3850
+ * ```
3851
+ *
3852
+ * @example Lifetime subscriptions in awake
3853
+ * ```ts
3854
+ * import { Behaviour } from "@needle-tools/engine";
3855
+ *
3856
+ * export class Persistent extends Behaviour {
3857
+ * awake() {
3858
+ * // Registered during awake → survives enable/disable, cleaned up on destroy
3859
+ * this.autoCleanup(() => this.save());
3860
+ * }
3861
+ * }
3862
+ * ```
3863
+ */
3864
+ protected autoCleanup(disposable: IDisposable | DisposeFn | Function | null | undefined): void;
3710
3865
  private get __isActive();
3711
3866
  private get __isActiveInHierarchy();
3712
3867
  private set __isActiveInHierarchy(value);
@@ -3725,11 +3880,6 @@ declare abstract class Component implements IComponent, EventTarget, Partial<INe
3725
3880
  * For example, URL to the glTF file this component was loaded from
3726
3881
  */
3727
3882
  sourceId?: SourceIdentifier;
3728
- /**
3729
- * Called when this component needs to remap guids after an instantiate operation.
3730
- * @param guidsMap Mapping from old guids to newly generated guids
3731
- */
3732
- resolveGuids?(guidsMap: GuidsMap): void;
3733
3883
  /**
3734
3884
  * Called once when the component becomes active for the first time.
3735
3885
  * This is the first lifecycle callback to be invoked
@@ -3942,6 +4092,10 @@ declare abstract class Component implements IComponent, EventTarget, Partial<INe
3942
4092
  destroy(): void;
3943
4093
  /* Excluded from this release type: __didAwake */
3944
4094
  /* Excluded from this release type: __didStart */
4095
+ /** True while start() has finished executing (used by autoCleanup to distinguish start from update) */
4096
+ private __didCompleteStart;
4097
+ /** True while onEnable() is executing (used by autoCleanup to route to disable store) */
4098
+ private __inEnableOrDisableCallback;
3945
4099
  /* Excluded from this release type: __didEnable */
3946
4100
  /* Excluded from this release type: __isEnabled */
3947
4101
  /* Excluded from this release type: __destroyed */
@@ -4097,7 +4251,7 @@ declare class ComponentSerializer extends TypeSerializer {
4097
4251
  findObjectForGuid(guid: string, root: Object3D): any;
4098
4252
  }
4099
4253
 
4100
- export declare const componentSerializer: ComponentSerializer;
4254
+ export declare let componentSerializer: ComponentSerializer;
4101
4255
 
4102
4256
  declare type ComponentType = "button" | "thumbstick" | "squeeze" | "touchpad";
4103
4257
 
@@ -4806,6 +4960,20 @@ export declare type ControlClipModel = {
4806
4960
  updateDirector: boolean;
4807
4961
  };
4808
4962
 
4963
+ /**
4964
+ * Options for a control clip in the timeline builder
4965
+ */
4966
+ export declare type ControlClipOptions = {
4967
+ /** Start time of the clip in seconds. If omitted, placed after the previous clip on this track. */
4968
+ start?: number;
4969
+ /** Duration of the clip in seconds (required) */
4970
+ duration: number;
4971
+ /** Whether to control the activation of the source object (default: true) */
4972
+ controlActivation?: boolean;
4973
+ /** Whether to update a nested PlayableDirector on the source object (default: true) */
4974
+ updateDirector?: boolean;
4975
+ };
4976
+
4809
4977
  /** true when selectstart was ever received.
4810
4978
  * On VisionOS 1.1 we always have select events (as per the spec), so this is always true
4811
4979
  */
@@ -5136,7 +5304,7 @@ export declare function decompressGpuTexture(texture: any, maxTextureSize?: numb
5136
5304
  * return true;
5137
5305
  * });
5138
5306
  * */
5139
- export declare function deepClone(obj: any, predicate?: deepClonePredicate): any;
5307
+ export declare function deepClone(obj: any, predicate?: deepClonePredicate, _visited?: WeakSet<object>): any;
5140
5308
 
5141
5309
  declare type deepClonePredicate = (owner: any, propertyName: string, current: any) => boolean;
5142
5310
 
@@ -5364,7 +5532,7 @@ export declare namespace DeviceUtilities {
5364
5532
  * Controls how the {@link PlayableDirector} behaves when playback reaches the end.
5365
5533
  * @see {@link PlayableDirector.extrapolationMode}
5366
5534
  */
5367
- declare enum DirectorWrapMode {
5535
+ export declare enum DirectorWrapMode {
5368
5536
  /** Hold the last frame when playback reaches the end of the timeline. */
5369
5537
  Hold = 0,
5370
5538
  /** Loop back to the start and continue playing indefinitely. */
@@ -5373,6 +5541,101 @@ declare enum DirectorWrapMode {
5373
5541
  None = 2
5374
5542
  }
5375
5543
 
5544
+ /**
5545
+ * A store for managing disposable resources (event subscriptions, listeners, callbacks)
5546
+ * that should be cleaned up together.
5547
+ *
5548
+ * DisposableStore collects disposables and disposes them all at once when
5549
+ * {@link dispose} is called. After disposal, the store can be reused — new items
5550
+ * can be added and a subsequent {@link dispose} call will clean those up.
5551
+ *
5552
+ * This is the same pattern used internally by VSCode for lifecycle-bound resource management.
5553
+ *
5554
+ * @example Basic usage
5555
+ * ```ts
5556
+ * import { DisposableStore, on } from "@needle-tools/engine";
5557
+ *
5558
+ * const store = new DisposableStore();
5559
+ *
5560
+ * // Register a DOM event listener (typed!)
5561
+ * store.add(on(window, "resize", (ev) => console.log(ev)));
5562
+ *
5563
+ * // Register the return value of EventList.on()
5564
+ * store.add(myEventList.on(data => console.log(data)));
5565
+ *
5566
+ * // Register a raw cleanup function
5567
+ * store.add(() => someSDK.off("event", handler));
5568
+ *
5569
+ * // Later: dispose everything at once
5570
+ * store.dispose();
5571
+ * ```
5572
+ *
5573
+ * @example Use with Needle Engine components
5574
+ * ```ts
5575
+ * import { Behaviour, serializable, EventList, on } from "@needle-tools/engine";
5576
+ *
5577
+ * export class MyComponent extends Behaviour {
5578
+ * @serializable(EventList)
5579
+ * onClick?: EventList;
5580
+ *
5581
+ * onEnable() {
5582
+ * // DOM events — fully typed
5583
+ * this.autoCleanup(on(window, "resize", (ev) => this.onResize(ev)));
5584
+ *
5585
+ * // EventList — .on() returns a function, autoCleanup accepts it
5586
+ * this.autoCleanup(this.onClick?.on(() => console.log("clicked!")));
5587
+ * }
5588
+ * // No onDisable needed — cleaned up automatically!
5589
+ * }
5590
+ * ```
5591
+ *
5592
+ * @category Utilities
5593
+ * @group Lifecycle
5594
+ */
5595
+ export declare class DisposableStore implements IDisposable {
5596
+ private _disposables;
5597
+ /** The number of registered disposables */
5598
+ get size(): number;
5599
+ /**
5600
+ * Register a disposable resource. Accepts:
5601
+ * - An {@link IDisposable} object (has a `dispose()` method) — e.g. from {@link on}
5602
+ * - A cleanup function (e.g. return value of `EventList.on()`)
5603
+ * - `null` or `undefined` (safe no-op for conditional subscriptions)
5604
+ *
5605
+ * When {@link dispose} is called, all registered resources are cleaned up.
5606
+ *
5607
+ * @param disposable The resource to register for disposal
5608
+ *
5609
+ * @example
5610
+ * ```ts
5611
+ * const store = new DisposableStore();
5612
+ *
5613
+ * // IDisposable object from on()
5614
+ * store.add(on(window, "resize", handler));
5615
+ *
5616
+ * // Function returned by EventList.on()
5617
+ * store.add(myEvent.on(handler));
5618
+ *
5619
+ * // Raw cleanup function
5620
+ * store.add(() => connection.close());
5621
+ *
5622
+ * // Conditional — safe with undefined
5623
+ * store.add(this.maybeEvent?.on(handler));
5624
+ * ```
5625
+ */
5626
+ add(disposable: IDisposable | DisposeFn | Function | null | undefined): void;
5627
+ /**
5628
+ * Dispose all registered resources. Each registered disposable is cleaned up,
5629
+ * then the internal list is cleared. The store can be reused after disposal.
5630
+ *
5631
+ * Called automatically by the engine when a component's `onDisable` lifecycle fires.
5632
+ */
5633
+ dispose(): void;
5634
+ }
5635
+
5636
+ /** A function that performs cleanup when called */
5637
+ export declare type DisposeFn = () => void;
5638
+
5376
5639
  /** Recursive disposes all referenced resources by this object. Does not traverse children */
5377
5640
  export declare function disposeObjectResources(obj: object | null | undefined): void;
5378
5641
 
@@ -5480,6 +5743,12 @@ export declare class DragControls extends Component implements IPointerEventHand
5480
5743
  * providing visual feedback about the object's position relative to surfaces below it.
5481
5744
  */
5482
5745
  showGizmo: boolean;
5746
+ /** Invoked once when a drag begins (after the minimum drag distance threshold is met). */
5747
+ dragStarted: EventList;
5748
+ /** Invoked every frame while the object is being dragged. */
5749
+ dragUpdated: EventList;
5750
+ /** Invoked once when the last pointer is released and the drag ends. */
5751
+ dragEnded: EventList;
5483
5752
  /**
5484
5753
  * Returns the object currently being dragged by this DragControls component, if any.
5485
5754
  * @returns The object being dragged or null if no object is currently dragged
@@ -5920,19 +6189,6 @@ export declare class EnvironmentScene extends Scene {
5920
6189
  createAreaLightMaterial(intensity: number): MeshBasicMaterial;
5921
6190
  }
5922
6191
 
5923
- export declare const euler: EulerSerializer;
5924
-
5925
- declare class EulerSerializer extends TypeSerializer {
5926
- constructor();
5927
- onDeserialize(data: any, _context: SerializationContext): Euler | undefined;
5928
- onSerialize(data: any, _context: SerializationContext): {
5929
- x: any;
5930
- y: any;
5931
- z: any;
5932
- order: any;
5933
- };
5934
- }
5935
-
5936
6192
  /**
5937
6193
  * EventList manages a list of callbacks that can be invoked together.
5938
6194
  * Used for Unity-style events that can be configured in the editor (Unity or Blender).
@@ -5979,13 +6235,9 @@ declare class EulerSerializer extends TypeSerializer {
5979
6235
  * @see {@link Button} for UI button events
5980
6236
  */
5981
6237
  export declare class EventList<TArgs extends any = any> implements IEventList {
6238
+ $serializedTypes: Record<string, any>;
5982
6239
  /** checked during instantiate to create a new instance */
5983
6240
  readonly isEventList = true;
5984
- /* Excluded from this release type: __internalOnInstantiate */
5985
- private target?;
5986
- private key?;
5987
- /** set an event target to try invoke the EventTarget dispatchEvent when this EventList is invoked */
5988
- setEventTarget(key: string, target: object): void;
5989
6241
  /** How many callback methods are subscribed to this event */
5990
6242
  get listenerCount(): number;
5991
6243
  /** If the event is currently being invoked */
@@ -6018,13 +6270,41 @@ export declare class EventList<TArgs extends any = any> implements IEventList {
6018
6270
  invoke(...args: Array<TArgs>): boolean;
6019
6271
  /** Add a new event listener to this event
6020
6272
  * @returns a function to remove the event listener
6273
+ * @see {@link removeEventListener} for more details and return value information
6274
+ * @see {@link off} for an alias with better readability when unsubscribing from events
6275
+ * @example
6276
+ * ```ts
6277
+ * const off = myEvent.addEventListener(args => console.log("Clicked!", args));
6278
+ * // later
6279
+ * off();
6280
+ * ```
6021
6281
  */
6022
6282
  addEventListener(callback: (args: TArgs) => void): Function;
6283
+ /**
6284
+ * Alias for addEventListener for better readability when subscribing to events. You can use it like this:
6285
+ * ```ts
6286
+ * myEvent.on(args => console.log("Clicked!", args));
6287
+ * ```
6288
+ * @returns a function to remove the event listener
6289
+ * @see {@link addEventListener} for more details and return value information
6290
+ */
6291
+ on(callback: (args: TArgs) => void): Function;
6023
6292
  /**
6024
6293
  * Remove an event listener from this event.
6025
6294
  * @returns true if the event listener was found and removed, false otherwise
6026
6295
  */
6027
6296
  removeEventListener(fn: Function | null | undefined): boolean;
6297
+ /**
6298
+ * Alias for removeEventListener for better readability when unsubscribing from events. You can use it like this:
6299
+ * ```ts
6300
+ * const off = myEvent.on(args => console.log("Clicked!", args));
6301
+ * // later
6302
+ * off();
6303
+ * ```
6304
+ *
6305
+ * @see {@link removeEventListener} for more details and return value information
6306
+ */
6307
+ off(callback: Function | null | undefined): boolean;
6028
6308
  /**
6029
6309
  * Remove all event listeners from this event. Use with caution! This will remove all listeners!
6030
6310
  */
@@ -6055,6 +6335,7 @@ declare type EventListenerOptions_2 = {
6055
6335
  signal?: AbortSignal;
6056
6336
  };
6057
6337
 
6338
+ /** @deprecated No longer automatically dispatched. Use `eventList.on()` directly instead. */
6058
6339
  export declare class EventListEvent<TArgs extends any> extends Event {
6059
6340
  args?: TArgs;
6060
6341
  }
@@ -6065,7 +6346,7 @@ declare class EventListSerializer extends TypeSerializer {
6065
6346
  onDeserialize(data: EventListData, context: SerializationContext): EventList<any> | undefined | null;
6066
6347
  }
6067
6348
 
6068
- export declare const eventListSerializer: EventListSerializer;
6349
+ export declare let eventListSerializer: EventListSerializer;
6069
6350
 
6070
6351
  /**
6071
6352
  * [EventSystem](https://engine.needle.tools/docs/api/EventSystem) is responsible for managing and dispatching input events to UI components within the scene.
@@ -6508,7 +6789,7 @@ declare type FitParameters = {
6508
6789
  * @see {@link HingeJoint} for rotating connections
6509
6790
  */
6510
6791
  export declare class FixedJoint extends Joint {
6511
- protected createJoint(self: Rigidbody, other: Rigidbody): void;
6792
+ protected createJoint(self: Rigidbody, other: Rigidbody): any;
6512
6793
  }
6513
6794
 
6514
6795
  declare type FocusRect = DOMRect | Element | {
@@ -7759,7 +8040,7 @@ export declare class HingeJoint extends Joint {
7759
8040
  anchor?: Vector3;
7760
8041
  /** Axis of rotation for the hinge (e.g., Vector3(0,1,0) for vertical axis) */
7761
8042
  axis?: Vector3;
7762
- protected createJoint(self: Rigidbody, other: Rigidbody): void;
8043
+ protected createJoint(self: Rigidbody, other: Rigidbody): any;
7763
8044
  }
7764
8045
 
7765
8046
  declare type HitPointObject = Object3D & {
@@ -7982,7 +8263,7 @@ declare const HTMLElementBase: typeof HTMLElement;
7982
8263
 
7983
8264
  export declare type IAnimationComponent = Pick<IComponent, "gameObject"> & {
7984
8265
  isAnimationComponent: boolean;
7985
- addClip?(clip: AnimationClip): any;
8266
+ addClip?(clip: AnimationClip): void;
7986
8267
  };
7987
8268
 
7988
8269
  /* Excluded from this release type: IApplyPrototypeExtension */
@@ -8056,6 +8337,12 @@ export declare interface ICollider extends IComponent {
8056
8337
  * Default: undefined
8057
8338
  */
8058
8339
  filter?: number[];
8340
+ /** The density of the collider used for automatic mass calculation.
8341
+ * When the attached Rigidbody has `autoMass` enabled, the mass is computed as `density × volume`.
8342
+ * Note: Make sure to call updateProperties after having changed this property
8343
+ * Default: undefined (uses physics engine default of 1.0)
8344
+ */
8345
+ density?: number;
8059
8346
  }
8060
8347
 
8061
8348
  export declare type ICollisionContext = {
@@ -8082,7 +8369,6 @@ export declare interface IComponent extends IHasGuid {
8082
8369
  /* Excluded from this release type: __internalEnable */
8083
8370
  /* Excluded from this release type: __internalDisable */
8084
8371
  /* Excluded from this release type: __internalDestroy */
8085
- /* Excluded from this release type: resolveGuids */
8086
8372
  /** experimental, called when the script is registered for the first time, this is called even if the component is not enabled. */
8087
8373
  registering?(): any;
8088
8374
  awake(): any;
@@ -8119,6 +8405,24 @@ export declare interface IConnectionData {
8119
8405
 
8120
8406
  export declare type IContext = Context;
8121
8407
 
8408
+ /**
8409
+ * Interface for objects that hold resources and can be disposed.
8410
+ * Implement this interface on any object that needs deterministic cleanup.
8411
+ *
8412
+ * @example
8413
+ * ```ts
8414
+ * class MyResource implements IDisposable {
8415
+ * dispose() { /* release resources *\/ }
8416
+ * }
8417
+ * ```
8418
+ *
8419
+ * @category Utilities
8420
+ * @group Lifecycle
8421
+ */
8422
+ export declare interface IDisposable {
8423
+ dispose(): void;
8424
+ }
8425
+
8122
8426
  /** Implement to receive callbacks from {@type @needle-tools/editor-sync} package */
8123
8427
  declare interface IEditorModification {
8124
8428
  /**
@@ -8138,7 +8442,6 @@ export declare interface IEffectProvider {
8138
8442
 
8139
8443
  export declare interface IEventList {
8140
8444
  readonly isEventList: true;
8141
- __internalOnInstantiate(map: InstantiateContext): IEventList;
8142
8445
  }
8143
8446
 
8144
8447
  export declare interface IGameObject extends Object3D {
@@ -8431,13 +8734,45 @@ export declare interface INeedleXRSessionEventReceiver extends Pick<IComponent,
8431
8734
  export declare interface INetworkConnection {
8432
8735
  get isConnected(): boolean;
8433
8736
  get isInRoom(): boolean;
8434
- send(key: string, data: IModel | object | boolean | null | string | number, queue: SendQueue): unknown;
8737
+ send(key: string, data?: IModel | object | boolean | string | number, queue?: SendQueue): unknown;
8435
8738
  }
8436
8739
 
8437
8740
  export declare interface INetworkingWebsocketUrlProvider {
8438
8741
  getWebsocketUrl(): string | null;
8439
8742
  }
8440
8743
 
8744
+ /**
8745
+ * @experimental
8746
+ * Interface for a network transport layer used by {@link NetworkConnection}.
8747
+ * The default implementation wraps a websocket via `websocket-ts`.
8748
+ * Custom implementations can be injected into {@link NetworkConnection.connect}
8749
+ * for testing or alternative transports.
8750
+ *
8751
+ * **Lifecycle:** After creating a transport and passing it to `connect()`,
8752
+ * `NetworkConnection` sets the four event callbacks (`onOpen`, `onClose`,
8753
+ * `onError`, `onMessage`) and then calls {@link start}. The transport
8754
+ * should call `onOpen` when the connection is ready.
8755
+ */
8756
+ export declare interface INetworkTransport {
8757
+ /** Start the connection. Called by NetworkConnection after event callbacks are set.
8758
+ * May return a promise if setup is async (e.g. dynamic imports). */
8759
+ start(): void | Promise<void>;
8760
+ /** Send data (string for JSON messages, Uint8Array for binary) */
8761
+ send(data: string | Uint8Array): void;
8762
+ /** Close the transport */
8763
+ close(): void | Promise<void>;
8764
+ /** The URL this transport is connected to, if applicable */
8765
+ readonly url: string | undefined;
8766
+ /** Called when the transport connection opens */
8767
+ onOpen: (() => void) | null;
8768
+ /** Called when the transport connection closes */
8769
+ onClose: (() => void) | null;
8770
+ /** Called when an error occurs */
8771
+ onError: ((err: any) => void) | null;
8772
+ /** Called when a message is received. Data is either a string (JSON) or Blob (binary). */
8773
+ onMessage: ((data: string | Blob) => void) | null;
8774
+ }
8775
+
8441
8776
  export declare class InheritVelocityModule {
8442
8777
  enabled: boolean;
8443
8778
  curve: MinMaxCurve;
@@ -8457,10 +8792,20 @@ export declare class InheritVelocityModule {
8457
8792
  applyCurrent(vel: Vector3 | Vector3_2, t01: number, lerpFactor: number): void;
8458
8793
  }
8459
8794
 
8795
+ /* Excluded from this release type: initAddressableSerializers */
8796
+
8797
+ /** Register all builtin serializers and prototype patches.
8798
+ * Must be called from {@link initEngine} so the registrations survive tree-shaking
8799
+ * when the package declares `sideEffects: false`.
8800
+ */
8801
+ export declare function initBuiltinSerializers(): void;
8802
+
8460
8803
  /** Register the Rapier physics backend. Called from {@link initEngine}
8461
8804
  * to ensure it runs regardless of tree-shaking. */
8462
8805
  export declare function initPhysics(): void;
8463
8806
 
8807
+ /* Excluded from this release type: initVolumeParameterSerializer */
8808
+
8464
8809
  /**
8465
8810
  * Handles all input events including mouse, touch, keyboard, and XR controllers.
8466
8811
  * Access via `this.context.input` from any component.
@@ -8984,7 +9329,7 @@ export declare function instantiate(instance: AssetReference, opts?: IInstantiat
8984
9329
  export declare function instantiate(instance: IGameObject | Object3D, opts?: IInstantiateOptions | null): IGameObject;
8985
9330
 
8986
9331
  /**
8987
- * Provides access to the instantiated object and its clone
9332
+ * Provides access to the instantiated object map (used by EventList etc.)
8988
9333
  */
8989
9334
  export declare type InstantiateContext = Readonly<InstantiateReferenceMap>;
8990
9335
 
@@ -9024,7 +9369,8 @@ export declare class InstantiateOptions implements IInstantiateOptions {
9024
9369
  cloneAssign(other: InstantiateOptions | IInstantiateOptions): void;
9025
9370
  }
9026
9371
 
9027
- declare type InstantiateReferenceMap = Record<string, ObjectCloneReference>;
9372
+ /** Maps uuid/guid { original, clone } for Object3D and Component instances */
9373
+ export declare type InstantiateReferenceMap = Record<string, ObjectCloneReference>;
9028
9374
 
9029
9375
  /**
9030
9376
  * An empty component that can be used to mark an object as interactable.
@@ -9095,8 +9441,10 @@ export declare interface IPhysicsEngine {
9095
9441
  postStep(): any;
9096
9442
  /** Indicates whether the physics engine is currently updating */
9097
9443
  get isUpdating(): boolean;
9098
- /** Clears all cached data (e.g., mesh data when creating scaled mesh colliders) */
9099
- clearCaches(): any;
9444
+ /** Tears down the physics world and frees all resources. The world will be re-created on next use. */
9445
+ dispose(): void;
9446
+ /** @deprecated Use {@link dispose} instead. */
9447
+ clearCaches(): void;
9100
9448
  /** Enables or disables the physics engine */
9101
9449
  enabled: boolean;
9102
9450
  /** Returns the underlying physics world object */
@@ -9326,8 +9674,9 @@ export declare interface IPhysicsEngine {
9326
9674
  * @returns The underlying physics body or null if not found
9327
9675
  */
9328
9676
  getBody(obj: ICollider | IRigidbody): null | any;
9329
- addFixedJoint(body1: IRigidbody, body2: IRigidbody): any;
9330
- addHingeJoint(body1: IRigidbody, body2: IRigidbody, anchor: Vec3, axis: Vec3): any;
9677
+ addFixedJoint(body1: IRigidbody, body2: IRigidbody): Promise<any> | any;
9678
+ addHingeJoint(body1: IRigidbody, body2: IRigidbody, anchor: Vec3, axis: Vec3): Promise<any> | any;
9679
+ removeJoint(joint: any): void;
9331
9680
  /** Enable to render collider shapes */
9332
9681
  debugRenderColliders: boolean;
9333
9682
  /** Enable to visualize raycasts in the scene with gizmos */
@@ -9548,6 +9897,18 @@ export declare function isDestroyed(go: Object3D): boolean;
9548
9897
  /** True when the application runs on a local url */
9549
9898
  export declare function isDevEnvironment(): boolean;
9550
9899
 
9900
+ /**
9901
+ * Type guard to check if an object implements {@link IDisposable}.
9902
+ *
9903
+ * @example
9904
+ * ```ts
9905
+ * if (isDisposable(obj)) {
9906
+ * obj.dispose(); // safe to call
9907
+ * }
9908
+ * ```
9909
+ */
9910
+ export declare function isDisposable(value: unknown): value is IDisposable;
9911
+
9551
9912
  export declare function isDisposed(obj: object): boolean;
9552
9913
 
9553
9914
  export declare interface ISerializable {
@@ -9582,6 +9943,10 @@ export declare function isHotReloadEnabled(): boolean;
9582
9943
  /**@returns true if the element is an needle engine icon element */
9583
9944
  export declare function isIconElement(element: Node): boolean;
9584
9945
 
9946
+ export declare interface ISignalReceiver {
9947
+ readonly isSignalReceiver: true;
9948
+ }
9949
+
9585
9950
  /** @deprecated use {@link DeviceUtilities.isiOS} instead */
9586
9951
  export declare function isiOS(): boolean;
9587
9952
 
@@ -9616,6 +9981,8 @@ export declare function isResourceTrackingEnabled(): boolean;
9616
9981
  /** @deprecated use {@link DeviceUtilities.isSafari} instead */
9617
9982
  export declare function isSafari(): boolean;
9618
9983
 
9984
+ export declare function isTrackModel(obj: unknown): obj is TrackModel;
9985
+
9619
9986
  export declare function isUsingInstancing(instance: Object3D): boolean;
9620
9987
 
9621
9988
  export declare interface ITime {
@@ -9740,7 +10107,9 @@ declare abstract class Joint extends Component {
9740
10107
  connectedBody?: Rigidbody;
9741
10108
  get rigidBody(): Rigidbody | null;
9742
10109
  private _rigidBody;
10110
+ private _jointHandle;
9743
10111
  onEnable(): void;
10112
+ onDisable(): void;
9744
10113
  private create;
9745
10114
  protected abstract createJoint(self: Rigidbody, other: Rigidbody): any;
9746
10115
  }
@@ -11002,6 +11371,7 @@ export declare type Model = (GLTF | FBX | OBJ | CustomModel);
11002
11371
 
11003
11372
  declare namespace Models {
11004
11373
  export {
11374
+ isTrackModel,
11005
11375
  TimelineAssetModel,
11006
11376
  TrackType,
11007
11377
  ClipExtrapolation,
@@ -11051,6 +11421,8 @@ export declare type MouseButtonName = "left" | "right" | "middle";
11051
11421
  * Safe to import at module level, including in SSR environments.
11052
11422
  * For pages with multiple `<needle-engine>` elements, use `ctx` directly instead.
11053
11423
  *
11424
+ * @experimental This API may change in future releases.
11425
+ *
11054
11426
  * @example
11055
11427
  * import { needle } from "@needle-tools/engine";
11056
11428
  * button.onclick = () => {
@@ -11207,11 +11579,17 @@ export declare interface NeedleEngineAttributes {
11207
11579
  'hash': string;
11208
11580
  /** Set to automatically add OrbitControls to the loaded scene. */
11209
11581
  'camera-controls': string;
11210
- /** Override the default draco decoder path location. */
11582
+ /** Override the default Draco decoder/decompressor path. Can be a URL or a local path to a directory containing the Draco decoder files.
11583
+ * @default "https://www.gstatic.com/draco/versioned/decoders/1.5.7/"
11584
+ * @example <needle-engine dracoDecoderPath="./decoders/draco/"></needle-engine>
11585
+ */
11211
11586
  'dracoDecoderPath': string;
11212
- /** Override the default draco library type. */
11587
+ /** Override the default Draco decoder type. */
11213
11588
  'dracoDecoderType': 'wasm' | 'js';
11214
- /** Override the default KTX2 transcoder/decoder path. */
11589
+ /** Override the default KTX2 transcoder/decoder path. Can be a URL or a local path to a directory containing the KTX2 transcoder files.
11590
+ * @default "https://cdn.needle.tools/static/three/0.179.1/basis2/"
11591
+ * @example <needle-engine ktx2DecoderPath="./decoders/ktx2/"></needle-engine>
11592
+ */
11215
11593
  'ktx2DecoderPath': string;
11216
11594
  /** Prevent context from being disposed when element is removed from DOM. */
11217
11595
  'keep-alive': 'true' | 'false';
@@ -12165,8 +12543,7 @@ export declare class NeedleXRSession implements INeedleXRSession {
12165
12543
  get referenceSpace(): XRSpace | null;
12166
12544
  /** @returns the XRFrame `viewerpose` using the xr `referenceSpace` */
12167
12545
  get viewerPose(): XRViewerPose | undefined;
12168
- /** @returns `true` if any image is currently being tracked */
12169
- /** returns true if images are currently being tracked */
12546
+ /** @returns `true` if any image is currently being tracked or emulated */
12170
12547
  get isTrackingImages(): boolean;
12171
12548
  /** The currently active XR rig */
12172
12549
  get rig(): IXRRig | null;
@@ -12212,6 +12589,8 @@ export declare class NeedleXRSession implements INeedleXRSession {
12212
12589
  private readonly _xr_update_scripts;
12213
12590
  /** scripts that are in the scene but inactive (e.g. disabled parent gameObject) */
12214
12591
  private readonly _inactive_scripts;
12592
+ /** tracks scripts that have received onEnterXR — prevents spurious onLeaveXR calls */
12593
+ private readonly _scripts_in_xr;
12215
12594
  private readonly _controllerAdded;
12216
12595
  private readonly _controllerRemoved;
12217
12596
  private readonly _originalCameraWorldPosition?;
@@ -12599,7 +12978,7 @@ export declare class NetworkConnection implements INetworkConnection {
12599
12978
  /** Use to leave a room that you are currently connected to (use `leaveRoom()` to disconnect from the currently active room but you can also specify a room name) */
12600
12979
  leaveRoom(room?: string | null): boolean;
12601
12980
  /** Send a message to the networking backend - it will be broadcasted to all connected users (except yourself) in the same room by default */
12602
- send<K extends NetworkEventKey>(key: K, data?: (K extends keyof NetworkEventMap ? NetworkEventData<K> : WebsocketSendType) | null, queue?: SendQueue): void;
12981
+ send<K extends NetworkEventKey>(key: K, data?: (K extends keyof NetworkEventMap ? NetworkEventData<K> : WebsocketSendType), queue?: SendQueue): void;
12603
12982
  /**
12604
12983
  * Deletes the network state for a specific object on the server.
12605
12984
  * This removes the object's state from the room, preventing it from being sent to newly joining users.
@@ -12621,61 +13000,69 @@ export declare class NetworkConnection implements INetworkConnection {
12621
13000
  private _defaultMessagesBufferArray;
12622
13001
  sendBufferedMessagesNow(): void;
12623
13002
  /** Use to start listening to networking events.
12624
- * To unsubscribe from events use the `{@link stopListen}` method.
13003
+ * Returns an unsubscribe function that removes the listener when called.
13004
+ * The returned function can also be passed to {@link stopListen} or {@link Component.autoCleanup} for automatic lifecycle management.
12625
13005
  *
12626
- * @example Custom event example
13006
+ * @example With autoCleanup (recommended)
12627
13007
  * ```ts
12628
- * // Listen to a custom event sent by the server
12629
- * this.context.connection.beginListen<MyDataType>("my-custom-event", (data) => {
12630
- * console.log("Received custom event:", data);
12631
- * });
13008
+ * export class MyComponent extends Behaviour {
13009
+ * onEnable() {
13010
+ * this.autoCleanup(this.context.connection.beginListen("joined-room", () => {
13011
+ * console.log("I joined a networked room");
13012
+ * }));
13013
+ * }
13014
+ * // Automatically unsubscribed on disable — no manual cleanup needed!
13015
+ * }
13016
+ * ```
13017
+ *
13018
+ * @example Manual unsubscribe
13019
+ * ```ts
13020
+ * const unsub = this.context.connection.beginListen("joined-room", () => { });
13021
+ * // Later:
13022
+ * unsub(); // removes the listener
12632
13023
  * ```
12633
13024
  *
12634
- * @example Listening to room events
13025
+ * @example With stopListen (legacy pattern, still supported)
12635
13026
  * ```ts
12636
- * // Make sure to unsubscribe from events when the component is disabled
12637
13027
  * export class MyComponent extends Behaviour {
12638
13028
  * onEnable() {
12639
- * this.connection.beginListen("joined-room", this.onJoinedRoom)
13029
+ * this.context.connection.beginListen("joined-room", this.onJoinedRoom);
12640
13030
  * }
12641
13031
  * onDisable() {
12642
- * this.connection.stopListen("joined-room", this.onJoinedRoom)
13032
+ * this.context.connection.stopListen("joined-room", this.onJoinedRoom);
12643
13033
  * }
12644
13034
  * onJoinedRoom = () => {
12645
- * console.log("I joined a networked room")
13035
+ * console.log("I joined a networked room");
12646
13036
  * }
12647
13037
  * }
12648
13038
  * ```
12649
13039
  * @link https://engine.needle.tools/docs/networking.html
12650
13040
  *
12651
13041
  */
12652
- beginListen<K extends NetworkEventKey>(key: K, callback: K extends keyof NetworkEventMap ? NetworkEventMap[K] : (...args: any[]) => void): K extends keyof NetworkEventMap ? NetworkEventMap[K] : (...args: any[]) => void;
13042
+ beginListen<K extends NetworkEventKey>(key: K, callback: K extends keyof NetworkEventMap ? NetworkEventMap[K] : (...args: any[]) => void): DisposeFn;
12653
13043
  /**@deprecated please use stopListen instead (2.65.2-pre) */
12654
13044
  stopListening<K extends NetworkEventKey>(key: K, callback: (K extends keyof NetworkEventMap ? NetworkEventMap[K] : (...args: any[]) => void) | null): void;
12655
- /** Use to stop listening to networking events
13045
+ /** Use to stop listening to networking events.
13046
+ * Accepts either the original callback or the unsubscribe function returned by {@link beginListen}.
12656
13047
  * To subscribe to events use the `{@link beginListen}` method.
12657
- * See the example below for typical usage:
12658
13048
  *
12659
- * ### Component Example
13049
+ * @example
12660
13050
  * ```ts
12661
- * // Make sure to unsubscribe from events when the component is disabled
12662
- * export class MyComponent extends Behaviour {
12663
- * onEnable() {
12664
- * this.connection.beginListen("joined-room", this.onJoinedRoom)
12665
- * }
12666
- * onDisable() {
12667
- * this.connection.stopListen("joined-room", this.onJoinedRoom)
12668
- * }
12669
- * onJoinedRoom = () => {
12670
- * console.log("I joined a networked room")
12671
- * }
12672
- * }
13051
+ * // Both patterns work:
13052
+ * this.context.connection.stopListen("joined-room", this.onJoinedRoom); // original callback
13053
+ * this.context.connection.stopListen("joined-room", unsub); // unsubscribe fn from beginListen
12673
13054
  * ```
12674
13055
  */
12675
- stopListen<K extends NetworkEventKey>(key: K, callback: (K extends keyof NetworkEventMap ? NetworkEventMap[K] : (...args: any[]) => void) | null): void;
12676
- /** Use to start listening to networking binary events */
12677
- beginListenBinary(identifier: string, callback: BinaryCallback): BinaryCallback;
12678
- /** Use to stop listening to networking binary events */
13056
+ private static _didLogStopListenHint;
13057
+ stopListen<K extends NetworkEventKey>(key: K, callback: (K extends keyof NetworkEventMap ? NetworkEventMap[K] : (...args: any[]) => void) | Function | null): void;
13058
+ /** Use to start listening to networking binary events.
13059
+ * Returns an unsubscribe function that removes the listener when called.
13060
+ * The returned function can also be passed to {@link stopListenBinary} or {@link Component.autoCleanup}.
13061
+ */
13062
+ beginListenBinary(identifier: string, callback: BinaryCallback): DisposeFn;
13063
+ /** Use to stop listening to networking binary events.
13064
+ * Accepts either the original callback or the unsubscribe function returned by {@link beginListenBinary}.
13065
+ */
12679
13066
  stopListenBinary(identifier: string, callback: any): void;
12680
13067
  private netWebSocketUrlProvider?;
12681
13068
  /** Use to override the networking server backend url.
@@ -12684,16 +13071,19 @@ export declare class NetworkConnection implements INetworkConnection {
12684
13071
  registerProvider(prov: INetworkingWebsocketUrlProvider): void;
12685
13072
  /** Used to connect to the networking server
12686
13073
  * @param url Optional url to connect to. If not provided, it will use the url from the registered `INetworkingWebsocketUrlProvider` or the default backend networking url. If you want to change the url after connecting, you need to disconnect first and then connect again with the new url.
13074
+ * @param transport Optional custom transport to use instead of the default websocket. Useful for testing or alternative transports.
12687
13075
  */
12688
- connect(url?: string): Promise<boolean>;
13076
+ connect(url?: string, transport?: INetworkTransport): Promise<boolean>;
12689
13077
  /** Disconnect from the networking backend + reset internal state */
12690
13078
  disconnect(): void;
13079
+ /** Full teardown: disconnect, clear all listeners, and release all resources.
13080
+ * Called when the owning Context is destroyed. After dispose(), this instance should not be reused. */
13081
+ dispose(): void;
12691
13082
  private _listeners;
12692
13083
  private _listenersBinary;
12693
13084
  private connected;
12694
- private channelId;
12695
13085
  private _connectionId;
12696
- private _ws;
13086
+ private _transport;
12697
13087
  private _waitingForSocket;
12698
13088
  private _isInRoom;
12699
13089
  private _currentRoomName;
@@ -12703,6 +13093,8 @@ export declare class NetworkConnection implements INetworkConnection {
12703
13093
  private _state;
12704
13094
  private _currentDelay;
12705
13095
  private _connectingToWebsocketPromise;
13096
+ /** Wire up a transport's event callbacks and start it */
13097
+ private connectTransport;
12706
13098
  private connectWebsocket;
12707
13099
  private onMessage;
12708
13100
  private handleIncomingBinaryMessage;
@@ -12831,7 +13223,7 @@ export declare interface NetworkEventMap {
12831
13223
  * @see {@link RoomEvents} for room lifecycle events
12832
13224
  * @see {@link isLocalNetwork} for local network detection
12833
13225
  * @link https://engine.needle.tools/docs/how-to-guides/networking/
12834
- * @summary Networking configuration
13226
+ * @summary Configures the websocket server URL for multiplayer networking
12835
13227
  * @category Networking
12836
13228
  * @group Components
12837
13229
  */
@@ -12968,7 +13360,7 @@ export declare type OBJ = {
12968
13360
  scenes: Object3D[];
12969
13361
  };
12970
13362
 
12971
- declare type ObjectCloneReference = {
13363
+ export declare type ObjectCloneReference = {
12972
13364
  readonly original: object;
12973
13365
  readonly clone: object;
12974
13366
  };
@@ -13052,7 +13444,7 @@ declare class ObjectSerializer extends TypeSerializer {
13052
13444
  onDeserialize(data: ObjectData | string | null, context: SerializationContext): Object3D<Object3DEventMap> | Component | null | undefined;
13053
13445
  }
13054
13446
 
13055
- export declare const objectSerializer: ObjectSerializer;
13447
+ export declare let objectSerializer: ObjectSerializer;
13056
13448
 
13057
13449
  declare type ObjectToNodeMap = {
13058
13450
  [uuid: string]: number;
@@ -13175,6 +13567,61 @@ export declare function offXRSessionEnd(fn: (evt: XRSessionEventArgs) => void):
13175
13567
  */
13176
13568
  export declare function offXRSessionStart(fn: (evt: XRSessionEventArgs) => void): void;
13177
13569
 
13570
+ /**
13571
+ * @experimental
13572
+ * Subscribe to a DOM event on any {@link EventTarget} (window, document, HTML elements, etc.)
13573
+ * and return an {@link IDisposable} that removes the listener when disposed.
13574
+ *
13575
+ * Provides full TypeScript event type inference — the callback parameter
13576
+ * is automatically typed based on the event name (e.g. `"resize"` → `UIEvent`,
13577
+ * `"click"` → `MouseEvent`).
13578
+ *
13579
+ * Use with {@link DisposableStore.add} for automatic lifecycle cleanup in components.
13580
+ *
13581
+ * @param target The EventTarget to listen on (window, document, an element, etc.)
13582
+ * @param type The event name (e.g. `"resize"`, `"click"`, `"keydown"`)
13583
+ * @param listener The event handler callback
13584
+ * @param options Optional addEventListener options (passive, capture, once, signal)
13585
+ * @returns An {@link IDisposable} that removes the event listener when disposed
13586
+ *
13587
+ * @example Standalone usage
13588
+ * ```ts
13589
+ * import { on } from "@needle-tools/engine";
13590
+ *
13591
+ * const sub = on(window, "resize", (ev) => {
13592
+ * // ev is typed as UIEvent
13593
+ * console.log("resized", ev.target);
13594
+ * });
13595
+ *
13596
+ * // Later: clean up
13597
+ * sub.dispose();
13598
+ * ```
13599
+ *
13600
+ * @example With autoCleanup in a component
13601
+ * ```ts
13602
+ * import { Behaviour, on } from "@needle-tools/engine";
13603
+ *
13604
+ * export class MyComponent extends Behaviour {
13605
+ * onEnable() {
13606
+ * this.autoCleanup(on(window, "resize", (ev) => { /* UIEvent *\/ }));
13607
+ * this.autoCleanup(on(document, "keydown", (ev) => { /* KeyboardEvent *\/ }));
13608
+ * this.autoCleanup(on(this.context.domElement, "click", (ev) => { /* MouseEvent *\/ }));
13609
+ * }
13610
+ * // All listeners removed automatically on disable!
13611
+ * }
13612
+ * ```
13613
+ *
13614
+ * @category Utilities
13615
+ * @group Lifecycle
13616
+ */
13617
+ export declare function on<K extends keyof WindowEventMap>(target: Window, type: K, listener: (ev: WindowEventMap[K]) => void, options?: boolean | AddEventListenerOptions): IDisposable;
13618
+
13619
+ export declare function on<K extends keyof DocumentEventMap>(target: Document, type: K, listener: (ev: DocumentEventMap[K]) => void, options?: boolean | AddEventListenerOptions): IDisposable;
13620
+
13621
+ export declare function on<K extends keyof HTMLElementEventMap>(target: HTMLElement, type: K, listener: (ev: HTMLElementEventMap[K]) => void, options?: boolean | AddEventListenerOptions): IDisposable;
13622
+
13623
+ export declare function on(target: EventTarget, type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): IDisposable;
13624
+
13178
13625
  /**
13179
13626
  * Register a callback in the engine onAfterRender event
13180
13627
  * This is called every frame after the main camera has rendered
@@ -14648,13 +15095,15 @@ export declare class OrbitControls extends Component implements ICameraControlle
14648
15095
  * The timeline asset containing tracks, clips, and markers that this director will play.
14649
15096
  * Assign a timeline asset exported from Unity or Blender to enable playback.
14650
15097
  */
14651
- playableAsset?: Models.TimelineAssetModel;
15098
+ get playableAsset(): Models.TimelineAssetModel | undefined;
15099
+ set playableAsset(value: Models.TimelineAssetModel | undefined);
15100
+ private _playableAsset?;
14652
15101
  /**
14653
15102
  * When true, the timeline starts playing automatically when the component awakens.
14654
15103
  * Set to false to control playback manually via `play()`.
14655
15104
  * @default false
14656
15105
  */
14657
- playOnAwake?: boolean;
15106
+ playOnAwake: boolean;
14658
15107
  /**
14659
15108
  * Determines how the timeline behaves when it reaches the end of its duration.
14660
15109
  * @default DirectorWrapMode.Loop
@@ -14749,6 +15198,14 @@ export declare class OrbitControls extends Component implements ICameraControlle
14749
15198
  * @returns all marker tracks of the timeline
14750
15199
  */
14751
15200
  get markerTracks(): Tracks.MarkerTrackHandler[];
15201
+ /**
15202
+ * @returns all activation tracks of the timeline
15203
+ */
15204
+ get activationTracks(): Tracks.ActivationTrackHandler[];
15205
+ /**
15206
+ * @returns all tracks of the timeline
15207
+ */
15208
+ get tracks(): ReadonlyArray<Tracks.TrackHandler>;
14752
15209
  /**
14753
15210
  * Iterates over all markers of the timeline, optionally filtering by type
14754
15211
  *
@@ -14762,13 +15219,13 @@ export declare class OrbitControls extends Component implements ICameraControlle
14762
15219
  *
14763
15220
  */
14764
15221
  foreachMarker<T extends Record<string, any>>(type?: string | null): Generator<(T & Models.MarkerModel)>;
14765
- private _guidsMap?;
14766
- /* Excluded from this release type: resolveGuids */
15222
+ private _needsGraphRebuild;
14767
15223
  private _isPlaying;
14768
15224
  private _internalUpdateRoutine;
14769
15225
  private _isPaused;
14770
15226
  /** internal, true during the time stop() is being processed */
14771
15227
  private _isStopping;
15228
+ /* Excluded from this release type: _isUserEvaluation */
14772
15229
  private _time;
14773
15230
  private _duration;
14774
15231
  private _weight;
@@ -14777,6 +15234,7 @@ export declare class OrbitControls extends Component implements ICameraControlle
14777
15234
  private readonly _signalTracks;
14778
15235
  private readonly _markerTracks;
14779
15236
  private readonly _controlTracks;
15237
+ private readonly _activationTracks;
14780
15238
  private readonly _customTracks;
14781
15239
  private readonly _tracksArray;
14782
15240
  private get _allTracks();
@@ -15955,6 +16413,10 @@ export declare class OrbitControls extends Component implements ICameraControlle
15955
16413
  private _gravity;
15956
16414
  get gravity(): Vec3;
15957
16415
  set gravity(value: Vec3);
16416
+ /** Tears down the physics world and frees all WASM resources.
16417
+ * After calling this, the world will be re-created on next use. */
16418
+ dispose(): void;
16419
+ /** @deprecated Use {@link dispose} instead. */
15958
16420
  clearCaches(): void;
15959
16421
  addBoxCollider(collider: ICollider, size: Vector3): Promise<void>;
15960
16422
  addSphereCollider(collider: ICollider): Promise<void>;
@@ -16001,7 +16463,8 @@ export declare class OrbitControls extends Component implements ICameraControlle
16001
16463
  private getRigidbodyRelativeMatrix;
16002
16464
  private static centerConnectionPos;
16003
16465
  private static centerConnectionRot;
16004
- addFixedJoint(body1: IRigidbody, body2: IRigidbody): void;
16466
+ private _jointTempMatrix;
16467
+ addFixedJoint(body1: IRigidbody, body2: IRigidbody): Promise<ImpulseJoint | null>;
16005
16468
  /** The joint prevents any relative movement between two rigid-bodies, except for relative rotations along one axis. This is typically used to simulate wheels, fans, etc. They are characterized by one local anchor as well as one local axis on each rigid-body. */
16006
16469
  addHingeJoint(body1: IRigidbody, body2: IRigidbody, anchor: {
16007
16470
  x: number;
@@ -16011,8 +16474,11 @@ export declare class OrbitControls extends Component implements ICameraControlle
16011
16474
  x: number;
16012
16475
  y: number;
16013
16476
  z: number;
16014
- }): void;
16477
+ }): Promise<ImpulseJoint | null>;
16478
+ removeJoint(joint: ImpulseJoint): void;
16479
+ /** Compute the relative transform from body1's local space to body2's local space (W2⁻¹ * W1), ignoring scale. */
16015
16480
  private calculateJointRelativeMatrices;
16481
+ private normalizeMatrixColumns;
16016
16482
  }
16017
16483
 
16018
16484
  /**
@@ -16815,10 +17281,17 @@ export declare class OrbitControls extends Component implements ICameraControlle
16815
17281
  */
16816
17282
  export declare class Rigidbody extends Component implements IRigidbody {
16817
17283
  get isRigidbody(): boolean;
16818
- /** When true the mass will be automatically calculated by the attached colliders */
17284
+ /** When true the mass is automatically computed from the attached colliders using `mass = density × volume`.
17285
+ * Each collider's {@link Collider.density} determines how heavy it contributes to the total mass.
17286
+ * Disable to set mass explicitly via the `mass` property.
17287
+ */
16819
17288
  autoMass: boolean;
16820
- /** By default the mass will be automatically calculated (see `autoMass`) by the physics engine using the collider sizes
16821
- * To set the mass manually you can either set the `mass` value or set `autoMass` to `false`
17289
+ /** The mass of the rigidbody in kg (when `autoMass` is disabled).
17290
+ * When `autoMass` is enabled, reading this returns the computed mass from `density × volume` of all attached colliders.
17291
+ * Setting this property automatically disables `autoMass`.
17292
+ *
17293
+ * **Prefer using {@link Collider.density}** with `autoMass` enabled instead — density scales
17294
+ * naturally with collider size, while explicit mass stays fixed regardless of shape changes.
16822
17295
  */
16823
17296
  set mass(value: number);
16824
17297
  get mass(): number;
@@ -16901,7 +17374,8 @@ export declare class OrbitControls extends Component implements ICameraControlle
16901
17374
  onEnable(): void;
16902
17375
  onDisable(): void;
16903
17376
  onDestroy(): void;
16904
- onValidate(): void;
17377
+ onValidate(property?: string): void;
17378
+ private static _didWarnAutoMass;
16905
17379
  beforePhysics(): Generator<undefined, void, unknown>;
16906
17380
  /** Teleport the rigidbody to a new position in the world.
16907
17381
  * Will reset forces before setting the object world position
@@ -18121,10 +18595,17 @@ export declare class OrbitControls extends Component implements ICameraControlle
18121
18595
 
18122
18596
  export declare function sendDestroyed(guid: string, con: INetworkConnection, opts?: SyncDestroyOptions): void;
18123
18597
 
18598
+ /** Controls when a network message is actually sent to the server.
18599
+ * @see {@link NetworkConnection.send}
18600
+ */
18124
18601
  export declare enum SendQueue {
18602
+ /** Hold the message until the transport connection opens, then send it. Use for messages that must arrive as soon as the socket is ready (e.g. join-room). */
18125
18603
  OnConnection = 0,
18604
+ /** Hold the message until the client has joined a room, then send it. Use for messages that require room context. */
18126
18605
  OnRoomJoin = 1,
18606
+ /** Buffer the message and send it on the next `sendBufferedMessagesNow()` call (typically once per frame). This is the default for `send()`. */
18127
18607
  Queued = 2,
18608
+ /** Send the message to the server immediately without buffering. */
18128
18609
  Immediate = 3
18129
18610
  }
18130
18611
 
@@ -18557,6 +19038,16 @@ export declare class OrbitControls extends Component implements ICameraControlle
18557
19038
  asset: string;
18558
19039
  }
18559
19040
 
19041
+ /**
19042
+ * Options for a signal marker in the timeline builder
19043
+ */
19044
+ export declare type SignalMarkerOptions = {
19045
+ /** Whether the signal should fire if the playback starts past its time (default: false) */
19046
+ retroActive?: boolean;
19047
+ /** Whether the signal should only fire once (default: false) */
19048
+ emitOnce?: boolean;
19049
+ };
19050
+
18560
19051
  /** SignalReceiver is a component that listens for signals and invokes a reaction when a signal is received.
18561
19052
  * Signals can be added to a signal track on a {@link PlayableDirector}
18562
19053
  *
@@ -18564,7 +19055,8 @@ export declare class OrbitControls extends Component implements ICameraControlle
18564
19055
  * @category Animation and Sequencing
18565
19056
  * @group Components
18566
19057
  */
18567
- export declare class SignalReceiver extends Component {
19058
+ export declare class SignalReceiver extends Component implements ISignalReceiver {
19059
+ readonly isSignalReceiver = true;
18568
19060
  private static receivers;
18569
19061
  static invoke(guid: string): void;
18570
19062
  events?: SignalReceiverEvent[];
@@ -18587,6 +19079,9 @@ export declare class OrbitControls extends Component implements ICameraControlle
18587
19079
  models: Models.SignalMarkerModel[];
18588
19080
  didTrigger: boolean[];
18589
19081
  receivers: Array<SignalReceiver | null>;
19082
+ private _lastTime;
19083
+ onEnable(): void;
19084
+ onMuteChanged(): void;
18590
19085
  evaluate(time: number): void;
18591
19086
  }
18592
19087
 
@@ -19086,10 +19581,6 @@ export declare class OrbitControls extends Component implements ICameraControlle
19086
19581
  * Removes scale change monitoring when the collider is disabled.
19087
19582
  */
19088
19583
  onDisable(): void;
19089
- /**
19090
- * Updates collider properties when validated in the editor or inspector.
19091
- */
19092
- onValidate(): void;
19093
19584
  }
19094
19585
 
19095
19586
  export declare class SphereIntersection implements Intersection {
@@ -20409,6 +20900,7 @@ export declare class OrbitControls extends Component implements ICameraControlle
20409
20900
  set font(val: string | null);
20410
20901
  get font(): string | null;
20411
20902
  private _font;
20903
+ private _assignedAtRuntime;
20412
20904
  /**
20413
20905
  * Whether to support basic rich text tags in the `text` property. Supported tags include `<b>`, `<i>`, and `<color=hex>`. For example: `Hello <b>World</b>` or `Score: <color=#ff0000>100</color>`
20414
20906
  * @default false
@@ -20673,6 +21165,166 @@ export declare class OrbitControls extends Component implements ICameraControlle
20673
21165
  tracks: TrackModel[];
20674
21166
  };
20675
21167
 
21168
+ /**
21169
+ * A fluent builder for creating timeline assets ({@link TimelineAssetModel}) from code.
21170
+ *
21171
+ * Use {@link TimelineBuilder.create} to start building a timeline.
21172
+ *
21173
+ * @example Using build() for timelines without signal callbacks
21174
+ * ```ts
21175
+ * const timeline = TimelineBuilder.create("MySequence")
21176
+ * .animationTrack("Character", animator)
21177
+ * .clip(walkClip, { duration: 2, easeIn: 0.3 })
21178
+ * .clip(runClip, { duration: 3, easeIn: 0.5, easeOut: 0.5 })
21179
+ * .activationTrack("FX", particleObject)
21180
+ * .clip({ start: 1, duration: 2 })
21181
+ * .audioTrack("Music", audioSource)
21182
+ * .clip("music.mp3", { start: 0, duration: 5, volume: 0.8 })
21183
+ * .build();
21184
+ *
21185
+ * director.playableAsset = timeline;
21186
+ * director.play();
21187
+ * ```
21188
+ *
21189
+ * @example Using install() with signal callbacks
21190
+ * ```ts
21191
+ * TimelineBuilder.create("WithSignals")
21192
+ * .animationTrack("Character", animator)
21193
+ * .clip(walkClip, { duration: 2 })
21194
+ * .signalTrack("Events")
21195
+ * .signal(1.0, () => console.log("1 second!"))
21196
+ * .signal(2.0, () => spawnParticles())
21197
+ * .install(director);
21198
+ *
21199
+ * director.play();
21200
+ * ```
21201
+ *
21202
+ * @category Animation and Sequencing
21203
+ * @group Utilities
21204
+ */
21205
+ export declare class TimelineBuilder {
21206
+ private _name;
21207
+ private _tracks;
21208
+ private _currentTrack;
21209
+ private _pendingSignals;
21210
+ private _idProvider;
21211
+ private constructor();
21212
+ /**
21213
+ * Creates a new TimelineBuilder instance.
21214
+ * @param name - Name for the timeline asset
21215
+ * @param seed - Optional numeric seed for deterministic guid generation. Defaults to `Date.now()`.
21216
+ */
21217
+ static create(name?: string, seed?: number): TimelineBuilder;
21218
+ /**
21219
+ * Adds an animation track. Subsequent `.clip()` calls add animation clips to this track.
21220
+ * @param name - Display name for the track
21221
+ * @param binding - The Animator or Object3D to animate
21222
+ */
21223
+ animationTrack(name: string, binding?: Animator | Object3D | null): this;
21224
+ /**
21225
+ * Adds an audio track. Subsequent `.clip()` calls add audio clips to this track.
21226
+ * @param name - Display name for the track
21227
+ * @param binding - The AudioSource to play audio on (optional)
21228
+ * @param volume - Track volume multiplier (default: 1)
21229
+ */
21230
+ audioTrack(name: string, binding?: AudioSource | Object3D | null, volume?: number): this;
21231
+ /**
21232
+ * Adds an activation track. Subsequent `.clip()` calls define when the bound object is active.
21233
+ * @param name - Display name for the track
21234
+ * @param binding - The Object3D to show/hide
21235
+ */
21236
+ activationTrack(name: string, binding?: Object3D | null): this;
21237
+ /**
21238
+ * Adds a control track. Subsequent `.clip()` calls control nested timelines or objects.
21239
+ * @param name - Display name for the track
21240
+ */
21241
+ controlTrack(name: string): this;
21242
+ /**
21243
+ * Adds a signal track. Use `.signal()` or `.marker()` to add signal markers.
21244
+ * @param name - Display name for the track
21245
+ * @param binding - The SignalReceiver component (optional — if using `.signal()` with callbacks, one is created automatically by {@link install})
21246
+ */
21247
+ signalTrack(name: string, binding?: SignalReceiver | Object3D | null): this;
21248
+ /**
21249
+ * Adds a marker track. Use `.marker()` to add markers.
21250
+ * @param name - Display name for the track
21251
+ */
21252
+ markerTrack(name: string): this;
21253
+ /**
21254
+ * Adds a clip to the current track. The clip type must match the track type.
21255
+ *
21256
+ * - On an **animation track**: pass an `AnimationClip` and optional {@link AnimationClipOptions}
21257
+ * - On an **audio track**: pass a clip URL (string) and {@link AudioClipOptions}
21258
+ * - On an **activation track**: pass {@link ActivationClipOptions}
21259
+ * - On a **control track**: pass an Object3D and {@link ControlClipOptions}
21260
+ */
21261
+ clip(asset: AnimationClip, options?: AnimationClipOptions): this;
21262
+ clip(url: string, options: AudioClipOptions): this;
21263
+ clip(options: ActivationClipOptions): this;
21264
+ clip(sourceObject: Object3D, options: ControlClipOptions): this;
21265
+ /**
21266
+ * Adds a signal marker to the current signal or marker track.
21267
+ * @param time - Time in seconds when the signal fires
21268
+ * @param asset - The signal asset identifier (guid string)
21269
+ * @param options - Optional marker configuration
21270
+ */
21271
+ marker(time: number, asset: string, options?: SignalMarkerOptions): this;
21272
+ /**
21273
+ * Adds a signal with a callback to the current signal track.
21274
+ * This is a convenience method that automatically generates a signal asset guid,
21275
+ * adds the marker, and registers the callback so that {@link install} can wire up
21276
+ * the `SignalReceiver` on the director's GameObject.
21277
+ *
21278
+ * @param time - Time in seconds when the signal fires
21279
+ * @param callback - The function to invoke when the signal fires
21280
+ * @param options - Optional marker configuration
21281
+ *
21282
+ * @example
21283
+ * ```ts
21284
+ * const timeline = TimelineBuilder.create("Sequence")
21285
+ * .signalTrack("Events")
21286
+ * .signal(1.0, () => console.log("1 second reached!"))
21287
+ * .signal(3.5, () => console.log("halfway!"), { emitOnce: true })
21288
+ * .install(director);
21289
+ * ```
21290
+ */
21291
+ signal(time: number, callback: Function, options?: SignalMarkerOptions): this;
21292
+ /**
21293
+ * Mutes the current track so it is skipped during playback.
21294
+ */
21295
+ muted(muted?: boolean): this;
21296
+ /**
21297
+ * Builds and returns the {@link TimelineAssetModel}.
21298
+ * Assign the result to `PlayableDirector.playableAsset` to play it.
21299
+ *
21300
+ * If you used `.signal()` with callbacks, use {@link install} instead — it calls `build()`
21301
+ * internally and also wires up the SignalReceiver on the director's GameObject.
21302
+ */
21303
+ build(): TimelineAssetModel;
21304
+ /**
21305
+ * Builds the timeline asset, assigns it to the director, and wires up any
21306
+ * `.signal()` callbacks by creating/configuring a {@link SignalReceiver} on the
21307
+ * director's GameObject.
21308
+ *
21309
+ * @param director - The PlayableDirector to install the timeline on
21310
+ * @returns The built TimelineAssetModel (also assigned to `director.playableAsset`)
21311
+ *
21312
+ * @example
21313
+ * ```ts
21314
+ * TimelineBuilder.create("MyTimeline")
21315
+ * .animationTrack("Anim", animator)
21316
+ * .clip(walkClip, { duration: 2 })
21317
+ * .signalTrack("Events")
21318
+ * .signal(1.0, () => console.log("signal fired!"))
21319
+ * .install(director);
21320
+ *
21321
+ * director.play();
21322
+ * ```
21323
+ */
21324
+ install(director: PlayableDirector): TimelineAssetModel;
21325
+ private pushTrack;
21326
+ }
21327
+
20676
21328
  declare type TonemappingAttributeOptions = "none" | "linear" | "neutral" | "agx";
20677
21329
 
20678
21330
  /**
@@ -20754,6 +21406,7 @@ export declare class OrbitControls extends Component implements ICameraControlle
20754
21406
  AudioTrackHandler,
20755
21407
  MarkerTrackHandler,
20756
21408
  SignalTrackHandler,
21409
+ ActivationTrackHandler,
20757
21410
  ControlTrackHandler
20758
21411
  }
20759
21412
  }
@@ -22477,7 +23130,7 @@ export declare class OrbitControls extends Component implements ICameraControlle
22477
23130
  private onApplyPose;
22478
23131
  }
22479
23132
 
22480
- declare type WebsocketSendType = IModel | object | boolean | null | string | number;
23133
+ declare type WebsocketSendType = IModel | object | boolean | string | number;
22481
23134
 
22482
23135
  /**
22483
23136
  * Use the [WebXR](https://engine.needle.tools/docs/api/WebXR) component to enable VR and AR on **iOS and Android** in your scene. VisionOS support is also provided via QuickLook USDZ export.
@@ -23520,6 +24173,28 @@ export declare class OrbitControls extends Component implements ICameraControlle
23520
24173
  export { }
23521
24174
 
23522
24175
 
24176
+ declare module 'three' {
24177
+ interface SkinnedMesh {
24178
+ staticGenerator?: StaticGeometryGenerator;
24179
+ staticGeometry?: BufferGeometry;
24180
+ staticGeometryLastUpdate?: number;
24181
+ }
24182
+ interface Mesh {
24183
+ acceleratedRaycast?: any;
24184
+ }
24185
+ interface SkinnedMesh {
24186
+ /** @deprecated use autoUpdateMeshBvhInterval */
24187
+ autoUpdateMeshBVH?: boolean;
24188
+ /**
24189
+ * Interval in milliseconds to automatically update the mesh BVH. When set to >= 0 the BVH will be updated every x milliseconds.
24190
+ * @default undefined (disabled)
24191
+ */
24192
+ autoUpdateMeshBvhInterval?: number;
24193
+ bvhNeedsUpdate?: boolean;
24194
+ }
24195
+ }
24196
+
24197
+
23523
24198
  declare module 'three' {
23524
24199
  interface Object3D {
23525
24200
  get guid(): string | undefined;
@@ -23665,25 +24340,3 @@ declare module 'three' {
23665
24340
  slerp(end: Vector3, t: number): Vector3;
23666
24341
  }
23667
24342
  }
23668
-
23669
-
23670
- declare module 'three' {
23671
- interface SkinnedMesh {
23672
- staticGenerator?: StaticGeometryGenerator;
23673
- staticGeometry?: BufferGeometry;
23674
- staticGeometryLastUpdate?: number;
23675
- }
23676
- interface Mesh {
23677
- acceleratedRaycast?: any;
23678
- }
23679
- interface SkinnedMesh {
23680
- /** @deprecated use autoUpdateMeshBvhInterval */
23681
- autoUpdateMeshBVH?: boolean;
23682
- /**
23683
- * Interval in milliseconds to automatically update the mesh BVH. When set to >= 0 the BVH will be updated every x milliseconds.
23684
- * @default undefined (disabled)
23685
- */
23686
- autoUpdateMeshBvhInterval?: number;
23687
- bvhNeedsUpdate?: boolean;
23688
- }
23689
- }