@relu-interactives/spatial-ecs 0.3.9 → 0.3.10

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-CxPz8VBp.d.ts → XRHandPose-CjacJ_16.d.ts} +70 -1
  2. package/dist/{XRHandPose-VuSbe4iz.d.cts → XRHandPose-hAtj9wm-.d.cts} +70 -1
  3. package/dist/{chunk-KIKIWCEB.js → chunk-5UVBEAGW.js} +4 -4
  4. package/dist/{chunk-KIKIWCEB.js.map → chunk-5UVBEAGW.js.map} +1 -1
  5. package/dist/{chunk-KVGGAL5V.js → chunk-ELSZ5U3F.js} +23 -3
  6. package/dist/chunk-ELSZ5U3F.js.map +1 -0
  7. package/dist/{chunk-L5BP727H.js → chunk-NJOO7NO6.js} +3 -3
  8. package/dist/{chunk-L5BP727H.js.map → chunk-NJOO7NO6.js.map} +1 -1
  9. package/dist/{chunk-W5TSYV6Q.js → chunk-O2HSIZFC.js} +572 -185
  10. package/dist/chunk-O2HSIZFC.js.map +1 -0
  11. package/dist/components/index.cjs +20 -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 +48 -0
  17. package/dist/factories/index.cjs +19 -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-C7XQyrgE.d.ts → index-B-KhN8Ox.d.ts} +51 -0
  23. package/dist/{index-BxdXgqiI.d.ts → index-B7JDsx4a.d.ts} +9 -2
  24. package/dist/{index-BIQoaKAA.d.cts → index-B9JqYr3Q.d.cts} +9 -2
  25. package/dist/{index-DyN50JZo.d.cts → index-DU-CF-3m.d.cts} +51 -0
  26. package/dist/index.cjs +710 -303
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +14 -5
  29. package/dist/index.d.ts +14 -5
  30. package/dist/index.js +8 -8
  31. package/dist/systems/index.cjs +617 -211
  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-KVGGAL5V.js.map +0 -1
  38. package/dist/chunk-W5TSYV6Q.js.map +0 -1
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var THREE14 = require('three');
3
+ var THREE26 = require('three');
4
4
  require('three/examples/jsm/utils/SkeletonUtils.js');
5
5
  var DRACOLoader_js = require('three/examples/jsm/loaders/DRACOLoader.js');
6
6
  var FBXLoader_js = require('three/examples/jsm/loaders/FBXLoader.js');
@@ -40,7 +40,7 @@ function _interopNamespace(e) {
40
40
  return Object.freeze(n);
41
41
  }
42
42
 
43
- var THREE14__namespace = /*#__PURE__*/_interopNamespace(THREE14);
43
+ var THREE26__namespace = /*#__PURE__*/_interopNamespace(THREE26);
44
44
 
45
45
  var __defProp = Object.defineProperty;
46
46
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
@@ -101,14 +101,14 @@ var _TransformComponent = class _TransformComponent extends Component {
101
101
  z: scale.z ?? 1
102
102
  };
103
103
  }
