@relu-interactives/spatial-ecs 0.4.5 → 0.5.1

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 (47) hide show
  1. package/dist/{System-ln4Q7Eot.d.cts → System-V_mv07le.d.cts} +2 -2
  2. package/dist/{System-ln4Q7Eot.d.ts → System-V_mv07le.d.ts} +2 -2
  3. package/dist/{XRHandPose-CxPv-LBo.d.cts → XRHandPose-CQTLGxFC.d.cts} +218 -2
  4. package/dist/{XRHandPose-BImIa4ZS.d.ts → XRHandPose-CU3vNFuS.d.ts} +218 -2
  5. package/dist/{chunk-4AK4I3QF.js → chunk-BUEKOSR5.js} +102 -3
  6. package/dist/chunk-BUEKOSR5.js.map +1 -0
  7. package/dist/{chunk-QIIWFP3V.js → chunk-Q52ADLF7.js} +1255 -18
  8. package/dist/chunk-Q52ADLF7.js.map +1 -0
  9. package/dist/{chunk-SGADE55G.js → chunk-RXBLOO5B.js} +249 -90
  10. package/dist/chunk-RXBLOO5B.js.map +1 -0
  11. package/dist/{chunk-4DWZK4X4.js → chunk-WJD2VKEH.js} +3 -3
  12. package/dist/chunk-WJD2VKEH.js.map +1 -0
  13. package/dist/components/index.cjs +99 -0
  14. package/dist/components/index.cjs.map +1 -1
  15. package/dist/components/index.d.cts +3 -3
  16. package/dist/components/index.d.ts +3 -3
  17. package/dist/components/index.js +1 -1
  18. package/dist/docs/guide/spatial-ui.md +165 -0
  19. package/dist/factories/index.cjs +372 -114
  20. package/dist/factories/index.cjs.map +1 -1
  21. package/dist/factories/index.d.cts +13 -3
  22. package/dist/factories/index.d.ts +13 -3
  23. package/dist/factories/index.js +3 -3
  24. package/dist/{index-CuGqxuk-.d.ts → index-C3ik3sA1.d.ts} +16 -3
  25. package/dist/{index-BphKHaV-.d.ts → index-D2Jt_JzH.d.ts} +156 -3
  26. package/dist/{index-CH7qMsQT.d.cts → index-DaG03vyN.d.cts} +156 -3
  27. package/dist/{index-CQsHUez3.d.cts → index-Dlr-7-4m.d.cts} +16 -3
  28. package/dist/index.cjs +1864 -360
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.d.cts +42 -9
  31. package/dist/index.d.ts +42 -9
  32. package/dist/index.js +10 -8
  33. package/dist/index.js.map +1 -1
  34. package/dist/systems/index.cjs +1346 -13
  35. package/dist/systems/index.cjs.map +1 -1
  36. package/dist/systems/index.d.cts +2 -2
  37. package/dist/systems/index.d.ts +2 -2
  38. package/dist/systems/index.js +3 -3
  39. package/dist/types.d.cts +1 -1
  40. package/dist/types.d.ts +1 -1
  41. package/dist/worldSnapshotUtils.d.cts +1 -1
  42. package/dist/worldSnapshotUtils.d.ts +1 -1
  43. package/package.json +1 -1
  44. package/dist/chunk-4AK4I3QF.js.map +0 -1
  45. package/dist/chunk-4DWZK4X4.js.map +0 -1
  46. package/dist/chunk-QIIWFP3V.js.map +0 -1
  47. package/dist/chunk-SGADE55G.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var THREE51 = require('three');
3
+ var THREE56 = require('three');
4
4
  var SkeletonUtils_js = require('three/examples/jsm/utils/SkeletonUtils.js');
5
5
  var RectAreaLightHelper_js = require('three/examples/jsm/helpers/RectAreaLightHelper.js');
6
6
  var DRACOLoader_js = require('three/examples/jsm/loaders/DRACOLoader.js');
@@ -41,7 +41,7 @@ function _interopNamespace(e) {
41
41
  return Object.freeze(n);
42
42
  }
43
43
 
44
- var THREE51__namespace = /*#__PURE__*/_interopNamespace(THREE51);
44
+ var THREE56__namespace = /*#__PURE__*/_interopNamespace(THREE56);
45
45
 
46
46
  var __defProp = Object.defineProperty;
47
47
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
@@ -605,14 +605,14 @@ var _AnimationComponent = class _AnimationComponent extends Component {
605
605
  return;
606
606
  }
