@relu-interactives/spatial-ecs 0.3.17 → 0.3.18

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 (38) hide show
  1. package/dist/{XRHandPose-LR4EhboN.d.cts → XRHandPose-B8xxFb9A.d.cts} +12 -0
  2. package/dist/{XRHandPose-SZ7ou63b.d.ts → XRHandPose-ubMe5Igc.d.ts} +12 -0
  3. package/dist/{chunk-CE2CPZSP.js → chunk-7SSOZWXM.js} +113 -35
  4. package/dist/chunk-7SSOZWXM.js.map +1 -0
  5. package/dist/{chunk-3LDQ4GVZ.js → chunk-J3EUNW57.js} +5 -2
  6. package/dist/chunk-J3EUNW57.js.map +1 -0
  7. package/dist/{chunk-UHJ4MDIM.js → chunk-KRWBNC6Y.js} +4 -4
  8. package/dist/{chunk-UHJ4MDIM.js.map → chunk-KRWBNC6Y.js.map} +1 -1
  9. package/dist/{chunk-PNQ7HDQC.js → chunk-PFE2SDXR.js} +3 -3
  10. package/dist/{chunk-PNQ7HDQC.js.map → chunk-PFE2SDXR.js.map} +1 -1
  11. package/dist/components/index.cjs +3 -0
  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/docs/guide/vr-and-hand-poses.md +1 -1
  17. package/dist/factories/index.cjs +3 -0
  18. package/dist/factories/index.cjs.map +1 -1
  19. package/dist/factories/index.d.cts +1 -1
  20. package/dist/factories/index.d.ts +1 -1
  21. package/dist/factories/index.js +3 -3
  22. package/dist/{index-ekS4iypo.d.cts → index-7CFf45fo.d.cts} +22 -1
  23. package/dist/{index-BL5EWkwY.d.cts → index-CA9fqh4Z.d.cts} +1 -1
  24. package/dist/{index-uKFxVCmr.d.ts → index-D7aSZ-e9.d.ts} +22 -1
  25. package/dist/{index-ByiUoIoh.d.ts → index-DhWfxUgL.d.ts} +1 -1
  26. package/dist/index.cjs +112 -31
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +5 -5
  29. package/dist/index.d.ts +5 -5
  30. package/dist/index.js +8 -8
  31. package/dist/systems/index.cjs +112 -31
  32. package/dist/systems/index.cjs.map +1 -1
  33. package/dist/systems/index.d.cts +1 -1
  34. package/dist/systems/index.d.ts +1 -1
  35. package/dist/systems/index.js +3 -3
  36. package/package.json +1 -1
  37. package/dist/chunk-3LDQ4GVZ.js.map +0 -1
  38. package/dist/chunk-CE2CPZSP.js.map +0 -1
@@ -1450,6 +1450,12 @@ type XRRigOptions = {
1450
1450
  snapTurnDegrees?: number;
1451
1451
  /** Height in metres used when the device reports no floor-relative space. */
1452
1452
  fallbackEyeHeight?: number;
1453
+ /** Teleport arc colour when it lands somewhere valid. */
1454
+ teleportArcColor?: string;
1455
+ /** Teleport arc colour when it lands nowhere teleportable. */
1456
+ teleportArcInvalidColor?: string;
1457
+ /** Teleport arc thickness (diameter), metres. */
1458
+ teleportArcThickness?: number;
1453
1459
  };
1454
1460
  /**
1455
1461
  * Marks an entity as the XR rig — the player's movable origin.
@@ -1478,6 +1484,12 @@ declare class XRRigComponent extends Component {
1478
1484
  snapTurnDegrees: number;
1479
1485
  /** Eye height fallback for devices without a floor-relative reference space. */
1480
1486
  fallbackEyeHeight: number;
1487
+ /** Teleport arc colour when it lands somewhere valid. */
1488
+ teleportArcColor: string;
1489
+ /** Teleport arc colour when it lands nowhere teleportable. */
1490
+ teleportArcInvalidColor: string;
1491
+ /** Teleport arc thickness (diameter), metres. */
1492
+ teleportArcThickness: number;
1481
1493
  constructor(options?: XRRigOptions);
1482
1494
  }
1483
1495
 
@@ -1450,6 +1450,12 @@ type XRRigOptions = {
1450
1450
  snapTurnDegrees?: number;
1451
1451
  /** Height in metres used when the device reports no floor-relative space. */
1452
1452
  fallbackEyeHeight?: number;
1453
+ /** Teleport arc colour when it lands somewhere valid. */
1454
+ teleportArcColor?: string;
1455
+ /** Teleport arc colour when it lands nowhere teleportable. */
1456
+ teleportArcInvalidColor?: string;
1457
+ /** Teleport arc thickness (diameter), metres. */
1458
+ teleportArcThickness?: number;
1453
1459
  };
