@needle-tools/engine 4.4.0-ci.1 → 4.4.2

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 (147) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/dist/assets/generateMeshBVH.worker-b7788939.js +25 -0
  3. package/dist/needle-engine.bundle.js +7043 -6766
  4. package/dist/needle-engine.bundle.light.js +7205 -6928
  5. package/dist/needle-engine.bundle.light.min.js +169 -139
  6. package/dist/needle-engine.bundle.light.umd.cjs +173 -143
  7. package/dist/needle-engine.bundle.min.js +169 -139
  8. package/dist/needle-engine.bundle.umd.cjs +172 -142
  9. package/dist/needle-engine.js +468 -467
  10. package/dist/needle-engine.light.js +468 -467
  11. package/dist/needle-engine.light.min.js +1 -1
  12. package/dist/needle-engine.light.umd.cjs +1 -1
  13. package/dist/needle-engine.min.js +1 -1
  14. package/dist/needle-engine.umd.cjs +1 -1
  15. package/dist/vendor.js +5108 -5122
  16. package/dist/vendor.light.js +5108 -5122
  17. package/dist/vendor.light.min.js +84 -84
  18. package/dist/vendor.light.umd.cjs +78 -78
  19. package/dist/vendor.min.js +84 -84
  20. package/dist/vendor.umd.cjs +78 -78
  21. package/lib/engine/codegen/register_types.js +2 -0
  22. package/lib/engine/codegen/register_types.js.map +1 -1
  23. package/lib/engine/engine_addressables.js.map +1 -1
  24. package/lib/engine/engine_components.js +3 -1
  25. package/lib/engine/engine_components.js.map +1 -1
  26. package/lib/engine/engine_context.d.ts +141 -14
  27. package/lib/engine/engine_context.js +164 -26
  28. package/lib/engine/engine_context.js.map +1 -1
  29. package/lib/engine/engine_element.js +12 -10
  30. package/lib/engine/engine_element.js.map +1 -1
  31. package/lib/engine/engine_gameobject.js +5 -0
  32. package/lib/engine/engine_gameobject.js.map +1 -1
  33. package/lib/engine/engine_license.d.ts +2 -0
  34. package/lib/engine/engine_license.js +103 -62
  35. package/lib/engine/engine_license.js.map +1 -1
  36. package/lib/engine/engine_networking_blob.js +40 -24
  37. package/lib/engine/engine_networking_blob.js.map +1 -1
  38. package/lib/engine/engine_physics_rapier.js +10 -9
  39. package/lib/engine/engine_physics_rapier.js.map +1 -1
  40. package/lib/engine/engine_serialization_core.js +6 -2
  41. package/lib/engine/engine_serialization_core.js.map +1 -1
  42. package/lib/engine/engine_utils_screenshot.js +1 -1
  43. package/lib/engine/engine_utils_screenshot.js.map +1 -1
  44. package/lib/engine/js-extensions/RGBAColor.d.ts +1 -0
  45. package/lib/engine/js-extensions/RGBAColor.js +56 -7
  46. package/lib/engine/js-extensions/RGBAColor.js.map +1 -1
  47. package/lib/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js +4 -3
  48. package/lib/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js.map +1 -1
  49. package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js +6 -6
  50. package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js.map +1 -1
  51. package/lib/engine/webcomponents/needle menu/needle-menu.d.ts +4 -0
  52. package/lib/engine/webcomponents/needle menu/needle-menu.js +13 -2
  53. package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
  54. package/lib/engine/xr/NeedleXRController.js +2 -3
  55. package/lib/engine/xr/NeedleXRController.js.map +1 -1
  56. package/lib/engine/xr/NeedleXRSession.js +12 -12
  57. package/lib/engine/xr/NeedleXRSession.js.map +1 -1
  58. package/lib/engine-components/AudioSource.js +7 -0
  59. package/lib/engine-components/AudioSource.js.map +1 -1
  60. package/lib/engine-components/Camera.js +18 -12
  61. package/lib/engine-components/Camera.js.map +1 -1
  62. package/lib/engine-components/CameraUtils.js +8 -14
  63. package/lib/engine-components/CameraUtils.js.map +1 -1
  64. package/lib/engine-components/GroundProjection.js +1 -1
  65. package/lib/engine-components/GroundProjection.js.map +1 -1
  66. package/lib/engine-components/NeedleMenu.js +1 -1
  67. package/lib/engine-components/NeedleMenu.js.map +1 -1
  68. package/lib/engine-components/OrbitControls.js +3 -1
  69. package/lib/engine-components/OrbitControls.js.map +1 -1
  70. package/lib/engine-components/ReflectionProbe.d.ts +1 -0
  71. package/lib/engine-components/ReflectionProbe.js +16 -9
  72. package/lib/engine-components/ReflectionProbe.js.map +1 -1
  73. package/lib/engine-components/SceneSwitcher.js +28 -7
  74. package/lib/engine-components/SceneSwitcher.js.map +1 -1
  75. package/lib/engine-components/SyncedTransform.d.ts +6 -0
  76. package/lib/engine-components/SyncedTransform.js +10 -5
  77. package/lib/engine-components/SyncedTransform.js.map +1 -1
  78. package/lib/engine-components/codegen/components.d.ts +1 -0
  79. package/lib/engine-components/codegen/components.js +1 -0
  80. package/lib/engine-components/codegen/components.js.map +1 -1
  81. package/lib/engine-components/export/usdz/extensions/USDZUI.js +2 -1
  82. package/lib/engine-components/export/usdz/extensions/USDZUI.js.map +1 -1
  83. package/lib/engine-components/ui/BaseUIComponent.d.ts +0 -1
  84. package/lib/engine-components/ui/BaseUIComponent.js +1 -1
  85. package/lib/engine-components/ui/BaseUIComponent.js.map +1 -1
  86. package/lib/engine-components/ui/EventSystem.js +1 -1
  87. package/lib/engine-components/ui/EventSystem.js.map +1 -1
  88. package/lib/engine-components/ui/Graphic.js +1 -0
  89. package/lib/engine-components/ui/Graphic.js.map +1 -1
  90. package/lib/engine-components/ui/RaycastUtils.js +1 -1
  91. package/lib/engine-components/ui/RaycastUtils.js.map +1 -1
  92. package/lib/engine-components/ui/RectTransform.d.ts +2 -2
  93. package/lib/engine-components/ui/RectTransform.js +9 -6
  94. package/lib/engine-components/ui/RectTransform.js.map +1 -1
  95. package/lib/engine-components/ui/Symbols.d.ts +1 -0
  96. package/lib/engine-components/ui/Symbols.js +2 -0
  97. package/lib/engine-components/ui/Symbols.js.map +1 -0
  98. package/lib/engine-components/ui/Utils.js +1 -1
  99. package/lib/engine-components/ui/Utils.js.map +1 -1
  100. package/lib/engine-components/utils/EnvironmentScene.d.ts +1 -1
  101. package/lib/engine-components/utils/EnvironmentScene.js +1 -1
  102. package/lib/engine-components/utils/EnvironmentScene.js.map +1 -1
  103. package/package.json +3 -3
  104. package/plugins/common/license.js +115 -27
  105. package/plugins/types/userconfig.d.ts +8 -0
  106. package/plugins/vite/build-pipeline.js +1 -1
  107. package/plugins/vite/defines.js +3 -1
  108. package/plugins/vite/dependencies.js +23 -4
  109. package/plugins/vite/facebook-instant-games.js +7 -4
  110. package/plugins/vite/index.js +1 -1
  111. package/plugins/vite/license.js +2 -1
  112. package/src/engine/codegen/register_types.ts +2 -0
  113. package/src/engine/engine_addressables.ts +3 -2
  114. package/src/engine/engine_components.ts +2 -1
  115. package/src/engine/engine_context.ts +169 -33
  116. package/src/engine/engine_element.ts +10 -9
  117. package/src/engine/engine_gameobject.ts +7 -0
  118. package/src/engine/engine_license.ts +116 -67
  119. package/src/engine/engine_networking_blob.ts +47 -26
  120. package/src/engine/engine_physics_rapier.ts +10 -12
  121. package/src/engine/engine_serialization_core.ts +6 -1
  122. package/src/engine/engine_utils_screenshot.ts +1 -1
  123. package/src/engine/js-extensions/RGBAColor.ts +59 -8
  124. package/src/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js +6 -6
  125. package/src/engine/webcomponents/needle menu/needle-menu-spatial.ts +6 -6
  126. package/src/engine/webcomponents/needle menu/needle-menu.ts +13 -2
  127. package/src/engine/xr/NeedleXRController.ts +2 -3
  128. package/src/engine/xr/NeedleXRSession.ts +12 -12
  129. package/src/engine-components/AudioSource.ts +8 -3
  130. package/src/engine-components/Camera.ts +34 -22
  131. package/src/engine-components/CameraUtils.ts +8 -16
  132. package/src/engine-components/GroundProjection.ts +1 -1
  133. package/src/engine-components/NeedleMenu.ts +1 -1
  134. package/src/engine-components/OrbitControls.ts +2 -1
  135. package/src/engine-components/ReflectionProbe.ts +15 -8
  136. package/src/engine-components/SceneSwitcher.ts +28 -11
  137. package/src/engine-components/SyncedTransform.ts +11 -6
  138. package/src/engine-components/codegen/components.ts +1 -0
  139. package/src/engine-components/export/usdz/extensions/USDZUI.ts +2 -2
  140. package/src/engine-components/ui/BaseUIComponent.ts +1 -1
  141. package/src/engine-components/ui/EventSystem.ts +1 -1
  142. package/src/engine-components/ui/Graphic.ts +1 -1
  143. package/src/engine-components/ui/RaycastUtils.ts +1 -1
  144. package/src/engine-components/ui/RectTransform.ts +10 -7
  145. package/src/engine-components/ui/Symbols.ts +2 -0
  146. package/src/engine-components/ui/Utils.ts +2 -1
  147. package/src/engine-components/utils/EnvironmentScene.ts +1 -1
