@needle-tools/engine 5.0.4 → 5.0.6-next.56fe65a

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 (95) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/components.needle.json +1 -1
  3. package/dist/{needle-engine.bundle-CYrPktak.umd.cjs → needle-engine.bundle-BakND7HQ.umd.cjs} +140 -139
  4. package/dist/{needle-engine.bundle-B3Km2VZ4.js → needle-engine.bundle-CsY10n4y.js} +8183 -7957
  5. package/dist/{needle-engine.bundle-CX-SJZzp.min.js → needle-engine.bundle-Drz4zRYf.min.js} +142 -141
  6. package/dist/needle-engine.d.ts +139 -14
  7. package/dist/needle-engine.js +560 -557
  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 +8 -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.js +27 -0
  32. package/lib/engine/engine_serialization_builtin_serializer.js.map +1 -1
  33. package/lib/engine/webcomponents/needle-engine.d.ts +9 -3
  34. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  35. package/lib/engine/xr/NeedleXRSession.d.ts +3 -2
  36. package/lib/engine/xr/NeedleXRSession.js +50 -14
  37. package/lib/engine/xr/NeedleXRSession.js.map +1 -1
  38. package/lib/engine-components/Animation.js +17 -16
  39. package/lib/engine-components/Animation.js.map +1 -1
  40. package/lib/engine-components/AnimatorController.d.ts +2 -0
  41. package/lib/engine-components/AnimatorController.js +4 -1
  42. package/lib/engine-components/AnimatorController.js.map +1 -1
  43. package/lib/engine-components/AudioSource.d.ts +19 -3
  44. package/lib/engine-components/AudioSource.js +121 -68
  45. package/lib/engine-components/AudioSource.js.map +1 -1
  46. package/lib/engine-components/DragControls.d.ts +7 -0
  47. package/lib/engine-components/DragControls.js +19 -0
  48. package/lib/engine-components/DragControls.js.map +1 -1
  49. package/lib/engine-components/NestedGltf.d.ts +19 -3
  50. package/lib/engine-components/NestedGltf.js +19 -3
  51. package/lib/engine-components/NestedGltf.js.map +1 -1
  52. package/lib/engine-components/Networking.d.ts +1 -1
  53. package/lib/engine-components/Networking.js +1 -1
  54. package/lib/engine-components/OrbitControls.js +16 -11
  55. package/lib/engine-components/OrbitControls.js.map +1 -1
  56. package/lib/engine-components/postprocessing/VolumeParameter.d.ts +2 -0
  57. package/lib/engine-components/postprocessing/VolumeParameter.js +4 -1
  58. package/lib/engine-components/postprocessing/VolumeParameter.js.map +1 -1
  59. package/lib/engine-components/ui/Canvas.d.ts +1 -1
  60. package/lib/engine-components/ui/Canvas.js +2 -8
  61. package/lib/engine-components/ui/Canvas.js.map +1 -1
  62. package/lib/engine-components/ui/Text.d.ts +8 -1
  63. package/lib/engine-components/ui/Text.js +29 -14
  64. package/lib/engine-components/ui/Text.js.map +1 -1
  65. package/lib/engine-components/web/CursorFollow.js +21 -12
  66. package/lib/engine-components/web/CursorFollow.js.map +1 -1
  67. package/lib/engine-components/webxr/WebXRImageTracking.js +4 -0
  68. package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
  69. package/package.json +2 -2
  70. package/plugins/vite/asap.js +17 -8
  71. package/plugins/vite/local-files-core.js +3 -3
  72. package/plugins/vite/local-files-utils.d.ts +3 -1
  73. package/plugins/vite/local-files-utils.js +29 -5
  74. package/src/engine/api.ts +3 -0
  75. package/src/engine/debug/debug_spatial_console.ts +10 -7
  76. package/src/engine/engine_addressables.ts +6 -3
  77. package/src/engine/engine_audio.ts +184 -0
  78. package/src/engine/engine_gameobject.ts +2 -2
  79. package/src/engine/engine_init.ts +8 -0
  80. package/src/engine/engine_mainloop_utils.ts +5 -2
  81. package/src/engine/engine_serialization_builtin_serializer.ts +31 -3
  82. package/src/engine/webcomponents/needle-engine.ts +9 -3
  83. package/src/engine/xr/NeedleXRSession.ts +48 -13
  84. package/src/engine-components/Animation.ts +19 -16
  85. package/src/engine-components/AnimatorController.ts +4 -1
  86. package/src/engine-components/AudioSource.ts +130 -79
  87. package/src/engine-components/DragControls.ts +18 -2
  88. package/src/engine-components/NestedGltf.ts +20 -4
  89. package/src/engine-components/Networking.ts +1 -1
  90. package/src/engine-components/OrbitControls.ts +18 -9
  91. package/src/engine-components/postprocessing/VolumeParameter.ts +4 -1
  92. package/src/engine-components/ui/Canvas.ts +2 -8
  93. package/src/engine-components/ui/Text.ts +43 -18
  94. package/src/engine-components/web/CursorFollow.ts +21 -13
  95. 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;
