@relu-interactives/spatial-ecs 0.3.2 → 0.3.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.
Files changed (37) hide show
  1. package/dist/{XRRig-Cu-EyliG.d.cts → XRRig-2686IqLQ.d.cts} +5 -5
  2. package/dist/{XRRig-CAmf04NX.d.ts → XRRig-D2QURXl1.d.ts} +5 -5
  3. package/dist/{chunk-67WGASUJ.js → chunk-2LVFGVWI.js} +3 -3
  4. package/dist/{chunk-67WGASUJ.js.map → chunk-2LVFGVWI.js.map} +1 -1
  5. package/dist/{chunk-JWTRFJBL.js → chunk-4BZYK3JP.js} +4 -4
  6. package/dist/{chunk-JWTRFJBL.js.map → chunk-4BZYK3JP.js.map} +1 -1
  7. package/dist/{chunk-U3MDYKPV.js → chunk-6QC2PJLD.js} +4 -3
  8. package/dist/chunk-6QC2PJLD.js.map +1 -0
  9. package/dist/{chunk-SALBG747.js → chunk-G53MZVKQ.js} +333 -25
  10. package/dist/chunk-G53MZVKQ.js.map +1 -0
  11. package/dist/components/index.cjs +2 -1
  12. package/dist/components/index.cjs.map +1 -1
  13. package/dist/components/index.d.cts +2 -2
  14. package/dist/components/index.d.ts +2 -2
  15. package/dist/components/index.js +1 -1
  16. package/dist/factories/index.cjs +2 -1
  17. package/dist/factories/index.cjs.map +1 -1
  18. package/dist/factories/index.d.cts +1 -1
  19. package/dist/factories/index.d.ts +1 -1
  20. package/dist/factories/index.js +3 -3
  21. package/dist/{index-CRmfSYdj.d.ts → index-B-CViRMx.d.ts} +57 -10
  22. package/dist/{index-w1oqWl_M.d.ts → index-BtKOaHfY.d.ts} +1 -1
  23. package/dist/{index-Bc0YCz1A.d.cts → index-BvCmmuJ0.d.cts} +57 -10
  24. package/dist/{index-CUFd71ri.d.cts → index-Xu238jLn.d.cts} +1 -1
  25. package/dist/index.cjs +337 -21
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.cts +50 -6
  28. package/dist/index.d.ts +50 -6
  29. package/dist/index.js +8 -8
  30. package/dist/systems/index.cjs +318 -21
  31. package/dist/systems/index.cjs.map +1 -1
  32. package/dist/systems/index.d.cts +1 -1
  33. package/dist/systems/index.d.ts +1 -1
  34. package/dist/systems/index.js +3 -3
  35. package/package.json +1 -1
  36. package/dist/chunk-SALBG747.js.map +0 -1
  37. package/dist/chunk-U3MDYKPV.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -2593,7 +2593,8 @@ var _VRTeleportAreaComponent = class _VRTeleportAreaComponent extends Component
2593
2593
  constructor(options) {
2594
2594
  super();
2595
2595
  this.enabled = options?.enabled ?? true;
2596
- this.shape = options?.shape ?? "plane";
2596
+ const shape = options?.shape;
2597
+ this.shape = shape === "cylinder" ? "circle" : options?.shape ?? "plane";
2597
2598
  this.width = options?.width ?? 10;
2598
2599
  this.depth = options?.depth ?? 10;
2599
2600
  }
@@ -4340,6 +4341,15 @@ function buildComponentValueMaps(snapshot) {
4340
4341
  snapshot.components,
4341
4342
  "ScriptObjectComponent"
4342
4343
  ),
4344
+ xrRigValues: readByComponent(snapshot.components, "XRRigComponent"),
4345
+ vrTeleportAreaValues: readByComponent(
4346
+ snapshot.components,
4347
+ "VRTeleportAreaComponent"
4348
+ ),
4349
+ xrInteractableValues: readByComponent(
4350
+ snapshot.components,
4351
+ "XRInteractableComponent"
4352
+ ),
4343
4353
  instancedMeshValues: readByComponent(snapshot.components, "InstancedMeshComponent"),
4344
4354
  instanceSlotValues: readByComponent(snapshot.components, "InstanceSlotComponent"),
4345
4355
  prefabNodeValues: readByComponent(snapshot.components, "PrefabNode"),