@@ -444,7 +444,7 @@ export class NeedleXRSession implements INeedleXRSession {
444
444
  if (!context) context = ContextRegistry.All[0] as Context;
445
445
  if (!context) throw new Error("No Needle Engine Context found");
446
446
 
447
- performance.mark('NeedleXRSession start');
447
+ //performance.mark('NeedleXRSession start');
448
448
 
449
449
  // setup session init args, make sure we have default values
450
450
  if (!init) init = {};
@@ -534,8 +534,8 @@ export class NeedleXRSession implements INeedleXRSession {
534
534
  return null;
535
535
  }
536
536
  const session = this.setSession(mode, newSession, init, context);
537
- performance.mark('NeedleXRSession end');
538
- performance.measure('NeedleXRSession Startup', 'NeedleXRSession start', 'NeedleXRSession end');
537
+ //performance.mark('NeedleXRSession end');
538
+ //performance.measure('NeedleXRSession Startup', 'NeedleXRSession start', 'NeedleXRSession end');
539
539
  return session;
540
540
  }
541
541
 
@@ -884,7 +884,7 @@ export class NeedleXRSession implements INeedleXRSession {
884
884
  /** the initialization arguments */
885
885
  init: XRSessionInit,
886
886
  }) {
887
- performance.mark(measure_SessionStartedMarker);
887
+ //performance.mark(measure_SessionStartedMarker);
888
888
 
889
889
  saveSessionInfo(mode, extra.init);
890
890
  this.session = session;
@@ -1128,8 +1128,8 @@ export class NeedleXRSession implements INeedleXRSession {
1128
1128
 
1129
1129
  enableSpatialConsole(false);
1130
1130
 
1131
- performance.mark(measure_SessionEndedMarker);
1132
- performance.measure('NeedleXRSession', measure_SessionStartedMarker, measure_SessionEndedMarker);
1131
+ //performance.mark(measure_SessionEndedMarker);
1132
+ //performance.measure('NeedleXRSession', measure_SessionStartedMarker, measure_SessionEndedMarker);
1133
1133
  };
1134
1134
 
1135
1135
  private _didStart: boolean = false;
@@ -1139,7 +1139,7 @@ export class NeedleXRSession implements INeedleXRSession {
1139
1139
  const frame = context.xrFrame;
1140
1140
  if (!frame) return;
1141
1141
 
1142
- performance.mark('NeedleXRSession onBefore start');
1142
+ //performance.mark('NeedleXRSession onBefore start');
1143
1143
 
1144
1144
  // ensure that XR is always set to a running session
1145
1145
  this.context.xr = this;
@@ -1291,7 +1291,7 @@ export class NeedleXRSession implements INeedleXRSession {
1291
1291
  console.error("XRControllers are not added but inputSources are present");
1292
1292
  }
1293
1293
 
1294
- performance.mark('NeedleXRSession update scripts start');
1294
+ //performance.mark('NeedleXRSession update scripts start');
1295
1295
  // invoke update on all scripts
1296
1296
  for (const script of this._xr_update_scripts) {
1297
1297
  if (script.destroyed === true) {
@@ -1304,8 +1304,8 @@ export class NeedleXRSession implements INeedleXRSession {
1304
1304
  }
1305
1305
  if (script.onUpdateXR) script.onUpdateXR(args);
1306
1306
  }
1307
- performance.mark('NeedleXRSession update scripts end');
1308
- performance.measure('NeedleXRSession update scripts', 'NeedleXRSession update scripts start', 'NeedleXRSession update scripts end');
1307
+ //performance.mark('NeedleXRSession update scripts end');
1308
+ //performance.measure('NeedleXRSession update scripts', 'NeedleXRSession update scripts start', 'NeedleXRSession update scripts end');
1309
1309
 
1310
1310
  // handle inactive scripts
1311
1311
  this.handleInactiveScripts();
@@ -1326,8 +1326,8 @@ export class NeedleXRSession implements INeedleXRSession {
1326
1326
  this.sync?.onUpdate(this);
1327
1327
 
1328
1328
  this.onRenderDebug();
1329
- performance.mark('NeedleXRSession onBefore end');
1330
- performance.measure('NE XR frame', 'NeedleXRSession onBefore start', 'NeedleXRSession onBefore end');
1329
+ //performance.mark('NeedleXRSession onBefore end');
1330
+ //performance.measure('NE XR frame', 'NeedleXRSession onBefore start', 'NeedleXRSession onBefore end');
1331
1331
  }
1332
1332
 
1333
1333
  private onRenderDebug() {
@@ -409,7 +409,12 @@ export class AudioSource extends Behaviour {
409
409
  this.sound?.setVolume(this.volume);
410
410
  }
411
411
 
412
- private createAudio = (buffer?: AudioBuffer) => {
412
+ private createAudio = (buffer?: AudioBuffer) => {
413
+ if(this.destroyed) {
414
+ if(debug) console.warn("AudioSource destroyed, not creating audio", this.name);
415
+ return;
416
+ }
417
+
413
418
  if (debug) console.log("AudioBuffer finished loading", buffer);
414
419
 
415
420
  const sound = this.Sound;
@@ -503,9 +508,9 @@ export class AudioSource extends Behaviour {
503
508
  if (debug)
504
509
  console.log("load audio", clip);
505
510
  const buffer = await this.audioLoader.loadAsync(clip).catch(console.error);
511
+ if(this.destroyed) return;
506
512
  this._lastClipStartedLoading = null;
507
- if (buffer)
508
- this.createAudio(buffer);
513
+ if (buffer) this.createAudio(buffer);
509
514
  }
510
515
  else console.warn("Unsupported audio clip type", clip)
511
516
  }
@@ -66,7 +66,7 @@ export class Camera extends Behaviour implements ICamera {
66
66
  }
67
67
  }
68
68
  }
69
-
69
+
70
70
  /**
71
71
  * Gets or sets the camera's field of view in degrees for perspective cameras.
72
72
  * When set, automatically updates the projection matrix.
@@ -167,13 +167,13 @@ export class Camera extends Behaviour implements ICamera {
167
167
  this._clearFlags = val;
168
168
  this.applyClearFlagsIfIsActiveCamera();
169
169
  }
170
-
170
+
171
171
  /**
172
172
  * Determines if the camera should use orthographic projection instead of perspective.
173
173
  */
174
174
  @serializable()
175
175
  public orthographic: boolean = false;
176
-
176
+
177
177
  /**
178
178
  * The size of the orthographic camera's view volume when in orthographic mode.
179
179
  * Larger values show more of the scene.
@@ -331,7 +331,7 @@ export class Camera extends Behaviour implements ICamera {
331
331
  public get cam(): PerspectiveCamera | OrthographicCamera {
332
332
  return this.threeCamera;
333
333
  }
334
-
334
+
335
335
  /**
336
336
  * Gets the three.js camera object. Creates one if it doesn't exist yet.
337
337
  * @returns {PerspectiveCamera | OrthographicCamera} The three.js camera object
@@ -344,7 +344,7 @@ export class Camera extends Behaviour implements ICamera {
344
344
 
345
345
  private static _origin: Vector3 = new Vector3();
346
346
  private static _direction: Vector3 = new Vector3();
347
-
347
+
348
348
  /**
349
349
  * Converts screen coordinates to a ray in world space.
350
350
  * Useful for implementing picking or raycasting from screen to world.
@@ -376,7 +376,7 @@ export class Camera extends Behaviour implements ICamera {
376
376
  }
377
377
 
378
378
  private _frustum?: Frustum;
379
-
379
+
380
380
  /**
381
381
  * Gets the camera's view frustum for culling and visibility checks.
382
382
  * Creates the frustum if it doesn't exist and returns it.
@@ -390,7 +390,7 @@ export class Camera extends Behaviour implements ICamera {
390
390
  }
391
391
  return this._frustum;
392
392
  }
393
-
393
+
394
394
  /**
395
395
  * Forces an update of the camera's frustum.
396
396
  * This is automatically called every frame in onBeforeRender.
@@ -399,7 +399,7 @@ export class Camera extends Behaviour implements ICamera {
399
399
  if (!this._frustum) this._frustum = new Frustum();
400
400
  this._frustum.setFromProjectionMatrix(this.getProjectionScreenMatrix(this._projScreenMatrix, true), this.context.renderer.coordinateSystem);
401
401
  }
402
-
402
+
403
403
  /**
404
404
  * Gets this camera's projection-screen matrix.
405
405
  *
@@ -556,13 +556,16 @@ export class Camera extends Behaviour implements ICamera {
556
556
  this.fieldOfView = this._fov;
557
557
 
558
558
  if (debug) {
559
- const msg = `Camera \"${this.name}\" clear flags: ${ClearFlags[this._clearFlags]}`;
559
+ const msg = `[Camera] Apply ClearFlags: ${ClearFlags[this._clearFlags]} - \"${this.name}\"`;
560
560
  console.debug(msg);
561
561
  }
562
+
563
+ const hasBackgroundImageOrColorAttribute = this.context.domElement.getAttribute("background-image") || this.context.domElement.getAttribute("background-color") || this.context.domElement.getAttribute("skybox-image");
564
+
562
565
  switch (this._clearFlags) {
563
566
  case ClearFlags.None:
564
567
  return;
565
-
568
+
566
569
  case ClearFlags.Skybox:
567
570
  if (Camera.backgroundShouldBeTransparent(this.context)) {
568
571
  if (!this.ARBackgroundAlpha || this.ARBackgroundAlpha < 0.001) {
@@ -577,18 +580,21 @@ export class Camera extends Behaviour implements ICamera {
577
580
  this.applySceneSkybox();
578
581
 
579
582
  // set background blurriness and intensity
580
- if (this._backgroundBlurriness !== undefined)
583
+ if (this._backgroundBlurriness !== undefined && !this.context.domElement.getAttribute("background-blurriness"))
581
584
  this.context.scene.backgroundBlurriness = this._backgroundBlurriness;
582
585
  else if (debug) console.warn(`Camera \"${this.name}\" has no background blurriness`)
583
- if (this._backgroundIntensity !== undefined)
586
+
587
+ if (this._backgroundIntensity !== undefined && !this.context.domElement.getAttribute("background-intensity"))
584
588
  this.context.scene.backgroundIntensity = this._backgroundIntensity;
585
- if (this._backgroundRotation !== undefined)
589
+
590
+ if (this._backgroundRotation !== undefined && !this.context.domElement.getAttribute("background-rotation"))
586
591
  this.context.scene.backgroundRotation = this._backgroundRotation;
592
+
587
593
  else if (debug) console.warn(`Camera \"${this.name}\" has no background intensity`)
588
594
 
589
595
  break;
590
596
  case ClearFlags.SolidColor:
591
- if (this._backgroundColor) {
597
+ if (this._backgroundColor && !hasBackgroundImageOrColorAttribute) {
592
598
  let alpha = this._backgroundColor.alpha;
593
599
  // when in WebXR use ar background alpha override or set to 0
594
600
  if (Camera.backgroundShouldBeTransparent(this.context)) {
@@ -602,13 +608,15 @@ export class Camera extends Behaviour implements ICamera {
602
608
  this.context.renderer.setClearColor(this._backgroundColor, alpha);
603
609
  }
604
610
  }
605
- else {
606
- if (debug) console.warn(`Camera \"${this.name}\" has no background color`, this)
611
+ else if (!this._backgroundColor) {
612
+ if (debug) console.warn(`[Camera] has no background color \"${this.name}\" `)
607
613
  }
608
614
  break;
609
615
  case ClearFlags.Uninitialized:
610
- this.context.scene.background = null
611
- this.context.renderer.setClearColor(0x000000, 0);
616
+ if (!hasBackgroundImageOrColorAttribute) {
617
+ this.context.scene.background = null
618
+ this.context.renderer.setClearColor(0x000000, 0);
619
+ }
612
620
  break;
613
621
  }
614
622
  }
@@ -685,10 +693,14 @@ class CameraSkybox {
685
693
  }
686
694
  }
687
695
  else if (this.context.scene.background !== this._skybox) {
688
- if (debug)
689
- console.log(`Camera \"${this._camera.name}\" set skybox`, this._camera, this._skybox);
690
- this._skybox.mapping = EquirectangularReflectionMapping;
691
- this.context.scene.background = this._skybox;
696
+
697
+ const hasBackgroundAttribute = this.context.domElement.getAttribute("background-image") || this.context.domElement.getAttribute("background-color") || this.context.domElement.getAttribute("skybox-image");
698
+
699
+ if (debug) console.debug(`[Camera] Apply Skybox ${this._skybox?.name} ${hasBackgroundAttribute} - \"${this._camera.name}\"`);
700
+ if (!hasBackgroundAttribute?.length) {
701
+ this._skybox.mapping = EquirectangularReflectionMapping;
702
+ this.context.scene.background = this._skybox;
703
+ }
692
704
  }
693
705
  }
694
706
  }
@@ -5,13 +5,11 @@ import { addNewComponent, getOrAddComponent } from "../engine/engine_components.
5
5
  import { Context } from "../engine/engine_context.js";
6
6
  import { ContextEvent, ContextRegistry } from "../engine/engine_context_registry.js";
7
7
  import { NeedleEngineHTMLElement } from "../engine/engine_element.js";
8
- import { createFlatTexture, createTrilightTexture } from "../engine/engine_shaders.js";
9
8
  import type { ICamera, IContext } from "../engine/engine_types.js";
10
9
  import { getParam } from "../engine/engine_utils.js";
11
- import { RGBAColor } from "../engine/js-extensions/index.js";
12
10
  import { Camera, ClearFlags } from "./Camera.js";
13
11
  import { OrbitControls } from "./OrbitControls.js";
14
- import EnvironmentScene from "./utils/EnvironmentScene.js";
12
+ import { EnvironmentScene } from "./utils/EnvironmentScene.js";
15
13
 
16
14
  const debug = getParam("debugmissingcamera");
17
15
 
@@ -48,26 +46,20 @@ ContextRegistry.registerCallback(ContextEvent.MissingCamera, (evt) => {
48
46
  else {
49
47
  camInstance.clearFlags = ClearFlags.SolidColor;
50
48
 
51
- let backgroundColor = "#efefef";
52
- if(typeof window !== undefined && (window.matchMedia('(prefers-color-scheme: dark)').matches)) {
53
- backgroundColor = "#1f1f1f";
49
+ // Don't set the background color if the user set a background color in the <needle-engine> element
50
+ if (!evt.context.domElement.getAttribute("background-color")) {
51
+ let backgroundColor = "#efefef";
52
+ if (typeof window !== undefined && (window.matchMedia('(prefers-color-scheme: dark)').matches)) {
53
+ backgroundColor = "#1f1f1f";
54
+ }
55
+ scene.background = new Color(backgroundColor); // dont set it on the camera because this might be controlled from "background-color" attribute which is set on the scene directly. If the camera has a background color, it will override the scene's background color
54
56
  }
55
- scene.background = new Color(backgroundColor); // dont set it on the camera because this might be controlled from "background-color" attribute which is set on the scene directly. If the camera has a background color, it will override the scene's background color
56
57
 
57
58
  // Generate a default environment map if none is set
58
59
  if (!scene.environment) {
59
- // const backgroundColorAttribute = evt.context.domElement.getAttribute("background-color") ?? "#fff";
60
- // const backgroundColor = new Color(backgroundColorAttribute);
61
60
  const pmremGenerator = new PMREMGenerator(evt.context.renderer);
62
61
  const env = new EnvironmentScene("neutral");
63
- // const background = scene.background;
64
- // const col0 = new Color(.1, .1, .1);
65
- // const col1 = new Color(.3, .3, .3);
66
- // const col2 = new Color(1, 1, 1);
67
- // const envmap = createTrilightTexture(col0, col1, col2, 32, 32);
68
- // scene.background = envmap;
69
62
  scene.environment = pmremGenerator.fromScene(env, .025).texture;
70
- // scene.background = background;
71
63
  }
72
64
  }
73
65
 
@@ -249,7 +249,7 @@ export class GroundProjectedEnv extends Behaviour {
249
249
  });
250
250
  this._blurrynessShader.depthWrite = false;
251
251
  this._blurrynessShader.uniforms.map.value = texture;
252
- this._blurrynessShader.uniforms.blurriness.value = 1;//blurriness;
252
+ this._blurrynessShader.uniforms.blurriness.value = blurriness;
253
253
  this._lastBlurriness = blurriness;
254
254
  texture.needsUpdate = true;
255
255
 
@@ -24,7 +24,7 @@ export class NeedleMenu extends Behaviour {
24
24
  * Controls the visibility of the Needle logo in the menu (requires PRO license)
25
25
  */
26
26
  @serializable()
27
- showNeedleLogo: boolean = true;
27
+ showNeedleLogo: boolean = false;
28
28
 
29
29
  /**
30
30
  * When enabled, displays the menu in VR/AR mode when the user looks up
@@ -506,6 +506,7 @@ export class OrbitControls extends Behaviour implements ICameraController {
506
506
  // if the look at target is set to the camera position we can't move at all anymore
507
507
  const distanceToCenter = Math.max(.01, worldPosition.length());
508
508
  const forward = new Vector3(0, 0, -distanceToCenter).applyMatrix4(camGo.threeCamera.matrixWorld);
509
+ if(debug) Gizmos.DrawLine(worldPosition, forward, 0x5555ff, 10)
509
510
  this.setLookTargetPosition(forward, true);
510
511
  }
511
512
  if (!this.setLookTargetFromConstraint()) {
@@ -682,7 +683,7 @@ export class OrbitControls extends Behaviour implements ICameraController {
682
683
  }
683
684
  const worldPosition = source.worldPosition;
684
685
  const forward = source.worldForward;
685
- const ray = new Ray(worldPosition, forward.multiplyScalar(-1));
686
+ const ray = new Ray(worldPosition, forward);
686
687
 
687
688
  if (debug) Gizmos.DrawRay(ray.origin, ray.direction, 0xff0000, 10);
688
689
 
@@ -1,5 +1,6 @@
1
- import { EquirectangularReflectionMapping, Material, MeshBasicMaterial, Object3D, SRGBColorSpace, Texture, Vector3 } from "three";
1
+ import { EquirectangularReflectionMapping, LinearSRGBColorSpace, Material, MeshBasicMaterial, Object3D, SRGBColorSpace, Texture, Vector3 } from "three";
2
2
 
3
+ import { isDevEnvironment, showBalloonWarning } from "../engine/debug/index.js";
3
4
  import { serializable } from "../engine/engine_serialization.js";
4
5
  import { Context } from "../engine/engine_setup.js";
5
6
  import type { IRenderer } from "../engine/engine_types.js";
@@ -35,13 +36,11 @@ export class ReflectionProbe extends Behaviour {
35
36
  return probe;
36
37
  }
37
38
  }
38
- /*
39
39
  // TODO not supported right now, as we'd have to pass the ReflectionProbe scale through as well.
40
40
  else if (probe.isInBox(object)) {
41
41
  if (debug) console.log("Found reflection probe", object.name, probe.name);
42
42
  return probe;
43
43
  }
44
- */
45
44
  }
46
45
  }
47
46
  }