1454
1460
  /**
1455
1461
  * Marks an entity as the XR rig — the player's movable origin.
@@ -1478,6 +1484,12 @@ declare class XRRigComponent extends Component {
1478
1484
  snapTurnDegrees: number;
1479
1485
  /** Eye height fallback for devices without a floor-relative reference space. */
1480
1486
  fallbackEyeHeight: number;
1487
+ /** Teleport arc colour when it lands somewhere valid. */
1488
+ teleportArcColor: string;
1489
+ /** Teleport arc colour when it lands nowhere teleportable. */
1490
+ teleportArcInvalidColor: string;
1491
+ /** Teleport arc thickness (diameter), metres. */
1492
+ teleportArcThickness: number;
1481
1493
  constructor(options?: XRRigOptions);
1482
1494
  }
1483
1495
 
@@ -1,5 +1,5 @@
1
- import { resolveDracoDecoderPath, applyTransform, SHARED_MODEL_RESOURCE_FLAG } from './chunk-PNQ7HDQC.js';
2
- import { AnimationComponent, ModelComponent, CameraComponent, Object3DRef, Environment, Postprocessing, TransformComponent, PhysicsComponent, setPhysicsLiveRef, LightComponent, MaterialComponent, DEFAULT_MESH_GEOMETRY_PARAMETERS, MeshGeometryComponent, InstancedMeshComponent, ParentId, ScriptComponent, ScriptObjectComponent, XRRigComponent, VRTeleportAreaComponent, XRInteractableComponent, createAttachPoint, XRHandPoseComponent, createHandPoseEntry, XRInteractorComponent, XRInteractorSideComponent, InstanceSlotComponent, Name, ImageComponent, SpriteComponent, VideoComponent, AudioComponent, ImageTarget, Selectable, PrefabNode, PrefabInstance, handPoseDefinitionFor, getHandPosePreset } from './chunk-3LDQ4GVZ.js';
1
+ import { resolveDracoDecoderPath, applyTransform, SHARED_MODEL_RESOURCE_FLAG } from './chunk-PFE2SDXR.js';
2
+ import { AnimationComponent, ModelComponent, CameraComponent, Object3DRef, Environment, Postprocessing, TransformComponent, PhysicsComponent, setPhysicsLiveRef, LightComponent, MaterialComponent, DEFAULT_MESH_GEOMETRY_PARAMETERS, MeshGeometryComponent, InstancedMeshComponent, ParentId, ScriptComponent, ScriptObjectComponent, XRRigComponent, VRTeleportAreaComponent, XRInteractableComponent, createAttachPoint, XRHandPoseComponent, createHandPoseEntry, XRInteractorComponent, XRInteractorSideComponent, InstanceSlotComponent, Name, ImageComponent, SpriteComponent, VideoComponent, AudioComponent, ImageTarget, Selectable, PrefabNode, PrefabInstance, handPoseDefinitionFor, getHandPosePreset } from './chunk-J3EUNW57.js';
3
3
  import { __name } from './chunk-OY7ZODZP.js';
4
4
  import * as THREE19 from 'three';
5
5
  import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
