@needle-tools/engine 4.3.0-alpha.1 → 4.3.0-alpha.3

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 (36) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/needle-engine.bundle.js +5222 -5177
  3. package/dist/needle-engine.bundle.light.js +5226 -5181
  4. package/dist/needle-engine.bundle.light.min.js +121 -118
  5. package/dist/needle-engine.bundle.light.umd.cjs +128 -125
  6. package/dist/needle-engine.bundle.min.js +119 -116
  7. package/dist/needle-engine.bundle.umd.cjs +124 -121
  8. package/dist/needle-engine.d.ts +9 -9
  9. package/lib/engine/engine_context.js +1 -1
  10. package/lib/engine/engine_context.js.map +1 -1
  11. package/lib/engine/engine_mainloop_utils.js +2 -4
  12. package/lib/engine/engine_mainloop_utils.js.map +1 -1
  13. package/lib/engine/engine_serialization_core.js +1 -1
  14. package/lib/engine/engine_serialization_core.js.map +1 -1
  15. package/lib/engine/xr/NeedleXRSession.d.ts +6 -1
  16. package/lib/engine/xr/NeedleXRSession.js +6 -1
  17. package/lib/engine/xr/NeedleXRSession.js.map +1 -1
  18. package/lib/engine-components/AudioSource.js +1 -3
  19. package/lib/engine-components/AudioSource.js.map +1 -1
  20. package/lib/engine-components/particlesystem/ParticleSystem.js +1 -1
  21. package/lib/engine-components/particlesystem/ParticleSystem.js.map +1 -1
  22. package/lib/engine-components/webxr/WebARSessionRoot.d.ts +8 -3
  23. package/lib/engine-components/webxr/WebARSessionRoot.js +30 -9
  24. package/lib/engine-components/webxr/WebARSessionRoot.js.map +1 -1
  25. package/lib/engine-components/webxr/WebXR.d.ts +25 -3
  26. package/lib/engine-components/webxr/WebXR.js +28 -3
  27. package/lib/engine-components/webxr/WebXR.js.map +1 -1
  28. package/package.json +1 -1
  29. package/src/engine/engine_context.ts +1 -1
  30. package/src/engine/engine_mainloop_utils.ts +2 -4
  31. package/src/engine/engine_serialization_core.ts +1 -1
  32. package/src/engine/xr/NeedleXRSession.ts +7 -1
  33. package/src/engine-components/AudioSource.ts +1 -2
  34. package/src/engine-components/particlesystem/ParticleSystem.ts +2 -2
  35. package/src/engine-components/webxr/WebARSessionRoot.ts +31 -8
  36. package/src/engine-components/webxr/WebXR.ts +39 -12
@@ -49,18 +49,25 @@ export class WebARSessionRoot extends Behaviour {
49
49
  }
50
50
  }
51
51
 
52
+ private static _hasPlaced: boolean = false;
53
+ /**
54
+ * @returns true if the scene has been placed in AR by the user or automatic placement
55
+ */
56
+ static get hasPlaced(): boolean {
57
+ return this._hasPlaced;
58
+ }
59
+
52
60
 
53
- /** The scale of a user in AR:
54
- * Note: a large value makes the scene appear smaller
61
+ /** The scale of the user in AR.
62
+ * **NOTE**: a large value makes the scene appear smaller
55
63
  * @default 1
56
64
  */
57
65
  get arScale(): number {
58
66
  return this._arScale;
59
67
  }
60
68
  set arScale(val: number) {
61
- if (val === this._arScale) return;
62
- this._arScale = val;
63
- this.onScaleChanged();
69
+ this._arScale = Math.max(0.000001, val);
70
+ this.onSetScale();
64
71
  }
65
72
  private _arScale: number = 1;
66
73
 
