@needle-tools/engine 5.0.3 → 5.0.5

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 (81) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/components.needle.json +1 -1
  3. package/dist/{needle-engine.bundle-CNH61kLA.umd.cjs → needle-engine.bundle-CwycbG-K.umd.cjs} +139 -138
  4. package/dist/{needle-engine.bundle-BXk8jYW3.js → needle-engine.bundle-DLNQOFNZ.js} +7045 -6862
  5. package/dist/{needle-engine.bundle-Dvh1jROn.min.js → needle-engine.bundle-yYWZqy6w.min.js} +139 -138
  6. package/dist/needle-engine.d.ts +135 -30
  7. package/dist/needle-engine.js +511 -508
  8. package/dist/needle-engine.min.js +1 -1
  9. package/dist/needle-engine.umd.cjs +1 -1
  10. package/dist/{vendor-vHLk8sXu.js → vendor-CAcsI0eU.js} +116 -115
  11. package/dist/{vendor-CntUvmJu.umd.cjs → vendor-CEM38hLE.umd.cjs} +2 -2
  12. package/dist/{vendor-DPbfJJ4d.min.js → vendor-HRlxIBga.min.js} +2 -2
  13. package/lib/engine/api.d.ts +2 -0
  14. package/lib/engine/api.js +2 -0
  15. package/lib/engine/api.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_gameobject.js +2 -2
  26. package/lib/engine/engine_gameobject.js.map +1 -1
  27. package/lib/engine/engine_init.js +10 -0
  28. package/lib/engine/engine_init.js.map +1 -1
  29. package/lib/engine/engine_mainloop_utils.js +5 -2
  30. package/lib/engine/engine_mainloop_utils.js.map +1 -1
  31. package/lib/engine/engine_serialization_builtin_serializer.d.ts +10 -16
  32. package/lib/engine/engine_serialization_builtin_serializer.js +55 -41
  33. package/lib/engine/engine_serialization_builtin_serializer.js.map +1 -1
  34. package/lib/engine/webcomponents/needle-engine.d.ts +9 -3
  35. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  36. package/lib/engine/xr/NeedleXRSession.d.ts +3 -2
  37. package/lib/engine/xr/NeedleXRSession.js +50 -14
  38. package/lib/engine/xr/NeedleXRSession.js.map +1 -1
  39. package/lib/engine-components/Animation.js +17 -16
  40. package/lib/engine-components/Animation.js.map +1 -1
  41. package/lib/engine-components/AnimatorController.d.ts +2 -0
  42. package/lib/engine-components/AnimatorController.js +4 -1
  43. package/lib/engine-components/AnimatorController.js.map +1 -1
  44. package/lib/engine-components/AudioSource.d.ts +19 -3
  45. package/lib/engine-components/AudioSource.js +121 -68
  46. package/lib/engine-components/AudioSource.js.map +1 -1
  47. package/lib/engine-components/NestedGltf.d.ts +19 -3
  48. package/lib/engine-components/NestedGltf.js +19 -3
  49. package/lib/engine-components/NestedGltf.js.map +1 -1
  50. package/lib/engine-components/Networking.d.ts +1 -1
  51. package/lib/engine-components/Networking.js +1 -1
  52. package/lib/engine-components/ReflectionProbe.js +2 -0
  53. package/lib/engine-components/ReflectionProbe.js.map +1 -1
  54. package/lib/engine-components/postprocessing/VolumeParameter.d.ts +2 -0
  55. package/lib/engine-components/postprocessing/VolumeParameter.js +4 -1
  56. package/lib/engine-components/postprocessing/VolumeParameter.js.map +1 -1
  57. package/lib/engine-components/ui/Canvas.d.ts +1 -1
  58. package/lib/engine-components/ui/Canvas.js +2 -8
  59. package/lib/engine-components/ui/Canvas.js.map +1 -1
  60. package/lib/engine-components/webxr/WebXRImageTracking.js +4 -0
  61. package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
  62. package/package.json +1 -1
  63. package/src/engine/api.ts +3 -0
  64. package/src/engine/debug/debug_spatial_console.ts +10 -7
  65. package/src/engine/engine_addressables.ts +6 -3
  66. package/src/engine/engine_audio.ts +184 -0
  67. package/src/engine/engine_gameobject.ts +2 -2
  68. package/src/engine/engine_init.ts +10 -0
  69. package/src/engine/engine_mainloop_utils.ts +5 -2
  70. package/src/engine/engine_serialization_builtin_serializer.ts +63 -46
  71. package/src/engine/webcomponents/needle-engine.ts +9 -3
  72. package/src/engine/xr/NeedleXRSession.ts +48 -13
  73. package/src/engine-components/Animation.ts +19 -16
  74. package/src/engine-components/AnimatorController.ts +4 -1
  75. package/src/engine-components/AudioSource.ts +130 -79
  76. package/src/engine-components/NestedGltf.ts +20 -4
  77. package/src/engine-components/Networking.ts +1 -1
  78. package/src/engine-components/ReflectionProbe.ts +2 -0
  79. package/src/engine-components/postprocessing/VolumeParameter.ts +4 -1
  80. package/src/engine-components/ui/Canvas.ts +2 -8
  81. package/src/engine-components/webxr/WebXRImageTracking.ts +2 -0