@@ -4465,6 +4475,67 @@ function restorePostCreateComponents(world, objectManagementSystem, targetEntity
4465
4475
  soc.data = remapEntityRefsInScriptData(data, idMap);
4466
4476
  }
4467
4477
  }
4478
+ {
4479
+ const sourceXrRig = asRecord3(values.xrRigValues.get(sourceEntityId));
4480
+ const rig = world.getComponent(targetEntityId, XRRigComponent);
4481
+ if (sourceXrRig && rig) {
4482
+ if (typeof sourceXrRig.locomotion === "string") {
4483
+ rig.locomotion = sourceXrRig.locomotion;
4484
+ }
4485
+ if (typeof sourceXrRig.moveSpeed === "number") {
4486
+ rig.moveSpeed = sourceXrRig.moveSpeed;
4487
+ }
4488
+ if (typeof sourceXrRig.snapTurn === "boolean") {
4489
+ rig.snapTurn = sourceXrRig.snapTurn;
4490
+ }
4491
+ if (typeof sourceXrRig.snapTurnDegrees === "number") {
4492
+ rig.snapTurnDegrees = sourceXrRig.snapTurnDegrees;
4493
+ }
4494
+ if (typeof sourceXrRig.fallbackEyeHeight === "number") {
4495
+ rig.fallbackEyeHeight = sourceXrRig.fallbackEyeHeight;
4496
+ }
4497
+ }
4498
+ }
4499
+ {
4500
+ const sourceArea = asRecord3(values.vrTeleportAreaValues.get(sourceEntityId));
4501
+ const area = world.getComponent(targetEntityId, VRTeleportAreaComponent);
4502
+ if (sourceArea && area) {
4503
+ if (typeof sourceArea.enabled === "boolean") {
4504
+ area.enabled = sourceArea.enabled;
4505
+ }
4506
+ if (typeof sourceArea.shape === "string") {
4507
+ area.shape = sourceArea.shape === "cylinder" ? "circle" : sourceArea.shape;
4508
+ }
4509
+ if (typeof sourceArea.width === "number") area.width = sourceArea.width;
4510
+ if (typeof sourceArea.depth === "number") area.depth = sourceArea.depth;
4511
+ }
4512
+ }
4513
+ {
4514
+ const sourceInteractable = asRecord3(
4515
+ values.xrInteractableValues.get(sourceEntityId)
4516
+ );
4517
+ const interactable = world.getComponent(
4518
+ targetEntityId,
4519
+ XRInteractableComponent
4520
+ );
4521
+ if (sourceInteractable && interactable) {
4522
+ if (typeof sourceInteractable.enabled === "boolean") {
4523
+ interactable.enabled = sourceInteractable.enabled;
4524
+ }
4525
+ if (typeof sourceInteractable.grabbable === "boolean") {
4526
+ interactable.grabbable = sourceInteractable.grabbable;
4527
+ }
4528
+ if (typeof sourceInteractable.pointable === "boolean") {
4529
+ interactable.pointable = sourceInteractable.pointable;
4530
+ }
4531
+ if (typeof sourceInteractable.grabMode === "string") {
4532
+ interactable.grabMode = sourceInteractable.grabMode;
4533
+ }
4534
+ if (typeof sourceInteractable.highlightOnHover === "boolean") {
4535
+ interactable.highlightOnHover = sourceInteractable.highlightOnHover;
4536
+ }
4537
+ }
4538
+ }
4468
4539
  {
4469
4540
  const imComponent = world.getComponent(targetEntityId, InstancedMeshComponent);
4470
4541
  if (imComponent && imComponent.instanceEntityIds.length > 0) {
@@ -10436,6 +10507,45 @@ var _XRInteractionSystem = class _XRInteractionSystem {
10436
10507
  };
10437
10508
  __name(_XRInteractionSystem, "XRInteractionSystem");
10438
10509
  var XRInteractionSystem = _XRInteractionSystem;
10510
+ var ARC_GRAVITY = 9.8;
10511
+ var ARC_SPEED = 7;
10512
+ var ARC_STEPS = 24;
10513
+ var ARC_MAX_TIME = 2;
10514
+ function sampleTeleportArc(origin, direction, out = [], options) {
10515
+ const speed = options?.speed ?? ARC_SPEED;
10516
+ const gravity = options?.gravity ?? ARC_GRAVITY;
10517
+ const steps = Math.max(2, options?.steps ?? ARC_STEPS);
10518
+ const maxTime = options?.maxTime ?? ARC_MAX_TIME;
10519
+ out.length = 0;
10520
+ const velocity = direction.clone().normalize().multiplyScalar(speed);
10521
+ for (let i = 0; i < steps; i += 1) {
10522
+ const t = i / (steps - 1) * maxTime;
10523
+ out.push(
10524
+ new THREE38__namespace.Vector3(
10525
+ origin.x + velocity.x * t,
10526
+ origin.y + velocity.y * t - 0.5 * gravity * t * t,
10527
+ origin.z + velocity.z * t
10528
+ )
10529
+ );
10530
+ }
10531
+ return out;
10532
+ }
10533
+ __name(sampleTeleportArc, "sampleTeleportArc");
10534
+ function arcGroundCrossing(points, groundY) {
10535
+ for (let i = 1; i < points.length; i += 1) {
10536
+ const previous = points[i - 1];
10537
+ const current = points[i];
10538
+ if (previous.y >= groundY && current.y <= groundY) {
10539
+ const span = previous.y - current.y;
10540
+ const alpha = span > 1e-6 ? (previous.y - groundY) / span : 0;
10541
+ return new THREE38__namespace.Vector3().lerpVectors(previous, current, alpha);
10542
+ }
10543
+ }
10544
+ return null;
10545
+ }
10546
+ __name(arcGroundCrossing, "arcGroundCrossing");
10547
+
10548
+ // core/systems/XRLocomotionSystem.ts
10439
10549
  var UP = new THREE38__namespace.Vector3(0, 1, 0);
10440
10550
  var AXIS_DEADZONE = 0.5;
10441
10551
  var _XRLocomotionSystem = class _XRLocomotionSystem {
@@ -10443,13 +10553,26 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
10443
10553
  this.raycaster = new THREE38__namespace.Raycaster();
10444
10554
  /** Per-source latch so one stick push yields exactly one snap turn. */
10445
10555
  this.turnLatched = /* @__PURE__ */ new WeakSet();
10446
- /** Where the pointer currently lands, for the consumer to draw a marker. */
10447
- this.teleportPoint = null;
10556
+ /** Reused arc buffer — aiming runs every frame. */
10557
+ this.arcPoints = [];
10558
+ /** Curve up to the landing point, for the visual system. Empty when not aiming. */
10559
+ this.aimCurve = [];
10560
+ this.landingPoint = null;
10561
+ /** True once we've tried to self-heal camera parenting for this session. */
10562
+ this.parentingChecked = false;
10448
10563
  this.inputSystem = inputSystem;
10449
10564
  }
10450
10565
  update(world, deltaTime) {
10451
- this.teleportPoint = null;
10452
- if (!world.isXrPresenting()) return;
10566
+ this.aimCurve = [];
10567
+ this.landingPoint = null;
10568
+ if (!world.isXrPresenting()) {
10569
+ this.parentingChecked = false;
10570
+ return;
10571
+ }
10572
+ if (!this.parentingChecked) {
10573
+ this.parentingChecked = true;
10574
+ this.ensureCameraUnderRig(world);
10575
+ }
10453
10576
  const rigEntityId = world.query(XRRigComponent, TransformComponent)[0];
10454
10577
  if (typeof rigEntityId !== "number") return;
10455
10578
  const rig = world.getComponent(rigEntityId, XRRigComponent);
@@ -10466,9 +10589,37 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
10466
10589
  this.applySmoothMove(world, rig, rigTransform, inputs, deltaTime);
10467
10590
  }
10468
10591
  }
10592
+ /**
10593
+ * Guarantee the render camera is a CHILD of the rig.
10594
+ *
10595
+ * Locomotion moves the rig, and three composes the head pose against
10596
+ * `camera.parent` — so if the camera sits at the scene root instead, moving
10597
+ * the rig does nothing at all and the player is frozen in place. Scenes
10598
+ * authored before the rig existed (or with the camera re-parented by hand)
10599
+ * would otherwise silently fail to move, which is exactly the symptom that is
10600
+ * hardest to diagnose from inside a headset. Repairing it via `ParentId` lets
10601
+ * `ObjectManagementSystem` reconcile the scene graph normally.
10602
+ */
10603
+ ensureCameraUnderRig(world) {
10604
+ const rigEntityId = world.query(XRRigComponent)[0];
10605
+ if (typeof rigEntityId !== "number") return;
10606
+ const activeCamera = world.getCamera();
10607
+ for (const entityId of world.query(CameraComponent, Object3DRef)) {
10608
+ if (world.getComponent(entityId, Object3DRef)?.object !== activeCamera) {
10609
+ continue;
10610
+ }
10611
+ const parent = world.getComponent(entityId, ParentId);
10612
+ if (parent) {
10613
+ if (parent.value !== rigEntityId) parent.value = rigEntityId;
10614
+ } else {
10615
+ world.addComponent(entityId, new ParentId(rigEntityId));
10616
+ }
10617
+ return;
10618
+ }
10619
+ }
10469
10620
  /**
10470
10621
  * Snap turning, not smooth turning — rotating the view continuously is the
10471
- * single biggest cause of VR nausea, so the comfort-safe option is the one
10622
+ * single biggest cause of VR nausea, so the comfort-safe option is what's
10472
10623
  * wired to the stick.
10473
10624
  */
10474
10625
  applySnapTurn(rig, transform, inputs) {
@@ -10482,8 +10633,7 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
10482
10633
  }
10483
10634
  if (this.turnLatched.has(source)) continue;
10484
10635
  this.turnLatched.add(source);
10485
- const step = THREE38__namespace.MathUtils.degToRad(rig.snapTurnDegrees);
10486
- transform.rotation.y -= Math.sign(x) * step;
10636
+ transform.rotation.y -= Math.sign(x) * THREE38__namespace.MathUtils.degToRad(rig.snapTurnDegrees);
10487
10637
  }
