@relu-interactives/spatial-ecs 0.3.8 → 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-LMTB4KQ4.js → chunk-O2HSIZFC.js} +591 -195
  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 +729 -312
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +29 -6
  29. package/dist/index.d.ts +29 -6
  30. package/dist/index.js +8 -8
  31. package/dist/systems/index.cjs +635 -220
  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-LMTB4KQ4.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++) {
@@ -5277,13 +5296,9 @@ function restorePostCreateComponents(world, objectManagementSystem, targetEntity
5277
5296
  runtimeMessage: typeof entry.runtimeMessage === "string" ? entry.runtimeMessage : void 0
5278
5297
  };
5279
5298
  }).filter((entry) => entry.className || entry.scriptUrl) : [];
5280
- if (!entries.length) {
5281
- return;
5299
+ if (entries.length) {
5300
+ world.addComponent(targetEntityId, new ScriptComponent(entries));
5282
5301
  }
5283
- world.addComponent(
5284
- targetEntityId,
5285
- new ScriptComponent(entries)
5286
- );
5287
5302
  }
5288
5303
  const sourceScriptObject = asRecord3(values.scriptObjectValues.get(sourceEntityId));
5289
5304
  if (sourceScriptObject) {
@@ -5332,10 +5347,14 @@ function restorePostCreateComponents(world, objectManagementSystem, targetEntity
5332
5347
  const sourceInteractable = asRecord3(
5333
5348
  values.xrInteractableValues.get(sourceEntityId)
5334
5349
  );
5335
- const interactable = world.getComponent(
5350
+ let interactable = world.getComponent(
5336
5351
  targetEntityId,
5337
5352
  XRInteractableComponent
5338
5353
  );
5354
+ if (sourceInteractable && !interactable) {
5355
+ interactable = new XRInteractableComponent();
5356
+ world.addComponent(targetEntityId, interactable);
5357
+ }
5339
5358
  if (sourceInteractable && interactable) {
5340
5359
  if (typeof sourceInteractable.enabled === "boolean") {
5341
5360
  interactable.enabled = sourceInteractable.enabled;
@@ -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
  }
@@ -5392,7 +5435,11 @@ function restorePostCreateComponents(world, objectManagementSystem, targetEntity
5392
5435
  const sourceHandPose = asRecord3(
5393
5436
  values.xrHandPoseValues.get(sourceEntityId)
5394
5437
  );
5395
- const handPose = world.getComponent(targetEntityId, XRHandPoseComponent);
5438
+ let handPose = world.getComponent(targetEntityId, XRHandPoseComponent);
5439
+ if (sourceHandPose && !handPose) {
5440
+ handPose = new XRHandPoseComponent();
5441
+ world.addComponent(targetEntityId, handPose);
5442
+ }
5396
5443
  if (sourceHandPose && handPose) {
5397
5444
  if (typeof sourceHandPose.enabled === "boolean") {
5398
5445
  handPose.enabled = sourceHandPose.enabled;
@@ -6565,7 +6612,7 @@ var _Behaviour = class _Behaviour {
6565
6612
  if (!this.threeRef) {
6566
6613
  return null;
6567
6614
  }
6568
- const position = new THREE14__namespace.Vector3();
6615
+ const position = new THREE26__namespace.Vector3();
6569
6616
  this.threeRef.object.getWorldPosition(position);
6570
6617
  return position;
6571
6618
  }
@@ -6577,7 +6624,7 @@ var _Behaviour = class _Behaviour {
6577
6624
  if (!this.threeRef) {
6578
6625
  return null;
6579
6626
  }
6580
- const target = new THREE14__namespace.Vector3();
6627
+ const target = new THREE26__namespace.Vector3();
6581
6628
  this.threeRef.object.getWorldDirection(target);
6582
6629
  return target;
6583
6630
  }
@@ -6639,7 +6686,7 @@ var _Behaviour = class _Behaviour {
6639
6686
  if (!this.threeRef) {
6640
6687
  return;
6641
6688
  }
6642
- const rotation = new THREE14__namespace.Quaternion();
6689
+ const rotation = new THREE26__namespace.Quaternion();
6643
6690
  this.threeRef.object.getWorldQuaternion(rotation);
6644
6691
  rotation.slerp(targetRotation, alpha);
6645
6692
  this.transform.setRotation(rotation);
@@ -6656,7 +6703,7 @@ var _Behaviour = class _Behaviour {
6656
6703
  return;
6657
6704
  }
6658
6705
  const clone = this.threeRef.object.clone();
6659
- const rotation = new THREE14__namespace.Quaternion();
6706
+ const rotation = new THREE26__namespace.Quaternion();
6660
6707
  clone.lookAt(targetPosition);
6661
6708
  clone.getWorldQuaternion(rotation);
6662
6709
  this.transform.setRotation(rotation);
@@ -6794,6 +6841,17 @@ var _Behaviour = class _Behaviour {
6794
6841
  *
6795
6842
  * @param input - The source doing the grabbing.
6796
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
+ }
6797
6855
  /**
6798
6856
  * A hand pose declared on this entity started being held.
6799
6857
  *
@@ -7011,8 +7069,8 @@ var _ScriptBehaviourSystem = class _ScriptBehaviourSystem {
7011
7069
  }, "onPointerUp");
7012
7070
  this.moduleLoader = moduleLoader ?? defaultModuleLoader;
7013
7071
  this.selectionCtx = selectionContext ?? null;
7014
- this.raycaster = new THREE14__namespace.Raycaster();
7015
- this.ndcPointer = new THREE14__namespace.Vector2();
7072
+ this.raycaster = new THREE26__namespace.Raycaster();
7073
+ this.ndcPointer = new THREE26__namespace.Vector2();
7016
7074
  if (this.selectionCtx) {
7017
7075
  this.selectionCtx.domElement.addEventListener("pointerdown", this.onPointerDown);
7018
7076
  this.selectionCtx.domElement.addEventListener("pointerup", this.onPointerUp);
@@ -7391,7 +7449,7 @@ function disposeBuiltObject(root) {
7391
7449
  for (const mat of materials) {
7392
7450
  if (mat.userData?.[SHARED_MODEL_RESOURCE_FLAG]) continue;
7393
7451
  for (const value of Object.values(mat)) {
7394
- if (value instanceof THREE14__namespace.Texture) value.dispose();
7452
+ if (value instanceof THREE26__namespace.Texture) value.dispose();
7395
7453
  }
7396
7454
  mat.dispose?.();
7397
7455
  }
@@ -7755,7 +7813,7 @@ var _AudioSystem = class _AudioSystem {
7755
7813
  if (!prev || prev.volume !== opts.volume) {
7756
7814
  sound.setVolume(opts.volume);
7757
7815
  }
7758
- if (opts.positional && sound instanceof THREE14__namespace.PositionalAudio) {
7816
+ if (opts.positional && sound instanceof THREE26__namespace.PositionalAudio) {
7759
7817
  if (!prev || prev.refDistance !== opts.refDistance) {
7760
7818
  sound.setRefDistance(opts.refDistance);
7761
7819
  }
@@ -7881,7 +7939,7 @@ var _VideoSystem = class _VideoSystem {
7881
7939
  component.object.scale.set(opts.width, opts.height, 1);
7882
7940
  }
7883
7941
  const material = component.material;
7884
- if (material instanceof THREE14__namespace.ShaderMaterial) {
7942
+ if (material instanceof THREE26__namespace.ShaderMaterial) {
7885
7943
  if (!prev || prev.backgroundColor !== opts.backgroundColor) {
7886
7944
  material.uniforms.keyColor.value.set(opts.backgroundColor);
7887
7945
  }
@@ -7895,7 +7953,7 @@ var _VideoSystem = class _VideoSystem {
7895
7953
  material.uniforms.spill.value = opts.spill;
7896
7954
  }
7897
7955
  }
7898
- if (opts.positional && component.audioNode instanceof THREE14__namespace.PositionalAudio) {
7956
+ if (opts.positional && component.audioNode instanceof THREE26__namespace.PositionalAudio) {
7899
7957
  const posAudio = component.audioNode;
7900
7958
  if (!prev || prev.refDistance !== opts.refDistance) {
7901
7959
  posAudio.setRefDistance(opts.refDistance);
@@ -7935,8 +7993,8 @@ function blankState(source) {
7935
7993
  handedness: handednessOf(source),
7936
7994
  kind: kindOf(source),
7937
7995
  connected: true,
7938
- rayOrigin: new THREE14__namespace.Vector3(),
7939
- rayDirection: new THREE14__namespace.Vector3(0, 0, -1),
7996
+ rayOrigin: new THREE26__namespace.Vector3(),
7997
+ rayDirection: new THREE26__namespace.Vector3(0, 0, -1),
7940
7998
  gripPosition: null,
7941
7999
  gripQuaternion: null,
7942
8000
  select: false,
@@ -7962,7 +8020,7 @@ function readHandJoints(frame, hand, referenceSpace, rigMatrix, existing) {
7962
8020
  }
7963
8021
  if (spaces.length === 0) return null;
7964
8022
  const target = existing ?? {};
7965
- const matrix = new THREE14__namespace.Matrix4();
8023
+ const matrix = new THREE26__namespace.Matrix4();
7966
8024
  const buffer = spaces.length * 16 <= JOINT_MATRIX_BUFFER.length ? JOINT_MATRIX_BUFFER : new Float32Array(spaces.length * 16);
7967
8025
  const fillPoses = frame.fillPoses;
7968
8026
  if (typeof fillPoses === "function") {
@@ -7975,7 +8033,7 @@ function readHandJoints(frame, hand, referenceSpace, rigMatrix, existing) {
7975
8033
  if (filled) {
7976
8034
  for (let i = 0; i < names.length; i += 1) {
7977
8035
  matrix.fromArray(buffer, i * 16).premultiply(rigMatrix);
7978
- const vector = target[names[i]] ?? new THREE14__namespace.Vector3();
8036
+ const vector = target[names[i]] ?? new THREE26__namespace.Vector3();
7979
8037
  vector.setFromMatrixPosition(matrix);
7980
8038
  target[names[i]] = vector;
7981
8039
  }
@@ -7993,7 +8051,7 @@ function readHandJoints(frame, hand, referenceSpace, rigMatrix, existing) {
7993
8051
  continue;
7994
8052
  }
7995
8053
  matrix.fromArray(pose.transform.matrix).premultiply(rigMatrix);
7996
- const vector = target[names[i]] ?? new THREE14__namespace.Vector3();
8054
+ const vector = target[names[i]] ?? new THREE26__namespace.Vector3();
7997
8055
  vector.setFromMatrixPosition(matrix);
7998
8056
  target[names[i]] = vector;
7999
8057
  anyTracked = true;
@@ -8005,7 +8063,7 @@ var _XRInputSystem = class _XRInputSystem {
8005
8063
  constructor() {
8006
8064
  this.records = /* @__PURE__ */ new Map();
8007
8065
  /** Reference-space → world matrix, rebuilt each frame from the XR rig. */
8008
- this.referenceToWorld = new THREE14__namespace.Matrix4();
8066
+ this.referenceToWorld = new THREE26__namespace.Matrix4();
8009
8067
  this.session = null;
8010
8068
  this.onSelectStart = /* @__PURE__ */ __name((event) => this.mark(event, "pendingSelectStart"), "onSelectStart");
8011
8069
  this.onSelectEnd = /* @__PURE__ */ __name((event) => this.mark(event, "pendingSelectEnd"), "onSelectEnd");
@@ -8103,19 +8161,19 @@ var _XRInputSystem = class _XRInputSystem {
8103
8161
  if (frame && referenceSpace && source.targetRaySpace) {
8104
8162
  const pose = frame.getPose(source.targetRaySpace, referenceSpace);
8105
8163
  if (pose) {
8106
- 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);
8107
8165
  state.rayOrigin.setFromMatrixPosition(m);
8108
8166
  state.rayDirection.set(0, 0, -1).applyQuaternion(
8109
- new THREE14__namespace.Quaternion().setFromRotationMatrix(m)
8167
+ new THREE26__namespace.Quaternion().setFromRotationMatrix(m)
8110
8168
  ).normalize();
8111
8169
  }
8112
8170
  }
8113
8171
  if (frame && referenceSpace && source.gripSpace) {
8114
8172
  const gripPose = frame.getPose(source.gripSpace, referenceSpace);
8115
8173
  if (gripPose) {
8116
- const m = new THREE14__namespace.Matrix4().fromArray(gripPose.transform.matrix).premultiply(rigMatrix);
8117
- state.gripPosition ?? (state.gripPosition = new THREE14__namespace.Vector3());
8118
- 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());
8119
8177
  state.gripPosition.setFromMatrixPosition(m);
8120
8178
  state.gripQuaternion.setFromRotationMatrix(m);
8121
8179
  }
@@ -8200,6 +8258,7 @@ __name(_XRInputSystem, "XRInputSystem");
8200
8258
  var XRInputSystem = _XRInputSystem;
8201
8259
  var VELOCITY_SAMPLES = 5;
8202
8260
  var MAX_SAMPLE_AGE_SECONDS = 0.2;
8261
+ var MAX_PLAUSIBLE_SPEED = 20;
8203
8262
  var _ThrowVelocityTracker = class _ThrowVelocityTracker {
8204
8263
  constructor() {
8205
8264
  this.samples = [];
@@ -8223,16 +8282,17 @@ var _ThrowVelocityTracker = class _ThrowVelocityTracker {
8223
8282
  const fresh = this.samples.filter(
8224
8283
  (sample) => now - sample.time <= MAX_SAMPLE_AGE_SECONDS
8225
8284
  );
8226
- if (fresh.length < 2) return new THREE14__namespace.Vector3();
8227
- let best = new THREE14__namespace.Vector3();
8285
+ if (fresh.length < 2) return new THREE26__namespace.Vector3();
8286
+ let best = new THREE26__namespace.Vector3();
8228
8287
  let bestSpeed = 0;
8229
8288
  for (let i = 1; i < fresh.length; i += 1) {
8230
8289
  const previous = fresh[i - 1];
8231
8290
  const current = fresh[i];
8232
8291
  const dt = current.time - previous.time;
8233
8292
  if (dt <= 1e-5) continue;
8234
- 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);
8235
8294
  const speed = velocity.length();
8295
+ if (speed > MAX_PLAUSIBLE_SPEED) continue;
8236
8296
  if (speed > bestSpeed) {
8237
8297
  bestSpeed = speed;
8238
8298
  best = velocity;
@@ -8247,23 +8307,75 @@ var _ThrowVelocityTracker = class _ThrowVelocityTracker {
8247
8307
  __name(_ThrowVelocityTracker, "ThrowVelocityTracker");
8248
8308
  var ThrowVelocityTracker = _ThrowVelocityTracker;
8249
8309
  function angularVelocityFrom(previous, current, deltaTime) {
8250
- if (deltaTime <= 1e-5) return new THREE14__namespace.Vector3();
8310
+ if (deltaTime <= 1e-5) return new THREE26__namespace.Vector3();
8251
8311
  const delta = current.clone().multiply(previous.clone().invert());
8252
8312
  if (delta.w < 0) {
8253
8313
  delta.set(-delta.x, -delta.y, -delta.z, -delta.w);
8254
8314
  }
8255
- 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));
8256
8316
  const sinHalf = Math.sqrt(Math.max(0, 1 - delta.w * delta.w));
8257
- if (sinHalf < 1e-6 || angle < 1e-6) return new THREE14__namespace.Vector3();
8258
- 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);
8259
8319
  }
8260
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");
8261
8362
 
8262
8363
  // core/systems/XRInteractionSystem.ts
8263
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");
8264
8376
  var _XRInteractionSystem = class _XRInteractionSystem {
8265
8377
  constructor(inputSystem) {
8266
- this.raycaster = new THREE14__namespace.Raycaster();
8378
+ this.raycaster = new THREE26__namespace.Raycaster();
8267
8379
  this.grabs = /* @__PURE__ */ new Map();
8268
8380
  this.hoveredEntityId = null;
8269
8381
  /** Monotonic seconds, accumulated from deltaTime for velocity sampling. */
@@ -8286,7 +8398,6 @@ var _XRInteractionSystem = class _XRInteractionSystem {
8286
8398
  }
8287
8399
  const held = this.grabs.get(input);
8288
8400
  if (held) {
8289
- this.moveHeld(world, input, held, deltaTime);
8290
8401
  if (this.wantsRelease(world, input, held)) {
8291
8402
  this.release(world, input);
8292
8403
  }
@@ -8307,9 +8418,122 @@ var _XRInteractionSystem = class _XRInteractionSystem {
8307
8418
  /* starting */
8308
8419
  true
8309
8420
  )) {
8310
- this.grab(world, input, candidate.entityId, candidate.viaDistance);
8421
+ this.tryGrab(world, input, candidate.entityId, candidate.viaDistance);
8311
8422
  }
8312
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;
8313
8537
  }
8314
8538
  /** Whether the grab gesture for this object is currently starting. */
8315
8539
  gestureMatches(input, interactable, starting) {
@@ -8358,7 +8582,7 @@ var _XRInteractionSystem = class _XRInteractionSystem {
8358
8582
  );
8359
8583
  if (!interactable2) continue;
8360
8584
  if (interactable2.grabReach === "distance") continue;
8361
- const position = new THREE14__namespace.Vector3();
8585
+ const position = new THREE26__namespace.Vector3();
8362
8586
  entry.object.getWorldPosition(position);
8363
8587
  const distance = position.distanceTo(hand);
8364
8588
  if (distance <= interactable2.grabRadius && distance < nearestDistance) {
@@ -8382,7 +8606,9 @@ var _XRInteractionSystem = class _XRInteractionSystem {
8382
8606
  if (!interactable?.enabled) continue;
8383
8607
  if (!world.isEntityVisible(entityId)) continue;
8384
8608
  const object = world.getComponent(entityId, Object3DRef)?.object;
8385
- if (object) out.push({ entityId, object });
8609
+ if (object) {
8610
+ out.push({ entityId, object, pointable: interactable.pointable });
8611
+ }
8386
8612
  }
8387
8613
  return out;
8388
8614
  }
@@ -8394,6 +8620,7 @@ var _XRInteractionSystem = class _XRInteractionSystem {
8394
8620
  let nearestId = null;
8395
8621
  let nearestDistance = Number.POSITIVE_INFINITY;
8396
8622
  for (const entry of interactables) {
8623
+ if (!entry.pointable) continue;
8397
8624
  const hit = this.raycaster.intersectObject(entry.object, true)[0];
8398
8625
  if (!hit) continue;
8399
8626
  if (hit.distance < nearestDistance) {
@@ -8403,7 +8630,52 @@ var _XRInteractionSystem = class _XRInteractionSystem {
8403
8630
  }
8404
8631
  return nearestId;
8405
8632
  }
8406
- 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) {
8407
8679
  const transform = world.getComponent(entityId, TransformComponent);
8408
8680
  const interactable = world.getComponent(entityId, XRInteractableComponent);
8409
8681
  if (!transform || !interactable) return;
@@ -8413,21 +8685,21 @@ var _XRInteractionSystem = class _XRInteractionSystem {
8413
8685
  let offset;
8414
8686
  let remoteDistance = 0;
8415
8687
  if (remote) {
8416
- const position = new THREE14__namespace.Vector3(
8688
+ const position = new THREE26__namespace.Vector3(
8417
8689
  transform.position.x,
8418
8690
  transform.position.y,
8419
8691
  transform.position.z
8420
8692
  );
8421
8693
  remoteDistance = position.distanceTo(input.rayOrigin);
8422
- offset = new THREE14__namespace.Vector3();
8694
+ offset = new THREE26__namespace.Vector3();
8423
8695
  } else if (viaDistance) {
8424
- offset = new THREE14__namespace.Vector3(
8696
+ offset = new THREE26__namespace.Vector3(
8425
8697
  interactable.grabOffsetPosition.x,
8426
8698
  interactable.grabOffsetPosition.y,
8427
8699
  interactable.grabOffsetPosition.z
8428
8700
  );
8429
8701
  } else {
8430
- offset = new THREE14__namespace.Vector3(
8702
+ offset = new THREE26__namespace.Vector3(
8431
8703
  transform.position.x - hand.x,
8432
8704
  transform.position.y - hand.y,
8433
8705
  transform.position.z - hand.z
@@ -8441,11 +8713,30 @@ var _XRInteractionSystem = class _XRInteractionSystem {
8441
8713
  }
8442
8714
  const tracker = new ThrowVelocityTracker();
8443
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);
8444
8725
  this.grabs.set(input, {
8445
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,
8446
8737
  offset,
8447
- rotationOffset: new THREE14__namespace.Quaternion().setFromEuler(
8448
- new THREE14__namespace.Euler(
8738
+ rotationOffset: new THREE26__namespace.Quaternion().setFromEuler(
8739
+ new THREE26__namespace.Euler(
8449
8740
  interactable.grabOffsetRotation.x,
8450
8741
  interactable.grabOffsetRotation.y,
8451
8742
  interactable.grabOffsetRotation.z
@@ -8456,33 +8747,110 @@ var _XRInteractionSystem = class _XRInteractionSystem {
8456
8747
  restoreBodyType,
8457
8748
  tracker,
8458
8749
  lastHandQuaternion: handQuaternion.clone(),
8459
- angularVelocity: new THREE14__namespace.Vector3()
8750
+ angularVelocity: new THREE26__namespace.Vector3()
8460
8751
  });
8461
- 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();
8462
8815
  }
8463
8816
  moveHeld(world, input, held, deltaTime) {
8464
8817
  const transform = world.getComponent(held.entityId, TransformComponent);
8465
8818
  if (!transform) return;
8466
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);
8467
8822
  if (held.remote) {
8468
- 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);
8469
8824
  transform.position.x = target.x;
8470
8825
  transform.position.y = target.y;
8471
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);
8472
8840
  } else {
8473
8841
  transform.position.x = hand.x + held.offset.x;
8474
8842
  transform.position.y = hand.y + held.offset.y;
8475
8843
  transform.position.z = hand.z + held.offset.z;
8844
+ writeEuler(transform.rotation, objectQuaternion);
8476
8845
  }
8477
8846
  held.tracker.record(
8478
- held.remote ? new THREE14__namespace.Vector3(
8847
+ held.remote ? new THREE26__namespace.Vector3(
8479
8848
  transform.position.x,
8480
8849
  transform.position.y,
8481
8850
  transform.position.z
8482
8851
  ) : hand,
8483
8852
  this.elapsed
8484
8853
  );
8485
- const handQuaternion = this.handQuaternion(input);
8486
8854
  held.angularVelocity = angularVelocityFrom(
8487
8855
  held.lastHandQuaternion,
8488
8856
  handQuaternion,
@@ -8498,6 +8866,30 @@ var _XRInteractionSystem = class _XRInteractionSystem {
8498
8866
  held.entityId,
8499
8867
  XRInteractableComponent
8500
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
+ }
8501
8893
  const physics = world.getComponent(held.entityId, PhysicsComponent);
8502
8894
  if (held.restoreBodyType !== null && physics) {
8503
8895
  physics.values.rigidbody.type = held.restoreBodyType;
@@ -8531,7 +8923,7 @@ var _XRInteractionSystem = class _XRInteractionSystem {
8531
8923
  */
8532
8924
  handPosition(input) {
8533
8925
  if (input.gripPosition) return input.gripPosition;
8534
- 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);
8535
8927
  }
8536
8928
  /**
8537
8929
  * Hand orientation. Grip-less sources (gaze / transient-pointer) have none,
@@ -8539,8 +8931,8 @@ var _XRInteractionSystem = class _XRInteractionSystem {
8539
8931
  */
8540
8932
  handQuaternion(input) {
8541
8933
  if (input.gripQuaternion) return input.gripQuaternion.clone();
8542
- return new THREE14__namespace.Quaternion().setFromUnitVectors(
8543
- new THREE14__namespace.Vector3(0, 0, -1),
8934
+ return new THREE26__namespace.Quaternion().setFromUnitVectors(
8935
+ new THREE26__namespace.Vector3(0, 0, -1),
8544
8936
  input.rayDirection.clone().normalize()
8545
8937
  );
8546
8938
  }
@@ -8565,6 +8957,29 @@ var _XRInteractionSystem = class _XRInteractionSystem {
8565
8957
  isGrabbing() {
8566
8958
  return this.grabs.size > 0;
8567
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
+ }
8568
8983
  };
8569
8984
  __name(_XRInteractionSystem, "XRInteractionSystem");
8570
8985
  var XRInteractionSystem = _XRInteractionSystem;
@@ -8582,7 +8997,7 @@ function sampleTeleportArc(origin, direction, out = [], options) {
8582
8997
  for (let i = 0; i < steps; i += 1) {
8583
8998
  const t = i / (steps - 1) * maxTime;
8584
8999
  out.push(
8585
- new THREE14__namespace.Vector3(
9000
+ new THREE26__namespace.Vector3(
8586
9001
  origin.x + velocity.x * t,
8587
9002
  origin.y + velocity.y * t - 0.5 * gravity * t * t,
8588
9003
  origin.z + velocity.z * t
@@ -8594,11 +9009,11 @@ function sampleTeleportArc(origin, direction, out = [], options) {
8594
9009
  __name(sampleTeleportArc, "sampleTeleportArc");
8595
9010
 
8596
9011
  // core/systems/XRLocomotionSystem.ts
8597
- var UP = new THREE14__namespace.Vector3(0, 1, 0);
9012
+ var UP = new THREE26__namespace.Vector3(0, 1, 0);
8598
9013
  var AXIS_DEADZONE = 0.5;
8599
9014
  var _XRLocomotionSystem = class _XRLocomotionSystem {
8600
9015
  constructor(inputSystem) {
8601
- this.raycaster = new THREE14__namespace.Raycaster();
9016
+ this.raycaster = new THREE26__namespace.Raycaster();
8602
9017
  /** Per-source latch so one stick push yields exactly one snap turn. */
8603
9018
  this.turnLatched = /* @__PURE__ */ new WeakSet();
8604
9019
  /** Reused arc buffer — aiming runs every frame. */
@@ -8707,7 +9122,7 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
8707
9122
  }
8708
9123
  if (this.turnLatched.has(source)) continue;
8709
9124
  this.turnLatched.add(source);
8710
- 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);
8711
9126
  }
8712
9127
  }
8713
9128
  applySmoothMove(world, rig, transform, inputs, deltaTime) {
@@ -8717,12 +9132,12 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
8717
9132
  const y = input.axes[1] ?? 0;
8718
9133
  if (Math.abs(x) < 0.15 && Math.abs(y) < 0.15) continue;
8719
9134
  const camera = world.getCamera();
8720
- const forward = new THREE14__namespace.Vector3();
9135
+ const forward = new THREE26__namespace.Vector3();
8721
9136
  camera.getWorldDirection(forward);
8722
9137
  forward.y = 0;
8723
9138
  if (forward.lengthSq() < 1e-6) continue;
8724
9139
  forward.normalize();
8725
- const right = new THREE14__namespace.Vector3().crossVectors(forward, UP).normalize();
9140
+ const right = new THREE26__namespace.Vector3().crossVectors(forward, UP).normalize();
8726
9141
  const step = rig.moveSpeed * Math.max(0, deltaTime);
8727
9142
  transform.position.x += (forward.x * -y + right.x * x) * step;
8728
9143
  transform.position.z += (forward.z * -y + right.z * x) * step;
@@ -8787,7 +9202,7 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
8787
9202
  for (let i = 1; i < points.length; i += 1) {
8788
9203
  const from = points[i - 1];
8789
9204
  const to = points[i];
8790
- const delta = new THREE14__namespace.Vector3().subVectors(to, from);
9205
+ const delta = new THREE26__namespace.Vector3().subVectors(to, from);
8791
9206
  const distance = delta.length();
8792
9207
  if (distance < 1e-6) continue;
8793
9208
  this.raycaster.set(from, delta.divideScalar(distance));
@@ -8995,9 +9410,9 @@ var XRSessionSystem = _XRSessionSystem;
8995
9410
  function buildGeometry2(area) {
8996
9411
  if (area.shape === "circle") {
8997
9412
  const radius = Math.max(5e-3, area.width / 2);
8998
- return new THREE14__namespace.CircleGeometry(radius, 48);
9413
+ return new THREE26__namespace.CircleGeometry(radius, 48);
8999
9414
  }
9000
- return new THREE14__namespace.PlaneGeometry(
9415
+ return new THREE26__namespace.PlaneGeometry(
9001
9416
  Math.max(0.01, area.width),
9002
9417
  Math.max(0.01, area.depth)
9003
9418
  );
@@ -9020,7 +9435,7 @@ var _VRTeleportAreaSystem = class _VRTeleportAreaSystem {
9020
9435
  for (const entityId of entityIds) {
9021
9436
  const area = world.getComponent(entityId, VRTeleportAreaComponent);
9022
9437
  const object = world.getComponent(entityId, Object3DRef)?.object;
9023
- if (!area || !(object instanceof THREE14__namespace.Mesh)) continue;
9438
+ if (!area || !(object instanceof THREE26__namespace.Mesh)) continue;
9024
9439
  const signature = signatureOf(area);
9025
9440
  if (this.signatures.get(entityId) === signature) continue;
9026
9441
  this.signatures.set(entityId, signature);
@@ -9032,18 +9447,18 @@ var _VRTeleportAreaSystem = class _VRTeleportAreaSystem {
9032
9447
  __name(_VRTeleportAreaSystem, "VRTeleportAreaSystem");
9033
9448
  var VRTeleportAreaSystem = _VRTeleportAreaSystem;
9034
9449
  function createHandMaterial(preset, options) {
9035
- const color = new THREE14__namespace.Color(options.color);
9450
+ const color = new THREE26__namespace.Color(options.color);
9036
9451
  switch (preset) {
9037
9452
  case "ghost":
9038
- return new THREE14__namespace.MeshBasicMaterial({
9453
+ return new THREE26__namespace.MeshBasicMaterial({
9039
9454
  color,
9040
9455
  transparent: true,
9041
9456
  opacity: Math.min(1, Math.max(0.05, options.opacity * 0.45)),
9042
9457
  depthWrite: false,
9043
- side: THREE14__namespace.DoubleSide
9458
+ side: THREE26__namespace.DoubleSide
9044
9459
  });
9045
9460
  case "neon":
9046
- return new THREE14__namespace.MeshStandardMaterial({
9461
+ return new THREE26__namespace.MeshStandardMaterial({
9047
9462
  color,
9048
9463
  emissive: color,
9049
9464
  emissiveIntensity: Math.max(0.5, options.emissiveIntensity || 2),
@@ -9053,7 +9468,7 @@ function createHandMaterial(preset, options) {
9053
9468
  opacity: options.opacity
9054
9469
  });
9055
9470
  case "skeleton":
9056
- return new THREE14__namespace.MeshBasicMaterial({
9471
+ return new THREE26__namespace.MeshBasicMaterial({
9057
9472
  color,
9058
9473
  wireframe: true,
9059
9474
  transparent: true,
@@ -9061,7 +9476,7 @@ function createHandMaterial(preset, options) {
9061
9476
  });
9062
9477
  case "custom":
9063
9478
  case "default":
9064
- return new THREE14__namespace.MeshStandardMaterial({
9479
+ return new THREE26__namespace.MeshStandardMaterial({
9065
9480
  color,
9066
9481
  roughness: 0.85,
9067
9482
  metalness: 0,
@@ -9069,10 +9484,10 @@ function createHandMaterial(preset, options) {
9069
9484
  emissiveIntensity: Math.max(0, options.emissiveIntensity),
9070
9485
  transparent: options.opacity < 1,
9071
9486
  opacity: options.opacity,
9072
- side: THREE14__namespace.DoubleSide
9487
+ side: THREE26__namespace.DoubleSide
9073
9488
  });
9074
9489
  default: {
9075
- return new THREE14__namespace.MeshStandardMaterial({ color });
9490
+ return new THREE26__namespace.MeshStandardMaterial({ color });
9076
9491
  }
9077
9492
  }
9078
9493
  }
@@ -9093,7 +9508,7 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
9093
9508
  constructor(options) {
9094
9509
  this.controllerModelFactory = new XRControllerModelFactory_js.XRControllerModelFactory();
9095
9510
  this.handModelFactory = new XRHandModelFactory_js.XRHandModelFactory();
9096
- this.group = new THREE14__namespace.Group();
9511
+ this.group = new THREE26__namespace.Group();
9097
9512
  this.slots = /* @__PURE__ */ new Map();
9098
9513
  this.attachedTo = null;
9099
9514
  /** Last applied preset signature, so materials rebuild only on real change. */
@@ -9242,17 +9657,17 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
9242
9657
  this.attachedTo = target;
9243
9658
  }
9244
9659
  createRay() {
9245
- const geometry = new THREE14__namespace.BufferGeometry().setFromPoints([
9246
- new THREE14__namespace.Vector3(0, 0, 0),
9247
- 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)
9248
9663
  ]);
9249
- const material = new THREE14__namespace.LineBasicMaterial({
9664
+ const material = new THREE26__namespace.LineBasicMaterial({
9250
9665
  color: "#4da3ff",
9251
9666
  transparent: true,
9252
9667
  opacity: 0.6,
9253
9668
  depthTest: false
9254
9669
  });
9255
- const line = new THREE14__namespace.Line(geometry, material);
9670
+ const line = new THREE26__namespace.Line(geometry, material);
9256
9671
  line.name = "XRPointerRay";
9257
9672
  line.renderOrder = 999;
9258
9673
  line.visible = false;
@@ -9281,23 +9696,23 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
9281
9696
  __name(_XRControllerVisualSystem, "XRControllerVisualSystem");
9282
9697
  var XRControllerVisualSystem = _XRControllerVisualSystem;
9283
9698
  var MARKER_RADIUS = 0.28;
9284
- var ACCENT = new THREE14__namespace.Color("#4da3ff");
9285
- var BLOCKED = new THREE14__namespace.Color("#ff5a5a");
9699
+ var ACCENT = new THREE26__namespace.Color("#4da3ff");
9700
+ var BLOCKED = new THREE26__namespace.Color("#ff5a5a");
9286
9701
  var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
9287
9702
  constructor(locomotionSystem) {
9288
- this.group = new THREE14__namespace.Group();
9289
- this.arcGeometry = new THREE14__namespace.BufferGeometry();
9290
- 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();
9291
9706
  this.attached = false;
9292
9707
  this.locomotionSystem = locomotionSystem;
9293
9708
  this.group.name = "XRTeleportVisuals";
9294
9709
  this.group.userData.ecsPreviewHidden = true;
9295
- const arcMaterial = new THREE14__namespace.LineBasicMaterial({
9710
+ const arcMaterial = new THREE26__namespace.LineBasicMaterial({
9296
9711
  vertexColors: true,
9297
9712
  transparent: true,
9298
9713
  depthTest: false
9299
9714
  });
9300
- this.arc = new THREE14__namespace.Line(this.arcGeometry, arcMaterial);
9715
+ this.arc = new THREE26__namespace.Line(this.arcGeometry, arcMaterial);
9301
9716
  this.arc.frustumCulled = false;
9302
9717
  this.arc.renderOrder = 998;
9303
9718
  this.group.add(this.arc);
@@ -9345,39 +9760,39 @@ var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
9345
9760
  }
9346
9761
  this.arcGeometry.setAttribute(
9347
9762
  "position",
9348
- new THREE14__namespace.BufferAttribute(positions, 3)
9763
+ new THREE26__namespace.BufferAttribute(positions, 3)
9349
9764
  );
9350
- this.arcGeometry.setAttribute("color", new THREE14__namespace.BufferAttribute(colors, 3));
9765
+ this.arcGeometry.setAttribute("color", new THREE26__namespace.BufferAttribute(colors, 3));
9351
9766
  this.arcGeometry.computeBoundingSphere();
9352
9767
  }
9353
9768
  createRing() {
9354
- const geometry = new THREE14__namespace.RingGeometry(
9769
+ const geometry = new THREE26__namespace.RingGeometry(
9355
9770
  MARKER_RADIUS * 0.72,
9356
9771
  MARKER_RADIUS,
9357
9772
  48
9358
9773
  );
9359
9774
  geometry.rotateX(-Math.PI / 2);
9360
- return new THREE14__namespace.Mesh(
9775
+ return new THREE26__namespace.Mesh(
9361
9776
  geometry,
9362
- new THREE14__namespace.MeshBasicMaterial({
9777
+ new THREE26__namespace.MeshBasicMaterial({
9363
9778
  color: ACCENT,
9364
9779
  transparent: true,
9365
9780
  opacity: 0.9,
9366
- side: THREE14__namespace.DoubleSide,
9781
+ side: THREE26__namespace.DoubleSide,
9367
9782
  depthTest: false
9368
9783
  })
9369
9784
  );
9370
9785
  }
9371
9786
  createDot() {
9372
- const geometry = new THREE14__namespace.CircleGeometry(MARKER_RADIUS * 0.16, 24);
9787
+ const geometry = new THREE26__namespace.CircleGeometry(MARKER_RADIUS * 0.16, 24);
9373
9788
  geometry.rotateX(-Math.PI / 2);
9374
- return new THREE14__namespace.Mesh(
9789
+ return new THREE26__namespace.Mesh(
9375
9790
  geometry,
9376
- new THREE14__namespace.MeshBasicMaterial({
9791
+ new THREE26__namespace.MeshBasicMaterial({
9377
9792
  color: ACCENT,
9378
9793
  transparent: true,
9379
9794
  opacity: 0.55,
9380
- side: THREE14__namespace.DoubleSide,
9795
+ side: THREE26__namespace.DoubleSide,
9381
9796
  depthTest: false
9382
9797
  })
9383
9798
  );
@@ -9479,7 +9894,7 @@ function boneDirections(joints, finger) {
9479
9894
  const from = joints[chain[i - 1]];
9480
9895
  const to = joints[chain[i]];
9481
9896
  if (!from || !to) return null;
9482
- const direction = new THREE14__namespace.Vector3().subVectors(to, from);
9897
+ const direction = new THREE26__namespace.Vector3().subVectors(to, from);
9483
9898
  if (direction.lengthSq() < 1e-12) return null;
9484
9899
  directions.push(direction.normalize());
9485
9900
  }
@@ -9552,8 +9967,8 @@ function computeSpread(joints, a, b) {
9552
9967
  const bBase = joints[METACARPAL_JOINTS[b]];
9553
9968
  const bTip = joints[TIP_JOINTS[b]];
9554
9969
  if (!aBase || !aTip || !bBase || !bTip) return null;
9555
- const dirA = new THREE14__namespace.Vector3().subVectors(aTip, aBase);
9556
- 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);
9557
9972
  if (dirA.lengthSq() < 1e-12 || dirB.lengthSq() < 1e-12) return null;
9558
9973
  return clamp01((1 - dirA.normalize().dot(dirB.normalize())) / 0.45);
9559
9974
  }
@@ -9563,18 +9978,18 @@ function computePalmPose(joints, handedness) {
9563
9978
  const indexBase = joints["index-finger-metacarpal"];
9564
9979
  const pinkyBase = joints["pinky-finger-metacarpal"];
9565
9980
  if (!wrist || !indexBase || !pinkyBase) return null;
9566
- const u = new THREE14__namespace.Vector3().subVectors(indexBase, wrist);
9567
- const v = new THREE14__namespace.Vector3().subVectors(pinkyBase, wrist);
9568
- 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);
9569
9984
  if (normal.lengthSq() < 1e-12) return null;
9570
9985
  normal.normalize();
9571
9986
  if (handedness === "left") normal.multiplyScalar(-1);
9572
- const right = new THREE14__namespace.Vector3().subVectors(indexBase, pinkyBase);
9987
+ const right = new THREE26__namespace.Vector3().subVectors(indexBase, pinkyBase);
9573
9988
  if (right.lengthSq() < 1e-12) return null;
9574
9989
  right.normalize();
9575
9990
  if (handedness === "left") right.multiplyScalar(-1);
9576
- const up = new THREE14__namespace.Vector3().crossVectors(normal, right).normalize();
9577
- 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);
9578
9993
  return {
9579
9994
  center,
9580
9995
  normal,
@@ -9605,7 +10020,7 @@ function computeHandShape(joints, handedness) {
9605
10020
  const thumbTip = joints["thumb-tip"];
9606
10021
  let thumbDirection = null;
9607
10022
  if (thumbBase && thumbTip) {
9608
- const direction = new THREE14__namespace.Vector3().subVectors(thumbTip, thumbBase);
10023
+ const direction = new THREE26__namespace.Vector3().subVectors(thumbTip, thumbBase);
9609
10024
  if (direction.lengthSq() > 1e-12) thumbDirection = direction.normalize();
9610
10025
  }
9611
10026
  return {
@@ -9637,12 +10052,12 @@ function scoreAgainst(actual, target, tolerance) {
9637
10052
  }
9638
10053
  __name(scoreAgainst, "scoreAgainst");
9639
10054
  var WORLD_DIRECTIONS = {
9640
- up: new THREE14__namespace.Vector3(0, 1, 0),
9641
- down: new THREE14__namespace.Vector3(0, -1, 0),
9642
- forward: new THREE14__namespace.Vector3(0, 0, -1),
9643
- back: new THREE14__namespace.Vector3(0, 0, 1),
9644
- left: new THREE14__namespace.Vector3(-1, 0, 0),
9645
- 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)
9646
10061
  };
9647
10062
  function axisVector(shape, axis) {
9648
10063
  if (axis === "thumb") return shape.thumbDirection;
@@ -9657,7 +10072,7 @@ function resolveDirection(direction, shape, context) {
9657
10072
  const head = context?.headPosition;
9658
10073
  const origin = shape.palm?.center;
9659
10074
  if (!head || !origin) return null;
9660
- const toHead = new THREE14__namespace.Vector3().subVectors(head, origin);
10075
+ const toHead = new THREE26__namespace.Vector3().subVectors(head, origin);
9661
10076
  if (toHead.lengthSq() < 1e-12) return null;
9662
10077
  toHead.normalize();
9663
10078
  return direction === "toward-head" ? toHead : toHead.multiplyScalar(-1);
@@ -9707,8 +10122,8 @@ function matchHandPose(shape, definition, context) {
9707
10122
  if (!handAxis || !wanted) {
9708
10123
  consider(0, "orientation");
9709
10124
  } else {
9710
- const angle = THREE14__namespace.MathUtils.radToDeg(
9711
- 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))
9712
10127
  );
9713
10128
  const normalizedError = Math.max(0, angle - toleranceDegrees) / 90;
9714
10129
  consider(clamp01(1 - normalizedError / MATCH_FALLOFF), "orientation");
@@ -9786,7 +10201,7 @@ var _XRHandPoseSystem = class _XRHandPoseSystem {
9786
10201
  this.trackers = /* @__PURE__ */ new Map();
9787
10202
  this.shapes = /* @__PURE__ */ new Map();
9788
10203
  /** Reused so head-relative orientation checks allocate nothing per frame. */
9789
- this.headPosition = new THREE14__namespace.Vector3();
10204
+ this.headPosition = new THREE26__namespace.Vector3();
9790
10205
  this.elapsed = 0;
9791
10206
  this.inputSystem = inputSystem;
9792
10207
  }