@relu-interactives/spatial-ecs 0.4.3 → 0.4.5

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.
package/dist/index.d.cts CHANGED
@@ -3,8 +3,8 @@ export { A as AssetInput, t as CheckboxInput, u as ColorInput, v as ComponentFac
3
3
  import * as THREE from 'three';
4
4
  import { O as Object3DRef, ar as XrHandPreset } from './XRHandPose-CxPv-LBo.cjs';
5
5
  export { aD as AnimationStateCallbacks, aE as AnimationStateMachine, aF as AnimationStateManager, aG as StateMachine } from './XRHandPose-CxPv-LBo.cjs';
6
- import { X as XrCapabilities, a as XrInputState, b as XrHandPoseEventDetail } from './index-CBdnIyI8.cjs';
7
- export { A as AnimationSystem, c as AudioSystem, C as CameraSyncSystem, E as EnvironmentSyncSystem, I as InstancedMeshSystem, L as LightSyncSystem, M as MaterialSyncSystem, d as MeshGeometrySystem, e as ModuleLoader, N as NO_XR_CAPABILITIES, O as ObjectVisibilitySystem, P as PhysicsSyncSystem, f as PostprocessingSyncSystem, S as SCRIPT_OBJECT_ROOT_FLAG, g as ScriptBehaviourSystem, h as ScriptObjectSystem, i as SelectionContext, V as VRTeleportAreaSystem, j as VideoSystem, k as XRAnchorSystem, l as XRControllerVisualSystem, m as XREnvironmentSystem, n as XRHandPoseSystem, o as XRHitTestSystem, p as XRHoverVisualSystem, q as XRInputSystem, r as XRInteractionSystem, s as XRLocomotionSystem, t as XRSessionSystem, u as XRTeleportVisualSystem, v as XR_HOVER_SHELL_FLAG, w as XrHandedness, x as XrHitResult, y as XrInputKind, z as readXrCapabilities } from './index-CBdnIyI8.cjs';
6
+ import { X as XrCapabilities, a as XrInputState, b as XrHandPoseEventDetail } from './index-CH7qMsQT.cjs';
7
+ export { A as AnimationSystem, c as AudioSystem, C as CameraSyncSystem, E as EnvironmentSyncSystem, I as InstancedMeshSystem, L as LightSyncSystem, M as MaterialSyncSystem, d as MeshGeometrySystem, e as ModuleLoader, N as NO_XR_CAPABILITIES, O as ObjectVisibilitySystem, P as PhysicsSyncSystem, f as PostprocessingSyncSystem, S as SCRIPT_OBJECT_ROOT_FLAG, g as ScriptBehaviourSystem, h as ScriptObjectSystem, i as SelectionContext, V as VRTeleportAreaSystem, j as VideoSystem, k as XRAnchorSystem, l as XRControllerVisualSystem, m as XREnvironmentSystem, n as XRHandPoseSystem, o as XRHitTestSystem, p as XRHoverVisualSystem, q as XRInputSystem, r as XRInteractionSystem, s as XRLocomotionSystem, t as XRSessionSystem, u as XRTeleportVisualSystem, v as XR_HOVER_SHELL_FLAG, w as XrHandedness, x as XrHitResult, y as XrInputKind, z as readXrCapabilities } from './index-CH7qMsQT.cjs';
8
8
  export { i as CoreComponents } from './index-CQsHUez3.cjs';
9
9
  export { createAnimationComponent, createAudioComponent, createCameraComponent, createEntityTypeComponent, createEnvironmentComponent, createImageComponent, createImageTargetAnchorComponent, createImageTargetComponent, createInstanceSlotComponent, createInstancedMeshComponent, createLightComponent, createMaterialComponent, createMeshComponent, createMeshGeometryComponent, createModelComponent, createNameComponent, createObject3DRefComponent, createParentIdComponent, createPhysicsComponent, createPostprocessingComponent, createScriptComponent, createScriptObjectComponent, createSelectableComponent, createSelectionTransformStateComponent, createSpriteComponent, createTransformComponent, createVRTeleportAreaComponent, createVideoComponent, createXRAnchorComponent, createXRHandPoseComponent, createXRInteractableComponent, createXRInteractorComponent, createXRInteractorSideComponent, createXRRigComponent, registerDefaultComponentFactories, registerDefaultFactories } from './factories/index.cjs';
10
10
  import { GLTF } from 'three/examples/jsm/loaders/GLTFLoader.js';
package/dist/index.d.ts CHANGED
@@ -3,8 +3,8 @@ export { A as AssetInput, t as CheckboxInput, u as ColorInput, v as ComponentFac
3
3
  import * as THREE from 'three';
4
4
  import { O as Object3DRef, ar as XrHandPreset } from './XRHandPose-BImIa4ZS.js';
5
5
  export { aD as AnimationStateCallbacks, aE as AnimationStateMachine, aF as AnimationStateManager, aG as StateMachine } from './XRHandPose-BImIa4ZS.js';
6
- import { X as XrCapabilities, a as XrInputState, b as XrHandPoseEventDetail } from './index-n7SeH119.js';
7
- export { A as AnimationSystem, c as AudioSystem, C as CameraSyncSystem, E as EnvironmentSyncSystem, I as InstancedMeshSystem, L as LightSyncSystem, M as MaterialSyncSystem, d as MeshGeometrySystem, e as ModuleLoader, N as NO_XR_CAPABILITIES, O as ObjectVisibilitySystem, P as PhysicsSyncSystem, f as PostprocessingSyncSystem, S as SCRIPT_OBJECT_ROOT_FLAG, g as ScriptBehaviourSystem, h as ScriptObjectSystem, i as SelectionContext, V as VRTeleportAreaSystem, j as VideoSystem, k as XRAnchorSystem, l as XRControllerVisualSystem, m as XREnvironmentSystem, n as XRHandPoseSystem, o as XRHitTestSystem, p as XRHoverVisualSystem, q as XRInputSystem, r as XRInteractionSystem, s as XRLocomotionSystem, t as XRSessionSystem, u as XRTeleportVisualSystem, v as XR_HOVER_SHELL_FLAG, w as XrHandedness, x as XrHitResult, y as XrInputKind, z as readXrCapabilities } from './index-n7SeH119.js';
6
+ import { X as XrCapabilities, a as XrInputState, b as XrHandPoseEventDetail } from './index-BphKHaV-.js';
7
+ export { A as AnimationSystem, c as AudioSystem, C as CameraSyncSystem, E as EnvironmentSyncSystem, I as InstancedMeshSystem, L as LightSyncSystem, M as MaterialSyncSystem, d as MeshGeometrySystem, e as ModuleLoader, N as NO_XR_CAPABILITIES, O as ObjectVisibilitySystem, P as PhysicsSyncSystem, f as PostprocessingSyncSystem, S as SCRIPT_OBJECT_ROOT_FLAG, g as ScriptBehaviourSystem, h as ScriptObjectSystem, i as SelectionContext, V as VRTeleportAreaSystem, j as VideoSystem, k as XRAnchorSystem, l as XRControllerVisualSystem, m as XREnvironmentSystem, n as XRHandPoseSystem, o as XRHitTestSystem, p as XRHoverVisualSystem, q as XRInputSystem, r as XRInteractionSystem, s as XRLocomotionSystem, t as XRSessionSystem, u as XRTeleportVisualSystem, v as XR_HOVER_SHELL_FLAG, w as XrHandedness, x as XrHitResult, y as XrInputKind, z as readXrCapabilities } from './index-BphKHaV-.js';
8
8
  export { i as CoreComponents } from './index-CuGqxuk-.js';
9
9
  export { createAnimationComponent, createAudioComponent, createCameraComponent, createEntityTypeComponent, createEnvironmentComponent, createImageComponent, createImageTargetAnchorComponent, createImageTargetComponent, createInstanceSlotComponent, createInstancedMeshComponent, createLightComponent, createMaterialComponent, createMeshComponent, createMeshGeometryComponent, createModelComponent, createNameComponent, createObject3DRefComponent, createParentIdComponent, createPhysicsComponent, createPostprocessingComponent, createScriptComponent, createScriptObjectComponent, createSelectableComponent, createSelectionTransformStateComponent, createSpriteComponent, createTransformComponent, createVRTeleportAreaComponent, createVideoComponent, createXRAnchorComponent, createXRHandPoseComponent, createXRInteractableComponent, createXRInteractorComponent, createXRInteractorSideComponent, createXRRigComponent, registerDefaultComponentFactories, registerDefaultFactories } from './factories/index.js';
10
10
  import { GLTF } from 'three/examples/jsm/loaders/GLTFLoader.js';
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { MeshGeometrySystem, InstancedMeshSystem, EnvironmentSyncSystem, PostprocessingSyncSystem, LightSyncSystem, MaterialSyncSystem, VRTeleportAreaSystem, PhysicsSyncSystem, AnimationSystem, AudioSystem, VideoSystem, CameraSyncSystem, TransformSyncSystem, ObjectVisibilitySystem, RenderSystem, spawnPrefab, despawnPrefab, buildNodeKeyMapsFromSnapshot, indexSnapshotByEntity, findTopLevelNestedRegions, collectSnapshotSubtreeIds, groupOverridePaths, OVERRIDE_DIFF_EXCLUDED_COMPONENTS, OVERRIDE_ROOT_EXCLUDED_COMPONENTS, canonicalizeComponentValue, mergeComponentValue, decanonicalizeComponentValue, computeInstanceOverrides, collectEntitySubtree, ADDED_NODE_MARKER_COMPONENT } from './chunk-6UZC6M7V.js';
2
- export { ADDED_NODE_MARKER_COMPONENT, ARC_GRAVITY, ARC_MAX_TIME, ARC_SPEED, ARC_STEPS, AnimationSystem, AudioSystem, Behaviour, CURLED_COS, CameraSyncSystem, DEFAULT_DIRECTION_TOLERANCE, DEFAULT_ENTER_CONFIDENCE, DEFAULT_EXIT_CONFIDENCE, DEFAULT_LOST_GRACE_SECONDS, DEFAULT_MIN_HOLD_SECONDS, EnvironmentSyncSystem, FALLBACK_HAND_SCALE, HYDRATABLE_ENTITY_KINDS, HandPoseTracker, InputSystem, InstancedMeshSystem, KeyboardKeys, LightSyncSystem, MATCH_FALLOFF, MAX_PLAUSIBLE_SPEED, MAX_SAMPLE_AGE_SECONDS, MaterialSyncSystem, MeshGeometrySystem, NODE_KEY_SEPARATOR, NO_XR_CAPABILITIES, OVERRIDE_DIFF_EXCLUDED_COMPONENTS, OVERRIDE_ROOT_EXCLUDED_COMPONENTS, ObjectVisibilitySystem, PINCH_FINGERS, PREFAB_FILE_VERSION, PREFAB_FILE_VERSION_NESTED, PhysicsSyncSystem, PostprocessingSyncSystem, RenderSystem, SCRIPT_OBJECT_ROOT_FLAG, STRAIGHT_COS, ScriptBehaviourSystem, ScriptObject, ScriptObjectSystem, TeleportAimGate, ThrowVelocityTracker, TransformSyncSystem, VELOCITY_SAMPLES, VRTeleportAreaSystem, VideoSystem, XRAnchorSystem, XRControllerVisualSystem, XREnvironmentSystem, XRHandPoseSystem, XRHitTestSystem, XRHoverVisualSystem, XRInputSystem, XRInteractionSystem, XRLocomotionSystem, XRSessionSystem, XRTeleportVisualSystem, XR_FINGERS, XR_HOVER_SHELL_FLAG, angularVelocityFrom, applyHandMaterial, arcGroundCrossing, buildComponentValueMaps, buildNodeKeyMapsFromSnapshot, buildNodeMapsFromSnapshot, canonicalizeComponentValue, clearPrefabCache, collectDiffPaths, collectEntitySubtree, collectSnapshotSubtreeIds, computeFingerCurl, computeHandShape, computeInstanceOverrides, computePalmPose, computePalmWidth, computePinch, computeSpread, createHandMaterial, decanonicalizeComponentValue, despawnPrefab, encodeOverride, estimateHandScale, findSnapshotRootEntityIds, findTopLevelNestedRegions, groupOverridePaths, hydrateWorldFromSnapshot, hydrateWorldFromSnapshotDetailed, indexSnapshotByEntity, instantiateSubtree, loadPrefab, matchHandPose, mergeComponentValue, parseOverride, parsePrefabAsset, prefabFileVersionFor, readXrCapabilities, restoreComponentState, restorePostCreateComponents, sampleTeleportArc, setPrefabAssetUrlResolver, spawnPrefab } from './chunk-6UZC6M7V.js';
1
+ import { MeshGeometrySystem, InstancedMeshSystem, EnvironmentSyncSystem, PostprocessingSyncSystem, LightSyncSystem, MaterialSyncSystem, VRTeleportAreaSystem, PhysicsSyncSystem, AnimationSystem, AudioSystem, VideoSystem, CameraSyncSystem, TransformSyncSystem, ObjectVisibilitySystem, RenderSystem, spawnPrefab, despawnPrefab, buildNodeKeyMapsFromSnapshot, indexSnapshotByEntity, findTopLevelNestedRegions, collectSnapshotSubtreeIds, groupOverridePaths, OVERRIDE_DIFF_EXCLUDED_COMPONENTS, OVERRIDE_ROOT_EXCLUDED_COMPONENTS, canonicalizeComponentValue, mergeComponentValue, decanonicalizeComponentValue, computeInstanceOverrides, collectEntitySubtree, ADDED_NODE_MARKER_COMPONENT } from './chunk-QIIWFP3V.js';
2
+ export { ADDED_NODE_MARKER_COMPONENT, ARC_GRAVITY, ARC_MAX_TIME, ARC_SPEED, ARC_STEPS, AnimationSystem, AudioSystem, Behaviour, CURLED_COS, CameraSyncSystem, DEFAULT_DIRECTION_TOLERANCE, DEFAULT_ENTER_CONFIDENCE, DEFAULT_EXIT_CONFIDENCE, DEFAULT_LOST_GRACE_SECONDS, DEFAULT_MIN_HOLD_SECONDS, EnvironmentSyncSystem, FALLBACK_HAND_SCALE, HYDRATABLE_ENTITY_KINDS, HandPoseTracker, InputSystem, InstancedMeshSystem, KeyboardKeys, LightSyncSystem, MATCH_FALLOFF, MAX_PLAUSIBLE_SPEED, MAX_SAMPLE_AGE_SECONDS, MaterialSyncSystem, MeshGeometrySystem, NODE_KEY_SEPARATOR, NO_XR_CAPABILITIES, OVERRIDE_DIFF_EXCLUDED_COMPONENTS, OVERRIDE_ROOT_EXCLUDED_COMPONENTS, ObjectVisibilitySystem, PINCH_FINGERS, PREFAB_FILE_VERSION, PREFAB_FILE_VERSION_NESTED, PhysicsSyncSystem, PostprocessingSyncSystem, RenderSystem, SCRIPT_OBJECT_ROOT_FLAG, STRAIGHT_COS, ScriptBehaviourSystem, ScriptObject, ScriptObjectSystem, TeleportAimGate, ThrowVelocityTracker, TransformSyncSystem, VELOCITY_SAMPLES, VRTeleportAreaSystem, VideoSystem, XRAnchorSystem, XRControllerVisualSystem, XREnvironmentSystem, XRHandPoseSystem, XRHitTestSystem, XRHoverVisualSystem, XRInputSystem, XRInteractionSystem, XRLocomotionSystem, XRSessionSystem, XRTeleportVisualSystem, XR_FINGERS, XR_HOVER_SHELL_FLAG, angularVelocityFrom, applyHandMaterial, arcGroundCrossing, buildComponentValueMaps, buildNodeKeyMapsFromSnapshot, buildNodeMapsFromSnapshot, canonicalizeComponentValue, clearPrefabCache, collectDiffPaths, collectEntitySubtree, collectSnapshotSubtreeIds, computeFingerCurl, computeHandShape, computeInstanceOverrides, computePalmPose, computePalmWidth, computePinch, computeSpread, createHandMaterial, decanonicalizeComponentValue, despawnPrefab, encodeOverride, estimateHandScale, findSnapshotRootEntityIds, findTopLevelNestedRegions, groupOverridePaths, hydrateWorldFromSnapshot, hydrateWorldFromSnapshotDetailed, indexSnapshotByEntity, instantiateSubtree, loadPrefab, matchHandPose, mergeComponentValue, parseOverride, parsePrefabAsset, prefabFileVersionFor, readXrCapabilities, restoreComponentState, restorePostCreateComponents, sampleTeleportArc, setPrefabAssetUrlResolver, spawnPrefab } from './chunk-QIIWFP3V.js';
3
3
  import { registerDefaultFactories } from './chunk-SGADE55G.js';
4
4
  export { createAnimationComponent, createAudioComponent, createCameraComponent, createEntityTypeComponent, createEnvironmentComponent, createImageComponent, createImageTargetAnchorComponent, createImageTargetComponent, createInstanceSlotComponent, createInstancedMeshComponent, createLightComponent, createMaterialComponent, createMeshComponent, createMeshGeometryComponent, createModelComponent, createNameComponent, createObject3DRefComponent, createParentIdComponent, createPhysicsComponent, createPostprocessingComponent, createScriptComponent, createScriptObjectComponent, createSelectableComponent, createSelectionTransformStateComponent, createSpriteComponent, createTransformComponent, createVRTeleportAreaComponent, createVideoComponent, createXRAnchorComponent, createXRHandPoseComponent, createXRInteractableComponent, createXRInteractorComponent, createXRInteractorSideComponent, createXRRigComponent, registerDefaultComponentFactories, registerDefaultFactories } from './chunk-SGADE55G.js';
5
5
  import { ObjectManagementSystem } from './chunk-4DWZK4X4.js';
@@ -9348,6 +9348,7 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
9348
9348
  const rig = world.getComponent(rigEntityId, XRRigComponent);
9349
9349
  const rigTransform = world.getComponent(rigEntityId, TransformComponent);
9350
9350
  if (!rig || !rigTransform) return;
9351
+ if (world.isXrPassthrough()) return;
9351
9352
  const inputs = this.inputSystem.getInputs();
9352
9353
  if (inputs.length === 0) return;
9353
9354
  if (rig.snapTurn) {
@@ -9594,6 +9595,8 @@ var _XRSessionSystem = class _XRSessionSystem {
9594
9595
  this.capabilities = NO_XR_CAPABILITIES;
9595
9596
  /** Y compensation applied when a floor-relative space was requested but not granted. */
9596
9597
  this.appliedOriginOffset = 0;
9598
+ /** The live session, so an async floor probe can tell if it has been replaced. */
9599
+ this.session = null;
9597
9600
  this.inputSystem = inputSystem ?? null;
9598
9601
  }
9599
9602
  update(world) {
@@ -9608,10 +9611,37 @@ var _XRSessionSystem = class _XRSessionSystem {
9608
9611
  }
9609
9612
  if (presenting) {
9610
9613
  this.dispatchInputEdges(world);
9614
+ this.muteDepthOcclusionColor(world);
9615
+ }
9616
+ }
9617
+ /**
9618
+ * Stop three's depth-occlusion pass from writing COLOR.
9619
+ *
9620
+ * With depth sensing granted, three draws a full-screen, head-locked mesh
9621
+ * every frame whose fragment shader assigns ONLY `gl_FragDepth` — that is
9622
+ * the whole occlusion mechanism — but its material never sets
9623
+ * `colorWrite: false`, so the colour output is UNDEFINED per GLSL. Desktop
9624
+ * drivers happen to zero it, which is why this ships unnoticed; Quest's
9625
+ * mobile GPU frequently leaves the last-computed temporary in the register —
9626
+ * the sampled DEPTH value — so the pass paints the depth camera's view over
9627
+ * the screen as faint head-locked contour bands. On device that reads as "a
9628
+ * large wireframe dome that follows my head".
9629
+ *
9630
+ * The mesh is created lazily inside three's render, so this is re-checked
9631
+ * every frame rather than hooked once; the write is idempotent and the
9632
+ * check is two property reads. Depth-only is the mesh's entire purpose —
9633
+ * occlusion is unaffected.
9634
+ */
9635
+ muteDepthOcclusionColor(world) {
9636
+ const xr = world.getRenderer().xr;
9637
+ const material = xr.getDepthSensingMesh?.()?.material;
9638
+ if (material && material.colorWrite !== false) {
9639
+ material.colorWrite = false;
9611
9640
  }
9612
9641
  }
9613
9642
  handleSessionStart(world) {
9614
9643
  const session = world.getRenderer().xr.getSession();
9644
+ this.session = session ?? null;
9615
9645
  const mode = session && session.environmentBlendMode !== "opaque" ? "immersive-ar" : "immersive-vr";
9616
9646
  this.capabilities = readXrCapabilities(session ?? null, mode);
9617
9647
  if (session && this.inputSystem) {
@@ -9650,16 +9680,16 @@ var _XRSessionSystem = class _XRSessionSystem {
9650
9680
  renderer.xr.setReferenceSpaceType(wantsFloor ? "local-floor" : "local");
9651
9681
  } catch {
9652
9682
  }
9653
- const granted = session?.enabledFeatures;
9654
- const floorGranted = Array.isArray(granted) ? granted.includes("local-floor") : (
9655
- // No report at all: trust the request, since a wrong offset is worse
9656
- // than none on devices that did honour it.
9657
- true
9658
- );
9659
- this.appliedOriginOffset = wantsFloor && !floorGranted ? rig.fallbackEyeHeight : 0;
9660
- if (this.appliedOriginOffset !== 0) {
9683
+ this.appliedOriginOffset = 0;
9684
+ if (!wantsFloor || !session) return;
9685
+ const sessionAtRequest = session;
9686
+ session.requestReferenceSpace("local-floor").then(() => {
9687
+ }).catch(() => {
9688
+ if (this.session !== sessionAtRequest) return;
9689
+ if (this.appliedOriginOffset !== 0) return;
9690
+ this.appliedOriginOffset = rig.fallbackEyeHeight;
9661
9691
  transform.position.y -= this.appliedOriginOffset;
9662
- }
9692
+ });
9663
9693
  }
9664
9694
  handleSessionEnd(world) {
9665
9695
  if (this.appliedOriginOffset !== 0) {
@@ -9670,6 +9700,7 @@ var _XRSessionSystem = class _XRSessionSystem {
9670
9700
  }
9671
9701
  this.appliedOriginOffset = 0;
9672
9702
  }
9703
+ this.session = null;
9673
9704
  this.capabilities = NO_XR_CAPABILITIES;
9674
9705
  this.inputSystem?.detachSession();
9675
9706
  this.forEachBehaviour(world, (behaviour) => {
@@ -9759,8 +9790,12 @@ function planeColliderFromPolygon(polygon) {
9759
9790
  __name(planeColliderFromPolygon, "planeColliderFromPolygon");
9760
9791
  function writeXrMeshGeometry(vertices, indices, existing) {
9761
9792
  const geometry = existing ?? new THREE26__namespace.BufferGeometry();
9762
- geometry.setAttribute("position", new THREE26__namespace.BufferAttribute(vertices, 3));
9763
- geometry.setIndex(new THREE26__namespace.BufferAttribute(indices, 1));
9793
+ geometry.setAttribute(
9794
+ "position",
9795
+ new THREE26__namespace.BufferAttribute(vertices.slice(), 3)
9796
+ );
9797
+ geometry.setIndex(new THREE26__namespace.BufferAttribute(indices.slice(), 1));
9798
+ geometry.deleteAttribute("normal");
9764
9799
  geometry.computeBoundingSphere();
9765
9800
  geometry.computeVertexNormals();
9766
9801
  return geometry;
@@ -9786,6 +9821,42 @@ __name(decomposeXrPose, "decomposeXrPose");
9786
9821
 
9787
9822
  // core/systems/XREnvironmentSystem.ts
9788
9823
  var DEBUG_COLOR = 5088255;
9824
+ function debugColorFor(kind, semanticLabel) {
9825
+ switch (semanticLabel) {
9826
+ case "floor":
9827
+ return 5100666;
9828
+ // green — the surface everything should rest on
9829
+ case "ceiling":
9830
+ return 11693055;
9831
+ // purple
9832
+ case "wall":
9833
+ case "wall face":
9834
+ return DEBUG_COLOR;
9835
+ // blue, the family's base colour
9836
+ case "global mesh":
9837
+ return 9079442;
9838
+ // dim gray — raw scan, not an object
9839
+ default:
9840
+ return semanticLabel ? 16747594 : DEBUG_COLOR;
9841
+ }
9842
+ }
9843
+ __name(debugColorFor, "debugColorFor");
9844
+ var GLOBAL_MESH_DEBUG_OPACITY = 0.35;
9845
+ var DEBUG_RENDER_ORDER = 900;
9846
+ var ROOM_CAPTURE_DELAY_SECONDS = 3;
9847
+ var SYNTHETIC_FLOOR_EXTENT = 50;
9848
+ var SYNTHETIC_FLOOR_PLANE = {
9849
+ planeSpace: {},
9850
+ polygon: [
9851
+ { x: -SYNTHETIC_FLOOR_EXTENT / 2, y: 0, z: -SYNTHETIC_FLOOR_EXTENT / 2 },
9852
+ { x: SYNTHETIC_FLOOR_EXTENT / 2, y: 0, z: -SYNTHETIC_FLOOR_EXTENT / 2 },
9853
+ { x: SYNTHETIC_FLOOR_EXTENT / 2, y: 0, z: SYNTHETIC_FLOOR_EXTENT / 2 },
9854
+ { x: -SYNTHETIC_FLOOR_EXTENT / 2, y: 0, z: SYNTHETIC_FLOOR_EXTENT / 2 }
9855
+ ],
9856
+ orientation: "horizontal",
9857
+ semanticLabel: "floor",
9858
+ lastChangedTime: 0
9859
+ };
9789
9860
  var _XREnvironmentSystem = class _XREnvironmentSystem {
9790
9861
  constructor() {
9791
9862
  /** Keyed by the XRPlane/XRMesh object itself — the runtime's own identity. */
@@ -9793,17 +9864,24 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
9793
9864
  this.meshes = /* @__PURE__ */ new Map();
9794
9865
  this.presenting = false;
9795
9866
  this.debugVisible = false;
9867
+ /** Seconds presenting, used to decide the room has genuinely nothing in it. */
9868
+ this.elapsed = 0;
9869
+ /** `initiateRoomCapture` may be called only ONCE per session. */
9870
+ this.roomCaptureRequested = false;
9796
9871
  }
9797
- update(world) {
9872
+ update(world, deltaTime = 0) {
9798
9873
  const presenting = world.isXrPresenting();
9799
9874
  if (!presenting) {
9800
9875
  if (this.presenting) {
9801
9876
  this.presenting = false;
9877
+ this.elapsed = 0;
9878
+ this.roomCaptureRequested = false;
9802
9879
  this.clearAll(world);
9803
9880
  }
9804
9881
  return;
9805
9882
  }
9806
9883
  this.presenting = true;
9884
+ this.elapsed += deltaTime;
9807
9885
  const rig = this.findRig(world);
9808
9886
  const mode = rig?.environmentPhysics ?? "none";
9809
9887
  if (mode === "none") {
@@ -9819,6 +9897,11 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
9819
9897
  const frame = xr.getFrame?.();
9820
9898
  const referenceSpace = xr.getReferenceSpace();
9821
9899
  if (!frame || !referenceSpace) return;
9900
+ if (frame.detectedPlanes === void 0 && frame.detectedMeshes === void 0) {
9901
+ this.ensureSyntheticFloor(world);
9902
+ return;
9903
+ }
9904
+ this.removeSyntheticFloor(world);
9822
9905
  const meshesAvailable = Boolean(frame.detectedMeshes);
9823
9906
  const useMesh = (mode === "mesh" || mode === "auto") && meshesAvailable;
9824
9907
  const usePlanes = mode === "planes" || mode === "auto" && !useMesh;
@@ -9832,11 +9915,84 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
9832
9915
  } else if (this.meshes.size > 0) {
9833
9916
  this.clearMap(world, this.meshes);
9834
9917
  }
9918
+ this.maybeCaptureRoom(world, frame);
9919
+ }
9920
+ /**
9921
+ * Ask the runtime to scan the room when it turns out we have no room.
9922
+ *
9923
+ * Plane and mesh detection do NOT scan anything — they replay a scan the user
9924
+ * captured earlier through the system's own room setup. Most people have
9925
+ * never run it, and those who have may have run it in a DIFFERENT room, so a
9926
+ * mixed-reality experience opens against either nothing at all or someone
9927
+ * else's furniture, with no prompt and no error.
9928
+ *
9929
+ * `XRSession.initiateRoomCapture()` (Meta's extension) launches that setup
9930
+ * from inside the session, and exists precisely for this case. Contract, from
9931
+ * Meta's docs: callable ONCE per session, and only worth calling once we are
9932
+ * confident the room really is empty — the arrays populate a beat after the
9933
+ * session starts, so a check on frame one would fire for everyone.
9934
+ */
9935
+ maybeCaptureRoom(world, frame) {
9936
+ if (this.roomCaptureRequested) return;
9937
+ if (this.elapsed < ROOM_CAPTURE_DELAY_SECONDS) return;
9938
+ if (this.planes.size > 0 || this.meshes.size > 0) return;
9939
+ if ((frame.detectedPlanes?.size ?? 0) > 0) return;
9940
+ if ((frame.detectedMeshes?.size ?? 0) > 0) return;
9941
+ const session = world.getRenderer().xr.getSession?.();
9942
+ if (typeof session?.initiateRoomCapture !== "function") return;
9943
+ this.roomCaptureRequested = true;
9944
+ session.initiateRoomCapture()?.catch(() => {
9945
+ });
9835
9946
  }
9836
9947
  /** How many pieces of real geometry are currently colliding. Script-facing. */
9837
9948
  getDetectedCount() {
9838
9949
  return { planes: this.planes.size, meshes: this.meshes.size };
9839
9950
  }
9951
+ /**
9952
+ * A census of every surface currently spawned: what it is, where it sits and
9953
+ * roughly how big it is. Built for the template's post-session readout, so a
9954
+ * mystery shape on the headset can be looked up by its label instead of
9955
+ * guessed at — a small-radius entry at head height IS the mystery shape, and
9956
+ * a clean list means whatever was seen did not come from this system.
9957
+ */
9958
+ getDebugSnapshot(world) {
9959
+ const snapshot = [];
9960
+ for (const [plane, entry] of this.planes) {
9961
+ const transform = world.getComponent(entry.entityId, TransformComponent);
9962
+ const collider = planeColliderFromPolygon(plane.polygon);
9963
+ snapshot.push({
9964
+ kind: "plane",
9965
+ label: plane.semanticLabel ?? null,
9966
+ position: transform ? { ...transform.position } : { x: 0, y: 0, z: 0 },
9967
+ radius: collider ? Math.hypot(collider.size.x, collider.size.z) / 2 : 0,
9968
+ emulated: entry.emulated
9969
+ });
9970
+ }
9971
+ for (const [mesh, entry] of this.meshes) {
9972
+ const transform = world.getComponent(entry.entityId, TransformComponent);
9973
+ snapshot.push({
9974
+ kind: "mesh",
9975
+ label: mesh.semanticLabel ?? null,
9976
+ position: transform ? { ...transform.position } : { x: 0, y: 0, z: 0 },
9977
+ radius: entry.geometry?.boundingSphere?.radius ?? 0,
9978
+ emulated: entry.emulated
9979
+ });
9980
+ }
9981
+ return snapshot;
9982
+ }
9983
+ /** Create the no-scan floor once; it lives in the ordinary plane map. */
9984
+ ensureSyntheticFloor(world) {
9985
+ if (this.planes.has(SYNTHETIC_FLOOR_PLANE)) return;
9986
+ const created = this.createPlaneEntity(world, SYNTHETIC_FLOOR_PLANE);
9987
+ if (created) this.planes.set(SYNTHETIC_FLOOR_PLANE, created);
9988
+ }
9989
+ /** Real scene data exists (or arrived) — the stand-in must go. */
9990
+ removeSyntheticFloor(world) {
9991
+ const entry = this.planes.get(SYNTHETIC_FLOOR_PLANE);
9992
+ if (!entry) return;
9993
+ this.destroyEntry(world, entry);
9994
+ this.planes.delete(SYNTHETIC_FLOOR_PLANE);
9995
+ }
9840
9996
  findRig(world) {
9841
9997
  const ids = world.query(XRRigComponent);
9842
9998
  if (ids.length === 0) return null;
@@ -9854,9 +10010,11 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
9854
10010
  for (const plane of detected) {
9855
10011
  const pose = frame.getPose(plane.planeSpace, referenceSpace);
9856
10012
  if (!pose) continue;
10013
+ const emulated = pose.emulatedPosition === true;
9857
10014
  let entry = this.planes.get(plane);
9858
10015
  const changed = plane.lastChangedTime ?? 0;
9859
10016
  if (!entry) {
10017
+ if (emulated) continue;
9860
10018
  const created = this.createPlaneEntity(world, plane);
9861
10019
  if (!created) continue;
9862
10020
  entry = created;
@@ -9869,11 +10027,17 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
9869
10027
  if (collider) {
9870
10028
  entry.geometry?.dispose();
9871
10029
  entry.geometry = null;
9872
- this.attachPlaneDebug(world, entry, collider);
10030
+ this.attachPlaneDebug(
10031
+ world,
10032
+ entry,
10033
+ collider,
10034
+ plane.semanticLabel ?? null
10035
+ );
9873
10036
  }
9874
10037
  }
9875
10038
  }
9876
- this.applyPose(world, entry.entityId, pose);
10039
+ entry.emulated = emulated;
10040
+ if (!emulated) this.applyPose(world, entry.entityId, pose);
9877
10041
  }
9878
10042
  }
9879
10043
  syncMeshes(world, frame, referenceSpace) {
@@ -9888,9 +10052,11 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
9888
10052
  for (const mesh of detected) {
9889
10053
  const pose = frame.getPose(mesh.meshSpace, referenceSpace);
9890
10054
  if (!pose) continue;
10055
+ const emulated = pose.emulatedPosition === true;
9891
10056
  let entry = this.meshes.get(mesh);
9892
10057
  const changed = mesh.lastChangedTime ?? 0;
9893
10058
  if (!entry) {
10059
+ if (emulated) continue;
9894
10060
  const created = this.createMeshEntity(world, mesh);
9895
10061
  if (!created) continue;
9896
10062
  entry = created;
@@ -9899,7 +10065,8 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
9899
10065
  entry.lastChangedTime = changed;
9900
10066
  writeXrMeshGeometry(mesh.vertices, mesh.indices, entry.geometry);
9901
10067
  }
9902
- this.applyPose(world, entry.entityId, pose);
10068
+ entry.emulated = emulated;
10069
+ if (!emulated) this.applyPose(world, entry.entityId, pose);
9903
10070
  }
9904
10071
  }
9905
10072
  createPlaneEntity(world, plane) {
@@ -9919,9 +10086,12 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
9919
10086
  entityId,
9920
10087
  lastChangedTime: plane.lastChangedTime ?? 0,
9921
10088
  geometry: null,
9922
- material: null
10089
+ material: null,
10090
+ emulated: false
9923
10091
  };
9924
- if (this.debugVisible) this.attachPlaneDebug(world, entry, collider);
10092
+ if (this.debugVisible) {
10093
+ this.attachPlaneDebug(world, entry, collider, plane.semanticLabel ?? null);
10094
+ }
9925
10095
  return entry;
9926
10096
  }
9927
10097
  applyPlaneCollider(world, entityId, plane) {
@@ -9946,15 +10116,36 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
9946
10116
  createMeshEntity(world, mesh) {
9947
10117
  if (!mesh.vertices?.length || !mesh.indices?.length) return null;
9948
10118
  const geometry = writeXrMeshGeometry(mesh.vertices, mesh.indices);
10119
+ const label = mesh.semanticLabel ?? null;
10120
+ const isGlobalMesh = label === "global mesh";
9949
10121
  const material = new THREE26__namespace.MeshBasicMaterial({
9950
- color: DEBUG_COLOR,
9951
- wireframe: true
10122
+ color: debugColorFor("mesh", label),
10123
+ wireframe: true,
10124
+ // The global scan is a coarse triangle soup of the whole room; at full
10125
+ // strength it reads as phantom objects rather than as context.
10126
+ transparent: isGlobalMesh,
10127
+ opacity: isGlobalMesh ? GLOBAL_MESH_DEBUG_OPACITY : 1,
10128
+ // Depth-TESTED, deliberately. The overlay was X-ray for one release —
10129
+ // introduced on the theory that depth occlusion was carving it into a
10130
+ // head-locked dome — but that theory was falsified (the dome was the
10131
+ // depth mesh's unset colour output, plus emulated poses; both fixed).
10132
+ // X-ray had its own on-device failure: the global scan is DENSE, and a
10133
+ // dense wireframe at 0.35 opacity fuses into a translucent sheet — with
10134
+ // no depth test the walls' sheets drew through everything, stacked in
10135
+ // front of the user's eyes ("planes covering my face"). With the depth
10136
+ // buffer now holding CORRECT real-world depth, normal testing gives the
10137
+ // right picture: the near wall hides the far one. depthWrite stays off
10138
+ // so the overlay never occludes actual content.
10139
+ depthTest: true,
10140
+ depthWrite: false
9952
10141
  });
9953
10142
  const root = new THREE26__namespace.Group();
9954
10143
  const child = new THREE26__namespace.Mesh(geometry, material);
9955
10144
  child.visible = this.debugVisible;
10145
+ child.renderOrder = DEBUG_RENDER_ORDER;
9956
10146
  root.add(child);
9957
10147
  const entityId = world.createEntity();
10148
+ root.userData.entityId = entityId;
9958
10149
  world.addComponents(entityId, [
9959
10150
  new TransformComponent(),
9960
10151
  new Object3DRef(root),
@@ -9968,29 +10159,37 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
9968
10159
  entityId,
9969
10160
  lastChangedTime: mesh.lastChangedTime ?? 0,
9970
10161
  geometry,
9971
- material
10162
+ material,
10163
+ emulated: false
9972
10164
  };
9973
10165
  }
9974
10166
  /** A thin box so a detected plane can be SEEN, not just collided with. */
9975
- attachPlaneDebug(world, entry, collider) {
9976
- const geometry = new THREE26__namespace.BoxGeometry(
10167
+ attachPlaneDebug(world, entry, collider, semanticLabel) {
10168
+ const box = new THREE26__namespace.BoxGeometry(
9977
10169
  collider.size.x,
9978
10170
  collider.size.y,
9979
10171
  collider.size.z
9980
10172
  );
9981
- const material = new THREE26__namespace.MeshBasicMaterial({
9982
- color: DEBUG_COLOR,
9983
- wireframe: true
10173
+ const geometry = new THREE26__namespace.EdgesGeometry(box);
10174
+ box.dispose();
10175
+ const material = new THREE26__namespace.LineBasicMaterial({
10176
+ color: debugColorFor("plane", semanticLabel),
10177
+ // Same depth policy as the mesh overlay — see createMeshEntity.
10178
+ depthTest: true,
10179
+ depthWrite: false
9984
10180
  });
9985
10181
  const root = new THREE26__namespace.Group();
9986
- const child = new THREE26__namespace.Mesh(geometry, material);
10182
+ const child = new THREE26__namespace.LineSegments(geometry, material);
10183
+ child.renderOrder = DEBUG_RENDER_ORDER;
9987
10184
  child.position.set(collider.offset.x, collider.offset.y, collider.offset.z);
9988
10185
  child.visible = this.debugVisible;
9989
10186
  root.add(child);
9990
10187
  entry.geometry = geometry;
9991
10188
  entry.material = material;
10189
+ root.userData.entityId = entry.entityId;
9992
10190
  const existing = world.getComponent(entry.entityId, Object3DRef);
9993
10191
  if (existing) {
10192
+ existing.object.removeFromParent();
9994
10193
  existing.object = root;
9995
10194
  } else {
9996
10195
  world.addComponent(entry.entityId, new Object3DRef(root));
@@ -10006,19 +10205,31 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
10006
10205
  for (const [plane, entry] of this.planes) {
10007
10206
  if (entry.geometry) continue;
10008
10207
  const collider = planeColliderFromPolygon(plane.polygon);
10009
- if (collider) this.attachPlaneDebug(world, entry, collider);
10208
+ if (collider) {
10209
+ this.attachPlaneDebug(
10210
+ world,
10211
+ entry,
10212
+ collider,
10213
+ plane.semanticLabel ?? null
10214
+ );
10215
+ }
10010
10216
  }
10011
10217
  }
10012
10218
  for (const map of [this.planes, this.meshes]) {
10013
10219
  for (const entry of map.values()) {
10014
10220
  const ref = world.getComponent(entry.entityId, Object3DRef);
10015
10221
  ref?.object.traverse((child) => {
10016
- if (child.isMesh) child.visible = this.debugVisible;
10222
+ const drawable = child;
10223
+ if (drawable.isMesh || drawable.isLine) {
10224
+ child.visible = this.debugVisible;
10225
+ }
10017
10226
  });
10018
10227
  }
10019
10228
  }
10020
10229
  }
10021
10230
  destroyEntry(world, entry) {
10231
+ const ref = world.getComponent(entry.entityId, Object3DRef);
10232
+ ref?.object.removeFromParent();
10022
10233
  entry.geometry?.dispose();
10023
10234
  entry.material?.dispose();
10024
10235
  world.destroyEntity(entry.entityId);
@@ -10195,7 +10406,9 @@ var _XRAnchorSystem = class _XRAnchorSystem {
10195
10406
  continue;
10196
10407
  }
10197
10408
  const pose = frame.getPose(anchor.anchorSpace, referenceSpace);
10198
- if (pose) decomposeXrPose(pose.transform.matrix, transform);
10409
+ if (pose && pose.emulatedPosition !== true) {
10410
+ decomposeXrPose(pose.transform.matrix, transform);
10411
+ }
10199
10412
  }
10200
10413
  }
10201
10414
  /** Whether this entity's pose is currently being driven by an anchor. */