@@ -53,6 +52,8 @@ export class ReflectionProbe extends Behaviour {
53
52
 
54
53
 
55
54
  private _texture!: Texture;
55
+
56
+ // @serializable(Texture)
56
57
  set texture(tex: Texture) {
57
58
  if (tex && !(tex instanceof Texture)) {
58
59
  console.error("ReflectionProbe.texture must be a Texture", tex);
@@ -61,7 +62,7 @@ export class ReflectionProbe extends Behaviour {
61
62
  this._texture = tex;
62
63
  if (tex) {
63
64
  tex.mapping = EquirectangularReflectionMapping;
64
- tex.colorSpace = SRGBColorSpace;
65
+ tex.colorSpace = LinearSRGBColorSpace;
65
66
  tex.needsUpdate = true;
66
67
  }
67
68
  }
@@ -94,10 +95,16 @@ export class ReflectionProbe extends Behaviour {
94
95
  if (debug)
95
96
  this._boxHelper.showHelper(0x555500, true);
96
97
 
97
- if (this.texture) {
98
- this.texture.mapping = EquirectangularReflectionMapping;
99
- this.texture.colorSpace = SRGBColorSpace;
100
- this.texture.needsUpdate = true;
98
+ if (this._texture) {
99
+ this._texture.mapping = EquirectangularReflectionMapping;
100
+ this._texture.colorSpace = LinearSRGBColorSpace;
101
+ this._texture.needsUpdate = true;
102
+ }
103
+ }
104
+ start(): void {
105
+ if (!this._texture && isDevEnvironment()) {
106
+ console.warn(`[ReflectionProbe] Missing texture. Please assign a custom cubemap texture. To use reflection probes assign them to your renderer's "anchor" property.`);
107
+ showBalloonWarning("ReflectionProbe configuration hint: See browser console for details")
101
108
  }
102
109
  }
103
110
 
@@ -258,7 +258,10 @@ export class SceneSwitcher extends Behaviour {
258
258
  // remove all scenes from the url that are in the scenes array at startup
259
259
  for (const scene of this.scenes) {
260
260
  if (scene && !scene.hasUrl && scene.asset instanceof Object3D) {
261
- scene.asset.removeFromParent();
261
+ GameObject.remove(scene.asset);
262
+ }
263
+ else if(scene instanceof Object3D) {
264
+ GameObject.remove(scene);
262
265
  }
263
266
  }
264
267
 
@@ -560,14 +563,20 @@ export class SceneSwitcher extends Behaviour {
560
563
  else if (type === "number") {
561
564
  return this.select(scene);
562
565
  }
566
+ // If we're switching an Object3D
567
+ else if (scene && (scene as Object3D) instanceof Object3D) {
568
+ const i = this.scenes?.indexOf(scene);
569
+ scene = new AssetReference((scene as Object3D).name, undefined, scene);
570
+ if (i >= 0) this.scenes[i] = scene; // update the asset in the list to the new asset reference
571
+ }
563
572
  else {
564
- console.warn("SceneSwitcher: Can't switch to scene", scene, "of type", type);
573
+ console.warn(`[SceneSwitcher] Can't switch to scene of type ${type}`);
565
574
  return false;
566
575
  }
567
576
  }
568
577
 
569
578
  if (scene.url === this.sourceId) {
570
- console.warn("SceneSwitcher: can't load own scene - prevent recursive loading", this.sourceId);
579
+ console.warn("[SceneSwitcher] Can't load own scene - prevent recursive loading", this.sourceId);
571
580
  return false;
572
581
  }
573
582
 
@@ -597,7 +606,7 @@ export class SceneSwitcher extends Behaviour {
597
606
  current.unload();
598
607
  // otherwise if it's a regular Object3D we just remove it from the scene
599
608
  else if (current.asset instanceof Object3D) {
600
- current.asset.removeFromParent();
609
+ GameObject.remove(current.asset as any as Object3D);
601
610
  }
602
611
  }
603
612
  }
@@ -619,6 +628,11 @@ export class SceneSwitcher extends Behaviour {
619
628
  await this.onStartLoading();
620
629
  // start loading and wait for the scene to be loaded
621
630
  await scene.loadAssetAsync((_, prog) => {
631
+ if (debug) {
632
+ const t01 = prog.loaded / prog.total;
633
+ const progressBarString = "[" + "=".repeat(Math.floor(t01 * 20)) + "-".repeat(20 - Math.floor(t01 * 20)) + "]";
634
+ console.debug(`[SceneSwitcher] Download ${(t01 * 100).toFixed(1)} % ${progressBarString}`, scene.url);
635
+ }
622
636
  this._currentLoadingProgress = prog;
623
637
  this.dispatchEvent(prog);
624
638
  this.sceneLoadingProgress?.invoke(prog);
@@ -678,7 +692,8 @@ export class SceneSwitcher extends Behaviour {
678
692
  let queryParameterValue = index.toString();
679
693
  // unless the user defines that he wants to use the scene name
680
694
  if (this.useSceneName) {
681
- queryParameterValue = sceneUriToName(scene.url);
695
+ if (scene instanceof Object3D) queryParameterValue = scene.name;
696
+ else if (scene.url) queryParameterValue = sceneUriToName(scene.url);
682
697
  }
683
698
  // save the loaded scene as an url parameter
684
699
  if (this.queryParameterName?.length)
@@ -743,7 +758,8 @@ export class SceneSwitcher extends Behaviour {
743
758
  for (let i = 0; i < this.scenes.length; i++) {
744
759
  const scene = this.scenes[i];
745
760
  if (!scene) continue;
746
- if (sceneUriToName(scene.url).toLowerCase().includes(lowerCaseValue)) {
761
+ const name = scene instanceof Object3D ? scene.name : sceneUriToName(scene.url);
762
+ if (name.toLowerCase().includes(lowerCaseValue)) {
747
763
  return this.select(i);;
748
764
  }
749
765
  }
@@ -864,10 +880,10 @@ function sceneUriToName(uri: string): string {
864
880
  class PreLoadScheduler {
865
881
  /** Maximum number of scenes to preload ahead of the current scene */
866
882
  maxLoadAhead: number;
867
-
883
+
868
884
  /** Maximum number of scenes to preload behind the current scene */
869
885
  maxLoadBehind: number;
870
-
886
+
871
887
  /** Maximum number of scenes that can be preloaded concurrently */
872
888
  maxConcurrent: number;
873
889
 
@@ -961,7 +977,8 @@ class PreLoadScheduler {
961
977
  allLoaded(): boolean {
962
978
  if (this._switcher.scenes) {
963
979
  for (const scene of this._switcher.scenes) {
964
- if (scene?.isLoaded() === false) return false;
980
+ if (!scene?.isLoaded) continue;
981
+ if (scene.isLoaded() === false) return false;
965
982
  }
966
983
  }
967
984
  return true;
@@ -974,10 +991,10 @@ class PreLoadScheduler {
974
991
  class LoadTask {
975
992
  /** The index of the scene in the scenes array */
976
993
  index: number;
977
-
994
+
978
995
  /** The AssetReference to be loaded */
979
996
  asset: AssetReference;
980
-
997
+
981
998
  /** The collection of active load tasks this task belongs to */
982
999
  tasks: LoadTask[];
983
1000
 
@@ -107,6 +107,15 @@ export class SyncedTransform extends Behaviour {
107
107
  this._model.requestOwnership();
108
108
  }
109
109
 
110
+ /**
111
+ * Free ownership of this object on the network.
112
+ * You need to be connected to a room for this to work.
113
+ * This will also be called automatically when the component is disabled.
114
+ */
115
+ public freeOwnership() {
116
+ this._model?.freeOwnership();
117
+ }
118
+
110
119
  /**
111
120
  * Checks if this client has ownership of the object
112
121
  * @returns true if this client has ownership, false if not, undefined if ownership state is unknown
@@ -312,8 +321,7 @@ export class SyncedTransform extends Behaviour {
312
321
 
313
322
  if (this._model && !this._model.hasOwnership && this._model.isOwned) {
314
323
  if (this._receivedDataBefore) {
315
- const factor = this._receivedFastUpdate || this.fastMode ? .5 : .3;
316
- const t = factor;//Mathf.clamp01(this.context.time.deltaTime * factor);
324
+ const t = this._receivedFastUpdate || this.fastMode ? .05 : .3;
317
325
  let requireMarkDirty = false;
318
326
  if (this.interpolatePosition && this._targetPosition) {
319
327
  const pos = this.worldPosition;
@@ -366,13 +374,10 @@ export class SyncedTransform extends Behaviour {
366
374
  FAST_ACTIVE_SYNCTRANSFORMS++;
367
375
  if (fastUpdate && FAST_INTERVAL > 0 && this.context.time.frameCount % FAST_INTERVAL !== 0) return;
368
376
 
369
- if (debug)
370
- console.log("send update", this.context.connection.connectionId, this.guid, this.gameObject.name, this.gameObject.guid);
377
+ if (debug) console.debug("[SyncedTransform] Send update", this.context.connection.connectionId, this.guid, this.gameObject.name, this.gameObject.guid);
371
378
 
372
379
  this._needsUpdate = false;
373
380
  const st = createTransformModel(this.guid, this, fastUpdate ? true : false);
374
- // this._state.update(this, this.rb);
375
- // this._state.fast = fastUpdate ? true : false;
376
381
  this.context.connection.sendBinary(st);
377
382
  }
378
383
  }
@@ -194,6 +194,7 @@ export { Rect } from "../ui/RectTransform.js";
194
194
  export { RectTransform } from "../ui/RectTransform.js";
195
195
  export { SpatialHtml } from "../ui/SpatialHtml.js";
196
196
  export { Text } from "../ui/Text.js";
197
+ export { EnvironmentScene } from "../utils/EnvironmentScene.js";
197
198
  export { LookAt } from "../utils/LookAt.js";
198
199
  export { OpenURL } from "../utils/OpenURL.js";
199
200
  export { VideoPlayer } from "../VideoPlayer.js";
@@ -1,12 +1,12 @@
1
1
  import { Color, Mesh, MeshBasicMaterial, Object3D } from "three";
2
2
 
3
3
  import { GameObject } from "../../../Component.js";
4
- import { SpriteRenderer } from "../../../SpriteRenderer.js";
5
- import { $shadowDomOwner, BaseUIComponent } from "../../../ui/BaseUIComponent.js";
4
+ import { BaseUIComponent } from "../../../ui/BaseUIComponent.js";
6
5
  import { Canvas } from "../../../ui/Canvas.js";
7
6
  import { RenderMode } from "../../../ui/Canvas.js";
8
7
  import { CanvasGroup } from "../../../ui/CanvasGroup.js";
9
8
  import { RectTransform } from "../../../ui/RectTransform.js";
9
+ import { $shadowDomOwner } from "../../../ui/Symbols.js";
10
10
  import { Text } from "../../../ui/Text.js";
11
11
  import type { IUSDExporterExtension } from "../Extension.js";
12
12
  import { USDObject, USDZExporterContext } from "../ThreeUSDZExporter.js";
@@ -8,6 +8,7 @@ import { getParam } from '../../engine/engine_utils.js';
8
8
  import { Behaviour, GameObject } from "../Component.js";
9
9
  import { EventSystem } from "./EventSystem.js";
10
10
  import type { ICanvas } from './Interfaces.js';
11
+ import { $shadowDomOwner } from './Symbols.js';
11
12
  export const includesDir = "./include";
12
13
 
13
14
  const debug = getParam("debugshadowcomponents");
@@ -24,7 +25,6 @@ ThreeMeshUI.Block.prototype["interactable"] = {
24
25
  }
25
26
  }
26
27
 
27
- export const $shadowDomOwner = Symbol("shadowDomOwner");
28
28
 
29
29
  /**
30
30
  * Derive from this class if you want to implement your own UI components.
@@ -9,11 +9,11 @@ import { Context } from "../../engine/engine_setup.js";
9
9
  import { HideFlags, type IComponent } from "../../engine/engine_types.js";
10
10
  import { getParam } from "../../engine/engine_utils.js";
11
11
  import { Behaviour, GameObject } from "../Component.js";
12
- import { $shadowDomOwner } from "./BaseUIComponent.js";
13
12
  import type { ICanvasGroup } from "./Interfaces.js";
14
13
  import { hasPointerEventComponent, type IPointerEventHandler, type IPointerUpHandler, PointerEventData } from "./PointerEvents.js";
15
14
  import { ObjectRaycaster, Raycaster } from "./Raycaster.js";
16
15
  import { UIRaycastUtils } from "./RaycastUtils.js";
16
+ import { $shadowDomOwner } from "./Symbols.js";
17
17
  import { isUIObject } from "./Utils.js";
18
18
 
19
19
  const debug = getParam("debugeventsystem");
@@ -98,6 +98,7 @@ export class Graphic extends BaseUIComponent implements IGraphic, IRectTransform
98
98
  super.__internalNewInstanceCreated(init);
99
99
  this._rect = null;
100
100
  this.uiObject = null;
101
+ this._stateManager = null;
101
102
  if (this._color) this._color = this._color.clone();
102
103
  return this;
103
104
  }
@@ -114,7 +115,6 @@ export class Graphic extends BaseUIComponent implements IGraphic, IRectTransform
114
115
  setupState(state: object) {
115
116
  this.makePanel();
116
117
  if (this.uiObject) {
117
-
118
118
  // @marwie : v7.x now have a concurrent state management in core mimicking html/css
119
119
  // ie : (::firstChild::hover::disabled) where firstchild, hover and disabled are all on different channels
120
120
  // In order to keep needle Raycaster and EventSystem intact, I added in v7 a SimpleStateBehavior, which acts as previously
@@ -2,8 +2,8 @@ import { Object3D } from "three";
2
2
 
3
3
  import { foreachComponent } from "../../engine/engine_gameobject.js";
4
4
  import { type IComponent } from "../../engine/engine_types.js";
5
- import { $shadowDomOwner } from "./BaseUIComponent.js";
6
5
  import { type ICanvasGroup, type IGraphic } from "./Interfaces.js";
6
+ import { $shadowDomOwner } from "./Symbols.js";
7
7
 
8
8
 
9
9
  export class UIRaycastUtils {