@@ -5338,6 +5423,12 @@ export declare class DragControls extends Component implements IPointerEventHand
5338
5423
  * providing visual feedback about the object's position relative to surfaces below it.
5339
5424
  */
5340
5425
  showGizmo: boolean;
5426
+ /** Invoked once when a drag begins (after the minimum drag distance threshold is met). */
5427
+ dragStarted: EventList;
5428
+ /** Invoked every frame while the object is being dragged. */
5429
+ dragUpdated: EventList;
5430
+ /** Invoked once when the last pointer is released and the drag ends. */
5431
+ dragEnded: EventList;
5341
5432
  /**
5342
5433
  * Returns the object currently being dragged by this DragControls component, if any.
5343
5434
  * @returns The object being dragged or null if no object is currently dragged
@@ -8272,12 +8363,16 @@ export declare class InheritVelocityModule {
8272
8363
  applyCurrent(vel: Vector3 | Vector3_2, t01: number, lerpFactor: number): void;
8273
8364
  }
8274
8365
 
8366
+ /* Excluded from this release type: initAddressableSerializers */
8367
+
8275
8368
  /** Register all builtin serializers and prototype patches.
8276
8369
  * Must be called from {@link initEngine} so the registrations survive tree-shaking
8277
8370
  * when the package declares `sideEffects: false`.
8278
8371
  */
8279
8372
  export declare function initBuiltinSerializers(): void;
8280
8373
 
8374
+ /* Excluded from this release type: initVolumeParameterSerializer */
8375
+
8281
8376
  /**
8282
8377
  * Handles all input events including mouse, touch, keyboard, and XR controllers.
8283
8378
  * Access via `this.context.input` from any component.
@@ -10950,11 +11045,17 @@ export declare interface NeedleEngineAttributes {
10950
11045
  'hash': string;
10951
11046
  /** Set to automatically add OrbitControls to the loaded scene. */
10952
11047
  'camera-controls': string;
10953
- /** Override the default draco decoder path location. */
11048
+ /** Override the default Draco decoder/decompressor path. Can be a URL or a local path to a directory containing the Draco decoder files.
11049
+ * @default "https://www.gstatic.com/draco/versioned/decoders/1.5.7/"
11050
+ * @example <needle-engine dracoDecoderPath="./decoders/draco/"></needle-engine>
11051
+ */
10954
11052
  'dracoDecoderPath': string;
10955
- /** Override the default draco library type. */
11053
+ /** Override the default Draco decoder type. */
10956
11054
  'dracoDecoderType': 'wasm' | 'js';
10957
- /** Override the default KTX2 transcoder/decoder path. */
11055
+ /** Override the default KTX2 transcoder/decoder path. Can be a URL or a local path to a directory containing the KTX2 transcoder files.
11056
+ * @default "https://cdn.needle.tools/static/three/0.179.1/basis2/"
11057
+ * @example <needle-engine ktx2DecoderPath="./decoders/ktx2/"></needle-engine>
11058
+ */
10958
11059
  'ktx2DecoderPath': string;
10959
11060
  /** Prevent context from being disposed when element is removed from DOM. */
10960
11061
  'keep-alive': 'true' | 'false';