10488
10638
  }
10489
10639
  applySmoothMove(world, rig, transform, inputs, deltaTime) {
@@ -10508,17 +10658,42 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
10508
10658
  const targets = this.collectTeleportTargets(world);
10509
10659
  if (targets.length === 0) return;
10510
10660
  for (const input of inputs) {
10511
- this.raycaster.set(input.rayOrigin, input.rayDirection);
10512
- const hit = this.raycaster.intersectObjects(targets, true)[0];
10661
+ if (!input.select && !input.selectEnd) continue;
10662
+ const points = sampleTeleportArc(
10663
+ input.rayOrigin,
10664
+ input.rayDirection,
10665
+ this.arcPoints
10666
+ );
10667
+ const hit = this.raycastArc(points, targets);
10513
10668
  if (!hit) continue;
10514
- this.teleportPoint = hit.point.clone();
10669
+ this.landingPoint = hit.point;
10670
+ this.aimCurve = points.slice(0, hit.segmentIndex + 1).concat(hit.point);
10515
10671
  if (input.selectEnd) {
10516
10672
  transform.position.x = hit.point.x;
10517
10673
  transform.position.y = hit.point.y;
10518
10674
  transform.position.z = hit.point.z;
10675
+ this.aimCurve = [];
10676
+ this.landingPoint = null;
10519
10677
  }
10520
10678
  }
10521
10679
  }