@@ -2974,6 +2974,15 @@ function restorePostCreateComponents(world, objectManagementSystem, targetEntity
2974
2974
  if (typeof sourceXrRig.snapTurnDegrees === "number") {
2975
2975
  rig.snapTurnDegrees = sourceXrRig.snapTurnDegrees;
2976
2976
  }
2977
+ if (typeof sourceXrRig.teleportArcColor === "string") {
2978
+ rig.teleportArcColor = sourceXrRig.teleportArcColor;
2979
+ }
2980
+ if (typeof sourceXrRig.teleportArcInvalidColor === "string") {
2981
+ rig.teleportArcInvalidColor = sourceXrRig.teleportArcInvalidColor;
2982
+ }
2983
+ if (typeof sourceXrRig.teleportArcThickness === "number") {
2984
+ rig.teleportArcThickness = sourceXrRig.teleportArcThickness;
2985
+ }
2977
2986
  if (typeof sourceXrRig.fallbackEyeHeight === "number") {
2978
2987
  rig.fallbackEyeHeight = sourceXrRig.fallbackEyeHeight;
2979
2988
  }
@@ -8102,24 +8111,33 @@ __name(_XRControllerVisualSystem, "XRControllerVisualSystem");
8102
8111
  var XRControllerVisualSystem = _XRControllerVisualSystem;
8103
8112
  var MARKER_RADIUS = 0.28;
8104
8113
  var ACCENT = new THREE19.Color("#4da3ff");
8105
- var BLOCKED = new THREE19.Color("#ff5a5a");
8114
+ var SEGMENT_AXIS = new THREE19.Vector3(0, 1, 0);
8115
+ var HEAD_CLEARANCE = 0.25;
8106
8116
  var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
8107
8117
  constructor(locomotionSystem) {
8108
8118
  this.group = new THREE19.Group();
8109
- this.arcGeometry = new THREE19.BufferGeometry();
8119
+ /** Holds the segment chain that draws the arc. */
8120
+ this.arc = new THREE19.Group();
8121
+ /**
8122
+ * Unit cylinder along +Y, reused by every segment.
8123
+ *
8124
+ * The arc was a `THREE.Line`, which WebGL always renders one pixel wide —
8125
+ * effectively invisible on a headset, and not thickenable at all. A chain of
8126
+ * scaled cylinders gives real thickness while rebuilding no geometry: each
8127
+ * frame only moves, rotates and scales meshes that already exist.
8128
+ */
8129
+ this.segmentGeometry = new THREE19.CylinderGeometry(1, 1, 1, 6, 1);
8130
+ this.segments = [];
8110
8131
  this.marker = new THREE19.Group();
8111
8132
  this.attached = false;
8133
+ this.scratchDirection = new THREE19.Vector3();
8134
+ this.scratchHead = new THREE19.Vector3();
8135
+ this.validColor = new THREE19.Color();
8136
+ this.invalidColor = new THREE19.Color();
8112
8137
  this.locomotionSystem = locomotionSystem;
8113
8138
  this.group.name = "XRTeleportVisuals";
8114
8139
  this.group.userData.ecsPreviewHidden = true;
8115
- const arcMaterial = new THREE19.LineBasicMaterial({
8116
- vertexColors: true,
8117
- transparent: true,
8118
- depthTest: false
8119
- });
8120
- this.arc = new THREE19.Line(this.arcGeometry, arcMaterial);
8121
- this.arc.frustumCulled = false;
8122
- this.arc.renderOrder = 998;
8140
+ this.arc.name = "XRTeleportArc";
8123
8141
  this.group.add(this.arc);
8124
8142
  this.marker.add(this.createRing(), this.createDot());
8125
8143
  this.marker.renderOrder = 999;
@@ -8131,15 +8149,27 @@ var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
8131
8149
  world.getScene().add(this.group);
8132
8150
  this.attached = true;
8133
8151
  }
8134
- const curve = this.locomotionSystem.getAimCurve();
8152
+ const raw = this.locomotionSystem.getAimCurve();
8135
8153
  const landing = this.locomotionSystem.getLandingPoint();
8136
8154
  const valid = this.locomotionSystem.isAimValid();
8155
+ if (raw.length < 2) {
8156
+ this.setVisible(false);
8157
+ return;
8158
+ }
8159
+ const curve = this.trimNearHead(world, raw);
8137
8160
  if (curve.length < 2) {
8138
8161
  this.setVisible(false);
8139
8162
  return;
8140
8163
  }
8141
- this.updateArcGeometry(curve, valid ? ACCENT : BLOCKED);
8164
+ const rig = this.resolveRig(world);
8165
+ const thickness = Math.min(
8166
+ 0.1,
8167
+ Math.max(1e-3, rig?.teleportArcThickness ?? 0.012)
8168
+ );
8169
+ const tint = valid ? this.validColor.set(rig?.teleportArcColor ?? "#4da3ff") : this.invalidColor.set(rig?.teleportArcInvalidColor ?? "#ff5a5a");
8170
+ this.updateArcGeometry(curve, tint, thickness);
8142
8171
  if (valid && landing) {
8172
+ this.tintMarker(tint);
8143
8173
  this.marker.position.copy(landing);
8144
8174
  this.marker.position.y += 0.01;
8145
8175
  this.marker.visible = true;
@@ -8148,27 +8178,66 @@ var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
8148
8178
  }
8149
8179
  this.setVisible(true);
8150
8180
  }
