@needle-tools/engine 4.12.3 → 4.12.4-next.4498846

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 (80) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/components.needle.json +1 -1
  3. package/dist/{gltf-progressive-Bfpfaz84.umd.cjs → gltf-progressive-BqUnxvCx.umd.cjs} +1 -1
  4. package/dist/{gltf-progressive-hFPACYio.min.js → gltf-progressive-CSaX5HQb.min.js} +2 -2
  5. package/dist/{gltf-progressive-DPunMlEM.js → gltf-progressive-ChnIhDXx.js} +27 -27
  6. package/dist/{loader.worker-DWzfDpAl.js → loader.worker-C1GG9A7C.js} +6 -6
  7. package/dist/{needle-engine.bundle-u-rSDw6R.js → needle-engine.bundle-C9mGVluu.js} +7444 -7358
  8. package/dist/{needle-engine.bundle-CLPD2ttK.umd.cjs → needle-engine.bundle-CnmG19ga.umd.cjs} +300 -293
  9. package/dist/{needle-engine.bundle-B3ssYJS0.min.js → needle-engine.bundle-ZJOekt7-.min.js} +297 -290
  10. package/dist/needle-engine.d.ts +53 -28
  11. package/dist/needle-engine.js +4 -4
  12. package/dist/needle-engine.min.js +1 -1
  13. package/dist/needle-engine.umd.cjs +1 -1
  14. package/dist/{postprocessing-ClLv0reO.min.js → postprocessing-12-UW7je.min.js} +1 -1
  15. package/dist/{postprocessing-BHQvwehB.umd.cjs → postprocessing-B3Hu0Ryi.umd.cjs} +1 -1
  16. package/dist/{postprocessing-DLI2N3LL.js → postprocessing-R535krvT.js} +2 -2
  17. package/dist/{three-Bf2NBxAw.umd.cjs → three-BzxwLtUE.umd.cjs} +176 -176
  18. package/dist/{three-BCCkyCA5.js → three-D9pcFbxc.js} +4637 -4636
  19. package/dist/{three-W7zWTcfP.min.js → three-DMvLgxja.min.js} +176 -176
  20. package/dist/{three-examples-DB5Uoja4.min.js → three-examples-CIv2roOA.min.js} +1 -1
  21. package/dist/{three-examples-Djbk6WA4.umd.cjs → three-examples-CjSwCv_b.umd.cjs} +1 -1
  22. package/dist/{three-examples-D4rE49Ui.js → three-examples-F0MJj0vr.js} +1 -1
  23. package/dist/{three-mesh-ui-zsOOA5Pq.umd.cjs → three-mesh-ui-BLnJQzMl.umd.cjs} +1 -1
  24. package/dist/{three-mesh-ui-CIez6qJQ.min.js → three-mesh-ui-BllgajJz.min.js} +1 -1
  25. package/dist/{three-mesh-ui-3nSSizT4.js → three-mesh-ui-DYyiRn5Y.js} +1 -1
  26. package/dist/{vendor-tyBvnMF-.umd.cjs → vendor-BFgQSG2m.umd.cjs} +1 -1
  27. package/dist/{vendor-DMZcbVO1.js → vendor-BIFy-gRe.js} +1 -1
  28. package/dist/{vendor-sURMCFSI.min.js → vendor-ChgmXMYr.min.js} +1 -1
  29. package/lib/engine/debug/debug_overlay.js +13 -2
  30. package/lib/engine/debug/debug_overlay.js.map +1 -1
  31. package/lib/engine/engine_animation.d.ts +7 -0
  32. package/lib/engine/engine_animation.js +16 -0
  33. package/lib/engine/engine_animation.js.map +1 -1
  34. package/lib/engine/engine_input.js +5 -3
  35. package/lib/engine/engine_input.js.map +1 -1
  36. package/lib/engine/webcomponents/WebXRButtons.js +8 -1
  37. package/lib/engine/webcomponents/WebXRButtons.js.map +1 -1
  38. package/lib/engine/webcomponents/buttons.js +4 -0
  39. package/lib/engine/webcomponents/buttons.js.map +1 -1
  40. package/lib/engine/webcomponents/icons.js +44 -5
  41. package/lib/engine/webcomponents/icons.js.map +1 -1
  42. package/lib/engine/webcomponents/logo-element.js +0 -1
  43. package/lib/engine/webcomponents/logo-element.js.map +1 -1
  44. package/lib/engine/webcomponents/needle menu/needle-menu.d.ts +19 -3
  45. package/lib/engine/webcomponents/needle menu/needle-menu.js +248 -161
  46. package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
  47. package/lib/engine/webcomponents/needle-engine.ar-overlay.js +1 -0
  48. package/lib/engine/webcomponents/needle-engine.ar-overlay.js.map +1 -1
  49. package/lib/engine/xr/NeedleXRSession.d.ts +2 -0
  50. package/lib/engine/xr/NeedleXRSession.js +19 -10
  51. package/lib/engine/xr/NeedleXRSession.js.map +1 -1
  52. package/lib/engine-components/Animation.js +2 -0
  53. package/lib/engine-components/Animation.js.map +1 -1
  54. package/lib/engine-components/AnimatorController.js +2 -0
  55. package/lib/engine-components/AnimatorController.js.map +1 -1
  56. package/lib/engine-components/Light.d.ts +17 -12
  57. package/lib/engine-components/Light.js +52 -36
  58. package/lib/engine-components/Light.js.map +1 -1
  59. package/lib/engine-components/webxr/WebXR.js +6 -8
  60. package/lib/engine-components/webxr/WebXR.js.map +1 -1
  61. package/lib/engine-components/webxr/WebXRImageTracking.js +9 -2
  62. package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
  63. package/package.json +3 -3
  64. package/plugins/common/license.js +3 -3
  65. package/src/engine/debug/debug_overlay.ts +15 -2
  66. package/src/engine/engine_animation.ts +19 -1
  67. package/src/engine/engine_input.ts +5 -3
  68. package/src/engine/webcomponents/WebXRButtons.ts +9 -1
  69. package/src/engine/webcomponents/buttons.ts +5 -0
  70. package/src/engine/webcomponents/icons.ts +47 -5
  71. package/src/engine/webcomponents/index.ts +1 -1
  72. package/src/engine/webcomponents/logo-element.ts +0 -1
  73. package/src/engine/webcomponents/needle menu/needle-menu.ts +270 -165
  74. package/src/engine/webcomponents/needle-engine.ar-overlay.ts +1 -0
  75. package/src/engine/xr/NeedleXRSession.ts +23 -10
  76. package/src/engine-components/Animation.ts +4 -1
  77. package/src/engine-components/AnimatorController.ts +3 -0
  78. package/src/engine-components/Light.ts +50 -42
  79. package/src/engine-components/webxr/WebXR.ts +6 -9
  80. package/src/engine-components/webxr/WebXRImageTracking.ts +12 -2