@@ -11907,8 +12008,7 @@ export declare class NeedleXRSession implements INeedleXRSession {
11907
12008
  get referenceSpace(): XRSpace | null;
11908
12009
  /** @returns the XRFrame `viewerpose` using the xr `referenceSpace` */
11909
12010
  get viewerPose(): XRViewerPose | undefined;
11910
- /** @returns `true` if any image is currently being tracked */
11911
- /** returns true if images are currently being tracked */
12011
+ /** @returns `true` if any image is currently being tracked or emulated */
11912
12012
  get isTrackingImages(): boolean;
11913
12013
  /** The currently active XR rig */
11914
12014
  get rig(): IXRRig | null;
@@ -11954,6 +12054,8 @@ export declare class NeedleXRSession implements INeedleXRSession {
11954
12054
  private readonly _xr_update_scripts;
11955
12055
  /** scripts that are in the scene but inactive (e.g. disabled parent gameObject) */
11956
12056
  private readonly _inactive_scripts;
12057
+ /** tracks scripts that have received onEnterXR — prevents spurious onLeaveXR calls */
12058
+ private readonly _scripts_in_xr;
11957
12059
  private readonly _controllerAdded;
11958
12060
  private readonly _controllerRemoved;
11959
12061
  private readonly _originalCameraWorldPosition?;
@@ -12161,8 +12263,8 @@ export declare type NEPointerEventIntersection = Intersection & {
12161
12263
 
12162
12264
  /**
12163
12265
  * NestedGltf loads and instantiates a glTF file when the component starts.
12164
- * NestedGltf components are created by the Unity exporter when nesting Objects with the GltfObject component (in Unity).
12165
- * Use this for lazy-loading content, modular scene composition, or dynamic asset loading.
12266
+ * This enables splitting a scene into multiple `.glb` files that are loaded on demand,
12267
+ * keeping initial load times small and allowing parts of a scene to be reused across different contexts.
12166
12268
  *
12167
12269
  * ![](https://cloud.needle.tools/-/media/lJKrr_2tWlqRFdFc46U4bQ.gif)
12168
12270
  *
@@ -12175,6 +12277,23 @@ export declare type NEPointerEventIntersection = Intersection & {
12175
12277
  * - Preloading support for faster display
12176
12278
  * - Event callback when loading completes
12177
12279
  *
12280
+ * **Limitations:**
12281
+ * - Loads only once; there is no public API to unload and reload content
12282
+ * - Requires a parent object — does nothing if the GameObject has no parent
12283
+ * - Not intended to be added from code. For loading glTF assets at runtime,
12284
+ * use {@link AssetReference.loadAsset} or {@link SceneSwitcher} instead
12285
+ *
12286
+ * **Unity Editor usage:**
12287
+ * NestedGltf components are created automatically by the exporter when nesting GltfObject components:
12288
+ * - A parent GameObject with a `GltfObject` component is exported as a `.glb` file
12289
+ * - Any child GameObject that also has a `GltfObject` component is exported as a separate `.glb` file
12290
+ * - The child's `GltfObject` is replaced with a `NestedGltf` reference pointing to that separate `.glb`
12291
+ *
12292
+ * ```
12293
+ * Parent [GltfObject] → exported as parent.glb
12294
+ * └─ Child [GltfObject] → exported as child.glb, replaced with NestedGltf in parent.glb
12295
+ * ```
12296
+ *
12178
12297
  * @example Load a glTF when object becomes active
12179
12298
  * ```ts
12180
12299
  * const nested = myPlaceholder.addComponent(NestedGltf);
@@ -12191,7 +12310,6 @@ export declare type NEPointerEventIntersection = Intersection & {
12191
12310
  * // Later, when object becomes active, it displays instantly
12192
12311
  * ```
12193
12312
  *
12194
- * @summary Loads and instantiates a nested glTF file
12195
12313
  * @category Asset Management
12196
12314
  * @group Components
12197
12315
  * @see {@link AssetReference} for asset loading utilities
@@ -12573,7 +12691,7 @@ export declare interface NetworkEventMap {
12573
12691
  * @see {@link RoomEvents} for room lifecycle events
12574
12692
  * @see {@link isLocalNetwork} for local network detection
12575
12693
  * @link https://engine.needle.tools/docs/how-to-guides/networking/
12576
- * @summary Networking configuration
12694
+ * @summary Configures the websocket server URL for multiplayer networking
12577
12695
  * @category Networking
12578
12696
  * @group Components
12579
12697
  */
@@ -19806,7 +19924,14 @@ export declare class OrbitControls extends Component implements ICameraControlle
19806
19924
  horizontalOverflow: HorizontalWrapMode;
19807
19925
  lineSpacing: number;
19808
19926
  supportRichText: boolean;
19809
- font?: string;
19927
+ set font(val: string | null);
19928
+ get font(): string | null;
19929
+ private _font;
19930
+ private _assignedAtRuntime;
19931
+ /**
19932
+ * 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>`
19933
+ * @default false
19934
+ */
19810
19935
  fontStyle: FontStyle;
19811
19936
  setAlphaFactor(factor: number): void;
19812
19937
  get text(): string;