607
607
  this.importedClips = clips.map((entry) => {
608
- if (entry instanceof THREE51__namespace.AnimationClip) {
608
+ if (entry instanceof THREE56__namespace.AnimationClip) {
609
609
  return { clip: entry, sourceUrl: null };
610
610
  }
611
611
  if (!entry || typeof entry !== "object") {
612
612
  return null;
613
613
  }
614
614
  const candidate = entry;
615
- if (!(candidate.clip instanceof THREE51__namespace.AnimationClip)) {
615
+ if (!(candidate.clip instanceof THREE56__namespace.AnimationClip)) {
616
616
  return null;
617
617
  }
618
618
  return {
@@ -820,11 +820,11 @@ function normalizeDistanceModel(distanceModel) {
820
820
  }
821
821
  __name(normalizeDistanceModel, "normalizeDistanceModel");
822
822
  function createConfiguredAudio(listener, options) {
823
- const sound = options.positional ? new THREE51__namespace.PositionalAudio(listener) : new THREE51__namespace.Audio(listener);
823
+ const sound = options.positional ? new THREE56__namespace.PositionalAudio(listener) : new THREE56__namespace.Audio(listener);
824
824
  sound.setLoop(options.loop);
825
825
  sound.setVolume(options.volume);
826
826
  sound.setPlaybackRate(options.pitch);
827
- if (sound instanceof THREE51__namespace.PositionalAudio) {
827
+ if (sound instanceof THREE56__namespace.PositionalAudio) {
828
828
  sound.setRefDistance(options.refDistance);
829
829
  sound.setDistanceModel(normalizeDistanceModel(options.distanceModel));
830
830
  sound.setRolloffFactor(options.rolloffFactor);
@@ -834,16 +834,16 @@ function createConfiguredAudio(listener, options) {
834
834
  __name(createConfiguredAudio, "createConfiguredAudio");
835
835
  function createAudioEditorHelper() {
836
836
  if (typeof document === "undefined") {
837
- const geometry = new THREE51__namespace.EdgesGeometry(
838
- new THREE51__namespace.OctahedronGeometry(0.22, 0)
837
+ const geometry = new THREE56__namespace.EdgesGeometry(
838
+ new THREE56__namespace.OctahedronGeometry(0.22, 0)
839
839
  );
840
- const material2 = new THREE51__namespace.LineBasicMaterial({
840
+ const material2 = new THREE56__namespace.LineBasicMaterial({
841
841
  color: "#8bc8ff",
842
842
  transparent: true,
843
843
  opacity: 0.95,
844
844
  depthTest: false
845
845
  });
846
- const fallback = new THREE51__namespace.LineSegments(geometry, material2);
846
+ const fallback = new THREE56__namespace.LineSegments(geometry, material2);
847
847
  fallback.renderOrder = 10;
848
848
  fallback.userData.ecsHelper = true;
849
849
  fallback.visible = false;
@@ -855,7 +855,7 @@ function createAudioEditorHelper() {
855
855
  canvas.height = size;
856
856
  const ctx = canvas.getContext("2d");
857
857
  if (!ctx) {
858
- return new THREE51__namespace.Object3D();
858
+ return new THREE56__namespace.Object3D();
859
859
  }
860
860
  ctx.clearRect(0, 0, size, size);
861
861
  ctx.fillStyle = "rgba(27, 35, 52, 0.9)";
@@ -886,14 +886,14 @@ function createAudioEditorHelper() {
886
886
  ctx.beginPath();
887
887
  ctx.arc(56, 48, 16, -0.8, 0.8);
888
888
  ctx.stroke();
889
- const texture = new THREE51__namespace.CanvasTexture(canvas);
889
+ const texture = new THREE56__namespace.CanvasTexture(canvas);
890
890
  texture.needsUpdate = true;
891
- const material = new THREE51__namespace.SpriteMaterial({
891
+ const material = new THREE56__namespace.SpriteMaterial({
892
892
  map: texture,
893
893
  transparent: true,
894
894
  depthTest: false
895
895
  });
896
- const helper = new THREE51__namespace.Sprite(material);
896
+ const helper = new THREE56__namespace.Sprite(material);
897
897
  helper.scale.set(0.68, 0.68, 0.68);
898
898
  helper.renderOrder = 10;
899
899
  helper.userData.ecsHelper = true;
@@ -927,7 +927,7 @@ var DEFAULT_ORTHO_TOP = 5;
927
927
  var DEFAULT_ORTHO_BOTTOM = -5;
928
928
  var DEFAULT_ZOOM = 1;
929
929
  function inferProjection(camera) {
930
- if (camera instanceof THREE51__namespace.OrthographicCamera) {
930
+ if (camera instanceof THREE56__namespace.OrthographicCamera) {
931
931
  return "orthographic";
932
932
  }
933
933
  return "perspective";
@@ -948,7 +948,7 @@ function readCameraFar(camera) {
948
948
  }
949
949
  __name(readCameraFar, "readCameraFar");
950
950
  function inferFov(camera) {
951
- if (camera instanceof THREE51__namespace.PerspectiveCamera && Number.isFinite(camera.fov)) {
951
+ if (camera instanceof THREE56__namespace.PerspectiveCamera && Number.isFinite(camera.fov)) {
952
952
  return camera.fov;
953
953
  }
954
954
  return DEFAULT_FOV;
@@ -971,28 +971,28 @@ function inferFar(camera) {
971
971
  }
972
972
  __name(inferFar, "inferFar");
973
973
  function inferOrthoLeft(camera) {
974
- if (camera instanceof THREE51__namespace.OrthographicCamera && Number.isFinite(camera.left)) {
974
+ if (camera instanceof THREE56__namespace.OrthographicCamera && Number.isFinite(camera.left)) {
975
975
  return camera.left;
976
976
  }
977
977
  return DEFAULT_ORTHO_LEFT;
978
978
  }
979
979
  __name(inferOrthoLeft, "inferOrthoLeft");
980
980
  function inferOrthoRight(camera) {
981
- if (camera instanceof THREE51__namespace.OrthographicCamera && Number.isFinite(camera.right)) {
981
+ if (camera instanceof THREE56__namespace.OrthographicCamera && Number.isFinite(camera.right)) {
982
982
  return camera.right;
983
983
  }
984
984
  return DEFAULT_ORTHO_RIGHT;
985
985
  }
986
986
  __name(inferOrthoRight, "inferOrthoRight");
987
987
  function inferOrthoTop(camera) {
988
- if (camera instanceof THREE51__namespace.OrthographicCamera && Number.isFinite(camera.top)) {
988
+ if (camera instanceof THREE56__namespace.OrthographicCamera && Number.isFinite(camera.top)) {
989
989
  return camera.top;
990
990
  }
991
991
  return DEFAULT_ORTHO_TOP;
992
992
  }
993
993
  __name(inferOrthoTop, "inferOrthoTop");
994
994
  function inferOrthoBottom(camera) {
995
- if (camera instanceof THREE51__namespace.OrthographicCamera && Number.isFinite(camera.bottom)) {
995
+ if (camera instanceof THREE56__namespace.OrthographicCamera && Number.isFinite(camera.bottom)) {
996
996
  return camera.bottom;
997
997
  }
998
998
  return DEFAULT_ORTHO_BOTTOM;
@@ -1008,7 +1008,7 @@ __name(inferZoom, "inferZoom");
1008
1008
  var _CameraComponent = class _CameraComponent extends Component {
1009
1009
  constructor(payload = {}) {
1010
1010
  super();
1011
- this.camera = payload.camera ?? new THREE51__namespace.PerspectiveCamera();
1011
+ this.camera = payload.camera ?? new THREE56__namespace.PerspectiveCamera();
1012
1012
  this.type = payload.type ?? "3d";
1013
1013
  this.isDefault = typeof payload.isDefault === "boolean" ? payload.isDefault : false;
1014
1014
  this.projection = payload.projection ?? inferProjection(payload.camera);
@@ -1039,7 +1039,7 @@ var Object3DRef = _Object3DRef;
1039
1039
  // core/factories/components/CameraFactory.ts
1040
1040
  function createCameraComponent(world, entityId, payload = {}) {
1041
1041
  const object = world.getComponent(entityId, Object3DRef)?.object;
1042
- const objectCamera = object instanceof THREE51__namespace.Camera ? object : void 0;
1042
+ const objectCamera = object instanceof THREE56__namespace.Camera ? object : void 0;
1043
1043
  const component = new CameraComponent({
1044
1044
  ...payload,
1045
1045
  camera: payload.camera ?? objectCamera
@@ -1609,15 +1609,15 @@ function createValueState(light) {
1609
1609
  castShadow: light.castShadow ?? false,
1610
1610
  frustumCulling: light.frustumCulled
1611
1611
  };
1612
- if (light instanceof THREE51__namespace.PointLight) {
1612
+ if (light instanceof THREE56__namespace.PointLight) {
1613
1613
  base.distance = light.distance;
1614
1614
  base.decay = light.decay;
1615
- } else if (light instanceof THREE51__namespace.SpotLight) {
1615
+ } else if (light instanceof THREE56__namespace.SpotLight) {
1616
1616
  base.distance = light.distance;
1617
1617
  base.decay = light.decay;
1618
1618
  base.angle = light.angle;
1619
1619
  base.penumbra = light.penumbra;
1620
- } else if (light instanceof THREE51__namespace.RectAreaLight) {
1620
+ } else if (light instanceof THREE56__namespace.RectAreaLight) {
1621
1621
  base.width = light.width;
1622
1622
  base.height = light.height;
1623
1623
  }
@@ -1660,13 +1660,13 @@ function toHexColor2(value, fallback) {
1660
1660
  }
1661
1661
  __name(toHexColor2, "toHexColor");
1662
1662
  function getMaterialType(material) {
1663
- if (material instanceof THREE51__namespace.MeshPhysicalMaterial) {
1663
+ if (material instanceof THREE56__namespace.MeshPhysicalMaterial) {
1664
1664
  return "physical";
1665
1665
  }
1666
- if (material instanceof THREE51__namespace.MeshPhongMaterial) {
1666
+ if (material instanceof THREE56__namespace.MeshPhongMaterial) {
1667
1667
  return "phong";
1668
1668
  }
1669
- if (material instanceof THREE51__namespace.MeshBasicMaterial) {
1669
+ if (material instanceof THREE56__namespace.MeshBasicMaterial) {
1670
1670
  return "basic";
1671
1671
  }
1672
1672
  return "standard";
@@ -1701,8 +1701,8 @@ function createMaterialValue(material) {
1701
1701
  opacity: typeof materialRecord.opacity === "number" ? materialRecord.opacity : 1,
1702
1702
  emissive: toHexColor2(materialRecord.emissive, "#000000"),
1703
1703
  emissiveIntensity: typeof materialRecord.emissiveIntensity === "number" ? materialRecord.emissiveIntensity : 0,
1704
- side: typeof materialRecord.side === "number" ? materialRecord.side : THREE51__namespace.FrontSide,
1705
- blending: typeof materialRecord.blending === "number" ? materialRecord.blending : THREE51__namespace.NormalBlending,
1704
+ side: typeof materialRecord.side === "number" ? materialRecord.side : THREE56__namespace.FrontSide,
1705
+ blending: typeof materialRecord.blending === "number" ? materialRecord.blending : THREE56__namespace.NormalBlending,
1706
1706
  depthTest: materialRecord.depthTest !== false,
1707
1707
  depthWrite: materialRecord.depthWrite !== false,
1708
1708
  wireframe: Boolean(materialRecord.wireframe),
@@ -1734,7 +1734,7 @@ function createMaterialValue(material) {
1734
1734
  materialRecord.lightMap
1735
1735
  ),
1736
1736
  envMap: textureImageSrc(materialRecord.envMap),
1737
- textureFiltering: map?.magFilter === THREE51__namespace.NearestFilter ? "sharp" : "smooth",
1737
+ textureFiltering: map?.magFilter === THREE56__namespace.NearestFilter ? "sharp" : "smooth",
1738
1738
  useMipmaps: map?.generateMipmaps !== false
1739
1739
  };
1740
1740
  }
@@ -1749,8 +1749,8 @@ function defaultMaterialValue() {
1749
1749
  opacity: 1,
1750
1750
  emissive: "#000000",
1751
1751
  emissiveIntensity: 0,
1752
- side: THREE51__namespace.FrontSide,
1753
- blending: THREE51__namespace.NormalBlending,
1752
+ side: THREE56__namespace.FrontSide,
1753
+ blending: THREE56__namespace.NormalBlending,
1754
1754
  depthTest: true,
1755
1755
  depthWrite: true,
1756
1756
  wireframe: false,
@@ -2327,14 +2327,14 @@ var _TransformComponent = class _TransformComponent extends Component {
2327
2327
  z: scale.z ?? 1
2328
2328
  };
2329
2329
  }
2330
- toPositionVector3(target = new THREE51.Vector3()) {
2330
+ toPositionVector3(target = new THREE56.Vector3()) {
2331
2331
  return target.set(this.position.x, this.position.y, this.position.z);
2332
2332
  }
2333
- toRotationEuler(target = new THREE51.Euler(), order = "XYZ") {
2333
+ toRotationEuler(target = new THREE56.Euler(), order = "XYZ") {
2334
2334
  return target.set(this.rotation.x, this.rotation.y, this.rotation.z, order);
2335
2335
  }
2336
- toRotationQuaternion(target = new THREE51.Quaternion(), order = "XYZ") {
2337
- const euler = new THREE51.Euler(
2336
+ toRotationQuaternion(target = new THREE56.Quaternion(), order = "XYZ") {
2337
+ const euler = new THREE56.Euler(
2338
2338
  this.rotation.x,
2339
2339
  this.rotation.y,
2340
2340
  this.rotation.z,
@@ -2342,7 +2342,7 @@ var _TransformComponent = class _TransformComponent extends Component {
2342
2342
  );
2343
2343
  return target.setFromEuler(euler);
2344
2344
  }
2345
- toScaleVector3(target = new THREE51.Vector3()) {
2345
+ toScaleVector3(target = new THREE56.Vector3()) {
2346
2346
  return target.set(this.scale.x, this.scale.y, this.scale.z);
2347
2347
  }
2348
2348
  setPosition(input) {
@@ -2360,8 +2360,8 @@ var _TransformComponent = class _TransformComponent extends Component {
2360
2360
  return this;
2361
2361
  }
2362
2362
  setRotation(input, order = "XYZ") {
2363
- if (input instanceof THREE51.Quaternion) {
2364
- const euler = new THREE51.Euler().setFromQuaternion(input, order);
2363
+ if (input instanceof THREE56.Quaternion) {
2364
+ const euler = new THREE56.Euler().setFromQuaternion(input, order);
2365
2365
  this.rotation.x = euler.x;
2366
2366
  this.rotation.y = euler.y;
2367
2367
  this.rotation.z = euler.z;
@@ -2978,6 +2978,140 @@ function createXRInteractorSideComponent(world, entityId, ...args) {
2978
2978
  }
2979
2979
  __name(createXRInteractorSideComponent, "createXRInteractorSideComponent");
2980
2980
 
2981
+ // core/components/UIButton.ts
2982
+ var _UIButtonComponent = class _UIButtonComponent extends Component {
2983
+ constructor(options) {
2984
+ super();
2985
+ this.label = options?.label ?? "Button";
2986
+ this.actionId = options?.actionId ?? "";
2987
+ this.width = options?.width ?? 0.3;
2988
+ this.height = options?.height ?? 0.1;
2989
+ this.fontSize = options?.fontSize ?? 0.03;
2990
+ this.fontWeight = options?.fontWeight ?? 600;
2991
+ this.textColor = options?.textColor ?? "#ffffff";
2992
+ this.backgroundColor = options?.backgroundColor ?? "#2a2a2a";
2993
+ this.backgroundOpacity = options?.backgroundOpacity ?? 1;
2994
+ this.cornerRadius = options?.cornerRadius ?? 0.02;
2995
+ this.borderWidth = options?.borderWidth ?? 2e-3;
2996
+ this.borderColor = options?.borderColor ?? "#3a3a3a";
2997
+ }
2998
+ };
2999
+ __name(_UIButtonComponent, "UIButtonComponent");
3000
+ var UIButtonComponent = _UIButtonComponent;
3001
+
3002
+ // core/factories/components/UIButtonComponentFactory.ts
3003
+ function createUIButtonComponent(world, entityId, ...args) {
3004
+ const component = new UIButtonComponent(...args);
3005
+ world.addComponent(entityId, component);
3006
+ return component;
3007
+ }
3008
+ __name(createUIButtonComponent, "createUIButtonComponent");
3009
+
3010
+ // core/components/UIPanel.ts
3011
+ var _UIPanelComponent = class _UIPanelComponent extends Component {
3012
+ constructor(options) {
3013
+ super();
3014
+ this.width = options?.width ?? 0.6;
3015
+ this.height = options?.height ?? 0.4;
3016
+ this.backgroundColor = options?.backgroundColor ?? "#1c1c1c";
3017
+ this.backgroundOpacity = options?.backgroundOpacity ?? 0.92;
3018
+ this.cornerRadius = options?.cornerRadius ?? 0.02;
3019
+ this.borderWidth = options?.borderWidth ?? 0;
3020
+ this.borderColor = options?.borderColor ?? "#333333";
3021
+ this.pixelDensity = options?.pixelDensity ?? 1024;
3022
+ this.follow = options?.follow ?? "world";
3023
+ }
3024
+ };
3025
+ __name(_UIPanelComponent, "UIPanelComponent");
3026
+ var UIPanelComponent = _UIPanelComponent;
3027
+
3028
+ // core/factories/components/UIPanelComponentFactory.ts
3029
+ function createUIPanelComponent(world, entityId, ...args) {
3030
+ const component = new UIPanelComponent(...args);
3031
+ world.addComponent(entityId, component);
3032
+ return component;
3033
+ }
3034
+ __name(createUIPanelComponent, "createUIPanelComponent");
3035
+
3036
+ // core/components/UISlider.ts
3037
+ var _UISliderComponent = class _UISliderComponent extends Component {
3038
+ constructor(options) {
3039
+ super();
3040
+ this.min = options?.min ?? 0;
3041
+ this.max = options?.max ?? Math.max(1, this.min + 1);
3042
+ if (this.max <= this.min) this.max = this.min + 1;
3043
+ const v = options?.value ?? (this.min + this.max) / 2;
3044
+ this.value = Math.min(this.max, Math.max(this.min, v));
3045
+ this.actionId = options?.actionId ?? "";
3046
+ this.width = options?.width ?? 0.4;
3047
+ this.height = options?.height ?? 0.06;
3048
+ this.trackColor = options?.trackColor ?? "#2a2a2a";
3049
+ this.accentColor = options?.accentColor ?? "#ff6b35";
3050
+ this.knobColor = options?.knobColor ?? "#ffffff";
3051
+ }
3052
+ };
3053
+ __name(_UISliderComponent, "UISliderComponent");
3054
+ var UISliderComponent = _UISliderComponent;
3055
+
3056
+ // core/factories/components/UISliderComponentFactory.ts
3057
+ function createUISliderComponent(world, entityId, ...args) {
3058
+ const component = new UISliderComponent(...args);
3059
+ world.addComponent(entityId, component);
3060
+ return component;
3061
+ }
3062
+ __name(createUISliderComponent, "createUISliderComponent");
3063
+
3064
+ // core/components/UIText.ts
3065
+ var _UITextComponent = class _UITextComponent extends Component {
3066
+ constructor(options) {
3067
+ super();
3068
+ this.text = options?.text ?? "Text";
3069
+ this.width = options?.width ?? 0.5;
3070
+ this.height = options?.height ?? 0.12;
3071
+ this.fontSize = options?.fontSize ?? 0.035;
3072
+ this.fontWeight = options?.fontWeight ?? 500;
3073
+ this.color = options?.color ?? "#ffffff";
3074
+ this.align = options?.align ?? "center";
3075
+ this.valign = options?.valign ?? "middle";
3076
+ this.lineHeight = options?.lineHeight ?? 1.25;
3077
+ this.padding = options?.padding ?? 0.01;
3078
+ }
3079
+ };
3080
+ __name(_UITextComponent, "UITextComponent");
3081
+ var UITextComponent = _UITextComponent;
3082
+
3083
+ // core/factories/components/UITextComponentFactory.ts
3084
+ function createUITextComponent(world, entityId, ...args) {
3085
+ const component = new UITextComponent(...args);
3086
+ world.addComponent(entityId, component);
3087
+ return component;
3088
+ }
3089
+ __name(createUITextComponent, "createUITextComponent");
3090
+
3091
+ // core/components/UIToggle.ts
3092
+ var _UIToggleComponent = class _UIToggleComponent extends Component {
3093
+ constructor(options) {
3094
+ super();
3095
+ this.value = options?.value ?? false;
3096
+ this.actionId = options?.actionId ?? "";
3097
+ this.width = options?.width ?? 0.14;
3098
+ this.height = options?.height ?? 0.07;
3099
+ this.trackColor = options?.trackColor ?? "#2a2a2a";
3100
+ this.accentColor = options?.accentColor ?? "#ff6b35";
3101
+ this.knobColor = options?.knobColor ?? "#ffffff";
3102
+ }
3103
+ };
3104
+ __name(_UIToggleComponent, "UIToggleComponent");
3105
+ var UIToggleComponent = _UIToggleComponent;
3106
+
3107
+ // core/factories/components/UIToggleComponentFactory.ts
3108
+ function createUIToggleComponent(world, entityId, ...args) {
3109
+ const component = new UIToggleComponent(...args);
3110
+ world.addComponent(entityId, component);
3111
+ return component;
3112
+ }
3113
+ __name(createUIToggleComponent, "createUIToggleComponent");
3114
+
2981
3115
  // core/factories/registerDefaultComponentFactories.ts
2982
3116
  function registerDefaultComponentFactories(objectManagementSystem) {
2983
3117
  objectManagementSystem.registerComponentFactory("animation", createAnimationComponent);
@@ -2991,6 +3125,11 @@ function registerDefaultComponentFactories(objectManagementSystem) {
2991
3125
  objectManagementSystem.registerComponentFactory("vrTeleportArea", createVRTeleportAreaComponent);
2992
3126
  objectManagementSystem.registerComponentFactory("xrHandPose", createXRHandPoseComponent);
2993
3127
  objectManagementSystem.registerComponentFactory("xrAnchor", createXRAnchorComponent);
3128
+ objectManagementSystem.registerComponentFactory("uiPanel", createUIPanelComponent);
3129
+ objectManagementSystem.registerComponentFactory("uiText", createUITextComponent);
3130
+ objectManagementSystem.registerComponentFactory("uiButton", createUIButtonComponent);
3131
+ objectManagementSystem.registerComponentFactory("uiToggle", createUIToggleComponent);
3132
+ objectManagementSystem.registerComponentFactory("uiSlider", createUISliderComponent);
2994
3133
  objectManagementSystem.registerComponentFactory("xrInteractable", createXRInteractableComponent);
2995
3134
  objectManagementSystem.registerComponentFactory("xrInteractor", createXRInteractorComponent);
2996
3135
  objectManagementSystem.registerComponentFactory("xrInteractorSide", createXRInteractorSideComponent);
@@ -3037,7 +3176,7 @@ var SHARED_MODEL_RESOURCE_FLAG = "spatialEcsSharedModelResource";
3037
3176
  var modelCache = /* @__PURE__ */ new Map();
3038
3177
  function markSharedResources(root) {
3039
3178
  root.traverse((child) => {
3040
- if (!(child instanceof THREE51__namespace.Mesh)) {
3179
+ if (!(child instanceof THREE56__namespace.Mesh)) {
3041
3180
  return;
3042
3181
  }
3043
3182
  if (child.geometry) {
@@ -3116,10 +3255,10 @@ var _ObjectManagementSystem = class _ObjectManagementSystem {
3116
3255
  }
3117
3256
  getOrCreateAudioListener() {
3118
3257
  const existing = this.camera.userData.ecsAudioListener;
3119
- if (existing instanceof THREE51__namespace.AudioListener) {
3258
+ if (existing instanceof THREE56__namespace.AudioListener) {
3120
3259
  return existing;
3121
3260
  }
3122
- const listener = new THREE51__namespace.AudioListener();
3261
+ const listener = new THREE56__namespace.AudioListener();
3123
3262
  this.camera.add(listener);
3124
3263
  this.camera.userData.ecsAudioListener = listener;
3125
3264
  return listener;
@@ -3193,7 +3332,7 @@ var _ObjectManagementSystem = class _ObjectManagementSystem {
3193
3332
  }
3194
3333
  if (dispose && object3d) {
3195
3334
  object3d.traverse((child) => {
3196
- if (child instanceof THREE51__namespace.Mesh) {
3335
+ if (child instanceof THREE56__namespace.Mesh) {
3197
3336
  if (!child.geometry?.userData?.[SHARED_MODEL_RESOURCE_FLAG]) {
3198
3337
  child.geometry?.dispose();
3199
3338
  }
@@ -3330,10 +3469,10 @@ __name(createBaseEntity, "createBaseEntity");
3330
3469
  // core/factories/objects/AudioFactory.ts
3331
3470
  function getOrCreateListener(camera) {
3332
3471
  const existing = camera.userData.ecsAudioListener;
3333
- if (existing instanceof THREE51__namespace.AudioListener) {
3472
+ if (existing instanceof THREE56__namespace.AudioListener) {
3334
3473
  return existing;
3335
3474
  }
3336
- const listener = new THREE51__namespace.AudioListener();
3475
+ const listener = new THREE56__namespace.AudioListener();
3337
3476
  camera.add(listener);
3338
3477
  camera.userData.ecsAudioListener = listener;
3339
3478
  return listener;
@@ -3346,7 +3485,7 @@ function createAudio({
3346
3485
  payload,
3347
3486
  isEditor
3348
3487
  }) {
3349
- const anchor = new THREE51__namespace.Object3D();
3488
+ const anchor = new THREE56__namespace.Object3D();
3350
3489
  const entityId = createBaseEntity(world, anchor, {
3351
3490
  label: payload.name ?? "Audio",
3352
3491
  entityType: "audio",
@@ -3368,7 +3507,7 @@ function createAudio({
3368
3507
  return entityId;
3369
3508
  }
3370
3509
  if (!isEditor) {
3371
- const loader = new THREE51__namespace.AudioLoader();
3510
+ const loader = new THREE56__namespace.AudioLoader();
3372
3511
  loader.load(
3373
3512
  audio.path,
3374
3513
  (buffer) => {
@@ -3443,7 +3582,7 @@ function applyCameraSettings(camera, options) {
3443
3582
  const near = typeof options.near === "number" ? options.near : DEFAULT_NEAR2;
3444
3583
  const far = typeof options.far === "number" ? options.far : DEFAULT_FAR2;
3445
3584
  const projection = options.projection;
3446
- if (camera instanceof THREE51__namespace.PerspectiveCamera) {
3585
+ if (camera instanceof THREE56__namespace.PerspectiveCamera) {
3447
3586
  if (!projection || projection === "perspective") {
3448
3587
  camera.fov = typeof options.fov === "number" ? options.fov : DEFAULT_FOV2;
3449
3588
  }
@@ -3453,7 +3592,7 @@ function applyCameraSettings(camera, options) {
3453
3592
  camera.updateProjectionMatrix();
3454
3593
  return;
3455
3594
  }
3456
- if (camera instanceof THREE51__namespace.OrthographicCamera) {
3595
+ if (camera instanceof THREE56__namespace.OrthographicCamera) {
3457
3596
  camera.left = typeof options.left === "number" ? options.left : -DEFAULT_ORTHOGRAPHIC_HALF_HEIGHT;
3458
3597
  camera.right = typeof options.right === "number" ? options.right : DEFAULT_ORTHOGRAPHIC_HALF_HEIGHT;
3459
3598
  camera.top = typeof options.top === "number" ? options.top : DEFAULT_ORTHOGRAPHIC_HALF_HEIGHT;
@@ -3474,7 +3613,7 @@ function createCameraObject(options) {
3474
3613
  const bottom = options.bottom ?? -DEFAULT_ORTHOGRAPHIC_HALF_HEIGHT;
3475
3614
  const left = options.left ?? -DEFAULT_ORTHOGRAPHIC_HALF_HEIGHT;
3476
3615
  const right = options.right ?? DEFAULT_ORTHOGRAPHIC_HALF_HEIGHT;
3477
- const camera = new THREE51__namespace.OrthographicCamera(
3616
+ const camera = new THREE56__namespace.OrthographicCamera(
3478
3617
  left,
3479
3618
  right,
3480
3619
  top,
@@ -3486,7 +3625,7 @@ function createCameraObject(options) {
3486
3625
  camera.updateProjectionMatrix();
3487
3626
  return camera;
3488
3627
  }
3489
- return new THREE51__namespace.PerspectiveCamera(
3628
+ return new THREE56__namespace.PerspectiveCamera(
3490
3629
  options.fov ?? DEFAULT_FOV2,
3491
3630
  readViewportAspect(),
3492
3631
  near,
@@ -3504,7 +3643,7 @@ function createCamera({ world, scene, camera, payload, isEditor }) {
3504
3643
  transformInput: payload.transform
3505
3644
  });
3506
3645
  const objectRef = world.getComponent(entityId, Object3DRef);
3507
- if (objectRef?.object instanceof THREE51__namespace.Camera) {
3646
+ if (objectRef?.object instanceof THREE56__namespace.Camera) {
3508
3647
  objectRef.object.userData.entityId = entityId;
3509
3648
  }
3510
3649
  const componentOptions = {
@@ -3536,9 +3675,9 @@ function createCapsule({
3536
3675
  scene,
3537
3676
  payload
3538
3677
  }) {
3539
- const geometry = new THREE51__namespace.CapsuleGeometry(0.5, 1, 4, 8);
3540
- const material = new THREE51__namespace.MeshStandardMaterial({ color: "#ffffff" });
3541
- const mesh = new THREE51__namespace.Mesh(geometry, material);
3678
+ const geometry = new THREE56__namespace.CapsuleGeometry(0.5, 1, 4, 8);
3679
+ const material = new THREE56__namespace.MeshStandardMaterial({ color: "#ffffff" });
3680
+ const mesh = new THREE56__namespace.Mesh(geometry, material);
3542
3681
  const entityId = createBaseEntity(world, mesh, {
3543
3682
  label: payload.name ?? "Capsule",
3544
3683
  entityType: "capsule",
@@ -3558,9 +3697,9 @@ function createCapsule({
3558
3697
  }
3559
3698
  __name(createCapsule, "createCapsule");
3560
3699
  function createCube({ world, scene, payload }) {
3561
- const geometry = new THREE51__namespace.BoxGeometry(1, 1, 1);
3562
- const material = new THREE51__namespace.MeshStandardMaterial({ color: "#ffffff" });
3563
- const mesh = new THREE51__namespace.Mesh(geometry, material);
3700
+ const geometry = new THREE56__namespace.BoxGeometry(1, 1, 1);
3701
+ const material = new THREE56__namespace.MeshStandardMaterial({ color: "#ffffff" });
3702
+ const mesh = new THREE56__namespace.Mesh(geometry, material);
3564
3703
  const entityId = createBaseEntity(world, mesh, {
3565
3704
  label: payload.name ?? "Cube",
3566
3705
  entityType: "cube",
@@ -3585,9 +3724,9 @@ function createCylinder({
3585
3724
  scene,
3586
3725
  payload
3587
3726
  }) {
3588
- const geometry = new THREE51__namespace.CylinderGeometry(0.5, 0.5, 1, 20);
3589
- const material = new THREE51__namespace.MeshStandardMaterial({ color: "#ffffff" });
3590
- const mesh = new THREE51__namespace.Mesh(geometry, material);
3727
+ const geometry = new THREE56__namespace.CylinderGeometry(0.5, 0.5, 1, 20);
3728
+ const material = new THREE56__namespace.MeshStandardMaterial({ color: "#ffffff" });
3729
+ const mesh = new THREE56__namespace.Mesh(geometry, material);
3591
3730
  const entityId = createBaseEntity(world, mesh, {
3592
3731
  label: payload.name ?? "Cylinder",
3593
3732
  entityType: "cylinder",
@@ -3607,7 +3746,7 @@ function createCylinder({
3607
3746
  }
3608
3747
  __name(createCylinder, "createCylinder");
3609
3748
  function createEmpty({ world, scene, payload, isEditor }) {
3610
- const object = new THREE51__namespace.Group();
3749
+ const object = new THREE56__namespace.Group();
3611
3750
  const entityId = createBaseEntity(world, object, {
3612
3751
  label: payload.name ?? "Empty",
3613
3752
  entityType: "empty",
@@ -3618,7 +3757,7 @@ function createEmpty({ world, scene, payload, isEditor }) {
3618
3757
  }
3619
3758
  __name(createEmpty, "createEmpty");
3620
3759
  function createImage({ world, scene, payload }) {
3621
- const anchor = new THREE51__namespace.Object3D();
3760
+ const anchor = new THREE56__namespace.Object3D();
3622
3761
  const imagePath = payload.path ?? "";
3623
3762
  const entityId = createBaseEntity(world, anchor, {
3624
3763
  label: payload.name ?? "Image",
@@ -3631,7 +3770,7 @@ function createImage({ world, scene, payload }) {
3631
3770
  if (!imagePath) {
3632
3771
  return entityId;
3633
3772
  }
3634
- const loader = new THREE51__namespace.TextureLoader();
3773
+ const loader = new THREE56__namespace.TextureLoader();
3635
3774
  loader.load(
3636
3775
  imagePath,
3637
3776
  (texture) => {
@@ -3639,13 +3778,13 @@ function createImage({ world, scene, payload }) {
3639
3778
  texture.dispose();
3640
3779
  return;
3641
3780
  }
3642
- const material = new THREE51__namespace.MeshBasicMaterial({
3781
+ const material = new THREE56__namespace.MeshBasicMaterial({
3643
3782
  map: texture,
3644
3783
  transparent: true,
3645
- side: THREE51__namespace.DoubleSide
3784
+ side: THREE56__namespace.DoubleSide
3646
3785
  });
3647
- const geometry = new THREE51__namespace.PlaneGeometry(1, 1);
3648
- const plane = new THREE51__namespace.Mesh(geometry, material);
3786
+ const geometry = new THREE56__namespace.PlaneGeometry(1, 1);
3787
+ const plane = new THREE56__namespace.Mesh(geometry, material);
3649
3788
  plane.userData.entityId = entityId;
3650
3789
  const textureImage = texture.image;
3651
3790
  const width = textureImage?.width ?? 1;
@@ -3691,7 +3830,7 @@ function createImageTarget({
3691
3830
  payload,
3692
3831
  isEditor
3693
3832
  }) {
3694
- const anchor = new THREE51__namespace.Object3D();
3833
+ const anchor = new THREE56__namespace.Object3D();
3695
3834
  const imagePath = payload.path ?? "";
3696
3835
  const entityId = createBaseEntity(world, anchor, {
3697
3836
  label: payload.name ?? "Image Target",
@@ -3708,7 +3847,7 @@ function createImageTarget({
3708
3847
  if (!isEditor || !imagePath) {
3709
3848
  return entityId;
3710
3849
  }
3711
- const loader = new THREE51__namespace.TextureLoader();
3850
+ const loader = new THREE56__namespace.TextureLoader();
3712
3851
  loader.load(
3713
3852
  imagePath,
3714
3853
  (texture) => {
@@ -3716,13 +3855,13 @@ function createImageTarget({
3716
3855
  texture.dispose();
3717
3856
  return;
3718
3857
  }
3719
- const material = new THREE51__namespace.MeshBasicMaterial({
3858
+ const material = new THREE56__namespace.MeshBasicMaterial({
3720
3859
  map: texture,
3721
3860
  transparent: true,
3722
- side: THREE51__namespace.DoubleSide
3861
+ side: THREE56__namespace.DoubleSide
3723
3862
  });
3724
- const geometry = new THREE51__namespace.PlaneGeometry(1, 1);
3725
- const plane = new THREE51__namespace.Mesh(geometry, material);
3863
+ const geometry = new THREE56__namespace.PlaneGeometry(1, 1);
3864
+ const plane = new THREE56__namespace.Mesh(geometry, material);
3726
3865
  plane.userData.entityId = entityId;
3727
3866
  const textureImage = texture.image;
3728
3867
  const width = textureImage?.width ?? 1;
@@ -3773,7 +3912,7 @@ function createInstancedMesh({
3773
3912
  scene,
3774
3913
  payload
3775
3914
  }) {
3776
- const anchor = new THREE51__namespace.Object3D();
3915
+ const anchor = new THREE56__namespace.Object3D();
3777
3916
  const opts = payload.options ?? {};
3778
3917
  const meshKind = isInstancedMeshKind(opts.meshKind) ? opts.meshKind : "cube";
3779
3918
  const meshParameters = opts.meshParameters && typeof opts.meshParameters === "object" ? opts.meshParameters : void 0;
@@ -3844,7 +3983,7 @@ function createAmbientLight({
3844
3983
  scene,
3845
3984
  payload
3846
3985
  }) {
3847
- const light = new THREE51__namespace.AmbientLight("#ffffff", 0.6);
3986
+ const light = new THREE56__namespace.AmbientLight("#ffffff", 0.6);
3848
3987
  const entityId = createBaseEntity(world, light, {
3849
3988
  label: payload.name ?? "Ambient Light",
3850
3989
  entityType: "ambientLight",
@@ -3861,7 +4000,7 @@ function createAreaLight({
3861
4000
  payload,
3862
4001
  isEditor
3863
4002
  }) {
3864
- const light = new THREE51__namespace.RectAreaLight("#ffffff", 5, 4, 4);
4003
+ const light = new THREE56__namespace.RectAreaLight("#ffffff", 5, 4, 4);
3865
4004
  light.lookAt(0, 0, 0);
3866
4005
  const entityId = createBaseEntity(world, light, {
3867
4006
  label: payload.name ?? "Area Light",
@@ -3890,7 +4029,7 @@ function createDirectionalLight({
3890
4029
  payload,
3891
4030
  isEditor
3892
4031
  }) {
3893
- const light = new THREE51__namespace.DirectionalLight("#ffffff", 1.5);
4032
+ const light = new THREE56__namespace.DirectionalLight("#ffffff", 1.5);
3894
4033
  light.castShadow = true;
3895
4034
  const entityId = createBaseEntity(world, light, {
3896
4035
  label: payload.name ?? "Directional Light",
@@ -3901,7 +4040,7 @@ function createDirectionalLight({
3901
4040
  });
3902
4041
  createLightComponent(world, entityId, light);
3903
4042
  if (isEditor) {
3904
- const helper = new THREE51__namespace.DirectionalLightHelper(light, 1.8, "#38bdf8");
4043
+ const helper = new THREE56__namespace.DirectionalLightHelper(light, 1.8, "#38bdf8");
3905
4044
  helper.onBeforeRender = () => {
3906
4045
  helper.update();
3907
4046
  };
@@ -3919,7 +4058,7 @@ function createPointLight({
3919
4058
  payload,
3920
4059
  isEditor
3921
4060
  }) {
3922
- const light = new THREE51__namespace.PointLight("#ffffff", 1, 10);
4061
+ const light = new THREE56__namespace.PointLight("#ffffff", 1, 10);
3923
4062
  const entityId = createBaseEntity(world, light, {
3924
4063
  label: payload.name ?? "Point Light",
3925
4064
  entityType: "pointLight",
@@ -3929,7 +4068,7 @@ function createPointLight({
3929
4068
  });
3930
4069
  createLightComponent(world, entityId, light);
3931
4070
  if (isEditor) {
3932
- const helper = new THREE51__namespace.PointLightHelper(light, 0.35, "#fbbf24");
4071
+ const helper = new THREE56__namespace.PointLightHelper(light, 0.35, "#fbbf24");
3933
4072
  helper.onBeforeRender = () => {
3934
4073
  helper.update();
3935
4074
  };
@@ -3947,7 +4086,7 @@ function createSpotLight({
3947
4086
  payload,
3948
4087
  isEditor
3949
4088
  }) {
3950
- const light = new THREE51__namespace.SpotLight("#ffffff", 1, 20, Math.PI / 6, 0.1, 1);
4089
+ const light = new THREE56__namespace.SpotLight("#ffffff", 1, 20, Math.PI / 6, 0.1, 1);
3951
4090
  const entityId = createBaseEntity(world, light, {
3952
4091
  label: payload.name ?? "Spot Light",
3953
4092
  entityType: "spotLight",
@@ -3957,7 +4096,7 @@ function createSpotLight({
3957
4096
  });
3958
4097
  createLightComponent(world, entityId, light);
3959
4098
  if (isEditor) {
3960
- const helper = new THREE51__namespace.SpotLightHelper(light, "#f59e0b");
4099
+ const helper = new THREE56__namespace.SpotLightHelper(light, "#f59e0b");
3961
4100
  helper.onBeforeRender = () => {
3962
4101
  helper.update();
3963
4102
  };
@@ -4042,6 +4181,11 @@ __export(components_exports, {
4042
4181
  SelectionTransformState: () => SelectionTransformState,
4043
4182
  SpriteComponent: () => SpriteComponent,
4044
4183
  TransformComponent: () => TransformComponent,
4184
+ UIButtonComponent: () => UIButtonComponent,
4185
+ UIPanelComponent: () => UIPanelComponent,
4186
+ UISliderComponent: () => UISliderComponent,
4187
+ UITextComponent: () => UITextComponent,
4188
+ UIToggleComponent: () => UIToggleComponent,
4045
4189
  VRTeleportAreaComponent: () => VRTeleportAreaComponent,
4046
4190
  VideoComponent: () => VideoComponent,
4047
4191
  XRAnchorComponent: () => XRAnchorComponent,
@@ -4124,7 +4268,7 @@ function createModel({
4124
4268
  payload,
4125
4269
  isEditor
4126
4270
  }) {
4127
- const anchor = new THREE51__namespace.Object3D();
4271
+ const anchor = new THREE56__namespace.Object3D();
4128
4272
  const modelPath = payload.path ?? "";
4129
4273
  const entityId = createBaseEntity(world, anchor, {
4130
4274
  label: payload.name ?? "Model",
@@ -4190,12 +4334,12 @@ function createModel({
4190
4334
  }
4191
4335
  __name(createModel, "createModel");
4192
4336
  function createPlane({ world, scene, payload }) {
4193
- const geometry = new THREE51__namespace.PlaneGeometry(100, 100);
4194
- const material = new THREE51__namespace.MeshStandardMaterial({
4337
+ const geometry = new THREE56__namespace.PlaneGeometry(100, 100);
4338
+ const material = new THREE56__namespace.MeshStandardMaterial({
4195
4339
  color: "#ffffff",
4196
- side: THREE51__namespace.DoubleSide
4340
+ side: THREE56__namespace.DoubleSide
4197
4341
  });
4198
- const mesh = new THREE51__namespace.Mesh(geometry, material);
4342
+ const mesh = new THREE56__namespace.Mesh(geometry, material);
4199
4343
  const entityId = createBaseEntity(
4200
4344
  world,
4201
4345
  mesh,
@@ -4231,7 +4375,7 @@ function createScriptObject({
4231
4375
  scene,
4232
4376
  payload
4233
4377
  }) {
4234
- const object = new THREE51__namespace.Group();
4378
+ const object = new THREE56__namespace.Group();
4235
4379
  const entityId = createBaseEntity(world, object, {
4236
4380
  label: payload.name ?? "Script Object",
4237
4381
  entityType: "scriptObject",
@@ -4256,15 +4400,15 @@ function createTeleportArea({
4256
4400
  const options = payload.options ?? {};
4257
4401
  const width = typeof options.width === "number" ? options.width : 10;
4258
4402
  const depth = typeof options.depth === "number" ? options.depth : 10;
4259
- const geometry = new THREE51__namespace.PlaneGeometry(width, depth);
4260
- const material = new THREE51__namespace.MeshBasicMaterial({
4403
+ const geometry = new THREE56__namespace.PlaneGeometry(width, depth);
4404
+ const material = new THREE56__namespace.MeshBasicMaterial({
4261
4405
  color: "#4da3ff",
4262
4406
  transparent: true,
4263
4407
  opacity: 0.18,
4264
- side: THREE51__namespace.DoubleSide,
4408
+ side: THREE56__namespace.DoubleSide,
4265
4409
  depthWrite: false
4266
4410
  });
4267
- const object = new THREE51__namespace.Mesh(geometry, material);
4411
+ const object = new THREE56__namespace.Mesh(geometry, material);
4268
4412
  const entityId = createBaseEntity(world, object, {
4269
4413
  label: payload.name ?? "Teleport Area",
4270
4414
  entityType: "teleportArea",
@@ -4292,7 +4436,7 @@ function createXRInteractor({
4292
4436
  scene,
4293
4437
  payload
4294
4438
  }) {
4295
- const root = new THREE51__namespace.Group();
4439
+ const root = new THREE56__namespace.Group();
4296
4440
  const options = payload.options ?? {};
4297
4441
  const entityId = createBaseEntity(world, root, {
4298
4442
  label: payload.name ?? "XR Interactor",
@@ -4305,7 +4449,7 @@ function createXRInteractor({
4305
4449
  return entityId;
4306
4450
  }
4307
4451
  for (const side of ["left", "right"]) {
4308
- const slot = new THREE51__namespace.Group();
4452
+ const slot = new THREE56__namespace.Group();
4309
4453
  const label = side === "left" ? "Left Interactor" : "Right Interactor";
4310
4454
  const slotEntityId = createBaseEntity(world, slot, {
4311
4455
  label,
@@ -4318,12 +4462,121 @@ function createXRInteractor({
4318
4462
  return entityId;
4319
4463
  }
4320
4464
  __name(createXRInteractor, "createXRInteractor");
4465
+ function createUIButton({
4466
+ world,
4467
+ scene,
4468
+ payload
4469
+ }) {
4470
+ const object = new THREE56__namespace.Group();
4471
+ const entityId = createBaseEntity(world, object, {
4472
+ label: payload.name ?? "UI Button",
4473
+ entityType: "uiButton",
4474
+ transformInput: payload.transform
4475
+ });
4476
+ const options = payload.options ?? {};
4477
+ world.addComponent(entityId, new UIButtonComponent(options));
4478
+ world.addComponent(
4479
+ entityId,
4480
+ new XRInteractableComponent({
4481
+ grabbable: false,
4482
+ pointable: true,
4483
+ hoverBehavior: "color"
4484
+ })
4485
+ );
4486
+ scene.add(object);
4487
+ return entityId;
4488
+ }
4489
+ __name(createUIButton, "createUIButton");
4490
+ function createUIPanel({
4491
+ world,
4492
+ scene,
4493
+ payload
4494
+ }) {
4495
+ const object = new THREE56__namespace.Group();
4496
+ const entityId = createBaseEntity(world, object, {
4497
+ label: payload.name ?? "UI Panel",
4498
+ entityType: "uiPanel",
4499
+ transformInput: payload.transform
4500
+ });
4501
+ const options = payload.options ?? {};
4502
+ world.addComponent(entityId, new UIPanelComponent(options));
4503
+ scene.add(object);
4504
+ return entityId;
4505
+ }
4506
+ __name(createUIPanel, "createUIPanel");
4507
+ function createUISlider({
4508
+ world,
4509
+ scene,
4510
+ payload
4511
+ }) {
4512
+ const object = new THREE56__namespace.Group();
4513
+ const entityId = createBaseEntity(world, object, {
4514
+ label: payload.name ?? "UI Slider",
4515
+ entityType: "uiSlider",
4516
+ transformInput: payload.transform
4517
+ });
4518
+ const options = payload.options ?? {};
4519
+ world.addComponent(entityId, new UISliderComponent(options));
4520
+ world.addComponent(
4521
+ entityId,
4522
+ new XRInteractableComponent({
4523
+ grabbable: false,
4524
+ pointable: true,
4525
+ hoverBehavior: "none"
4526
+ })
4527
+ );
4528
+ scene.add(object);
4529
+ return entityId;
4530
+ }
4531
+ __name(createUISlider, "createUISlider");
4532
+ function createUIText({
4533
+ world,
4534
+ scene,
4535
+ payload
4536
+ }) {
4537
+ const object = new THREE56__namespace.Group();
4538
+ const entityId = createBaseEntity(world, object, {
4539
+ label: payload.name ?? "UI Text",
4540
+ entityType: "uiText",
4541
+ transformInput: payload.transform
4542
+ });
4543
+ const options = payload.options ?? {};
4544
+ world.addComponent(entityId, new UITextComponent(options));
4545
+ scene.add(object);
4546
+ return entityId;
4547
+ }
4548
+ __name(createUIText, "createUIText");
4549
+ function createUIToggle({
4550
+ world,
4551
+ scene,
4552
+ payload
4553
+ }) {
4554
+ const object = new THREE56__namespace.Group();
4555
+ const entityId = createBaseEntity(world, object, {
4556
+ label: payload.name ?? "UI Toggle",
4557
+ entityType: "uiToggle",
4558
+ transformInput: payload.transform
4559
+ });
4560
+ const options = payload.options ?? {};
4561
+ world.addComponent(entityId, new UIToggleComponent(options));
4562
+ world.addComponent(
4563
+ entityId,
4564
+ new XRInteractableComponent({
4565
+ grabbable: false,
4566
+ pointable: true,
4567
+ hoverBehavior: "color"
4568
+ })
4569
+ );
4570
+ scene.add(object);
4571
+ return entityId;
4572
+ }
4573
+ __name(createUIToggle, "createUIToggle");
4321
4574
  function createXRRig({
4322
4575
  world,
4323
4576
  scene,
4324
4577
  payload
4325
4578
  }) {
4326
- const object = new THREE51__namespace.Group();
4579
+ const object = new THREE56__namespace.Group();
4327
4580
  const entityId = createBaseEntity(world, object, {
4328
4581
  label: payload.name ?? "XR Rig",
4329
4582
  entityType: "xrRig",
@@ -4336,7 +4589,7 @@ function createXRRig({
4336
4589
  }
4337
4590
  __name(createXRRig, "createXRRig");
4338
4591
  function createSprite({ world, scene, payload }) {
4339
- const anchor = new THREE51__namespace.Object3D();
4592
+ const anchor = new THREE56__namespace.Object3D();
4340
4593
  const imagePath = payload.path ?? "";
4341
4594
  const entityId = createBaseEntity(world, anchor, {
4342
4595
  label: payload.name ?? "Sprite",
@@ -4348,7 +4601,7 @@ function createSprite({ world, scene, payload }) {
4348
4601
  if (!imagePath) {
4349
4602
  return entityId;
4350
4603
  }
4351
- const loader = new THREE51__namespace.TextureLoader();
4604
+ const loader = new THREE56__namespace.TextureLoader();
4352
4605
  loader.load(
4353
4606
  imagePath,
4354
4607
  (texture) => {
@@ -4356,11 +4609,11 @@ function createSprite({ world, scene, payload }) {
4356
4609
  texture.dispose();
4357
4610
  return;
4358
4611
  }
4359
- const material = new THREE51__namespace.SpriteMaterial({
4612
+ const material = new THREE56__namespace.SpriteMaterial({
4360
4613
  map: texture,
4361
4614
  transparent: true
4362
4615
  });
4363
- const sprite = new THREE51__namespace.Sprite(material);
4616
+ const sprite = new THREE56__namespace.Sprite(material);
4364
4617
  sprite.userData.entityId = entityId;
4365
4618
  const textureImage = texture.image;
4366
4619
  spriteComponent.width = textureImage?.width ?? 1;
@@ -4378,9 +4631,9 @@ function createSprite({ world, scene, payload }) {
4378
4631
  }
4379
4632
  __name(createSprite, "createSprite");
4380
4633
  function createSphere({ world, scene, payload }) {
4381
- const geometry = new THREE51__namespace.SphereGeometry(0.5, 24, 24);
4382
- const material = new THREE51__namespace.MeshStandardMaterial({ color: "#ffffff" });
4383
- const mesh = new THREE51__namespace.Mesh(geometry, material);
4634
+ const geometry = new THREE56__namespace.SphereGeometry(0.5, 24, 24);
4635
+ const material = new THREE56__namespace.MeshStandardMaterial({ color: "#ffffff" });
4636
+ const mesh = new THREE56__namespace.Mesh(geometry, material);
4384
4637
  const entityId = createBaseEntity(world, mesh, {
4385
4638
  label: payload.name ?? "Sphere",
4386
4639
  entityType: "sphere",
@@ -4400,10 +4653,10 @@ function createSphere({ world, scene, payload }) {
4400
4653
  __name(createSphere, "createSphere");
4401
4654
  function getOrCreateListener2(camera) {
4402
4655
  const existing = camera.userData.ecsAudioListener;
4403
- if (existing instanceof THREE51__namespace.AudioListener) {
4656
+ if (existing instanceof THREE56__namespace.AudioListener) {
4404
4657
  return existing;
4405
4658
  }
4406
- const listener = new THREE51__namespace.AudioListener();
4659
+ const listener = new THREE56__namespace.AudioListener();
4407
4660
  camera.add(listener);
4408
4661
  camera.userData.ecsAudioListener = listener;
4409
4662
  return listener;
@@ -4453,10 +4706,10 @@ function normalizeOptions(input) {
4453
4706
  }
4454
4707
  __name(normalizeOptions, "normalizeOptions");
4455
4708
  function createChromaMaterial(texture, options) {
4456
- return new THREE51__namespace.ShaderMaterial({
4709
+ return new THREE56__namespace.ShaderMaterial({
4457
4710
  uniforms: {
4458
4711
  tex: { value: texture },
4459
- keyColor: { value: new THREE51__namespace.Color(options.backgroundColor) },
4712
+ keyColor: { value: new THREE56__namespace.Color(options.backgroundColor) },
4460
4713
  similarity: { value: options.similarity },
4461
4714
  smoothness: { value: options.smoothness },
4462
4715
  spill: { value: options.spill }
@@ -4488,22 +4741,22 @@ function createChromaMaterial(texture, options) {
4488
4741
  }
4489
4742
  `,
4490
4743
  transparent: true,
4491
- side: THREE51__namespace.DoubleSide
4744
+ side: THREE56__namespace.DoubleSide
4492
4745
  });
4493
4746
  }
4494
4747
  __name(createChromaMaterial, "createChromaMaterial");
4495
4748
  function createStandardMaterial(texture) {
4496
- return new THREE51__namespace.MeshBasicMaterial({
4749
+ return new THREE56__namespace.MeshBasicMaterial({
4497
4750
  map: texture,
4498
4751
  transparent: true,
4499
- side: THREE51__namespace.DoubleSide
4752
+ side: THREE56__namespace.DoubleSide
4500
4753
  });
4501
4754
  }
4502
4755
  __name(createStandardMaterial, "createStandardMaterial");
4503
4756
  function createVideoMesh(entityId, texture, options) {
4504
- const geometry = new THREE51__namespace.PlaneGeometry(1, 1);
4757
+ const geometry = new THREE56__namespace.PlaneGeometry(1, 1);
4505
4758
  const material = options.isGreenScreen ? createChromaMaterial(texture, options) : createStandardMaterial(texture);
4506
- const mesh = new THREE51__namespace.Mesh(geometry, material);
4759
+ const mesh = new THREE56__namespace.Mesh(geometry, material);
4507
4760
  mesh.userData.entityId = entityId;
4508
4761
  mesh.scale.set(options.width, options.height, 1);
4509
4762
  return { mesh, material };
@@ -4538,7 +4791,7 @@ function createVideo({
4538
4791
  payload,
4539
4792
  isEditor
4540
4793
  }) {
4541
- const anchor = new THREE51__namespace.Object3D();
4794
+ const anchor = new THREE56__namespace.Object3D();
4542
4795
  const path = payload.path ?? "";
4543
4796
  const options = normalizeOptions(payload.options);
4544
4797
  const entityId = createBaseEntity(world, anchor, {
@@ -4553,8 +4806,8 @@ function createVideo({
4553
4806
  return entityId;
4554
4807
  }
4555
4808
  const video = createVideoElement(path, options);
4556
- const texture = new THREE51__namespace.VideoTexture(video);
4557
- texture.colorSpace = THREE51__namespace.SRGBColorSpace;
4809
+ const texture = new THREE56__namespace.VideoTexture(video);
4810
+ texture.colorSpace = THREE56__namespace.SRGBColorSpace;
4558
4811
  texture.needsUpdate = true;
4559
4812
  const { mesh, material } = createVideoMesh(entityId, texture, options);
4560
4813
  anchor.add(mesh);
@@ -4570,7 +4823,7 @@ function createVideo({
4570
4823
  });
4571
4824
  if (!isEditor && options.positional) {
4572
4825
  const listener = getOrCreateListener2(camera);
4573
- const audioNode = new THREE51__namespace.PositionalAudio(listener);
4826
+ const audioNode = new THREE56__namespace.PositionalAudio(listener);
4574
4827
  audioNode.setVolume(options.volume);
4575
4828
  audioNode.setRefDistance(options.refDistance);
4576
4829
  audioNode.setDistanceModel(normalizeDistanceModel2(options.distanceModel));
@@ -4613,6 +4866,11 @@ function registerDefaultFactories(objectManagementSystem) {
4613
4866
  objectManagementSystem.register("xrRig", createXRRig);
4614
4867
  objectManagementSystem.register("xrInteractor", createXRInteractor);
4615
4868
  objectManagementSystem.register("teleportArea", createTeleportArea);
4869
+ objectManagementSystem.register("uiPanel", createUIPanel);
4870
+ objectManagementSystem.register("uiText", createUIText);
4871
+ objectManagementSystem.register("uiButton", createUIButton);
4872
+ objectManagementSystem.register("uiToggle", createUIToggle);
4873
+ objectManagementSystem.register("uiSlider", createUISlider);
4616
4874
  registerDefaultComponentFactories(objectManagementSystem);
4617
4875
  }
4618
4876
  __name(registerDefaultFactories, "registerDefaultFactories");
@@ -4763,6 +5021,11 @@ function buildComponentValueMaps(snapshot) {
4763
5021
  "XRHandPoseComponent"
4764
5022
  ),
4765
5023
  xrAnchorValues: readByComponent(snapshot.components, "XRAnchorComponent"),
5024
+ uiPanelValues: readByComponent(snapshot.components, "UIPanelComponent"),
5025
+ uiTextValues: readByComponent(snapshot.components, "UITextComponent"),
5026
+ uiButtonValues: readByComponent(snapshot.components, "UIButtonComponent"),
5027
+ uiToggleValues: readByComponent(snapshot.components, "UIToggleComponent"),
5028
+ uiSliderValues: readByComponent(snapshot.components, "UISliderComponent"),
4766
5029
  xrInteractorSideValues: readByComponent(
4767
5030
  snapshot.components,
4768
5031
  "XRInteractorSideComponent"
@@ -5084,6 +5347,49 @@ function restorePostCreateComponents(world, objectManagementSystem, targetEntity
5084
5347
  }
5085
5348
  }
5086
5349
  }
5350
+ {
5351
+ const restoreUi = /* @__PURE__ */ __name((map, Ctor, existing) => {
5352
+ const source = asRecord3(map.get(sourceEntityId));
5353
+ if (!source) return;
5354
+ let component = existing;
5355
+ if (!component) {
5356
+ component = new Ctor();
5357
+ world.addComponent(targetEntityId, component);
5358
+ }
5359
+ const target = component;
5360
+ for (const [key, value] of Object.entries(source)) {
5361
+ const current = target[key];
5362
+ if ((typeof value === "string" || typeof value === "number" || typeof value === "boolean") && typeof current === typeof value) {
5363
+ target[key] = value;
5364
+ }
5365
+ }
5366
+ }, "restoreUi");
5367
+ restoreUi(
5368
+ values.uiPanelValues,
5369
+ UIPanelComponent,
5370
+ world.getComponent(targetEntityId, UIPanelComponent)
5371
+ );
5372
+ restoreUi(
5373
+ values.uiTextValues,
5374
+ UITextComponent,
5375
+ world.getComponent(targetEntityId, UITextComponent)
5376
+ );
5377
+ restoreUi(
5378
+ values.uiButtonValues,
5379
+ UIButtonComponent,
5380
+ world.getComponent(targetEntityId, UIButtonComponent)
5381
+ );
5382
+ restoreUi(
5383
+ values.uiToggleValues,
5384
+ UIToggleComponent,
5385
+ world.getComponent(targetEntityId, UIToggleComponent)
5386
+ );
5387
+ restoreUi(
5388
+ values.uiSliderValues,
5389
+ UISliderComponent,
5390
+ world.getComponent(targetEntityId, UISliderComponent)
5391
+ );
5392
+ }
5087
5393
  {
5088
5394
  const sourceInteractor = asRecord3(
5089
5395
  values.xrInteractorValues.get(sourceEntityId)
@@ -6841,7 +7147,7 @@ function transitionToClip(runtime, nextClipId, crossFadeDuration) {
6841
7147
  }
6842
7148
  __name(transitionToClip, "transitionToClip");
6843
7149
  function applyActionState(action, component, paused, shouldLoop) {
6844
- const loopMode = shouldLoop ? THREE51__namespace.LoopRepeat : THREE51__namespace.LoopOnce;
7150
+ const loopMode = shouldLoop ? THREE56__namespace.LoopRepeat : THREE56__namespace.LoopOnce;
6845
7151
  const repetitions = shouldLoop ? Infinity : 1;
6846
7152
  action.setLoop(loopMode, repetitions);
6847
7153
  action.clampWhenFinished = !shouldLoop;
@@ -7014,7 +7320,7 @@ var _AnimationSystem = class _AnimationSystem {
7014
7320
  if (runtime) {
7015
7321
  stopAllActions(runtime);
7016
7322
  }
7017
- const mixer = new THREE51__namespace.AnimationMixer(root);
7323
+ const mixer = new THREE56__namespace.AnimationMixer(root);
7018
7324
  const entries2 = readRuntimeClipEntries(animation);
7019
7325
  const indexedActions = createActions(mixer, entries2);
7020
7326
  runtime = {
@@ -7140,11 +7446,11 @@ function normalizeOrthoBounds(component) {
7140
7446
  }
7141
7447
  __name(normalizeOrthoBounds, "normalizeOrthoBounds");
7142
7448
  function isPerspectiveCamera(camera) {
7143
- return camera instanceof THREE51__namespace.PerspectiveCamera;
7449
+ return camera instanceof THREE56__namespace.PerspectiveCamera;
7144
7450
  }
7145
7451
  __name(isPerspectiveCamera, "isPerspectiveCamera");
7146
7452
  function isOrthographicCamera(camera) {
7147
- return camera instanceof THREE51__namespace.OrthographicCamera;
7453
+ return camera instanceof THREE56__namespace.OrthographicCamera;
7148
7454
  }
7149
7455
  __name(isOrthographicCamera, "isOrthographicCamera");
7150
7456
  function readWindowAspect() {
@@ -7198,7 +7504,7 @@ var _CameraSyncSystem = class _CameraSyncSystem {
7198
7504
  continue;
7199
7505
  }
7200
7506
  const camera = objectRef.object;
7201
- if (!(camera instanceof THREE51__namespace.Camera)) {
7507
+ if (!(camera instanceof THREE56__namespace.Camera)) {
7202
7508
  continue;
7203
7509
  }
7204
7510
  if (xrCamera !== null && camera === xrCamera) {
@@ -7265,7 +7571,7 @@ var MIN_DENSITY = 0;
7265
7571
  function createGradientTexture(effect, colors) {
7266
7572
  if (typeof document === "undefined") {
7267
7573
  const pixel = new Uint8Array([30, 30, 30, 255]);
7268
- const fallback = new THREE51__namespace.DataTexture(pixel, 1, 1, THREE51__namespace.RGBAFormat);
7574
+ const fallback = new THREE56__namespace.DataTexture(pixel, 1, 1, THREE56__namespace.RGBAFormat);
7269
7575
  fallback.needsUpdate = true;
7270
7576
  return fallback;
7271
7577
  }
@@ -7274,7 +7580,7 @@ function createGradientTexture(effect, colors) {
7274
7580
  canvas.height = 512;
7275
7581
  const context = canvas.getContext("2d");
7276
7582
  if (!context) {
7277
- const fallback = new THREE51__namespace.CanvasTexture(canvas);
7583
+ const fallback = new THREE56__namespace.CanvasTexture(canvas);
7278
7584
  fallback.needsUpdate = true;
7279
7585
  return fallback;
7280
7586
  }
@@ -7302,15 +7608,15 @@ function createGradientTexture(effect, colors) {
7302
7608
  context.fillRect(0, 0, 512, 512);
7303
7609
  context.globalCompositeOperation = "source-over";
7304
7610
  }
7305
- const texture = new THREE51__namespace.CanvasTexture(canvas);
7306
- texture.colorSpace = THREE51__namespace.SRGBColorSpace;
7611
+ const texture = new THREE56__namespace.CanvasTexture(canvas);
7612
+ texture.colorSpace = THREE56__namespace.SRGBColorSpace;
7307
7613
  texture.needsUpdate = true;
7308
7614
  return texture;
7309
7615
  }
7310
7616
  __name(createGradientTexture, "createGradientTexture");
7311
7617
  var _EnvironmentSyncSystem = class _EnvironmentSyncSystem {
7312
7618
  constructor(scene) {
7313
- this.textureLoader = new THREE51__namespace.TextureLoader();
7619
+ this.textureLoader = new THREE56__namespace.TextureLoader();
7314
7620
  this.signature = null;
7315
7621
  this.activeTexture = null;
7316
7622
  this.pendingImageUrl = null;
@@ -7335,7 +7641,7 @@ var _EnvironmentSyncSystem = class _EnvironmentSyncSystem {
7335
7641
  if (skybox.type === "color") {
7336
7642
  this.disposeActiveTexture();
7337
7643
  this.pendingImageUrl = null;
7338
- this.scene.background = new THREE51__namespace.Color(skybox.color || "#1e1e1e");
7644
+ this.scene.background = new THREE56__namespace.Color(skybox.color || "#1e1e1e");
7339
7645
  return;
7340
7646
  }
7341
7647
  if (skybox.type === "gradient") {
@@ -7369,7 +7675,7 @@ var _EnvironmentSyncSystem = class _EnvironmentSyncSystem {
7369
7675
  texture.dispose();
7370
7676
  return;
7371
7677
  }
7372
- texture.colorSpace = THREE51__namespace.SRGBColorSpace;
7678
+ texture.colorSpace = THREE56__namespace.SRGBColorSpace;
7373
7679
  this.activeTexture = texture;
7374
7680
  this.scene.background = texture;
7375
7681
  },
@@ -7388,16 +7694,16 @@ var _EnvironmentSyncSystem = class _EnvironmentSyncSystem {
7388
7694
  this.scene.fog = null;
7389
7695
  return;
7390
7696
  }
7391
- const fogColor = new THREE51__namespace.Color(fog.color || "#1e1e1e");
7697
+ const fogColor = new THREE56__namespace.Color(fog.color || "#1e1e1e");
7392
7698
  if (fog.type === "linear") {
7393
7699
  const near = Number.isFinite(fog.linear.near) ? fog.linear.near : 1;
7394
7700
  const farCandidate = Number.isFinite(fog.linear.far) ? fog.linear.far : near + 10;
7395
7701
  const far = Math.max(near + MIN_FOG_DELTA, farCandidate);
7396
- this.scene.fog = new THREE51__namespace.Fog(fogColor, near, far);
7702
+ this.scene.fog = new THREE56__namespace.Fog(fogColor, near, far);
7397
7703
  return;
7398
7704
  }
7399
7705
  const density = Number.isFinite(fog.exponential.density) ? Math.max(MIN_DENSITY, fog.exponential.density) : 2e-3;
7400
- this.scene.fog = new THREE51__namespace.FogExp2(fogColor, density);
7706
+ this.scene.fog = new THREE56__namespace.FogExp2(fogColor, density);
7401
7707
  }
7402
7708
  update(world) {
7403
7709
  const passthrough = world.isXrPassthrough();
@@ -7491,10 +7797,10 @@ var _PostprocessingSyncSystem = class _PostprocessingSyncSystem {
7491
7797
  );
7492
7798
  }
7493
7799
  if (values.bloom.enabled) {
7494
- const size = this.renderer.getSize(new THREE51__namespace.Vector2());
7800
+ const size = this.renderer.getSize(new THREE56__namespace.Vector2());
7495
7801
  composer.addPass(
7496
7802
  new UnrealBloomPass_js.UnrealBloomPass(
7497
- new THREE51__namespace.Vector2(size.width, size.height),
7803
+ new THREE56__namespace.Vector2(size.width, size.height),
7498
7804
  values.bloom.intensity,
7499
7805
  values.bloom.radius,
7500
7806
  values.bloom.threshold
@@ -7539,7 +7845,7 @@ var _PostprocessingSyncSystem = class _PostprocessingSyncSystem {
7539
7845
  if (values.dotScreen.enabled) {
7540
7846
  composer.addPass(
7541
7847
  new DotScreenPass_js.DotScreenPass(
7542
- new THREE51__namespace.Vector2(0, 0),
7848
+ new THREE56__namespace.Vector2(0, 0),
7543
7849
  values.dotScreen.angle ?? values.dotScreen.dotScreenAngle,
7544
7850
  values.dotScreen.scale ?? values.dotScreen.dotScreenScale
7545
7851
  )
@@ -7627,7 +7933,7 @@ function computeColliderState(colliderValues, object) {
7627
7933
  if (!object) {
7628
7934
  return colliderValues;
7629
7935
  }
7630
- const scale = new THREE51__namespace.Vector3();
7936
+ const scale = new THREE56__namespace.Vector3();
7631
7937
  object.getWorldScale(scale);
7632
7938
  return {
7633
7939
  ...colliderValues,
@@ -7678,8 +7984,8 @@ function createColliderDesc(RAPIER, values, triMeshData) {
7678
7984
  values.offsetPosition.y,
7679
7985
  values.offsetPosition.z
7680
7986
  );
7681
- const offsetQuaternion = new THREE51__namespace.Quaternion().setFromEuler(
7682
- new THREE51__namespace.Euler(
7987
+ const offsetQuaternion = new THREE56__namespace.Quaternion().setFromEuler(
7988
+ new THREE56__namespace.Euler(
7683
7989
  values.offsetRotation.x,
7684
7990
  values.offsetRotation.y,
7685
7991
  values.offsetRotation.z
@@ -7694,17 +8000,17 @@ function collectTriMeshParts(object) {
7694
8000
  return null;
7695
8001
  }
7696
8002
  object.updateWorldMatrix(true, true);
7697
- const worldScale = new THREE51__namespace.Vector3();
8003
+ const worldScale = new THREE56__namespace.Vector3();
7698
8004
  object.getWorldScale(worldScale);
7699
8005
  const scale = {
7700
8006
  x: Math.abs(worldScale.x) || 1,
7701
8007
  y: Math.abs(worldScale.y) || 1,
7702
8008
  z: Math.abs(worldScale.z) || 1
7703
8009
  };
7704
- const worldToObject = new THREE51__namespace.Matrix4().copy(object.matrixWorld).invert();
8010
+ const worldToObject = new THREE56__namespace.Matrix4().copy(object.matrixWorld).invert();
7705
8011
  const parts = [];
7706
8012
  object.traverse((child) => {
7707
- if (!(child instanceof THREE51__namespace.Mesh) || !child.geometry) {
8013
+ if (!(child instanceof THREE56__namespace.Mesh) || !child.geometry) {
7708
8014
  return;
7709
8015
  }
7710
8016
  const geometry = child.geometry;
@@ -7721,7 +8027,7 @@ function collectTriMeshParts(object) {
7721
8027
  if (indexCount < 3) {
7722
8028
  return;
7723
8029
  }
7724
- const relativeMatrix = new THREE51__namespace.Matrix4().multiplyMatrices(
8030
+ const relativeMatrix = new THREE56__namespace.Matrix4().multiplyMatrices(
7725
8031
  worldToObject,
7726
8032
  child.matrixWorld
7727
8033
  );
@@ -7762,7 +8068,7 @@ function createTriMeshData(collected) {
7762
8068
  }
7763
8069
  const vertices = new Float32Array(vertexTotal * 3);
7764
8070
  const indices = new Uint32Array(indexTotal);
7765
- const point = new THREE51__namespace.Vector3();
8071
+ const point = new THREE56__namespace.Vector3();
7766
8072
  let vertexOffset = 0;
7767
8073
  let indexOffset = 0;
7768
8074
  for (const part of parts) {
@@ -7794,8 +8100,8 @@ function createTriMeshData(collected) {
7794
8100
  }
7795
8101
  __name(createTriMeshData, "createTriMeshData");
7796
8102
  function syncBodyFromTransform(body, transform) {
7797
- const quaternion = new THREE51__namespace.Quaternion().setFromEuler(
7798
- new THREE51__namespace.Euler(transform.rotation.x, transform.rotation.y, transform.rotation.z)
8103
+ const quaternion = new THREE56__namespace.Quaternion().setFromEuler(
8104
+ new THREE56__namespace.Euler(transform.rotation.x, transform.rotation.y, transform.rotation.z)
7799
8105
  );
7800
8106
  body.setTranslation(
7801
8107
  {
@@ -7822,8 +8128,8 @@ function syncTransformFromBody(transform, body) {
7822
8128
  transform.position.x = position.x;
7823
8129
  transform.position.y = position.y;
7824
8130
  transform.position.z = position.z;
7825
- const euler = new THREE51__namespace.Euler().setFromQuaternion(
7826
- new THREE51__namespace.Quaternion(rotation.x, rotation.y, rotation.z, rotation.w)
8131
+ const euler = new THREE56__namespace.Euler().setFromQuaternion(
8132
+ new THREE56__namespace.Quaternion(rotation.x, rotation.y, rotation.z, rotation.w)
7827
8133
  );
7828
8134
  transform.rotation.x = euler.x;
7829
8135
  transform.rotation.y = euler.y;
@@ -7936,8 +8242,8 @@ var _PhysicsSyncSystem = class _PhysicsSyncSystem {
7936
8242
  transform.position.y,
7937
8243
  transform.position.z
7938
8244
  );
7939
- const quaternion = new THREE51__namespace.Quaternion().setFromEuler(
7940
- new THREE51__namespace.Euler(
8245
+ const quaternion = new THREE56__namespace.Quaternion().setFromEuler(
8246
+ new THREE56__namespace.Euler(
7941
8247
  transform.rotation.x,
7942
8248
  transform.rotation.y,
7943
8249
  transform.rotation.z
@@ -8535,7 +8841,7 @@ function applyLightValues(lightComponent) {
8535
8841
  values.castShadow
8536
8842
  );
8537
8843
  }
8538
- if (light instanceof THREE51__namespace.PointLight) {
8844
+ if (light instanceof THREE56__namespace.PointLight) {
8539
8845
  if (typeof values.distance === "number" && Number.isFinite(values.distance)) {
8540
8846
  light.distance = Math.max(MIN_LIGHT_DISTANCE, values.distance);
8541
8847
  }
@@ -8543,7 +8849,7 @@ function applyLightValues(lightComponent) {
8543
8849
  light.decay = Math.max(0, values.decay);
8544
8850
  }
8545
8851
  }
8546
- if (light instanceof THREE51__namespace.SpotLight) {
8852
+ if (light instanceof THREE56__namespace.SpotLight) {
8547
8853
  if (typeof values.distance === "number" && Number.isFinite(values.distance)) {
8548
8854
  light.distance = Math.max(MIN_LIGHT_DISTANCE, values.distance);
8549
8855
  }
@@ -8557,7 +8863,7 @@ function applyLightValues(lightComponent) {
8557
8863
  light.penumbra = Math.max(0, Math.min(1, values.penumbra));
8558
8864
  }
8559
8865
  }
8560
- if (light instanceof THREE51__namespace.RectAreaLight) {
8866
+ if (light instanceof THREE56__namespace.RectAreaLight) {
8561
8867
  if (typeof values.width === "number" && Number.isFinite(values.width)) {
8562
8868
  light.width = Math.max(MIN_AREA_SIZE, values.width);
8563
8869
  }
@@ -8618,15 +8924,15 @@ function resolveMaterialPropertyKey(key) {
8618
8924
  __name(resolveMaterialPropertyKey, "resolveMaterialPropertyKey");
8619
8925
  function createMaterialByType(type) {
8620
8926
  if (type === "basic") {
8621
- return new THREE51__namespace.MeshBasicMaterial();
8927
+ return new THREE56__namespace.MeshBasicMaterial();
8622
8928
  }
8623
8929
  if (type === "phong") {
8624
- return new THREE51__namespace.MeshPhongMaterial();
8930
+ return new THREE56__namespace.MeshPhongMaterial();
8625
8931
  }
8626
8932
  if (type === "physical") {
8627
- return new THREE51__namespace.MeshPhysicalMaterial();
8933
+ return new THREE56__namespace.MeshPhysicalMaterial();
8628
8934
  }
8629
- return new THREE51__namespace.MeshStandardMaterial();
8935
+ return new THREE56__namespace.MeshStandardMaterial();
8630
8936
  }
8631
8937
  __name(createMaterialByType, "createMaterialByType");
8632
8938
  function replaceMaterialAcrossObject(object, previous, next) {
@@ -8685,12 +8991,12 @@ function applyTextureFiltering(material, filtering) {
8685
8991
  const target = material;
8686
8992
  for (const slot of materialTextureSlots) {
8687
8993
  const texture = target[slot];
8688
- if (!texture || !(texture instanceof THREE51__namespace.Texture)) {
8994
+ if (!texture || !(texture instanceof THREE56__namespace.Texture)) {
8689
8995
  continue;
8690
8996
  }
8691
8997
  const useMipmaps = texture.generateMipmaps !== false;
8692
- texture.magFilter = sharp ? THREE51__namespace.NearestFilter : THREE51__namespace.LinearFilter;
8693
- texture.minFilter = useMipmaps ? sharp ? THREE51__namespace.NearestMipmapNearestFilter : THREE51__namespace.LinearMipmapLinearFilter : sharp ? THREE51__namespace.NearestFilter : THREE51__namespace.LinearFilter;
8998
+ texture.magFilter = sharp ? THREE56__namespace.NearestFilter : THREE56__namespace.LinearFilter;
8999
+ texture.minFilter = useMipmaps ? sharp ? THREE56__namespace.NearestMipmapNearestFilter : THREE56__namespace.LinearMipmapLinearFilter : sharp ? THREE56__namespace.NearestFilter : THREE56__namespace.LinearFilter;
8694
9000
  texture.needsUpdate = true;
8695
9001
  }
8696
9002
  material.needsUpdate = true;
@@ -8700,12 +9006,12 @@ function setTextureMipmaps(material, enabled) {
8700
9006
  const target = material;
8701
9007
  for (const slot of materialTextureSlots) {
8702
9008
  const texture = target[slot];
8703
- if (!texture || !(texture instanceof THREE51__namespace.Texture)) {
9009
+ if (!texture || !(texture instanceof THREE56__namespace.Texture)) {
8704
9010
  continue;
8705
9011
  }
8706
9012
  texture.generateMipmaps = enabled;
8707
- const sharp = texture.magFilter === THREE51__namespace.NearestFilter;
8708
- texture.minFilter = enabled ? sharp ? THREE51__namespace.NearestMipmapNearestFilter : THREE51__namespace.LinearMipmapLinearFilter : sharp ? THREE51__namespace.NearestFilter : THREE51__namespace.LinearFilter;
9013
+ const sharp = texture.magFilter === THREE56__namespace.NearestFilter;
9014
+ texture.minFilter = enabled ? sharp ? THREE56__namespace.NearestMipmapNearestFilter : THREE56__namespace.LinearMipmapLinearFilter : sharp ? THREE56__namespace.NearestFilter : THREE56__namespace.LinearFilter;
8709
9015
  texture.needsUpdate = true;
8710
9016
  }
8711
9017
  material.needsUpdate = true;
@@ -8716,7 +9022,7 @@ function assignMaterialTexture(material, rawKey, url, textureCache) {
8716
9022
  const key = resolveMaterialPropertyKey(rawKey);
8717
9023
  let texture = textureCache.get(url);
8718
9024
  if (!texture) {
8719
- texture = new THREE51__namespace.TextureLoader().load(url);
9025
+ texture = new THREE56__namespace.TextureLoader().load(url);
8720
9026
  textureCache.set(url, texture);
8721
9027
  }
8722
9028
  target[key] = texture;
@@ -8754,7 +9060,7 @@ function applyMaterialState(material, value, textureCache) {
8754
9060
  }
8755
9061
  target.side = value.side;
8756
9062
  target.blending = value.blending;
8757
- target.premultipliedAlpha = value.blending === THREE51__namespace.MultiplyBlending || value.blending === THREE51__namespace.SubtractiveBlending;
9063
+ target.premultipliedAlpha = value.blending === THREE56__namespace.MultiplyBlending || value.blending === THREE56__namespace.SubtractiveBlending;
8758
9064
  target.depthTest = value.depthTest;
8759
9065
  target.depthWrite = value.depthWrite;
8760
9066
  target.wireframe = value.wireframe;
@@ -8915,12 +9221,12 @@ function resolvePrimaryMesh(object) {
8915
9221
  if (!object) {
8916
9222
  return null;
8917
9223
  }
8918
- if (object instanceof THREE51__namespace.Mesh) {
9224
+ if (object instanceof THREE56__namespace.Mesh) {
8919
9225
  return object;
8920
9226
  }
8921
9227
  let found = null;
8922
9228
  object.traverse((child) => {
8923
- if (!found && child instanceof THREE51__namespace.Mesh) {
9229
+ if (!found && child instanceof THREE56__namespace.Mesh) {
8924
9230
  found = child;
8925
9231
  }
8926
9232
  });
@@ -8941,22 +9247,22 @@ function applyGeometry(component) {
8941
9247
  switch (component.kind) {
8942
9248
  case "cube": {
8943
9249
  const params = sanitized;
8944
- nextGeometry = new THREE51__namespace.BoxGeometry(params.width, params.height, params.depth);
9250
+ nextGeometry = new THREE56__namespace.BoxGeometry(params.width, params.height, params.depth);
8945
9251
  break;
8946
9252
  }
8947
9253
  case "plane": {
8948
9254
  const params = sanitized;
8949
- nextGeometry = new THREE51__namespace.PlaneGeometry(params.width, params.height);
9255
+ nextGeometry = new THREE56__namespace.PlaneGeometry(params.width, params.height);
8950
9256
  break;
8951
9257
  }
8952
9258
  case "sphere": {
8953
9259
  const params = sanitized;
8954
- nextGeometry = new THREE51__namespace.SphereGeometry(params.radius, 24, 24);
9260
+ nextGeometry = new THREE56__namespace.SphereGeometry(params.radius, 24, 24);
8955
9261
  break;
8956
9262
  }
8957
9263
  case "cylinder": {
8958
9264
  const params = sanitized;
8959
- nextGeometry = new THREE51__namespace.CylinderGeometry(
9265
+ nextGeometry = new THREE56__namespace.CylinderGeometry(
8960
9266
  params.radius,
8961
9267
  params.radius,
8962
9268
  params.height,
@@ -8966,7 +9272,7 @@ function applyGeometry(component) {
8966
9272
  }
8967
9273
  case "capsule": {
8968
9274
  const params = sanitized;
8969
- nextGeometry = new THREE51__namespace.CapsuleGeometry(params.radius, params.height, 4, 8);
9275
+ nextGeometry = new THREE56__namespace.CapsuleGeometry(params.radius, params.height, 4, 8);
8970
9276
  break;
8971
9277
  }
8972
9278
  default:
@@ -8982,7 +9288,7 @@ function applyShadowFlags(component) {
8982
9288
  return;
8983
9289
  }
8984
9290
  component.object.traverse((child) => {
8985
- if (child instanceof THREE51__namespace.Mesh) {
9291
+ if (child instanceof THREE56__namespace.Mesh) {
8986
9292
  child.castShadow = component.castShadow;
8987
9293
  child.receiveShadow = component.receiveShadow;
8988
9294
  }
@@ -9065,35 +9371,35 @@ function buildGeometry(component) {
9065
9371
  switch (component.meshKind) {
9066
9372
  case "cube": {
9067
9373
  const params = p;
9068
- return new THREE51__namespace.BoxGeometry(params.width, params.height, params.depth);
9374
+ return new THREE56__namespace.BoxGeometry(params.width, params.height, params.depth);
9069
9375
  }
9070
9376
  case "plane": {
9071
9377
  const params = p;
9072
- return new THREE51__namespace.PlaneGeometry(params.width, params.height);
9378
+ return new THREE56__namespace.PlaneGeometry(params.width, params.height);
9073
9379
  }
9074
9380
  case "sphere": {
9075
9381
  const params = p;
9076
- return new THREE51__namespace.SphereGeometry(params.radius, 24, 24);
9382
+ return new THREE56__namespace.SphereGeometry(params.radius, 24, 24);
9077
9383
  }
9078
9384
  case "cylinder": {
9079
9385
  const params = p;
9080
- return new THREE51__namespace.CylinderGeometry(params.radius, params.radius, params.height, 20);
9386
+ return new THREE56__namespace.CylinderGeometry(params.radius, params.radius, params.height, 20);
9081
9387
  }
9082
9388
  case "capsule": {
9083
9389
  const params = p;
9084
- return new THREE51__namespace.CapsuleGeometry(params.radius, params.height, 4, 8);
9390
+ return new THREE56__namespace.CapsuleGeometry(params.radius, params.height, 4, 8);
9085
9391
  }
9086
9392
  default:
9087
- return new THREE51__namespace.BoxGeometry(1, 1, 1);
9393
+ return new THREE56__namespace.BoxGeometry(1, 1, 1);
9088
9394
  }
9089
9395
  }
9090
9396
  __name(buildGeometry, "buildGeometry");
9091
- var _position = new THREE51__namespace.Vector3();
9092
- var _quaternion = new THREE51__namespace.Quaternion();
9093
- var _euler = new THREE51__namespace.Euler();
9094
- var _scale = new THREE51__namespace.Vector3();
9095
- var _matrix = new THREE51__namespace.Matrix4();
9096
- var _modelMatrix = new THREE51__namespace.Matrix4();
9397
+ var _position = new THREE56__namespace.Vector3();
9398
+ var _quaternion = new THREE56__namespace.Quaternion();
9399
+ var _euler = new THREE56__namespace.Euler();
9400
+ var _scale = new THREE56__namespace.Vector3();
9401
+ var _matrix = new THREE56__namespace.Matrix4();
9402
+ var _modelMatrix = new THREE56__namespace.Matrix4();
9097
9403
  function instanceTransformFromComponent(transform, out) {
9098
9404
  _position.set(transform.position.x, transform.position.y, transform.position.z);
9099
9405
  _euler.set(transform.rotation.x, transform.rotation.y, transform.rotation.z, "XYZ");
@@ -9246,7 +9552,7 @@ var _InstancedMeshSystem = class _InstancedMeshSystem {
9246
9552
  const sourceMaterial = Array.isArray(meshChild.material) ? meshChild.material.map((m) => m.clone()) : meshChild.material.clone();
9247
9553
  meshChild.updateWorldMatrix(true, false);
9248
9554
  const localMatrix = meshChild.matrixWorld.clone();
9249
- const instancedMesh2 = new THREE51__namespace.InstancedMesh(
9555
+ const instancedMesh2 = new THREE56__namespace.InstancedMesh(
9250
9556
  geometry2,
9251
9557
  Array.isArray(sourceMaterial) ? sourceMaterial : sourceMaterial,
9252
9558
  count2
@@ -9271,7 +9577,7 @@ var _InstancedMeshSystem = class _InstancedMeshSystem {
9271
9577
  this.loadingSignatures.delete(targetEntityId);
9272
9578
  return;
9273
9579
  }
9274
- const group = new THREE51__namespace.Group();
9580
+ const group = new THREE56__namespace.Group();
9275
9581
  for (const entry of entries) {
9276
9582
  group.add(entry.instancedMesh);
9277
9583
  }
@@ -9289,8 +9595,8 @@ var _InstancedMeshSystem = class _InstancedMeshSystem {
9289
9595
  }
9290
9596
  const count = instanceCount;
9291
9597
  const geometry = buildGeometry(comp);
9292
- const material = new THREE51__namespace.MeshStandardMaterial({ color: "#ffffff" });
9293
- const instancedMesh = new THREE51__namespace.InstancedMesh(geometry, material, count);
9598
+ const material = new THREE56__namespace.MeshStandardMaterial({ color: "#ffffff" });
9599
+ const instancedMesh = new THREE56__namespace.InstancedMesh(geometry, material, count);
9294
9600
  instancedMesh.castShadow = comp.castShadow;
9295
9601
  instancedMesh.receiveShadow = comp.receiveShadow;
9296
9602
  for (let i = 0; i < count; i++) {
@@ -9473,7 +9779,7 @@ var _Behaviour = class _Behaviour {
9473
9779
  if (!this.threeRef) {
9474
9780
  return null;
9475
9781
  }
9476
- const position = new THREE51__namespace.Vector3();
9782
+ const position = new THREE56__namespace.Vector3();
9477
9783
  this.threeRef.object.getWorldPosition(position);
9478
9784
  return position;
9479
9785
  }
@@ -9485,7 +9791,7 @@ var _Behaviour = class _Behaviour {
9485
9791
  if (!this.threeRef) {
9486
9792
  return null;
9487
9793
  }
9488
- const target = new THREE51__namespace.Vector3();
9794
+ const target = new THREE56__namespace.Vector3();
9489
9795
  this.threeRef.object.getWorldDirection(target);
9490
9796
  return target;
9491
9797
  }
@@ -9547,7 +9853,7 @@ var _Behaviour = class _Behaviour {
9547
9853
  if (!this.threeRef) {
9548
9854
  return;
9549
9855
  }
9550
- const rotation = new THREE51__namespace.Quaternion();
9856
+ const rotation = new THREE56__namespace.Quaternion();
9551
9857
  this.threeRef.object.getWorldQuaternion(rotation);
9552
9858
  rotation.slerp(targetRotation, alpha);
9553
9859
  this.transform.setRotation(rotation);
@@ -9564,7 +9870,7 @@ var _Behaviour = class _Behaviour {
9564
9870
  return;
9565
9871
  }
9566
9872
  const clone3 = this.threeRef.object.clone();
9567
- const rotation = new THREE51__namespace.Quaternion();
9873
+ const rotation = new THREE56__namespace.Quaternion();
9568
9874
  clone3.lookAt(targetPosition);
9569
9875
  clone3.getWorldQuaternion(rotation);
9570
9876
  this.transform.setRotation(rotation);
@@ -9729,6 +10035,23 @@ var _Behaviour = class _Behaviour {
9729
10035
  /** Called when this entity is released. Optional XR hook. */
9730
10036
  onRelease(input) {
9731
10037
  }
10038
+ /** A UI button on this entity (or a descendant) was clicked. Clicks fire on
10039
+ * RELEASE while still pointing at the widget — sliding off cancels. */
10040
+ onUiPress(_event) {
10041
+ }
10042
+ /** A pointer began hovering a UI widget on this entity (or a descendant). */
10043
+ onUiHoverStart(_event) {
10044
+ }
10045
+ /** The pointer left the widget. */
10046
+ onUiHoverEnd(_event) {
10047
+ }
10048
+ /** A UI toggle flipped; `event.value` is the new boolean. */
10049
+ onUiToggle(_event) {
10050
+ }
10051
+ /** A UI slider moved; `event.value` is the new number. Fires on real value
10052
+ * changes during the drag and once more on release. */
10053
+ onUiChange(_event) {
10054
+ }
9732
10055
  };
9733
10056
  __name(_Behaviour, "Behaviour");
9734
10057
  /**
@@ -9930,8 +10253,8 @@ var _ScriptBehaviourSystem = class _ScriptBehaviourSystem {
9930
10253
  }, "onPointerUp");
9931
10254
  this.moduleLoader = moduleLoader ?? defaultModuleLoader;
9932
10255
  this.selectionCtx = selectionContext ?? null;
9933
- this.raycaster = new THREE51__namespace.Raycaster();
9934
- this.ndcPointer = new THREE51__namespace.Vector2();
10256
+ this.raycaster = new THREE56__namespace.Raycaster();
10257
+ this.ndcPointer = new THREE56__namespace.Vector2();
9935
10258
  if (this.selectionCtx) {
9936
10259
  this.selectionCtx.domElement.addEventListener("pointerdown", this.onPointerDown);
9937
10260
  this.selectionCtx.domElement.addEventListener("pointerup", this.onPointerUp);
@@ -10310,7 +10633,7 @@ function disposeBuiltObject(root) {
10310
10633
  for (const mat of materials) {
10311
10634
  if (mat.userData?.[SHARED_MODEL_RESOURCE_FLAG]) continue;
10312
10635
  for (const value of Object.values(mat)) {
10313
- if (value instanceof THREE51__namespace.Texture) value.dispose();
10636
+ if (value instanceof THREE56__namespace.Texture) value.dispose();
10314
10637
  }
10315
10638
  mat.dispose?.();
10316
10639
  }
@@ -10674,7 +10997,7 @@ var _AudioSystem = class _AudioSystem {
10674
10997
  if (!prev || prev.volume !== opts.volume) {
10675
10998
  sound.setVolume(opts.volume);
10676
10999
  }
10677
- if (opts.positional && sound instanceof THREE51__namespace.PositionalAudio) {
11000
+ if (opts.positional && sound instanceof THREE56__namespace.PositionalAudio) {
10678
11001
  if (!prev || prev.refDistance !== opts.refDistance) {
10679
11002
  sound.setRefDistance(opts.refDistance);
10680
11003
  }
@@ -10800,7 +11123,7 @@ var _VideoSystem = class _VideoSystem {
10800
11123
  component.object.scale.set(opts.width, opts.height, 1);
10801
11124
  }
10802
11125
  const material = component.material;
10803
- if (material instanceof THREE51__namespace.ShaderMaterial) {
11126
+ if (material instanceof THREE56__namespace.ShaderMaterial) {
10804
11127
  if (!prev || prev.backgroundColor !== opts.backgroundColor) {
10805
11128
  material.uniforms.keyColor.value.set(opts.backgroundColor);
10806
11129
  }
@@ -10814,7 +11137,7 @@ var _VideoSystem = class _VideoSystem {
10814
11137
  material.uniforms.spill.value = opts.spill;
10815
11138
  }
10816
11139
  }
10817
- if (opts.positional && component.audioNode instanceof THREE51__namespace.PositionalAudio) {
11140
+ if (opts.positional && component.audioNode instanceof THREE56__namespace.PositionalAudio) {
10818
11141
  const posAudio = component.audioNode;
10819
11142
  if (!prev || prev.refDistance !== opts.refDistance) {
10820
11143
  posAudio.setRefDistance(opts.refDistance);
@@ -10854,8 +11177,8 @@ function blankState(source) {
10854
11177
  handedness: handednessOf(source),
10855
11178
  kind: kindOf(source),
10856
11179
  connected: true,
10857
- rayOrigin: new THREE51__namespace.Vector3(),
10858
- rayDirection: new THREE51__namespace.Vector3(0, 0, -1),
11180
+ rayOrigin: new THREE56__namespace.Vector3(),
11181
+ rayDirection: new THREE56__namespace.Vector3(0, 0, -1),
10859
11182
  gripPosition: null,
10860
11183
  gripQuaternion: null,
10861
11184
  select: false,
@@ -10881,7 +11204,7 @@ function readHandJoints(frame, hand, referenceSpace, rigMatrix, existing) {
10881
11204
  }
10882
11205
  if (spaces.length === 0) return null;
10883
11206
  const target = existing ?? {};
10884
- const matrix = new THREE51__namespace.Matrix4();
11207
+ const matrix = new THREE56__namespace.Matrix4();
10885
11208
  const buffer = spaces.length * 16 <= JOINT_MATRIX_BUFFER.length ? JOINT_MATRIX_BUFFER : new Float32Array(spaces.length * 16);
10886
11209
  const fillPoses = frame.fillPoses;
10887
11210
  if (typeof fillPoses === "function") {
@@ -10894,7 +11217,7 @@ function readHandJoints(frame, hand, referenceSpace, rigMatrix, existing) {
10894
11217
  if (filled) {
10895
11218
  for (let i = 0; i < names.length; i += 1) {
10896
11219
  matrix.fromArray(buffer, i * 16).premultiply(rigMatrix);
10897
- const vector = target[names[i]] ?? new THREE51__namespace.Vector3();
11220
+ const vector = target[names[i]] ?? new THREE56__namespace.Vector3();
10898
11221
  vector.setFromMatrixPosition(matrix);
10899
11222
  target[names[i]] = vector;
10900
11223
  }
@@ -10912,7 +11235,7 @@ function readHandJoints(frame, hand, referenceSpace, rigMatrix, existing) {
10912
11235
  continue;
10913
11236
  }
10914
11237
  matrix.fromArray(pose.transform.matrix).premultiply(rigMatrix);
10915
- const vector = target[names[i]] ?? new THREE51__namespace.Vector3();
11238
+ const vector = target[names[i]] ?? new THREE56__namespace.Vector3();
10916
11239
  vector.setFromMatrixPosition(matrix);
10917
11240
  target[names[i]] = vector;
10918
11241
  anyTracked = true;
@@ -10924,7 +11247,7 @@ var _XRInputSystem = class _XRInputSystem {
10924
11247
  constructor() {
10925
11248
  this.records = /* @__PURE__ */ new Map();
10926
11249
  /** Reference-space → world matrix, rebuilt each frame from the XR rig. */
10927
- this.referenceToWorld = new THREE51__namespace.Matrix4();
11250
+ this.referenceToWorld = new THREE56__namespace.Matrix4();
10928
11251
  this.session = null;
10929
11252
  this.onSelectStart = /* @__PURE__ */ __name((event) => this.mark(event, "pendingSelectStart"), "onSelectStart");
10930
11253
  this.onSelectEnd = /* @__PURE__ */ __name((event) => this.mark(event, "pendingSelectEnd"), "onSelectEnd");
@@ -11022,19 +11345,19 @@ var _XRInputSystem = class _XRInputSystem {
11022
11345
  if (frame && referenceSpace && source.targetRaySpace) {
11023
11346
  const pose = frame.getPose(source.targetRaySpace, referenceSpace);
11024
11347
  if (pose) {
11025
- const m = new THREE51__namespace.Matrix4().fromArray(pose.transform.matrix).premultiply(rigMatrix);
11348
+ const m = new THREE56__namespace.Matrix4().fromArray(pose.transform.matrix).premultiply(rigMatrix);
11026
11349
  state.rayOrigin.setFromMatrixPosition(m);
11027
11350
  state.rayDirection.set(0, 0, -1).applyQuaternion(
11028
- new THREE51__namespace.Quaternion().setFromRotationMatrix(m)
11351
+ new THREE56__namespace.Quaternion().setFromRotationMatrix(m)
11029
11352
  ).normalize();
11030
11353
  }
11031
11354
  }
11032
11355
  if (frame && referenceSpace && source.gripSpace) {
11033
11356
  const gripPose = frame.getPose(source.gripSpace, referenceSpace);
11034
11357
  if (gripPose) {
11035
- const m = new THREE51__namespace.Matrix4().fromArray(gripPose.transform.matrix).premultiply(rigMatrix);
11036
- state.gripPosition ?? (state.gripPosition = new THREE51__namespace.Vector3());
11037
- state.gripQuaternion ?? (state.gripQuaternion = new THREE51__namespace.Quaternion());
11358
+ const m = new THREE56__namespace.Matrix4().fromArray(gripPose.transform.matrix).premultiply(rigMatrix);
11359
+ state.gripPosition ?? (state.gripPosition = new THREE56__namespace.Vector3());
11360
+ state.gripQuaternion ?? (state.gripQuaternion = new THREE56__namespace.Quaternion());
11038
11361
  state.gripPosition.setFromMatrixPosition(m);
11039
11362
  state.gripQuaternion.setFromRotationMatrix(m);
11040
11363
  }
@@ -11162,15 +11485,15 @@ var _ThrowVelocityTracker = class _ThrowVelocityTracker {
11162
11485
  const fresh = this.samples.filter(
11163
11486
  (sample) => now - sample.time <= MAX_SAMPLE_AGE_SECONDS
11164
11487
  );
11165
- if (fresh.length < 2) return new THREE51__namespace.Vector3();
11166
- let best = new THREE51__namespace.Vector3();
11488
+ if (fresh.length < 2) return new THREE56__namespace.Vector3();
11489
+ let best = new THREE56__namespace.Vector3();
11167
11490
  let bestSpeed = 0;
11168
11491
  for (let i = 1; i < fresh.length; i += 1) {
11169
11492
  const previous = fresh[i - 1];
11170
11493
  const current = fresh[i];
11171
11494
  const dt = current.time - previous.time;
11172
11495
  if (dt <= 1e-5) continue;
11173
- const velocity = new THREE51__namespace.Vector3().subVectors(current.position, previous.position).divideScalar(dt);
11496
+ const velocity = new THREE56__namespace.Vector3().subVectors(current.position, previous.position).divideScalar(dt);
11174
11497
  const speed = velocity.length();
11175
11498
  if (speed > MAX_PLAUSIBLE_SPEED) continue;
11176
11499
  if (speed > bestSpeed) {
@@ -11187,15 +11510,15 @@ var _ThrowVelocityTracker = class _ThrowVelocityTracker {
11187
11510
  __name(_ThrowVelocityTracker, "ThrowVelocityTracker");
11188
11511
  var ThrowVelocityTracker = _ThrowVelocityTracker;
11189
11512
  function angularVelocityFrom(previous, current, deltaTime) {
11190
- if (deltaTime <= 1e-5) return new THREE51__namespace.Vector3();
11513
+ if (deltaTime <= 1e-5) return new THREE56__namespace.Vector3();
11191
11514
  const delta = current.clone().multiply(previous.clone().invert());
11192
11515
  if (delta.w < 0) {
11193
11516
  delta.set(-delta.x, -delta.y, -delta.z, -delta.w);
11194
11517
  }
11195
- const angle = 2 * Math.acos(THREE51__namespace.MathUtils.clamp(delta.w, -1, 1));
11518
+ const angle = 2 * Math.acos(THREE56__namespace.MathUtils.clamp(delta.w, -1, 1));
11196
11519
  const sinHalf = Math.sqrt(Math.max(0, 1 - delta.w * delta.w));
11197
- if (sinHalf < 1e-6 || angle < 1e-6) return new THREE51__namespace.Vector3();
11198
- return new THREE51__namespace.Vector3(delta.x, delta.y, delta.z).divideScalar(sinHalf).multiplyScalar(angle / deltaTime);
11520
+ if (sinHalf < 1e-6 || angle < 1e-6) return new THREE56__namespace.Vector3();
11521
+ return new THREE56__namespace.Vector3(delta.x, delta.y, delta.z).divideScalar(sinHalf).multiplyScalar(angle / deltaTime);
11199
11522
  }
11200
11523
  __name(angularVelocityFrom, "angularVelocityFrom");
11201
11524
  var MIN_HAND_SEPARATION = 0.06;
@@ -11203,7 +11526,7 @@ var MIN_ANCHOR_SEPARATION = 1e-3;
11203
11526
  var SCALE_DEADZONE = 0.05;
11204
11527
  function solveTwoHandTransform(primary, secondary, basis, options) {
11205
11528
  const separation = primary.position.distanceTo(secondary.position);
11206
- const anchorDelta = new THREE51__namespace.Vector3().subVectors(
11529
+ const anchorDelta = new THREE56__namespace.Vector3().subVectors(
11207
11530
  basis.secondaryLocal,
11208
11531
  basis.primaryLocal
11209
11532
  );
@@ -11227,8 +11550,8 @@ function solveTwoHandTransform(primary, secondary, basis, options) {
11227
11550
  } else {
11228
11551
  const axisLocal = anchorDelta.clone().normalize();
11229
11552
  const currentAxis = axisLocal.clone().applyQuaternion(base).normalize();
11230
- const desiredAxis = new THREE51__namespace.Vector3().subVectors(secondary.position, primary.position).normalize();
11231
- const correction = new THREE51__namespace.Quaternion().setFromUnitVectors(
11553
+ const desiredAxis = new THREE56__namespace.Vector3().subVectors(secondary.position, primary.position).normalize();
11554
+ const correction = new THREE56__namespace.Quaternion().setFromUnitVectors(
11232
11555
  currentAxis,
11233
11556
  desiredAxis
11234
11557
  );
@@ -11243,11 +11566,11 @@ __name(solveTwoHandTransform, "solveTwoHandTransform");
11243
11566
  // core/systems/XRInteractionSystem.ts
11244
11567
  var RAYLESS_HOLD_DISTANCE = 0.5;
11245
11568
  function quatFromEulerVec(r) {
11246
- return new THREE51__namespace.Quaternion().setFromEuler(new THREE51__namespace.Euler(r.x, r.y, r.z));
11569
+ return new THREE56__namespace.Quaternion().setFromEuler(new THREE56__namespace.Euler(r.x, r.y, r.z));
11247
11570
  }
11248
11571
  __name(quatFromEulerVec, "quatFromEulerVec");
11249
11572
  function writeEuler(target, q) {
11250
- const euler = new THREE51__namespace.Euler().setFromQuaternion(q);
11573
+ const euler = new THREE56__namespace.Euler().setFromQuaternion(q);
11251
11574
  target.x = euler.x;
11252
11575
  target.y = euler.y;
11253
11576
  target.z = euler.z;
@@ -11255,10 +11578,11 @@ function writeEuler(target, q) {
11255
11578
  __name(writeEuler, "writeEuler");
11256
11579
  var _XRInteractionSystem = class _XRInteractionSystem {
11257
11580
  constructor(inputSystem) {
11258
- this.raycaster = new THREE51__namespace.Raycaster();
11581
+ this.raycaster = new THREE56__namespace.Raycaster();
11259
11582
  this.grabs = /* @__PURE__ */ new Map();
11260
11583
  this.hoveredEntityId = null;
11261
11584
  /** Per-hand hover, with the hit distance so the ray can stop at the surface. */
11585
+ this.busyContributors = [];
11262
11586
  this.hovers = /* @__PURE__ */ new Map();
11263
11587
  /** Monotonic seconds, accumulated from deltaTime for velocity sampling. */
11264
11588
  this.elapsed = 0;
@@ -11267,6 +11591,8 @@ var _XRInteractionSystem = class _XRInteractionSystem {
11267
11591
  update(world, deltaTime) {
11268
11592
  if (!world.isXrPresenting()) {
11269
11593
  this.releaseAll(world);
11594
+ this.hovers.clear();
11595
+ this.hoveredEntityId = null;
11270
11596
  return;
11271
11597
  }
11272
11598
  this.elapsed += Math.max(0, deltaTime);
@@ -11363,7 +11689,7 @@ var _XRInteractionSystem = class _XRInteractionSystem {
11363
11689
  const hand = this.handPosition(input);
11364
11690
  const handQuaternion = this.handQuaternion(input);
11365
11691
  const objectQuaternion = quatFromEulerVec(transform.rotation);
11366
- record.offset = new THREE51__namespace.Vector3(
11692
+ record.offset = new THREE56__namespace.Vector3(
11367
11693
  transform.position.x - hand.x,
11368
11694
  transform.position.y - hand.y,
11369
11695
  transform.position.z - hand.z
@@ -11395,7 +11721,7 @@ var _XRInteractionSystem = class _XRInteractionSystem {
11395
11721
  primary.record.twoHand = {
11396
11722
  primaryLocal,
11397
11723
  secondaryLocal,
11398
- initialScale: new THREE51__namespace.Vector3(
11724
+ initialScale: new THREE56__namespace.Vector3(
11399
11725
  transform.scale.x,
11400
11726
  transform.scale.y,
11401
11727
  transform.scale.z
@@ -11411,7 +11737,7 @@ var _XRInteractionSystem = class _XRInteractionSystem {
11411
11737
  /** World point → the object's UNSCALED local space. */
11412
11738
  objectLocalPoint(transform, worldPoint) {
11413
11739
  const local = worldPoint.clone().sub(
11414
- new THREE51__namespace.Vector3(
11740
+ new THREE56__namespace.Vector3(
11415
11741
  transform.position.x,
11416
11742
  transform.position.y,
11417
11743
  transform.position.z
@@ -11469,7 +11795,7 @@ var _XRInteractionSystem = class _XRInteractionSystem {
11469
11795
  );
11470
11796
  if (!interactable2) continue;
11471
11797
  if (interactable2.grabReach === "distance") continue;
11472
- const position = new THREE51__namespace.Vector3();
11798
+ const position = new THREE56__namespace.Vector3();
11473
11799
  entry.object.getWorldPosition(position);
11474
11800
  const distance = position.distanceTo(hand);
11475
11801
  if (distance <= interactable2.grabRadius && distance < nearestDistance) {
@@ -11541,13 +11867,13 @@ var _XRInteractionSystem = class _XRInteractionSystem {
11541
11867
  this.holdersOf(entityId).map((holder) => holder.record.attachPointId).filter((id) => id !== null)
11542
11868
  );
11543
11869
  const hand = this.handPosition(input);
11544
- const objectPosition = new THREE51__namespace.Vector3(
11870
+ const objectPosition = new THREE56__namespace.Vector3(
11545
11871
  transform.position.x,
11546
11872
  transform.position.y,
11547
11873
  transform.position.z
11548
11874
  );
11549
11875
  const objectQuaternion = quatFromEulerVec(transform.rotation);
11550
- const scale = new THREE51__namespace.Vector3(
11876
+ const scale = new THREE56__namespace.Vector3(
11551
11877
  transform.scale.x,
11552
11878
  transform.scale.y,
11553
11879
  transform.scale.z
@@ -11558,7 +11884,7 @@ var _XRInteractionSystem = class _XRInteractionSystem {
11558
11884
  if (taken.has(point.id)) continue;
11559
11885
  if (point.hand !== "any" && point.hand !== input.handedness) continue;
11560
11886
  if (point.role !== "any" && point.role !== role) continue;
11561
- const world3 = new THREE51__namespace.Vector3(
11887
+ const world3 = new THREE56__namespace.Vector3(
11562
11888
  point.position.x,
11563
11889
  point.position.y,
11564
11890
  point.position.z
@@ -11581,21 +11907,21 @@ var _XRInteractionSystem = class _XRInteractionSystem {
11581
11907
  let offset;
11582
11908
  let remoteDistance = 0;
11583
11909
  if (remote) {
11584
- const position = new THREE51__namespace.Vector3(
11910
+ const position = new THREE56__namespace.Vector3(
11585
11911
  transform.position.x,
11586
11912
  transform.position.y,
11587
11913
  transform.position.z
11588
11914
  );
11589
11915
  remoteDistance = position.distanceTo(input.rayOrigin);
11590
- offset = new THREE51__namespace.Vector3();
11916
+ offset = new THREE56__namespace.Vector3();
11591
11917
  } else if (viaDistance) {
11592
- offset = new THREE51__namespace.Vector3(
11918
+ offset = new THREE56__namespace.Vector3(
11593
11919
  interactable.grabOffsetPosition.x,
11594
11920
  interactable.grabOffsetPosition.y,
11595
11921
  interactable.grabOffsetPosition.z
11596
11922
  );
11597
11923
  } else {
11598
- offset = new THREE51__namespace.Vector3(
11924
+ offset = new THREE56__namespace.Vector3(
11599
11925
  transform.position.x - hand.x,
11600
11926
  transform.position.y - hand.y,
11601
11927
  transform.position.z - hand.z
@@ -11622,7 +11948,7 @@ var _XRInteractionSystem = class _XRInteractionSystem {
11622
11948
  entityId,
11623
11949
  role,
11624
11950
  attachPointId: attachPoint?.id ?? null,
11625
- attachLocal: attachPoint ? new THREE51__namespace.Vector3(
11951
+ attachLocal: attachPoint ? new THREE56__namespace.Vector3(
11626
11952
  attachPoint.position.x,
11627
11953
  attachPoint.position.y,
11628
11954
  attachPoint.position.z
@@ -11631,8 +11957,8 @@ var _XRInteractionSystem = class _XRInteractionSystem {
11631
11957
  handRotationOffset,
11632
11958
  twoHand: null,
11633
11959
  offset,
11634
- rotationOffset: new THREE51__namespace.Quaternion().setFromEuler(
11635
- new THREE51__namespace.Euler(
11960
+ rotationOffset: new THREE56__namespace.Quaternion().setFromEuler(
11961
+ new THREE56__namespace.Euler(
11636
11962
  interactable.grabOffsetRotation.x,
11637
11963
  interactable.grabOffsetRotation.y,
11638
11964
  interactable.grabOffsetRotation.z
@@ -11643,7 +11969,7 @@ var _XRInteractionSystem = class _XRInteractionSystem {
11643
11969
  restoreBodyType,
11644
11970
  tracker,
11645
11971
  lastHandQuaternion: handQuaternion.clone(),
11646
- angularVelocity: new THREE51__namespace.Vector3()
11972
+ angularVelocity: new THREE56__namespace.Vector3()
11647
11973
  });
11648
11974
  if (role === "primary") {
11649
11975
  this.dispatch(world, entityId, (b) => b.onGrab(input));
@@ -11716,14 +12042,14 @@ var _XRInteractionSystem = class _XRInteractionSystem {
11716
12042
  const handQuaternion = this.handQuaternion(input);
11717
12043
  const objectQuaternion = held.attachQuaternion ? handQuaternion.clone().multiply(held.rotationOffset).multiply(held.attachQuaternion.clone().invert()) : handQuaternion.clone().multiply(held.handRotationOffset);
11718
12044
  if (held.remote) {
11719
- const target = new THREE51__namespace.Vector3().copy(input.rayDirection).multiplyScalar(held.remoteDistance).add(input.rayOrigin);
12045
+ const target = new THREE56__namespace.Vector3().copy(input.rayDirection).multiplyScalar(held.remoteDistance).add(input.rayOrigin);
11720
12046
  transform.position.x = target.x;
11721
12047
  transform.position.y = target.y;
11722
12048
  transform.position.z = target.z;
11723
12049
  writeEuler(transform.rotation, objectQuaternion);
11724
12050
  } else if (held.attachLocal) {
11725
12051
  const anchor = held.attachLocal.clone().multiply(
11726
- new THREE51__namespace.Vector3(
12052
+ new THREE56__namespace.Vector3(
11727
12053
  transform.scale.x,
11728
12054
  transform.scale.y,
11729
12055
  transform.scale.z
@@ -11741,7 +12067,7 @@ var _XRInteractionSystem = class _XRInteractionSystem {
11741
12067
  writeEuler(transform.rotation, objectQuaternion);
11742
12068
  }
11743
12069
  held.tracker.record(
11744
- held.remote ? new THREE51__namespace.Vector3(
12070
+ held.remote ? new THREE56__namespace.Vector3(
11745
12071
  transform.position.x,
11746
12072
  transform.position.y,
11747
12073
  transform.position.z
@@ -11815,7 +12141,7 @@ var _XRInteractionSystem = class _XRInteractionSystem {
11815
12141
  */
11816
12142
  handPosition(input) {
11817
12143
  if (input.gripPosition) return input.gripPosition;
11818
- return new THREE51__namespace.Vector3().copy(input.rayDirection).multiplyScalar(RAYLESS_HOLD_DISTANCE).add(input.rayOrigin);
12144
+ return new THREE56__namespace.Vector3().copy(input.rayDirection).multiplyScalar(RAYLESS_HOLD_DISTANCE).add(input.rayOrigin);
11819
12145
  }
11820
12146
  /**
11821
12147
  * Hand orientation. Grip-less sources (gaze / transient-pointer) have none,
@@ -11823,8 +12149,8 @@ var _XRInteractionSystem = class _XRInteractionSystem {
11823
12149
  */
11824
12150
  handQuaternion(input) {
11825
12151
  if (input.gripQuaternion) return input.gripQuaternion.clone();
11826
- return new THREE51__namespace.Quaternion().setFromUnitVectors(
11827
- new THREE51__namespace.Vector3(0, 0, -1),
12152
+ return new THREE56__namespace.Quaternion().setFromUnitVectors(
12153
+ new THREE56__namespace.Vector3(0, 0, -1),
11828
12154
  input.rayDirection.clone().normalize()
11829
12155
  );
11830
12156
  }
@@ -11889,13 +12215,30 @@ var _XRInteractionSystem = class _XRInteractionSystem {
11889
12215
  */
11890
12216
  isSourceBusy(world, input) {
11891
12217
  if (this.grabs.has(input)) return true;
12218
+ for (const contributor of this.busyContributors) {
12219
+ try {
12220
+ if (contributor(world, input)) return true;
12221
+ } catch {
12222
+ }
12223
+ }
11892
12224
  const hover = this.hovers.get(input);
11893
12225
  if (!hover) return false;
11894
12226
  const interactable = world.getComponent(
11895
12227
  hover.entityId,
11896
12228
  XRInteractableComponent
11897
12229
  );
11898
- return Boolean(interactable?.enabled && interactable.grabbable);
12230
+ return Boolean(
12231
+ interactable?.enabled && (interactable.grabbable || interactable.pointable)
12232
+ );
12233
+ }
12234
+ /** OR-ed into isSourceBusy; see the comment there. */
12235
+ registerBusyContributor(contributor) {
12236
+ this.busyContributors.push(contributor);
12237
+ }
12238
+ /** Hover for a specific input source (handedness-free — Vision Pro's
12239
+ * transient pointers all report handedness "none"). */
12240
+ getHoverForInput(input) {
12241
+ return this.hovers.get(input) ?? null;
11899
12242
  }
11900
12243
  /** True when THIS hand is holding something. */
11901
12244
  isGrabbingWith(handedness) {
@@ -11944,7 +12287,7 @@ function sampleTeleportArc(origin, direction, out = [], options) {
11944
12287
  for (let i = 0; i < steps; i += 1) {
11945
12288
  const t = i / (steps - 1) * maxTime;
11946
12289
  out.push(
11947
- new THREE51__namespace.Vector3(
12290
+ new THREE56__namespace.Vector3(
11948
12291
  origin.x + velocity.x * t,
11949
12292
  origin.y + velocity.y * t - 0.5 * gravity * t * t,
11950
12293
  origin.z + velocity.z * t
@@ -11961,7 +12304,7 @@ function arcGroundCrossing(points, groundY) {
11961
12304
  if (previous.y >= groundY && current.y <= groundY) {
11962
12305
  const span = previous.y - current.y;
11963
12306
  const alpha = span > 1e-6 ? (previous.y - groundY) / span : 0;
11964
- return new THREE51__namespace.Vector3().lerpVectors(previous, current, alpha);
12307
+ return new THREE56__namespace.Vector3().lerpVectors(previous, current, alpha);
11965
12308
  }
11966
12309
  }
11967
12310
  return null;
@@ -12005,11 +12348,11 @@ __name(_TeleportAimGate, "TeleportAimGate");
12005
12348
  var TeleportAimGate = _TeleportAimGate;
12006
12349
 
12007
12350
  // core/systems/XRLocomotionSystem.ts
12008
- var UP = new THREE51__namespace.Vector3(0, 1, 0);
12351
+ var UP = new THREE56__namespace.Vector3(0, 1, 0);
12009
12352
  var AXIS_DEADZONE = 0.5;
12010
12353
  var _XRLocomotionSystem = class _XRLocomotionSystem {
12011
12354
  constructor(inputSystem) {
12012
- this.raycaster = new THREE51__namespace.Raycaster();
12355
+ this.raycaster = new THREE56__namespace.Raycaster();
12013
12356
  /** Per-source latch so one stick push yields exactly one snap turn. */
12014
12357
  this.turnLatched = /* @__PURE__ */ new WeakSet();
12015
12358
  /** Reused arc buffer — aiming runs every frame. */
@@ -12135,7 +12478,7 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
12135
12478
  }
12136
12479
  if (this.turnLatched.has(source)) continue;
12137
12480
  this.turnLatched.add(source);
12138
- transform.rotation.y -= Math.sign(x) * THREE51__namespace.MathUtils.degToRad(rig.snapTurnDegrees);
12481
+ transform.rotation.y -= Math.sign(x) * THREE56__namespace.MathUtils.degToRad(rig.snapTurnDegrees);
12139
12482
  }
12140
12483
  }
12141
12484
  applySmoothMove(world, rig, transform, inputs, deltaTime) {
@@ -12145,12 +12488,12 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
12145
12488
  const y = input.axes[1] ?? 0;
12146
12489
  if (Math.abs(x) < 0.15 && Math.abs(y) < 0.15) continue;
12147
12490
  const camera = world.getCamera();
12148
- const forward = new THREE51__namespace.Vector3();
12491
+ const forward = new THREE56__namespace.Vector3();
12149
12492
  camera.getWorldDirection(forward);
12150
12493
  forward.y = 0;
12151
12494
  if (forward.lengthSq() < 1e-6) continue;
12152
12495
  forward.normalize();
12153
- const right = new THREE51__namespace.Vector3().crossVectors(forward, UP).normalize();
12496
+ const right = new THREE56__namespace.Vector3().crossVectors(forward, UP).normalize();
12154
12497
  const step = rig.moveSpeed * Math.max(0, deltaTime);
12155
12498
  transform.position.x += (forward.x * -y + right.x * x) * step;
12156
12499
  transform.position.z += (forward.z * -y + right.z * x) * step;
@@ -12231,7 +12574,7 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
12231
12574
  for (let i = 1; i < points.length; i += 1) {
12232
12575
  const from = points[i - 1];
12233
12576
  const to = points[i];
12234
- const delta = new THREE51__namespace.Vector3().subVectors(to, from);
12577
+ const delta = new THREE56__namespace.Vector3().subVectors(to, from);
12235
12578
  const distance = delta.length();
12236
12579
  if (distance < 1e-6) continue;
12237
12580
  this.raycaster.set(from, delta.divideScalar(distance));
@@ -12500,12 +12843,12 @@ function planeColliderFromPolygon(polygon) {
12500
12843
  }
12501
12844
  __name(planeColliderFromPolygon, "planeColliderFromPolygon");
12502
12845
  function writeXrMeshGeometry(vertices, indices, existing) {
12503
- const geometry = existing ?? new THREE51__namespace.BufferGeometry();
12846
+ const geometry = existing ?? new THREE56__namespace.BufferGeometry();
12504
12847
  geometry.setAttribute(
12505
12848
  "position",
12506
- new THREE51__namespace.BufferAttribute(vertices.slice(), 3)
12849
+ new THREE56__namespace.BufferAttribute(vertices.slice(), 3)
12507
12850
  );
12508
- geometry.setIndex(new THREE51__namespace.BufferAttribute(indices.slice(), 1));
12851
+ geometry.setIndex(new THREE56__namespace.BufferAttribute(indices.slice(), 1));
12509
12852
  geometry.deleteAttribute("normal");
12510
12853
  geometry.computeBoundingSphere();
12511
12854
  geometry.computeVertexNormals();
@@ -12513,14 +12856,14 @@ function writeXrMeshGeometry(vertices, indices, existing) {
12513
12856
  }
12514
12857
  __name(writeXrMeshGeometry, "writeXrMeshGeometry");
12515
12858
  function decomposeXrPose(matrixElements, target) {
12516
- const matrix = new THREE51__namespace.Matrix4().fromArray(
12859
+ const matrix = new THREE56__namespace.Matrix4().fromArray(
12517
12860
  matrixElements
12518
12861
  );
12519
- const position = new THREE51__namespace.Vector3();
12520
- const quaternion = new THREE51__namespace.Quaternion();
12521
- const scale = new THREE51__namespace.Vector3();
12862
+ const position = new THREE56__namespace.Vector3();
12863
+ const quaternion = new THREE56__namespace.Quaternion();
12864
+ const scale = new THREE56__namespace.Vector3();
12522
12865
  matrix.decompose(position, quaternion, scale);
12523
- const euler = new THREE51__namespace.Euler().setFromQuaternion(quaternion, "XYZ");
12866
+ const euler = new THREE56__namespace.Euler().setFromQuaternion(quaternion, "XYZ");
12524
12867
  target.position.x = position.x;
12525
12868
  target.position.y = position.y;
12526
12869
  target.position.z = position.z;
@@ -12530,6 +12873,88 @@ function decomposeXrPose(matrixElements, target) {
12530
12873
  }
12531
12874
  __name(decomposeXrPose, "decomposeXrPose");
12532
12875
 
12876
+ // core/xr/poseStability.ts
12877
+ var GLUED_REF_SPEED = 0.12;
12878
+ var STILL_SPEED = 0.05;
12879
+ var GLUED_FRAMES_TO_FREEZE = 3;
12880
+ var STATIC_FRAMES_TO_RECOVER = 10;
12881
+ var SNAP_SPEED = 3;
12882
+ var dist = /* @__PURE__ */ __name((a, b) => Math.hypot(a.x - b.x, a.y - b.y, a.z - b.z), "dist");
12883
+ var _SurfacePoseGate = class _SurfacePoseGate {
12884
+ constructor() {
12885
+ this.prevRef = null;
12886
+ this.prevView = null;
12887
+ this.gluedStreak = 0;
12888
+ this.staticStreak = 0;
12889
+ this.suspect = false;
12890
+ this.deltas = 0;
12891
+ }
12892
+ /** True while poses are being rejected as head-glued. */
12893
+ get frozen() {
12894
+ return this.suspect;
12895
+ }
12896
+ /**
12897
+ * True once enough motion has been observed to classify the pose at all.
12898
+ * Surface CREATION waits for this: an entity spawned from a glued pose
12899
+ * materializes wherever the head happens to be — a rotated ghost copy of
12900
+ * the room — and freezing it there is barely better than letting it follow.
12901
+ */
12902
+ get warmedUp() {
12903
+ return this.deltas >= GLUED_FRAMES_TO_FREEZE;
12904
+ }
12905
+ /**
12906
+ * Feed this frame's surface position in reference space and in view
12907
+ * (viewer-relative) space. Returns true when the pose should be APPLIED,
12908
+ * false when it should be frozen out.
12909
+ *
12910
+ * `viewPos` may be null when the viewer pose is unavailable (older
12911
+ * runtimes) — the gate then passes everything through, degrading to the
12912
+ * flag-only behavior.
12913
+ */
12914
+ update(refPos, viewPos, deltaTime) {
12915
+ if (!viewPos || deltaTime <= 0) {
12916
+ this.prevRef = { ...refPos };
12917
+ this.prevView = viewPos ? { ...viewPos } : null;
12918
+ return !this.suspect;
12919
+ }
12920
+ const prevRef = this.prevRef;
12921
+ const prevView = this.prevView;
12922
+ this.prevRef = { ...refPos };
12923
+ this.prevView = { ...viewPos };
12924
+ if (!prevRef || !prevView) return !this.suspect;
12925
+ this.deltas += 1;
12926
+ const refSpeed = dist(refPos, prevRef) / deltaTime;
12927
+ const viewSpeed = dist(viewPos, prevView) / deltaTime;
12928
+ const glued = refSpeed > GLUED_REF_SPEED && viewSpeed < STILL_SPEED;
12929
+ const worldStatic = refSpeed < STILL_SPEED && viewSpeed > GLUED_REF_SPEED;
12930
+ if (this.suspect) {
12931
+ if (refSpeed > SNAP_SPEED && viewSpeed > SNAP_SPEED) {
12932
+ this.suspect = false;
12933
+ this.gluedStreak = 0;
12934
+ this.staticStreak = 0;
12935
+ return true;
12936
+ }
12937
+ this.staticStreak = worldStatic ? this.staticStreak + 1 : 0;
12938
+ if (this.staticStreak >= STATIC_FRAMES_TO_RECOVER) {
12939
+ this.suspect = false;
12940
+ this.gluedStreak = 0;
12941
+ this.staticStreak = 0;
12942
+ return true;
12943
+ }
12944
+ return false;
12945
+ }
12946
+ this.gluedStreak = glued ? this.gluedStreak + 1 : 0;
12947
+ if (this.gluedStreak >= GLUED_FRAMES_TO_FREEZE) {
12948
+ this.suspect = true;
12949
+ this.staticStreak = 0;
12950
+ return false;
12951
+ }
12952
+ return true;
12953
+ }
12954
+ };
12955
+ __name(_SurfacePoseGate, "SurfacePoseGate");
12956
+ var SurfacePoseGate = _SurfacePoseGate;
12957
+
12533
12958
  // core/systems/XREnvironmentSystem.ts
12534
12959
  var DEBUG_COLOR = 5088255;
12535
12960
  function debugColorFor(kind, semanticLabel) {
@@ -12553,6 +12978,11 @@ function debugColorFor(kind, semanticLabel) {
12553
12978
  }
12554
12979
  __name(debugColorFor, "debugColorFor");
12555
12980
  var GLOBAL_MESH_DEBUG_OPACITY = 0.35;
12981
+ var GLOBAL_MESH_SWITCH_MARGIN = 1.5;
12982
+ function isGlobalMeshSurface(mesh) {
12983
+ return (mesh.semanticLabel ?? null) === "global mesh";
12984
+ }
12985
+ __name(isGlobalMeshSurface, "isGlobalMeshSurface");
12556
12986
  var DEBUG_RENDER_ORDER = 900;
12557
12987
  var ROOM_CAPTURE_DELAY_SECONDS = 3;
12558
12988
  var SYNTHETIC_FLOOR_EXTENT = 50;
@@ -12573,12 +13003,30 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
12573
13003
  /** Keyed by the XRPlane/XRMesh object itself — the runtime's own identity. */
12574
13004
  this.planes = /* @__PURE__ */ new Map();
12575
13005
  this.meshes = /* @__PURE__ */ new Map();
13006
+ /**
13007
+ * Surfaces observed but not yet SPAWNED — their gate is still proving the
13008
+ * pose is world-anchored. Creating from an unflagged head-glued pose (seen
13009
+ * on-device after a suspend/resume regenerated the scan identities) plants
13010
+ * a rotated ghost copy of the room wherever the head happens to be, which
13011
+ * the apply-gate then freezes there — wrong forever. So admission itself
13012
+ * is gated: a few frames of world-anchored behavior first.
13013
+ */
13014
+ this.pendingPlanes = /* @__PURE__ */ new Map();
13015
+ this.pendingMeshes = /* @__PURE__ */ new Map();
12576
13016
  this.presenting = false;
12577
13017
  this.debugVisible = false;
12578
13018
  /** Seconds presenting, used to decide the room has genuinely nothing in it. */
12579
13019
  this.elapsed = 0;
12580
13020
  /** `initiateRoomCapture` may be called only ONCE per session. */
12581
13021
  this.roomCaptureRequested = false;
13022
+ /** This frame's inverse viewer matrix, or null when unavailable. */
13023
+ this.viewerInverse = null;
13024
+ /** This frame's viewer position in reference space, for room election. */
13025
+ this.viewerPos = null;
13026
+ /** The ONE global room mesh currently allowed to spawn. */
13027
+ this.electedGlobalMesh = null;
13028
+ this.tmpViewerMatrix = new THREE56__namespace.Matrix4();
13029
+ this.tmpViewPos = new THREE56__namespace.Vector3();
12582
13030
  }
12583
13031
  update(world, deltaTime = 0) {
12584
13032
  const presenting = world.isXrPresenting();
@@ -12616,13 +13064,22 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
12616
13064
  const meshesAvailable = Boolean(frame.detectedMeshes);
12617
13065
  const useMesh = (mode === "mesh" || mode === "auto") && meshesAvailable;
12618
13066
  const usePlanes = mode === "planes" || mode === "auto" && !useMesh;
13067
+ const viewer = frame.getViewerPose?.(referenceSpace);
13068
+ if (viewer) {
13069
+ const vm = viewer.transform.matrix;
13070
+ this.viewerPos = { x: vm[12], y: vm[13], z: vm[14] };
13071
+ this.viewerInverse = this.tmpViewerMatrix.fromArray(vm).invert();
13072
+ } else {
13073
+ this.viewerPos = null;
13074
+ this.viewerInverse = null;
13075
+ }
12619
13076
  if (usePlanes) {
12620
- this.syncPlanes(world, frame, referenceSpace);
13077
+ this.syncPlanes(world, frame, referenceSpace, deltaTime);
12621
13078
  } else if (this.planes.size > 0) {
12622
13079
  this.clearMap(world, this.planes);
12623
13080
  }
12624
13081
  if (useMesh) {
12625
- this.syncMeshes(world, frame, referenceSpace);
13082
+ this.syncMeshes(world, frame, referenceSpace, deltaTime);
12626
13083
  } else if (this.meshes.size > 0) {
12627
13084
  this.clearMap(world, this.meshes);
12628
13085
  }
@@ -12709,7 +13166,7 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
12709
13166
  if (ids.length === 0) return null;
12710
13167
  return world.getComponent(ids[0], XRRigComponent) ?? null;
12711
13168
  }
12712
- syncPlanes(world, frame, referenceSpace) {
13169
+ syncPlanes(world, frame, referenceSpace, deltaTime) {
12713
13170
  const detected = frame.detectedPlanes;
12714
13171
  if (!detected) return;
12715
13172
  for (const [plane, entry] of this.planes) {
@@ -12718,6 +13175,9 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
12718
13175
  this.planes.delete(plane);
12719
13176
  }
12720
13177
  }
13178
+ for (const plane of this.pendingPlanes.keys()) {
13179
+ if (!detected.has(plane)) this.pendingPlanes.delete(plane);
13180
+ }
12721
13181
  for (const plane of detected) {
12722
13182
  const pose = frame.getPose(plane.planeSpace, referenceSpace);
12723
13183
  if (!pose) continue;
@@ -12726,8 +13186,11 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
12726
13186
  const changed = plane.lastChangedTime ?? 0;
12727
13187
  if (!entry) {
12728
13188
  if (emulated) continue;
13189
+ const gate = this.admit(this.pendingPlanes, plane, pose, deltaTime);
13190
+ if (!gate) continue;
12729
13191
  const created = this.createPlaneEntity(world, plane);
12730
13192
  if (!created) continue;
13193
+ created.gate = gate;
12731
13194
  entry = created;
12732
13195
  this.planes.set(plane, entry);
12733
13196
  } else if (changed !== entry.lastChangedTime) {
@@ -12747,11 +13210,12 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
12747
13210
  }
12748
13211
  }
12749
13212
  }
12750
- entry.emulated = emulated;
12751
- if (!emulated) this.applyPose(world, entry.entityId, pose);
13213
+ const allowed = !emulated && this.gateAllows(entry.gate, pose, deltaTime);
13214
+ entry.emulated = emulated || entry.gate.frozen;
13215
+ if (allowed) this.applyPose(world, entry.entityId, pose);
12752
13216
  }
12753
13217
  }
12754
- syncMeshes(world, frame, referenceSpace) {
13218
+ syncMeshes(world, frame, referenceSpace, deltaTime) {
12755
13219
  const detected = frame.detectedMeshes;
12756
13220
  if (!detected) return;
12757
13221
  for (const [mesh, entry] of this.meshes) {
@@ -12760,7 +13224,20 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
12760
13224
  this.meshes.delete(mesh);
12761
13225
  }
12762
13226
  }
13227
+ for (const mesh of this.pendingMeshes.keys()) {
13228
+ if (!detected.has(mesh)) this.pendingMeshes.delete(mesh);
13229
+ }
13230
+ const electedGlobal = this.electGlobalMesh(frame, detected, referenceSpace);
12763
13231
  for (const mesh of detected) {
13232
+ if (isGlobalMeshSurface(mesh) && mesh !== electedGlobal) {
13233
+ const stale = this.meshes.get(mesh);
13234
+ if (stale) {
13235
+ this.destroyEntry(world, stale);
13236
+ this.meshes.delete(mesh);
13237
+ }
13238
+ this.pendingMeshes.delete(mesh);
13239
+ continue;
13240
+ }
12764
13241
  const pose = frame.getPose(mesh.meshSpace, referenceSpace);
12765
13242
  if (!pose) continue;
12766
13243
  const emulated = pose.emulatedPosition === true;
@@ -12768,17 +13245,95 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
12768
13245
  const changed = mesh.lastChangedTime ?? 0;
12769
13246
  if (!entry) {
12770
13247
  if (emulated) continue;
13248
+ const gate = this.admit(this.pendingMeshes, mesh, pose, deltaTime);
13249
+ if (!gate) continue;
12771
13250
  const created = this.createMeshEntity(world, mesh);
12772
13251
  if (!created) continue;
13252
+ created.gate = gate;
12773
13253
  entry = created;
12774
13254
  this.meshes.set(mesh, entry);
12775
13255
  } else if (changed !== entry.lastChangedTime) {
12776
13256
  entry.lastChangedTime = changed;
12777
13257
  writeXrMeshGeometry(mesh.vertices, mesh.indices, entry.geometry);
12778
13258
  }
12779
- entry.emulated = emulated;
12780
- if (!emulated) this.applyPose(world, entry.entityId, pose);
13259
+ const allowed = !emulated && this.gateAllows(entry.gate, pose, deltaTime);
13260
+ entry.emulated = emulated || entry.gate.frozen;
13261
+ if (allowed) this.applyPose(world, entry.entityId, pose);
13262
+ }
13263
+ }
13264
+ /**
13265
+ * Pick THE room's global mesh: the one whose scan origin is nearest the
13266
+ * viewer, sticky to the current choice within a margin so origin jitter
13267
+ * can't flap the room. Without a viewer pose (or with a single candidate)
13268
+ * the first candidate stands; ties are impossible to break anyway.
13269
+ */
13270
+ electGlobalMesh(frame, detected, referenceSpace) {
13271
+ let nearest = null;
13272
+ let nearestDist = Number.POSITIVE_INFINITY;
13273
+ let currentDist = Number.POSITIVE_INFINITY;
13274
+ let currentStillDetected = false;
13275
+ for (const mesh of detected) {
13276
+ if (!isGlobalMeshSurface(mesh)) continue;
13277
+ if (!this.viewerPos) {
13278
+ return this.electedGlobalMesh && detected.has(this.electedGlobalMesh) ? this.electedGlobalMesh : mesh;
13279
+ }
13280
+ const pose = frame.getPose(mesh.meshSpace, referenceSpace);
13281
+ if (!pose) continue;
13282
+ const m = pose.transform.matrix;
13283
+ const d = Math.hypot(
13284
+ m[12] - this.viewerPos.x,
13285
+ m[13] - this.viewerPos.y,
13286
+ m[14] - this.viewerPos.z
13287
+ );
13288
+ if (mesh === this.electedGlobalMesh) {
13289
+ currentDist = d;
13290
+ currentStillDetected = true;
13291
+ }
13292
+ if (d < nearestDist) {
13293
+ nearestDist = d;
13294
+ nearest = mesh;
13295
+ }
13296
+ }
13297
+ if (currentStillDetected && currentDist < nearestDist + GLOBAL_MESH_SWITCH_MARGIN) {
13298
+ return this.electedGlobalMesh;
13299
+ }
13300
+ this.electedGlobalMesh = nearest;
13301
+ return nearest;
13302
+ }
13303
+ /**
13304
+ * Admission control for a NOT-yet-spawned surface. With a viewer pose
13305
+ * available, the surface must behave world-anchored for a few frames before
13306
+ * an entity is created for it; without one (older runtimes, tests) it is
13307
+ * admitted immediately — the gate can't classify anyway. Returns the
13308
+ * warmed-up gate (carried into the entry so its motion history survives),
13309
+ * or null while the surface must keep waiting.
13310
+ */
13311
+ admit(pending, key, pose, deltaTime) {
13312
+ if (!this.viewerInverse) return new SurfacePoseGate();
13313
+ let gate = pending.get(key);
13314
+ if (!gate) {
13315
+ gate = new SurfacePoseGate();
13316
+ pending.set(key, gate);
13317
+ }
13318
+ const allowed = this.gateAllows(gate, pose, deltaTime);
13319
+ if (!allowed || !gate.warmedUp) return null;
13320
+ pending.delete(key);
13321
+ return gate;
13322
+ }
13323
+ /**
13324
+ * Run a surface's pose through its head-glue gate: position in reference
13325
+ * space vs position relative to the viewer. Without a viewer pose the gate
13326
+ * passes everything, degrading to the flag-only behavior.
13327
+ */
13328
+ gateAllows(gate, pose, deltaTime) {
13329
+ const m = pose.transform.matrix;
13330
+ const refPos = { x: m[12], y: m[13], z: m[14] };
13331
+ let viewPos = null;
13332
+ if (this.viewerInverse) {
13333
+ const v = this.tmpViewPos.set(refPos.x, refPos.y, refPos.z).applyMatrix4(this.viewerInverse);
13334
+ viewPos = { x: v.x, y: v.y, z: v.z };
12781
13335
  }
13336
+ return gate.update(refPos, viewPos, deltaTime);
12782
13337
  }
12783
13338
  createPlaneEntity(world, plane) {
12784
13339
  const collider = planeColliderFromPolygon(plane.polygon);
@@ -12798,7 +13353,8 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
12798
13353
  lastChangedTime: plane.lastChangedTime ?? 0,
12799
13354
  geometry: null,
12800
13355
  material: null,
12801
- emulated: false
13356
+ emulated: false,
13357
+ gate: new SurfacePoseGate()
12802
13358
  };
12803
13359
  if (this.debugVisible) {
12804
13360
  this.attachPlaneDebug(world, entry, collider, plane.semanticLabel ?? null);
@@ -12829,7 +13385,7 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
12829
13385
  const geometry = writeXrMeshGeometry(mesh.vertices, mesh.indices);
12830
13386
  const label = mesh.semanticLabel ?? null;
12831
13387
  const isGlobalMesh = label === "global mesh";
12832
- const material = new THREE51__namespace.MeshBasicMaterial({
13388
+ const material = new THREE56__namespace.MeshBasicMaterial({
12833
13389
  color: debugColorFor("mesh", label),
12834
13390
  wireframe: true,
12835
13391
  // The global scan is a coarse triangle soup of the whole room; at full
@@ -12850,8 +13406,8 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
12850
13406
  depthTest: true,
12851
13407
  depthWrite: false
12852
13408
  });
12853
- const root = new THREE51__namespace.Group();
12854
- const child = new THREE51__namespace.Mesh(geometry, material);
13409
+ const root = new THREE56__namespace.Group();
13410
+ const child = new THREE56__namespace.Mesh(geometry, material);
12855
13411
  child.visible = this.debugVisible;
12856
13412
  child.renderOrder = DEBUG_RENDER_ORDER;
12857
13413
  root.add(child);
@@ -12871,26 +13427,27 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
12871
13427
  lastChangedTime: mesh.lastChangedTime ?? 0,
12872
13428
  geometry,
12873
13429
  material,
12874
- emulated: false
13430
+ emulated: false,
13431
+ gate: new SurfacePoseGate()
12875
13432
  };
12876
13433
  }
12877
13434
  /** A thin box so a detected plane can be SEEN, not just collided with. */
12878
13435
  attachPlaneDebug(world, entry, collider, semanticLabel) {
12879
- const box = new THREE51__namespace.BoxGeometry(
13436
+ const box = new THREE56__namespace.BoxGeometry(
12880
13437
  collider.size.x,
12881
13438
  collider.size.y,
12882
13439
  collider.size.z
12883
13440
  );
12884
- const geometry = new THREE51__namespace.EdgesGeometry(box);
13441
+ const geometry = new THREE56__namespace.EdgesGeometry(box);
12885
13442
  box.dispose();
12886
- const material = new THREE51__namespace.LineBasicMaterial({
13443
+ const material = new THREE56__namespace.LineBasicMaterial({
12887
13444
  color: debugColorFor("plane", semanticLabel),
12888
13445
  // Same depth policy as the mesh overlay — see createMeshEntity.
12889
13446
  depthTest: true,
12890
13447
  depthWrite: false
12891
13448
  });
12892
- const root = new THREE51__namespace.Group();
12893
- const child = new THREE51__namespace.LineSegments(geometry, material);
13449
+ const root = new THREE56__namespace.Group();
13450
+ const child = new THREE56__namespace.LineSegments(geometry, material);
12894
13451
  child.renderOrder = DEBUG_RENDER_ORDER;
12895
13452
  child.position.set(collider.offset.x, collider.offset.y, collider.offset.z);
12896
13453
  child.visible = this.debugVisible;
@@ -12952,6 +13509,9 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
12952
13509
  clearAll(world) {
12953
13510
  this.clearMap(world, this.planes);
12954
13511
  this.clearMap(world, this.meshes);
13512
+ this.pendingPlanes.clear();
13513
+ this.pendingMeshes.clear();
13514
+ this.electedGlobalMesh = null;
12955
13515
  }
12956
13516
  dispose(world) {
12957
13517
  this.clearAll(world);
@@ -12963,6 +13523,918 @@ function normalizeOrientation(value) {
12963
13523
  return value === "horizontal" || value === "vertical" ? value : null;
12964
13524
  }
12965
13525
  __name(normalizeOrientation, "normalizeOrientation");
13526
+ var MOUSE_CLICK_TRAVEL_PX = 6;
13527
+ var PRESS_TINT_MIN_SECONDS = 0.1;
13528
+ var PRESS_TINT = 0.72;
13529
+ var HOVER_TINT = 0.9;
13530
+ var _UIInteractionSystem = class _UIInteractionSystem {
13531
+ /**
13532
+ * @param interaction The XR interaction system, or null in a world with no
13533
+ * XR (flat 3D experiences) — the mouse path still works via
13534
+ * `options.inputSystem`.
13535
+ */
13536
+ constructor(interaction, options) {
13537
+ this.xrPresses = /* @__PURE__ */ new Map();
13538
+ this.mousePress = null;
13539
+ this.mouseHover = null;
13540
+ /** entityId → seconds of pressed-tint left to display. */
13541
+ this.tintFloors = /* @__PURE__ */ new Map();
13542
+ this.tinted = /* @__PURE__ */ new Set();
13543
+ this.raycaster = new THREE56__namespace.Raycaster();
13544
+ this.interaction = interaction;
13545
+ this.inputSystem = options?.inputSystem ?? null;
13546
+ interaction?.registerBusyContributor(
13547
+ (_world, input) => this.xrPresses.has(input)
13548
+ );
13549
+ }
13550
+ update(world, deltaTime = 0) {
13551
+ if (world.isEditorMode()) return;
13552
+ if (world.isXrPresenting()) {
13553
+ this.updateXr(world);
13554
+ } else {
13555
+ this.updateMouse(world);
13556
+ }
13557
+ this.updateTints(world, deltaTime);
13558
+ }
13559
+ // ── XR path ────────────────────────────────────────────────────────────────
13560
+ updateXr(world) {
13561
+ const interaction = this.interaction;
13562
+ if (!interaction) return;
13563
+ const xrInput = interaction.inputSystem;
13564
+ const inputs = xrInput.getInputs();
13565
+ for (const input of inputs) {
13566
+ const hover = interaction.getHoverForInput(input);
13567
+ const hovered = hover ? this.widgetKind(world, hover.entityId) : null;
13568
+ if (input.selectStart && hover && hovered) {
13569
+ this.xrPresses.set(input, {
13570
+ entityId: hover.entityId,
13571
+ kind: hovered,
13572
+ travelPx: 0
13573
+ });
13574
+ this.beginPressTint(world, hover.entityId);
13575
+ }
13576
+ const press = this.xrPresses.get(input);
13577
+ if (press && press.kind === "slider") {
13578
+ this.dragSlider(world, press.entityId, input);
13579
+ }
13580
+ if (input.selectEnd || !input.connected) {
13581
+ if (press) {
13582
+ this.xrPresses.delete(input);
13583
+ const stillOn = hover?.entityId === press.entityId || // Vision Pro: the transient source is gone from the hover map on
13584
+ // its release frame — confirm against the last latched ray.
13585
+ this.rayHitsWidget(world, press.entityId, input);
13586
+ if (stillOn || press.kind === "slider") {
13587
+ this.fire(world, press, input);
13588
+ }
13589
+ this.endPressTint(press.entityId);
13590
+ }
13591
+ }
13592
+ }
13593
+ for (const [input] of this.xrPresses) {
13594
+ if (!inputs.includes(input)) this.xrPresses.delete(input);
13595
+ }
13596
+ }
13597
+ // ── Mouse path (flat preview) ──────────────────────────────────────────────
13598
+ updateMouse(world) {
13599
+ const input = this.inputSystem;
13600
+ if (!input) return;
13601
+ const hit = this.raycastMouse(world);
13602
+ const hovered = hit && this.widgetKind(world, hit) ? hit : null;
13603
+ if (hovered !== this.mouseHover) {
13604
+ if (this.mouseHover !== null) {
13605
+ this.setTint(world, this.mouseHover, 1);
13606
+ this.dispatchBubbling(
13607
+ world,
13608
+ this.mouseHover,
13609
+ (b, e) => b.onUiHoverEnd(e)
13610
+ );
13611
+ }
13612
+ if (hovered !== null) {
13613
+ this.setTint(world, hovered, HOVER_TINT);
13614
+ this.dispatchBubbling(world, hovered, (b, e) => b.onUiHoverStart(e));
13615
+ }
13616
+ this.mouseHover = hovered;
13617
+ }
13618
+ if (input.getMouseDown("left") && hovered) {
13619
+ const kind = this.widgetKind(world, hovered);
13620
+ if (kind) {
13621
+ this.mousePress = { entityId: hovered, kind, travelPx: 0 };
13622
+ this.beginPressTint(world, hovered);
13623
+ }
13624
+ }
13625
+ if (this.mousePress) {
13626
+ const delta = input.getMouseDelta();
13627
+ this.mousePress.travelPx += Math.hypot(delta.x, delta.y);
13628
+ if (this.mousePress.kind === "slider") {
13629
+ this.dragSliderMouse(world, this.mousePress.entityId);
13630
+ }
13631
+ }
13632
+ if (input.getMouseUp("left") && this.mousePress) {
13633
+ const press = this.mousePress;
13634
+ this.mousePress = null;
13635
+ const stillOn = hovered === press.entityId;
13636
+ const withinTravel = press.travelPx <= MOUSE_CLICK_TRAVEL_PX;
13637
+ if (press.kind === "slider" || stillOn && withinTravel) {
13638
+ this.fire(world, press, null);
13639
+ }
13640
+ this.endPressTint(press.entityId);
13641
+ }
13642
+ }
13643
+ raycastMouse(world) {
13644
+ const input = this.inputSystem;
13645
+ if (!input) return null;
13646
+ const dom = world.getRenderer().domElement;
13647
+ const rect = dom.getBoundingClientRect();
13648
+ let ndcX = 0;
13649
+ let ndcY = 0;
13650
+ if (input.isMousePointerLocked()) {
13651
+ ndcX = 0;
13652
+ ndcY = 0;
13653
+ } else {
13654
+ const pos = input.getMousePosition();
13655
+ ndcX = (pos.x - rect.left) / Math.max(1, rect.width) * 2 - 1;
13656
+ ndcY = -((pos.y - rect.top) / Math.max(1, rect.height) * 2 - 1);
13657
+ if (ndcX < -1 || ndcX > 1 || ndcY < -1 || ndcY > 1) return null;
13658
+ }
13659
+ this.raycaster.setFromCamera(new THREE56__namespace.Vector2(ndcX, ndcY), world.getCamera());
13660
+ const hits = world.raycast(
13661
+ this.raycaster.ray.origin,
13662
+ this.raycaster.ray.direction
13663
+ );
13664
+ for (const hit of hits) {
13665
+ if (typeof hit.entityId !== "number") continue;
13666
+ if (this.widgetKind(world, hit.entityId)) return hit.entityId;
13667
+ return null;
13668
+ }
13669
+ return null;
13670
+ }
13671
+ // ── Shared machinery ───────────────────────────────────────────────────────
13672
+ widgetKind(world, entityId) {
13673
+ if (world.getComponent(entityId, UIButtonComponent)) return "button";
13674
+ if (world.getComponent(entityId, UIToggleComponent)) return "toggle";
13675
+ if (world.getComponent(entityId, UISliderComponent)) return "slider";
13676
+ return null;
13677
+ }
13678
+ fire(world, press, input) {
13679
+ if (press.kind === "button") {
13680
+ this.dispatchBubbling(world, press.entityId, (b, e) => b.onUiPress(e), input);
13681
+ return;
13682
+ }
13683
+ if (press.kind === "toggle") {
13684
+ const toggle = world.getComponent(press.entityId, UIToggleComponent);
13685
+ if (!toggle) return;
13686
+ toggle.value = !toggle.value;
13687
+ this.dispatchBubbling(
13688
+ world,
13689
+ press.entityId,
13690
+ (b, e) => b.onUiToggle(e),
13691
+ input,
13692
+ toggle.value
13693
+ );
13694
+ return;
13695
+ }
13696
+ const slider = world.getComponent(press.entityId, UISliderComponent);
13697
+ if (!slider) return;
13698
+ this.dispatchBubbling(
13699
+ world,
13700
+ press.entityId,
13701
+ (b, e) => b.onUiChange(e),
13702
+ input,
13703
+ slider.value
13704
+ );
13705
+ }
13706
+ dragSlider(world, entityId, input) {
13707
+ const point = this.rayPointOnWidget(world, entityId, input);
13708
+ if (point) this.applySliderPoint(world, entityId, point, input);
13709
+ }
13710
+ dragSliderMouse(world, entityId) {
13711
+ const object = this.widgetObject(world, entityId);
13712
+ if (!object) return;
13713
+ const hits = this.raycaster.intersectObject(object, true);
13714
+ if (hits.length > 0) this.applySliderPoint(world, entityId, hits[0].point, null);
13715
+ }
13716
+ applySliderPoint(world, entityId, worldPoint, input) {
13717
+ const slider = world.getComponent(entityId, UISliderComponent);
13718
+ const object = this.widgetObject(world, entityId);
13719
+ if (!slider || !object) return;
13720
+ const local = object.worldToLocal(worldPoint.clone());
13721
+ const inset = slider.height / 2;
13722
+ const usable = Math.max(1e-3, slider.width - inset * 2);
13723
+ const t = Math.min(1, Math.max(0, local.x / usable + 0.5));
13724
+ const next = slider.min + t * (slider.max - slider.min);
13725
+ if (Math.abs(next - slider.value) < 1e-4) return;
13726
+ slider.value = next;
13727
+ this.dispatchBubbling(
13728
+ world,
13729
+ entityId,
13730
+ (b, e) => b.onUiChange(e),
13731
+ input,
13732
+ next
13733
+ );
13734
+ }
13735
+ widgetObject(world, entityId) {
13736
+ return world.getComponent(entityId, Object3DRef)?.object;
13737
+ }
13738
+ rayHitsWidget(world, entityId, input) {
13739
+ const object = this.widgetObject(world, entityId);
13740
+ if (!object) return false;
13741
+ this.raycaster.set(
13742
+ input.rayOrigin.clone(),
13743
+ input.rayDirection.clone().normalize()
13744
+ );
13745
+ return this.raycaster.intersectObject(object, true).length > 0;
13746
+ }
13747
+ rayPointOnWidget(world, entityId, input) {
13748
+ const object = this.widgetObject(world, entityId);
13749
+ if (!object) return null;
13750
+ this.raycaster.set(
13751
+ input.rayOrigin.clone(),
13752
+ input.rayDirection.clone().normalize()
13753
+ );
13754
+ const hits = this.raycaster.intersectObject(object, true);
13755
+ return hits.length > 0 ? hits[0].point : null;
13756
+ }
13757
+ /**
13758
+ * Dispatch to the widget's Behaviours, then BUBBLE up the parent chain so a
13759
+ * panel script hears its children. Bubbling (not a world broadcast) keeps
13760
+ * two spawned copies of the same menu prefab independent.
13761
+ */
13762
+ dispatchBubbling(world, entityId, visit, input = null, value) {
13763
+ const event = {
13764
+ targetEntityId: entityId,
13765
+ actionId: this.actionIdOf(world, entityId),
13766
+ input,
13767
+ ...value === void 0 ? {} : { value }
13768
+ };
13769
+ const visited = /* @__PURE__ */ new Set();
13770
+ let current = entityId;
13771
+ for (; ; ) {
13772
+ if (visited.has(current)) break;
13773
+ visited.add(current);
13774
+ const script = world.getComponent(current, ScriptComponent);
13775
+ const instances = script?.scriptInstances;
13776
+ if (instances) {
13777
+ for (const instance of instances.values()) {
13778
+ if (!(instance instanceof Behaviour)) continue;
13779
+ try {
13780
+ visit(instance, event);
13781
+ } catch (error) {
13782
+ console.error("[UIInteractionSystem] hook failed:", error);
13783
+ }
13784
+ }
13785
+ }
13786
+ const parentId = world.getComponent(current, ParentId)?.value;
13787
+ if (typeof parentId !== "number") break;
13788
+ current = parentId;
13789
+ }
13790
+ }
13791
+ actionIdOf(world, entityId) {
13792
+ const button = world.getComponent(entityId, UIButtonComponent);
13793
+ if (button?.actionId) return button.actionId;
13794
+ const toggle = world.getComponent(entityId, UIToggleComponent);
13795
+ if (toggle?.actionId) return toggle.actionId;
13796
+ const slider = world.getComponent(entityId, UISliderComponent);
13797
+ if (slider?.actionId) return slider.actionId;
13798
+ const name = world.getComponent(entityId, Name)?.value;
13799
+ return typeof name === "string" ? name : String(entityId);
13800
+ }
13801
+ // ── Pressed/hover tint ─────────────────────────────────────────────────────
13802
+ beginPressTint(world, entityId) {
13803
+ this.setTint(world, entityId, PRESS_TINT);
13804
+ this.tintFloors.set(entityId, PRESS_TINT_MIN_SECONDS);
13805
+ }
13806
+ endPressTint(entityId) {
13807
+ if (!this.tintFloors.has(entityId)) {
13808
+ this.tintFloors.set(entityId, 0);
13809
+ }
13810
+ }
13811
+ updateTints(world, deltaTime) {
13812
+ for (const [entityId, remaining] of this.tintFloors) {
13813
+ const next = remaining - deltaTime;
13814
+ const stillHeld = [...this.xrPresses.values()].some((p) => p.entityId === entityId) || this.mousePress?.entityId === entityId;
13815
+ if (stillHeld) continue;
13816
+ if (next <= 0) {
13817
+ this.tintFloors.delete(entityId);
13818
+ this.setTint(
13819
+ world,
13820
+ entityId,
13821
+ this.mouseHover === entityId ? HOVER_TINT : 1
13822
+ );
13823
+ } else {
13824
+ this.tintFloors.set(entityId, next);
13825
+ }
13826
+ }
13827
+ }
13828
+ setTint(world, entityId, scalar) {
13829
+ const object = this.widgetObject(world, entityId);
13830
+ if (!object) return;
13831
+ if (scalar === 1) this.tinted.delete(entityId);
13832
+ else this.tinted.add(entityId);
13833
+ object.traverse((child) => {
13834
+ const material = child.material;
13835
+ if (material?.color) material.color.setScalar(scalar);
13836
+ });
13837
+ }
13838
+ };
13839
+ __name(_UIInteractionSystem, "UIInteractionSystem");
13840
+ var UIInteractionSystem = _UIInteractionSystem;
13841
+
13842
+ // core/ui/uiCanvas.ts
13843
+ var DEFAULT_PIXELS_PER_METER = 1024;
13844
+ var MIN_PIXELS_PER_METER = 256;
13845
+ var MAX_PIXELS_PER_METER = 2048;
13846
+ var MAX_CANVAS_SIDE = 2048;
13847
+ function resolveCanvasSize(widthMeters, heightMeters, pixelDensity = DEFAULT_PIXELS_PER_METER) {
13848
+ const w = Math.max(0.01, widthMeters);
13849
+ const h = Math.max(0.01, heightMeters);
13850
+ const authored = Math.min(
13851
+ MAX_PIXELS_PER_METER,
13852
+ Math.max(MIN_PIXELS_PER_METER, pixelDensity)
13853
+ );
13854
+ const density = Math.min(authored, MAX_CANVAS_SIDE / Math.max(w, h));
13855
+ const even = /* @__PURE__ */ __name((v) => Math.max(2, 2 * Math.round(v * density / 2)), "even");
13856
+ return { pxWidth: even(w), pxHeight: even(h), density };
13857
+ }
13858
+ __name(resolveCanvasSize, "resolveCanvasSize");
13859
+ function wrapText(measure, text, maxWidthPx) {
13860
+ const lines = [];
13861
+ for (const paragraph of text.split("\n")) {
13862
+ const words = paragraph.split(/\s+/).filter((w) => w.length > 0);
13863
+ if (words.length === 0) {
13864
+ lines.push("");
13865
+ continue;
13866
+ }
13867
+ let line = "";
13868
+ for (const word of words) {
13869
+ const candidate = line ? `${line} ${word}` : word;
13870
+ if (measure(candidate) <= maxWidthPx) {
13871
+ line = candidate;
13872
+ continue;
13873
+ }
13874
+ if (line) {
13875
+ lines.push(line);
13876
+ line = "";
13877
+ }
13878
+ if (measure(word) <= maxWidthPx) {
13879
+ line = word;
13880
+ continue;
13881
+ }
13882
+ let chunk = "";
13883
+ for (const char of word) {
13884
+ const next = chunk + char;
13885
+ if (measure(next) <= maxWidthPx || chunk.length === 0) {
13886
+ chunk = next;
13887
+ } else {
13888
+ lines.push(chunk);
13889
+ chunk = char;
13890
+ }
13891
+ }
13892
+ line = chunk;
13893
+ }
13894
+ lines.push(line);
13895
+ }
13896
+ return lines;
13897
+ }
13898
+ __name(wrapText, "wrapText");
13899
+ var ELLIPSIS = "\u2026";
13900
+ function clampLines(measure, lines, maxLines, maxWidthPx) {
13901
+ if (maxLines <= 0) return [];
13902
+ if (lines.length <= maxLines) return lines;
13903
+ const kept = lines.slice(0, maxLines);
13904
+ let last = kept[maxLines - 1];
13905
+ while (last.length > 0 && measure(last + ELLIPSIS) > maxWidthPx) {
13906
+ last = last.slice(0, -1);
13907
+ }
13908
+ kept[maxLines - 1] = last + ELLIPSIS;
13909
+ return kept;
13910
+ }
13911
+ __name(clampLines, "clampLines");
13912
+ var UI_FONT_STACK = '-apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
13913
+ function tracePath(ctx, x, y, w, h, r) {
13914
+ const radius = Math.max(0, Math.min(r, w / 2, h / 2));
13915
+ ctx.beginPath();
13916
+ if (typeof ctx.roundRect === "function") {
13917
+ ctx.roundRect(x, y, w, h, radius);
13918
+ return;
13919
+ }
13920
+ ctx.moveTo(x + radius, y);
13921
+ ctx.arcTo(x + w, y, x + w, y + h, radius);
13922
+ ctx.arcTo(x + w, y + h, x, y + h, radius);
13923
+ ctx.arcTo(x, y + h, x, y, radius);
13924
+ ctx.arcTo(x, y, x + w, y, radius);
13925
+ ctx.closePath();
13926
+ }
13927
+ __name(tracePath, "tracePath");
13928
+ function withOpacity(ctx, color, opacity) {
13929
+ if (opacity >= 1) return color;
13930
+ ctx.save();
13931
+ ctx.fillStyle = color;
13932
+ const parsed = ctx.fillStyle;
13933
+ ctx.restore();
13934
+ if (parsed.startsWith("#") && (parsed.length === 7 || parsed.length === 4)) {
13935
+ const hex = parsed.length === 4 ? `#${parsed[1]}${parsed[1]}${parsed[2]}${parsed[2]}${parsed[3]}${parsed[3]}` : parsed;
13936
+ const r = Number.parseInt(hex.slice(1, 3), 16);
13937
+ const g = Number.parseInt(hex.slice(3, 5), 16);
13938
+ const b = Number.parseInt(hex.slice(5, 7), 16);
13939
+ return `rgba(${r}, ${g}, ${b}, ${opacity})`;
13940
+ }
13941
+ return parsed;
13942
+ }
13943
+ __name(withOpacity, "withOpacity");
13944
+ function drawChrome(ctx, pxWidth, pxHeight, density, style) {
13945
+ ctx.clearRect(0, 0, pxWidth, pxHeight);
13946
+ const border = Math.max(0, style.borderWidthMeters * density);
13947
+ const radius = style.cornerRadiusMeters * density;
13948
+ tracePath(ctx, 0, 0, pxWidth, pxHeight, radius);
13949
+ ctx.fillStyle = withOpacity(
13950
+ ctx,
13951
+ style.backgroundColor,
13952
+ Math.max(0, Math.min(1, style.backgroundOpacity))
13953
+ );
13954
+ ctx.fill();
13955
+ if (border > 0) {
13956
+ tracePath(
13957
+ ctx,
13958
+ border / 2,
13959
+ border / 2,
13960
+ pxWidth - border,
13961
+ pxHeight - border,
13962
+ Math.max(0, radius - border / 2)
13963
+ );
13964
+ ctx.strokeStyle = style.borderColor;
13965
+ ctx.lineWidth = border;
13966
+ ctx.stroke();
13967
+ }
13968
+ }
13969
+ __name(drawChrome, "drawChrome");
13970
+ function drawTextBlock(ctx, pxWidth, pxHeight, density, text, style) {
13971
+ const fontPx = Math.max(4, style.fontSizeMeters * density);
13972
+ const paddingPx = style.paddingMeters * density;
13973
+ const contentW = Math.max(1, pxWidth - paddingPx * 2);
13974
+ const contentH = Math.max(1, pxHeight - paddingPx * 2);
13975
+ const lineHeightPx = fontPx * style.lineHeight;
13976
+ ctx.font = `${style.fontWeight} ${fontPx}px ${UI_FONT_STACK}`;
13977
+ const measure = /* @__PURE__ */ __name((s) => ctx.measureText(s).width, "measure");
13978
+ const maxLines = Math.max(1, Math.floor(contentH / lineHeightPx));
13979
+ const lines = clampLines(
13980
+ measure,
13981
+ wrapText(measure, text, contentW),
13982
+ maxLines,
13983
+ contentW
13984
+ );
13985
+ const blockH = lines.length * lineHeightPx;
13986
+ const top = style.valign === "top" ? paddingPx : style.valign === "bottom" ? pxHeight - paddingPx - blockH : (pxHeight - blockH) / 2;
13987
+ const anchorX = style.align === "left" ? paddingPx : style.align === "right" ? pxWidth - paddingPx : pxWidth / 2;
13988
+ ctx.save();
13989
+ tracePath(ctx, 0, 0, pxWidth, pxHeight, 0);
13990
+ ctx.clip();
13991
+ ctx.fillStyle = style.color;
13992
+ ctx.textAlign = style.align;
13993
+ ctx.textBaseline = "middle";
13994
+ for (let i = 0; i < lines.length; i += 1) {
13995
+ ctx.fillText(lines[i], anchorX, top + (i + 0.5) * lineHeightPx);
13996
+ }
13997
+ ctx.restore();
13998
+ }
13999
+ __name(drawTextBlock, "drawTextBlock");
14000
+ function panelSignature(widthM, heightM, size, style) {
14001
+ return JSON.stringify([
14002
+ widthM,
14003
+ heightM,
14004
+ size.pxWidth,
14005
+ size.pxHeight,
14006
+ style.backgroundColor,
14007
+ style.backgroundOpacity,
14008
+ style.cornerRadiusMeters,
14009
+ style.borderWidthMeters,
14010
+ style.borderColor
14011
+ ]);
14012
+ }
14013
+ __name(panelSignature, "panelSignature");
14014
+ function textSignature(widthM, heightM, size, text, style) {
14015
+ return JSON.stringify([
14016
+ widthM,
14017
+ heightM,
14018
+ size.pxWidth,
14019
+ size.pxHeight,
14020
+ text,
14021
+ style.fontSizeMeters,
14022
+ style.fontWeight,
14023
+ style.color,
14024
+ style.align,
14025
+ style.valign,
14026
+ style.lineHeight,
14027
+ style.paddingMeters
14028
+ ]);
14029
+ }
14030
+ __name(textSignature, "textSignature");
14031
+ function buttonSignature(widthM, heightM, size, panel, label, text) {
14032
+ return JSON.stringify([
14033
+ panelSignature(widthM, heightM, size, panel),
14034
+ label,
14035
+ text.fontSizeMeters,
14036
+ text.fontWeight,
14037
+ text.color
14038
+ ]);
14039
+ }
14040
+ __name(buttonSignature, "buttonSignature");
14041
+ function trackSignature(widthM, heightM, size, panel, accentColor, knobColor) {
14042
+ return JSON.stringify([
14043
+ panelSignature(widthM, heightM, size, panel),
14044
+ accentColor,
14045
+ knobColor
14046
+ ]);
14047
+ }
14048
+ __name(trackSignature, "trackSignature");
14049
+ function drawRoundedBar(ctx, pxX, pxY, pxW, pxH, color) {
14050
+ tracePath(ctx, pxX, pxY, pxW, pxH, pxH / 2);
14051
+ ctx.fillStyle = color;
14052
+ ctx.fill();
14053
+ }
14054
+ __name(drawRoundedBar, "drawRoundedBar");
14055
+
14056
+ // core/systems/UIPanelSystem.ts
14057
+ var FACE_RENDER_ORDER = 10;
14058
+ var CHILD_Z = 2e-3;
14059
+ var _UIPanelSystem = class _UIPanelSystem {
14060
+ constructor(options) {
14061
+ this.entries = /* @__PURE__ */ new Map();
14062
+ this.createCanvas = options?.createCanvas ?? (() => document.createElement("canvas"));
14063
+ }
14064
+ update(world, deltaTime = 0) {
14065
+ const live = /* @__PURE__ */ new Set();
14066
+ for (const entityId of world.query(UIPanelComponent, Object3DRef)) {
14067
+ const panel = world.getComponent(entityId, UIPanelComponent);
14068
+ if (!panel) continue;
14069
+ live.add(entityId);
14070
+ this.syncPanel(world, entityId, panel);
14071
+ this.applyFollow(world, entityId, panel);
14072
+ }
14073
+ for (const entityId of world.query(UITextComponent, Object3DRef)) {
14074
+ const text = world.getComponent(entityId, UITextComponent);
14075
+ if (!text) continue;
14076
+ live.add(entityId);
14077
+ this.syncText(world, entityId, text);
14078
+ }
14079
+ for (const entityId of world.query(UIButtonComponent, Object3DRef)) {
14080
+ const button = world.getComponent(entityId, UIButtonComponent);
14081
+ if (!button) continue;
14082
+ live.add(entityId);
14083
+ this.syncButton(world, entityId, button);
14084
+ }
14085
+ for (const entityId of world.query(UIToggleComponent, Object3DRef)) {
14086
+ const toggle = world.getComponent(entityId, UIToggleComponent);
14087
+ if (!toggle) continue;
14088
+ live.add(entityId);
14089
+ this.syncToggle(world, entityId, toggle, deltaTime);
14090
+ }
14091
+ for (const entityId of world.query(UISliderComponent, Object3DRef)) {
14092
+ const slider = world.getComponent(entityId, UISliderComponent);
14093
+ if (!slider) continue;
14094
+ live.add(entityId);
14095
+ this.syncSlider(world, entityId, slider);
14096
+ }
14097
+ for (const [entityId, entry] of this.entries) {
14098
+ if (!live.has(entityId)) {
14099
+ this.destroyEntry(entry);
14100
+ this.entries.delete(entityId);
14101
+ }
14102
+ }
14103
+ }
14104
+ /** All GPU/canvas resources; call on world teardown. */
14105
+ dispose() {
14106
+ for (const entry of this.entries.values()) this.destroyEntry(entry);
14107
+ this.entries.clear();
14108
+ }
14109
+ // ── Widgets ────────────────────────────────────────────────────────────────
14110
+ syncPanel(world, entityId, panel) {
14111
+ const size = resolveCanvasSize(panel.width, panel.height, panel.pixelDensity);
14112
+ const style = {
14113
+ backgroundColor: panel.backgroundColor,
14114
+ backgroundOpacity: panel.backgroundOpacity,
14115
+ cornerRadiusMeters: panel.cornerRadius,
14116
+ borderWidthMeters: panel.borderWidth,
14117
+ borderColor: panel.borderColor
14118
+ };
14119
+ const signature = panelSignature(panel.width, panel.height, size, style);
14120
+ this.rebuildIfChanged(world, entityId, signature, panel.width, panel.height, size, (ctx) => {
14121
+ drawChrome(ctx, size.pxWidth, size.pxHeight, size.density, style);
14122
+ });
14123
+ }
14124
+ syncText(world, entityId, text) {
14125
+ const size = resolveCanvasSize(text.width, text.height);
14126
+ const style = {
14127
+ fontSizeMeters: text.fontSize,
14128
+ fontWeight: text.fontWeight,
14129
+ color: text.color,
14130
+ align: text.align,
14131
+ valign: text.valign,
14132
+ lineHeight: text.lineHeight,
14133
+ paddingMeters: text.padding
14134
+ };
14135
+ const signature = textSignature(text.width, text.height, size, text.text, style);
14136
+ this.rebuildIfChanged(world, entityId, signature, text.width, text.height, size, (ctx) => {
14137
+ ctx.clearRect(0, 0, size.pxWidth, size.pxHeight);
14138
+ drawTextBlock(ctx, size.pxWidth, size.pxHeight, size.density, text.text, style);
14139
+ });
14140
+ }
14141
+ syncButton(world, entityId, button) {
14142
+ const size = resolveCanvasSize(button.width, button.height);
14143
+ const chrome = {
14144
+ backgroundColor: button.backgroundColor,
14145
+ backgroundOpacity: button.backgroundOpacity,
14146
+ cornerRadiusMeters: button.cornerRadius,
14147
+ borderWidthMeters: button.borderWidth,
14148
+ borderColor: button.borderColor
14149
+ };
14150
+ const label = {
14151
+ fontSizeMeters: button.fontSize,
14152
+ fontWeight: button.fontWeight,
14153
+ color: button.textColor,
14154
+ align: "center",
14155
+ valign: "middle",
14156
+ lineHeight: 1.2,
14157
+ paddingMeters: 0.01
14158
+ };
14159
+ const signature = buttonSignature(
14160
+ button.width,
14161
+ button.height,
14162
+ size,
14163
+ chrome,
14164
+ button.label,
14165
+ label
14166
+ );
14167
+ this.rebuildIfChanged(world, entityId, signature, button.width, button.height, size, (ctx) => {
14168
+ drawChrome(ctx, size.pxWidth, size.pxHeight, size.density, chrome);
14169
+ drawTextBlock(ctx, size.pxWidth, size.pxHeight, size.density, button.label, label);
14170
+ });
14171
+ }
14172
+ syncToggle(world, entityId, toggle, deltaTime) {
14173
+ const size = resolveCanvasSize(toggle.width, toggle.height);
14174
+ const chrome = {
14175
+ backgroundColor: toggle.value ? toggle.accentColor : toggle.trackColor,
14176
+ backgroundOpacity: 1,
14177
+ cornerRadiusMeters: toggle.height / 2,
14178
+ borderWidthMeters: 0,
14179
+ borderColor: "#000000"
14180
+ };
14181
+ const signature = JSON.stringify([
14182
+ trackSignature(
14183
+ toggle.width,
14184
+ toggle.height,
14185
+ size,
14186
+ chrome,
14187
+ toggle.accentColor,
14188
+ toggle.knobColor
14189
+ ),
14190
+ toggle.value
14191
+ ]);
14192
+ const entry = this.rebuildIfChanged(
14193
+ world,
14194
+ entityId,
14195
+ signature,
14196
+ toggle.width,
14197
+ toggle.height,
14198
+ size,
14199
+ (ctx) => {
14200
+ drawChrome(ctx, size.pxWidth, size.pxHeight, size.density, chrome);
14201
+ }
14202
+ );
14203
+ if (!entry) return;
14204
+ if (!entry.knob) {
14205
+ entry.knob = this.makeDisc(
14206
+ toggle.height * 0.4,
14207
+ toggle.knobColor,
14208
+ entry.face.parent,
14209
+ CHILD_Z
14210
+ );
14211
+ }
14212
+ const inset = toggle.height / 2;
14213
+ const target = toggle.value ? toggle.width / 2 - inset : -(toggle.width / 2 - inset);
14214
+ const knob = entry.knob;
14215
+ const ease = Math.min(1, deltaTime * 14);
14216
+ knob.position.x += (target - knob.position.x) * (deltaTime > 0 ? ease : 1);
14217
+ knob.position.z = CHILD_Z;
14218
+ }
14219
+ syncSlider(world, entityId, slider) {
14220
+ const size = resolveCanvasSize(slider.width, slider.height);
14221
+ const trackThickness = slider.height * 0.32;
14222
+ const knobRadius = slider.height * 0.45;
14223
+ const usable = Math.max(1e-3, slider.width - slider.height);
14224
+ const chrome = {
14225
+ backgroundColor: slider.trackColor,
14226
+ backgroundOpacity: 1,
14227
+ cornerRadiusMeters: trackThickness / 2,
14228
+ borderWidthMeters: 0,
14229
+ borderColor: "#000000"
14230
+ };
14231
+ const signature = trackSignature(
14232
+ slider.width,
14233
+ slider.height,
14234
+ size,
14235
+ chrome,
14236
+ slider.accentColor,
14237
+ slider.knobColor
14238
+ );
14239
+ const entry = this.rebuildIfChanged(
14240
+ world,
14241
+ entityId,
14242
+ signature,
14243
+ slider.width,
14244
+ slider.height,
14245
+ size,
14246
+ (ctx) => {
14247
+ ctx.clearRect(0, 0, size.pxWidth, size.pxHeight);
14248
+ const trackWidthM = usable + trackThickness;
14249
+ drawRoundedBar(
14250
+ ctx,
14251
+ (slider.width - trackWidthM) / 2 * size.density,
14252
+ (slider.height - trackThickness) / 2 * size.density,
14253
+ trackWidthM * size.density,
14254
+ trackThickness * size.density,
14255
+ slider.trackColor
14256
+ );
14257
+ }
14258
+ );
14259
+ if (!entry) return;
14260
+ if (!entry.fill) {
14261
+ entry.fill = this.makeQuad(
14262
+ 1,
14263
+ trackThickness,
14264
+ slider.accentColor,
14265
+ entry.face.parent,
14266
+ CHILD_Z / 2
14267
+ );
14268
+ entry.cap = this.makeDisc(
14269
+ trackThickness / 2,
14270
+ slider.accentColor,
14271
+ entry.face.parent,
14272
+ CHILD_Z / 2,
14273
+ Math.PI / 2,
14274
+ Math.PI
14275
+ );
14276
+ entry.cap.position.x = -usable / 2;
14277
+ }
14278
+ if (!entry.knob) {
14279
+ entry.knob = this.makeDisc(
14280
+ knobRadius,
14281
+ slider.knobColor,
14282
+ entry.face.parent,
14283
+ CHILD_Z
14284
+ );
14285
+ }
14286
+ const range = Math.max(1e-6, slider.max - slider.min);
14287
+ const t = Math.min(1, Math.max(0, (slider.value - slider.min) / range));
14288
+ entry.knob.position.x = -usable / 2 + t * usable;
14289
+ entry.knob.position.z = CHILD_Z;
14290
+ entry.fill.scale.x = Math.max(1e-4, t * usable);
14291
+ entry.fill.position.x = -usable / 2 + t * usable / 2;
14292
+ entry.fill.position.z = CHILD_Z / 2;
14293
+ }
14294
+ // ── Machinery ──────────────────────────────────────────────────────────────
14295
+ rebuildIfChanged(world, entityId, signature, widthM, heightM, size, draw) {
14296
+ const root = world.getComponent(entityId, Object3DRef)?.object;
14297
+ if (!root) return null;
14298
+ let entry = this.entries.get(entityId);
14299
+ if (entry && entry.signature === signature) return entry;
14300
+ if (entry) this.disposeMovingParts(entry);
14301
+ if (!entry) {
14302
+ const canvas2 = this.createCanvas();
14303
+ const texture = new THREE56__namespace.CanvasTexture(
14304
+ canvas2
14305
+ );
14306
+ this.configureTexture(world, texture);
14307
+ const material = new THREE56__namespace.MeshBasicMaterial({
14308
+ map: texture,
14309
+ transparent: true,
14310
+ depthWrite: false,
14311
+ // UI colours are authored absolutes; scene tone mapping would shift
14312
+ // them (the classic "why is my white UI beige" bug).
14313
+ toneMapped: false,
14314
+ side: THREE56__namespace.DoubleSide,
14315
+ premultipliedAlpha: true
14316
+ });
14317
+ const face = new THREE56__namespace.Mesh(
14318
+ new THREE56__namespace.PlaneGeometry(widthM, heightM),
14319
+ material
14320
+ );
14321
+ face.renderOrder = FACE_RENDER_ORDER;
14322
+ root.add(face);
14323
+ entry = {
14324
+ signature: "",
14325
+ face,
14326
+ texture,
14327
+ material,
14328
+ canvas: canvas2,
14329
+ knob: null,
14330
+ fill: null,
14331
+ cap: null
14332
+ };
14333
+ this.entries.set(entityId, entry);
14334
+ }
14335
+ const { canvas } = entry;
14336
+ if (canvas.width !== size.pxWidth || canvas.height !== size.pxHeight) {
14337
+ canvas.width = size.pxWidth;
14338
+ canvas.height = size.pxHeight;
14339
+ }
14340
+ const params = entry.face.geometry.parameters;
14341
+ if (params.width !== widthM || params.height !== heightM) {
14342
+ entry.face.geometry.dispose();
14343
+ entry.face.geometry = new THREE56__namespace.PlaneGeometry(widthM, heightM);
14344
+ }
14345
+ const ctx = canvas.getContext("2d");
14346
+ if (ctx) draw(ctx);
14347
+ entry.texture.needsUpdate = true;
14348
+ entry.signature = signature;
14349
+ return entry;
14350
+ }
14351
+ configureTexture(world, texture) {
14352
+ texture.colorSpace = THREE56__namespace.SRGBColorSpace;
14353
+ texture.generateMipmaps = true;
14354
+ texture.minFilter = THREE56__namespace.LinearMipmapLinearFilter;
14355
+ texture.magFilter = THREE56__namespace.LinearFilter;
14356
+ texture.premultiplyAlpha = true;
14357
+ try {
14358
+ const max = world.getRenderer().capabilities?.getMaxAnisotropy?.();
14359
+ if (typeof max === "number") texture.anisotropy = Math.min(8, max);
14360
+ } catch {
14361
+ }
14362
+ }
14363
+ makeQuad(widthM, heightM, color, parent, z) {
14364
+ return this.addPart(
14365
+ new THREE56__namespace.PlaneGeometry(widthM, heightM),
14366
+ color,
14367
+ parent,
14368
+ z
14369
+ );
14370
+ }
14371
+ /** A filled disc (or arc segment, for the fill's rounded cap). */
14372
+ makeDisc(radiusM, color, parent, z, thetaStart = 0, thetaLength = Math.PI * 2) {
14373
+ return this.addPart(
14374
+ new THREE56__namespace.CircleGeometry(radiusM, 32, thetaStart, thetaLength),
14375
+ color,
14376
+ parent,
14377
+ z
14378
+ );
14379
+ }
14380
+ addPart(geometry, color, parent, z) {
14381
+ const mesh = new THREE56__namespace.Mesh(
14382
+ geometry,
14383
+ new THREE56__namespace.MeshBasicMaterial({
14384
+ color,
14385
+ transparent: true,
14386
+ depthWrite: false,
14387
+ toneMapped: false,
14388
+ side: THREE56__namespace.DoubleSide
14389
+ })
14390
+ );
14391
+ mesh.renderOrder = FACE_RENDER_ORDER + 1;
14392
+ mesh.position.z = z;
14393
+ mesh.raycast = () => {
14394
+ };
14395
+ parent?.add(mesh);
14396
+ return mesh;
14397
+ }
14398
+ /** Remove + dispose knob/fill/cap so a sync pass rebuilds them fresh. */
14399
+ disposeMovingParts(entry) {
14400
+ for (const key of ["knob", "fill", "cap"]) {
14401
+ const mesh = entry[key];
14402
+ if (!mesh) continue;
14403
+ mesh.removeFromParent();
14404
+ mesh.geometry.dispose();
14405
+ mesh.material.dispose();
14406
+ entry[key] = null;
14407
+ }
14408
+ }
14409
+ /**
14410
+ * Billboard: yaw the ENTITY TRANSFORM toward the camera. Writing the
14411
+ * Object3D directly would be overwritten by `TransformSyncSystem` (which
14412
+ * runs after this system, before render) — the same reason locomotion
14413
+ * writes the rig transform. Skipped in the editor so the gizmo and the
14414
+ * authored rotation stay in charge while authoring.
14415
+ */
14416
+ applyFollow(world, entityId, panel) {
14417
+ if (panel.follow !== "billboard" || world.isEditorMode()) return;
14418
+ const transform = world.getComponent(entityId, TransformComponent);
14419
+ const object = world.getComponent(entityId, Object3DRef)?.object;
14420
+ if (!transform || !object) return;
14421
+ const camera = world.getCamera();
14422
+ const cam = new THREE56__namespace.Vector3();
14423
+ const self = new THREE56__namespace.Vector3();
14424
+ camera.getWorldPosition(cam);
14425
+ object.getWorldPosition(self);
14426
+ transform.rotation.y = Math.atan2(cam.x - self.x, cam.z - self.z);
14427
+ }
14428
+ destroyEntry(entry) {
14429
+ this.disposeMovingParts(entry);
14430
+ entry.face.removeFromParent();
14431
+ entry.face.geometry.dispose();
14432
+ entry.face.material.dispose();
14433
+ entry.texture.dispose();
14434
+ }
14435
+ };
14436
+ __name(_UIPanelSystem, "UIPanelSystem");
14437
+ var UIPanelSystem = _UIPanelSystem;
12966
14438
  var _XRHitTestSystem = class _XRHitTestSystem {
12967
14439
  constructor() {
12968
14440
  this.sources = /* @__PURE__ */ new Map();
@@ -12999,12 +14471,12 @@ var _XRHitTestSystem = class _XRHitTestSystem {
12999
14471
  if (!hits || hits.length === 0) continue;
13000
14472
  const pose = hits[0].getPose(referenceSpace);
13001
14473
  if (!pose) continue;
13002
- const matrix = new THREE51__namespace.Matrix4().fromArray(
14474
+ const matrix = new THREE56__namespace.Matrix4().fromArray(
13003
14475
  pose.transform.matrix
13004
14476
  );
13005
- const position = new THREE51__namespace.Vector3();
13006
- const quaternion = new THREE51__namespace.Quaternion();
13007
- matrix.decompose(position, quaternion, new THREE51__namespace.Vector3());
14477
+ const position = new THREE56__namespace.Vector3();
14478
+ const quaternion = new THREE56__namespace.Quaternion();
14479
+ matrix.decompose(position, quaternion, new THREE56__namespace.Vector3());
13008
14480
  this.results.set(key, { position, quaternion });
13009
14481
  }
13010
14482
  }
@@ -13075,9 +14547,13 @@ var _XRAnchorSystem = class _XRAnchorSystem {
13075
14547
  this.anchors = /* @__PURE__ */ new Map();
13076
14548
  /** In-flight creations, so one entity is not anchored twice. */
13077
14549
  this.pending = /* @__PURE__ */ new Set();
14550
+ /** Per-anchor head-glue gates — see XREnvironmentSystem's TrackedEntry. */
14551
+ this.gates = /* @__PURE__ */ new Map();
13078
14552
  this.presenting = false;
14553
+ this.tmpViewerMatrix = new THREE56__namespace.Matrix4();
14554
+ this.tmpViewPos = new THREE56__namespace.Vector3();
13079
14555
  }
13080
- update(world) {
14556
+ update(world, deltaTime = 0) {
13081
14557
  const presenting = world.isXrPresenting();
13082
14558
  if (!presenting) {
13083
14559
  if (this.presenting) {
@@ -13097,8 +14573,11 @@ var _XRAnchorSystem = class _XRAnchorSystem {
13097
14573
  if (!live.has(entityId)) {
13098
14574
  anchor.delete?.();
13099
14575
  this.anchors.delete(entityId);
14576
+ this.gates.delete(entityId);
13100
14577
  }
13101
14578
  }
14579
+ const viewer = frame.getViewerPose?.(referenceSpace);
14580
+ const viewerInverse = viewer ? this.tmpViewerMatrix.fromArray(viewer.transform.matrix).invert() : null;
13102
14581
  for (const entityId of entityIds) {
13103
14582
  const component = world.getComponent(entityId, XRAnchorComponent);
13104
14583
  const transform = world.getComponent(entityId, TransformComponent);
@@ -13108,6 +14587,7 @@ var _XRAnchorSystem = class _XRAnchorSystem {
13108
14587
  if (existing) {
13109
14588
  existing.delete?.();
13110
14589
  this.anchors.delete(entityId);
14590
+ this.gates.delete(entityId);
13111
14591
  }
13112
14592
  continue;
13113
14593
  }
@@ -13118,7 +14598,21 @@ var _XRAnchorSystem = class _XRAnchorSystem {
13118
14598
  }
13119
14599
  const pose = frame.getPose(anchor.anchorSpace, referenceSpace);
13120
14600
  if (pose && pose.emulatedPosition !== true) {
13121
- decomposeXrPose(pose.transform.matrix, transform);
14601
+ let gate = this.gates.get(entityId);
14602
+ if (!gate) {
14603
+ gate = new SurfacePoseGate();
14604
+ this.gates.set(entityId, gate);
14605
+ }
14606
+ const m = pose.transform.matrix;
14607
+ const refPos = { x: m[12], y: m[13], z: m[14] };
14608
+ let viewPos = null;
14609
+ if (viewerInverse) {
14610
+ const v = this.tmpViewPos.set(refPos.x, refPos.y, refPos.z).applyMatrix4(viewerInverse);
14611
+ viewPos = { x: v.x, y: v.y, z: v.z };
14612
+ }
14613
+ if (gate.update(refPos, viewPos, deltaTime)) {
14614
+ decomposeXrPose(pose.transform.matrix, transform);
14615
+ }
13122
14616
  }
13123
14617
  }
13124
14618
  }
@@ -13131,8 +14625,8 @@ var _XRAnchorSystem = class _XRAnchorSystem {
13131
14625
  if (typeof frame.createAnchor !== "function") return;
13132
14626
  const RigidTransform = globalThis.XRRigidTransform;
13133
14627
  if (!RigidTransform) return;
13134
- const quaternion = new THREE51__namespace.Quaternion().setFromEuler(
13135
- new THREE51__namespace.Euler(
14628
+ const quaternion = new THREE56__namespace.Quaternion().setFromEuler(
14629
+ new THREE56__namespace.Euler(
13136
14630
  transform.rotation.x,
13137
14631
  transform.rotation.y,
13138
14632
  transform.rotation.z,
@@ -13163,6 +14657,7 @@ var _XRAnchorSystem = class _XRAnchorSystem {
13163
14657
  }).finally(() => this.pending.delete(entityId));
13164
14658
  }
13165
14659
  releaseAll() {
14660
+ this.gates.clear();
13166
14661
  for (const anchor of this.anchors.values()) anchor.delete?.();
13167
14662
  this.anchors.clear();
13168
14663
  this.pending.clear();
@@ -13177,9 +14672,9 @@ var XRAnchorSystem = _XRAnchorSystem;
13177
14672
  function buildGeometry2(area) {
13178
14673
  if (area.shape === "circle") {
13179
14674
  const radius = Math.max(5e-3, area.width / 2);
13180
- return new THREE51__namespace.CircleGeometry(radius, 48);
14675
+ return new THREE56__namespace.CircleGeometry(radius, 48);
13181
14676
  }
13182
- return new THREE51__namespace.PlaneGeometry(
14677
+ return new THREE56__namespace.PlaneGeometry(
13183
14678
  Math.max(0.01, area.width),
13184
14679
  Math.max(0.01, area.depth)
13185
14680
  );
@@ -13202,7 +14697,7 @@ var _VRTeleportAreaSystem = class _VRTeleportAreaSystem {
13202
14697
  for (const entityId of entityIds) {
13203
14698
  const area = world.getComponent(entityId, VRTeleportAreaComponent);
13204
14699
  const object = world.getComponent(entityId, Object3DRef)?.object;
13205
- if (!area || !(object instanceof THREE51__namespace.Mesh)) continue;
14700
+ if (!area || !(object instanceof THREE56__namespace.Mesh)) continue;
13206
14701
  const signature = signatureOf(area);
13207
14702
  if (this.signatures.get(entityId) === signature) continue;
13208
14703
  this.signatures.set(entityId, signature);
@@ -13214,18 +14709,18 @@ var _VRTeleportAreaSystem = class _VRTeleportAreaSystem {
13214
14709
  __name(_VRTeleportAreaSystem, "VRTeleportAreaSystem");
13215
14710
  var VRTeleportAreaSystem = _VRTeleportAreaSystem;
13216
14711
  function createHandMaterial(preset, options) {
13217
- const color = new THREE51__namespace.Color(options.color);
14712
+ const color = new THREE56__namespace.Color(options.color);
13218
14713
  switch (preset) {
13219
14714
  case "ghost":
13220
- return new THREE51__namespace.MeshBasicMaterial({
14715
+ return new THREE56__namespace.MeshBasicMaterial({
13221
14716
  color,
13222
14717
  transparent: true,
13223
14718
  opacity: Math.min(1, Math.max(0.05, options.opacity * 0.45)),
13224
14719
  depthWrite: false,
13225
- side: THREE51__namespace.DoubleSide
14720
+ side: THREE56__namespace.DoubleSide
13226
14721
  });
13227
14722
  case "neon":
13228
- return new THREE51__namespace.MeshStandardMaterial({
14723
+ return new THREE56__namespace.MeshStandardMaterial({
13229
14724
  color,
13230
14725
  emissive: color,
13231
14726
  emissiveIntensity: Math.max(0.5, options.emissiveIntensity || 2),
@@ -13235,7 +14730,7 @@ function createHandMaterial(preset, options) {
13235
14730
  opacity: options.opacity
13236
14731
  });
13237
14732
  case "skeleton":
13238
- return new THREE51__namespace.MeshBasicMaterial({
14733
+ return new THREE56__namespace.MeshBasicMaterial({
13239
14734
  color,
13240
14735
  wireframe: true,
13241
14736
  transparent: true,
@@ -13243,7 +14738,7 @@ function createHandMaterial(preset, options) {
13243
14738
  });
13244
14739
  case "custom":
13245
14740
  case "default":
13246
- return new THREE51__namespace.MeshStandardMaterial({
14741
+ return new THREE56__namespace.MeshStandardMaterial({
13247
14742
  color,
13248
14743
  roughness: 0.85,
13249
14744
  metalness: 0,
@@ -13251,10 +14746,10 @@ function createHandMaterial(preset, options) {
13251
14746
  emissiveIntensity: Math.max(0, options.emissiveIntensity),
13252
14747
  transparent: options.opacity < 1,
13253
14748
  opacity: options.opacity,
13254
- side: THREE51__namespace.DoubleSide
14749
+ side: THREE56__namespace.DoubleSide
13255
14750
  });
13256
14751
  default: {
13257
- return new THREE51__namespace.MeshStandardMaterial({ color });
14752
+ return new THREE56__namespace.MeshStandardMaterial({ color });
13258
14753
  }
13259
14754
  }
13260
14755
  }
@@ -13279,9 +14774,9 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
13279
14774
  constructor(options) {
13280
14775
  this.controllerModelFactory = new XRControllerModelFactory_js.XRControllerModelFactory();
13281
14776
  this.handModelFactory = new XRHandModelFactory_js.XRHandModelFactory();
13282
- this.group = new THREE51__namespace.Group();
14777
+ this.group = new THREE56__namespace.Group();
13283
14778
  /** Reused so a per-frame colour compare allocates nothing. */
13284
- this.rayColorScratch = new THREE51__namespace.Color();
14779
+ this.rayColorScratch = new THREE56__namespace.Color();
13285
14780
  this.slots = /* @__PURE__ */ new Map();
13286
14781
  this.attachedTo = null;
13287
14782
  /** Last applied preset signature, so materials rebuild only on real change. */
@@ -13468,17 +14963,17 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
13468
14963
  * without pulling in a line-rendering extension.
13469
14964
  */
13470
14965
  createRay() {
13471
- const geometry = new THREE51__namespace.CylinderGeometry(RAY_RADIUS, RAY_RADIUS, 1, 8, 1);
14966
+ const geometry = new THREE56__namespace.CylinderGeometry(RAY_RADIUS, RAY_RADIUS, 1, 8, 1);
13472
14967
  geometry.rotateX(-Math.PI / 2);
13473
14968
  geometry.translate(0, 0, -0.5);
13474
- const material = new THREE51__namespace.MeshBasicMaterial({
14969
+ const material = new THREE56__namespace.MeshBasicMaterial({
13475
14970
  color: "#4da3ff",
13476
14971
  transparent: true,
13477
14972
  opacity: 0.75,
13478
14973
  depthTest: false,
13479
14974
  depthWrite: false
13480
14975
  });
13481
- const mesh = new THREE51__namespace.Mesh(geometry, material);
14976
+ const mesh = new THREE56__namespace.Mesh(geometry, material);
13482
14977
  mesh.name = "XRPointerRay";
13483
14978
  mesh.renderOrder = 999;
13484
14979
  mesh.visible = false;
@@ -13509,14 +15004,14 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
13509
15004
  __name(_XRControllerVisualSystem, "XRControllerVisualSystem");
13510
15005
  var XRControllerVisualSystem = _XRControllerVisualSystem;
13511
15006
  var MARKER_RADIUS = 0.28;
13512
- var ACCENT = new THREE51__namespace.Color("#4da3ff");
13513
- var SEGMENT_AXIS = new THREE51__namespace.Vector3(0, 1, 0);
15007
+ var ACCENT = new THREE56__namespace.Color("#4da3ff");
15008
+ var SEGMENT_AXIS = new THREE56__namespace.Vector3(0, 1, 0);
13514
15009
  var HEAD_CLEARANCE = 0.25;
13515
15010
  var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
13516
15011
  constructor(locomotionSystem) {
13517
- this.group = new THREE51__namespace.Group();
15012
+ this.group = new THREE56__namespace.Group();
13518
15013
  /** Holds the segment chain that draws the arc. */
13519
- this.arc = new THREE51__namespace.Group();
15014
+ this.arc = new THREE56__namespace.Group();
13520
15015
  /**
13521
15016
  * Unit cylinder along +Y, reused by every segment.
13522
15017
  *
@@ -13525,14 +15020,14 @@ var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
13525
15020
  * scaled cylinders gives real thickness while rebuilding no geometry: each
13526
15021
  * frame only moves, rotates and scales meshes that already exist.
13527
15022
  */
13528
- this.segmentGeometry = new THREE51__namespace.CylinderGeometry(1, 1, 1, 6, 1);
15023
+ this.segmentGeometry = new THREE56__namespace.CylinderGeometry(1, 1, 1, 6, 1);
13529
15024
  this.segments = [];
13530
- this.marker = new THREE51__namespace.Group();
15025
+ this.marker = new THREE56__namespace.Group();
13531
15026
  this.attached = false;
13532
- this.scratchDirection = new THREE51__namespace.Vector3();
13533
- this.scratchHead = new THREE51__namespace.Vector3();
13534
- this.validColor = new THREE51__namespace.Color();
13535
- this.invalidColor = new THREE51__namespace.Color();
15027
+ this.scratchDirection = new THREE56__namespace.Vector3();
15028
+ this.scratchHead = new THREE56__namespace.Vector3();
15029
+ this.validColor = new THREE56__namespace.Color();
15030
+ this.invalidColor = new THREE56__namespace.Color();
13536
15031
  this.locomotionSystem = locomotionSystem;
13537
15032
  this.group.name = "XRTeleportVisuals";
13538
15033
  this.group.userData.ecsPreviewHidden = true;
@@ -13610,12 +15105,12 @@ var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
13610
15105
  /** Grow the segment pool to cover the current arc. */
13611
15106
  ensureSegments(count) {
13612
15107
  while (this.segments.length < count) {
13613
- const material = new THREE51__namespace.MeshBasicMaterial({
15108
+ const material = new THREE56__namespace.MeshBasicMaterial({
13614
15109
  transparent: true,
13615
15110
  depthTest: false,
13616
15111
  depthWrite: false
13617
15112
  });
13618
- const mesh = new THREE51__namespace.Mesh(this.segmentGeometry, material);
15113
+ const mesh = new THREE56__namespace.Mesh(this.segmentGeometry, material);
13619
15114
  mesh.frustumCulled = false;
13620
15115
  mesh.renderOrder = 998;
13621
15116
  mesh.raycast = () => {
@@ -13639,33 +15134,33 @@ var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
13639
15134
  return world.getComponent(entityId, XRRigComponent) ?? null;
13640
15135
  }
13641
15136
  createRing() {
13642
- const geometry = new THREE51__namespace.RingGeometry(
15137
+ const geometry = new THREE56__namespace.RingGeometry(
13643
15138
  MARKER_RADIUS * 0.72,
13644
15139
  MARKER_RADIUS,
13645
15140
  48
13646
15141
  );
13647
15142
  geometry.rotateX(-Math.PI / 2);
13648
- return new THREE51__namespace.Mesh(
15143
+ return new THREE56__namespace.Mesh(
13649
15144
  geometry,
13650
- new THREE51__namespace.MeshBasicMaterial({
15145
+ new THREE56__namespace.MeshBasicMaterial({
13651
15146
  color: ACCENT,
13652
15147
  transparent: true,
13653
15148
  opacity: 0.9,
13654
- side: THREE51__namespace.DoubleSide,
15149
+ side: THREE56__namespace.DoubleSide,
13655
15150
  depthTest: false
13656
15151
  })
13657
15152
  );
13658
15153
  }
13659
15154
  createDot() {
13660
- const geometry = new THREE51__namespace.CircleGeometry(MARKER_RADIUS * 0.16, 24);
15155
+ const geometry = new THREE56__namespace.CircleGeometry(MARKER_RADIUS * 0.16, 24);
13661
15156
  geometry.rotateX(-Math.PI / 2);
13662
- return new THREE51__namespace.Mesh(
15157
+ return new THREE56__namespace.Mesh(
13663
15158
  geometry,
13664
- new THREE51__namespace.MeshBasicMaterial({
15159
+ new THREE56__namespace.MeshBasicMaterial({
13665
15160
  color: ACCENT,
13666
15161
  transparent: true,
13667
15162
  opacity: 0.55,
13668
- side: THREE51__namespace.DoubleSide,
15163
+ side: THREE56__namespace.DoubleSide,
13669
15164
  depthTest: false
13670
15165
  })
13671
15166
  );
@@ -13776,7 +15271,7 @@ function boneDirections(joints, finger) {
13776
15271
  const from = joints[chain[i - 1]];
13777
15272
  const to = joints[chain[i]];
13778
15273
  if (!from || !to) return null;
13779
- const direction = new THREE51__namespace.Vector3().subVectors(to, from);
15274
+ const direction = new THREE56__namespace.Vector3().subVectors(to, from);
13780
15275
  if (direction.lengthSq() < 1e-12) return null;
13781
15276
  directions.push(direction.normalize());
13782
15277
  }
@@ -13849,8 +15344,8 @@ function computeSpread(joints, a, b) {
13849
15344
  const bBase = joints[METACARPAL_JOINTS[b]];
13850
15345
  const bTip = joints[TIP_JOINTS[b]];
13851
15346
  if (!aBase || !aTip || !bBase || !bTip) return null;
13852
- const dirA = new THREE51__namespace.Vector3().subVectors(aTip, aBase);
13853
- const dirB = new THREE51__namespace.Vector3().subVectors(bTip, bBase);
15347
+ const dirA = new THREE56__namespace.Vector3().subVectors(aTip, aBase);
15348
+ const dirB = new THREE56__namespace.Vector3().subVectors(bTip, bBase);
13854
15349
  if (dirA.lengthSq() < 1e-12 || dirB.lengthSq() < 1e-12) return null;
13855
15350
  return clamp01((1 - dirA.normalize().dot(dirB.normalize())) / 0.45);
13856
15351
  }
@@ -13860,18 +15355,18 @@ function computePalmPose(joints, handedness) {
13860
15355
  const indexBase = joints["index-finger-metacarpal"];
13861
15356
  const pinkyBase = joints["pinky-finger-metacarpal"];
13862
15357
  if (!wrist || !indexBase || !pinkyBase) return null;
13863
- const u = new THREE51__namespace.Vector3().subVectors(indexBase, wrist);
13864
- const v = new THREE51__namespace.Vector3().subVectors(pinkyBase, wrist);
13865
- const normal = new THREE51__namespace.Vector3().crossVectors(u, v);
15358
+ const u = new THREE56__namespace.Vector3().subVectors(indexBase, wrist);
15359
+ const v = new THREE56__namespace.Vector3().subVectors(pinkyBase, wrist);
15360
+ const normal = new THREE56__namespace.Vector3().crossVectors(u, v);
13866
15361
  if (normal.lengthSq() < 1e-12) return null;
13867
15362
  normal.normalize();
13868
15363
  if (handedness === "left") normal.multiplyScalar(-1);
13869
- const right = new THREE51__namespace.Vector3().subVectors(indexBase, pinkyBase);
15364
+ const right = new THREE56__namespace.Vector3().subVectors(indexBase, pinkyBase);
13870
15365
  if (right.lengthSq() < 1e-12) return null;
13871
15366
  right.normalize();
13872
15367
  if (handedness === "left") right.multiplyScalar(-1);
13873
- const up = new THREE51__namespace.Vector3().crossVectors(normal, right).normalize();
13874
- const center = new THREE51__namespace.Vector3().add(wrist).add(indexBase).add(pinkyBase).divideScalar(3);
15368
+ const up = new THREE56__namespace.Vector3().crossVectors(normal, right).normalize();
15369
+ const center = new THREE56__namespace.Vector3().add(wrist).add(indexBase).add(pinkyBase).divideScalar(3);
13875
15370
  return {
13876
15371
  center,
13877
15372
  normal,
@@ -13902,7 +15397,7 @@ function computeHandShape(joints, handedness) {
13902
15397
  const thumbTip = joints["thumb-tip"];
13903
15398
  let thumbDirection = null;
13904
15399
  if (thumbBase && thumbTip) {
13905
- const direction = new THREE51__namespace.Vector3().subVectors(thumbTip, thumbBase);
15400
+ const direction = new THREE56__namespace.Vector3().subVectors(thumbTip, thumbBase);
13906
15401
  if (direction.lengthSq() > 1e-12) thumbDirection = direction.normalize();
13907
15402
  }
13908
15403
  const fingerDirections = {};
@@ -13913,7 +15408,7 @@ function computeHandShape(joints, handedness) {
13913
15408
  fingerDirections[finger] = null;
13914
15409
  continue;
13915
15410
  }
13916
- const direction = new THREE51__namespace.Vector3().subVectors(tip, base);
15411
+ const direction = new THREE56__namespace.Vector3().subVectors(tip, base);
13917
15412
  fingerDirections[finger] = direction.lengthSq() > 1e-12 ? direction.normalize() : null;
13918
15413
  }
13919
15414
  return {
@@ -13947,12 +15442,12 @@ function scoreAgainst(actual, target, tolerance) {
13947
15442
  __name(scoreAgainst, "scoreAgainst");
13948
15443
  var DEFAULT_DIRECTION_TOLERANCE = 45;
13949
15444
  var WORLD_DIRECTIONS = {
13950
- up: new THREE51__namespace.Vector3(0, 1, 0),
13951
- down: new THREE51__namespace.Vector3(0, -1, 0),
13952
- forward: new THREE51__namespace.Vector3(0, 0, -1),
13953
- back: new THREE51__namespace.Vector3(0, 0, 1),
13954
- left: new THREE51__namespace.Vector3(-1, 0, 0),
13955
- right: new THREE51__namespace.Vector3(1, 0, 0)
15445
+ up: new THREE56__namespace.Vector3(0, 1, 0),
15446
+ down: new THREE56__namespace.Vector3(0, -1, 0),
15447
+ forward: new THREE56__namespace.Vector3(0, 0, -1),
15448
+ back: new THREE56__namespace.Vector3(0, 0, 1),
15449
+ left: new THREE56__namespace.Vector3(-1, 0, 0),
15450
+ right: new THREE56__namespace.Vector3(1, 0, 0)
13956
15451
  };
13957
15452
  function axisVector(shape, axis) {
13958
15453
  if (axis === "thumb") return shape.thumbDirection;
@@ -13967,7 +15462,7 @@ function resolveDirection(direction, shape, context) {
13967
15462
  const head = context?.headPosition;
13968
15463
  const origin = shape.palm?.center;
13969
15464
  if (!head || !origin) return null;
13970
- const toHead = new THREE51__namespace.Vector3().subVectors(head, origin);
15465
+ const toHead = new THREE56__namespace.Vector3().subVectors(head, origin);
13971
15466
  if (toHead.lengthSq() < 1e-12) return null;
13972
15467
  toHead.normalize();
13973
15468
  return direction === "toward-head" ? toHead : toHead.multiplyScalar(-1);
@@ -13979,8 +15474,8 @@ function scoreDirections(actual, accepted, shape, toleranceDegrees, context) {
13979
15474
  for (const direction of accepted) {
13980
15475
  const wanted = resolveDirection(direction, shape, context);
13981
15476
  if (!wanted) continue;
13982
- const angle = THREE51__namespace.MathUtils.radToDeg(
13983
- Math.acos(THREE51__namespace.MathUtils.clamp(actual.dot(wanted), -1, 1))
15477
+ const angle = THREE56__namespace.MathUtils.radToDeg(
15478
+ Math.acos(THREE56__namespace.MathUtils.clamp(actual.dot(wanted), -1, 1))
13984
15479
  );
13985
15480
  const normalizedError = Math.max(0, angle - toleranceDegrees) / 90;
13986
15481
  const score = clamp01(1 - normalizedError / MATCH_FALLOFF);
@@ -14045,8 +15540,8 @@ function matchHandPose(shape, definition, context) {
14045
15540
  if (!handAxis || !wanted) {
14046
15541
  consider(0, "orientation");
14047
15542
  } else {
14048
- const angle = THREE51__namespace.MathUtils.radToDeg(
14049
- Math.acos(THREE51__namespace.MathUtils.clamp(handAxis.dot(wanted), -1, 1))
15543
+ const angle = THREE56__namespace.MathUtils.radToDeg(
15544
+ Math.acos(THREE56__namespace.MathUtils.clamp(handAxis.dot(wanted), -1, 1))
14050
15545
  );
14051
15546
  const normalizedError = Math.max(0, angle - toleranceDegrees) / 90;
14052
15547
  consider(clamp01(1 - normalizedError / MATCH_FALLOFF), "orientation");
@@ -14124,7 +15619,7 @@ var _XRHandPoseSystem = class _XRHandPoseSystem {
14124
15619
  this.trackers = /* @__PURE__ */ new Map();
14125
15620
  this.shapes = /* @__PURE__ */ new Map();
14126
15621
  /** Reused so head-relative orientation checks allocate nothing per frame. */
14127
- this.headPosition = new THREE51__namespace.Vector3();
15622
+ this.headPosition = new THREE56__namespace.Vector3();
14128
15623
  this.elapsed = 0;
14129
15624
  this.warnedNoHands = false;
14130
15625
  this.noHandSeconds = 0;
@@ -14301,7 +15796,7 @@ var _XRHoverVisualSystem = class _XRHoverVisualSystem {
14301
15796
  const wantsColor = interactable.hoverBehavior === "color" || interactable.hoverBehavior === "both";
14302
15797
  this.records.set(entityId, {
14303
15798
  shell: wantsColor ? this.addShell(world, entityId, interactable) : null,
14304
- baseScale: new THREE51__namespace.Vector3(
15799
+ baseScale: new THREE56__namespace.Vector3(
14305
15800
  transform.scale.x,
14306
15801
  transform.scale.y,
14307
15802
  transform.scale.z
@@ -14314,27 +15809,27 @@ var _XRHoverVisualSystem = class _XRHoverVisualSystem {
14314
15809
  addShell(world, entityId, interactable) {
14315
15810
  const object = world.getComponent(entityId, Object3DRef)?.object;
14316
15811
  if (!object) return null;
14317
- const material = new THREE51__namespace.MeshBasicMaterial({
14318
- color: new THREE51__namespace.Color(interactable.hoverColor),
15812
+ const material = new THREE56__namespace.MeshBasicMaterial({
15813
+ color: new THREE56__namespace.Color(interactable.hoverColor),
14319
15814
  // Back faces only, so the shell shows just outside the silhouette instead
14320
15815
  // of covering the object.
14321
- side: THREE51__namespace.BackSide,
15816
+ side: THREE56__namespace.BackSide,
14322
15817
  transparent: true,
14323
15818
  opacity: 0.85,
14324
15819
  depthWrite: false
14325
15820
  });
14326
- const group = new THREE51__namespace.Group();
15821
+ const group = new THREE56__namespace.Group();
14327
15822
  group.name = "XRHoverShell";
14328
15823
  group.userData[XR_HOVER_SHELL_FLAG] = true;
14329
15824
  group.renderOrder = 998;
14330
15825
  object.traverse((child) => {
14331
- if (!(child instanceof THREE51__namespace.Mesh) || !child.geometry) return;
15826
+ if (!(child instanceof THREE56__namespace.Mesh) || !child.geometry) return;
14332
15827
  if (child.userData[XR_HOVER_SHELL_FLAG]) return;
14333
- const clone3 = new THREE51__namespace.Mesh(child.geometry, material);
15828
+ const clone3 = new THREE56__namespace.Mesh(child.geometry, material);
14334
15829
  child.updateWorldMatrix(true, false);
14335
15830
  object.updateWorldMatrix(true, false);
14336
15831
  clone3.matrixAutoUpdate = false;
14337
- clone3.matrix.copy(object.matrixWorld).invert().multiply(child.matrixWorld).scale(new THREE51__namespace.Vector3(SHELL_INFLATE, SHELL_INFLATE, SHELL_INFLATE));
15832
+ clone3.matrix.copy(object.matrixWorld).invert().multiply(child.matrixWorld).scale(new THREE56__namespace.Vector3(SHELL_INFLATE, SHELL_INFLATE, SHELL_INFLATE));
14338
15833
  clone3.userData[XR_HOVER_SHELL_FLAG] = true;
14339
15834
  clone3.raycast = () => {
14340
15835
  };
@@ -14383,7 +15878,7 @@ var _XRHoverVisualSystem = class _XRHoverVisualSystem {
14383
15878
  if (!shell) return;
14384
15879
  shell.parent?.remove(shell);
14385
15880
  shell.traverse((child) => {
14386
- if (child instanceof THREE51__namespace.Mesh) {
15881
+ if (child instanceof THREE56__namespace.Mesh) {
14387
15882
  const material = child.material;
14388
15883
  if (Array.isArray(material)) {
14389
15884
  for (const entry of material) entry.dispose();
@@ -14753,6 +16248,7 @@ var _World = class _World {
14753
16248
  const lightSyncSystem = new LightSyncSystem();
14754
16249
  const materialSyncSystem = new MaterialSyncSystem();
14755
16250
  const vrTeleportAreaSystem = new VRTeleportAreaSystem();
16251
+ const uiPanelSystem = new UIPanelSystem();
14756
16252
  const physicsSyncSystem = new PhysicsSyncSystem({
14757
16253
  isEditor: isEditor ?? false
14758
16254
  });
@@ -14783,6 +16279,7 @@ var _World = class _World {
14783
16279
  this.addSystems([
14784
16280
  ...coreSystems,
14785
16281
  vrTeleportAreaSystem,
16282
+ uiPanelSystem,
14786
16283
  physicsSyncSystem,
14787
16284
  ...systems,
14788
16285
  objectVisibilitySystem,
@@ -15095,8 +16592,8 @@ var _World = class _World {
15095
16592
  * ```
15096
16593
  */
15097
16594
  raycast(origin, direction, near = 0, far = Infinity) {
15098
- const rayOrigin = new THREE51__namespace.Vector3(origin.x, origin.y, origin.z);
15099
- const rayDirection = new THREE51__namespace.Vector3(
16595
+ const rayOrigin = new THREE56__namespace.Vector3(origin.x, origin.y, origin.z);
16596
+ const rayDirection = new THREE56__namespace.Vector3(
15100
16597
  direction.x,
15101
16598
  direction.y,
15102
16599
  direction.z
@@ -15105,7 +16602,7 @@ var _World = class _World {
15105
16602
  return [];
15106
16603
  }
15107
16604
  rayDirection.normalize();
15108
- const raycaster = new THREE51__namespace.Raycaster(rayOrigin, rayDirection, near, far);
16605
+ const raycaster = new THREE56__namespace.Raycaster(rayOrigin, rayDirection, near, far);
15109
16606
  const intersections = raycaster.intersectObjects(
15110
16607
  this.scene.children,
15111
16608
  true
@@ -15139,14 +16636,14 @@ var _World = class _World {
15139
16636
  if (!sourceObject) {
15140
16637
  return [];
15141
16638
  }
15142
- const rayOrigin = new THREE51__namespace.Vector3();
15143
- const rayDirection = new THREE51__namespace.Vector3();
16639
+ const rayOrigin = new THREE56__namespace.Vector3();
16640
+ const rayDirection = new THREE56__namespace.Vector3();
15144
16641
  sourceObject.getWorldPosition(rayOrigin);
15145
16642
  sourceObject.getWorldDirection(rayDirection);
15146
16643
  if (rayDirection.lengthSq() === 0) {
15147
16644
  return [];
15148
16645
  }
15149
- const raycaster = new THREE51__namespace.Raycaster(rayOrigin, rayDirection, near, far);
16646
+ const raycaster = new THREE56__namespace.Raycaster(rayOrigin, rayDirection, near, far);
15150
16647
  const intersections = raycaster.intersectObjects(
15151
16648
  this.scene.children,
15152
16649
  true
@@ -15853,6 +17350,8 @@ exports.ScriptObjectSystem = ScriptObjectSystem;
15853
17350
  exports.TeleportAimGate = TeleportAimGate;
15854
17351
  exports.ThrowVelocityTracker = ThrowVelocityTracker;
15855
17352
  exports.TransformSyncSystem = TransformSyncSystem;
17353
+ exports.UIInteractionSystem = UIInteractionSystem;
17354
+ exports.UIPanelSystem = UIPanelSystem;
15856
17355
  exports.VELOCITY_SAMPLES = VELOCITY_SAMPLES;
15857
17356
  exports.VRTeleportAreaSystem = VRTeleportAreaSystem;
15858
17357
  exports.VideoSystem = VideoSystem;
@@ -15919,6 +17418,11 @@ exports.createSelectableComponent = createSelectableComponent;
15919
17418
  exports.createSelectionTransformStateComponent = createSelectionTransformStateComponent;
15920
17419
  exports.createSpriteComponent = createSpriteComponent;
15921
17420
  exports.createTransformComponent = createTransformComponent;
17421
+ exports.createUIButtonComponent = createUIButtonComponent;
17422
+ exports.createUIPanelComponent = createUIPanelComponent;
17423
+ exports.createUISliderComponent = createUISliderComponent;
17424
+ exports.createUITextComponent = createUITextComponent;
17425
+ exports.createUIToggleComponent = createUIToggleComponent;
15922
17426
  exports.createVRTeleportAreaComponent = createVRTeleportAreaComponent;
15923
17427
  exports.createVideoComponent = createVideoComponent;
15924
17428
  exports.createXRAnchorComponent = createXRAnchorComponent;