@@ -454,6 +454,9 @@ export class NeedleXRSession implements INeedleXRSession {
454
454
  */
455
455
  static async start(mode: XRSessionMode | "ar" | "quicklook", init?: XRSessionInit, context?: Context): Promise<NeedleXRSession | null> {
456
456
 
457
+ // setup session init args, make sure we have default values
458
+ if (!init) init = {};
459
+
457
460
  // handle iOS platform where "immersive-ar" is special:
458
461
  // - we either launch QuickLook
459
462
  // - or forward to the Needle App Clip experience for WebXR AR
@@ -477,7 +480,9 @@ export class NeedleXRSession implements INeedleXRSession {
477
480
  }
478
481
 
479
482
  if (!arSupported && (mode === "immersive-ar" || mode === "ar")) {
480
- // const debugAppClip = getParam("debugappclip")
483
+
484
+ this.invokeSessionRequestStart("immersive-ar", init);
485
+
481
486
  // Forward to the AppClip experience (Using the apple.com url the appclip overlay shows immediately)
482
487
  // const url =`https://appclip.needle.tools/ar?url=${(location.href)}`;
483
488
  const url = new URL("https://appclip.apple.com/id?p=tools.needle.launch-app.Clip");
@@ -511,6 +516,10 @@ export class NeedleXRSession implements INeedleXRSession {
511
516
  else window.location.href = urlStr;
512
517
  }
513
518
 
519
+ setTimeout(() => {
520
+ this.invokeSessionRequestEnd("immersive-ar", init || {}, null);
521
+ }, 3000);
522
+
514
523
  return null;
515
524
  }
516
525
  }
@@ -549,9 +558,6 @@ export class NeedleXRSession implements INeedleXRSession {
549
558
 
550
559
  //performance.mark('NeedleXRSession start');
551
560
 
552
- // setup session init args, make sure we have default values
553
- if (!init) init = {};
554
-
555
561
  switch (mode) {
556
562
 
557
563
  // Setup VR initialization parameters
@@ -615,9 +621,7 @@ export class NeedleXRSession implements INeedleXRSession {
615
621
  script.onBeforeXR(mode, init);
616
622
  }
617
623
  }
618
- for (const listener of this._sessionRequestStartListeners) {
619
- listener({ mode, init });
620
- }
624
+ this.invokeSessionRequestStart(mode, init);
621
625
  if (debug) showBalloonMessage("Requesting " + mode + " session (" + Date.now() + ")");
622
626
  Telemetry.sendEvent(Context.Current, "xr", {
623
627
  action: "session_request",
@@ -637,9 +641,7 @@ export class NeedleXRSession implements INeedleXRSession {
637
641
  });
638
642
  this._currentSessionRequest = undefined;
639
643
  this._currentSessionRequestMode = null;
640
- for (const listener of this._sessionRequestEndListeners) {
641
- listener({ mode, init, newSession: newSession || null });
642
- }
644
+ this.invokeSessionRequestEnd(mode, init, newSession);
643
645
  if (!newSession) {
644
646
  console.warn("XR Session request was rejected");
645
647
  return null;
@@ -650,6 +652,17 @@ export class NeedleXRSession implements INeedleXRSession {
650
652
  return session;
651
653
  }
652
654
 
655
+ private static invokeSessionRequestStart(mode: XRSessionMode, init: XRSessionInit) {
656
+ for (const listener of this._sessionRequestStartListeners) {
657
+ listener({ mode, init });
658
+ }
659
+ }
660
+ private static invokeSessionRequestEnd(mode: XRSessionMode, init: XRSessionInit, session: XRSession | null | undefined | void) {
661
+ for (const listener of this._sessionRequestEndListeners) {
662
+ listener({ mode, init, newSession: session || null });
663
+ }
664
+ }
665
+
653
666
  static setSession(mode: XRSessionMode, session: XRSession, init: XRSessionInit, context: Context) {
654
667
  if (this._activeSession) {
655
668
  console.error("A XRSession is already running");
@@ -1,4 +1,5 @@
1
1
  import { AnimationAction, AnimationClip, AnimationMixer, LoopOnce, LoopRepeat } from "three";
2
+ import { AnimationUtils } from "../engine/engine_animation.js";
2
3
 
3
4
  import { Mathf } from "../engine/engine_math.js";
4
5
  import { serializable } from "../engine/engine_serialization_decorator.js";
@@ -447,7 +448,7 @@ export class Animation extends Behaviour implements IAnimationComponent {
447
448
  action.time = Mathf.lerp(options.minMaxOffsetNormalized.x, options.minMaxOffsetNormalized.y, Math.random()) * clip.duration;
448
449
  }
449
450
  // If the animation is at the end, reset the time
450
- else if(action.time >= action.getClip().duration) {
451
+ else if (action.time >= action.getClip().duration) {
451
452
  action.time = 0;
452
453
  }
453
454
 
@@ -473,6 +474,8 @@ export class Animation extends Behaviour implements IAnimationComponent {
473
474
  action.paused = false;
474
475
  action.play();
475
476
 
477
+ window.requestAnimationFrame(() => AnimationUtils.testIfRootCanAnimate(action));
478
+
476
479
  if (debug) console.log("PLAY", action.getClip().name, action)
477
480
  const handle = new AnimationHandle(action, this.mixer!, options, _ => {
478
481
  this._handles.splice(this._handles.indexOf(handle), 1);
@@ -1,6 +1,7 @@
1
1
  import { AnimationAction, AnimationClip, AnimationMixer, AxesHelper, Euler, KeyframeTrack, LoopOnce, Object3D, Quaternion, Vector3 } from "three";
2
2
 
3
3
  import { isDevEnvironment } from "../engine/debug/index.js";
4
+ import { AnimationUtils } from "../engine/engine_animation.js";
4
5
  import { Mathf } from "../engine/engine_math.js";
5
6
  import { InstantiateIdProvider } from "../engine/engine_networking_instantiate.js";
6
7
  import { assign, SerializationContext, TypeSerializer } from "../engine/engine_serialization_core.js";
@@ -775,6 +776,8 @@ export class AnimatorController {
775
776
  else action.weight = 1;
776
777
  action.play();
777
778
 
779
+ window.requestAnimationFrame(() => AnimationUtils.testIfRootCanAnimate(action));
780
+
778
781
  if (this.rootMotionHandler) {
779
782
  this.rootMotionHandler.onStart(action);
780
783
  }
@@ -1,4 +1,5 @@
1
1
  import { CameraHelper, Color, DirectionalLight, DirectionalLightHelper, Light as ThreeLight, OrthographicCamera, PointLight, SpotLight, Vector3 } from "three";
2
+ import { get } from "three-mesh-ui/build/types/core/DefaultValues.js";
2
3
 
3
4
  import { serializable } from "../engine/engine_serialization_decorator.js";
4
5
  import { FrameEvent } from "../engine/engine_setup.js";
@@ -82,25 +83,64 @@ enum LightShadows {
82
83
  export class Light extends Behaviour implements ILight {
83
84
 
84
85
  /**
85
- * The type of light (spot, directional, point, etc.)
86
+ * The type of light (spot, directional, point, etc.)
87
+ * Can not be changed at runtime.
86
88
  */
87
89
  @serializable()
88
90
  private type: LightType = 0;
89
91
 
90
92
  /**
91
- * The maximum distance the light affects
93
+ * The maximum distance the light affects.
94
+ * Only applicable for spot and point lights.
92
95
  */
93
- public range: number = 1;
94
-
96
+ @serializable()
97
+ get range(): number {
98
+ return this._range;
99
+ }
100
+ set range(value: number) {
101
+ this._range = value;
102
+ if (this.light && (this.light.type === "SpotLight" || this.light.type === "PointLight") && ("distance" in this.light)) {
103
+ this.light.distance = value;
104
+ }
105
+ }
106
+ private _range: number = 1;
107
+
95
108
  /**
96
- * The full outer angle of the spotlight cone in degrees
109
+ * The full outer angle of the spotlight cone in degrees.
110
+ * Only applicable for spot lights.
97
111
  */
98
- public spotAngle: number = 1;
99
-
112
+ @serializable()
113
+ get spotAngle(): number {
114
+ return this._spotAngle;
115
+ }
116
+ set spotAngle(value: number) {
117
+ this._spotAngle = value;
118
+ if (this.light && this.light.type === "SpotLight" && ("angle" in this.light)) {
119
+ (this.light as SpotLight).angle = toRadians(value / 2);
120
+ }
121
+ }
122
+ private _spotAngle: number = 30;
123
+
124
+
100
125
  /**
101
- * The angle of the inner cone in degrees for soft-edge spotlights
126
+ * The angle of the inner cone in degrees for soft-edge spotlights.
127
+ * Must be less than or equal to the outer spot angle.
128
+ * Only applicable for spot lights.
102
129
  */
103
- public innerSpotAngle: number = 1;
130
+ @serializable()
131
+ get innerSpotAngle(): number {
132
+ return this._innerSpotAngle;
133
+ }
134
+ set innerSpotAngle(value: number) {
135
+ this._innerSpotAngle = value;
136
+ if (this.light && this.light.type === "SpotLight" && ("penumbra" in this.light)) {
137
+ const outerAngle = this.spotAngle;
138
+ const innerAngle = value;
139
+ const penumbra = 1 - (toRadians(innerAngle / 2) / toRadians(outerAngle / 2));
140
+ (this.light as SpotLight).penumbra = penumbra;
141
+ }
142
+ }
143
+ private _innerSpotAngle: number = 10;
104
144
 
105
145
  /**
106
146
  * The color of the light
@@ -194,14 +234,7 @@ export class Light extends Behaviour implements ILight {
194
234
  set intensity(val: number) {
195
235
  this._intensity = val;
196
236
  if (this.light) {
197
- let factor: number = 1;
198
- if (this.context.isInXR && this._webARRoot) {
199
- const scaleFactor = this._webARRoot?.arScale;
200
- if (typeof scaleFactor === "number" && scaleFactor > 0) {
201
- factor /= scaleFactor;
202
- }
203
- }
204
- this.light.intensity = val * factor;
237
+ this.light.intensity = val;
205
238
  }
206
239
  if (debug) console.log("Set light intensity to " + this._intensity, val, this)
207
240
  }
@@ -297,10 +330,6 @@ export class Light extends Behaviour implements ILight {
297
330
  return vec;
298
331
  }
299
332
 
300
- // public updateIntensity() {
301
- // this.intensity = this._intensity;
302
- // }
303
-
304
333
  awake() {
305
334
  this.color = new Color(this.color ?? 0xffffff);
306
335
  if (debug) console.log(this.name, this);
@@ -334,27 +363,6 @@ export class Light extends Behaviour implements ILight {
334
363
  }
335
364
  }
336
365
 
337
- private _webXRStartedListener?: Function;
338
- private _webXREndedListener?: Function;
339
- private _webARRoot?: WebARSessionRoot;
340
-
341
- onEnterXR(_args: NeedleXREventArgs): void {
342
- this._webARRoot = GameObject.getComponentInParent(this.gameObject, WebARSessionRoot) ?? undefined;
343
- // this.startCoroutine(this._updateLightIntensityInARRoutine());
344
- }
345
-
346
- // private *_updateLightIntensityInARRoutine() {
347
- // while (this.context.isInAR) {
348
- // yield;
349
- // // this.updateIntensity();
350
- // for (let i = 0; i < 30; i++) yield;
351
- // }
352
- // }
353
-
354
- onLeaveXR(_args: NeedleXREventArgs): void {
355
- // this.updateIntensity();
356
- }
357
-
358
366
  /**
359
367
  * Creates the appropriate three.js light based on the configured light type
360
368
  * and applies all settings like shadows, intensity, and color.
@@ -551,8 +551,6 @@ export class WebXR extends Behaviour {
551
551
  * and device capabilities. Handles creating AR, VR, QuickLook buttons and utility buttons like QR codes.
552
552
  */
553
553
  private handleCreatingHTML() {
554
- const xrButtonsPriority = 50;
555
-
556
554
  if (this.createARButton || this.createVRButton || this.useQuicklookExport) {
557
555
  // Quicklook / iOS
558
556
  if ((DeviceUtilities.isiOS() && DeviceUtilities.isSafari()) || debugQuicklook) {
@@ -560,18 +558,18 @@ export class WebXR extends Behaviour {
560
558
  const usdzExporter = GameObject.findObjectOfType(USDZExporter);
561
559
  if (!usdzExporter || (usdzExporter && usdzExporter.allowCreateQuicklookButton)) {
562
560
  const button = this.getButtonsFactory().createQuicklookButton();
563
- this.addButton(button, xrButtonsPriority);
561
+ this.addButton(button);
564
562
  }
565
563
  }
566
564
  }
567
565
  // WebXR
568
566
  if (this.createARButton) {
569
567
  const arbutton = this.getButtonsFactory().createARButton();
570
- this.addButton(arbutton, xrButtonsPriority);
568
+ this.addButton(arbutton);
571
569
  }
572
570
  if (this.createVRButton) {
573
571
  const vrbutton = this.getButtonsFactory().createVRButton();
574
- this.addButton(vrbutton, xrButtonsPriority);
572
+ this.addButton(vrbutton);
575
573
  }
576
574
  }
577
575
 
@@ -579,7 +577,7 @@ export class WebXR extends Behaviour {
579
577
  NeedleXRSession.isVRSupported().then(supported => {
580
578
  if (!supported) {
581
579
  const button = this.getButtonsFactory().createSendToQuestButton();
582
- this.addButton(button, xrButtonsPriority);
580
+ this.addButton(button);
583
581
  }
584
582
  });
585
583
  }
@@ -592,7 +590,7 @@ export class WebXR extends Behaviour {
592
590
  }
593
591
  else if (!DeviceUtilities.isMobileDevice()) {
594
592
  const qrCode = ButtonsFactory.getOrCreate().createQRCode();
595
- this.addButton(qrCode, xrButtonsPriority);
593
+ this.addButton(qrCode,);
596
594
  }
597
595
  }
598
596
  }
@@ -607,9 +605,8 @@ export class WebXR extends Behaviour {
607
605
  * @param button The HTML element to add
608
606
  * @param priority The button's priority value (lower numbers appear first)
609
607
  */
610
- private addButton(button: HTMLElement, priority: number) {
608
+ private addButton(button: HTMLElement) {
611
609
  this._buttons.push(button);
612
- button.setAttribute("priority", priority.toString());
613
610
  this.context.menu.appendChild(button);
614
611
  }
615
612
 
@@ -1,7 +1,7 @@
1
1
  import { ImageBitmapLoader, Matrix4, Object3D, Quaternion, Vector3 } from "three";
2
2
  import { Object3DEventMap } from "three";
3
3
 
4
- import { isDevEnvironment, showBalloonWarning } from "../../engine/debug/index.js";
4
+ import { isDevEnvironment, showBalloonMessage, showBalloonWarning } from "../../engine/debug/index.js";
5
5
  import { AssetReference } from "../../engine/engine_addressables.js";
6
6
  import { Context } from "../../engine/engine_context.js";
7
7
  import { serializable } from "../../engine/engine_serialization.js";
@@ -18,6 +18,8 @@ import { Renderer } from "../Renderer.js";
18
18
 
19
19
  const debug = getParam("debugimagetracking");
20
20
 
21
+ // #region WebXRTrackedImage
22
+
21
23
  export class WebXRTrackedImage {
22
24
 
23
25
  get url(): string { return this._trackedImage.image ?? ""; }
@@ -100,6 +102,10 @@ declare type InitialTrackedObjectState = {
100
102
  parent: Object3D | undefined | null;
101
103
  matrix: Matrix4;
102
104
  }
105
+
106
+
107
+ // #region Model
108
+
103
109
  /**
104
110
  * WebXRImageTracking allows you to track images in the real world and place objects on top of them.
105
111
  * This component is only available in WebXR sessions.
@@ -171,6 +177,8 @@ export class WebXRImageTrackingModel {
171
177
  }
172
178
  }
173
179
 
180
+
181
+ // #region USDZ Extension
174
182
  class ImageTrackingExtension implements IUSDExporterExtension {
175
183
 
176
184
 
@@ -289,6 +297,7 @@ class ImageTrackingExtension implements IUSDExporterExtension {
289
297
  }
290
298
 
291
299
 
300
+ // #region Tracking Component
292
301
  /**
293
302
  * Add this component to a object to enable image tracking in WebXR sessions.
294
303
  *
@@ -394,7 +403,7 @@ export class WebXRImageTracking extends Behaviour {
394
403
  if (!args.optionalFeatures.includes("image-tracking"))
395
404
  args.optionalFeatures.push("image-tracking");
396
405
 
397
- args.trackedImages = [];
406
+ if(!args.trackedImages) args.trackedImages = [];
398
407
  for (const trackedImage of this.trackedImages) {
399
408
  if (trackedImage.image?.length && trackedImage.widthInMeters > 0) {
400
409
  const bitmap = _imageElements.get(trackedImage.image);
@@ -533,6 +542,7 @@ export class WebXRImageTracking extends Behaviour {
533
542
  if (trackedImage.model === key) {
534
543
  // Make sure to keep the object visible if it's marked as static OR is tracked OR was tracked very recently (e.g. low framerate or bad tracking on device)
535
544
  const timeSinceLastTracking = Date.now() - value.lastTrackingTime;
545
+ if(debug) showBalloonMessage(key.image + ", State: " + trackedImage.state + (key.imageDoesNotMove ? " (static)" : "") + (timeSinceLastTracking <= hysteresis ? " (hysteresis)" : ""));
536
546
  if (key.imageDoesNotMove || trackedImage.state === "tracked" || timeSinceLastTracking <= hysteresis) {
537
547
  found = true;
538
548
  break;