@@ -134,6 +141,7 @@ export class WebARSessionRoot extends Behaviour {
134
141
  if (debug) console.log("ENTER WEBXR: SessionRoot start...");
135
142
 
136
143
  this._anchor = null;
144
+ WebARSessionRoot._hasPlaced = false;
137
145
 
138
146
  // if (_args.xr.session.enabledFeatures?.includes("image-tracking")) {
139
147
  // console.warn("Image tracking is enabled - will not place scene");
@@ -193,6 +201,7 @@ export class WebARSessionRoot extends Behaviour {
193
201
  this.onRevertSceneChanges();
194
202
  // this._anchor?.delete();
195
203
  this._anchor = null;
204
+ WebARSessionRoot._hasPlaced = false;
196
205
  this._rigPlacementMatrix = undefined;
197
206
  }
198
207
  onUpdateXR(args: NeedleXREventArgs): void {
@@ -405,6 +414,7 @@ export class WebARSessionRoot extends Behaviour {
405
414
  reticle.quaternion.copy(reticle["lastQuat"]);
406
415
 
407
416
  this.onApplyPose(reticle);
417
+ WebARSessionRoot._hasPlaced = true;
408
418
 
409
419
  if (this.useXRAnchor) {
410
420
  this.onCreateAnchor(NeedleXRSession.active!, hit);
@@ -417,8 +427,16 @@ export class WebARSessionRoot extends Behaviour {
417
427
  }
418
428
  }
419
429
 
420
- private onScaleChanged() {
421
- // TODO: implement
430
+ private onSetScale() {
431
+ if (!WebARSessionRoot._hasPlaced) return;
432
+ const rig = NeedleXRSession.active?.rig?.gameObject;
433
+ if (rig) {
434
+ const currentScale = NeedleXRSession.active?.rigScale || 1;
435
+ const newScale = (1 / this._arScale) * currentScale;
436
+ const scaleMatrix = new Matrix4().makeScale(newScale, newScale, newScale).invert();
437
+ rig.matrix.premultiply(scaleMatrix);
438
+ rig.matrix.decompose(rig.position, rig.quaternion, rig.scale);
439
+ }
422
440
  }
423
441
 
424
442
  private onRevertSceneChanges() {
@@ -516,7 +534,7 @@ export class WebARSessionRoot extends Behaviour {
516
534
  console.warn("No rig object to place");
517
535
  return;
518
536
  }
519
- const rigScale = NeedleXRSession.active?.rigScale || 1;
537
+ // const rigScale = NeedleXRSession.active?.rigScale || 1;
520
538
 
521
539
  // save the previous rig parent
522
540
  const previousParent = rigObject.parent || this.context.scene;
@@ -578,6 +596,10 @@ class WebXRSessionRootUserInput {
578
596
  private _scale: number = 1;
579
597
  private _hasChanged: boolean = false;
580
598
 
599
+ get scale() {
600
+ return this._scale;
601
+ }
602
+
581
603
  // readonly translate: Vector3 = new Vector3();
582
604
  // readonly rotation: Quaternion = new Quaternion();
583
605
  // readonly scale: Vector3 = new Vector3(1, 1, 1);
@@ -594,6 +616,7 @@ class WebXRSessionRootUserInput {
594
616
  reset() {
595
617
  this._scale = 1;
596
618
  this.offset.identity();
619
+ this._hasChanged = true;
597
620
  }
598
621
  get hasChanged() { return this._hasChanged; }
599
622
 
@@ -58,7 +58,7 @@ export class WebXR extends Behaviour {
58
58
 
59
59
  // VR Settings
60
60
  /**
61
- * When enabled, default movement controls will be automatically added to the scene when entering VR.
61
+ * When enabled, default movement controls will be automatically added to the scene when entering VR.
62
62
  * This includes teleportation and smooth locomotion options for VR controllers.
63
63
  */
64
64
  @serializable()
@@ -96,14 +96,14 @@ export class WebXR extends Behaviour {
96
96
  usePlacementAdjustment: boolean = true;
97
97
 
98
98
  /**
99
- * Determines the scale of the user relative to the scene in AR. Larger values make the 3D content appear smaller.
99
+ * Determines the scale of the user relative to the scene in AR. Larger values make the 3D content appear smaller.
100
100
  * Only applies when `usePlacementReticle` is enabled.
101
101
  */
102
102
  @serializable()
103
103
  arScale: number = 1;
104
104
 
105
105
  /**
106
- * When enabled, an XRAnchor will be created for the AR scene and its position will be regularly updated to match the anchor.
106
+ * When enabled, an XRAnchor will be created for the AR scene and its position will be regularly updated to match the anchor.
107
107
  * This can help with spatial persistence in AR experiences.
108
108
  * @experimental
109
109
  */
@@ -118,21 +118,21 @@ export class WebXR extends Behaviour {
118
118
  autoPlace: boolean = false;
119
119
 
120
120
  /**
121
- * When enabled, the AR session root center will be automatically adjusted to place the center of the scene.
121
+ * When enabled, the AR session root center will be automatically adjusted to place the center of the scene.
122
122
  * This helps ensure the scene is properly aligned with detected surfaces.
123
123
  */
124
124
  @serializable()
125
125
  autoCenter: boolean = false;
126
126
 
127
127
  /**
128
- * When enabled, a USDZExporter component will be automatically added to the scene if none is found.
128
+ * When enabled, a USDZExporter component will be automatically added to the scene if none is found.
129
129
  * This allows iOS and visionOS devices to view 3D content using Apple's AR QuickLook.
130
130
  */
131
131
  @serializable()
132
132
  useQuicklookExport: boolean = false;
133
133
 
134
134
  /**
135
- * When enabled, the 'depth-sensing' WebXR feature will be requested to provide real-time depth occlusion.
135
+ * When enabled, the 'depth-sensing' WebXR feature will be requested to provide real-time depth occlusion.
136
136
  * Currently only supported on Oculus Quest devices.
137
137
  * @see https://developer.mozilla.org/en-US/docs/Web/API/XRDepthInformation
138
138
  * @experimental
@@ -141,7 +141,7 @@ export class WebXR extends Behaviour {
141
141
  useDepthSensing: boolean = false;
142
142
 
143
143
  /**
144
- * When enabled, a {@link SpatialGrabRaycaster} will be added or enabled in the scene,
144
+ * When enabled, a {@link SpatialGrabRaycaster} will be added or enabled in the scene,
145
145
  * allowing users to interact with objects at a distance in VR/AR.
146
146
  * @default true
147
147
  */
@@ -149,7 +149,7 @@ export class WebXR extends Behaviour {
149
149
  useSpatialGrab: boolean = true;
150
150
 
151
151
  /**
152
- * Specifies the avatar representation that will be created when entering a WebXR session.
152
+ * Specifies the avatar representation that will be created when entering a WebXR session.
153
153
  * Can be a reference to a 3D model or a boolean to use the default avatar.
154
154
  */
155
155
  @serializable(AssetReference)
@@ -166,6 +166,7 @@ export class WebXR extends Behaviour {
166
166
 
167
167
  /**
168
168
  * Initializes the WebXR component by obtaining the XR sync object for this context.
169
+ * @internal
169
170
  */
170
171
  awake() {
171
172
  NeedleXRSession.getXRSync(this.context);
@@ -174,6 +175,7 @@ export class WebXR extends Behaviour {
174
175
  /**
175
176
  * Sets up the WebXR component when it's enabled. Checks for HTTPS connection,
176
177
  * sets up USDZ export if enabled, creates UI buttons, and configures avatar settings.
178
+ * @internal
177
179
  */
178
180
  onEnable(): void {
179
181
  // check if we're on a secure connection:
@@ -216,6 +218,7 @@ export class WebXR extends Behaviour {
216
218
  /**
217
219
  * Cleans up resources when the component is disabled.
218
220
  * Destroys the USDZ exporter if one was created and removes UI buttons.
221
+ * @internal
219
222
  */
220
223
  onDisable(): void {
221
224
  this._usdzExporter?.destroy();
@@ -251,23 +254,40 @@ export class WebXR extends Behaviour {
251
254
  get sessionMode(): XRSessionMode | null {
252
255
  return NeedleXRSession.activeMode ?? null;;
253
256
  }
257
+ /** While AR: this will return the currently active WebARSessionRoot component.
258
+ * You can also query this component in your scene with `findObjectOfType(WebARSessionRoot)`
259
+ */
260
+ get arSessionRoot() {
261
+ return this._activeWebARSessionRoot;
262
+ }
254
263
 
255
- /** Call to start an WebVR session */
264
+ /** Call to start an WebVR session.
265
+ *
266
+ * This is a shorthand for `NeedleXRSession.start("immersive-vr", init, this.context)`
267
+ */
256
268
  async enterVR(init?: XRSessionInit): Promise<NeedleXRSession | null> {
257
269
  return NeedleXRSession.start("immersive-vr", init, this.context);
258
270
  }
259
- /** Call to start an WebAR session */
271
+ /** Call to start an WebAR session
272
+ *
273
+ * This is a shorthand for `NeedleXRSession.start("immersive-ar", init, this.context)`
274
+ */
260
275
  async enterAR(init?: XRSessionInit): Promise<NeedleXRSession | null> {
261
276
  return NeedleXRSession.start("immersive-ar", init, this.context);
262
277
  }
263
- /** Call to end a WebXR (AR or VR) session */
278
+
279
+ /** Call to end a WebXR (AR or VR) session.
280
+ *
281
+ * This is a shorthand for `NeedleXRSession.stop()`
282
+ */
264
283
  exitXR() {
265
284
  NeedleXRSession.stop();
266
285
  }
267
286
 
268
- private _exitXRMenuButton?: HTMLElement;
287
+ private _exitXRMenuButton?: HTMLElement;
269
288
  private _previousXRState: number = 0;
270
289
  private _spatialGrabRaycaster?: SpatialGrabRaycaster;
290
+ private _activeWebARSessionRoot: WebARSessionRoot | null = null;
271
291
 
272
292
  private get isActiveWebXR() {
273
293
  return !WebXR.activeWebXRComponent || WebXR.activeWebXRComponent === this;
@@ -277,6 +297,7 @@ export class WebXR extends Behaviour {
277
297
  * Called before entering a WebXR session. Sets up optional features like depth sensing, if needed.
278
298
  * @param _mode The XR session mode being requested (immersive-ar or immersive-vr)
279
299
  * @param args The XRSessionInit object that will be passed to the WebXR API
300
+ * @internal
280
301
  */
281
302
  onBeforeXR(_mode: XRSessionMode, args: XRSessionInit): void {
282
303
  if (!this.isActiveWebXR) {
@@ -295,6 +316,7 @@ export class WebXR extends Behaviour {
295
316
  * Called when a WebXR session begins. Sets up the scene for XR by configuring controllers,
296
317
  * AR placement, and other features based on component settings.
297
318
  * @param args Event arguments containing information about the started XR session
319
+ * @internal
298
320
  */
299
321
  async onEnterXR(args: NeedleXREventArgs) {
300
322
  if (!this.isActiveWebXR) return;
@@ -323,6 +345,7 @@ export class WebXR extends Behaviour {
323
345
  }
324
346
  }
325
347
 
348
+ this._activeWebARSessionRoot = sessionroot;
326
349
  if (sessionroot) {
327
350
  // sessionroot.enabled = this.usePlacementReticle; // < not sure if we want to disable the session root when placement reticle if OFF...
328
351
  sessionroot.customReticle = this.customARPlacementReticle;
@@ -371,6 +394,7 @@ export class WebXR extends Behaviour {
371
394
  * Called every frame during an active WebXR session.
372
395
  * Updates components that depend on the current XR state.
373
396
  * @param _args Event arguments containing information about the current XR session frame
397
+ * @internal
374
398
  */
375
399
  onUpdateXR(_args: NeedleXREventArgs): void {
376
400
  if (!this.isActiveWebXR) return;
@@ -383,6 +407,7 @@ export class WebXR extends Behaviour {
383
407
  * Called when a WebXR session ends. Restores pre-session state,
384
408
  * removes temporary components, and cleans up resources.
385
409
  * @param _ Event arguments containing information about the ended XR session
410
+ * @internal
386
411
  */
387
412
  onLeaveXR(_: NeedleXREventArgs): void {
388
413
  this._exitXRMenuButton?.remove();
@@ -399,6 +424,8 @@ export class WebXR extends Behaviour {
399
424
  }
400
425
  this._createdComponentsInSession.length = 0;
401
426
 
427
+ this._activeWebARSessionRoot = null;
428
+
402
429
  this.handleOfferSession();
403
430
 
404
431
  delayForFrames(1).then(() => WebXR.activeWebXRComponent = null);