10680
+ /** Walk the arc segment-by-segment, returning the first surface hit. */
10681
+ raycastArc(points, targets) {
10682
+ for (let i = 1; i < points.length; i += 1) {
10683
+ const from = points[i - 1];
10684
+ const to = points[i];
10685
+ const delta = new THREE38__namespace.Vector3().subVectors(to, from);
10686
+ const distance = delta.length();
10687
+ if (distance < 1e-6) continue;
10688
+ this.raycaster.set(from, delta.divideScalar(distance));
10689
+ this.raycaster.far = distance;
10690
+ const hit = this.raycaster.intersectObjects(targets, true)[0];
10691
+ if (hit) {
10692
+ return { point: hit.point.clone(), segmentIndex: i - 1 };
10693
+ }
10694
+ }
10695
+ return null;
10696
+ }
10522
10697
  collectTeleportTargets(world) {
10523
10698
  const objects = [];
10524
10699
  for (const entityId of world.query(VRTeleportAreaComponent, Object3DRef)) {
@@ -10530,12 +10705,13 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
10530
10705
  }
10531
10706
  return objects;
10532
10707
  }
10533
- /**
10534
- * Where the teleport pointer currently lands this frame, or null.
10535
- * Consumers use this to render an aim marker.
10536
- */
10537
- getTeleportPoint() {
10538
- return this.teleportPoint;
10708
+ /** Arc points up to the landing spot this frame; empty when not aiming. */
10709
+ getAimCurve() {
10710
+ return this.aimCurve;
10711
+ }
10712
+ /** Where the arc currently lands, or null when not aiming at a valid area. */
10713
+ getLandingPoint() {
10714
+ return this.landingPoint;
10539
10715
  }
10540
10716
  };