104
- toPositionVector3(target = new THREE14.Vector3()) {
104
+ toPositionVector3(target = new THREE26.Vector3()) {
105
105
  return target.set(this.position.x, this.position.y, this.position.z);
106
106
  }
107
- toRotationEuler(target = new THREE14.Euler(), order = "XYZ") {
107
+ toRotationEuler(target = new THREE26.Euler(), order = "XYZ") {
108
108
  return target.set(this.rotation.x, this.rotation.y, this.rotation.z, order);
109
109
  }
110
- toRotationQuaternion(target = new THREE14.Quaternion(), order = "XYZ") {
111
- const euler = new THREE14.Euler(
110
+ toRotationQuaternion(target = new THREE26.Quaternion(), order = "XYZ") {
111
+ const euler = new THREE26.Euler(
112
112
  this.rotation.x,
113
113
  this.rotation.y,
114
114
  this.rotation.z,
@@ -116,7 +116,7 @@ var _TransformComponent = class _TransformComponent extends Component {
116
116
  );
117
117
  return target.setFromEuler(euler);
118
118
  }
119
- toScaleVector3(target = new THREE14.Vector3()) {
119
+ toScaleVector3(target = new THREE26.Vector3()) {
120
120
  return target.set(this.scale.x, this.scale.y, this.scale.z);
121
121
  }
122
122
  setPosition(input) {
@@ -134,8 +134,8 @@ var _TransformComponent = class _TransformComponent extends Component {
134
134
  return this;
135
135
  }
136
136
  setRotation(input, order = "XYZ") {
137
- if (input instanceof THREE14.Quaternion) {
138
- const euler = new THREE14.Euler().setFromQuaternion(input, order);
137
+ if (input instanceof THREE26.Quaternion) {
138
+ const euler = new THREE26.Euler().setFromQuaternion(input, order);
139
139
  this.rotation.x = euler.x;
140
140
  this.rotation.y = euler.y;
141
141
  this.rotation.z = euler.z;
@@ -184,10 +184,10 @@ var _ObjectManagementSystem = class _ObjectManagementSystem {
184
184
  }
185
185
  getOrCreateAudioListener() {
186
186
  const existing = this.camera.userData.ecsAudioListener;
187
- if (existing instanceof THREE14__namespace.AudioListener) {
187
+ if (existing instanceof THREE26__namespace.AudioListener) {
188
188
  return existing;
189
189
  }
190
- const listener = new THREE14__namespace.AudioListener();
190
+ const listener = new THREE26__namespace.AudioListener();
191
191
  this.camera.add(listener);
192
192
  this.camera.userData.ecsAudioListener = listener;
193
193
  return listener;
@@ -261,7 +261,7 @@ var _ObjectManagementSystem = class _ObjectManagementSystem {
261
261
  }
262
262
  if (dispose && object3d) {
263
263
  object3d.traverse((child) => {
264
- if (child instanceof THREE14__namespace.Mesh) {
264
+ if (child instanceof THREE26__namespace.Mesh) {
265
265
  if (!child.geometry?.userData?.[SHARED_MODEL_RESOURCE_FLAG]) {
266
266
  child.geometry?.dispose();
267
267
  }
@@ -641,14 +641,14 @@ var _AnimationComponent = class _AnimationComponent extends Component {
641
641
  return;
642
642
  }
643
643
  this.importedClips = clips.map((entry) => {
644
- if (entry instanceof THREE14__namespace.AnimationClip) {
644
+ if (entry instanceof THREE26__namespace.AnimationClip) {
645
645
  return { clip: entry, sourceUrl: null };
646
646
  }
647
647
  if (!entry || typeof entry !== "object") {
648
648
  return null;
649
649
  }
650
650
  const candidate = entry;
651
- if (!(candidate.clip instanceof THREE14__namespace.AnimationClip)) {
651
+ if (!(candidate.clip instanceof THREE26__namespace.AnimationClip)) {
652
652
  return null;
653
653
  }
654
654
  return {
@@ -782,7 +782,7 @@ var DEFAULT_ORTHO_TOP = 5;
782
782
  var DEFAULT_ORTHO_BOTTOM = -5;
783
783
  var DEFAULT_ZOOM = 1;
784
784
  function inferProjection(camera) {
785
- if (camera instanceof THREE14__namespace.OrthographicCamera) {
785
+ if (camera instanceof THREE26__namespace.OrthographicCamera) {
786
786
  return "orthographic";
787
787
  }
788
788
  return "perspective";
@@ -803,7 +803,7 @@ function readCameraFar(camera) {
803
803
  }
804
804
  __name(readCameraFar, "readCameraFar");
805
805
  function inferFov(camera) {
806
- if (camera instanceof THREE14__namespace.PerspectiveCamera && Number.isFinite(camera.fov)) {
806
+ if (camera instanceof THREE26__namespace.PerspectiveCamera && Number.isFinite(camera.fov)) {
807
807
  return camera.fov;
808
808
  }
809
809
  return DEFAULT_FOV;
@@ -826,28 +826,28 @@ function inferFar(camera) {
826
826
  }
827
827
  __name(inferFar, "inferFar");
828
828
  function inferOrthoLeft(camera) {
829
- if (camera instanceof THREE14__namespace.OrthographicCamera && Number.isFinite(camera.left)) {
829
+ if (camera instanceof THREE26__namespace.OrthographicCamera && Number.isFinite(camera.left)) {
830
830
  return camera.left;
831
831
  }
832
832
  return DEFAULT_ORTHO_LEFT;
833
833
  }
834
834
  __name(inferOrthoLeft, "inferOrthoLeft");
835
835
  function inferOrthoRight(camera) {
836
- if (camera instanceof THREE14__namespace.OrthographicCamera && Number.isFinite(camera.right)) {
836
+ if (camera instanceof THREE26__namespace.OrthographicCamera && Number.isFinite(camera.right)) {
837
837
  return camera.right;
838
838
  }
839
839
  return DEFAULT_ORTHO_RIGHT;
840
840
  }
841
841
  __name(inferOrthoRight, "inferOrthoRight");
842
842
  function inferOrthoTop(camera) {
843
- if (camera instanceof THREE14__namespace.OrthographicCamera && Number.isFinite(camera.top)) {
843
+ if (camera instanceof THREE26__namespace.OrthographicCamera && Number.isFinite(camera.top)) {
844
844
  return camera.top;
845
845
  }
846
846
  return DEFAULT_ORTHO_TOP;
847
847
  }
848
848
  __name(inferOrthoTop, "inferOrthoTop");
849
849
  function inferOrthoBottom(camera) {
850
- if (camera instanceof THREE14__namespace.OrthographicCamera && Number.isFinite(camera.bottom)) {
850
+ if (camera instanceof THREE26__namespace.OrthographicCamera && Number.isFinite(camera.bottom)) {
851
851
  return camera.bottom;
852
852
  }
853
853
  return DEFAULT_ORTHO_BOTTOM;
@@ -863,7 +863,7 @@ __name(inferZoom, "inferZoom");
863
863
  var _CameraComponent = class _CameraComponent extends Component {
864
864
  constructor(payload = {}) {
865
865
  super();
866
- this.camera = payload.camera ?? new THREE14__namespace.PerspectiveCamera();
866
+ this.camera = payload.camera ?? new THREE26__namespace.PerspectiveCamera();
867
867
  this.type = payload.type ?? "3d";
868
868
  this.isDefault = typeof payload.isDefault === "boolean" ? payload.isDefault : false;
869
869
  this.projection = payload.projection ?? inferProjection(payload.camera);
@@ -1666,15 +1666,15 @@ function createValueState(light) {
1666
1666
  castShadow: light.castShadow ?? false,
1667
1667
  frustumCulling: light.frustumCulled
1668
1668
  };
1669
- if (light instanceof THREE14__namespace.PointLight) {
1669
+ if (light instanceof THREE26__namespace.PointLight) {
1670
1670
  base.distance = light.distance;
1671
1671
  base.decay = light.decay;
1672
- } else if (light instanceof THREE14__namespace.SpotLight) {
1672
+ } else if (light instanceof THREE26__namespace.SpotLight) {
1673
1673
  base.distance = light.distance;
1674
1674
  base.decay = light.decay;
1675
1675
  base.angle = light.angle;
1676
1676
  base.penumbra = light.penumbra;
1677
- } else if (light instanceof THREE14__namespace.RectAreaLight) {
1677
+ } else if (light instanceof THREE26__namespace.RectAreaLight) {
1678
1678
  base.width = light.width;
1679
1679
  base.height = light.height;
1680
1680
  }
@@ -1709,13 +1709,13 @@ function toHexColor2(value, fallback) {
1709
1709
  }
1710
1710
  __name(toHexColor2, "toHexColor");
1711
1711
  function getMaterialType(material) {
1712
- if (material instanceof THREE14__namespace.MeshPhysicalMaterial) {
1712
+ if (material instanceof THREE26__namespace.MeshPhysicalMaterial) {
1713
1713
  return "physical";
1714
1714
  }
1715
- if (material instanceof THREE14__namespace.MeshPhongMaterial) {
1715
+ if (material instanceof THREE26__namespace.MeshPhongMaterial) {
1716
1716
  return "phong";
1717
1717
  }
1718
- if (material instanceof THREE14__namespace.MeshBasicMaterial) {
1718
+ if (material instanceof THREE26__namespace.MeshBasicMaterial) {
1719
1719
  return "basic";
1720
1720
  }
1721
1721
  return "standard";
@@ -1750,8 +1750,8 @@ function createMaterialValue(material) {
1750
1750
  opacity: typeof materialRecord.opacity === "number" ? materialRecord.opacity : 1,
1751
1751
  emissive: toHexColor2(materialRecord.emissive, "#000000"),
1752
1752
  emissiveIntensity: typeof materialRecord.emissiveIntensity === "number" ? materialRecord.emissiveIntensity : 0,
1753
- side: typeof materialRecord.side === "number" ? materialRecord.side : THREE14__namespace.FrontSide,
1754
- blending: typeof materialRecord.blending === "number" ? materialRecord.blending : THREE14__namespace.NormalBlending,
1753
+ side: typeof materialRecord.side === "number" ? materialRecord.side : THREE26__namespace.FrontSide,
1754
+ blending: typeof materialRecord.blending === "number" ? materialRecord.blending : THREE26__namespace.NormalBlending,
1755
1755
  depthTest: materialRecord.depthTest !== false,
1756
1756
  depthWrite: materialRecord.depthWrite !== false,
1757
1757
  wireframe: Boolean(materialRecord.wireframe),
@@ -1783,7 +1783,7 @@ function createMaterialValue(material) {
1783
1783
  materialRecord.lightMap
1784
1784
  ),
1785
1785
  envMap: textureImageSrc(materialRecord.envMap),
1786
- textureFiltering: map?.magFilter === THREE14__namespace.NearestFilter ? "sharp" : "smooth",
1786
+ textureFiltering: map?.magFilter === THREE26__namespace.NearestFilter ? "sharp" : "smooth",
1787
1787
  useMipmaps: map?.generateMipmaps !== false
1788
1788
  };
1789
1789
  }
@@ -1798,8 +1798,8 @@ function defaultMaterialValue() {
1798
1798
  opacity: 1,
1799
1799
  emissive: "#000000",
1800
1800
  emissiveIntensity: 0,
1801
- side: THREE14__namespace.FrontSide,
1802
- blending: THREE14__namespace.NormalBlending,
1801
+ side: THREE26__namespace.FrontSide,
1802
+ blending: THREE26__namespace.NormalBlending,
1803
1803
  depthTest: true,
1804
1804
  depthWrite: true,
1805
1805
  wireframe: false,
@@ -2113,6 +2113,14 @@ var _XRInteractableComponent = class _XRInteractableComponent extends Component
2113
2113
  y: 0,
2114
2114
  z: 0
2115
2115
  };
2116
+ this.grabHands = options?.grabHands ?? "handOff";
2117
+ this.twoHandRotation = options?.twoHandRotation ?? "align";
2118
+ this.allowTwoHandScale = options?.allowTwoHandScale ?? false;
2119
+ this.minScale = options?.minScale ?? 0.25;
2120
+ this.maxScale = options?.maxScale ?? 4;
2121
+ this.attachPoints = (options?.attachPoints ?? []).map(
2122
+ (point) => createAttachPoint(point)
2123
+ );
2116
2124
  this.throwOnRelease = options?.throwOnRelease ?? true;
2117
2125
  this.throwStrength = options?.throwStrength ?? 1;
2118
2126
  this.highlightOnHover = options?.highlightOnHover ?? true;
@@ -2120,6 +2128,17 @@ var _XRInteractableComponent = class _XRInteractableComponent extends Component
2120
2128
  };
2121
2129
  __name(_XRInteractableComponent, "XRInteractableComponent");
2122
2130
  var XRInteractableComponent = _XRInteractableComponent;
2131
+ function createAttachPoint(partial) {
2132
+ return {
2133
+ id: partial.id,
2134
+ name: partial.name ?? partial.id,
2135
+ position: { x: 0, y: 0, z: 0, ...partial.position },
2136
+ rotation: { x: 0, y: 0, z: 0, ...partial.rotation },
2137
+ hand: partial.hand ?? "any",
2138
+ role: partial.role ?? "any"
2139
+ };
2140
+ }
2141
+ __name(createAttachPoint, "createAttachPoint");
2123
2142
 
2124
2143
  // core/components/XRRig.ts
2125
2144
  var _XRRigComponent = class _XRRigComponent extends Component {
@@ -2525,7 +2544,7 @@ function transitionToClip(runtime, nextClipId, crossFadeDuration) {
2525
2544
  }
2526
2545
  __name(transitionToClip, "transitionToClip");
2527
2546
  function applyActionState(action, component, paused, shouldLoop) {
2528
- const loopMode = shouldLoop ? THREE14__namespace.LoopRepeat : THREE14__namespace.LoopOnce;
2547
+ const loopMode = shouldLoop ? THREE26__namespace.LoopRepeat : THREE26__namespace.LoopOnce;
2529
2548
  const repetitions = shouldLoop ? Infinity : 1;
2530
2549
  action.setLoop(loopMode, repetitions);
2531
2550
  action.clampWhenFinished = !shouldLoop;
@@ -2698,7 +2717,7 @@ var _AnimationSystem = class _AnimationSystem {
2698
2717
  if (runtime) {
2699
2718
  stopAllActions(runtime);
2700
2719
  }
2701
- const mixer = new THREE14__namespace.AnimationMixer(root);
2720
+ const mixer = new THREE26__namespace.AnimationMixer(root);
2702
2721
  const entries2 = readRuntimeClipEntries(animation);
2703
2722
  const indexedActions = createActions(mixer, entries2);
2704
2723
  runtime = {
@@ -2824,11 +2843,11 @@ function normalizeOrthoBounds(component) {
2824
2843
  }
2825
2844
  __name(normalizeOrthoBounds, "normalizeOrthoBounds");
2826
2845
  function isPerspectiveCamera(camera) {
2827
- return camera instanceof THREE14__namespace.PerspectiveCamera;
2846
+ return camera instanceof THREE26__namespace.PerspectiveCamera;
2828
2847
  }
2829
2848
  __name(isPerspectiveCamera, "isPerspectiveCamera");
2830
2849
  function isOrthographicCamera(camera) {
2831
- return camera instanceof THREE14__namespace.OrthographicCamera;
2850
+ return camera instanceof THREE26__namespace.OrthographicCamera;
2832
2851
  }
2833
2852
  __name(isOrthographicCamera, "isOrthographicCamera");
2834
2853
  function readWindowAspect() {
@@ -2882,7 +2901,7 @@ var _CameraSyncSystem = class _CameraSyncSystem {
2882
2901
  continue;
2883
2902
  }
2884
2903
  const camera = objectRef.object;
2885
- if (!(camera instanceof THREE14__namespace.Camera)) {
2904
+ if (!(camera instanceof THREE26__namespace.Camera)) {
2886
2905
  continue;
2887
2906
  }
2888
2907
  if (xrCamera !== null && camera === xrCamera) {
@@ -2949,7 +2968,7 @@ var MIN_DENSITY = 0;
2949
2968
  function createGradientTexture(effect, colors) {
2950
2969
  if (typeof document === "undefined") {
2951
2970
  const pixel = new Uint8Array([30, 30, 30, 255]);
2952
- const fallback = new THREE14__namespace.DataTexture(pixel, 1, 1, THREE14__namespace.RGBAFormat);
2971
+ const fallback = new THREE26__namespace.DataTexture(pixel, 1, 1, THREE26__namespace.RGBAFormat);
2953
2972
  fallback.needsUpdate = true;
2954
2973
  return fallback;
2955
2974
  }
@@ -2958,7 +2977,7 @@ function createGradientTexture(effect, colors) {
2958
2977
  canvas.height = 512;
2959
2978
  const context = canvas.getContext("2d");
2960
2979
  if (!context) {
2961
- const fallback = new THREE14__namespace.CanvasTexture(canvas);
2980
+ const fallback = new THREE26__namespace.CanvasTexture(canvas);
2962
2981
  fallback.needsUpdate = true;
2963
2982
  return fallback;
2964
2983
  }
@@ -2986,15 +3005,15 @@ function createGradientTexture(effect, colors) {
2986
3005
  context.fillRect(0, 0, 512, 512);
2987
3006
  context.globalCompositeOperation = "source-over";
2988
3007
  }
2989
- const texture = new THREE14__namespace.CanvasTexture(canvas);
2990
- texture.colorSpace = THREE14__namespace.SRGBColorSpace;
3008
+ const texture = new THREE26__namespace.CanvasTexture(canvas);
3009
+ texture.colorSpace = THREE26__namespace.SRGBColorSpace;
2991
3010
  texture.needsUpdate = true;
2992
3011
  return texture;
2993
3012
  }
2994
3013
  __name(createGradientTexture, "createGradientTexture");
2995
3014
  var _EnvironmentSyncSystem = class _EnvironmentSyncSystem {
2996
3015
  constructor(scene) {
2997
- this.textureLoader = new THREE14__namespace.TextureLoader();
3016
+ this.textureLoader = new THREE26__namespace.TextureLoader();
2998
3017
  this.signature = null;
2999
3018
  this.activeTexture = null;
3000
3019
  this.pendingImageUrl = null;
@@ -3017,7 +3036,7 @@ var _EnvironmentSyncSystem = class _EnvironmentSyncSystem {
3017
3036
  if (skybox.type === "color") {
3018
3037
  this.disposeActiveTexture();
3019
3038
  this.pendingImageUrl = null;
3020
- this.scene.background = new THREE14__namespace.Color(skybox.color || "#1e1e1e");
3039
+ this.scene.background = new THREE26__namespace.Color(skybox.color || "#1e1e1e");
3021
3040
  return;
3022
3041
  }
3023
3042
  if (skybox.type === "gradient") {
@@ -3051,7 +3070,7 @@ var _EnvironmentSyncSystem = class _EnvironmentSyncSystem {
3051
3070
  texture.dispose();
3052
3071
  return;
3053
3072
  }
3054
- texture.colorSpace = THREE14__namespace.SRGBColorSpace;
3073
+ texture.colorSpace = THREE26__namespace.SRGBColorSpace;
3055
3074
  this.activeTexture = texture;
3056
3075
  this.scene.background = texture;
3057
3076
  },
@@ -3070,16 +3089,16 @@ var _EnvironmentSyncSystem = class _EnvironmentSyncSystem {
3070
3089
  this.scene.fog = null;
3071
3090
  return;
3072
3091
  }
3073
- const fogColor = new THREE14__namespace.Color(fog.color || "#1e1e1e");
3092
+ const fogColor = new THREE26__namespace.Color(fog.color || "#1e1e1e");
3074
3093
  if (fog.type === "linear") {
3075
3094
  const near = Number.isFinite(fog.linear.near) ? fog.linear.near : 1;
3076
3095
  const farCandidate = Number.isFinite(fog.linear.far) ? fog.linear.far : near + 10;
3077
3096
  const far = Math.max(near + MIN_FOG_DELTA, farCandidate);
3078
- this.scene.fog = new THREE14__namespace.Fog(fogColor, near, far);
3097
+ this.scene.fog = new THREE26__namespace.Fog(fogColor, near, far);
3079
3098
  return;
3080
3099
  }
3081
3100
  const density = Number.isFinite(fog.exponential.density) ? Math.max(MIN_DENSITY, fog.exponential.density) : 2e-3;
3082
- this.scene.fog = new THREE14__namespace.FogExp2(fogColor, density);
3101
+ this.scene.fog = new THREE26__namespace.FogExp2(fogColor, density);
3083
3102
  }
3084
3103
  update(world) {
3085
3104
  const entityIds = world.query(Environment);
@@ -3161,10 +3180,10 @@ var _PostprocessingSyncSystem = class _PostprocessingSyncSystem {
3161
3180
  );
3162
3181
  }
3163
3182
  if (values.bloom.enabled) {
3164
- const size = this.renderer.getSize(new THREE14__namespace.Vector2());
3183
+ const size = this.renderer.getSize(new THREE26__namespace.Vector2());
3165
3184
  composer.addPass(
3166
3185
  new UnrealBloomPass_js.UnrealBloomPass(
3167
- new THREE14__namespace.Vector2(size.width, size.height),
3186
+ new THREE26__namespace.Vector2(size.width, size.height),
3168
3187
  values.bloom.intensity,
3169
3188
  values.bloom.radius,
3170
3189
  values.bloom.threshold
@@ -3209,7 +3228,7 @@ var _PostprocessingSyncSystem = class _PostprocessingSyncSystem {
3209
3228
  if (values.dotScreen.enabled) {
3210
3229
  composer.addPass(
3211
3230
  new DotScreenPass_js.DotScreenPass(
3212
- new THREE14__namespace.Vector2(0, 0),
3231
+ new THREE26__namespace.Vector2(0, 0),
3213
3232
  values.dotScreen.angle ?? values.dotScreen.dotScreenAngle,
3214
3233
  values.dotScreen.scale ?? values.dotScreen.dotScreenScale
3215
3234
  )
@@ -3283,7 +3302,7 @@ function computeColliderState(colliderValues, object) {
3283
3302
  if (!object) {
3284
3303
  return colliderValues;
3285
3304
  }
3286
- const scale = new THREE14__namespace.Vector3();
3305
+ const scale = new THREE26__namespace.Vector3();
3287
3306
  object.getWorldScale(scale);
3288
3307
  return {
3289
3308
  ...colliderValues,
@@ -3334,8 +3353,8 @@ function createColliderDesc(RAPIER, values, triMeshData) {
3334
3353
  values.offsetPosition.y,
3335
3354
  values.offsetPosition.z
3336
3355
  );
3337
- const offsetQuaternion = new THREE14__namespace.Quaternion().setFromEuler(
3338
- new THREE14__namespace.Euler(
3356
+ const offsetQuaternion = new THREE26__namespace.Quaternion().setFromEuler(
3357
+ new THREE26__namespace.Euler(
3339
3358
  values.offsetRotation.x,
3340
3359
  values.offsetRotation.y,
3341
3360
  values.offsetRotation.z
@@ -3350,17 +3369,17 @@ function collectTriMeshParts(object) {
3350
3369
  return null;
3351
3370
  }
3352
3371
  object.updateWorldMatrix(true, true);
3353
- const worldScale = new THREE14__namespace.Vector3();
3372
+ const worldScale = new THREE26__namespace.Vector3();
3354
3373
  object.getWorldScale(worldScale);
3355
3374
  const scale = {
3356
3375
  x: Math.abs(worldScale.x) || 1,
3357
3376
  y: Math.abs(worldScale.y) || 1,
3358
3377
  z: Math.abs(worldScale.z) || 1
3359
3378
  };
3360
- const worldToObject = new THREE14__namespace.Matrix4().copy(object.matrixWorld).invert();
3379
+ const worldToObject = new THREE26__namespace.Matrix4().copy(object.matrixWorld).invert();
3361
3380
  const parts = [];
3362
3381
  object.traverse((child) => {
3363
- if (!(child instanceof THREE14__namespace.Mesh) || !child.geometry) {
3382
+ if (!(child instanceof THREE26__namespace.Mesh) || !child.geometry) {
3364
3383
  return;
3365
3384
  }
3366
3385
  const geometry = child.geometry;
@@ -3377,7 +3396,7 @@ function collectTriMeshParts(object) {
3377
3396
  if (indexCount < 3) {
3378
3397
  return;
3379
3398
  }
3380
- const relativeMatrix = new THREE14__namespace.Matrix4().multiplyMatrices(
3399
+ const relativeMatrix = new THREE26__namespace.Matrix4().multiplyMatrices(
3381
3400
  worldToObject,
3382
3401
  child.matrixWorld
3383
3402
  );
@@ -3418,7 +3437,7 @@ function createTriMeshData(collected) {
3418
3437
  }
3419
3438
  const vertices = new Float32Array(vertexTotal * 3);
3420
3439
  const indices = new Uint32Array(indexTotal);
3421
- const point = new THREE14__namespace.Vector3();
3440
+ const point = new THREE26__namespace.Vector3();
3422
3441
  let vertexOffset = 0;
3423
3442
  let indexOffset = 0;
3424
3443
  for (const part of parts) {
@@ -3450,8 +3469,8 @@ function createTriMeshData(collected) {
3450
3469
  }
3451
3470
  __name(createTriMeshData, "createTriMeshData");
3452
3471
  function syncBodyFromTransform(body, transform) {
3453
- const quaternion = new THREE14__namespace.Quaternion().setFromEuler(
3454
- new THREE14__namespace.Euler(transform.rotation.x, transform.rotation.y, transform.rotation.z)
3472
+ const quaternion = new THREE26__namespace.Quaternion().setFromEuler(
3473
+ new THREE26__namespace.Euler(transform.rotation.x, transform.rotation.y, transform.rotation.z)
3455
3474
  );
3456
3475
  body.setTranslation(
3457
3476
  {
@@ -3478,8 +3497,8 @@ function syncTransformFromBody(transform, body) {
3478
3497
  transform.position.x = position.x;
3479
3498
  transform.position.y = position.y;
3480
3499
  transform.position.z = position.z;
3481
- const euler = new THREE14__namespace.Euler().setFromQuaternion(
3482
- new THREE14__namespace.Quaternion(rotation.x, rotation.y, rotation.z, rotation.w)
3500
+ const euler = new THREE26__namespace.Euler().setFromQuaternion(
3501
+ new THREE26__namespace.Quaternion(rotation.x, rotation.y, rotation.z, rotation.w)
3483
3502
  );
3484
3503
  transform.rotation.x = euler.x;
3485
3504
  transform.rotation.y = euler.y;
@@ -3591,8 +3610,8 @@ var _PhysicsSyncSystem = class _PhysicsSyncSystem {
3591
3610
  transform.position.y,
3592
3611
  transform.position.z
3593
3612
  );
3594
- const quaternion = new THREE14__namespace.Quaternion().setFromEuler(
3595
- new THREE14__namespace.Euler(
3613
+ const quaternion = new THREE26__namespace.Quaternion().setFromEuler(
3614
+ new THREE26__namespace.Euler(
3596
3615
  transform.rotation.x,
3597
3616
  transform.rotation.y,
3598
3617
  transform.rotation.z
@@ -4171,7 +4190,7 @@ function applyLightValues(lightComponent) {
4171
4190
  values.castShadow
4172
4191
  );
4173
4192
  }
4174
- if (light instanceof THREE14__namespace.PointLight) {
4193
+ if (light instanceof THREE26__namespace.PointLight) {
4175
4194
  if (typeof values.distance === "number" && Number.isFinite(values.distance)) {
4176
4195
  light.distance = Math.max(MIN_LIGHT_DISTANCE, values.distance);
4177
4196
  }
@@ -4179,7 +4198,7 @@ function applyLightValues(lightComponent) {
4179
4198
  light.decay = Math.max(0, values.decay);
4180
4199
  }
4181
4200
  }
4182
- if (light instanceof THREE14__namespace.SpotLight) {
4201
+ if (light instanceof THREE26__namespace.SpotLight) {
4183
4202
  if (typeof values.distance === "number" && Number.isFinite(values.distance)) {
4184
4203
  light.distance = Math.max(MIN_LIGHT_DISTANCE, values.distance);
4185
4204
  }
@@ -4193,7 +4212,7 @@ function applyLightValues(lightComponent) {
4193
4212
  light.penumbra = Math.max(0, Math.min(1, values.penumbra));
4194
4213
  }
4195
4214
  }
4196
- if (light instanceof THREE14__namespace.RectAreaLight) {
4215
+ if (light instanceof THREE26__namespace.RectAreaLight) {
4197
4216
  if (typeof values.width === "number" && Number.isFinite(values.width)) {
4198
4217
  light.width = Math.max(MIN_AREA_SIZE, values.width);
4199
4218
  }
@@ -4254,15 +4273,15 @@ function resolveMaterialPropertyKey(key) {
4254
4273
  __name(resolveMaterialPropertyKey, "resolveMaterialPropertyKey");
4255
4274
  function createMaterialByType(type) {
4256
4275
  if (type === "basic") {
4257
- return new THREE14__namespace.MeshBasicMaterial();
4276
+ return new THREE26__namespace.MeshBasicMaterial();
4258
4277
  }
4259
4278
  if (type === "phong") {
4260
- return new THREE14__namespace.MeshPhongMaterial();
4279
+ return new THREE26__namespace.MeshPhongMaterial();
4261
4280
  }
4262
4281
  if (type === "physical") {
4263
- return new THREE14__namespace.MeshPhysicalMaterial();
4282
+ return new THREE26__namespace.MeshPhysicalMaterial();
4264
4283
  }
4265
- return new THREE14__namespace.MeshStandardMaterial();
4284
+ return new THREE26__namespace.MeshStandardMaterial();
4266
4285
  }
4267
4286
  __name(createMaterialByType, "createMaterialByType");
4268
4287
  function replaceMaterialAcrossObject(object, previous, next) {
@@ -4321,12 +4340,12 @@ function applyTextureFiltering(material, filtering) {
4321
4340
  const target = material;
4322
4341
  for (const slot of materialTextureSlots) {
4323
4342
  const texture = target[slot];
4324
- if (!texture || !(texture instanceof THREE14__namespace.Texture)) {
4343
+ if (!texture || !(texture instanceof THREE26__namespace.Texture)) {
4325
4344
  continue;
4326
4345
  }
4327
4346
  const useMipmaps = texture.generateMipmaps !== false;
4328
- texture.magFilter = sharp ? THREE14__namespace.NearestFilter : THREE14__namespace.LinearFilter;
4329
- texture.minFilter = useMipmaps ? sharp ? THREE14__namespace.NearestMipmapNearestFilter : THREE14__namespace.LinearMipmapLinearFilter : sharp ? THREE14__namespace.NearestFilter : THREE14__namespace.LinearFilter;
4347
+ texture.magFilter = sharp ? THREE26__namespace.NearestFilter : THREE26__namespace.LinearFilter;
4348
+ texture.minFilter = useMipmaps ? sharp ? THREE26__namespace.NearestMipmapNearestFilter : THREE26__namespace.LinearMipmapLinearFilter : sharp ? THREE26__namespace.NearestFilter : THREE26__namespace.LinearFilter;
4330
4349
  texture.needsUpdate = true;
4331
4350
  }
4332
4351
  material.needsUpdate = true;
@@ -4336,12 +4355,12 @@ function setTextureMipmaps(material, enabled) {
4336
4355
  const target = material;
4337
4356
  for (const slot of materialTextureSlots) {
4338
4357
  const texture = target[slot];
4339
- if (!texture || !(texture instanceof THREE14__namespace.Texture)) {
4358
+ if (!texture || !(texture instanceof THREE26__namespace.Texture)) {
4340
4359
  continue;
4341
4360
  }
4342
4361
  texture.generateMipmaps = enabled;
4343
- const sharp = texture.magFilter === THREE14__namespace.NearestFilter;
4344
- texture.minFilter = enabled ? sharp ? THREE14__namespace.NearestMipmapNearestFilter : THREE14__namespace.LinearMipmapLinearFilter : sharp ? THREE14__namespace.NearestFilter : THREE14__namespace.LinearFilter;
4362
+ const sharp = texture.magFilter === THREE26__namespace.NearestFilter;
4363
+ texture.minFilter = enabled ? sharp ? THREE26__namespace.NearestMipmapNearestFilter : THREE26__namespace.LinearMipmapLinearFilter : sharp ? THREE26__namespace.NearestFilter : THREE26__namespace.LinearFilter;
4345
4364
  texture.needsUpdate = true;
4346
4365
  }
4347
4366
  material.needsUpdate = true;
@@ -4352,7 +4371,7 @@ function assignMaterialTexture(material, rawKey, url, textureCache) {
4352
4371
  const key = resolveMaterialPropertyKey(rawKey);
4353
4372
  let texture = textureCache.get(url);
4354
4373
  if (!texture) {
4355
- texture = new THREE14__namespace.TextureLoader().load(url);
4374
+ texture = new THREE26__namespace.TextureLoader().load(url);
4356
4375
  textureCache.set(url, texture);
4357
4376
  }
4358
4377
  target[key] = texture;
@@ -4390,7 +4409,7 @@ function applyMaterialState(material, value, textureCache) {
4390
4409
  }
4391
4410
  target.side = value.side;
4392
4411
  target.blending = value.blending;
4393
- target.premultipliedAlpha = value.blending === THREE14__namespace.MultiplyBlending || value.blending === THREE14__namespace.SubtractiveBlending;
4412
+ target.premultipliedAlpha = value.blending === THREE26__namespace.MultiplyBlending || value.blending === THREE26__namespace.SubtractiveBlending;
4394
4413
  target.depthTest = value.depthTest;
4395
4414
  target.depthWrite = value.depthWrite;
4396
4415
  target.wireframe = value.wireframe;
@@ -4551,12 +4570,12 @@ function resolvePrimaryMesh(object) {
4551
4570
  if (!object) {
4552
4571
  return null;
4553
4572
  }
4554
- if (object instanceof THREE14__namespace.Mesh) {
4573
+ if (object instanceof THREE26__namespace.Mesh) {
4555
4574
  return object;
4556
4575
  }
4557
4576
  let found = null;
4558
4577
  object.traverse((child) => {
4559
- if (!found && child instanceof THREE14__namespace.Mesh) {
4578
+ if (!found && child instanceof THREE26__namespace.Mesh) {
4560
4579
  found = child;
4561
4580
  }
4562
4581
  });
@@ -4577,22 +4596,22 @@ function applyGeometry(component) {
4577
4596
  switch (component.kind) {
4578
4597
  case "cube": {
4579
4598
  const params = sanitized;
4580
- nextGeometry = new THREE14__namespace.BoxGeometry(params.width, params.height, params.depth);
4599
+ nextGeometry = new THREE26__namespace.BoxGeometry(params.width, params.height, params.depth);
4581
4600
  break;
4582
4601
  }
4583
4602
  case "plane": {
4584
4603
  const params = sanitized;
4585
- nextGeometry = new THREE14__namespace.PlaneGeometry(params.width, params.height);
4604
+ nextGeometry = new THREE26__namespace.PlaneGeometry(params.width, params.height);
4586
4605
  break;
4587
4606
  }
4588
4607
  case "sphere": {
4589
4608
  const params = sanitized;
4590
- nextGeometry = new THREE14__namespace.SphereGeometry(params.radius, 24, 24);
4609
+ nextGeometry = new THREE26__namespace.SphereGeometry(params.radius, 24, 24);
4591
4610
  break;
4592
4611
  }
4593
4612
  case "cylinder": {
4594
4613
  const params = sanitized;
4595
- nextGeometry = new THREE14__namespace.CylinderGeometry(
4614
+ nextGeometry = new THREE26__namespace.CylinderGeometry(
4596
4615
  params.radius,
4597
4616
  params.radius,
4598
4617
  params.height,
@@ -4602,7 +4621,7 @@ function applyGeometry(component) {
4602
4621
  }
4603
4622
  case "capsule": {
4604
4623
  const params = sanitized;
4605
- nextGeometry = new THREE14__namespace.CapsuleGeometry(params.radius, params.height, 4, 8);
4624
+ nextGeometry = new THREE26__namespace.CapsuleGeometry(params.radius, params.height, 4, 8);
4606
4625
  break;
4607
4626
  }
4608
4627
  default:
@@ -4618,7 +4637,7 @@ function applyShadowFlags(component) {
4618
4637
  return;
4619
4638
  }
4620
4639
  component.object.traverse((child) => {
4621
- if (child instanceof THREE14__namespace.Mesh) {
4640
+ if (child instanceof THREE26__namespace.Mesh) {
4622
4641
  child.castShadow = component.castShadow;
4623
4642
  child.receiveShadow = component.receiveShadow;
4624
4643
  }
@@ -4701,35 +4720,35 @@ function buildGeometry(component) {
4701
4720
  switch (component.meshKind) {
4702
4721
  case "cube": {
4703
4722
  const params = p;
4704
- return new THREE14__namespace.BoxGeometry(params.width, params.height, params.depth);
4723
+ return new THREE26__namespace.BoxGeometry(params.width, params.height, params.depth);
4705
4724
  }
4706
4725
  case "plane": {
4707
4726
  const params = p;
4708
- return new THREE14__namespace.PlaneGeometry(params.width, params.height);
4727
+ return new THREE26__namespace.PlaneGeometry(params.width, params.height);
4709
4728
  }
4710
4729
  case "sphere": {
4711
4730
  const params = p;
4712
- return new THREE14__namespace.SphereGeometry(params.radius, 24, 24);
4731
+ return new THREE26__namespace.SphereGeometry(params.radius, 24, 24);
4713
4732
  }
4714
4733
  case "cylinder": {
4715
4734
  const params = p;
4716
- return new THREE14__namespace.CylinderGeometry(params.radius, params.radius, params.height, 20);
4735
+ return new THREE26__namespace.CylinderGeometry(params.radius, params.radius, params.height, 20);
4717
4736
  }
4718
4737
  case "capsule": {
4719
4738
  const params = p;
4720
- return new THREE14__namespace.CapsuleGeometry(params.radius, params.height, 4, 8);
4739
+ return new THREE26__namespace.CapsuleGeometry(params.radius, params.height, 4, 8);
4721
4740
  }
4722
4741
  default:
4723
- return new THREE14__namespace.BoxGeometry(1, 1, 1);
4742
+ return new THREE26__namespace.BoxGeometry(1, 1, 1);
4724
4743
  }
4725
4744
  }
4726
4745
  __name(buildGeometry, "buildGeometry");
4727
- var _position = new THREE14__namespace.Vector3();
4728
- var _quaternion = new THREE14__namespace.Quaternion();
4729
- var _euler = new THREE14__namespace.Euler();
4730
- var _scale = new THREE14__namespace.Vector3();
4731
- var _matrix = new THREE14__namespace.Matrix4();
4732
- var _modelMatrix = new THREE14__namespace.Matrix4();
4746
+ var _position = new THREE26__namespace.Vector3();
4747
+ var _quaternion = new THREE26__namespace.Quaternion();
4748
+ var _euler = new THREE26__namespace.Euler();
4749
+ var _scale = new THREE26__namespace.Vector3();
4750
+ var _matrix = new THREE26__namespace.Matrix4();
4751
+ var _modelMatrix = new THREE26__namespace.Matrix4();
4733
4752
  function instanceTransformFromComponent(transform, out) {
4734
4753
  _position.set(transform.position.x, transform.position.y, transform.position.z);
4735
4754
  _euler.set(transform.rotation.x, transform.rotation.y, transform.rotation.z, "XYZ");
@@ -4882,7 +4901,7 @@ var _InstancedMeshSystem = class _InstancedMeshSystem {
4882
4901
  const sourceMaterial = Array.isArray(meshChild.material) ? meshChild.material.map((m) => m.clone()) : meshChild.material.clone();
4883
4902
  meshChild.updateWorldMatrix(true, false);
4884
4903
  const localMatrix = meshChild.matrixWorld.clone();
4885
- const instancedMesh2 = new THREE14__namespace.InstancedMesh(
4904
+ const instancedMesh2 = new THREE26__namespace.InstancedMesh(
4886
4905
  geometry2,
4887
4906
  Array.isArray(sourceMaterial) ? sourceMaterial : sourceMaterial,
4888
4907
  count2
@@ -4907,7 +4926,7 @@ var _InstancedMeshSystem = class _InstancedMeshSystem {
4907
4926
  this.loadingSignatures.delete(targetEntityId);
4908
4927
  return;
4909
4928
  }
4910
- const group = new THREE14__namespace.Group();
4929
+ const group = new THREE26__namespace.Group();
4911
4930
  for (const entry of entries) {
4912
4931
  group.add(entry.instancedMesh);
4913
4932
  }
@@ -4925,8 +4944,8 @@ var _InstancedMeshSystem = class _InstancedMeshSystem {
4925
4944
  }
4926
4945
  const count = instanceCount;
4927
4946
  const geometry = buildGeometry(comp);
4928
- const material = new THREE14__namespace.MeshStandardMaterial({ color: "#ffffff" });
4929
- const instancedMesh = new THREE14__namespace.InstancedMesh(geometry, material, count);
4947
+ const material = new THREE26__namespace.MeshStandardMaterial({ color: "#ffffff" });
4948
+ const instancedMesh = new THREE26__namespace.InstancedMesh(geometry, material, count);
4930
4949
  instancedMesh.castShadow = comp.castShadow;
4931
4950
  instancedMesh.receiveShadow = comp.receiveShadow;
4932
4951
  for (let i = 0; i < count; i++) {
@@ -5361,6 +5380,30 @@ function restorePostCreateComponents(world, objectManagementSystem, targetEntity
5361
5380
  if (typeof sourceInteractable.grabRadius === "number") {
5362
5381
  interactable.grabRadius = sourceInteractable.grabRadius;
5363
5382
  }
5383
+ if (typeof sourceInteractable.grabHands === "string") {
5384
+ interactable.grabHands = sourceInteractable.grabHands;
5385
+ }
5386
+ if (typeof sourceInteractable.twoHandRotation === "string") {
5387
+ interactable.twoHandRotation = sourceInteractable.twoHandRotation;
5388
+ }
5389
+ if (typeof sourceInteractable.allowTwoHandScale === "boolean") {
5390
+ interactable.allowTwoHandScale = sourceInteractable.allowTwoHandScale;
5391
+ }
5392
+ if (typeof sourceInteractable.minScale === "number") {
5393
+ interactable.minScale = sourceInteractable.minScale;
5394
+ }
5395
+ if (typeof sourceInteractable.maxScale === "number") {
5396
+ interactable.maxScale = sourceInteractable.maxScale;
5397
+ }
5398
+ if (Array.isArray(sourceInteractable.attachPoints)) {
5399
+ interactable.attachPoints = sourceInteractable.attachPoints.map((point) => asRecord3(point)).filter(
5400
+ (point) => point !== null && typeof point.id === "string"
5401
+ ).map(
5402
+ (point) => createAttachPoint(
5403
+ point
5404
+ )
5405
+ );
5406
+ }
5364
5407
  if (typeof sourceInteractable.throwOnRelease === "boolean") {
5365
5408
  interactable.throwOnRelease = sourceInteractable.throwOnRelease;
5366
5409
  }
@@ -6569,7 +6612,7 @@ var _Behaviour = class _Behaviour {
6569
6612
  if (!this.threeRef) {
6570
6613
  return null;
6571
6614
  }
6572
- const position = new THREE14__namespace.Vector3();
6615
+ const position = new THREE26__namespace.Vector3();
6573
6616
  this.threeRef.object.getWorldPosition(position);
6574
6617
  return position;
6575
6618
  }
@@ -6581,7 +6624,7 @@ var _Behaviour = class _Behaviour {
6581
6624
  if (!this.threeRef) {
6582
6625
  return null;
6583
6626
  }
6584
- const target = new THREE14__namespace.Vector3();
6627
+ const target = new THREE26__namespace.Vector3();
6585
6628
  this.threeRef.object.getWorldDirection(target);
6586
6629
  return target;
6587
6630
  }
@@ -6643,7 +6686,7 @@ var _Behaviour = class _Behaviour {
6643
6686
  if (!this.threeRef) {
6644
6687
  return;
6645
6688
  }
6646
- const rotation = new THREE14__namespace.Quaternion();
6689
+ const rotation = new THREE26__namespace.Quaternion();
6647
6690
  this.threeRef.object.getWorldQuaternion(rotation);
6648
6691
  rotation.slerp(targetRotation, alpha);
6649
6692
  this.transform.setRotation(rotation);
@@ -6660,7 +6703,7 @@ var _Behaviour = class _Behaviour {
6660
6703
  return;
6661
6704
  }
6662
6705
  const clone = this.threeRef.object.clone();
6663
- const rotation = new THREE14__namespace.Quaternion();
6706
+ const rotation = new THREE26__namespace.Quaternion();
6664
6707
  clone.lookAt(targetPosition);
6665
6708
  clone.getWorldQuaternion(rotation);
6666
6709
  this.transform.setRotation(rotation);
@@ -6798,6 +6841,17 @@ var _Behaviour = class _Behaviour {
6798
6841
  *
6799
6842
  * @param input - The source doing the grabbing.
6800
6843
  */
6844
+ /**
6845
+ * A SECOND hand joined a two-hand grab on this entity.
6846
+ *
6847
+ * The first hand anchors the object and keeps holding it; this fires for the
6848
+ * hand that came second — the foregrip on a rifle, say.
6849
+ */
6850
+ onSecondaryGrab(_input) {
6851
+ }
6852
+ /** The second hand let go, leaving the object in the first hand alone. */
6853
+ onSecondaryRelease(_input) {
6854
+ }
6801
6855
  /**
6802
6856
  * A hand pose declared on this entity started being held.
6803
6857
  *
@@ -7015,8 +7069,8 @@ var _ScriptBehaviourSystem = class _ScriptBehaviourSystem {
7015
7069
  }, "onPointerUp");
7016
7070
  this.moduleLoader = moduleLoader ?? defaultModuleLoader;
7017
7071
  this.selectionCtx = selectionContext ?? null;
7018
- this.raycaster = new THREE14__namespace.Raycaster();
7019
- this.ndcPointer = new THREE14__namespace.Vector2();
7072
+ this.raycaster = new THREE26__namespace.Raycaster();
7073
+ this.ndcPointer = new THREE26__namespace.Vector2();
7020
7074
  if (this.selectionCtx) {
7021
7075
  this.selectionCtx.domElement.addEventListener("pointerdown", this.onPointerDown);
7022
7076
  this.selectionCtx.domElement.addEventListener("pointerup", this.onPointerUp);
@@ -7395,7 +7449,7 @@ function disposeBuiltObject(root) {
7395
7449
  for (const mat of materials) {
7396
7450
  if (mat.userData?.[SHARED_MODEL_RESOURCE_FLAG]) continue;
7397
7451
  for (const value of Object.values(mat)) {
7398
- if (value instanceof THREE14__namespace.Texture) value.dispose();
7452
+ if (value instanceof THREE26__namespace.Texture) value.dispose();
7399
7453
  }
7400
7454
  mat.dispose?.();
7401
7455
  }
@@ -7759,7 +7813,7 @@ var _AudioSystem = class _AudioSystem {
7759
7813
  if (!prev || prev.volume !== opts.volume) {
7760
7814
  sound.setVolume(opts.volume);
7761
7815
  }
7762
- if (opts.positional && sound instanceof THREE14__namespace.PositionalAudio) {
7816
+ if (opts.positional && sound instanceof THREE26__namespace.PositionalAudio) {
7763
7817
  if (!prev || prev.refDistance !== opts.refDistance) {
7764
7818
  sound.setRefDistance(opts.refDistance);
7765
7819
  }
@@ -7885,7 +7939,7 @@ var _VideoSystem = class _VideoSystem {
7885
7939
  component.object.scale.set(opts.width, opts.height, 1);
7886
7940
  }
7887
7941
  const material = component.material;
7888
- if (material instanceof THREE14__namespace.ShaderMaterial) {
7942
+ if (material instanceof THREE26__namespace.ShaderMaterial) {
7889
7943
  if (!prev || prev.backgroundColor !== opts.backgroundColor) {
7890
7944
  material.uniforms.keyColor.value.set(opts.backgroundColor);
7891
7945
  }
@@ -7899,7 +7953,7 @@ var _VideoSystem = class _VideoSystem {
7899
7953
  material.uniforms.spill.value = opts.spill;
7900
7954
  }
7901
7955
  }
7902
- if (opts.positional && component.audioNode instanceof THREE14__namespace.PositionalAudio) {
7956
+ if (opts.positional && component.audioNode instanceof THREE26__namespace.PositionalAudio) {
7903
7957
  const posAudio = component.audioNode;
7904
7958
  if (!prev || prev.refDistance !== opts.refDistance) {
7905
7959
  posAudio.setRefDistance(opts.refDistance);
@@ -7939,8 +7993,8 @@ function blankState(source) {
7939
7993
  handedness: handednessOf(source),
7940
7994
  kind: kindOf(source),
7941
7995
  connected: true,
7942
- rayOrigin: new THREE14__namespace.Vector3(),
7943
- rayDirection: new THREE14__namespace.Vector3(0, 0, -1),
7996
+ rayOrigin: new THREE26__namespace.Vector3(),
7997
+ rayDirection: new THREE26__namespace.Vector3(0, 0, -1),
7944
7998
  gripPosition: null,
7945
7999
  gripQuaternion: null,
7946
8000
  select: false,
@@ -7966,7 +8020,7 @@ function readHandJoints(frame, hand, referenceSpace, rigMatrix, existing) {
7966
8020
  }
7967
8021
  if (spaces.length === 0) return null;
7968
8022
  const target = existing ?? {};
7969
- const matrix = new THREE14__namespace.Matrix4();
8023
+ const matrix = new THREE26__namespace.Matrix4();
7970
8024
  const buffer = spaces.length * 16 <= JOINT_MATRIX_BUFFER.length ? JOINT_MATRIX_BUFFER : new Float32Array(spaces.length * 16);
7971
8025
  const fillPoses = frame.fillPoses;
7972
8026
  if (typeof fillPoses === "function") {
@@ -7979,7 +8033,7 @@ function readHandJoints(frame, hand, referenceSpace, rigMatrix, existing) {
7979
8033
  if (filled) {
7980
8034
  for (let i = 0; i < names.length; i += 1) {
7981
8035
  matrix.fromArray(buffer, i * 16).premultiply(rigMatrix);
7982
- const vector = target[names[i]] ?? new THREE14__namespace.Vector3();
8036
+ const vector = target[names[i]] ?? new THREE26__namespace.Vector3();
7983
8037
  vector.setFromMatrixPosition(matrix);
7984
8038
  target[names[i]] = vector;
7985
8039
  }
@@ -7997,7 +8051,7 @@ function readHandJoints(frame, hand, referenceSpace, rigMatrix, existing) {
7997
8051
  continue;
7998
8052
  }
7999
8053
  matrix.fromArray(pose.transform.matrix).premultiply(rigMatrix);
8000
- const vector = target[names[i]] ?? new THREE14__namespace.Vector3();
8054
+ const vector = target[names[i]] ?? new THREE26__namespace.Vector3();
8001
8055
  vector.setFromMatrixPosition(matrix);
8002
8056
  target[names[i]] = vector;
8003
8057
  anyTracked = true;
@@ -8009,7 +8063,7 @@ var _XRInputSystem = class _XRInputSystem {
8009
8063
  constructor() {
8010
8064
  this.records = /* @__PURE__ */ new Map();
8011
8065
  /** Reference-space → world matrix, rebuilt each frame from the XR rig. */
8012
- this.referenceToWorld = new THREE14__namespace.Matrix4();
8066
+ this.referenceToWorld = new THREE26__namespace.Matrix4();
8013
8067
  this.session = null;
8014
8068
  this.onSelectStart = /* @__PURE__ */ __name((event) => this.mark(event, "pendingSelectStart"), "onSelectStart");
8015
8069
  this.onSelectEnd = /* @__PURE__ */ __name((event) => this.mark(event, "pendingSelectEnd"), "onSelectEnd");
@@ -8107,19 +8161,19 @@ var _XRInputSystem = class _XRInputSystem {
8107
8161
  if (frame && referenceSpace && source.targetRaySpace) {
8108
8162
  const pose = frame.getPose(source.targetRaySpace, referenceSpace);
8109
8163
  if (pose) {
8110
- const m = new THREE14__namespace.Matrix4().fromArray(pose.transform.matrix).premultiply(rigMatrix);
8164
+ const m = new THREE26__namespace.Matrix4().fromArray(pose.transform.matrix).premultiply(rigMatrix);
8111
8165
  state.rayOrigin.setFromMatrixPosition(m);
8112
8166
  state.rayDirection.set(0, 0, -1).applyQuaternion(
8113
- new THREE14__namespace.Quaternion().setFromRotationMatrix(m)
8167
+ new THREE26__namespace.Quaternion().setFromRotationMatrix(m)
8114
8168
  ).normalize();
8115
8169
  }
8116
8170
  }
8117
8171
  if (frame && referenceSpace && source.gripSpace) {
8118
8172
  const gripPose = frame.getPose(source.gripSpace, referenceSpace);
8119
8173
  if (gripPose) {
8120
- const m = new THREE14__namespace.Matrix4().fromArray(gripPose.transform.matrix).premultiply(rigMatrix);
8121
- state.gripPosition ?? (state.gripPosition = new THREE14__namespace.Vector3());
8122
- state.gripQuaternion ?? (state.gripQuaternion = new THREE14__namespace.Quaternion());
8174
+ const m = new THREE26__namespace.Matrix4().fromArray(gripPose.transform.matrix).premultiply(rigMatrix);
8175
+ state.gripPosition ?? (state.gripPosition = new THREE26__namespace.Vector3());
8176
+ state.gripQuaternion ?? (state.gripQuaternion = new THREE26__namespace.Quaternion());
8123
8177
  state.gripPosition.setFromMatrixPosition(m);
8124
8178
  state.gripQuaternion.setFromRotationMatrix(m);
8125
8179
  }
@@ -8228,15 +8282,15 @@ var _ThrowVelocityTracker = class _ThrowVelocityTracker {
8228
8282
  const fresh = this.samples.filter(
8229
8283
  (sample) => now - sample.time <= MAX_SAMPLE_AGE_SECONDS
8230
8284
  );
8231
- if (fresh.length < 2) return new THREE14__namespace.Vector3();
8232
- let best = new THREE14__namespace.Vector3();
8285
+ if (fresh.length < 2) return new THREE26__namespace.Vector3();
8286
+ let best = new THREE26__namespace.Vector3();
8233
8287
  let bestSpeed = 0;
8234
8288
  for (let i = 1; i < fresh.length; i += 1) {
8235
8289
  const previous = fresh[i - 1];
8236
8290
  const current = fresh[i];
8237
8291
  const dt = current.time - previous.time;
8238
8292
  if (dt <= 1e-5) continue;
8239
- const velocity = new THREE14__namespace.Vector3().subVectors(current.position, previous.position).divideScalar(dt);
8293
+ const velocity = new THREE26__namespace.Vector3().subVectors(current.position, previous.position).divideScalar(dt);
8240
8294
  const speed = velocity.length();
8241
8295
  if (speed > MAX_PLAUSIBLE_SPEED) continue;
8242
8296
  if (speed > bestSpeed) {
@@ -8253,23 +8307,75 @@ var _ThrowVelocityTracker = class _ThrowVelocityTracker {
8253
8307
  __name(_ThrowVelocityTracker, "ThrowVelocityTracker");
8254
8308
  var ThrowVelocityTracker = _ThrowVelocityTracker;
8255
8309
  function angularVelocityFrom(previous, current, deltaTime) {
8256
- if (deltaTime <= 1e-5) return new THREE14__namespace.Vector3();
8310
+ if (deltaTime <= 1e-5) return new THREE26__namespace.Vector3();
8257
8311
  const delta = current.clone().multiply(previous.clone().invert());
8258
8312
  if (delta.w < 0) {
8259
8313
  delta.set(-delta.x, -delta.y, -delta.z, -delta.w);
8260
8314
  }
8261
- const angle = 2 * Math.acos(THREE14__namespace.MathUtils.clamp(delta.w, -1, 1));
8315
+ const angle = 2 * Math.acos(THREE26__namespace.MathUtils.clamp(delta.w, -1, 1));
8262
8316
  const sinHalf = Math.sqrt(Math.max(0, 1 - delta.w * delta.w));
8263
- if (sinHalf < 1e-6 || angle < 1e-6) return new THREE14__namespace.Vector3();
8264
- return new THREE14__namespace.Vector3(delta.x, delta.y, delta.z).divideScalar(sinHalf).multiplyScalar(angle / deltaTime);
8317
+ if (sinHalf < 1e-6 || angle < 1e-6) return new THREE26__namespace.Vector3();
8318
+ return new THREE26__namespace.Vector3(delta.x, delta.y, delta.z).divideScalar(sinHalf).multiplyScalar(angle / deltaTime);
8265
8319
  }
8266
8320
  __name(angularVelocityFrom, "angularVelocityFrom");
8321
+ var MIN_HAND_SEPARATION = 0.06;
8322
+ var MIN_ANCHOR_SEPARATION = 1e-3;
8323
+ var SCALE_DEADZONE = 0.05;
8324
+ function solveTwoHandTransform(primary, secondary, basis, options) {
8325
+ const separation = primary.position.distanceTo(secondary.position);
8326
+ const anchorDelta = new THREE26__namespace.Vector3().subVectors(
8327
+ basis.secondaryLocal,
8328
+ basis.primaryLocal
8329
+ );
8330
+ const anchorLength = anchorDelta.length();
8331
+ let factor = 1;
8332
+ if (options.allowScale && basis.initialSeparation > MIN_ANCHOR_SEPARATION && separation > MIN_ANCHOR_SEPARATION) {
8333
+ factor = separation / basis.initialSeparation;
8334
+ if (Math.abs(factor - 1) <= SCALE_DEADZONE) {
8335
+ factor = 1;
8336
+ } else {
8337
+ factor += factor > 1 ? -SCALE_DEADZONE : SCALE_DEADZONE;
8338
+ }
8339
+ factor = Math.min(options.maxScale, Math.max(options.minScale, factor));
8340
+ }
8341
+ const scale = basis.initialScale.clone().multiplyScalar(factor);
8342
+ const degenerate = separation < MIN_HAND_SEPARATION || anchorLength < MIN_ANCHOR_SEPARATION;
8343
+ const base = primary.quaternion.clone().multiply(basis.primaryHandOffset);
8344
+ let quaternion;
8345
+ if (options.rotationMode === "primary" || degenerate) {
8346
+ quaternion = base;
8347
+ } else {
8348
+ const axisLocal = anchorDelta.clone().normalize();
8349
+ const currentAxis = axisLocal.clone().applyQuaternion(base).normalize();
8350
+ const desiredAxis = new THREE26__namespace.Vector3().subVectors(secondary.position, primary.position).normalize();
8351
+ const correction = new THREE26__namespace.Quaternion().setFromUnitVectors(
8352
+ currentAxis,
8353
+ desiredAxis
8354
+ );
8355
+ quaternion = correction.multiply(base);
8356
+ }
8357
+ const anchorOffset = basis.primaryLocal.clone().multiply(scale).applyQuaternion(quaternion);
8358
+ const position = primary.position.clone().sub(anchorOffset);
8359
+ return { position, quaternion, scale, degenerate };
8360
+ }
8361
+ __name(solveTwoHandTransform, "solveTwoHandTransform");
8267
8362
 
8268
8363
  // core/systems/XRInteractionSystem.ts
8269
8364
  var RAYLESS_HOLD_DISTANCE = 0.5;
8365
+ function quatFromEulerVec(r) {
8366
+ return new THREE26__namespace.Quaternion().setFromEuler(new THREE26__namespace.Euler(r.x, r.y, r.z));
8367
+ }
8368
+ __name(quatFromEulerVec, "quatFromEulerVec");
8369
+ function writeEuler(target, q) {
8370
+ const euler = new THREE26__namespace.Euler().setFromQuaternion(q);
8371
+ target.x = euler.x;
8372
+ target.y = euler.y;
8373
+ target.z = euler.z;
8374
+ }
8375
+ __name(writeEuler, "writeEuler");
8270
8376
  var _XRInteractionSystem = class _XRInteractionSystem {
8271
8377
  constructor(inputSystem) {
8272
- this.raycaster = new THREE14__namespace.Raycaster();
8378
+ this.raycaster = new THREE26__namespace.Raycaster();
8273
8379
  this.grabs = /* @__PURE__ */ new Map();
8274
8380
  this.hoveredEntityId = null;
8275
8381
  /** Monotonic seconds, accumulated from deltaTime for velocity sampling. */
@@ -8292,7 +8398,6 @@ var _XRInteractionSystem = class _XRInteractionSystem {
8292
8398
  }
8293
8399
  const held = this.grabs.get(input);
8294
8400
  if (held) {
8295
- this.moveHeld(world, input, held, deltaTime);
8296
8401
  if (this.wantsRelease(world, input, held)) {
8297
8402
  this.release(world, input);
8298
8403
  }
@@ -8313,9 +8418,122 @@ var _XRInteractionSystem = class _XRInteractionSystem {
8313
8418
  /* starting */
8314
8419
  true
8315
8420
  )) {
8316
- this.grab(world, input, candidate.entityId, candidate.viaDistance);
8421
+ this.tryGrab(world, input, candidate.entityId, candidate.viaDistance);
8317
8422
  }
8318
8423
  }
8424
+ this.moveAllHeld(world, deltaTime);
8425
+ }
8426
+ /** Hands currently holding an entity. */
8427
+ holdersOf(entityId) {
8428
+ const holders = [];
8429
+ for (const [input, record] of this.grabs) {
8430
+ if (record.entityId === entityId) holders.push({ input, record });
8431
+ }
8432
+ return holders;
8433
+ }
8434
+ /**
8435
+ * Route a new grab: first hand, hand-off, or second hand.
8436
+ *
8437
+ * Which of those happens is the object's choice (`grabHands`), not the
8438
+ * hand's — a ball should pass between hands, a rifle should be held by both,
8439
+ * and a lever should stay with whoever grabbed it first.
8440
+ */
8441
+ tryGrab(world, input, entityId, viaDistance) {
8442
+ const interactable = world.getComponent(entityId, XRInteractableComponent);
8443
+ if (!interactable) return;
8444
+ const holders = this.holdersOf(entityId);
8445
+ if (holders.length === 0) {
8446
+ this.grab(world, input, entityId, viaDistance, "primary");
8447
+ return;
8448
+ }
8449
+ if (holders.some((holder) => holder.input === input)) return;
8450
+ if (interactable.grabHands === "single") return;
8451
+ if (interactable.grabHands === "handOff") {
8452
+ const previous = holders[0];
8453
+ this.grabs.delete(previous.input);
8454
+ const record = previous.record;
8455
+ record.role = "primary";
8456
+ record.twoHand = null;
8457
+ this.reanchor(world, input, record, interactable);
8458
+ this.grabs.set(input, record);
8459
+ this.dispatch(world, entityId, (b) => b.onGrab(input));
8460
+ return;
8461
+ }
8462
+ if (holders.length >= 2) return;
8463
+ this.grab(world, input, entityId, viaDistance, "secondary");
8464
+ this.beginTwoHand(world, entityId);
8465
+ }
8466
+ /**
8467
+ * Re-derive a record's hold from where the object is NOW.
8468
+ *
8469
+ * Used on hand-off and on promotion after the primary lets go. Without it the
8470
+ * object snaps to whatever offset the previous hand had, which reads as the
8471
+ * object jumping out of your grip at the moment you take it.
8472
+ */
8473
+ reanchor(world, input, record, interactable) {
8474
+ const transform = world.getComponent(record.entityId, TransformComponent);
8475
+ if (!transform) return;
8476
+ const hand = this.handPosition(input);
8477
+ const handQuaternion = this.handQuaternion(input);
8478
+ const objectQuaternion = quatFromEulerVec(transform.rotation);
8479
+ record.offset = new THREE26__namespace.Vector3(
8480
+ transform.position.x - hand.x,
8481
+ transform.position.y - hand.y,
8482
+ transform.position.z - hand.z
8483
+ );
8484
+ record.handRotationOffset = handQuaternion.clone().invert().multiply(objectQuaternion);
8485
+ record.remote = false;
8486
+ record.tracker.clear();
8487
+ record.tracker.record(hand, this.elapsed);
8488
+ record.lastHandQuaternion = handQuaternion.clone();
8489
+ if (record.attachLocal && interactable.attachPoints.length === 0) {
8490
+ record.attachLocal = null;
8491
+ record.attachQuaternion = null;
8492
+ record.attachPointId = null;
8493
+ }
8494
+ }
8495
+ /** Capture the two-hand basis once both hands are on the object. */
8496
+ beginTwoHand(world, entityId) {
8497
+ const holders = this.holdersOf(entityId);
8498
+ if (holders.length !== 2) return;
8499
+ const primary = holders.find((h) => h.record.role === "primary");
8500
+ const secondary = holders.find((h) => h.record.role === "secondary");
8501
+ if (!primary || !secondary) return;
8502
+ const transform = world.getComponent(entityId, TransformComponent);
8503
+ if (!transform) return;
8504
+ const primaryHand = this.handPosition(primary.input);
8505
+ const secondaryHand = this.handPosition(secondary.input);
8506
+ const primaryLocal = primary.record.attachLocal?.clone() ?? this.objectLocalPoint(transform, primaryHand);
8507
+ const secondaryLocal = secondary.record.attachLocal?.clone() ?? this.objectLocalPoint(transform, secondaryHand);
8508
+ primary.record.twoHand = {
8509
+ primaryLocal,
8510
+ secondaryLocal,
8511
+ initialScale: new THREE26__namespace.Vector3(
8512
+ transform.scale.x,
8513
+ transform.scale.y,
8514
+ transform.scale.z
8515
+ ),
8516
+ initialSeparation: primaryHand.distanceTo(secondaryHand),
8517
+ // How the object sits relative to the anchoring hand right now, so the
8518
+ // two-hand solve picks up exactly where the one-hand hold left off.
8519
+ primaryHandOffset: this.handQuaternion(primary.input).invert().multiply(quatFromEulerVec(transform.rotation)),
8520
+ initialQuaternion: quatFromEulerVec(transform.rotation)
8521
+ };
8522
+ this.dispatch(world, entityId, (b) => b.onSecondaryGrab(secondary.input));
8523
+ }
8524
+ /** World point → the object's UNSCALED local space. */
8525
+ objectLocalPoint(transform, worldPoint) {
8526
+ const local = worldPoint.clone().sub(
8527
+ new THREE26__namespace.Vector3(
8528
+ transform.position.x,
8529
+ transform.position.y,
8530
+ transform.position.z
8531
+ )
8532
+ ).applyQuaternion(quatFromEulerVec(transform.rotation).invert());
8533
+ local.x /= transform.scale.x || 1;
8534
+ local.y /= transform.scale.y || 1;
8535
+ local.z /= transform.scale.z || 1;
8536
+ return local;
8319
8537
  }
8320
8538
  /** Whether the grab gesture for this object is currently starting. */
8321
8539
  gestureMatches(input, interactable, starting) {
@@ -8364,7 +8582,7 @@ var _XRInteractionSystem = class _XRInteractionSystem {
8364
8582
  );
8365
8583
  if (!interactable2) continue;
8366
8584
  if (interactable2.grabReach === "distance") continue;
8367
- const position = new THREE14__namespace.Vector3();
8585
+ const position = new THREE26__namespace.Vector3();
8368
8586
  entry.object.getWorldPosition(position);
8369
8587
  const distance = position.distanceTo(hand);
8370
8588
  if (distance <= interactable2.grabRadius && distance < nearestDistance) {
@@ -8412,7 +8630,52 @@ var _XRInteractionSystem = class _XRInteractionSystem {
8412
8630
  }
8413
8631
  return nearestId;
8414
8632
  }
8415
- grab(world, input, entityId, viaDistance) {
8633
+ /**
8634
+ * Pick the authored hold this hand should take.
8635
+ *
8636
+ * Filters by hand and by role — that is what makes "the trigger hand goes on
8637
+ * the grip" hold regardless of which hand reaches first — then takes the
8638
+ * nearest remaining one so grabbing near the foregrip picks the foregrip.
8639
+ */
8640
+ chooseAttachPoint(world, input, entityId, interactable, role) {
8641
+ if (interactable.attachPoints.length === 0) return null;
8642
+ const transform = world.getComponent(entityId, TransformComponent);
8643
+ if (!transform) return null;
8644
+ const taken = new Set(
8645
+ this.holdersOf(entityId).map((holder) => holder.record.attachPointId).filter((id) => id !== null)
8646
+ );
8647
+ const hand = this.handPosition(input);
8648
+ const objectPosition = new THREE26__namespace.Vector3(
8649
+ transform.position.x,
8650
+ transform.position.y,
8651
+ transform.position.z
8652
+ );
8653
+ const objectQuaternion = quatFromEulerVec(transform.rotation);
8654
+ const scale = new THREE26__namespace.Vector3(
8655
+ transform.scale.x,
8656
+ transform.scale.y,
8657
+ transform.scale.z
8658
+ );
8659
+ let best = null;
8660
+ let bestDistance = Number.POSITIVE_INFINITY;
8661
+ for (const point of interactable.attachPoints) {
8662
+ if (taken.has(point.id)) continue;
8663
+ if (point.hand !== "any" && point.hand !== input.handedness) continue;
8664
+ if (point.role !== "any" && point.role !== role) continue;
8665
+ const world3 = new THREE26__namespace.Vector3(
8666
+ point.position.x,
8667
+ point.position.y,
8668
+ point.position.z
8669
+ ).multiply(scale).applyQuaternion(objectQuaternion).add(objectPosition);
8670
+ const distance = world3.distanceTo(hand);
8671
+ if (distance < bestDistance) {
8672
+ bestDistance = distance;
8673
+ best = point;
8674
+ }
8675
+ }
8676
+ return best;
8677
+ }
8678
+ grab(world, input, entityId, viaDistance, role) {
8416
8679
  const transform = world.getComponent(entityId, TransformComponent);
8417
8680
  const interactable = world.getComponent(entityId, XRInteractableComponent);
8418
8681
  if (!transform || !interactable) return;
@@ -8422,21 +8685,21 @@ var _XRInteractionSystem = class _XRInteractionSystem {
8422
8685
  let offset;
8423
8686
  let remoteDistance = 0;
8424
8687
  if (remote) {
8425
- const position = new THREE14__namespace.Vector3(
8688
+ const position = new THREE26__namespace.Vector3(
8426
8689
  transform.position.x,
8427
8690
  transform.position.y,
8428
8691
  transform.position.z
8429
8692
  );
8430
8693
  remoteDistance = position.distanceTo(input.rayOrigin);
8431
- offset = new THREE14__namespace.Vector3();
8694
+ offset = new THREE26__namespace.Vector3();
8432
8695
  } else if (viaDistance) {
8433
- offset = new THREE14__namespace.Vector3(
8696
+ offset = new THREE26__namespace.Vector3(
8434
8697
  interactable.grabOffsetPosition.x,
8435
8698
  interactable.grabOffsetPosition.y,
8436
8699
  interactable.grabOffsetPosition.z
8437
8700
  );
8438
8701
  } else {
8439
- offset = new THREE14__namespace.Vector3(
8702
+ offset = new THREE26__namespace.Vector3(
8440
8703
  transform.position.x - hand.x,
8441
8704
  transform.position.y - hand.y,
8442
8705
  transform.position.z - hand.z
@@ -8450,11 +8713,30 @@ var _XRInteractionSystem = class _XRInteractionSystem {
8450
8713
  }
8451
8714
  const tracker = new ThrowVelocityTracker();
8452
8715
  tracker.record(hand, this.elapsed);
8716
+ const attachPoint = this.chooseAttachPoint(
8717
+ world,
8718
+ input,
8719
+ entityId,
8720
+ interactable,
8721
+ role
8722
+ );
8723
+ const objectQuaternion = quatFromEulerVec(transform.rotation);
8724
+ const handRotationOffset = handQuaternion.clone().invert().multiply(objectQuaternion);
8453
8725
  this.grabs.set(input, {
8454
8726
  entityId,
8727
+ role,
8728
+ attachPointId: attachPoint?.id ?? null,
8729
+ attachLocal: attachPoint ? new THREE26__namespace.Vector3(
8730
+ attachPoint.position.x,
8731
+ attachPoint.position.y,
8732
+ attachPoint.position.z
8733
+ ) : null,
8734
+ attachQuaternion: attachPoint ? quatFromEulerVec(attachPoint.rotation) : null,
8735
+ handRotationOffset,
8736
+ twoHand: null,
8455
8737
  offset,
8456
- rotationOffset: new THREE14__namespace.Quaternion().setFromEuler(
8457
- new THREE14__namespace.Euler(
8738
+ rotationOffset: new THREE26__namespace.Quaternion().setFromEuler(
8739
+ new THREE26__namespace.Euler(
8458
8740
  interactable.grabOffsetRotation.x,
8459
8741
  interactable.grabOffsetRotation.y,
8460
8742
  interactable.grabOffsetRotation.z
@@ -8465,33 +8747,110 @@ var _XRInteractionSystem = class _XRInteractionSystem {
8465
8747
  restoreBodyType,
8466
8748
  tracker,
8467
8749
  lastHandQuaternion: handQuaternion.clone(),
8468
- angularVelocity: new THREE14__namespace.Vector3()
8750
+ angularVelocity: new THREE26__namespace.Vector3()
8469
8751
  });
8470
- this.dispatch(world, entityId, (b) => b.onGrab(input));
8752
+ if (role === "primary") {
8753
+ this.dispatch(world, entityId, (b) => b.onGrab(input));
8754
+ }
8755
+ }
8756
+ /** Drive every held object, once each, after grabs and releases settle. */
8757
+ moveAllHeld(world, deltaTime) {
8758
+ const done = /* @__PURE__ */ new Set();
8759
+ for (const [input, record] of this.grabs) {
8760
+ if (done.has(record.entityId)) continue;
8761
+ done.add(record.entityId);
8762
+ const holders = this.holdersOf(record.entityId);
8763
+ if (holders.length >= 2) {
8764
+ this.moveTwoHand(world, record.entityId, holders, deltaTime);
8765
+ } else {
8766
+ this.moveHeld(world, input, record, deltaTime);
8767
+ }
8768
+ }
8769
+ }
8770
+ /** Solve and apply a two-hand hold. */
8771
+ moveTwoHand(world, entityId, holders, deltaTime) {
8772
+ const primary = holders.find((h) => h.record.role === "primary");
8773
+ const secondary = holders.find((h) => h.record.role === "secondary");
8774
+ const transform = world.getComponent(entityId, TransformComponent);
8775
+ const interactable = world.getComponent(entityId, XRInteractableComponent);
8776
+ const basis = primary?.record.twoHand ?? null;
8777
+ if (!primary || !secondary || !transform || !interactable || !basis) {
8778
+ if (primary) {
8779
+ this.moveHeld(world, primary.input, primary.record, deltaTime);
8780
+ }
8781
+ return;
8782
+ }
8783
+ const primaryHand = this.handPosition(primary.input);
8784
+ const primaryQuaternion = this.handQuaternion(primary.input);
8785
+ const solved = solveTwoHandTransform(
8786
+ { position: primaryHand, quaternion: primaryQuaternion },
8787
+ {
8788
+ position: this.handPosition(secondary.input),
8789
+ quaternion: this.handQuaternion(secondary.input)
8790
+ },
8791
+ basis,
8792
+ {
8793
+ rotationMode: interactable.twoHandRotation,
8794
+ allowScale: interactable.allowTwoHandScale,
8795
+ minScale: interactable.minScale,
8796
+ maxScale: interactable.maxScale
8797
+ }
8798
+ );
8799
+ transform.position.x = solved.position.x;
8800
+ transform.position.y = solved.position.y;
8801
+ transform.position.z = solved.position.z;
8802
+ writeEuler(transform.rotation, solved.quaternion);
8803
+ if (interactable.allowTwoHandScale) {
8804
+ transform.scale.x = solved.scale.x;
8805
+ transform.scale.y = solved.scale.y;
8806
+ transform.scale.z = solved.scale.z;
8807
+ }
8808
+ primary.record.tracker.record(primaryHand, this.elapsed);
8809
+ primary.record.angularVelocity = angularVelocityFrom(
8810
+ primary.record.lastHandQuaternion,
8811
+ primaryQuaternion,
8812
+ deltaTime
8813
+ );
8814
+ primary.record.lastHandQuaternion = primaryQuaternion.clone();
8471
8815
  }
8472
8816
  moveHeld(world, input, held, deltaTime) {
8473
8817
  const transform = world.getComponent(held.entityId, TransformComponent);
8474
8818
  if (!transform) return;
8475
8819
  const hand = this.handPosition(input);
8820
+ const handQuaternion = this.handQuaternion(input);
8821
+ const objectQuaternion = held.attachQuaternion ? handQuaternion.clone().multiply(held.rotationOffset).multiply(held.attachQuaternion.clone().invert()) : handQuaternion.clone().multiply(held.handRotationOffset);
8476
8822
  if (held.remote) {
8477
- const target = new THREE14__namespace.Vector3().copy(input.rayDirection).multiplyScalar(held.remoteDistance).add(input.rayOrigin);
8823
+ const target = new THREE26__namespace.Vector3().copy(input.rayDirection).multiplyScalar(held.remoteDistance).add(input.rayOrigin);
8478
8824
  transform.position.x = target.x;
8479
8825
  transform.position.y = target.y;
8480
8826
  transform.position.z = target.z;
8827
+ writeEuler(transform.rotation, objectQuaternion);
8828
+ } else if (held.attachLocal) {
8829
+ const anchor = held.attachLocal.clone().multiply(
8830
+ new THREE26__namespace.Vector3(
8831
+ transform.scale.x,
8832
+ transform.scale.y,
8833
+ transform.scale.z
8834
+ )
8835
+ ).applyQuaternion(objectQuaternion);
8836
+ transform.position.x = hand.x - anchor.x;
8837
+ transform.position.y = hand.y - anchor.y;
8838
+ transform.position.z = hand.z - anchor.z;
8839
+ writeEuler(transform.rotation, objectQuaternion);
8481
8840
  } else {
8482
8841
  transform.position.x = hand.x + held.offset.x;
8483
8842
  transform.position.y = hand.y + held.offset.y;
8484
8843
  transform.position.z = hand.z + held.offset.z;
8844
+ writeEuler(transform.rotation, objectQuaternion);
8485
8845
  }
8486
8846
  held.tracker.record(
8487
- held.remote ? new THREE14__namespace.Vector3(
8847
+ held.remote ? new THREE26__namespace.Vector3(
8488
8848
  transform.position.x,
8489
8849
  transform.position.y,
8490
8850
  transform.position.z
8491
8851
  ) : hand,
8492
8852
  this.elapsed
8493
8853
  );
8494
- const handQuaternion = this.handQuaternion(input);
8495
8854
  held.angularVelocity = angularVelocityFrom(
8496
8855
  held.lastHandQuaternion,
8497
8856
  handQuaternion,
@@ -8507,6 +8866,30 @@ var _XRInteractionSystem = class _XRInteractionSystem {
8507
8866
  held.entityId,
8508
8867
  XRInteractableComponent
8509
8868
  );
8869
+ const remaining = this.holdersOf(held.entityId);
8870
+ if (remaining.length > 0 && interactable) {
8871
+ if (held.role === "secondary") {
8872
+ const primary = remaining.find((h) => h.record.role === "primary");
8873
+ if (primary) {
8874
+ primary.record.twoHand = null;
8875
+ this.reanchor(world, primary.input, primary.record, interactable);
8876
+ }
8877
+ this.dispatch(
8878
+ world,
8879
+ held.entityId,
8880
+ (b) => b.onSecondaryRelease(input)
8881
+ );
8882
+ } else {
8883
+ const next = remaining[0];
8884
+ next.record.role = "primary";
8885
+ next.record.twoHand = null;
8886
+ next.record.restoreBodyType = held.restoreBodyType;
8887
+ this.reanchor(world, next.input, next.record, interactable);
8888
+ this.dispatch(world, held.entityId, (b) => b.onRelease(input));
8889
+ }
8890
+ held.tracker.clear();
8891
+ return;
8892
+ }
8510
8893
  const physics = world.getComponent(held.entityId, PhysicsComponent);
8511
8894
  if (held.restoreBodyType !== null && physics) {
8512
8895
  physics.values.rigidbody.type = held.restoreBodyType;
@@ -8540,7 +8923,7 @@ var _XRInteractionSystem = class _XRInteractionSystem {
8540
8923
  */
8541
8924
  handPosition(input) {
8542
8925
  if (input.gripPosition) return input.gripPosition;
8543
- return new THREE14__namespace.Vector3().copy(input.rayDirection).multiplyScalar(RAYLESS_HOLD_DISTANCE).add(input.rayOrigin);
8926
+ return new THREE26__namespace.Vector3().copy(input.rayDirection).multiplyScalar(RAYLESS_HOLD_DISTANCE).add(input.rayOrigin);
8544
8927
  }
8545
8928
  /**
8546
8929
  * Hand orientation. Grip-less sources (gaze / transient-pointer) have none,
@@ -8548,8 +8931,8 @@ var _XRInteractionSystem = class _XRInteractionSystem {
8548
8931
  */
8549
8932
  handQuaternion(input) {
8550
8933
  if (input.gripQuaternion) return input.gripQuaternion.clone();
8551
- return new THREE14__namespace.Quaternion().setFromUnitVectors(
8552
- new THREE14__namespace.Vector3(0, 0, -1),
8934
+ return new THREE26__namespace.Quaternion().setFromUnitVectors(
8935
+ new THREE26__namespace.Vector3(0, 0, -1),
8553
8936
  input.rayDirection.clone().normalize()
8554
8937
  );
8555
8938
  }
@@ -8574,6 +8957,29 @@ var _XRInteractionSystem = class _XRInteractionSystem {
8574
8957
  isGrabbing() {
8575
8958
  return this.grabs.size > 0;
8576
8959
  }
8960
+ /**
8961
+ * How an entity is currently held.
8962
+ *
8963
+ * Exposed for scripts: a Behaviour can poll this in `onUpdate` to drive
8964
+ * two-hand-specific behaviour — showing a bipod when both hands are on a
8965
+ * weapon, reading the live hand separation to gate a gesture, or reacting to
8966
+ * the scale a pull-apart produced. Returns null when nothing holds it.
8967
+ */
8968
+ getGrabInfo(entityId) {
8969
+ const holders = this.holdersOf(entityId);
8970
+ if (holders.length === 0) return null;
8971
+ const primary = holders.find((h) => h.record.role === "primary");
8972
+ const secondary = holders.find((h) => h.record.role === "secondary");
8973
+ return {
8974
+ hands: holders.length,
8975
+ primaryHandedness: primary?.input.handedness ?? null,
8976
+ secondaryHandedness: secondary?.input.handedness ?? null,
8977
+ handSeparation: primary && secondary ? this.handPosition(primary.input).distanceTo(
8978
+ this.handPosition(secondary.input)
8979
+ ) : null,
8980
+ attachPointIds: holders.map((h) => h.record.attachPointId)
8981
+ };
8982
+ }
8577
8983
  };
8578
8984
  __name(_XRInteractionSystem, "XRInteractionSystem");
8579
8985
  var XRInteractionSystem = _XRInteractionSystem;
@@ -8591,7 +8997,7 @@ function sampleTeleportArc(origin, direction, out = [], options) {
8591
8997
  for (let i = 0; i < steps; i += 1) {
8592
8998
  const t = i / (steps - 1) * maxTime;
8593
8999
  out.push(
8594
- new THREE14__namespace.Vector3(
9000
+ new THREE26__namespace.Vector3(
8595
9001
  origin.x + velocity.x * t,
8596
9002
  origin.y + velocity.y * t - 0.5 * gravity * t * t,
8597
9003
  origin.z + velocity.z * t
@@ -8603,11 +9009,11 @@ function sampleTeleportArc(origin, direction, out = [], options) {
8603
9009
  __name(sampleTeleportArc, "sampleTeleportArc");
8604
9010
 
8605
9011
  // core/systems/XRLocomotionSystem.ts
8606
- var UP = new THREE14__namespace.Vector3(0, 1, 0);
9012
+ var UP = new THREE26__namespace.Vector3(0, 1, 0);
8607
9013
  var AXIS_DEADZONE = 0.5;
8608
9014
  var _XRLocomotionSystem = class _XRLocomotionSystem {
8609
9015
  constructor(inputSystem) {
8610
- this.raycaster = new THREE14__namespace.Raycaster();
9016
+ this.raycaster = new THREE26__namespace.Raycaster();
8611
9017
  /** Per-source latch so one stick push yields exactly one snap turn. */
8612
9018
  this.turnLatched = /* @__PURE__ */ new WeakSet();
8613
9019
  /** Reused arc buffer — aiming runs every frame. */
@@ -8716,7 +9122,7 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
8716
9122
  }
8717
9123
  if (this.turnLatched.has(source)) continue;
8718
9124
  this.turnLatched.add(source);
8719
- transform.rotation.y -= Math.sign(x) * THREE14__namespace.MathUtils.degToRad(rig.snapTurnDegrees);
9125
+ transform.rotation.y -= Math.sign(x) * THREE26__namespace.MathUtils.degToRad(rig.snapTurnDegrees);
8720
9126
  }
8721
9127
  }
8722
9128
  applySmoothMove(world, rig, transform, inputs, deltaTime) {
@@ -8726,12 +9132,12 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
8726
9132
  const y = input.axes[1] ?? 0;
8727
9133
  if (Math.abs(x) < 0.15 && Math.abs(y) < 0.15) continue;
8728
9134
  const camera = world.getCamera();
8729
- const forward = new THREE14__namespace.Vector3();
9135
+ const forward = new THREE26__namespace.Vector3();
8730
9136
  camera.getWorldDirection(forward);
8731
9137
  forward.y = 0;
8732
9138
  if (forward.lengthSq() < 1e-6) continue;
8733
9139
  forward.normalize();
8734
- const right = new THREE14__namespace.Vector3().crossVectors(forward, UP).normalize();
9140
+ const right = new THREE26__namespace.Vector3().crossVectors(forward, UP).normalize();
8735
9141
  const step = rig.moveSpeed * Math.max(0, deltaTime);
8736
9142
  transform.position.x += (forward.x * -y + right.x * x) * step;
8737
9143
  transform.position.z += (forward.z * -y + right.z * x) * step;
@@ -8796,7 +9202,7 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
8796
9202
  for (let i = 1; i < points.length; i += 1) {
8797
9203
  const from = points[i - 1];
8798
9204
  const to = points[i];
8799
- const delta = new THREE14__namespace.Vector3().subVectors(to, from);
9205
+ const delta = new THREE26__namespace.Vector3().subVectors(to, from);
8800
9206
  const distance = delta.length();
8801
9207
  if (distance < 1e-6) continue;
8802
9208
  this.raycaster.set(from, delta.divideScalar(distance));
@@ -9004,9 +9410,9 @@ var XRSessionSystem = _XRSessionSystem;
9004
9410
  function buildGeometry2(area) {
9005
9411
  if (area.shape === "circle") {
9006
9412
  const radius = Math.max(5e-3, area.width / 2);
9007
- return new THREE14__namespace.CircleGeometry(radius, 48);
9413
+ return new THREE26__namespace.CircleGeometry(radius, 48);
9008
9414
  }
9009
- return new THREE14__namespace.PlaneGeometry(
9415
+ return new THREE26__namespace.PlaneGeometry(
9010
9416
  Math.max(0.01, area.width),
9011
9417
  Math.max(0.01, area.depth)
9012
9418
  );
@@ -9029,7 +9435,7 @@ var _VRTeleportAreaSystem = class _VRTeleportAreaSystem {
9029
9435
  for (const entityId of entityIds) {
9030
9436
  const area = world.getComponent(entityId, VRTeleportAreaComponent);
9031
9437
  const object = world.getComponent(entityId, Object3DRef)?.object;
9032
- if (!area || !(object instanceof THREE14__namespace.Mesh)) continue;
9438
+ if (!area || !(object instanceof THREE26__namespace.Mesh)) continue;
9033
9439
  const signature = signatureOf(area);
9034
9440
  if (this.signatures.get(entityId) === signature) continue;
9035
9441
  this.signatures.set(entityId, signature);
@@ -9041,18 +9447,18 @@ var _VRTeleportAreaSystem = class _VRTeleportAreaSystem {
9041
9447
  __name(_VRTeleportAreaSystem, "VRTeleportAreaSystem");
9042
9448
  var VRTeleportAreaSystem = _VRTeleportAreaSystem;
9043
9449
  function createHandMaterial(preset, options) {
9044
- const color = new THREE14__namespace.Color(options.color);
9450
+ const color = new THREE26__namespace.Color(options.color);
9045
9451
  switch (preset) {
9046
9452
  case "ghost":
9047
- return new THREE14__namespace.MeshBasicMaterial({
9453
+ return new THREE26__namespace.MeshBasicMaterial({
9048
9454
  color,
9049
9455
  transparent: true,
9050
9456
  opacity: Math.min(1, Math.max(0.05, options.opacity * 0.45)),
9051
9457
  depthWrite: false,
9052
- side: THREE14__namespace.DoubleSide
9458
+ side: THREE26__namespace.DoubleSide
9053
9459
  });
9054
9460
  case "neon":
9055
- return new THREE14__namespace.MeshStandardMaterial({
9461
+ return new THREE26__namespace.MeshStandardMaterial({
9056
9462
  color,
9057
9463
  emissive: color,
9058
9464
  emissiveIntensity: Math.max(0.5, options.emissiveIntensity || 2),
@@ -9062,7 +9468,7 @@ function createHandMaterial(preset, options) {
9062
9468
  opacity: options.opacity
9063
9469
  });
9064
9470
  case "skeleton":
9065
- return new THREE14__namespace.MeshBasicMaterial({
9471
+ return new THREE26__namespace.MeshBasicMaterial({
9066
9472
  color,
9067
9473
  wireframe: true,
9068
9474
  transparent: true,
@@ -9070,7 +9476,7 @@ function createHandMaterial(preset, options) {
9070
9476
  });
9071
9477
  case "custom":
9072
9478
  case "default":
9073
- return new THREE14__namespace.MeshStandardMaterial({
9479
+ return new THREE26__namespace.MeshStandardMaterial({
9074
9480
  color,
9075
9481
  roughness: 0.85,
9076
9482
  metalness: 0,
@@ -9078,10 +9484,10 @@ function createHandMaterial(preset, options) {
9078
9484
  emissiveIntensity: Math.max(0, options.emissiveIntensity),
9079
9485
  transparent: options.opacity < 1,
9080
9486
  opacity: options.opacity,
9081
- side: THREE14__namespace.DoubleSide
9487
+ side: THREE26__namespace.DoubleSide
9082
9488
  });
9083
9489
  default: {
9084
- return new THREE14__namespace.MeshStandardMaterial({ color });
9490
+ return new THREE26__namespace.MeshStandardMaterial({ color });
9085
9491
  }
9086
9492
  }
9087
9493
  }
@@ -9102,7 +9508,7 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
9102
9508
  constructor(options) {
9103
9509
  this.controllerModelFactory = new XRControllerModelFactory_js.XRControllerModelFactory();
9104
9510
  this.handModelFactory = new XRHandModelFactory_js.XRHandModelFactory();
9105
- this.group = new THREE14__namespace.Group();
9511
+ this.group = new THREE26__namespace.Group();
9106
9512
  this.slots = /* @__PURE__ */ new Map();
9107
9513
  this.attachedTo = null;
9108
9514
  /** Last applied preset signature, so materials rebuild only on real change. */
@@ -9251,17 +9657,17 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
9251
9657
  this.attachedTo = target;
9252
9658
  }
9253
9659
  createRay() {
9254
- const geometry = new THREE14__namespace.BufferGeometry().setFromPoints([
9255
- new THREE14__namespace.Vector3(0, 0, 0),
9256
- new THREE14__namespace.Vector3(0, 0, -5)
9660
+ const geometry = new THREE26__namespace.BufferGeometry().setFromPoints([
9661
+ new THREE26__namespace.Vector3(0, 0, 0),
9662
+ new THREE26__namespace.Vector3(0, 0, -5)
9257
9663
  ]);
9258
- const material = new THREE14__namespace.LineBasicMaterial({
9664
+ const material = new THREE26__namespace.LineBasicMaterial({
9259
9665
  color: "#4da3ff",
9260
9666
  transparent: true,
9261
9667
  opacity: 0.6,
9262
9668
  depthTest: false
9263
9669
  });
9264
- const line = new THREE14__namespace.Line(geometry, material);
9670
+ const line = new THREE26__namespace.Line(geometry, material);
9265
9671
  line.name = "XRPointerRay";
9266
9672
  line.renderOrder = 999;
9267
9673
  line.visible = false;
@@ -9290,23 +9696,23 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
9290
9696
  __name(_XRControllerVisualSystem, "XRControllerVisualSystem");
9291
9697
  var XRControllerVisualSystem = _XRControllerVisualSystem;
9292
9698
  var MARKER_RADIUS = 0.28;
9293
- var ACCENT = new THREE14__namespace.Color("#4da3ff");
9294
- var BLOCKED = new THREE14__namespace.Color("#ff5a5a");
9699
+ var ACCENT = new THREE26__namespace.Color("#4da3ff");
9700
+ var BLOCKED = new THREE26__namespace.Color("#ff5a5a");
9295
9701
  var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
9296
9702
  constructor(locomotionSystem) {
9297
- this.group = new THREE14__namespace.Group();
9298
- this.arcGeometry = new THREE14__namespace.BufferGeometry();
9299
- this.marker = new THREE14__namespace.Group();
9703
+ this.group = new THREE26__namespace.Group();
9704
+ this.arcGeometry = new THREE26__namespace.BufferGeometry();
9705
+ this.marker = new THREE26__namespace.Group();
9300
9706
  this.attached = false;
9301
9707
  this.locomotionSystem = locomotionSystem;
9302
9708
  this.group.name = "XRTeleportVisuals";
9303
9709
  this.group.userData.ecsPreviewHidden = true;
9304
- const arcMaterial = new THREE14__namespace.LineBasicMaterial({
9710
+ const arcMaterial = new THREE26__namespace.LineBasicMaterial({
9305
9711
  vertexColors: true,
9306
9712
  transparent: true,
9307
9713
  depthTest: false
9308
9714
  });
9309
- this.arc = new THREE14__namespace.Line(this.arcGeometry, arcMaterial);
9715
+ this.arc = new THREE26__namespace.Line(this.arcGeometry, arcMaterial);
9310
9716
  this.arc.frustumCulled = false;
9311
9717
  this.arc.renderOrder = 998;
9312
9718
  this.group.add(this.arc);
@@ -9354,39 +9760,39 @@ var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
9354
9760
  }
9355
9761
  this.arcGeometry.setAttribute(
9356
9762
  "position",
9357
- new THREE14__namespace.BufferAttribute(positions, 3)
9763
+ new THREE26__namespace.BufferAttribute(positions, 3)
9358
9764
  );
9359
- this.arcGeometry.setAttribute("color", new THREE14__namespace.BufferAttribute(colors, 3));
9765
+ this.arcGeometry.setAttribute("color", new THREE26__namespace.BufferAttribute(colors, 3));
9360
9766
  this.arcGeometry.computeBoundingSphere();
9361
9767
  }
9362
9768
  createRing() {
9363
- const geometry = new THREE14__namespace.RingGeometry(
9769
+ const geometry = new THREE26__namespace.RingGeometry(
9364
9770
  MARKER_RADIUS * 0.72,
9365
9771
  MARKER_RADIUS,
9366
9772
  48
9367
9773
  );
9368
9774
  geometry.rotateX(-Math.PI / 2);
9369
- return new THREE14__namespace.Mesh(
9775
+ return new THREE26__namespace.Mesh(
9370
9776
  geometry,
9371
- new THREE14__namespace.MeshBasicMaterial({
9777
+ new THREE26__namespace.MeshBasicMaterial({
9372
9778
  color: ACCENT,
9373
9779
  transparent: true,
9374
9780
  opacity: 0.9,
9375
- side: THREE14__namespace.DoubleSide,
9781
+ side: THREE26__namespace.DoubleSide,
9376
9782
  depthTest: false
9377
9783
  })
9378
9784
  );
9379
9785
  }
9380
9786
  createDot() {
9381
- const geometry = new THREE14__namespace.CircleGeometry(MARKER_RADIUS * 0.16, 24);
9787
+ const geometry = new THREE26__namespace.CircleGeometry(MARKER_RADIUS * 0.16, 24);
9382
9788
  geometry.rotateX(-Math.PI / 2);
9383
- return new THREE14__namespace.Mesh(
9789
+ return new THREE26__namespace.Mesh(
9384
9790
  geometry,
9385
- new THREE14__namespace.MeshBasicMaterial({
9791
+ new THREE26__namespace.MeshBasicMaterial({
9386
9792
  color: ACCENT,
9387
9793
  transparent: true,
9388
9794
  opacity: 0.55,
9389
- side: THREE14__namespace.DoubleSide,
9795
+ side: THREE26__namespace.DoubleSide,
9390
9796
  depthTest: false
9391
9797
  })
9392
9798
  );
@@ -9488,7 +9894,7 @@ function boneDirections(joints, finger) {
9488
9894
  const from = joints[chain[i - 1]];
9489
9895
  const to = joints[chain[i]];
9490
9896
  if (!from || !to) return null;
9491
- const direction = new THREE14__namespace.Vector3().subVectors(to, from);
9897
+ const direction = new THREE26__namespace.Vector3().subVectors(to, from);
9492
9898
  if (direction.lengthSq() < 1e-12) return null;
9493
9899
  directions.push(direction.normalize());
9494
9900
  }
@@ -9561,8 +9967,8 @@ function computeSpread(joints, a, b) {
9561
9967
  const bBase = joints[METACARPAL_JOINTS[b]];
9562
9968
  const bTip = joints[TIP_JOINTS[b]];
9563
9969
  if (!aBase || !aTip || !bBase || !bTip) return null;
9564
- const dirA = new THREE14__namespace.Vector3().subVectors(aTip, aBase);
9565
- const dirB = new THREE14__namespace.Vector3().subVectors(bTip, bBase);
9970
+ const dirA = new THREE26__namespace.Vector3().subVectors(aTip, aBase);
9971
+ const dirB = new THREE26__namespace.Vector3().subVectors(bTip, bBase);
9566
9972
  if (dirA.lengthSq() < 1e-12 || dirB.lengthSq() < 1e-12) return null;
9567
9973
  return clamp01((1 - dirA.normalize().dot(dirB.normalize())) / 0.45);
9568
9974
  }
@@ -9572,18 +9978,18 @@ function computePalmPose(joints, handedness) {
9572
9978
  const indexBase = joints["index-finger-metacarpal"];
9573
9979
  const pinkyBase = joints["pinky-finger-metacarpal"];
9574
9980
  if (!wrist || !indexBase || !pinkyBase) return null;
9575
- const u = new THREE14__namespace.Vector3().subVectors(indexBase, wrist);
9576
- const v = new THREE14__namespace.Vector3().subVectors(pinkyBase, wrist);
9577
- const normal = new THREE14__namespace.Vector3().crossVectors(u, v);
9981
+ const u = new THREE26__namespace.Vector3().subVectors(indexBase, wrist);
9982
+ const v = new THREE26__namespace.Vector3().subVectors(pinkyBase, wrist);
9983
+ const normal = new THREE26__namespace.Vector3().crossVectors(u, v);
9578
9984
  if (normal.lengthSq() < 1e-12) return null;
9579
9985
  normal.normalize();
9580
9986
  if (handedness === "left") normal.multiplyScalar(-1);
9581
- const right = new THREE14__namespace.Vector3().subVectors(indexBase, pinkyBase);
9987
+ const right = new THREE26__namespace.Vector3().subVectors(indexBase, pinkyBase);
9582
9988
  if (right.lengthSq() < 1e-12) return null;
9583
9989
  right.normalize();
9584
9990
  if (handedness === "left") right.multiplyScalar(-1);
9585
- const up = new THREE14__namespace.Vector3().crossVectors(normal, right).normalize();
9586
- const center = new THREE14__namespace.Vector3().add(wrist).add(indexBase).add(pinkyBase).divideScalar(3);
9991
+ const up = new THREE26__namespace.Vector3().crossVectors(normal, right).normalize();
9992
+ const center = new THREE26__namespace.Vector3().add(wrist).add(indexBase).add(pinkyBase).divideScalar(3);
9587
9993
  return {
9588
9994
  center,
9589
9995
  normal,
@@ -9614,7 +10020,7 @@ function computeHandShape(joints, handedness) {
9614
10020
  const thumbTip = joints["thumb-tip"];
9615
10021
  let thumbDirection = null;
9616
10022
  if (thumbBase && thumbTip) {
9617
- const direction = new THREE14__namespace.Vector3().subVectors(thumbTip, thumbBase);
10023
+ const direction = new THREE26__namespace.Vector3().subVectors(thumbTip, thumbBase);
9618
10024
  if (direction.lengthSq() > 1e-12) thumbDirection = direction.normalize();
9619
10025
  }
9620
10026
  return {
@@ -9646,12 +10052,12 @@ function scoreAgainst(actual, target, tolerance) {
9646
10052
  }
9647
10053
  __name(scoreAgainst, "scoreAgainst");
9648
10054
  var WORLD_DIRECTIONS = {
9649
- up: new THREE14__namespace.Vector3(0, 1, 0),
9650
- down: new THREE14__namespace.Vector3(0, -1, 0),
9651
- forward: new THREE14__namespace.Vector3(0, 0, -1),
9652
- back: new THREE14__namespace.Vector3(0, 0, 1),
9653
- left: new THREE14__namespace.Vector3(-1, 0, 0),
9654
- right: new THREE14__namespace.Vector3(1, 0, 0)
10055
+ up: new THREE26__namespace.Vector3(0, 1, 0),
10056
+ down: new THREE26__namespace.Vector3(0, -1, 0),
10057
+ forward: new THREE26__namespace.Vector3(0, 0, -1),
10058
+ back: new THREE26__namespace.Vector3(0, 0, 1),
10059
+ left: new THREE26__namespace.Vector3(-1, 0, 0),
10060
+ right: new THREE26__namespace.Vector3(1, 0, 0)
9655
10061
  };
9656
10062
  function axisVector(shape, axis) {
9657
10063
  if (axis === "thumb") return shape.thumbDirection;
@@ -9666,7 +10072,7 @@ function resolveDirection(direction, shape, context) {
9666
10072
  const head = context?.headPosition;
9667
10073
  const origin = shape.palm?.center;
9668
10074
  if (!head || !origin) return null;
9669
- const toHead = new THREE14__namespace.Vector3().subVectors(head, origin);
10075
+ const toHead = new THREE26__namespace.Vector3().subVectors(head, origin);
9670
10076
  if (toHead.lengthSq() < 1e-12) return null;
9671
10077
  toHead.normalize();
9672
10078
  return direction === "toward-head" ? toHead : toHead.multiplyScalar(-1);
@@ -9716,8 +10122,8 @@ function matchHandPose(shape, definition, context) {
9716
10122
  if (!handAxis || !wanted) {
9717
10123
  consider(0, "orientation");
9718
10124
  } else {
9719
- const angle = THREE14__namespace.MathUtils.radToDeg(
9720
- Math.acos(THREE14__namespace.MathUtils.clamp(handAxis.dot(wanted), -1, 1))
10125
+ const angle = THREE26__namespace.MathUtils.radToDeg(
10126
+ Math.acos(THREE26__namespace.MathUtils.clamp(handAxis.dot(wanted), -1, 1))
9721
10127
  );
9722
10128
  const normalizedError = Math.max(0, angle - toleranceDegrees) / 90;
9723
10129
  consider(clamp01(1 - normalizedError / MATCH_FALLOFF), "orientation");
@@ -9795,7 +10201,7 @@ var _XRHandPoseSystem = class _XRHandPoseSystem {
9795
10201
  this.trackers = /* @__PURE__ */ new Map();
9796
10202
  this.shapes = /* @__PURE__ */ new Map();
9797
10203
  /** Reused so head-relative orientation checks allocate nothing per frame. */
9798
- this.headPosition = new THREE14__namespace.Vector3();
10204
+ this.headPosition = new THREE26__namespace.Vector3();
9799
10205
  this.elapsed = 0;
9800
10206
  this.inputSystem = inputSystem;
9801
10207
  }