@@ -1362,6 +1362,75 @@ export declare class Attractor extends Component {
1362
1362
 
1363
1363
  declare type AttributeChangeCallback = (value: string | null) => void;
1364
1364
 
1365
+ /**
1366
+ * Represents an audio clip that can be loaded and played independently.
1367
+ * The AudioClip class encapsulates the URL of the audio resource and provides
1368
+ * methods for playback control (play, pause, stop) and querying duration.
1369
+ */
1370
+ export declare class AudioClip {
1371
+ readonly url: string;
1372
+ /**
1373
+ * Creates a new AudioClip instance with the specified URL.
1374
+ * @param url The URL of the audio resource to load. This can be a path to an audio file or a MediaStream URL.
1375
+ */
1376
+ constructor(url: string);
1377
+ /** Whether the clip is currently playing.
1378
+ * @returns `true` if the clip is actively playing audio.
1379
+ */
1380
+ get isPlaying(): boolean;
1381
+ /**
1382
+ * The total duration of the audio clip in seconds.
1383
+ * Loads the audio metadata if not already available.
1384
+ * @returns A promise that resolves with the duration in seconds.
1385
+ */
1386
+ getDuration(): Promise<number>;
1387
+ /**
1388
+ * Plays the audio clip from the current position.
1389
+ * @returns A promise that resolves when playback finishes, or rejects on error.
1390
+ * If the clip is looping, the promise will never resolve on its own – call {@link stop} or {@link pause} to end playback.
1391
+ */
1392
+ play(): Promise<void>;
1393
+ /**
1394
+ * Pauses playback at the current position.
1395
+ * Call {@link play} to resume.
1396
+ */
1397
+ pause(): void;
1398
+ /**
1399
+ * Stops playback and resets the position to the beginning.
1400
+ */
1401
+ stop(): void;
1402
+ /** Whether the clip should loop when reaching the end. */
1403
+ get loop(): boolean;
1404
+ set loop(value: boolean);
1405
+ /** Playback volume from 0 (silent) to 1 (full). */
1406
+ get volume(): number;
1407
+ set volume(value: number);
1408
+ /** Current playback position in seconds. */
1409
+ get currentTime(): number;
1410
+ set currentTime(value: number);
1411
+ /** Normalized playback progress from 0 to 1.
1412
+ * @returns The current playback position as a value between 0 and 1, or 0 if the duration is unknown.
1413
+ */
1414
+ get progress(): number;
1415
+ /**
1416
+ * Seeks to a normalized position (0–1) in the clip.
1417
+ * @param position A value between 0 (start) and 1 (end).
1418
+ */
1419
+ seek(position: number): void;
1420
+ /** The underlying HTMLAudioElement, or `undefined` if not yet created.
1421
+ * Use this to connect the element to the Web Audio API via `createMediaElementSource()`.
1422
+ * @returns The HTMLAudioElement if the clip has been loaded or played, otherwise `undefined`.
1423
+ */
1424
+ get audioElement(): HTMLAudioElement | undefined;
1425
+ private _audioElement?;
1426
+ private _duration?;
1427
+ private _loadPromise?;
1428
+ private _loop;
1429
+ private _volume;
1430
+ /** Lazily creates and loads the shared HTMLAudioElement. */
1431
+ private ensureAudioElement;
1432
+ }
1433
+
1365
1434
  /**
1366
1435
  * @category Animation and Sequencing
1367
1436
  * @see {@link PlayableDirector} for the main component to control timelines in Needle Engine.
@@ -1517,9 +1586,10 @@ export declare class AudioSource extends Component {
1517
1586
  */
1518
1587
  get isPlaying(): boolean;
1519
1588
  /**
1520
- * The total duration of the current audio clip in seconds.
1589
+ * The total duration of the currently loaded audio clip in seconds.
1521
1590
  *
1522
1591
  * @returns Duration in seconds or undefined if no clip is loaded
1592
+ * @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.
1523
1593
  */
1524
1594
  get duration(): number | undefined;
1525
1595
  /**
@@ -1544,7 +1614,8 @@ export declare class AudioSource extends Component {
1544
1614
  /**
1545
1615
  * Controls how the audio is positioned in space.
1546
1616
  * Values range from 0 (2D, non-positional) to 1 (fully 3D positioned).
1547
- * Note: 2D playback is not fully supported in the current implementation.
1617
+ * Internally uses a dual-path audio graph to crossfade between a spatialized (PannerNode)
1618
+ * and a non-spatialized (direct) signal path.
1548
1619
  */
1549
1620
  get spatialBlend(): number;
1550
1621
  set spatialBlend(val: number);
@@ -1592,7 +1663,11 @@ export declare class AudioSource extends Component {
1592
1663
  private audioLoader;
1593
1664
  private shouldPlay;
1594
1665
  private _lastClipStartedLoading;
1666
+ private _loadedClip;
1595
1667
  private _audioElement;
1668
+ private _entryNode;
1669
+ private _spatialGain;
1670
+ private _bypassGain;
1596
1671
  /**
1597
1672
  * Returns the underlying {@link PositionalAudio} object, creating it if necessary.
1598
1673
  * The audio source needs a user interaction to be initialized due to browser autoplay policies.
@@ -1620,6 +1695,15 @@ export declare class AudioSource extends Component {
1620
1695
  private onApplicationMuteChanged;
1621
1696
  private createAudio;
1622
1697
  private __onAllowAudioCallback;
1698
+ /**
1699
+ * Sets up the dual-path audio graph for spatial blend crossfading.
1700
+ * Creates two parallel signal paths from source to output:
1701
+ * - 3D path: entry → panner → spatialGain → gain (spatialized)
1702
+ * - 2D path: entry → bypassGain → gain (non-spatialized)
1703
+ */
1704
+ private setupSpatialBlendNodes;
1705
+ /** Updates the spatial/bypass gain values based on the current spatialBlend. */
1706
+ private updateSpatialBlendGains;
1623
1707
  private applySpatialDistanceSettings;
1624
1708
  private onNewClip;
1625
1709
  /**
@@ -1627,8 +1711,9 @@ export declare class AudioSource extends Component {
1627
1711
  * If no argument is provided, plays the currently assigned clip.
1628
1712
  *
1629
1713
  * @param clip - Optional audio clip or {@link MediaStream} to play
1714
+ * @returns A promise that resolves when playback starts successfully, or rejects on error
1630
1715
  */
1631
- play(clip?: string | MediaStream | undefined): void;
1716
+ play(clip?: string | MediaStream | undefined): Promise<boolean>;
1632
1717
  /**
1633
1718
  * Pauses audio playback while maintaining the current position.
1634
1719
  * Use play() to resume from the paused position.
@@ -2836,7 +2921,7 @@ export declare class Canvas extends UIRootComponent implements ICanvas {
2836
2921
  private _receivers;
2837
2922
  registerEventReceiver(receiver: ICanvasEventReceiver): void;
2838
2923
  unregisterEventReceiver(receiver: ICanvasEventReceiver): void;
2839
- onEnterXR(args: NeedleXREventArgs): Promise<void>;
2924
+ onEnterXR(args: NeedleXREventArgs): void;
2840
2925
  onLeaveXR(args: NeedleXREventArgs): void;
2841
2926
  onBeforeRenderRoutine: () => void;
2842
2927
  onAfterRenderRoutine: () => void;
@@ -3513,7 +3598,7 @@ declare class ColorSerializer extends TypeSerializer {
3513
3598
  onSerialize(data: any): any | void;
3514
3599
  }
3515
3600
 
3516
- export declare const colorSerializer: ColorSerializer;
3601
+ export declare let colorSerializer: ColorSerializer;
3517
3602
 
3518
3603
  /**
3519
3604
  * Utility method to check if two materials were created from the same glTF material
@@ -3987,7 +4072,7 @@ declare class ComponentSerializer extends TypeSerializer {
3987
4072
  findObjectForGuid(guid: string, root: Object3D): any;
3988
4073
  }
3989
4074
 
3990
- export declare const componentSerializer: ComponentSerializer;
4075
+ export declare let componentSerializer: ComponentSerializer;
3991
4076
 
3992
4077
  declare type ComponentType = "button" | "thumbstick" | "squeeze" | "touchpad";
3993
4078
 
@@ -5778,19 +5863,6 @@ export declare class EnvironmentScene extends Scene {
5778
5863
  createAreaLightMaterial(intensity: number): MeshBasicMaterial;
5779
5864
  }
5780
5865
 
5781
- export declare const euler: EulerSerializer;
5782
-
5783
- declare class EulerSerializer extends TypeSerializer {
5784
- constructor();
5785
- onDeserialize(data: any, _context: SerializationContext): Euler | undefined;
5786
- onSerialize(data: any, _context: SerializationContext): {
5787
- x: any;
5788
- y: any;
5789
- z: any;
5790
- order: any;
5791
- };
5792
- }
5793
-
5794
5866
  /**
5795
5867
  * EventList manages a list of callbacks that can be invoked together.
5796
5868
  * Used for Unity-style events that can be configured in the editor (Unity or Blender).
@@ -5923,7 +5995,7 @@ declare class EventListSerializer extends TypeSerializer {
5923
5995
  onDeserialize(data: EventListData, context: SerializationContext): EventList<any> | undefined | null;
5924
5996
  }
5925
5997
 
5926
- export declare const eventListSerializer: EventListSerializer;
5998
+ export declare let eventListSerializer: EventListSerializer;
5927
5999
 
5928
6000
  /**
5929
6001
  * [EventSystem](https://engine.needle.tools/docs/api/EventSystem) is responsible for managing and dispatching input events to UI components within the scene.
@@ -8285,6 +8357,16 @@ export declare class InheritVelocityModule {
8285
8357
  applyCurrent(vel: Vector3 | Vector3_2, t01: number, lerpFactor: number): void;
8286
8358
  }
8287
8359
 
8360
+ /* Excluded from this release type: initAddressableSerializers */
8361
+
8362
+ /** Register all builtin serializers and prototype patches.
8363
+ * Must be called from {@link initEngine} so the registrations survive tree-shaking
8364
+ * when the package declares `sideEffects: false`.
8365
+ */
8366
+ export declare function initBuiltinSerializers(): void;
8367
+
8368
+ /* Excluded from this release type: initVolumeParameterSerializer */
8369
+
8288
8370
  /**
8289
8371
  * Handles all input events including mouse, touch, keyboard, and XR controllers.
8290
8372
  * Access via `this.context.input` from any component.
@@ -10957,11 +11039,17 @@ export declare interface NeedleEngineAttributes {
10957
11039
  'hash': string;
10958
11040
  /** Set to automatically add OrbitControls to the loaded scene. */
10959
11041
  'camera-controls': string;
10960
- /** Override the default draco decoder path location. */
11042
+ /** Override the default Draco decoder/decompressor path. Can be a URL or a local path to a directory containing the Draco decoder files.
11043
+ * @default "https://www.gstatic.com/draco/versioned/decoders/1.5.7/"
11044
+ * @example <needle-engine dracoDecoderPath="./decoders/draco/"></needle-engine>
11045
+ */
10961
11046
  'dracoDecoderPath': string;
10962
- /** Override the default draco library type. */
11047
+ /** Override the default Draco decoder type. */
10963
11048
  'dracoDecoderType': 'wasm' | 'js';
10964
- /** Override the default KTX2 transcoder/decoder path. */
11049
+ /** Override the default KTX2 transcoder/decoder path. Can be a URL or a local path to a directory containing the KTX2 transcoder files.
11050
+ * @default "https://cdn.needle.tools/static/three/0.179.1/basis2/"
11051
+ * @example <needle-engine ktx2DecoderPath="./decoders/ktx2/"></needle-engine>
11052
+ */
10965
11053
  'ktx2DecoderPath': string;
10966
11054
  /** Prevent context from being disposed when element is removed from DOM. */
10967
11055
  'keep-alive': 'true' | 'false';
@@ -11914,8 +12002,7 @@ export declare class NeedleXRSession implements INeedleXRSession {
11914
12002
  get referenceSpace(): XRSpace | null;
11915
12003
  /** @returns the XRFrame `viewerpose` using the xr `referenceSpace` */
11916
12004
  get viewerPose(): XRViewerPose | undefined;
11917
- /** @returns `true` if any image is currently being tracked */
11918
- /** returns true if images are currently being tracked */
12005
+ /** @returns `true` if any image is currently being tracked or emulated */
11919
12006
  get isTrackingImages(): boolean;
11920
12007
  /** The currently active XR rig */
11921
12008
  get rig(): IXRRig | null;
@@ -11961,6 +12048,8 @@ export declare class NeedleXRSession implements INeedleXRSession {
11961
12048
  private readonly _xr_update_scripts;
11962
12049
  /** scripts that are in the scene but inactive (e.g. disabled parent gameObject) */
11963
12050
  private readonly _inactive_scripts;
12051
+ /** tracks scripts that have received onEnterXR — prevents spurious onLeaveXR calls */
12052
+ private readonly _scripts_in_xr;
11964
12053
  private readonly _controllerAdded;
11965
12054
  private readonly _controllerRemoved;
11966
12055
  private readonly _originalCameraWorldPosition?;
@@ -12168,8 +12257,8 @@ export declare type NEPointerEventIntersection = Intersection & {
12168
12257
 
12169
12258
  /**
12170
12259
  * NestedGltf loads and instantiates a glTF file when the component starts.
12171
- * NestedGltf components are created by the Unity exporter when nesting Objects with the GltfObject component (in Unity).
12172
- * Use this for lazy-loading content, modular scene composition, or dynamic asset loading.
12260
+ * This enables splitting a scene into multiple `.glb` files that are loaded on demand,
12261
+ * keeping initial load times small and allowing parts of a scene to be reused across different contexts.
12173
12262
  *
12174
12263
  * ![](https://cloud.needle.tools/-/media/lJKrr_2tWlqRFdFc46U4bQ.gif)
12175
12264
  *
@@ -12182,6 +12271,23 @@ export declare type NEPointerEventIntersection = Intersection & {
12182
12271
  * - Preloading support for faster display
12183
12272
  * - Event callback when loading completes
12184
12273
  *
12274
+ * **Limitations:**
12275
+ * - Loads only once; there is no public API to unload and reload content
12276
+ * - Requires a parent object — does nothing if the GameObject has no parent
12277
+ * - Not intended to be added from code. For loading glTF assets at runtime,
12278
+ * use {@link AssetReference.loadAsset} or {@link SceneSwitcher} instead
12279
+ *
12280
+ * **Unity Editor usage:**
12281
+ * NestedGltf components are created automatically by the exporter when nesting GltfObject components:
12282
+ * - A parent GameObject with a `GltfObject` component is exported as a `.glb` file
12283
+ * - Any child GameObject that also has a `GltfObject` component is exported as a separate `.glb` file
12284
+ * - The child's `GltfObject` is replaced with a `NestedGltf` reference pointing to that separate `.glb`
12285
+ *
12286
+ * ```
12287
+ * Parent [GltfObject] → exported as parent.glb
12288
+ * └─ Child [GltfObject] → exported as child.glb, replaced with NestedGltf in parent.glb
12289
+ * ```
12290
+ *
12185
12291
  * @example Load a glTF when object becomes active
12186
12292
  * ```ts
12187
12293
  * const nested = myPlaceholder.addComponent(NestedGltf);
@@ -12198,7 +12304,6 @@ export declare type NEPointerEventIntersection = Intersection & {
12198
12304
  * // Later, when object becomes active, it displays instantly
12199
12305
  * ```
12200
12306
  *
12201
- * @summary Loads and instantiates a nested glTF file
12202
12307
  * @category Asset Management
12203
12308
  * @group Components
12204
12309
  * @see {@link AssetReference} for asset loading utilities
@@ -12580,7 +12685,7 @@ export declare interface NetworkEventMap {
12580
12685
  * @see {@link RoomEvents} for room lifecycle events
12581
12686
  * @see {@link isLocalNetwork} for local network detection
12582
12687
  * @link https://engine.needle.tools/docs/how-to-guides/networking/
12583
- * @summary Networking configuration
12688
+ * @summary Configures the websocket server URL for multiplayer networking
12584
12689
  * @category Networking
12585
12690
  * @group Components
12586
12691
  */
@@ -12801,7 +12906,7 @@ declare class ObjectSerializer extends TypeSerializer {
12801
12906
  onDeserialize(data: ObjectData | string | null, context: SerializationContext): Object3D<Object3DEventMap> | Component | null | undefined;
12802
12907
  }
12803
12908
 
12804
- export declare const objectSerializer: ObjectSerializer;
12909
+ export declare let objectSerializer: ObjectSerializer;
12805
12910
 
12806
12911
  declare type ObjectToNodeMap = {
12807
12912
  [uuid: string]: number;