10541
10717
  __name(_XRLocomotionSystem, "XRLocomotionSystem");
@@ -10658,7 +10834,7 @@ var _XRSessionSystem = class _XRSessionSystem {
10658
10834
  __name(_XRSessionSystem, "XRSessionSystem");
10659
10835
  var XRSessionSystem = _XRSessionSystem;
10660
10836
  function buildGeometry2(area) {
10661
- if (area.shape === "cylinder") {
10837
+ if (area.shape === "circle") {
10662
10838
  const radius = Math.max(5e-3, area.width / 2);
10663
10839
  return new THREE38__namespace.CircleGeometry(radius, 48);
10664
10840
  }
@@ -10697,7 +10873,7 @@ var _VRTeleportAreaSystem = class _VRTeleportAreaSystem {
10697
10873
  __name(_VRTeleportAreaSystem, "VRTeleportAreaSystem");
10698
10874
  var VRTeleportAreaSystem = _VRTeleportAreaSystem;
10699
10875
  var _XRControllerVisualSystem = class _XRControllerVisualSystem {
10700
- constructor(slots = 2) {
10876
+ constructor(options) {
10701
10877
  this.controllerModelFactory = new XRControllerModelFactory_js.XRControllerModelFactory();
10702
10878
  this.handModelFactory = new XRHandModelFactory_js.XRHandModelFactory();
10703
10879
  this.group = new THREE38__namespace.Group();
@@ -10705,7 +10881,9 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
10705
10881
  this.attachedTo = null;
10706
10882
  /** Index → whether we've already attached visuals for that slot. */
10707
10883
  this.ready = /* @__PURE__ */ new Set();
10708
- this.slots = slots;
10884
+ this.rays = [];
10885
+ this.slots = options?.slots ?? 2;
10886
+ this.interactionSystem = options?.interactionSystem ?? null;
10709
10887
  this.group.name = "XRControllerVisuals";
10710
10888
  this.group.userData.ecsPreviewHidden = true;
10711
10889
  }
@@ -10713,6 +10891,7 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
10713
10891
  const renderer = world.getRenderer();
10714
10892
  if (!renderer.xr?.enabled) return;
10715
10893
  this.ensureAttached(world);
10894
+ this.updateRayVisibility();
10716
10895
  if (this.built) return;
10717
10896
  for (let index = 0; index < this.slots; index += 1) {
10718
10897
  if (this.ready.has(index)) continue;
@@ -10720,7 +10899,9 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
10720
10899
  const grip = renderer.xr.getControllerGrip(index);
10721
10900
  const hand = renderer.xr.getHand(index);
10722
10901
  if (!controller || !grip || !hand) continue;
10723
- controller.add(this.createRay());
10902
+ const ray = this.createRay();
10903
+ this.rays.push(ray);
10904
+ controller.add(ray);
10724
10905
  this.group.add(controller);
10725
10906
  grip.add(this.controllerModelFactory.createControllerModel(grip));
10726
10907
  this.group.add(grip);
@@ -10732,6 +10913,17 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
10732
10913
  this.built = true;
10733
10914
  }
10734
10915
  }
10916
+ /**
10917
+ * Show the aim ray only when it is meaningful: hovering something
10918
+ * interactive, or mid-grab. A permanently-drawn ray is visual noise, and it
10919
+ * implies everything is clickable when most of the scene is not. Teleport
10920
+ * aiming has its own arc, so the straight ray stays hidden for that.
10921
+ */
10922
+ updateRayVisibility() {
10923
+ if (!this.interactionSystem) return;
10924
+ const active = this.interactionSystem.getHoveredEntityId() !== null || this.interactionSystem.isGrabbing();
10925
+ for (const ray of this.rays) ray.visible = active;
10926
+ }
10735
10927
  /**
10736
10928
  * Parent the visuals to the XR rig when there is one, so locomotion moves the
10737
10929
  * hands with the player. Falls back to the scene root.
@@ -10757,6 +10949,7 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
10757
10949
  const line = new THREE38__namespace.Line(geometry, material);
10758
10950
  line.name = "XRPointerRay";
10759
10951
  line.renderOrder = 999;
10952
+ line.visible = this.interactionSystem === null;
10760
10953
  return line;
10761
10954
  }
10762
10955
  dispose() {
@@ -10772,6 +10965,7 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
10772
10965
  }
10773
10966
  });
10774
10967
  this.group.clear();
10968
+ this.rays.length = 0;
10775
10969
  this.ready.clear();
10776
10970
  this.built = false;
10777
10971
  this.attachedTo = null;
@@ -10779,6 +10973,121 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
10779
10973
  };
10780
10974
  __name(_XRControllerVisualSystem, "XRControllerVisualSystem");
10781
10975
  var XRControllerVisualSystem = _XRControllerVisualSystem;
10976
+ var MARKER_RADIUS = 0.28;
10977
+ var ACCENT = new THREE38__namespace.Color("#4da3ff");
10978
+ var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
10979
+ constructor(locomotionSystem) {
10980
+ this.group = new THREE38__namespace.Group();
10981
+ this.arcGeometry = new THREE38__namespace.BufferGeometry();
10982
+ this.marker = new THREE38__namespace.Group();
10983
+ this.attached = false;
10984
+ this.locomotionSystem = locomotionSystem;
10985
+ this.group.name = "XRTeleportVisuals";
10986
+ this.group.userData.ecsPreviewHidden = true;
10987
+ const arcMaterial = new THREE38__namespace.LineBasicMaterial({
10988
+ vertexColors: true,
10989
+ transparent: true,
10990
+ depthTest: false
10991
+ });
10992
+ this.arc = new THREE38__namespace.Line(this.arcGeometry, arcMaterial);
10993
+ this.arc.frustumCulled = false;
10994
+ this.arc.renderOrder = 998;
10995
+ this.group.add(this.arc);
10996
+ this.marker.add(this.createRing(), this.createDot());
10997
+ this.marker.renderOrder = 999;
10998
+ this.group.add(this.marker);
10999
+ this.setVisible(false);
11000
+ }
11001
+ update(world) {
11002
+ if (!this.attached) {
11003
+ world.getScene().add(this.group);
11004
+ this.attached = true;
11005
+ }
11006
+ const curve = this.locomotionSystem.getAimCurve();
11007
+ const landing = this.locomotionSystem.getLandingPoint();
11008
+ if (!landing || curve.length < 2) {
11009
+ this.setVisible(false);
11010
+ return;
11011
+ }
11012
+ this.updateArcGeometry(curve);
11013
+ this.marker.position.copy(landing);
11014
+ this.marker.position.y += 0.01;
11015
+ this.setVisible(true);
11016
+ }
11017
+ updateArcGeometry(curve) {
11018
+ const count = curve.length;
11019
+ const positions = new Float32Array(count * 3);
11020
+ const colors = new Float32Array(count * 3);
11021
+ for (let i = 0; i < count; i += 1) {
11022
+ const point = curve[i];
11023
+ positions[i * 3] = point.x;
11024
+ positions[i * 3 + 1] = point.y;
11025
+ positions[i * 3 + 2] = point.z;
11026
+ const t = count > 1 ? i / (count - 1) : 0;
11027
+ const fade = 1 - t * 0.75;
11028
+ colors[i * 3] = ACCENT.r * fade;
11029
+ colors[i * 3 + 1] = ACCENT.g * fade;
11030
+ colors[i * 3 + 2] = ACCENT.b * fade;
11031
+ }
11032
+ this.arcGeometry.setAttribute(
11033
+ "position",
11034
+ new THREE38__namespace.BufferAttribute(positions, 3)
11035
+ );
11036
+ this.arcGeometry.setAttribute("color", new THREE38__namespace.BufferAttribute(colors, 3));
11037
+ this.arcGeometry.computeBoundingSphere();
11038
+ }
11039
+ createRing() {
11040
+ const geometry = new THREE38__namespace.RingGeometry(
11041
+ MARKER_RADIUS * 0.72,
11042
+ MARKER_RADIUS,
11043
+ 48
11044
+ );
11045
+ geometry.rotateX(-Math.PI / 2);
11046
+ return new THREE38__namespace.Mesh(
11047
+ geometry,
11048
+ new THREE38__namespace.MeshBasicMaterial({
11049
+ color: ACCENT,
11050
+ transparent: true,
11051
+ opacity: 0.9,
11052
+ side: THREE38__namespace.DoubleSide,
11053
+ depthTest: false
11054
+ })
11055
+ );
11056
+ }
11057
+ createDot() {
11058
+ const geometry = new THREE38__namespace.CircleGeometry(MARKER_RADIUS * 0.16, 24);
11059
+ geometry.rotateX(-Math.PI / 2);
11060
+ return new THREE38__namespace.Mesh(
11061
+ geometry,
11062
+ new THREE38__namespace.MeshBasicMaterial({
11063
+ color: ACCENT,
11064
+ transparent: true,
11065
+ opacity: 0.55,
11066
+ side: THREE38__namespace.DoubleSide,
11067
+ depthTest: false
11068
+ })
11069
+ );
11070
+ }
11071
+ setVisible(visible) {
11072
+ this.group.visible = visible;
11073
+ }
11074
+ dispose() {
11075
+ this.group.removeFromParent();
11076
+ this.group.traverse((child) => {
11077
+ const mesh = child;
11078
+ mesh.geometry?.dispose?.();
11079
+ const material = mesh.material;
11080
+ if (Array.isArray(material)) {
11081
+ for (const entry of material) entry.dispose?.();
11082
+ } else {
11083
+ material?.dispose?.();
11084
+ }
11085
+ });
11086
+ this.attached = false;
11087
+ }
11088
+ };
11089
+ __name(_XRTeleportVisualSystem, "XRTeleportVisualSystem");
11090
+ var XRTeleportVisualSystem = _XRTeleportVisualSystem;
10782
11091
 
10783
11092
  // core/World.ts
10784
11093
  var _World = class _World {
@@ -12153,6 +12462,10 @@ function serializeEntitySubtree(world, rootId, options) {
12153
12462
  __name(serializeEntitySubtree, "serializeEntitySubtree");
12154
12463
 
12155
12464
  exports.ADDED_NODE_MARKER_COMPONENT = ADDED_NODE_MARKER_COMPONENT;
12465
+ exports.ARC_GRAVITY = ARC_GRAVITY;
12466
+ exports.ARC_MAX_TIME = ARC_MAX_TIME;
12467
+ exports.ARC_SPEED = ARC_SPEED;
12468
+ exports.ARC_STEPS = ARC_STEPS;
12156
12469
  exports.AnimationStateMachine = AnimationStateMachine;
12157
12470
  exports.AnimationStateManager = AnimationStateManager;
12158
12471
  exports.AnimationSystem = AnimationSystem;
@@ -12194,7 +12507,9 @@ exports.XRInputSystem = XRInputSystem;
12194
12507
  exports.XRInteractionSystem = XRInteractionSystem;
12195
12508
  exports.XRLocomotionSystem = XRLocomotionSystem;
12196
12509
  exports.XRSessionSystem = XRSessionSystem;
12510
+ exports.XRTeleportVisualSystem = XRTeleportVisualSystem;
12197
12511
  exports.applyPrefabToSnapshotInstances = applyPrefabToSnapshotInstances;
12512
+ exports.arcGroundCrossing = arcGroundCrossing;
12198
12513
  exports.buildComponentValueMaps = buildComponentValueMaps;
12199
12514
  exports.buildNodeKeyMapsFromSnapshot = buildNodeKeyMapsFromSnapshot;
12200
12515
  exports.buildNodeMapsFromSnapshot = buildNodeMapsFromSnapshot;
@@ -12259,6 +12574,7 @@ exports.remapSnapshotEntityIds = remapSnapshotEntityIds;
12259
12574
  exports.resolveDracoDecoderPath = resolveDracoDecoderPath;
12260
12575
  exports.restoreComponentState = restoreComponentState;
12261
12576
  exports.restorePostCreateComponents = restorePostCreateComponents;
12577
+ exports.sampleTeleportArc = sampleTeleportArc;
12262
12578
  exports.serializeEntitySubtree = serializeEntitySubtree;
12263
12579
  exports.setDracoDecoderPath = setDracoDecoderPath;
12264
12580
  exports.setPrefabAssetUrlResolver = setPrefabAssetUrlResolver;