8151
- updateArcGeometry(curve, tint) {
8152
- const count = curve.length;
8153
- const positions = new Float32Array(count * 3);
8154
- const colors = new Float32Array(count * 3);
8155
- for (let i = 0; i < count; i += 1) {
8156
- const point = curve[i];
8157
- positions[i * 3] = point.x;
8158
- positions[i * 3 + 1] = point.y;
8159
- positions[i * 3 + 2] = point.z;
8160
- const t = count > 1 ? i / (count - 1) : 0;
8181
+ updateArcGeometry(curve, tint, thickness) {
8182
+ const needed = curve.length - 1;
8183
+ this.ensureSegments(needed);
8184
+ const radius = thickness / 2;
8185
+ for (let i = 0; i < this.segments.length; i += 1) {
8186
+ const segment = this.segments[i];
8187
+ if (i >= needed) {
8188
+ segment.visible = false;
8189
+ continue;
8190
+ }
8191
+ const from = curve[i];
8192
+ const to = curve[i + 1];
8193
+ this.scratchDirection.subVectors(to, from);
8194
+ const length = this.scratchDirection.length();
8195
+ if (length < 1e-6) {
8196
+ segment.visible = false;
8197
+ continue;
8198
+ }
8199
+ segment.visible = true;
8200
+ segment.position.copy(from).addScaledVector(this.scratchDirection, 0.5);
8201
+ segment.quaternion.setFromUnitVectors(
8202
+ SEGMENT_AXIS,
8203
+ this.scratchDirection.divideScalar(length)
8204
+ );
8205
+ segment.scale.set(radius, length, radius);
8206
+ const t = needed > 1 ? i / (needed - 1) : 0;
8161
8207
  const fade = 1 - t * 0.75;
8162
- colors[i * 3] = tint.r * fade;
8163
- colors[i * 3 + 1] = tint.g * fade;
8164
- colors[i * 3 + 2] = tint.b * fade;
8208
+ segment.material.color.copy(tint).multiplyScalar(fade);
8209
+ }
8210
+ }
8211
+ /** Grow the segment pool to cover the current arc. */
8212
+ ensureSegments(count) {
8213
+ while (this.segments.length < count) {
8214
+ const material = new THREE19.MeshBasicMaterial({
8215
+ transparent: true,
8216
+ depthTest: false,
8217
+ depthWrite: false
8218
+ });
8219
+ const mesh = new THREE19.Mesh(this.segmentGeometry, material);
8220
+ mesh.frustumCulled = false;
8221
+ mesh.renderOrder = 998;
8222
+ mesh.raycast = () => {
8223
+ };
8224
+ this.segments.push(mesh);
8225
+ this.arc.add(mesh);
8165
8226
  }
8166
- this.arcGeometry.setAttribute(
8167
- "position",
8168
- new THREE19.BufferAttribute(positions, 3)
8169
- );
8170
- this.arcGeometry.setAttribute("color", new THREE19.BufferAttribute(colors, 3));
8171
- this.arcGeometry.computeBoundingSphere();
8227
+ }
8228
+ /** Drop leading points that sit too close to the viewer's head. */
8229
+ trimNearHead(world, curve) {
8230
+ world.getCamera().getWorldPosition(this.scratchHead);
8231
+ let start = 0;
8232
+ while (start < curve.length - 2 && curve[start].distanceTo(this.scratchHead) < HEAD_CLEARANCE) {
8233
+ start += 1;
8234
+ }
8235
+ return start === 0 ? curve : curve.slice(start);
8236
+ }
8237
+ resolveRig(world) {
8238
+ const entityId = world.query(XRRigComponent)[0];
8239
+ if (typeof entityId !== "number") return null;
8240
+ return world.getComponent(entityId, XRRigComponent) ?? null;
8172
8241
  }
8173
8242
  createRing() {
8174
8243
  const geometry = new THREE19.RingGeometry(
@@ -8202,6 +8271,15 @@ var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
8202
8271
  })
8203
8272
  );
8204
8273
  }
8274
+ /** Recolour the landing marker to match the arc. */
8275
+ tintMarker(color) {
8276
+ this.marker.traverse((child) => {
8277
+ const material = child.material;
8278
+ if (material && !Array.isArray(material)) {
8279
+ material.color?.copy(color);
8280
+ }
8281
+ });
8282
+ }
8205
8283
  setVisible(visible) {
8206
8284
  this.group.visible = visible;
8207
8285
  }
@@ -8875,5 +8953,5 @@ __name(_XRHoverVisualSystem, "XRHoverVisualSystem");
8875
8953
  var XRHoverVisualSystem = _XRHoverVisualSystem;
8876
8954
 
8877
8955
  export { ADDED_NODE_MARKER_COMPONENT, ARC_GRAVITY, ARC_MAX_TIME, ARC_SPEED, ARC_STEPS, AnimationSystem, AudioSystem, Behaviour, CURLED_COS, CameraSyncSystem, 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, XRControllerVisualSystem, XRHandPoseSystem, 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 };
8878
- //# sourceMappingURL=chunk-CE2CPZSP.js.map
8879
- //# sourceMappingURL=chunk-CE2CPZSP.js.map
8956
+ //# sourceMappingURL=chunk-7SSOZWXM.js.map
8957
+ //# sourceMappingURL=chunk-7SSOZWXM.js.map