@relu-interactives/spatial-ecs 0.3.9 → 0.3.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/{XRHandPose-CxPz8VBp.d.ts → XRHandPose-CjacJ_16.d.ts} +70 -1
  2. package/dist/{XRHandPose-VuSbe4iz.d.cts → XRHandPose-hAtj9wm-.d.cts} +70 -1
  3. package/dist/{chunk-KIKIWCEB.js → chunk-5UVBEAGW.js} +4 -4
  4. package/dist/{chunk-KIKIWCEB.js.map → chunk-5UVBEAGW.js.map} +1 -1
  5. package/dist/{chunk-KVGGAL5V.js → chunk-ELSZ5U3F.js} +23 -3
  6. package/dist/chunk-ELSZ5U3F.js.map +1 -0
  7. package/dist/{chunk-L5BP727H.js → chunk-NJOO7NO6.js} +3 -3
  8. package/dist/{chunk-L5BP727H.js.map → chunk-NJOO7NO6.js.map} +1 -1
  9. package/dist/{chunk-W5TSYV6Q.js → chunk-O2HSIZFC.js} +572 -185
  10. package/dist/chunk-O2HSIZFC.js.map +1 -0
  11. package/dist/components/index.cjs +20 -0
  12. package/dist/components/index.cjs.map +1 -1
  13. package/dist/components/index.d.cts +2 -2
  14. package/dist/components/index.d.ts +2 -2
  15. package/dist/components/index.js +1 -1
  16. package/dist/docs/guide/vr-and-hand-poses.md +48 -0
  17. package/dist/factories/index.cjs +19 -0
  18. package/dist/factories/index.cjs.map +1 -1
  19. package/dist/factories/index.d.cts +1 -1
  20. package/dist/factories/index.d.ts +1 -1
  21. package/dist/factories/index.js +3 -3
  22. package/dist/{index-C7XQyrgE.d.ts → index-B-KhN8Ox.d.ts} +51 -0
  23. package/dist/{index-BxdXgqiI.d.ts → index-B7JDsx4a.d.ts} +9 -2
  24. package/dist/{index-BIQoaKAA.d.cts → index-B9JqYr3Q.d.cts} +9 -2
  25. package/dist/{index-DyN50JZo.d.cts → index-DU-CF-3m.d.cts} +51 -0
  26. package/dist/index.cjs +710 -303
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +14 -5
  29. package/dist/index.d.ts +14 -5
  30. package/dist/index.js +8 -8
  31. package/dist/systems/index.cjs +617 -211
  32. package/dist/systems/index.cjs.map +1 -1
  33. package/dist/systems/index.d.cts +1 -1
  34. package/dist/systems/index.d.ts +1 -1
  35. package/dist/systems/index.js +3 -3
  36. package/package.json +1 -1
  37. package/dist/chunk-KVGGAL5V.js.map +0 -1
  38. package/dist/chunk-W5TSYV6Q.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var THREE39 = require('three');
3
+ var THREE51 = require('three');
4
4
  var SkeletonUtils_js = require('three/examples/jsm/utils/SkeletonUtils.js');
5
5
  var RectAreaLightHelper_js = require('three/examples/jsm/helpers/RectAreaLightHelper.js');
6
6
  var DRACOLoader_js = require('three/examples/jsm/loaders/DRACOLoader.js');
@@ -41,7 +41,7 @@ function _interopNamespace(e) {
41
41
  return Object.freeze(n);
42
42
  }
43
43
 
44
- var THREE39__namespace = /*#__PURE__*/_interopNamespace(THREE39);
44
+ var THREE51__namespace = /*#__PURE__*/_interopNamespace(THREE51);
45
45
 
46
46
  var __defProp = Object.defineProperty;
47
47
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
@@ -605,14 +605,14 @@ var _AnimationComponent = class _AnimationComponent extends Component {
605
605
  return;
606
606
  }
607
607
  this.importedClips = clips.map((entry) => {
608
- if (entry instanceof THREE39__namespace.AnimationClip) {
608
+ if (entry instanceof THREE51__namespace.AnimationClip) {
609
609
  return { clip: entry, sourceUrl: null };
610
610
  }
611
611
  if (!entry || typeof entry !== "object") {
612
612
  return null;
613
613
  }
614
614
  const candidate = entry;
615
- if (!(candidate.clip instanceof THREE39__namespace.AnimationClip)) {
615
+ if (!(candidate.clip instanceof THREE51__namespace.AnimationClip)) {
616
616
  return null;
617
617
  }
618
618
  return {
@@ -820,11 +820,11 @@ function normalizeDistanceModel(distanceModel) {
820
820
  }
821
821
  __name(normalizeDistanceModel, "normalizeDistanceModel");
822
822
  function createConfiguredAudio(listener, options) {
823
- const sound = options.positional ? new THREE39__namespace.PositionalAudio(listener) : new THREE39__namespace.Audio(listener);
823
+ const sound = options.positional ? new THREE51__namespace.PositionalAudio(listener) : new THREE51__namespace.Audio(listener);
824
824
  sound.setLoop(options.loop);
825
825
  sound.setVolume(options.volume);
826
826
  sound.setPlaybackRate(options.pitch);
827
- if (sound instanceof THREE39__namespace.PositionalAudio) {
827
+ if (sound instanceof THREE51__namespace.PositionalAudio) {
828
828
  sound.setRefDistance(options.refDistance);
829
829
  sound.setDistanceModel(normalizeDistanceModel(options.distanceModel));
830
830
  sound.setRolloffFactor(options.rolloffFactor);
@@ -834,16 +834,16 @@ function createConfiguredAudio(listener, options) {
834
834
  __name(createConfiguredAudio, "createConfiguredAudio");
835
835
  function createAudioEditorHelper() {
836
836
  if (typeof document === "undefined") {
837
- const geometry = new THREE39__namespace.EdgesGeometry(
838
- new THREE39__namespace.OctahedronGeometry(0.22, 0)
837
+ const geometry = new THREE51__namespace.EdgesGeometry(
838
+ new THREE51__namespace.OctahedronGeometry(0.22, 0)
839
839
  );
840
- const material2 = new THREE39__namespace.LineBasicMaterial({
840
+ const material2 = new THREE51__namespace.LineBasicMaterial({
841
841
  color: "#8bc8ff",
842
842
  transparent: true,
843
843
  opacity: 0.95,
844
844
  depthTest: false
845
845
  });
846
- const fallback = new THREE39__namespace.LineSegments(geometry, material2);
846
+ const fallback = new THREE51__namespace.LineSegments(geometry, material2);
847
847
  fallback.renderOrder = 10;
848
848
  fallback.userData.ecsHelper = true;
849
849
  fallback.visible = false;
@@ -855,7 +855,7 @@ function createAudioEditorHelper() {
855
855
  canvas.height = size;
856
856
  const ctx = canvas.getContext("2d");
857
857
  if (!ctx) {
858
- return new THREE39__namespace.Object3D();
858
+ return new THREE51__namespace.Object3D();
859
859
  }
860
860
  ctx.clearRect(0, 0, size, size);
861
861
  ctx.fillStyle = "rgba(27, 35, 52, 0.9)";
@@ -886,14 +886,14 @@ function createAudioEditorHelper() {
886
886
  ctx.beginPath();
887
887
  ctx.arc(56, 48, 16, -0.8, 0.8);
888
888
  ctx.stroke();
889
- const texture = new THREE39__namespace.CanvasTexture(canvas);
889
+ const texture = new THREE51__namespace.CanvasTexture(canvas);
890
890
  texture.needsUpdate = true;
891
- const material = new THREE39__namespace.SpriteMaterial({
891
+ const material = new THREE51__namespace.SpriteMaterial({
892
892
  map: texture,
893
893
  transparent: true,
894
894
  depthTest: false
895
895
  });
896
- const helper = new THREE39__namespace.Sprite(material);
896
+ const helper = new THREE51__namespace.Sprite(material);
897
897
  helper.scale.set(0.68, 0.68, 0.68);
898
898
  helper.renderOrder = 10;
899
899
  helper.userData.ecsHelper = true;
@@ -927,7 +927,7 @@ var DEFAULT_ORTHO_TOP = 5;
927
927
  var DEFAULT_ORTHO_BOTTOM = -5;
928
928
  var DEFAULT_ZOOM = 1;
929
929
  function inferProjection(camera) {
930
- if (camera instanceof THREE39__namespace.OrthographicCamera) {
930
+ if (camera instanceof THREE51__namespace.OrthographicCamera) {
931
931
  return "orthographic";
932
932
  }
933
933
  return "perspective";
@@ -948,7 +948,7 @@ function readCameraFar(camera) {
948
948
  }
949
949
  __name(readCameraFar, "readCameraFar");
950
950
  function inferFov(camera) {
951
- if (camera instanceof THREE39__namespace.PerspectiveCamera && Number.isFinite(camera.fov)) {
951
+ if (camera instanceof THREE51__namespace.PerspectiveCamera && Number.isFinite(camera.fov)) {
952
952
  return camera.fov;
953
953
  }
954
954
  return DEFAULT_FOV;
@@ -971,28 +971,28 @@ function inferFar(camera) {
971
971
  }
972
972
  __name(inferFar, "inferFar");
973
973
  function inferOrthoLeft(camera) {
974
- if (camera instanceof THREE39__namespace.OrthographicCamera && Number.isFinite(camera.left)) {
974
+ if (camera instanceof THREE51__namespace.OrthographicCamera && Number.isFinite(camera.left)) {
975
975
  return camera.left;
976
976
  }
977
977
  return DEFAULT_ORTHO_LEFT;
978
978
  }
979
979
  __name(inferOrthoLeft, "inferOrthoLeft");
980
980
  function inferOrthoRight(camera) {
981
- if (camera instanceof THREE39__namespace.OrthographicCamera && Number.isFinite(camera.right)) {
981
+ if (camera instanceof THREE51__namespace.OrthographicCamera && Number.isFinite(camera.right)) {
982
982
  return camera.right;
983
983
  }
984
984
  return DEFAULT_ORTHO_RIGHT;
985
985
  }
986
986
  __name(inferOrthoRight, "inferOrthoRight");
987
987
  function inferOrthoTop(camera) {
988
- if (camera instanceof THREE39__namespace.OrthographicCamera && Number.isFinite(camera.top)) {
988
+ if (camera instanceof THREE51__namespace.OrthographicCamera && Number.isFinite(camera.top)) {
989
989
  return camera.top;
990
990
  }
991
991
  return DEFAULT_ORTHO_TOP;
992
992
  }
993
993
  __name(inferOrthoTop, "inferOrthoTop");
994
994
  function inferOrthoBottom(camera) {
995
- if (camera instanceof THREE39__namespace.OrthographicCamera && Number.isFinite(camera.bottom)) {
995
+ if (camera instanceof THREE51__namespace.OrthographicCamera && Number.isFinite(camera.bottom)) {
996
996
  return camera.bottom;
997
997
  }
998
998
  return DEFAULT_ORTHO_BOTTOM;
@@ -1008,7 +1008,7 @@ __name(inferZoom, "inferZoom");
1008
1008
  var _CameraComponent = class _CameraComponent extends Component {
1009
1009
  constructor(payload = {}) {
1010
1010
  super();
1011
- this.camera = payload.camera ?? new THREE39__namespace.PerspectiveCamera();
1011
+ this.camera = payload.camera ?? new THREE51__namespace.PerspectiveCamera();
1012
1012
  this.type = payload.type ?? "3d";
1013
1013
  this.isDefault = typeof payload.isDefault === "boolean" ? payload.isDefault : false;
1014
1014
  this.projection = payload.projection ?? inferProjection(payload.camera);
@@ -1039,7 +1039,7 @@ var Object3DRef = _Object3DRef;
1039
1039
  // core/factories/components/CameraFactory.ts
1040
1040
  function createCameraComponent(world, entityId, payload = {}) {
1041
1041
  const object = world.getComponent(entityId, Object3DRef)?.object;
1042
- const objectCamera = object instanceof THREE39__namespace.Camera ? object : void 0;
1042
+ const objectCamera = object instanceof THREE51__namespace.Camera ? object : void 0;
1043
1043
  const component = new CameraComponent({
1044
1044
  ...payload,
1045
1045
  camera: payload.camera ?? objectCamera
@@ -1609,15 +1609,15 @@ function createValueState(light) {
1609
1609
  castShadow: light.castShadow ?? false,
1610
1610
  frustumCulling: light.frustumCulled
1611
1611
  };
1612
- if (light instanceof THREE39__namespace.PointLight) {
1612
+ if (light instanceof THREE51__namespace.PointLight) {
1613
1613
  base.distance = light.distance;
1614
1614
  base.decay = light.decay;
1615
- } else if (light instanceof THREE39__namespace.SpotLight) {
1615
+ } else if (light instanceof THREE51__namespace.SpotLight) {
1616
1616
  base.distance = light.distance;
1617
1617
  base.decay = light.decay;
1618
1618
  base.angle = light.angle;
1619
1619
  base.penumbra = light.penumbra;
1620
- } else if (light instanceof THREE39__namespace.RectAreaLight) {
1620
+ } else if (light instanceof THREE51__namespace.RectAreaLight) {
1621
1621
  base.width = light.width;
1622
1622
  base.height = light.height;
1623
1623
  }
@@ -1660,13 +1660,13 @@ function toHexColor2(value, fallback) {
1660
1660
  }
1661
1661
  __name(toHexColor2, "toHexColor");
1662
1662
  function getMaterialType(material) {
1663
- if (material instanceof THREE39__namespace.MeshPhysicalMaterial) {
1663
+ if (material instanceof THREE51__namespace.MeshPhysicalMaterial) {
1664
1664
  return "physical";
1665
1665
  }
1666
- if (material instanceof THREE39__namespace.MeshPhongMaterial) {
1666
+ if (material instanceof THREE51__namespace.MeshPhongMaterial) {
1667
1667
  return "phong";
1668
1668
  }
1669
- if (material instanceof THREE39__namespace.MeshBasicMaterial) {
1669
+ if (material instanceof THREE51__namespace.MeshBasicMaterial) {
1670
1670
  return "basic";
1671
1671
  }
1672
1672
  return "standard";
@@ -1701,8 +1701,8 @@ function createMaterialValue(material) {
1701
1701
  opacity: typeof materialRecord.opacity === "number" ? materialRecord.opacity : 1,
1702
1702
  emissive: toHexColor2(materialRecord.emissive, "#000000"),
1703
1703
  emissiveIntensity: typeof materialRecord.emissiveIntensity === "number" ? materialRecord.emissiveIntensity : 0,
1704
- side: typeof materialRecord.side === "number" ? materialRecord.side : THREE39__namespace.FrontSide,
1705
- blending: typeof materialRecord.blending === "number" ? materialRecord.blending : THREE39__namespace.NormalBlending,
1704
+ side: typeof materialRecord.side === "number" ? materialRecord.side : THREE51__namespace.FrontSide,
1705
+ blending: typeof materialRecord.blending === "number" ? materialRecord.blending : THREE51__namespace.NormalBlending,
1706
1706
  depthTest: materialRecord.depthTest !== false,
1707
1707
  depthWrite: materialRecord.depthWrite !== false,
1708
1708
  wireframe: Boolean(materialRecord.wireframe),
@@ -1734,7 +1734,7 @@ function createMaterialValue(material) {
1734
1734
  materialRecord.lightMap
1735
1735
  ),
1736
1736
  envMap: textureImageSrc(materialRecord.envMap),
1737
- textureFiltering: map?.magFilter === THREE39__namespace.NearestFilter ? "sharp" : "smooth",
1737
+ textureFiltering: map?.magFilter === THREE51__namespace.NearestFilter ? "sharp" : "smooth",
1738
1738
  useMipmaps: map?.generateMipmaps !== false
1739
1739
  };
1740
1740
  }
@@ -1749,8 +1749,8 @@ function defaultMaterialValue() {
1749
1749
  opacity: 1,
1750
1750
  emissive: "#000000",
1751
1751
  emissiveIntensity: 0,
1752
- side: THREE39__namespace.FrontSide,
1753
- blending: THREE39__namespace.NormalBlending,
1752
+ side: THREE51__namespace.FrontSide,
1753
+ blending: THREE51__namespace.NormalBlending,
1754
1754
  depthTest: true,
1755
1755
  depthWrite: true,
1756
1756
  wireframe: false,
@@ -2327,14 +2327,14 @@ var _TransformComponent = class _TransformComponent extends Component {
2327
2327
  z: scale.z ?? 1
2328
2328
  };
2329
2329
  }
2330
- toPositionVector3(target = new THREE39.Vector3()) {
2330
+ toPositionVector3(target = new THREE51.Vector3()) {
2331
2331
  return target.set(this.position.x, this.position.y, this.position.z);
2332
2332
  }
2333
- toRotationEuler(target = new THREE39.Euler(), order = "XYZ") {
2333
+ toRotationEuler(target = new THREE51.Euler(), order = "XYZ") {
2334
2334
  return target.set(this.rotation.x, this.rotation.y, this.rotation.z, order);
2335
2335
  }
2336
- toRotationQuaternion(target = new THREE39.Quaternion(), order = "XYZ") {
2337
- const euler = new THREE39.Euler(
2336
+ toRotationQuaternion(target = new THREE51.Quaternion(), order = "XYZ") {
2337
+ const euler = new THREE51.Euler(
2338
2338
  this.rotation.x,
2339
2339
  this.rotation.y,
2340
2340
  this.rotation.z,
@@ -2342,7 +2342,7 @@ var _TransformComponent = class _TransformComponent extends Component {
2342
2342
  );
2343
2343
  return target.setFromEuler(euler);
2344
2344
  }
2345
- toScaleVector3(target = new THREE39.Vector3()) {
2345
+ toScaleVector3(target = new THREE51.Vector3()) {
2346
2346
  return target.set(this.scale.x, this.scale.y, this.scale.z);
2347
2347
  }
2348
2348
  setPosition(input) {
@@ -2360,8 +2360,8 @@ var _TransformComponent = class _TransformComponent extends Component {
2360
2360
  return this;
2361
2361
  }
2362
2362
  setRotation(input, order = "XYZ") {
2363
- if (input instanceof THREE39.Quaternion) {
2364
- const euler = new THREE39.Euler().setFromQuaternion(input, order);
2363
+ if (input instanceof THREE51.Quaternion) {
2364
+ const euler = new THREE51.Euler().setFromQuaternion(input, order);
2365
2365
  this.rotation.x = euler.x;
2366
2366
  this.rotation.y = euler.y;
2367
2367
  this.rotation.z = euler.z;
@@ -2845,6 +2845,14 @@ var _XRInteractableComponent = class _XRInteractableComponent extends Component
2845
2845
  y: 0,
2846
2846
  z: 0
2847
2847
  };
2848
+ this.grabHands = options?.grabHands ?? "handOff";
2849
+ this.twoHandRotation = options?.twoHandRotation ?? "align";
2850
+ this.allowTwoHandScale = options?.allowTwoHandScale ?? false;
2851
+ this.minScale = options?.minScale ?? 0.25;
2852
+ this.maxScale = options?.maxScale ?? 4;
2853
+ this.attachPoints = (options?.attachPoints ?? []).map(
2854
+ (point) => createAttachPoint(point)
2855
+ );
2848
2856
  this.throwOnRelease = options?.throwOnRelease ?? true;
2849
2857
  this.throwStrength = options?.throwStrength ?? 1;
2850
2858
  this.highlightOnHover = options?.highlightOnHover ?? true;
@@ -2852,6 +2860,17 @@ var _XRInteractableComponent = class _XRInteractableComponent extends Component
2852
2860
  };
2853
2861
  __name(_XRInteractableComponent, "XRInteractableComponent");
2854
2862
  var XRInteractableComponent = _XRInteractableComponent;
2863
+ function createAttachPoint(partial) {
2864
+ return {
2865
+ id: partial.id,
2866
+ name: partial.name ?? partial.id,
2867
+ position: { x: 0, y: 0, z: 0, ...partial.position },
2868
+ rotation: { x: 0, y: 0, z: 0, ...partial.rotation },
2869
+ hand: partial.hand ?? "any",
2870
+ role: partial.role ?? "any"
2871
+ };
2872
+ }
2873
+ __name(createAttachPoint, "createAttachPoint");
2855
2874
 
2856
2875
  // core/factories/components/XRInteractableFactory.ts
2857
2876
  function createXRInteractableComponent(world, entityId, ...args) {
@@ -2958,7 +2977,7 @@ var SHARED_MODEL_RESOURCE_FLAG = "spatialEcsSharedModelResource";
2958
2977
  var modelCache = /* @__PURE__ */ new Map();
2959
2978
  function markSharedResources(root) {
2960
2979
  root.traverse((child) => {
2961
- if (!(child instanceof THREE39__namespace.Mesh)) {
2980
+ if (!(child instanceof THREE51__namespace.Mesh)) {
2962
2981
  return;
2963
2982
  }
2964
2983
  if (child.geometry) {
@@ -3037,10 +3056,10 @@ var _ObjectManagementSystem = class _ObjectManagementSystem {
3037
3056
  }
3038
3057
  getOrCreateAudioListener() {
3039
3058
  const existing = this.camera.userData.ecsAudioListener;
3040
- if (existing instanceof THREE39__namespace.AudioListener) {
3059
+ if (existing instanceof THREE51__namespace.AudioListener) {
3041
3060
  return existing;
3042
3061
  }
3043
- const listener = new THREE39__namespace.AudioListener();
3062
+ const listener = new THREE51__namespace.AudioListener();
3044
3063
  this.camera.add(listener);
3045
3064
  this.camera.userData.ecsAudioListener = listener;
3046
3065
  return listener;
@@ -3114,7 +3133,7 @@ var _ObjectManagementSystem = class _ObjectManagementSystem {
3114
3133
  }
3115
3134
  if (dispose && object3d) {
3116
3135
  object3d.traverse((child) => {
3117
- if (child instanceof THREE39__namespace.Mesh) {
3136
+ if (child instanceof THREE51__namespace.Mesh) {
3118
3137
  if (!child.geometry?.userData?.[SHARED_MODEL_RESOURCE_FLAG]) {
3119
3138
  child.geometry?.dispose();
3120
3139
  }
@@ -3251,10 +3270,10 @@ __name(createBaseEntity, "createBaseEntity");
3251
3270
  // core/factories/objects/AudioFactory.ts
3252
3271
  function getOrCreateListener(camera) {
3253
3272
  const existing = camera.userData.ecsAudioListener;
3254
- if (existing instanceof THREE39__namespace.AudioListener) {
3273
+ if (existing instanceof THREE51__namespace.AudioListener) {
3255
3274
  return existing;
3256
3275
  }
3257
- const listener = new THREE39__namespace.AudioListener();
3276
+ const listener = new THREE51__namespace.AudioListener();
3258
3277
  camera.add(listener);
3259
3278
  camera.userData.ecsAudioListener = listener;
3260
3279
  return listener;
@@ -3267,7 +3286,7 @@ function createAudio({
3267
3286
  payload,
3268
3287
  isEditor
3269
3288
  }) {
3270
- const anchor = new THREE39__namespace.Object3D();
3289
+ const anchor = new THREE51__namespace.Object3D();
3271
3290
  const entityId = createBaseEntity(world, anchor, {
3272
3291
  label: payload.name ?? "Audio",
3273
3292
  entityType: "audio",
@@ -3289,7 +3308,7 @@ function createAudio({
3289
3308
  return entityId;
3290
3309
  }
3291
3310
  if (!isEditor) {
3292
- const loader = new THREE39__namespace.AudioLoader();
3311
+ const loader = new THREE51__namespace.AudioLoader();
3293
3312
  loader.load(
3294
3313
  audio.path,
3295
3314
  (buffer) => {
@@ -3364,7 +3383,7 @@ function applyCameraSettings(camera, options) {
3364
3383
  const near = typeof options.near === "number" ? options.near : DEFAULT_NEAR2;
3365
3384
  const far = typeof options.far === "number" ? options.far : DEFAULT_FAR2;
3366
3385
  const projection = options.projection;
3367
- if (camera instanceof THREE39__namespace.PerspectiveCamera) {
3386
+ if (camera instanceof THREE51__namespace.PerspectiveCamera) {
3368
3387
  if (!projection || projection === "perspective") {
3369
3388
  camera.fov = typeof options.fov === "number" ? options.fov : DEFAULT_FOV2;
3370
3389
  }
@@ -3374,7 +3393,7 @@ function applyCameraSettings(camera, options) {
3374
3393
  camera.updateProjectionMatrix();
3375
3394
  return;
3376
3395
  }
3377
- if (camera instanceof THREE39__namespace.OrthographicCamera) {
3396
+ if (camera instanceof THREE51__namespace.OrthographicCamera) {
3378
3397
  camera.left = typeof options.left === "number" ? options.left : -DEFAULT_ORTHOGRAPHIC_HALF_HEIGHT;
3379
3398
  camera.right = typeof options.right === "number" ? options.right : DEFAULT_ORTHOGRAPHIC_HALF_HEIGHT;
3380
3399
  camera.top = typeof options.top === "number" ? options.top : DEFAULT_ORTHOGRAPHIC_HALF_HEIGHT;
@@ -3395,7 +3414,7 @@ function createCameraObject(options) {
3395
3414
  const bottom = options.bottom ?? -DEFAULT_ORTHOGRAPHIC_HALF_HEIGHT;
3396
3415
  const left = options.left ?? -DEFAULT_ORTHOGRAPHIC_HALF_HEIGHT;
3397
3416
  const right = options.right ?? DEFAULT_ORTHOGRAPHIC_HALF_HEIGHT;
3398
- const camera = new THREE39__namespace.OrthographicCamera(
3417
+ const camera = new THREE51__namespace.OrthographicCamera(
3399
3418
  left,
3400
3419
  right,
3401
3420
  top,
@@ -3407,7 +3426,7 @@ function createCameraObject(options) {
3407
3426
  camera.updateProjectionMatrix();
3408
3427
  return camera;
3409
3428
  }
3410
- return new THREE39__namespace.PerspectiveCamera(
3429
+ return new THREE51__namespace.PerspectiveCamera(
3411
3430
  options.fov ?? DEFAULT_FOV2,
3412
3431
  readViewportAspect(),
3413
3432
  near,
@@ -3425,7 +3444,7 @@ function createCamera({ world, scene, camera, payload, isEditor }) {
3425
3444
  transformInput: payload.transform
3426
3445
  });
3427
3446
  const objectRef = world.getComponent(entityId, Object3DRef);
3428
- if (objectRef?.object instanceof THREE39__namespace.Camera) {
3447
+ if (objectRef?.object instanceof THREE51__namespace.Camera) {
3429
3448
  objectRef.object.userData.entityId = entityId;
3430
3449
  }
3431
3450
  const componentOptions = {
@@ -3457,9 +3476,9 @@ function createCapsule({
3457
3476
  scene,
3458
3477
  payload
3459
3478
  }) {
3460
- const geometry = new THREE39__namespace.CapsuleGeometry(0.5, 1, 4, 8);
3461
- const material = new THREE39__namespace.MeshStandardMaterial({ color: "#ffffff" });
3462
- const mesh = new THREE39__namespace.Mesh(geometry, material);
3479
+ const geometry = new THREE51__namespace.CapsuleGeometry(0.5, 1, 4, 8);
3480
+ const material = new THREE51__namespace.MeshStandardMaterial({ color: "#ffffff" });
3481
+ const mesh = new THREE51__namespace.Mesh(geometry, material);
3463
3482
  const entityId = createBaseEntity(world, mesh, {
3464
3483
  label: payload.name ?? "Capsule",
3465
3484
  entityType: "capsule",
@@ -3479,9 +3498,9 @@ function createCapsule({
3479
3498
  }
3480
3499
  __name(createCapsule, "createCapsule");
3481
3500
  function createCube({ world, scene, payload }) {
3482
- const geometry = new THREE39__namespace.BoxGeometry(1, 1, 1);
3483
- const material = new THREE39__namespace.MeshStandardMaterial({ color: "#ffffff" });
3484
- const mesh = new THREE39__namespace.Mesh(geometry, material);
3501
+ const geometry = new THREE51__namespace.BoxGeometry(1, 1, 1);
3502
+ const material = new THREE51__namespace.MeshStandardMaterial({ color: "#ffffff" });
3503
+ const mesh = new THREE51__namespace.Mesh(geometry, material);
3485
3504
  const entityId = createBaseEntity(world, mesh, {
3486
3505
  label: payload.name ?? "Cube",
3487
3506
  entityType: "cube",
@@ -3506,9 +3525,9 @@ function createCylinder({
3506
3525
  scene,
3507
3526
  payload
3508
3527
  }) {
3509
- const geometry = new THREE39__namespace.CylinderGeometry(0.5, 0.5, 1, 20);
3510
- const material = new THREE39__namespace.MeshStandardMaterial({ color: "#ffffff" });
3511
- const mesh = new THREE39__namespace.Mesh(geometry, material);
3528
+ const geometry = new THREE51__namespace.CylinderGeometry(0.5, 0.5, 1, 20);
3529
+ const material = new THREE51__namespace.MeshStandardMaterial({ color: "#ffffff" });
3530
+ const mesh = new THREE51__namespace.Mesh(geometry, material);
3512
3531
  const entityId = createBaseEntity(world, mesh, {
3513
3532
  label: payload.name ?? "Cylinder",
3514
3533
  entityType: "cylinder",
@@ -3528,7 +3547,7 @@ function createCylinder({
3528
3547
  }
3529
3548
  __name(createCylinder, "createCylinder");
3530
3549
  function createEmpty({ world, scene, payload, isEditor }) {
3531
- const object = new THREE39__namespace.Group();
3550
+ const object = new THREE51__namespace.Group();
3532
3551
  const entityId = createBaseEntity(world, object, {
3533
3552
  label: payload.name ?? "Empty",
3534
3553
  entityType: "empty",
@@ -3539,7 +3558,7 @@ function createEmpty({ world, scene, payload, isEditor }) {
3539
3558
  }
3540
3559
  __name(createEmpty, "createEmpty");
3541
3560
  function createImage({ world, scene, payload }) {
3542
- const anchor = new THREE39__namespace.Object3D();
3561
+ const anchor = new THREE51__namespace.Object3D();
3543
3562
  const imagePath = payload.path ?? "";
3544
3563
  const entityId = createBaseEntity(world, anchor, {
3545
3564
  label: payload.name ?? "Image",
@@ -3552,7 +3571,7 @@ function createImage({ world, scene, payload }) {
3552
3571
  if (!imagePath) {
3553
3572
  return entityId;
3554
3573
  }
3555
- const loader = new THREE39__namespace.TextureLoader();
3574
+ const loader = new THREE51__namespace.TextureLoader();
3556
3575
  loader.load(
3557
3576
  imagePath,
3558
3577
  (texture) => {
@@ -3560,13 +3579,13 @@ function createImage({ world, scene, payload }) {
3560
3579
  texture.dispose();
3561
3580
  return;
3562
3581
  }
3563
- const material = new THREE39__namespace.MeshBasicMaterial({
3582
+ const material = new THREE51__namespace.MeshBasicMaterial({
3564
3583
  map: texture,
3565
3584
  transparent: true,
3566
- side: THREE39__namespace.DoubleSide
3585
+ side: THREE51__namespace.DoubleSide
3567
3586
  });
3568
- const geometry = new THREE39__namespace.PlaneGeometry(1, 1);
3569
- const plane = new THREE39__namespace.Mesh(geometry, material);
3587
+ const geometry = new THREE51__namespace.PlaneGeometry(1, 1);
3588
+ const plane = new THREE51__namespace.Mesh(geometry, material);
3570
3589
  plane.userData.entityId = entityId;
3571
3590
  const textureImage = texture.image;
3572
3591
  const width = textureImage?.width ?? 1;
@@ -3612,7 +3631,7 @@ function createImageTarget({
3612
3631
  payload,
3613
3632
  isEditor
3614
3633
  }) {
3615
- const anchor = new THREE39__namespace.Object3D();
3634
+ const anchor = new THREE51__namespace.Object3D();
3616
3635
  const imagePath = payload.path ?? "";
3617
3636
  const entityId = createBaseEntity(world, anchor, {
3618
3637
  label: payload.name ?? "Image Target",
@@ -3629,7 +3648,7 @@ function createImageTarget({
3629
3648
  if (!isEditor || !imagePath) {
3630
3649
  return entityId;
3631
3650
  }
3632
- const loader = new THREE39__namespace.TextureLoader();
3651
+ const loader = new THREE51__namespace.TextureLoader();
3633
3652
  loader.load(
3634
3653
  imagePath,
3635
3654
  (texture) => {
@@ -3637,13 +3656,13 @@ function createImageTarget({
3637
3656
  texture.dispose();
3638
3657
  return;
3639
3658
  }
3640
- const material = new THREE39__namespace.MeshBasicMaterial({
3659
+ const material = new THREE51__namespace.MeshBasicMaterial({
3641
3660
  map: texture,
3642
3661
  transparent: true,
3643
- side: THREE39__namespace.DoubleSide
3662
+ side: THREE51__namespace.DoubleSide
3644
3663
  });
3645
- const geometry = new THREE39__namespace.PlaneGeometry(1, 1);
3646
- const plane = new THREE39__namespace.Mesh(geometry, material);
3664
+ const geometry = new THREE51__namespace.PlaneGeometry(1, 1);
3665
+ const plane = new THREE51__namespace.Mesh(geometry, material);
3647
3666
  plane.userData.entityId = entityId;
3648
3667
  const textureImage = texture.image;
3649
3668
  const width = textureImage?.width ?? 1;
@@ -3694,7 +3713,7 @@ function createInstancedMesh({
3694
3713
  scene,
3695
3714
  payload
3696
3715
  }) {
3697
- const anchor = new THREE39__namespace.Object3D();
3716
+ const anchor = new THREE51__namespace.Object3D();
3698
3717
  const opts = payload.options ?? {};
3699
3718
  const meshKind = isInstancedMeshKind(opts.meshKind) ? opts.meshKind : "cube";
3700
3719
  const meshParameters = opts.meshParameters && typeof opts.meshParameters === "object" ? opts.meshParameters : void 0;
@@ -3765,7 +3784,7 @@ function createAmbientLight({
3765
3784
  scene,
3766
3785
  payload
3767
3786
  }) {
3768
- const light = new THREE39__namespace.AmbientLight("#ffffff", 0.6);
3787
+ const light = new THREE51__namespace.AmbientLight("#ffffff", 0.6);
3769
3788
  const entityId = createBaseEntity(world, light, {
3770
3789
  label: payload.name ?? "Ambient Light",
3771
3790
  entityType: "ambientLight",
@@ -3782,7 +3801,7 @@ function createAreaLight({
3782
3801
  payload,
3783
3802
  isEditor
3784
3803
  }) {
3785
- const light = new THREE39__namespace.RectAreaLight("#ffffff", 5, 4, 4);
3804
+ const light = new THREE51__namespace.RectAreaLight("#ffffff", 5, 4, 4);
3786
3805
  light.lookAt(0, 0, 0);
3787
3806
  const entityId = createBaseEntity(world, light, {
3788
3807
  label: payload.name ?? "Area Light",
@@ -3811,7 +3830,7 @@ function createDirectionalLight({
3811
3830
  payload,
3812
3831
  isEditor
3813
3832
  }) {
3814
- const light = new THREE39__namespace.DirectionalLight("#ffffff", 1.5);
3833
+ const light = new THREE51__namespace.DirectionalLight("#ffffff", 1.5);
3815
3834
  light.castShadow = true;
3816
3835
  const entityId = createBaseEntity(world, light, {
3817
3836
  label: payload.name ?? "Directional Light",
@@ -3822,7 +3841,7 @@ function createDirectionalLight({
3822
3841
  });
3823
3842
  createLightComponent(world, entityId, light);
3824
3843
  if (isEditor) {
3825
- const helper = new THREE39__namespace.DirectionalLightHelper(light, 1.8, "#38bdf8");
3844
+ const helper = new THREE51__namespace.DirectionalLightHelper(light, 1.8, "#38bdf8");
3826
3845
  helper.onBeforeRender = () => {
3827
3846
  helper.update();
3828
3847
  };
@@ -3840,7 +3859,7 @@ function createPointLight({
3840
3859
  payload,
3841
3860
  isEditor
3842
3861
  }) {
3843
- const light = new THREE39__namespace.PointLight("#ffffff", 1, 10);
3862
+ const light = new THREE51__namespace.PointLight("#ffffff", 1, 10);
3844
3863
  const entityId = createBaseEntity(world, light, {
3845
3864
  label: payload.name ?? "Point Light",
3846
3865
  entityType: "pointLight",
@@ -3850,7 +3869,7 @@ function createPointLight({
3850
3869
  });
3851
3870
  createLightComponent(world, entityId, light);
3852
3871
  if (isEditor) {
3853
- const helper = new THREE39__namespace.PointLightHelper(light, 0.35, "#fbbf24");
3872
+ const helper = new THREE51__namespace.PointLightHelper(light, 0.35, "#fbbf24");
3854
3873
  helper.onBeforeRender = () => {
3855
3874
  helper.update();
3856
3875
  };
@@ -3868,7 +3887,7 @@ function createSpotLight({
3868
3887
  payload,
3869
3888
  isEditor
3870
3889
  }) {
3871
- const light = new THREE39__namespace.SpotLight("#ffffff", 1, 20, Math.PI / 6, 0.1, 1);
3890
+ const light = new THREE51__namespace.SpotLight("#ffffff", 1, 20, Math.PI / 6, 0.1, 1);
3872
3891
  const entityId = createBaseEntity(world, light, {
3873
3892
  label: payload.name ?? "Spot Light",
3874
3893
  entityType: "spotLight",
@@ -3878,7 +3897,7 @@ function createSpotLight({
3878
3897
  });
3879
3898
  createLightComponent(world, entityId, light);
3880
3899
  if (isEditor) {
3881
- const helper = new THREE39__namespace.SpotLightHelper(light, "#f59e0b");
3900
+ const helper = new THREE51__namespace.SpotLightHelper(light, "#f59e0b");
3882
3901
  helper.onBeforeRender = () => {
3883
3902
  helper.update();
3884
3903
  };
@@ -3969,6 +3988,7 @@ __export(components_exports, {
3969
3988
  XRInteractorComponent: () => XRInteractorComponent,
3970
3989
  XRInteractorSideComponent: () => XRInteractorSideComponent,
3971
3990
  XRRigComponent: () => XRRigComponent,
3991
+ createAttachPoint: () => createAttachPoint,
3972
3992
  createHandPoseEntry: () => createHandPoseEntry,
3973
3993
  defaultMaterialValue: () => defaultMaterialValue,
3974
3994
  handPoseDefinitionFor: () => handPoseDefinitionFor,
@@ -4029,7 +4049,7 @@ function createModel({
4029
4049
  payload,
4030
4050
  isEditor
4031
4051
  }) {
4032
- const anchor = new THREE39__namespace.Object3D();
4052
+ const anchor = new THREE51__namespace.Object3D();
4033
4053
  const modelPath = payload.path ?? "";
4034
4054
  const entityId = createBaseEntity(world, anchor, {
4035
4055
  label: payload.name ?? "Model",
@@ -4095,12 +4115,12 @@ function createModel({
4095
4115
  }
4096
4116
  __name(createModel, "createModel");
4097
4117
  function createPlane({ world, scene, payload }) {
4098
- const geometry = new THREE39__namespace.PlaneGeometry(100, 100);
4099
- const material = new THREE39__namespace.MeshStandardMaterial({
4118
+ const geometry = new THREE51__namespace.PlaneGeometry(100, 100);
4119
+ const material = new THREE51__namespace.MeshStandardMaterial({
4100
4120
  color: "#ffffff",
4101
- side: THREE39__namespace.DoubleSide
4121
+ side: THREE51__namespace.DoubleSide
4102
4122
  });
4103
- const mesh = new THREE39__namespace.Mesh(geometry, material);
4123
+ const mesh = new THREE51__namespace.Mesh(geometry, material);
4104
4124
  const entityId = createBaseEntity(
4105
4125
  world,
4106
4126
  mesh,
@@ -4136,7 +4156,7 @@ function createScriptObject({
4136
4156
  scene,
4137
4157
  payload
4138
4158
  }) {
4139
- const object = new THREE39__namespace.Group();
4159
+ const object = new THREE51__namespace.Group();
4140
4160
  const entityId = createBaseEntity(world, object, {
4141
4161
  label: payload.name ?? "Script Object",
4142
4162
  entityType: "scriptObject",
@@ -4161,15 +4181,15 @@ function createTeleportArea({
4161
4181
  const options = payload.options ?? {};
4162
4182
  const width = typeof options.width === "number" ? options.width : 10;
4163
4183
  const depth = typeof options.depth === "number" ? options.depth : 10;
4164
- const geometry = new THREE39__namespace.PlaneGeometry(width, depth);
4165
- const material = new THREE39__namespace.MeshBasicMaterial({
4184
+ const geometry = new THREE51__namespace.PlaneGeometry(width, depth);
4185
+ const material = new THREE51__namespace.MeshBasicMaterial({
4166
4186
  color: "#4da3ff",
4167
4187
  transparent: true,
4168
4188
  opacity: 0.18,
4169
- side: THREE39__namespace.DoubleSide,
4189
+ side: THREE51__namespace.DoubleSide,
4170
4190
  depthWrite: false
4171
4191
  });
4172
- const object = new THREE39__namespace.Mesh(geometry, material);
4192
+ const object = new THREE51__namespace.Mesh(geometry, material);
4173
4193
  const entityId = createBaseEntity(world, object, {
4174
4194
  label: payload.name ?? "Teleport Area",
4175
4195
  entityType: "teleportArea",
@@ -4197,7 +4217,7 @@ function createXRInteractor({
4197
4217
  scene,
4198
4218
  payload
4199
4219
  }) {
4200
- const root = new THREE39__namespace.Group();
4220
+ const root = new THREE51__namespace.Group();
4201
4221
  const options = payload.options ?? {};
4202
4222
  const entityId = createBaseEntity(world, root, {
4203
4223
  label: payload.name ?? "XR Interactor",
@@ -4207,7 +4227,7 @@ function createXRInteractor({
4207
4227
  world.addComponent(entityId, new XRInteractorComponent(options));
4208
4228
  scene.add(root);
4209
4229
  for (const side of ["left", "right"]) {
4210
- const slot = new THREE39__namespace.Group();
4230
+ const slot = new THREE51__namespace.Group();
4211
4231
  const label = side === "left" ? "Left Interactor" : "Right Interactor";
4212
4232
  const slotEntityId = createBaseEntity(world, slot, {
4213
4233
  label,
@@ -4225,7 +4245,7 @@ function createXRRig({
4225
4245
  scene,
4226
4246
  payload
4227
4247
  }) {
4228
- const object = new THREE39__namespace.Group();
4248
+ const object = new THREE51__namespace.Group();
4229
4249
  const entityId = createBaseEntity(world, object, {
4230
4250
  label: payload.name ?? "XR Rig",
4231
4251
  entityType: "xrRig",
@@ -4238,7 +4258,7 @@ function createXRRig({
4238
4258
  }
4239
4259
  __name(createXRRig, "createXRRig");
4240
4260
  function createSprite({ world, scene, payload }) {
4241
- const anchor = new THREE39__namespace.Object3D();
4261
+ const anchor = new THREE51__namespace.Object3D();
4242
4262
  const imagePath = payload.path ?? "";
4243
4263
  const entityId = createBaseEntity(world, anchor, {
4244
4264
  label: payload.name ?? "Sprite",
@@ -4250,7 +4270,7 @@ function createSprite({ world, scene, payload }) {
4250
4270
  if (!imagePath) {
4251
4271
  return entityId;
4252
4272
  }
4253
- const loader = new THREE39__namespace.TextureLoader();
4273
+ const loader = new THREE51__namespace.TextureLoader();
4254
4274
  loader.load(
4255
4275
  imagePath,
4256
4276
  (texture) => {
@@ -4258,11 +4278,11 @@ function createSprite({ world, scene, payload }) {
4258
4278
  texture.dispose();
4259
4279
  return;
4260
4280
  }
4261
- const material = new THREE39__namespace.SpriteMaterial({
4281
+ const material = new THREE51__namespace.SpriteMaterial({
4262
4282
  map: texture,
4263
4283
  transparent: true
4264
4284
  });
4265
- const sprite = new THREE39__namespace.Sprite(material);
4285
+ const sprite = new THREE51__namespace.Sprite(material);
4266
4286
  sprite.userData.entityId = entityId;
4267
4287
  const textureImage = texture.image;
4268
4288
  spriteComponent.width = textureImage?.width ?? 1;
@@ -4280,9 +4300,9 @@ function createSprite({ world, scene, payload }) {
4280
4300
  }
4281
4301
  __name(createSprite, "createSprite");
4282
4302
  function createSphere({ world, scene, payload }) {
4283
- const geometry = new THREE39__namespace.SphereGeometry(0.5, 24, 24);
4284
- const material = new THREE39__namespace.MeshStandardMaterial({ color: "#ffffff" });
4285
- const mesh = new THREE39__namespace.Mesh(geometry, material);
4303
+ const geometry = new THREE51__namespace.SphereGeometry(0.5, 24, 24);
4304
+ const material = new THREE51__namespace.MeshStandardMaterial({ color: "#ffffff" });
4305
+ const mesh = new THREE51__namespace.Mesh(geometry, material);
4286
4306
  const entityId = createBaseEntity(world, mesh, {
4287
4307
  label: payload.name ?? "Sphere",
4288
4308
  entityType: "sphere",
@@ -4302,10 +4322,10 @@ function createSphere({ world, scene, payload }) {
4302
4322
  __name(createSphere, "createSphere");
4303
4323
  function getOrCreateListener2(camera) {
4304
4324
  const existing = camera.userData.ecsAudioListener;
4305
- if (existing instanceof THREE39__namespace.AudioListener) {
4325
+ if (existing instanceof THREE51__namespace.AudioListener) {
4306
4326
  return existing;
4307
4327
  }
4308
- const listener = new THREE39__namespace.AudioListener();
4328
+ const listener = new THREE51__namespace.AudioListener();
4309
4329
  camera.add(listener);
4310
4330
  camera.userData.ecsAudioListener = listener;
4311
4331
  return listener;
@@ -4355,10 +4375,10 @@ function normalizeOptions(input) {
4355
4375
  }
4356
4376
  __name(normalizeOptions, "normalizeOptions");
4357
4377
  function createChromaMaterial(texture, options) {
4358
- return new THREE39__namespace.ShaderMaterial({
4378
+ return new THREE51__namespace.ShaderMaterial({
4359
4379
  uniforms: {
4360
4380
  tex: { value: texture },
4361
- keyColor: { value: new THREE39__namespace.Color(options.backgroundColor) },
4381
+ keyColor: { value: new THREE51__namespace.Color(options.backgroundColor) },
4362
4382
  similarity: { value: options.similarity },
4363
4383
  smoothness: { value: options.smoothness },
4364
4384
  spill: { value: options.spill }
@@ -4390,22 +4410,22 @@ function createChromaMaterial(texture, options) {
4390
4410
  }
4391
4411
  `,
4392
4412
  transparent: true,
4393
- side: THREE39__namespace.DoubleSide
4413
+ side: THREE51__namespace.DoubleSide
4394
4414
  });
4395
4415
  }
4396
4416
  __name(createChromaMaterial, "createChromaMaterial");
4397
4417
  function createStandardMaterial(texture) {
4398
- return new THREE39__namespace.MeshBasicMaterial({
4418
+ return new THREE51__namespace.MeshBasicMaterial({
4399
4419
  map: texture,
4400
4420
  transparent: true,
4401
- side: THREE39__namespace.DoubleSide
4421
+ side: THREE51__namespace.DoubleSide
4402
4422
  });
4403
4423
  }
4404
4424
  __name(createStandardMaterial, "createStandardMaterial");
4405
4425
  function createVideoMesh(entityId, texture, options) {
4406
- const geometry = new THREE39__namespace.PlaneGeometry(1, 1);
4426
+ const geometry = new THREE51__namespace.PlaneGeometry(1, 1);
4407
4427
  const material = options.isGreenScreen ? createChromaMaterial(texture, options) : createStandardMaterial(texture);
4408
- const mesh = new THREE39__namespace.Mesh(geometry, material);
4428
+ const mesh = new THREE51__namespace.Mesh(geometry, material);
4409
4429
  mesh.userData.entityId = entityId;
4410
4430
  mesh.scale.set(options.width, options.height, 1);
4411
4431
  return { mesh, material };
@@ -4440,7 +4460,7 @@ function createVideo({
4440
4460
  payload,
4441
4461
  isEditor
4442
4462
  }) {
4443
- const anchor = new THREE39__namespace.Object3D();
4463
+ const anchor = new THREE51__namespace.Object3D();
4444
4464
  const path = payload.path ?? "";
4445
4465
  const options = normalizeOptions(payload.options);
4446
4466
  const entityId = createBaseEntity(world, anchor, {
@@ -4455,8 +4475,8 @@ function createVideo({
4455
4475
  return entityId;
4456
4476
  }
4457
4477
  const video = createVideoElement(path, options);
4458
- const texture = new THREE39__namespace.VideoTexture(video);
4459
- texture.colorSpace = THREE39__namespace.SRGBColorSpace;
4478
+ const texture = new THREE51__namespace.VideoTexture(video);
4479
+ texture.colorSpace = THREE51__namespace.SRGBColorSpace;
4460
4480
  texture.needsUpdate = true;
4461
4481
  const { mesh, material } = createVideoMesh(entityId, texture, options);
4462
4482
  anchor.add(mesh);
@@ -4472,7 +4492,7 @@ function createVideo({
4472
4492
  });
4473
4493
  if (!isEditor && options.positional) {
4474
4494
  const listener = getOrCreateListener2(camera);
4475
- const audioNode = new THREE39__namespace.PositionalAudio(listener);
4495
+ const audioNode = new THREE51__namespace.PositionalAudio(listener);
4476
4496
  audioNode.setVolume(options.volume);
4477
4497
  audioNode.setRefDistance(options.refDistance);
4478
4498
  audioNode.setDistanceModel(normalizeDistanceModel2(options.distanceModel));
@@ -4861,6 +4881,30 @@ function restorePostCreateComponents(world, objectManagementSystem, targetEntity
4861
4881
  if (typeof sourceInteractable.grabRadius === "number") {
4862
4882
  interactable.grabRadius = sourceInteractable.grabRadius;
4863
4883
  }
4884
+ if (typeof sourceInteractable.grabHands === "string") {
4885
+ interactable.grabHands = sourceInteractable.grabHands;
4886
+ }
4887
+ if (typeof sourceInteractable.twoHandRotation === "string") {
4888
+ interactable.twoHandRotation = sourceInteractable.twoHandRotation;
4889
+ }
4890
+ if (typeof sourceInteractable.allowTwoHandScale === "boolean") {
4891
+ interactable.allowTwoHandScale = sourceInteractable.allowTwoHandScale;
4892
+ }
4893
+ if (typeof sourceInteractable.minScale === "number") {
4894
+ interactable.minScale = sourceInteractable.minScale;
4895
+ }
4896
+ if (typeof sourceInteractable.maxScale === "number") {
4897
+ interactable.maxScale = sourceInteractable.maxScale;
4898
+ }
4899
+ if (Array.isArray(sourceInteractable.attachPoints)) {
4900
+ interactable.attachPoints = sourceInteractable.attachPoints.map((point) => asRecord3(point)).filter(
4901
+ (point) => point !== null && typeof point.id === "string"
4902
+ ).map(
4903
+ (point) => createAttachPoint(
4904
+ point
4905
+ )
4906
+ );
4907
+ }
4864
4908
  if (typeof sourceInteractable.throwOnRelease === "boolean") {
4865
4909
  interactable.throwOnRelease = sourceInteractable.throwOnRelease;
4866
4910
  }
@@ -6660,7 +6704,7 @@ function transitionToClip(runtime, nextClipId, crossFadeDuration) {
6660
6704
  }
6661
6705
  __name(transitionToClip, "transitionToClip");
6662
6706
  function applyActionState(action, component, paused, shouldLoop) {
6663
- const loopMode = shouldLoop ? THREE39__namespace.LoopRepeat : THREE39__namespace.LoopOnce;
6707
+ const loopMode = shouldLoop ? THREE51__namespace.LoopRepeat : THREE51__namespace.LoopOnce;
6664
6708
  const repetitions = shouldLoop ? Infinity : 1;
6665
6709
  action.setLoop(loopMode, repetitions);
6666
6710
  action.clampWhenFinished = !shouldLoop;
@@ -6833,7 +6877,7 @@ var _AnimationSystem = class _AnimationSystem {
6833
6877
  if (runtime) {
6834
6878
  stopAllActions(runtime);
6835
6879
  }
6836
- const mixer = new THREE39__namespace.AnimationMixer(root);
6880
+ const mixer = new THREE51__namespace.AnimationMixer(root);
6837
6881
  const entries2 = readRuntimeClipEntries(animation);
6838
6882
  const indexedActions = createActions(mixer, entries2);
6839
6883
  runtime = {
@@ -6959,11 +7003,11 @@ function normalizeOrthoBounds(component) {
6959
7003
  }
6960
7004
  __name(normalizeOrthoBounds, "normalizeOrthoBounds");
6961
7005
  function isPerspectiveCamera(camera) {
6962
- return camera instanceof THREE39__namespace.PerspectiveCamera;
7006
+ return camera instanceof THREE51__namespace.PerspectiveCamera;
6963
7007
  }
6964
7008
  __name(isPerspectiveCamera, "isPerspectiveCamera");
6965
7009
  function isOrthographicCamera(camera) {
6966
- return camera instanceof THREE39__namespace.OrthographicCamera;
7010
+ return camera instanceof THREE51__namespace.OrthographicCamera;
6967
7011
  }
6968
7012
  __name(isOrthographicCamera, "isOrthographicCamera");
6969
7013
  function readWindowAspect() {
@@ -7017,7 +7061,7 @@ var _CameraSyncSystem = class _CameraSyncSystem {
7017
7061
  continue;
7018
7062
  }
7019
7063
  const camera = objectRef.object;
7020
- if (!(camera instanceof THREE39__namespace.Camera)) {
7064
+ if (!(camera instanceof THREE51__namespace.Camera)) {
7021
7065
  continue;
7022
7066
  }
7023
7067
  if (xrCamera !== null && camera === xrCamera) {
@@ -7084,7 +7128,7 @@ var MIN_DENSITY = 0;
7084
7128
  function createGradientTexture(effect, colors) {
7085
7129
  if (typeof document === "undefined") {
7086
7130
  const pixel = new Uint8Array([30, 30, 30, 255]);
7087
- const fallback = new THREE39__namespace.DataTexture(pixel, 1, 1, THREE39__namespace.RGBAFormat);
7131
+ const fallback = new THREE51__namespace.DataTexture(pixel, 1, 1, THREE51__namespace.RGBAFormat);
7088
7132
  fallback.needsUpdate = true;
7089
7133
  return fallback;
7090
7134
  }
@@ -7093,7 +7137,7 @@ function createGradientTexture(effect, colors) {
7093
7137
  canvas.height = 512;
7094
7138
  const context = canvas.getContext("2d");
7095
7139
  if (!context) {
7096
- const fallback = new THREE39__namespace.CanvasTexture(canvas);
7140
+ const fallback = new THREE51__namespace.CanvasTexture(canvas);
7097
7141
  fallback.needsUpdate = true;
7098
7142
  return fallback;
7099
7143
  }
@@ -7121,15 +7165,15 @@ function createGradientTexture(effect, colors) {
7121
7165
  context.fillRect(0, 0, 512, 512);
7122
7166
  context.globalCompositeOperation = "source-over";
7123
7167
  }
7124
- const texture = new THREE39__namespace.CanvasTexture(canvas);
7125
- texture.colorSpace = THREE39__namespace.SRGBColorSpace;
7168
+ const texture = new THREE51__namespace.CanvasTexture(canvas);
7169
+ texture.colorSpace = THREE51__namespace.SRGBColorSpace;
7126
7170
  texture.needsUpdate = true;
7127
7171
  return texture;
7128
7172
  }
7129
7173
  __name(createGradientTexture, "createGradientTexture");
7130
7174
  var _EnvironmentSyncSystem = class _EnvironmentSyncSystem {
7131
7175
  constructor(scene) {
7132
- this.textureLoader = new THREE39__namespace.TextureLoader();
7176
+ this.textureLoader = new THREE51__namespace.TextureLoader();
7133
7177
  this.signature = null;
7134
7178
  this.activeTexture = null;
7135
7179
  this.pendingImageUrl = null;
@@ -7152,7 +7196,7 @@ var _EnvironmentSyncSystem = class _EnvironmentSyncSystem {
7152
7196
  if (skybox.type === "color") {
7153
7197
  this.disposeActiveTexture();
7154
7198
  this.pendingImageUrl = null;
7155
- this.scene.background = new THREE39__namespace.Color(skybox.color || "#1e1e1e");
7199
+ this.scene.background = new THREE51__namespace.Color(skybox.color || "#1e1e1e");
7156
7200
  return;
7157
7201
  }
7158
7202
  if (skybox.type === "gradient") {
@@ -7186,7 +7230,7 @@ var _EnvironmentSyncSystem = class _EnvironmentSyncSystem {
7186
7230
  texture.dispose();
7187
7231
  return;
7188
7232
  }
7189
- texture.colorSpace = THREE39__namespace.SRGBColorSpace;
7233
+ texture.colorSpace = THREE51__namespace.SRGBColorSpace;
7190
7234
  this.activeTexture = texture;
7191
7235
  this.scene.background = texture;
7192
7236
  },
@@ -7205,16 +7249,16 @@ var _EnvironmentSyncSystem = class _EnvironmentSyncSystem {
7205
7249
  this.scene.fog = null;
7206
7250
  return;
7207
7251
  }
7208
- const fogColor = new THREE39__namespace.Color(fog.color || "#1e1e1e");
7252
+ const fogColor = new THREE51__namespace.Color(fog.color || "#1e1e1e");
7209
7253
  if (fog.type === "linear") {
7210
7254
  const near = Number.isFinite(fog.linear.near) ? fog.linear.near : 1;
7211
7255
  const farCandidate = Number.isFinite(fog.linear.far) ? fog.linear.far : near + 10;
7212
7256
  const far = Math.max(near + MIN_FOG_DELTA, farCandidate);
7213
- this.scene.fog = new THREE39__namespace.Fog(fogColor, near, far);
7257
+ this.scene.fog = new THREE51__namespace.Fog(fogColor, near, far);
7214
7258
  return;
7215
7259
  }
7216
7260
  const density = Number.isFinite(fog.exponential.density) ? Math.max(MIN_DENSITY, fog.exponential.density) : 2e-3;
7217
- this.scene.fog = new THREE39__namespace.FogExp2(fogColor, density);
7261
+ this.scene.fog = new THREE51__namespace.FogExp2(fogColor, density);
7218
7262
  }
7219
7263
  update(world) {
7220
7264
  const entityIds = world.query(Environment);
@@ -7296,10 +7340,10 @@ var _PostprocessingSyncSystem = class _PostprocessingSyncSystem {
7296
7340
  );
7297
7341
  }
7298
7342
  if (values.bloom.enabled) {
7299
- const size = this.renderer.getSize(new THREE39__namespace.Vector2());
7343
+ const size = this.renderer.getSize(new THREE51__namespace.Vector2());
7300
7344
  composer.addPass(
7301
7345
  new UnrealBloomPass_js.UnrealBloomPass(
7302
- new THREE39__namespace.Vector2(size.width, size.height),
7346
+ new THREE51__namespace.Vector2(size.width, size.height),
7303
7347
  values.bloom.intensity,
7304
7348
  values.bloom.radius,
7305
7349
  values.bloom.threshold
@@ -7344,7 +7388,7 @@ var _PostprocessingSyncSystem = class _PostprocessingSyncSystem {
7344
7388
  if (values.dotScreen.enabled) {
7345
7389
  composer.addPass(
7346
7390
  new DotScreenPass_js.DotScreenPass(
7347
- new THREE39__namespace.Vector2(0, 0),
7391
+ new THREE51__namespace.Vector2(0, 0),
7348
7392
  values.dotScreen.angle ?? values.dotScreen.dotScreenAngle,
7349
7393
  values.dotScreen.scale ?? values.dotScreen.dotScreenScale
7350
7394
  )
@@ -7418,7 +7462,7 @@ function computeColliderState(colliderValues, object) {
7418
7462
  if (!object) {
7419
7463
  return colliderValues;
7420
7464
  }
7421
- const scale = new THREE39__namespace.Vector3();
7465
+ const scale = new THREE51__namespace.Vector3();
7422
7466
  object.getWorldScale(scale);
7423
7467
  return {
7424
7468
  ...colliderValues,
@@ -7469,8 +7513,8 @@ function createColliderDesc(RAPIER, values, triMeshData) {
7469
7513
  values.offsetPosition.y,
7470
7514
  values.offsetPosition.z
7471
7515
  );
7472
- const offsetQuaternion = new THREE39__namespace.Quaternion().setFromEuler(
7473
- new THREE39__namespace.Euler(
7516
+ const offsetQuaternion = new THREE51__namespace.Quaternion().setFromEuler(
7517
+ new THREE51__namespace.Euler(
7474
7518
  values.offsetRotation.x,
7475
7519
  values.offsetRotation.y,
7476
7520
  values.offsetRotation.z
@@ -7485,17 +7529,17 @@ function collectTriMeshParts(object) {
7485
7529
  return null;
7486
7530
  }
7487
7531
  object.updateWorldMatrix(true, true);
7488
- const worldScale = new THREE39__namespace.Vector3();
7532
+ const worldScale = new THREE51__namespace.Vector3();
7489
7533
  object.getWorldScale(worldScale);
7490
7534
  const scale = {
7491
7535
  x: Math.abs(worldScale.x) || 1,
7492
7536
  y: Math.abs(worldScale.y) || 1,
7493
7537
  z: Math.abs(worldScale.z) || 1
7494
7538
  };
7495
- const worldToObject = new THREE39__namespace.Matrix4().copy(object.matrixWorld).invert();
7539
+ const worldToObject = new THREE51__namespace.Matrix4().copy(object.matrixWorld).invert();
7496
7540
  const parts = [];
7497
7541
  object.traverse((child) => {
7498
- if (!(child instanceof THREE39__namespace.Mesh) || !child.geometry) {
7542
+ if (!(child instanceof THREE51__namespace.Mesh) || !child.geometry) {
7499
7543
  return;
7500
7544
  }
7501
7545
  const geometry = child.geometry;
@@ -7512,7 +7556,7 @@ function collectTriMeshParts(object) {
7512
7556
  if (indexCount < 3) {
7513
7557
  return;
7514
7558
  }
7515
- const relativeMatrix = new THREE39__namespace.Matrix4().multiplyMatrices(
7559
+ const relativeMatrix = new THREE51__namespace.Matrix4().multiplyMatrices(
7516
7560
  worldToObject,
7517
7561
  child.matrixWorld
7518
7562
  );
@@ -7553,7 +7597,7 @@ function createTriMeshData(collected) {
7553
7597
  }
7554
7598
  const vertices = new Float32Array(vertexTotal * 3);
7555
7599
  const indices = new Uint32Array(indexTotal);
7556
- const point = new THREE39__namespace.Vector3();
7600
+ const point = new THREE51__namespace.Vector3();
7557
7601
  let vertexOffset = 0;
7558
7602
  let indexOffset = 0;
7559
7603
  for (const part of parts) {
@@ -7585,8 +7629,8 @@ function createTriMeshData(collected) {
7585
7629
  }
7586
7630
  __name(createTriMeshData, "createTriMeshData");
7587
7631
  function syncBodyFromTransform(body, transform) {
7588
- const quaternion = new THREE39__namespace.Quaternion().setFromEuler(
7589
- new THREE39__namespace.Euler(transform.rotation.x, transform.rotation.y, transform.rotation.z)
7632
+ const quaternion = new THREE51__namespace.Quaternion().setFromEuler(
7633
+ new THREE51__namespace.Euler(transform.rotation.x, transform.rotation.y, transform.rotation.z)
7590
7634
  );
7591
7635
  body.setTranslation(
7592
7636
  {
@@ -7613,8 +7657,8 @@ function syncTransformFromBody(transform, body) {
7613
7657
  transform.position.x = position.x;
7614
7658
  transform.position.y = position.y;
7615
7659
  transform.position.z = position.z;
7616
- const euler = new THREE39__namespace.Euler().setFromQuaternion(
7617
- new THREE39__namespace.Quaternion(rotation.x, rotation.y, rotation.z, rotation.w)
7660
+ const euler = new THREE51__namespace.Euler().setFromQuaternion(
7661
+ new THREE51__namespace.Quaternion(rotation.x, rotation.y, rotation.z, rotation.w)
7618
7662
  );
7619
7663
  transform.rotation.x = euler.x;
7620
7664
  transform.rotation.y = euler.y;
@@ -7726,8 +7770,8 @@ var _PhysicsSyncSystem = class _PhysicsSyncSystem {
7726
7770
  transform.position.y,
7727
7771
  transform.position.z
7728
7772
  );
7729
- const quaternion = new THREE39__namespace.Quaternion().setFromEuler(
7730
- new THREE39__namespace.Euler(
7773
+ const quaternion = new THREE51__namespace.Quaternion().setFromEuler(
7774
+ new THREE51__namespace.Euler(
7731
7775
  transform.rotation.x,
7732
7776
  transform.rotation.y,
7733
7777
  transform.rotation.z
@@ -8306,7 +8350,7 @@ function applyLightValues(lightComponent) {
8306
8350
  values.castShadow
8307
8351
  );
8308
8352
  }
8309
- if (light instanceof THREE39__namespace.PointLight) {
8353
+ if (light instanceof THREE51__namespace.PointLight) {
8310
8354
  if (typeof values.distance === "number" && Number.isFinite(values.distance)) {
8311
8355
  light.distance = Math.max(MIN_LIGHT_DISTANCE, values.distance);
8312
8356
  }
@@ -8314,7 +8358,7 @@ function applyLightValues(lightComponent) {
8314
8358
  light.decay = Math.max(0, values.decay);
8315
8359
  }
8316
8360
  }
8317
- if (light instanceof THREE39__namespace.SpotLight) {
8361
+ if (light instanceof THREE51__namespace.SpotLight) {
8318
8362
  if (typeof values.distance === "number" && Number.isFinite(values.distance)) {
8319
8363
  light.distance = Math.max(MIN_LIGHT_DISTANCE, values.distance);
8320
8364
  }
@@ -8328,7 +8372,7 @@ function applyLightValues(lightComponent) {
8328
8372
  light.penumbra = Math.max(0, Math.min(1, values.penumbra));
8329
8373
  }
8330
8374
  }
8331
- if (light instanceof THREE39__namespace.RectAreaLight) {
8375
+ if (light instanceof THREE51__namespace.RectAreaLight) {
8332
8376
  if (typeof values.width === "number" && Number.isFinite(values.width)) {
8333
8377
  light.width = Math.max(MIN_AREA_SIZE, values.width);
8334
8378
  }
@@ -8389,15 +8433,15 @@ function resolveMaterialPropertyKey(key) {
8389
8433
  __name(resolveMaterialPropertyKey, "resolveMaterialPropertyKey");
8390
8434
  function createMaterialByType(type) {
8391
8435
  if (type === "basic") {
8392
- return new THREE39__namespace.MeshBasicMaterial();
8436
+ return new THREE51__namespace.MeshBasicMaterial();
8393
8437
  }
8394
8438
  if (type === "phong") {
8395
- return new THREE39__namespace.MeshPhongMaterial();
8439
+ return new THREE51__namespace.MeshPhongMaterial();
8396
8440
  }
8397
8441
  if (type === "physical") {
8398
- return new THREE39__namespace.MeshPhysicalMaterial();
8442
+ return new THREE51__namespace.MeshPhysicalMaterial();
8399
8443
  }
8400
- return new THREE39__namespace.MeshStandardMaterial();
8444
+ return new THREE51__namespace.MeshStandardMaterial();
8401
8445
  }
8402
8446
  __name(createMaterialByType, "createMaterialByType");
8403
8447
  function replaceMaterialAcrossObject(object, previous, next) {
@@ -8456,12 +8500,12 @@ function applyTextureFiltering(material, filtering) {
8456
8500
  const target = material;
8457
8501
  for (const slot of materialTextureSlots) {
8458
8502
  const texture = target[slot];
8459
- if (!texture || !(texture instanceof THREE39__namespace.Texture)) {
8503
+ if (!texture || !(texture instanceof THREE51__namespace.Texture)) {
8460
8504
  continue;
8461
8505
  }
8462
8506
  const useMipmaps = texture.generateMipmaps !== false;
8463
- texture.magFilter = sharp ? THREE39__namespace.NearestFilter : THREE39__namespace.LinearFilter;
8464
- texture.minFilter = useMipmaps ? sharp ? THREE39__namespace.NearestMipmapNearestFilter : THREE39__namespace.LinearMipmapLinearFilter : sharp ? THREE39__namespace.NearestFilter : THREE39__namespace.LinearFilter;
8507
+ texture.magFilter = sharp ? THREE51__namespace.NearestFilter : THREE51__namespace.LinearFilter;
8508
+ texture.minFilter = useMipmaps ? sharp ? THREE51__namespace.NearestMipmapNearestFilter : THREE51__namespace.LinearMipmapLinearFilter : sharp ? THREE51__namespace.NearestFilter : THREE51__namespace.LinearFilter;
8465
8509
  texture.needsUpdate = true;
8466
8510
  }
8467
8511
  material.needsUpdate = true;
@@ -8471,12 +8515,12 @@ function setTextureMipmaps(material, enabled) {
8471
8515
  const target = material;
8472
8516
  for (const slot of materialTextureSlots) {
8473
8517
  const texture = target[slot];
8474
- if (!texture || !(texture instanceof THREE39__namespace.Texture)) {
8518
+ if (!texture || !(texture instanceof THREE51__namespace.Texture)) {
8475
8519
  continue;
8476
8520
  }
8477
8521
  texture.generateMipmaps = enabled;
8478
- const sharp = texture.magFilter === THREE39__namespace.NearestFilter;
8479
- texture.minFilter = enabled ? sharp ? THREE39__namespace.NearestMipmapNearestFilter : THREE39__namespace.LinearMipmapLinearFilter : sharp ? THREE39__namespace.NearestFilter : THREE39__namespace.LinearFilter;
8522
+ const sharp = texture.magFilter === THREE51__namespace.NearestFilter;
8523
+ texture.minFilter = enabled ? sharp ? THREE51__namespace.NearestMipmapNearestFilter : THREE51__namespace.LinearMipmapLinearFilter : sharp ? THREE51__namespace.NearestFilter : THREE51__namespace.LinearFilter;
8480
8524
  texture.needsUpdate = true;
8481
8525
  }
8482
8526
  material.needsUpdate = true;
@@ -8487,7 +8531,7 @@ function assignMaterialTexture(material, rawKey, url, textureCache) {
8487
8531
  const key = resolveMaterialPropertyKey(rawKey);
8488
8532
  let texture = textureCache.get(url);
8489
8533
  if (!texture) {
8490
- texture = new THREE39__namespace.TextureLoader().load(url);
8534
+ texture = new THREE51__namespace.TextureLoader().load(url);
8491
8535
  textureCache.set(url, texture);
8492
8536
  }
8493
8537
  target[key] = texture;
@@ -8525,7 +8569,7 @@ function applyMaterialState(material, value, textureCache) {
8525
8569
  }
8526
8570
  target.side = value.side;
8527
8571
  target.blending = value.blending;
8528
- target.premultipliedAlpha = value.blending === THREE39__namespace.MultiplyBlending || value.blending === THREE39__namespace.SubtractiveBlending;
8572
+ target.premultipliedAlpha = value.blending === THREE51__namespace.MultiplyBlending || value.blending === THREE51__namespace.SubtractiveBlending;
8529
8573
  target.depthTest = value.depthTest;
8530
8574
  target.depthWrite = value.depthWrite;
8531
8575
  target.wireframe = value.wireframe;
@@ -8686,12 +8730,12 @@ function resolvePrimaryMesh(object) {
8686
8730
  if (!object) {
8687
8731
  return null;
8688
8732
  }
8689
- if (object instanceof THREE39__namespace.Mesh) {
8733
+ if (object instanceof THREE51__namespace.Mesh) {
8690
8734
  return object;
8691
8735
  }
8692
8736
  let found = null;
8693
8737
  object.traverse((child) => {
8694
- if (!found && child instanceof THREE39__namespace.Mesh) {
8738
+ if (!found && child instanceof THREE51__namespace.Mesh) {
8695
8739
  found = child;
8696
8740
  }
8697
8741
  });
@@ -8712,22 +8756,22 @@ function applyGeometry(component) {
8712
8756
  switch (component.kind) {
8713
8757
  case "cube": {
8714
8758
  const params = sanitized;
8715
- nextGeometry = new THREE39__namespace.BoxGeometry(params.width, params.height, params.depth);
8759
+ nextGeometry = new THREE51__namespace.BoxGeometry(params.width, params.height, params.depth);
8716
8760
  break;
8717
8761
  }
8718
8762
  case "plane": {
8719
8763
  const params = sanitized;
8720
- nextGeometry = new THREE39__namespace.PlaneGeometry(params.width, params.height);
8764
+ nextGeometry = new THREE51__namespace.PlaneGeometry(params.width, params.height);
8721
8765
  break;
8722
8766
  }
8723
8767
  case "sphere": {
8724
8768
  const params = sanitized;
8725
- nextGeometry = new THREE39__namespace.SphereGeometry(params.radius, 24, 24);
8769
+ nextGeometry = new THREE51__namespace.SphereGeometry(params.radius, 24, 24);
8726
8770
  break;
8727
8771
  }
8728
8772
  case "cylinder": {
8729
8773
  const params = sanitized;
8730
- nextGeometry = new THREE39__namespace.CylinderGeometry(
8774
+ nextGeometry = new THREE51__namespace.CylinderGeometry(
8731
8775
  params.radius,
8732
8776
  params.radius,
8733
8777
  params.height,
@@ -8737,7 +8781,7 @@ function applyGeometry(component) {
8737
8781
  }
8738
8782
  case "capsule": {
8739
8783
  const params = sanitized;
8740
- nextGeometry = new THREE39__namespace.CapsuleGeometry(params.radius, params.height, 4, 8);
8784
+ nextGeometry = new THREE51__namespace.CapsuleGeometry(params.radius, params.height, 4, 8);
8741
8785
  break;
8742
8786
  }
8743
8787
  default:
@@ -8753,7 +8797,7 @@ function applyShadowFlags(component) {
8753
8797
  return;
8754
8798
  }
8755
8799
  component.object.traverse((child) => {
8756
- if (child instanceof THREE39__namespace.Mesh) {
8800
+ if (child instanceof THREE51__namespace.Mesh) {
8757
8801
  child.castShadow = component.castShadow;
8758
8802
  child.receiveShadow = component.receiveShadow;
8759
8803
  }
@@ -8836,35 +8880,35 @@ function buildGeometry(component) {
8836
8880
  switch (component.meshKind) {
8837
8881
  case "cube": {
8838
8882
  const params = p;
8839
- return new THREE39__namespace.BoxGeometry(params.width, params.height, params.depth);
8883
+ return new THREE51__namespace.BoxGeometry(params.width, params.height, params.depth);
8840
8884
  }
8841
8885
  case "plane": {
8842
8886
  const params = p;
8843
- return new THREE39__namespace.PlaneGeometry(params.width, params.height);
8887
+ return new THREE51__namespace.PlaneGeometry(params.width, params.height);
8844
8888
  }
8845
8889
  case "sphere": {
8846
8890
  const params = p;
8847
- return new THREE39__namespace.SphereGeometry(params.radius, 24, 24);
8891
+ return new THREE51__namespace.SphereGeometry(params.radius, 24, 24);
8848
8892
  }
8849
8893
  case "cylinder": {
8850
8894
  const params = p;
8851
- return new THREE39__namespace.CylinderGeometry(params.radius, params.radius, params.height, 20);
8895
+ return new THREE51__namespace.CylinderGeometry(params.radius, params.radius, params.height, 20);
8852
8896
  }
8853
8897
  case "capsule": {
8854
8898
  const params = p;
8855
- return new THREE39__namespace.CapsuleGeometry(params.radius, params.height, 4, 8);
8899
+ return new THREE51__namespace.CapsuleGeometry(params.radius, params.height, 4, 8);
8856
8900
  }
8857
8901
  default:
8858
- return new THREE39__namespace.BoxGeometry(1, 1, 1);
8902
+ return new THREE51__namespace.BoxGeometry(1, 1, 1);
8859
8903
  }
8860
8904
  }
8861
8905
  __name(buildGeometry, "buildGeometry");
8862
- var _position = new THREE39__namespace.Vector3();
8863
- var _quaternion = new THREE39__namespace.Quaternion();
8864
- var _euler = new THREE39__namespace.Euler();
8865
- var _scale = new THREE39__namespace.Vector3();
8866
- var _matrix = new THREE39__namespace.Matrix4();
8867
- var _modelMatrix = new THREE39__namespace.Matrix4();
8906
+ var _position = new THREE51__namespace.Vector3();
8907
+ var _quaternion = new THREE51__namespace.Quaternion();
8908
+ var _euler = new THREE51__namespace.Euler();
8909
+ var _scale = new THREE51__namespace.Vector3();
8910
+ var _matrix = new THREE51__namespace.Matrix4();
8911
+ var _modelMatrix = new THREE51__namespace.Matrix4();
8868
8912
  function instanceTransformFromComponent(transform, out) {
8869
8913
  _position.set(transform.position.x, transform.position.y, transform.position.z);
8870
8914
  _euler.set(transform.rotation.x, transform.rotation.y, transform.rotation.z, "XYZ");
@@ -9017,7 +9061,7 @@ var _InstancedMeshSystem = class _InstancedMeshSystem {
9017
9061
  const sourceMaterial = Array.isArray(meshChild.material) ? meshChild.material.map((m) => m.clone()) : meshChild.material.clone();
9018
9062
  meshChild.updateWorldMatrix(true, false);
9019
9063
  const localMatrix = meshChild.matrixWorld.clone();
9020
- const instancedMesh2 = new THREE39__namespace.InstancedMesh(
9064
+ const instancedMesh2 = new THREE51__namespace.InstancedMesh(
9021
9065
  geometry2,
9022
9066
  Array.isArray(sourceMaterial) ? sourceMaterial : sourceMaterial,
9023
9067
  count2
@@ -9042,7 +9086,7 @@ var _InstancedMeshSystem = class _InstancedMeshSystem {
9042
9086
  this.loadingSignatures.delete(targetEntityId);
9043
9087
  return;
9044
9088
  }
9045
- const group = new THREE39__namespace.Group();
9089
+ const group = new THREE51__namespace.Group();
9046
9090
  for (const entry of entries) {
9047
9091
  group.add(entry.instancedMesh);
9048
9092
  }
@@ -9060,8 +9104,8 @@ var _InstancedMeshSystem = class _InstancedMeshSystem {
9060
9104
  }
9061
9105
  const count = instanceCount;
9062
9106
  const geometry = buildGeometry(comp);
9063
- const material = new THREE39__namespace.MeshStandardMaterial({ color: "#ffffff" });
9064
- const instancedMesh = new THREE39__namespace.InstancedMesh(geometry, material, count);
9107
+ const material = new THREE51__namespace.MeshStandardMaterial({ color: "#ffffff" });
9108
+ const instancedMesh = new THREE51__namespace.InstancedMesh(geometry, material, count);
9065
9109
  instancedMesh.castShadow = comp.castShadow;
9066
9110
  instancedMesh.receiveShadow = comp.receiveShadow;
9067
9111
  for (let i = 0; i < count; i++) {
@@ -9244,7 +9288,7 @@ var _Behaviour = class _Behaviour {
9244
9288
  if (!this.threeRef) {
9245
9289
  return null;
9246
9290
  }
9247
- const position = new THREE39__namespace.Vector3();
9291
+ const position = new THREE51__namespace.Vector3();
9248
9292
  this.threeRef.object.getWorldPosition(position);
9249
9293
  return position;
9250
9294
  }
@@ -9256,7 +9300,7 @@ var _Behaviour = class _Behaviour {
9256
9300
  if (!this.threeRef) {
9257
9301
  return null;
9258
9302
  }
9259
- const target = new THREE39__namespace.Vector3();
9303
+ const target = new THREE51__namespace.Vector3();
9260
9304
  this.threeRef.object.getWorldDirection(target);
9261
9305
  return target;
9262
9306
  }
@@ -9318,7 +9362,7 @@ var _Behaviour = class _Behaviour {
9318
9362
  if (!this.threeRef) {
9319
9363
  return;
9320
9364
  }
9321
- const rotation = new THREE39__namespace.Quaternion();
9365
+ const rotation = new THREE51__namespace.Quaternion();
9322
9366
  this.threeRef.object.getWorldQuaternion(rotation);
9323
9367
  rotation.slerp(targetRotation, alpha);
9324
9368
  this.transform.setRotation(rotation);
@@ -9335,7 +9379,7 @@ var _Behaviour = class _Behaviour {
9335
9379
  return;
9336
9380
  }
9337
9381
  const clone3 = this.threeRef.object.clone();
9338
- const rotation = new THREE39__namespace.Quaternion();
9382
+ const rotation = new THREE51__namespace.Quaternion();
9339
9383
  clone3.lookAt(targetPosition);
9340
9384
  clone3.getWorldQuaternion(rotation);
9341
9385
  this.transform.setRotation(rotation);
@@ -9473,6 +9517,17 @@ var _Behaviour = class _Behaviour {
9473
9517
  *
9474
9518
  * @param input - The source doing the grabbing.
9475
9519
  */
9520
+ /**
9521
+ * A SECOND hand joined a two-hand grab on this entity.
9522
+ *
9523
+ * The first hand anchors the object and keeps holding it; this fires for the
9524
+ * hand that came second — the foregrip on a rifle, say.
9525
+ */
9526
+ onSecondaryGrab(_input) {
9527
+ }
9528
+ /** The second hand let go, leaving the object in the first hand alone. */
9529
+ onSecondaryRelease(_input) {
9530
+ }
9476
9531
  /**
9477
9532
  * A hand pose declared on this entity started being held.
9478
9533
  *
@@ -9690,8 +9745,8 @@ var _ScriptBehaviourSystem = class _ScriptBehaviourSystem {
9690
9745
  }, "onPointerUp");
9691
9746
  this.moduleLoader = moduleLoader ?? defaultModuleLoader;
9692
9747
  this.selectionCtx = selectionContext ?? null;
9693
- this.raycaster = new THREE39__namespace.Raycaster();
9694
- this.ndcPointer = new THREE39__namespace.Vector2();
9748
+ this.raycaster = new THREE51__namespace.Raycaster();
9749
+ this.ndcPointer = new THREE51__namespace.Vector2();
9695
9750
  if (this.selectionCtx) {
9696
9751
  this.selectionCtx.domElement.addEventListener("pointerdown", this.onPointerDown);
9697
9752
  this.selectionCtx.domElement.addEventListener("pointerup", this.onPointerUp);
@@ -10070,7 +10125,7 @@ function disposeBuiltObject(root) {
10070
10125
  for (const mat of materials) {
10071
10126
  if (mat.userData?.[SHARED_MODEL_RESOURCE_FLAG]) continue;
10072
10127
  for (const value of Object.values(mat)) {
10073
- if (value instanceof THREE39__namespace.Texture) value.dispose();
10128
+ if (value instanceof THREE51__namespace.Texture) value.dispose();
10074
10129
  }
10075
10130
  mat.dispose?.();
10076
10131
  }
@@ -10434,7 +10489,7 @@ var _AudioSystem = class _AudioSystem {
10434
10489
  if (!prev || prev.volume !== opts.volume) {
10435
10490
  sound.setVolume(opts.volume);
10436
10491
  }
10437
- if (opts.positional && sound instanceof THREE39__namespace.PositionalAudio) {
10492
+ if (opts.positional && sound instanceof THREE51__namespace.PositionalAudio) {
10438
10493
  if (!prev || prev.refDistance !== opts.refDistance) {
10439
10494
  sound.setRefDistance(opts.refDistance);
10440
10495
  }
@@ -10560,7 +10615,7 @@ var _VideoSystem = class _VideoSystem {
10560
10615
  component.object.scale.set(opts.width, opts.height, 1);
10561
10616
  }
10562
10617
  const material = component.material;
10563
- if (material instanceof THREE39__namespace.ShaderMaterial) {
10618
+ if (material instanceof THREE51__namespace.ShaderMaterial) {
10564
10619
  if (!prev || prev.backgroundColor !== opts.backgroundColor) {
10565
10620
  material.uniforms.keyColor.value.set(opts.backgroundColor);
10566
10621
  }
@@ -10574,7 +10629,7 @@ var _VideoSystem = class _VideoSystem {
10574
10629
  material.uniforms.spill.value = opts.spill;
10575
10630
  }
10576
10631
  }
10577
- if (opts.positional && component.audioNode instanceof THREE39__namespace.PositionalAudio) {
10632
+ if (opts.positional && component.audioNode instanceof THREE51__namespace.PositionalAudio) {
10578
10633
  const posAudio = component.audioNode;
10579
10634
  if (!prev || prev.refDistance !== opts.refDistance) {
10580
10635
  posAudio.setRefDistance(opts.refDistance);
@@ -10614,8 +10669,8 @@ function blankState(source) {
10614
10669
  handedness: handednessOf(source),
10615
10670
  kind: kindOf(source),
10616
10671
  connected: true,
10617
- rayOrigin: new THREE39__namespace.Vector3(),
10618
- rayDirection: new THREE39__namespace.Vector3(0, 0, -1),
10672
+ rayOrigin: new THREE51__namespace.Vector3(),
10673
+ rayDirection: new THREE51__namespace.Vector3(0, 0, -1),
10619
10674
  gripPosition: null,
10620
10675
  gripQuaternion: null,
10621
10676
  select: false,
@@ -10641,7 +10696,7 @@ function readHandJoints(frame, hand, referenceSpace, rigMatrix, existing) {
10641
10696
  }
10642
10697
  if (spaces.length === 0) return null;
10643
10698
  const target = existing ?? {};
10644
- const matrix = new THREE39__namespace.Matrix4();
10699
+ const matrix = new THREE51__namespace.Matrix4();
10645
10700
  const buffer = spaces.length * 16 <= JOINT_MATRIX_BUFFER.length ? JOINT_MATRIX_BUFFER : new Float32Array(spaces.length * 16);
10646
10701
  const fillPoses = frame.fillPoses;
10647
10702
  if (typeof fillPoses === "function") {
@@ -10654,7 +10709,7 @@ function readHandJoints(frame, hand, referenceSpace, rigMatrix, existing) {
10654
10709
  if (filled) {
10655
10710
  for (let i = 0; i < names.length; i += 1) {
10656
10711
  matrix.fromArray(buffer, i * 16).premultiply(rigMatrix);
10657
- const vector = target[names[i]] ?? new THREE39__namespace.Vector3();
10712
+ const vector = target[names[i]] ?? new THREE51__namespace.Vector3();
10658
10713
  vector.setFromMatrixPosition(matrix);
10659
10714
  target[names[i]] = vector;
10660
10715
  }
@@ -10672,7 +10727,7 @@ function readHandJoints(frame, hand, referenceSpace, rigMatrix, existing) {
10672
10727
  continue;
10673
10728
  }
10674
10729
  matrix.fromArray(pose.transform.matrix).premultiply(rigMatrix);
10675
- const vector = target[names[i]] ?? new THREE39__namespace.Vector3();
10730
+ const vector = target[names[i]] ?? new THREE51__namespace.Vector3();
10676
10731
  vector.setFromMatrixPosition(matrix);
10677
10732
  target[names[i]] = vector;
10678
10733
  anyTracked = true;
@@ -10684,7 +10739,7 @@ var _XRInputSystem = class _XRInputSystem {
10684
10739
  constructor() {
10685
10740
  this.records = /* @__PURE__ */ new Map();
10686
10741
  /** Reference-space → world matrix, rebuilt each frame from the XR rig. */
10687
- this.referenceToWorld = new THREE39__namespace.Matrix4();
10742
+ this.referenceToWorld = new THREE51__namespace.Matrix4();
10688
10743
  this.session = null;
10689
10744
  this.onSelectStart = /* @__PURE__ */ __name((event) => this.mark(event, "pendingSelectStart"), "onSelectStart");
10690
10745
  this.onSelectEnd = /* @__PURE__ */ __name((event) => this.mark(event, "pendingSelectEnd"), "onSelectEnd");
@@ -10782,19 +10837,19 @@ var _XRInputSystem = class _XRInputSystem {
10782
10837
  if (frame && referenceSpace && source.targetRaySpace) {
10783
10838
  const pose = frame.getPose(source.targetRaySpace, referenceSpace);
10784
10839
  if (pose) {
10785
- const m = new THREE39__namespace.Matrix4().fromArray(pose.transform.matrix).premultiply(rigMatrix);
10840
+ const m = new THREE51__namespace.Matrix4().fromArray(pose.transform.matrix).premultiply(rigMatrix);
10786
10841
  state.rayOrigin.setFromMatrixPosition(m);
10787
10842
  state.rayDirection.set(0, 0, -1).applyQuaternion(
10788
- new THREE39__namespace.Quaternion().setFromRotationMatrix(m)
10843
+ new THREE51__namespace.Quaternion().setFromRotationMatrix(m)
10789
10844
  ).normalize();
10790
10845
  }
10791
10846
  }
10792
10847
  if (frame && referenceSpace && source.gripSpace) {
10793
10848
  const gripPose = frame.getPose(source.gripSpace, referenceSpace);
10794
10849
  if (gripPose) {
10795
- const m = new THREE39__namespace.Matrix4().fromArray(gripPose.transform.matrix).premultiply(rigMatrix);
10796
- state.gripPosition ?? (state.gripPosition = new THREE39__namespace.Vector3());
10797
- state.gripQuaternion ?? (state.gripQuaternion = new THREE39__namespace.Quaternion());
10850
+ const m = new THREE51__namespace.Matrix4().fromArray(gripPose.transform.matrix).premultiply(rigMatrix);
10851
+ state.gripPosition ?? (state.gripPosition = new THREE51__namespace.Vector3());
10852
+ state.gripQuaternion ?? (state.gripQuaternion = new THREE51__namespace.Quaternion());
10798
10853
  state.gripPosition.setFromMatrixPosition(m);
10799
10854
  state.gripQuaternion.setFromRotationMatrix(m);
10800
10855
  }
@@ -10903,15 +10958,15 @@ var _ThrowVelocityTracker = class _ThrowVelocityTracker {
10903
10958
  const fresh = this.samples.filter(
10904
10959
  (sample) => now - sample.time <= MAX_SAMPLE_AGE_SECONDS
10905
10960
  );
10906
- if (fresh.length < 2) return new THREE39__namespace.Vector3();
10907
- let best = new THREE39__namespace.Vector3();
10961
+ if (fresh.length < 2) return new THREE51__namespace.Vector3();
10962
+ let best = new THREE51__namespace.Vector3();
10908
10963
  let bestSpeed = 0;
10909
10964
  for (let i = 1; i < fresh.length; i += 1) {
10910
10965
  const previous = fresh[i - 1];
10911
10966
  const current = fresh[i];
10912
10967
  const dt = current.time - previous.time;
10913
10968
  if (dt <= 1e-5) continue;
10914
- const velocity = new THREE39__namespace.Vector3().subVectors(current.position, previous.position).divideScalar(dt);
10969
+ const velocity = new THREE51__namespace.Vector3().subVectors(current.position, previous.position).divideScalar(dt);
10915
10970
  const speed = velocity.length();
10916
10971
  if (speed > MAX_PLAUSIBLE_SPEED) continue;
10917
10972
  if (speed > bestSpeed) {
@@ -10928,23 +10983,75 @@ var _ThrowVelocityTracker = class _ThrowVelocityTracker {
10928
10983
  __name(_ThrowVelocityTracker, "ThrowVelocityTracker");
10929
10984
  var ThrowVelocityTracker = _ThrowVelocityTracker;
10930
10985
  function angularVelocityFrom(previous, current, deltaTime) {
10931
- if (deltaTime <= 1e-5) return new THREE39__namespace.Vector3();
10986
+ if (deltaTime <= 1e-5) return new THREE51__namespace.Vector3();
10932
10987
  const delta = current.clone().multiply(previous.clone().invert());
10933
10988
  if (delta.w < 0) {
10934
10989
  delta.set(-delta.x, -delta.y, -delta.z, -delta.w);
10935
10990
  }
10936
- const angle = 2 * Math.acos(THREE39__namespace.MathUtils.clamp(delta.w, -1, 1));
10991
+ const angle = 2 * Math.acos(THREE51__namespace.MathUtils.clamp(delta.w, -1, 1));
10937
10992
  const sinHalf = Math.sqrt(Math.max(0, 1 - delta.w * delta.w));
10938
- if (sinHalf < 1e-6 || angle < 1e-6) return new THREE39__namespace.Vector3();
10939
- return new THREE39__namespace.Vector3(delta.x, delta.y, delta.z).divideScalar(sinHalf).multiplyScalar(angle / deltaTime);
10993
+ if (sinHalf < 1e-6 || angle < 1e-6) return new THREE51__namespace.Vector3();
10994
+ return new THREE51__namespace.Vector3(delta.x, delta.y, delta.z).divideScalar(sinHalf).multiplyScalar(angle / deltaTime);
10940
10995
  }
10941
10996
  __name(angularVelocityFrom, "angularVelocityFrom");
10997
+ var MIN_HAND_SEPARATION = 0.06;
10998
+ var MIN_ANCHOR_SEPARATION = 1e-3;
10999
+ var SCALE_DEADZONE = 0.05;
11000
+ function solveTwoHandTransform(primary, secondary, basis, options) {
11001
+ const separation = primary.position.distanceTo(secondary.position);
11002
+ const anchorDelta = new THREE51__namespace.Vector3().subVectors(
11003
+ basis.secondaryLocal,
11004
+ basis.primaryLocal
11005
+ );
11006
+ const anchorLength = anchorDelta.length();
11007
+ let factor = 1;
11008
+ if (options.allowScale && basis.initialSeparation > MIN_ANCHOR_SEPARATION && separation > MIN_ANCHOR_SEPARATION) {
11009
+ factor = separation / basis.initialSeparation;
11010
+ if (Math.abs(factor - 1) <= SCALE_DEADZONE) {
11011
+ factor = 1;
11012
+ } else {
11013
+ factor += factor > 1 ? -SCALE_DEADZONE : SCALE_DEADZONE;
11014
+ }
11015
+ factor = Math.min(options.maxScale, Math.max(options.minScale, factor));
11016
+ }
11017
+ const scale = basis.initialScale.clone().multiplyScalar(factor);
11018
+ const degenerate = separation < MIN_HAND_SEPARATION || anchorLength < MIN_ANCHOR_SEPARATION;
11019
+ const base = primary.quaternion.clone().multiply(basis.primaryHandOffset);
11020
+ let quaternion;
11021
+ if (options.rotationMode === "primary" || degenerate) {
11022
+ quaternion = base;
11023
+ } else {
11024
+ const axisLocal = anchorDelta.clone().normalize();
11025
+ const currentAxis = axisLocal.clone().applyQuaternion(base).normalize();
11026
+ const desiredAxis = new THREE51__namespace.Vector3().subVectors(secondary.position, primary.position).normalize();
11027
+ const correction = new THREE51__namespace.Quaternion().setFromUnitVectors(
11028
+ currentAxis,
11029
+ desiredAxis
11030
+ );
11031
+ quaternion = correction.multiply(base);
11032
+ }
11033
+ const anchorOffset = basis.primaryLocal.clone().multiply(scale).applyQuaternion(quaternion);
11034
+ const position = primary.position.clone().sub(anchorOffset);
11035
+ return { position, quaternion, scale, degenerate };
11036
+ }
11037
+ __name(solveTwoHandTransform, "solveTwoHandTransform");
10942
11038
 
10943
11039
  // core/systems/XRInteractionSystem.ts
10944
11040
  var RAYLESS_HOLD_DISTANCE = 0.5;
11041
+ function quatFromEulerVec(r) {
11042
+ return new THREE51__namespace.Quaternion().setFromEuler(new THREE51__namespace.Euler(r.x, r.y, r.z));
11043
+ }
11044
+ __name(quatFromEulerVec, "quatFromEulerVec");
11045
+ function writeEuler(target, q) {
11046
+ const euler = new THREE51__namespace.Euler().setFromQuaternion(q);
11047
+ target.x = euler.x;
11048
+ target.y = euler.y;
11049
+ target.z = euler.z;
11050
+ }
11051
+ __name(writeEuler, "writeEuler");
10945
11052
  var _XRInteractionSystem = class _XRInteractionSystem {
10946
11053
  constructor(inputSystem) {
10947
- this.raycaster = new THREE39__namespace.Raycaster();
11054
+ this.raycaster = new THREE51__namespace.Raycaster();
10948
11055
  this.grabs = /* @__PURE__ */ new Map();
10949
11056
  this.hoveredEntityId = null;
10950
11057
  /** Monotonic seconds, accumulated from deltaTime for velocity sampling. */
@@ -10967,7 +11074,6 @@ var _XRInteractionSystem = class _XRInteractionSystem {
10967
11074
  }
10968
11075
  const held = this.grabs.get(input);
10969
11076
  if (held) {
10970
- this.moveHeld(world, input, held, deltaTime);
10971
11077
  if (this.wantsRelease(world, input, held)) {
10972
11078
  this.release(world, input);
10973
11079
  }
@@ -10988,9 +11094,122 @@ var _XRInteractionSystem = class _XRInteractionSystem {
10988
11094
  /* starting */
10989
11095
  true
10990
11096
  )) {
10991
- this.grab(world, input, candidate.entityId, candidate.viaDistance);
11097
+ this.tryGrab(world, input, candidate.entityId, candidate.viaDistance);
10992
11098
  }
10993
11099
  }
11100
+ this.moveAllHeld(world, deltaTime);
11101
+ }
11102
+ /** Hands currently holding an entity. */
11103
+ holdersOf(entityId) {
11104
+ const holders = [];
11105
+ for (const [input, record] of this.grabs) {
11106
+ if (record.entityId === entityId) holders.push({ input, record });
11107
+ }
11108
+ return holders;
11109
+ }
11110
+ /**
11111
+ * Route a new grab: first hand, hand-off, or second hand.
11112
+ *
11113
+ * Which of those happens is the object's choice (`grabHands`), not the
11114
+ * hand's — a ball should pass between hands, a rifle should be held by both,
11115
+ * and a lever should stay with whoever grabbed it first.
11116
+ */
11117
+ tryGrab(world, input, entityId, viaDistance) {
11118
+ const interactable = world.getComponent(entityId, XRInteractableComponent);
11119
+ if (!interactable) return;
11120
+ const holders = this.holdersOf(entityId);
11121
+ if (holders.length === 0) {
11122
+ this.grab(world, input, entityId, viaDistance, "primary");
11123
+ return;
11124
+ }
11125
+ if (holders.some((holder) => holder.input === input)) return;
11126
+ if (interactable.grabHands === "single") return;
11127
+ if (interactable.grabHands === "handOff") {
11128
+ const previous = holders[0];
11129
+ this.grabs.delete(previous.input);
11130
+ const record = previous.record;
11131
+ record.role = "primary";
11132
+ record.twoHand = null;
11133
+ this.reanchor(world, input, record, interactable);
11134
+ this.grabs.set(input, record);
11135
+ this.dispatch(world, entityId, (b) => b.onGrab(input));
11136
+ return;
11137
+ }
11138
+ if (holders.length >= 2) return;
11139
+ this.grab(world, input, entityId, viaDistance, "secondary");
11140
+ this.beginTwoHand(world, entityId);
11141
+ }
11142
+ /**
11143
+ * Re-derive a record's hold from where the object is NOW.
11144
+ *
11145
+ * Used on hand-off and on promotion after the primary lets go. Without it the
11146
+ * object snaps to whatever offset the previous hand had, which reads as the
11147
+ * object jumping out of your grip at the moment you take it.
11148
+ */
11149
+ reanchor(world, input, record, interactable) {
11150
+ const transform = world.getComponent(record.entityId, TransformComponent);
11151
+ if (!transform) return;
11152
+ const hand = this.handPosition(input);
11153
+ const handQuaternion = this.handQuaternion(input);
11154
+ const objectQuaternion = quatFromEulerVec(transform.rotation);
11155
+ record.offset = new THREE51__namespace.Vector3(
11156
+ transform.position.x - hand.x,
11157
+ transform.position.y - hand.y,
11158
+ transform.position.z - hand.z
11159
+ );
11160
+ record.handRotationOffset = handQuaternion.clone().invert().multiply(objectQuaternion);
11161
+ record.remote = false;
11162
+ record.tracker.clear();
11163
+ record.tracker.record(hand, this.elapsed);
11164
+ record.lastHandQuaternion = handQuaternion.clone();
11165
+ if (record.attachLocal && interactable.attachPoints.length === 0) {
11166
+ record.attachLocal = null;
11167
+ record.attachQuaternion = null;
11168
+ record.attachPointId = null;
11169
+ }
11170
+ }
11171
+ /** Capture the two-hand basis once both hands are on the object. */
11172
+ beginTwoHand(world, entityId) {
11173
+ const holders = this.holdersOf(entityId);
11174
+ if (holders.length !== 2) return;
11175
+ const primary = holders.find((h) => h.record.role === "primary");
11176
+ const secondary = holders.find((h) => h.record.role === "secondary");
11177
+ if (!primary || !secondary) return;
11178
+ const transform = world.getComponent(entityId, TransformComponent);
11179
+ if (!transform) return;
11180
+ const primaryHand = this.handPosition(primary.input);
11181
+ const secondaryHand = this.handPosition(secondary.input);
11182
+ const primaryLocal = primary.record.attachLocal?.clone() ?? this.objectLocalPoint(transform, primaryHand);
11183
+ const secondaryLocal = secondary.record.attachLocal?.clone() ?? this.objectLocalPoint(transform, secondaryHand);
11184
+ primary.record.twoHand = {
11185
+ primaryLocal,
11186
+ secondaryLocal,
11187
+ initialScale: new THREE51__namespace.Vector3(
11188
+ transform.scale.x,
11189
+ transform.scale.y,
11190
+ transform.scale.z
11191
+ ),
11192
+ initialSeparation: primaryHand.distanceTo(secondaryHand),
11193
+ // How the object sits relative to the anchoring hand right now, so the
11194
+ // two-hand solve picks up exactly where the one-hand hold left off.
11195
+ primaryHandOffset: this.handQuaternion(primary.input).invert().multiply(quatFromEulerVec(transform.rotation)),
11196
+ initialQuaternion: quatFromEulerVec(transform.rotation)
11197
+ };
11198
+ this.dispatch(world, entityId, (b) => b.onSecondaryGrab(secondary.input));
11199
+ }
11200
+ /** World point → the object's UNSCALED local space. */
11201
+ objectLocalPoint(transform, worldPoint) {
11202
+ const local = worldPoint.clone().sub(
11203
+ new THREE51__namespace.Vector3(
11204
+ transform.position.x,
11205
+ transform.position.y,
11206
+ transform.position.z
11207
+ )
11208
+ ).applyQuaternion(quatFromEulerVec(transform.rotation).invert());
11209
+ local.x /= transform.scale.x || 1;
11210
+ local.y /= transform.scale.y || 1;
11211
+ local.z /= transform.scale.z || 1;
11212
+ return local;
10994
11213
  }
10995
11214
  /** Whether the grab gesture for this object is currently starting. */
10996
11215
  gestureMatches(input, interactable, starting) {
@@ -11039,7 +11258,7 @@ var _XRInteractionSystem = class _XRInteractionSystem {
11039
11258
  );
11040
11259
  if (!interactable2) continue;
11041
11260
  if (interactable2.grabReach === "distance") continue;
11042
- const position = new THREE39__namespace.Vector3();
11261
+ const position = new THREE51__namespace.Vector3();
11043
11262
  entry.object.getWorldPosition(position);
11044
11263
  const distance = position.distanceTo(hand);
11045
11264
  if (distance <= interactable2.grabRadius && distance < nearestDistance) {
@@ -11087,7 +11306,52 @@ var _XRInteractionSystem = class _XRInteractionSystem {
11087
11306
  }
11088
11307
  return nearestId;
11089
11308
  }
11090
- grab(world, input, entityId, viaDistance) {
11309
+ /**
11310
+ * Pick the authored hold this hand should take.
11311
+ *
11312
+ * Filters by hand and by role — that is what makes "the trigger hand goes on
11313
+ * the grip" hold regardless of which hand reaches first — then takes the
11314
+ * nearest remaining one so grabbing near the foregrip picks the foregrip.
11315
+ */
11316
+ chooseAttachPoint(world, input, entityId, interactable, role) {
11317
+ if (interactable.attachPoints.length === 0) return null;
11318
+ const transform = world.getComponent(entityId, TransformComponent);
11319
+ if (!transform) return null;
11320
+ const taken = new Set(
11321
+ this.holdersOf(entityId).map((holder) => holder.record.attachPointId).filter((id) => id !== null)
11322
+ );
11323
+ const hand = this.handPosition(input);
11324
+ const objectPosition = new THREE51__namespace.Vector3(
11325
+ transform.position.x,
11326
+ transform.position.y,
11327
+ transform.position.z
11328
+ );
11329
+ const objectQuaternion = quatFromEulerVec(transform.rotation);
11330
+ const scale = new THREE51__namespace.Vector3(
11331
+ transform.scale.x,
11332
+ transform.scale.y,
11333
+ transform.scale.z
11334
+ );
11335
+ let best = null;
11336
+ let bestDistance = Number.POSITIVE_INFINITY;
11337
+ for (const point of interactable.attachPoints) {
11338
+ if (taken.has(point.id)) continue;
11339
+ if (point.hand !== "any" && point.hand !== input.handedness) continue;
11340
+ if (point.role !== "any" && point.role !== role) continue;
11341
+ const world3 = new THREE51__namespace.Vector3(
11342
+ point.position.x,
11343
+ point.position.y,
11344
+ point.position.z
11345
+ ).multiply(scale).applyQuaternion(objectQuaternion).add(objectPosition);
11346
+ const distance = world3.distanceTo(hand);
11347
+ if (distance < bestDistance) {
11348
+ bestDistance = distance;
11349
+ best = point;
11350
+ }
11351
+ }
11352
+ return best;
11353
+ }
11354
+ grab(world, input, entityId, viaDistance, role) {
11091
11355
  const transform = world.getComponent(entityId, TransformComponent);
11092
11356
  const interactable = world.getComponent(entityId, XRInteractableComponent);
11093
11357
  if (!transform || !interactable) return;
@@ -11097,21 +11361,21 @@ var _XRInteractionSystem = class _XRInteractionSystem {
11097
11361
  let offset;
11098
11362
  let remoteDistance = 0;
11099
11363
  if (remote) {
11100
- const position = new THREE39__namespace.Vector3(
11364
+ const position = new THREE51__namespace.Vector3(
11101
11365
  transform.position.x,
11102
11366
  transform.position.y,
11103
11367
  transform.position.z
11104
11368
  );
11105
11369
  remoteDistance = position.distanceTo(input.rayOrigin);
11106
- offset = new THREE39__namespace.Vector3();
11370
+ offset = new THREE51__namespace.Vector3();
11107
11371
  } else if (viaDistance) {
11108
- offset = new THREE39__namespace.Vector3(
11372
+ offset = new THREE51__namespace.Vector3(
11109
11373
  interactable.grabOffsetPosition.x,
11110
11374
  interactable.grabOffsetPosition.y,
11111
11375
  interactable.grabOffsetPosition.z
11112
11376
  );
11113
11377
  } else {
11114
- offset = new THREE39__namespace.Vector3(
11378
+ offset = new THREE51__namespace.Vector3(
11115
11379
  transform.position.x - hand.x,
11116
11380
  transform.position.y - hand.y,
11117
11381
  transform.position.z - hand.z
@@ -11125,11 +11389,30 @@ var _XRInteractionSystem = class _XRInteractionSystem {
11125
11389
  }
11126
11390
  const tracker = new ThrowVelocityTracker();
11127
11391
  tracker.record(hand, this.elapsed);
11392
+ const attachPoint = this.chooseAttachPoint(
11393
+ world,
11394
+ input,
11395
+ entityId,
11396
+ interactable,
11397
+ role
11398
+ );
11399
+ const objectQuaternion = quatFromEulerVec(transform.rotation);
11400
+ const handRotationOffset = handQuaternion.clone().invert().multiply(objectQuaternion);
11128
11401
  this.grabs.set(input, {
11129
11402
  entityId,
11403
+ role,
11404
+ attachPointId: attachPoint?.id ?? null,
11405
+ attachLocal: attachPoint ? new THREE51__namespace.Vector3(
11406
+ attachPoint.position.x,
11407
+ attachPoint.position.y,
11408
+ attachPoint.position.z
11409
+ ) : null,
11410
+ attachQuaternion: attachPoint ? quatFromEulerVec(attachPoint.rotation) : null,
11411
+ handRotationOffset,
11412
+ twoHand: null,
11130
11413
  offset,
11131
- rotationOffset: new THREE39__namespace.Quaternion().setFromEuler(
11132
- new THREE39__namespace.Euler(
11414
+ rotationOffset: new THREE51__namespace.Quaternion().setFromEuler(
11415
+ new THREE51__namespace.Euler(
11133
11416
  interactable.grabOffsetRotation.x,
11134
11417
  interactable.grabOffsetRotation.y,
11135
11418
  interactable.grabOffsetRotation.z
@@ -11140,33 +11423,110 @@ var _XRInteractionSystem = class _XRInteractionSystem {
11140
11423
  restoreBodyType,
11141
11424
  tracker,
11142
11425
  lastHandQuaternion: handQuaternion.clone(),
11143
- angularVelocity: new THREE39__namespace.Vector3()
11426
+ angularVelocity: new THREE51__namespace.Vector3()
11144
11427
  });
11145
- this.dispatch(world, entityId, (b) => b.onGrab(input));
11428
+ if (role === "primary") {
11429
+ this.dispatch(world, entityId, (b) => b.onGrab(input));
11430
+ }
11431
+ }
11432
+ /** Drive every held object, once each, after grabs and releases settle. */
11433
+ moveAllHeld(world, deltaTime) {
11434
+ const done = /* @__PURE__ */ new Set();
11435
+ for (const [input, record] of this.grabs) {
11436
+ if (done.has(record.entityId)) continue;
11437
+ done.add(record.entityId);
11438
+ const holders = this.holdersOf(record.entityId);
11439
+ if (holders.length >= 2) {
11440
+ this.moveTwoHand(world, record.entityId, holders, deltaTime);
11441
+ } else {
11442
+ this.moveHeld(world, input, record, deltaTime);
11443
+ }
11444
+ }
11445
+ }
11446
+ /** Solve and apply a two-hand hold. */
11447
+ moveTwoHand(world, entityId, holders, deltaTime) {
11448
+ const primary = holders.find((h) => h.record.role === "primary");
11449
+ const secondary = holders.find((h) => h.record.role === "secondary");
11450
+ const transform = world.getComponent(entityId, TransformComponent);
11451
+ const interactable = world.getComponent(entityId, XRInteractableComponent);
11452
+ const basis = primary?.record.twoHand ?? null;
11453
+ if (!primary || !secondary || !transform || !interactable || !basis) {
11454
+ if (primary) {
11455
+ this.moveHeld(world, primary.input, primary.record, deltaTime);
11456
+ }
11457
+ return;
11458
+ }
11459
+ const primaryHand = this.handPosition(primary.input);
11460
+ const primaryQuaternion = this.handQuaternion(primary.input);
11461
+ const solved = solveTwoHandTransform(
11462
+ { position: primaryHand, quaternion: primaryQuaternion },
11463
+ {
11464
+ position: this.handPosition(secondary.input),
11465
+ quaternion: this.handQuaternion(secondary.input)
11466
+ },
11467
+ basis,
11468
+ {
11469
+ rotationMode: interactable.twoHandRotation,
11470
+ allowScale: interactable.allowTwoHandScale,
11471
+ minScale: interactable.minScale,
11472
+ maxScale: interactable.maxScale
11473
+ }
11474
+ );
11475
+ transform.position.x = solved.position.x;
11476
+ transform.position.y = solved.position.y;
11477
+ transform.position.z = solved.position.z;
11478
+ writeEuler(transform.rotation, solved.quaternion);
11479
+ if (interactable.allowTwoHandScale) {
11480
+ transform.scale.x = solved.scale.x;
11481
+ transform.scale.y = solved.scale.y;
11482
+ transform.scale.z = solved.scale.z;
11483
+ }
11484
+ primary.record.tracker.record(primaryHand, this.elapsed);
11485
+ primary.record.angularVelocity = angularVelocityFrom(
11486
+ primary.record.lastHandQuaternion,
11487
+ primaryQuaternion,
11488
+ deltaTime
11489
+ );
11490
+ primary.record.lastHandQuaternion = primaryQuaternion.clone();
11146
11491
  }
11147
11492
  moveHeld(world, input, held, deltaTime) {
11148
11493
  const transform = world.getComponent(held.entityId, TransformComponent);
11149
11494
  if (!transform) return;
11150
11495
  const hand = this.handPosition(input);
11496
+ const handQuaternion = this.handQuaternion(input);
11497
+ const objectQuaternion = held.attachQuaternion ? handQuaternion.clone().multiply(held.rotationOffset).multiply(held.attachQuaternion.clone().invert()) : handQuaternion.clone().multiply(held.handRotationOffset);
11151
11498
  if (held.remote) {
11152
- const target = new THREE39__namespace.Vector3().copy(input.rayDirection).multiplyScalar(held.remoteDistance).add(input.rayOrigin);
11499
+ const target = new THREE51__namespace.Vector3().copy(input.rayDirection).multiplyScalar(held.remoteDistance).add(input.rayOrigin);
11153
11500
  transform.position.x = target.x;
11154
11501
  transform.position.y = target.y;
11155
11502
  transform.position.z = target.z;
11503
+ writeEuler(transform.rotation, objectQuaternion);
11504
+ } else if (held.attachLocal) {
11505
+ const anchor = held.attachLocal.clone().multiply(
11506
+ new THREE51__namespace.Vector3(
11507
+ transform.scale.x,
11508
+ transform.scale.y,
11509
+ transform.scale.z
11510
+ )
11511
+ ).applyQuaternion(objectQuaternion);
11512
+ transform.position.x = hand.x - anchor.x;
11513
+ transform.position.y = hand.y - anchor.y;
11514
+ transform.position.z = hand.z - anchor.z;
11515
+ writeEuler(transform.rotation, objectQuaternion);
11156
11516
  } else {
11157
11517
  transform.position.x = hand.x + held.offset.x;
11158
11518
  transform.position.y = hand.y + held.offset.y;
11159
11519
  transform.position.z = hand.z + held.offset.z;
11520
+ writeEuler(transform.rotation, objectQuaternion);
11160
11521
  }
11161
11522
  held.tracker.record(
11162
- held.remote ? new THREE39__namespace.Vector3(
11523
+ held.remote ? new THREE51__namespace.Vector3(
11163
11524
  transform.position.x,
11164
11525
  transform.position.y,
11165
11526
  transform.position.z
11166
11527
  ) : hand,
11167
11528
  this.elapsed
11168
11529
  );
11169
- const handQuaternion = this.handQuaternion(input);
11170
11530
  held.angularVelocity = angularVelocityFrom(
11171
11531
  held.lastHandQuaternion,
11172
11532
  handQuaternion,
@@ -11182,6 +11542,30 @@ var _XRInteractionSystem = class _XRInteractionSystem {
11182
11542
  held.entityId,
11183
11543
  XRInteractableComponent
11184
11544
  );
11545
+ const remaining = this.holdersOf(held.entityId);
11546
+ if (remaining.length > 0 && interactable) {
11547
+ if (held.role === "secondary") {
11548
+ const primary = remaining.find((h) => h.record.role === "primary");
11549
+ if (primary) {
11550
+ primary.record.twoHand = null;
11551
+ this.reanchor(world, primary.input, primary.record, interactable);
11552
+ }
11553
+ this.dispatch(
11554
+ world,
11555
+ held.entityId,
11556
+ (b) => b.onSecondaryRelease(input)
11557
+ );
11558
+ } else {
11559
+ const next = remaining[0];
11560
+ next.record.role = "primary";
11561
+ next.record.twoHand = null;
11562
+ next.record.restoreBodyType = held.restoreBodyType;
11563
+ this.reanchor(world, next.input, next.record, interactable);
11564
+ this.dispatch(world, held.entityId, (b) => b.onRelease(input));
11565
+ }
11566
+ held.tracker.clear();
11567
+ return;
11568
+ }
11185
11569
  const physics = world.getComponent(held.entityId, PhysicsComponent);
11186
11570
  if (held.restoreBodyType !== null && physics) {
11187
11571
  physics.values.rigidbody.type = held.restoreBodyType;
@@ -11215,7 +11599,7 @@ var _XRInteractionSystem = class _XRInteractionSystem {
11215
11599
  */
11216
11600
  handPosition(input) {
11217
11601
  if (input.gripPosition) return input.gripPosition;
11218
- return new THREE39__namespace.Vector3().copy(input.rayDirection).multiplyScalar(RAYLESS_HOLD_DISTANCE).add(input.rayOrigin);
11602
+ return new THREE51__namespace.Vector3().copy(input.rayDirection).multiplyScalar(RAYLESS_HOLD_DISTANCE).add(input.rayOrigin);
11219
11603
  }
11220
11604
  /**
11221
11605
  * Hand orientation. Grip-less sources (gaze / transient-pointer) have none,
@@ -11223,8 +11607,8 @@ var _XRInteractionSystem = class _XRInteractionSystem {
11223
11607
  */
11224
11608
  handQuaternion(input) {
11225
11609
  if (input.gripQuaternion) return input.gripQuaternion.clone();
11226
- return new THREE39__namespace.Quaternion().setFromUnitVectors(
11227
- new THREE39__namespace.Vector3(0, 0, -1),
11610
+ return new THREE51__namespace.Quaternion().setFromUnitVectors(
11611
+ new THREE51__namespace.Vector3(0, 0, -1),
11228
11612
  input.rayDirection.clone().normalize()
11229
11613
  );
11230
11614
  }
@@ -11249,6 +11633,29 @@ var _XRInteractionSystem = class _XRInteractionSystem {
11249
11633
  isGrabbing() {
11250
11634
  return this.grabs.size > 0;
11251
11635
  }
11636
+ /**
11637
+ * How an entity is currently held.
11638
+ *
11639
+ * Exposed for scripts: a Behaviour can poll this in `onUpdate` to drive
11640
+ * two-hand-specific behaviour — showing a bipod when both hands are on a
11641
+ * weapon, reading the live hand separation to gate a gesture, or reacting to
11642
+ * the scale a pull-apart produced. Returns null when nothing holds it.
11643
+ */
11644
+ getGrabInfo(entityId) {
11645
+ const holders = this.holdersOf(entityId);
11646
+ if (holders.length === 0) return null;
11647
+ const primary = holders.find((h) => h.record.role === "primary");
11648
+ const secondary = holders.find((h) => h.record.role === "secondary");
11649
+ return {
11650
+ hands: holders.length,
11651
+ primaryHandedness: primary?.input.handedness ?? null,
11652
+ secondaryHandedness: secondary?.input.handedness ?? null,
11653
+ handSeparation: primary && secondary ? this.handPosition(primary.input).distanceTo(
11654
+ this.handPosition(secondary.input)
11655
+ ) : null,
11656
+ attachPointIds: holders.map((h) => h.record.attachPointId)
11657
+ };
11658
+ }
11252
11659
  };
11253
11660
  __name(_XRInteractionSystem, "XRInteractionSystem");
11254
11661
  var XRInteractionSystem = _XRInteractionSystem;
@@ -11266,7 +11673,7 @@ function sampleTeleportArc(origin, direction, out = [], options) {
11266
11673
  for (let i = 0; i < steps; i += 1) {
11267
11674
  const t = i / (steps - 1) * maxTime;
11268
11675
  out.push(
11269
- new THREE39__namespace.Vector3(
11676
+ new THREE51__namespace.Vector3(
11270
11677
  origin.x + velocity.x * t,
11271
11678
  origin.y + velocity.y * t - 0.5 * gravity * t * t,
11272
11679
  origin.z + velocity.z * t
@@ -11283,7 +11690,7 @@ function arcGroundCrossing(points, groundY) {
11283
11690
  if (previous.y >= groundY && current.y <= groundY) {
11284
11691
  const span = previous.y - current.y;
11285
11692
  const alpha = span > 1e-6 ? (previous.y - groundY) / span : 0;
11286
- return new THREE39__namespace.Vector3().lerpVectors(previous, current, alpha);
11693
+ return new THREE51__namespace.Vector3().lerpVectors(previous, current, alpha);
11287
11694
  }
11288
11695
  }
11289
11696
  return null;
@@ -11291,11 +11698,11 @@ function arcGroundCrossing(points, groundY) {
11291
11698
  __name(arcGroundCrossing, "arcGroundCrossing");
11292
11699
 
11293
11700
  // core/systems/XRLocomotionSystem.ts
11294
- var UP = new THREE39__namespace.Vector3(0, 1, 0);
11701
+ var UP = new THREE51__namespace.Vector3(0, 1, 0);
11295
11702
  var AXIS_DEADZONE = 0.5;
11296
11703
  var _XRLocomotionSystem = class _XRLocomotionSystem {
11297
11704
  constructor(inputSystem) {
11298
- this.raycaster = new THREE39__namespace.Raycaster();
11705
+ this.raycaster = new THREE51__namespace.Raycaster();
11299
11706
  /** Per-source latch so one stick push yields exactly one snap turn. */
11300
11707
  this.turnLatched = /* @__PURE__ */ new WeakSet();
11301
11708
  /** Reused arc buffer — aiming runs every frame. */
@@ -11404,7 +11811,7 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
11404
11811
  }
11405
11812
  if (this.turnLatched.has(source)) continue;
11406
11813
  this.turnLatched.add(source);
11407
- transform.rotation.y -= Math.sign(x) * THREE39__namespace.MathUtils.degToRad(rig.snapTurnDegrees);
11814
+ transform.rotation.y -= Math.sign(x) * THREE51__namespace.MathUtils.degToRad(rig.snapTurnDegrees);
11408
11815
  }
11409
11816
  }
11410
11817
  applySmoothMove(world, rig, transform, inputs, deltaTime) {
@@ -11414,12 +11821,12 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
11414
11821
  const y = input.axes[1] ?? 0;
11415
11822
  if (Math.abs(x) < 0.15 && Math.abs(y) < 0.15) continue;
11416
11823
  const camera = world.getCamera();
11417
- const forward = new THREE39__namespace.Vector3();
11824
+ const forward = new THREE51__namespace.Vector3();
11418
11825
  camera.getWorldDirection(forward);
11419
11826
  forward.y = 0;
11420
11827
  if (forward.lengthSq() < 1e-6) continue;
11421
11828
  forward.normalize();
11422
- const right = new THREE39__namespace.Vector3().crossVectors(forward, UP).normalize();
11829
+ const right = new THREE51__namespace.Vector3().crossVectors(forward, UP).normalize();
11423
11830
  const step = rig.moveSpeed * Math.max(0, deltaTime);
11424
11831
  transform.position.x += (forward.x * -y + right.x * x) * step;
11425
11832
  transform.position.z += (forward.z * -y + right.z * x) * step;
@@ -11484,7 +11891,7 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
11484
11891
  for (let i = 1; i < points.length; i += 1) {
11485
11892
  const from = points[i - 1];
11486
11893
  const to = points[i];
11487
- const delta = new THREE39__namespace.Vector3().subVectors(to, from);
11894
+ const delta = new THREE51__namespace.Vector3().subVectors(to, from);
11488
11895
  const distance = delta.length();
11489
11896
  if (distance < 1e-6) continue;
11490
11897
  this.raycaster.set(from, delta.divideScalar(distance));
@@ -11692,9 +12099,9 @@ var XRSessionSystem = _XRSessionSystem;
11692
12099
  function buildGeometry2(area) {
11693
12100
  if (area.shape === "circle") {
11694
12101
  const radius = Math.max(5e-3, area.width / 2);
11695
- return new THREE39__namespace.CircleGeometry(radius, 48);
12102
+ return new THREE51__namespace.CircleGeometry(radius, 48);
11696
12103
  }
11697
- return new THREE39__namespace.PlaneGeometry(
12104
+ return new THREE51__namespace.PlaneGeometry(
11698
12105
  Math.max(0.01, area.width),
11699
12106
  Math.max(0.01, area.depth)
11700
12107
  );
@@ -11717,7 +12124,7 @@ var _VRTeleportAreaSystem = class _VRTeleportAreaSystem {
11717
12124
  for (const entityId of entityIds) {
11718
12125
  const area = world.getComponent(entityId, VRTeleportAreaComponent);
11719
12126
  const object = world.getComponent(entityId, Object3DRef)?.object;
11720
- if (!area || !(object instanceof THREE39__namespace.Mesh)) continue;
12127
+ if (!area || !(object instanceof THREE51__namespace.Mesh)) continue;
11721
12128
  const signature = signatureOf(area);
11722
12129
  if (this.signatures.get(entityId) === signature) continue;
11723
12130
  this.signatures.set(entityId, signature);
@@ -11729,18 +12136,18 @@ var _VRTeleportAreaSystem = class _VRTeleportAreaSystem {
11729
12136
  __name(_VRTeleportAreaSystem, "VRTeleportAreaSystem");
11730
12137
  var VRTeleportAreaSystem = _VRTeleportAreaSystem;
11731
12138
  function createHandMaterial(preset, options) {
11732
- const color = new THREE39__namespace.Color(options.color);
12139
+ const color = new THREE51__namespace.Color(options.color);
11733
12140
  switch (preset) {
11734
12141
  case "ghost":
11735
- return new THREE39__namespace.MeshBasicMaterial({
12142
+ return new THREE51__namespace.MeshBasicMaterial({
11736
12143
  color,
11737
12144
  transparent: true,
11738
12145
  opacity: Math.min(1, Math.max(0.05, options.opacity * 0.45)),
11739
12146
  depthWrite: false,
11740
- side: THREE39__namespace.DoubleSide
12147
+ side: THREE51__namespace.DoubleSide
11741
12148
  });
11742
12149
  case "neon":
11743
- return new THREE39__namespace.MeshStandardMaterial({
12150
+ return new THREE51__namespace.MeshStandardMaterial({
11744
12151
  color,
11745
12152
  emissive: color,
11746
12153
  emissiveIntensity: Math.max(0.5, options.emissiveIntensity || 2),
@@ -11750,7 +12157,7 @@ function createHandMaterial(preset, options) {
11750
12157
  opacity: options.opacity
11751
12158
  });
11752
12159
  case "skeleton":
11753
- return new THREE39__namespace.MeshBasicMaterial({
12160
+ return new THREE51__namespace.MeshBasicMaterial({
11754
12161
  color,
11755
12162
  wireframe: true,
11756
12163
  transparent: true,
@@ -11758,7 +12165,7 @@ function createHandMaterial(preset, options) {
11758
12165
  });
11759
12166
  case "custom":
11760
12167
  case "default":
11761
- return new THREE39__namespace.MeshStandardMaterial({
12168
+ return new THREE51__namespace.MeshStandardMaterial({
11762
12169
  color,
11763
12170
  roughness: 0.85,
11764
12171
  metalness: 0,
@@ -11766,10 +12173,10 @@ function createHandMaterial(preset, options) {
11766
12173
  emissiveIntensity: Math.max(0, options.emissiveIntensity),
11767
12174
  transparent: options.opacity < 1,
11768
12175
  opacity: options.opacity,
11769
- side: THREE39__namespace.DoubleSide
12176
+ side: THREE51__namespace.DoubleSide
11770
12177
  });
11771
12178
  default: {
11772
- return new THREE39__namespace.MeshStandardMaterial({ color });
12179
+ return new THREE51__namespace.MeshStandardMaterial({ color });
11773
12180
  }
11774
12181
  }
11775
12182
  }
@@ -11790,7 +12197,7 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
11790
12197
  constructor(options) {
11791
12198
  this.controllerModelFactory = new XRControllerModelFactory_js.XRControllerModelFactory();
11792
12199
  this.handModelFactory = new XRHandModelFactory_js.XRHandModelFactory();
11793
- this.group = new THREE39__namespace.Group();
12200
+ this.group = new THREE51__namespace.Group();
11794
12201
  this.slots = /* @__PURE__ */ new Map();
11795
12202
  this.attachedTo = null;
11796
12203
  /** Last applied preset signature, so materials rebuild only on real change. */
@@ -11939,17 +12346,17 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
11939
12346
  this.attachedTo = target;
11940
12347
  }
11941
12348
  createRay() {
11942
- const geometry = new THREE39__namespace.BufferGeometry().setFromPoints([
11943
- new THREE39__namespace.Vector3(0, 0, 0),
11944
- new THREE39__namespace.Vector3(0, 0, -5)
12349
+ const geometry = new THREE51__namespace.BufferGeometry().setFromPoints([
12350
+ new THREE51__namespace.Vector3(0, 0, 0),
12351
+ new THREE51__namespace.Vector3(0, 0, -5)
11945
12352
  ]);
11946
- const material = new THREE39__namespace.LineBasicMaterial({
12353
+ const material = new THREE51__namespace.LineBasicMaterial({
11947
12354
  color: "#4da3ff",
11948
12355
  transparent: true,
11949
12356
  opacity: 0.6,
11950
12357
  depthTest: false
11951
12358
  });
11952
- const line = new THREE39__namespace.Line(geometry, material);
12359
+ const line = new THREE51__namespace.Line(geometry, material);
11953
12360
  line.name = "XRPointerRay";
11954
12361
  line.renderOrder = 999;
11955
12362
  line.visible = false;
@@ -11978,23 +12385,23 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
11978
12385
  __name(_XRControllerVisualSystem, "XRControllerVisualSystem");
11979
12386
  var XRControllerVisualSystem = _XRControllerVisualSystem;
11980
12387
  var MARKER_RADIUS = 0.28;
11981
- var ACCENT = new THREE39__namespace.Color("#4da3ff");
11982
- var BLOCKED = new THREE39__namespace.Color("#ff5a5a");
12388
+ var ACCENT = new THREE51__namespace.Color("#4da3ff");
12389
+ var BLOCKED = new THREE51__namespace.Color("#ff5a5a");
11983
12390
  var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
11984
12391
  constructor(locomotionSystem) {
11985
- this.group = new THREE39__namespace.Group();
11986
- this.arcGeometry = new THREE39__namespace.BufferGeometry();
11987
- this.marker = new THREE39__namespace.Group();
12392
+ this.group = new THREE51__namespace.Group();
12393
+ this.arcGeometry = new THREE51__namespace.BufferGeometry();
12394
+ this.marker = new THREE51__namespace.Group();
11988
12395
  this.attached = false;
11989
12396
  this.locomotionSystem = locomotionSystem;
11990
12397
  this.group.name = "XRTeleportVisuals";
11991
12398
  this.group.userData.ecsPreviewHidden = true;
11992
- const arcMaterial = new THREE39__namespace.LineBasicMaterial({
12399
+ const arcMaterial = new THREE51__namespace.LineBasicMaterial({
11993
12400
  vertexColors: true,
11994
12401
  transparent: true,
11995
12402
  depthTest: false
11996
12403
  });
11997
- this.arc = new THREE39__namespace.Line(this.arcGeometry, arcMaterial);
12404
+ this.arc = new THREE51__namespace.Line(this.arcGeometry, arcMaterial);
11998
12405
  this.arc.frustumCulled = false;
11999
12406
  this.arc.renderOrder = 998;
12000
12407
  this.group.add(this.arc);
@@ -12042,39 +12449,39 @@ var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
12042
12449
  }
12043
12450
  this.arcGeometry.setAttribute(
12044
12451
  "position",
12045
- new THREE39__namespace.BufferAttribute(positions, 3)
12452
+ new THREE51__namespace.BufferAttribute(positions, 3)
12046
12453
  );
12047
- this.arcGeometry.setAttribute("color", new THREE39__namespace.BufferAttribute(colors, 3));
12454
+ this.arcGeometry.setAttribute("color", new THREE51__namespace.BufferAttribute(colors, 3));
12048
12455
  this.arcGeometry.computeBoundingSphere();
12049
12456
  }
12050
12457
  createRing() {
12051
- const geometry = new THREE39__namespace.RingGeometry(
12458
+ const geometry = new THREE51__namespace.RingGeometry(
12052
12459
  MARKER_RADIUS * 0.72,
12053
12460
  MARKER_RADIUS,
12054
12461
  48
12055
12462
  );
12056
12463
  geometry.rotateX(-Math.PI / 2);
12057
- return new THREE39__namespace.Mesh(
12464
+ return new THREE51__namespace.Mesh(
12058
12465
  geometry,
12059
- new THREE39__namespace.MeshBasicMaterial({
12466
+ new THREE51__namespace.MeshBasicMaterial({
12060
12467
  color: ACCENT,
12061
12468
  transparent: true,
12062
12469
  opacity: 0.9,
12063
- side: THREE39__namespace.DoubleSide,
12470
+ side: THREE51__namespace.DoubleSide,
12064
12471
  depthTest: false
12065
12472
  })
12066
12473
  );
12067
12474
  }
12068
12475
  createDot() {
12069
- const geometry = new THREE39__namespace.CircleGeometry(MARKER_RADIUS * 0.16, 24);
12476
+ const geometry = new THREE51__namespace.CircleGeometry(MARKER_RADIUS * 0.16, 24);
12070
12477
  geometry.rotateX(-Math.PI / 2);
12071
- return new THREE39__namespace.Mesh(
12478
+ return new THREE51__namespace.Mesh(
12072
12479
  geometry,
12073
- new THREE39__namespace.MeshBasicMaterial({
12480
+ new THREE51__namespace.MeshBasicMaterial({
12074
12481
  color: ACCENT,
12075
12482
  transparent: true,
12076
12483
  opacity: 0.55,
12077
- side: THREE39__namespace.DoubleSide,
12484
+ side: THREE51__namespace.DoubleSide,
12078
12485
  depthTest: false
12079
12486
  })
12080
12487
  );
@@ -12176,7 +12583,7 @@ function boneDirections(joints, finger) {
12176
12583
  const from = joints[chain[i - 1]];
12177
12584
  const to = joints[chain[i]];
12178
12585
  if (!from || !to) return null;
12179
- const direction = new THREE39__namespace.Vector3().subVectors(to, from);
12586
+ const direction = new THREE51__namespace.Vector3().subVectors(to, from);
12180
12587
  if (direction.lengthSq() < 1e-12) return null;
12181
12588
  directions.push(direction.normalize());
12182
12589
  }
@@ -12249,8 +12656,8 @@ function computeSpread(joints, a, b) {
12249
12656
  const bBase = joints[METACARPAL_JOINTS[b]];
12250
12657
  const bTip = joints[TIP_JOINTS[b]];
12251
12658
  if (!aBase || !aTip || !bBase || !bTip) return null;
12252
- const dirA = new THREE39__namespace.Vector3().subVectors(aTip, aBase);
12253
- const dirB = new THREE39__namespace.Vector3().subVectors(bTip, bBase);
12659
+ const dirA = new THREE51__namespace.Vector3().subVectors(aTip, aBase);
12660
+ const dirB = new THREE51__namespace.Vector3().subVectors(bTip, bBase);
12254
12661
  if (dirA.lengthSq() < 1e-12 || dirB.lengthSq() < 1e-12) return null;
12255
12662
  return clamp01((1 - dirA.normalize().dot(dirB.normalize())) / 0.45);
12256
12663
  }
@@ -12260,18 +12667,18 @@ function computePalmPose(joints, handedness) {
12260
12667
  const indexBase = joints["index-finger-metacarpal"];
12261
12668
  const pinkyBase = joints["pinky-finger-metacarpal"];
12262
12669
  if (!wrist || !indexBase || !pinkyBase) return null;
12263
- const u = new THREE39__namespace.Vector3().subVectors(indexBase, wrist);
12264
- const v = new THREE39__namespace.Vector3().subVectors(pinkyBase, wrist);
12265
- const normal = new THREE39__namespace.Vector3().crossVectors(u, v);
12670
+ const u = new THREE51__namespace.Vector3().subVectors(indexBase, wrist);
12671
+ const v = new THREE51__namespace.Vector3().subVectors(pinkyBase, wrist);
12672
+ const normal = new THREE51__namespace.Vector3().crossVectors(u, v);
12266
12673
  if (normal.lengthSq() < 1e-12) return null;
12267
12674
  normal.normalize();
12268
12675
  if (handedness === "left") normal.multiplyScalar(-1);
12269
- const right = new THREE39__namespace.Vector3().subVectors(indexBase, pinkyBase);
12676
+ const right = new THREE51__namespace.Vector3().subVectors(indexBase, pinkyBase);
12270
12677
  if (right.lengthSq() < 1e-12) return null;
12271
12678
  right.normalize();
12272
12679
  if (handedness === "left") right.multiplyScalar(-1);
12273
- const up = new THREE39__namespace.Vector3().crossVectors(normal, right).normalize();
12274
- const center = new THREE39__namespace.Vector3().add(wrist).add(indexBase).add(pinkyBase).divideScalar(3);
12680
+ const up = new THREE51__namespace.Vector3().crossVectors(normal, right).normalize();
12681
+ const center = new THREE51__namespace.Vector3().add(wrist).add(indexBase).add(pinkyBase).divideScalar(3);
12275
12682
  return {
12276
12683
  center,
12277
12684
  normal,
@@ -12302,7 +12709,7 @@ function computeHandShape(joints, handedness) {
12302
12709
  const thumbTip = joints["thumb-tip"];
12303
12710
  let thumbDirection = null;
12304
12711
  if (thumbBase && thumbTip) {
12305
- const direction = new THREE39__namespace.Vector3().subVectors(thumbTip, thumbBase);
12712
+ const direction = new THREE51__namespace.Vector3().subVectors(thumbTip, thumbBase);
12306
12713
  if (direction.lengthSq() > 1e-12) thumbDirection = direction.normalize();
12307
12714
  }
12308
12715
  return {
@@ -12334,12 +12741,12 @@ function scoreAgainst(actual, target, tolerance) {
12334
12741
  }
12335
12742
  __name(scoreAgainst, "scoreAgainst");
12336
12743
  var WORLD_DIRECTIONS = {
12337
- up: new THREE39__namespace.Vector3(0, 1, 0),
12338
- down: new THREE39__namespace.Vector3(0, -1, 0),
12339
- forward: new THREE39__namespace.Vector3(0, 0, -1),
12340
- back: new THREE39__namespace.Vector3(0, 0, 1),
12341
- left: new THREE39__namespace.Vector3(-1, 0, 0),
12342
- right: new THREE39__namespace.Vector3(1, 0, 0)
12744
+ up: new THREE51__namespace.Vector3(0, 1, 0),
12745
+ down: new THREE51__namespace.Vector3(0, -1, 0),
12746
+ forward: new THREE51__namespace.Vector3(0, 0, -1),
12747
+ back: new THREE51__namespace.Vector3(0, 0, 1),
12748
+ left: new THREE51__namespace.Vector3(-1, 0, 0),
12749
+ right: new THREE51__namespace.Vector3(1, 0, 0)
12343
12750
  };
12344
12751
  function axisVector(shape, axis) {
12345
12752
  if (axis === "thumb") return shape.thumbDirection;
@@ -12354,7 +12761,7 @@ function resolveDirection(direction, shape, context) {
12354
12761
  const head = context?.headPosition;
12355
12762
  const origin = shape.palm?.center;
12356
12763
  if (!head || !origin) return null;
12357
- const toHead = new THREE39__namespace.Vector3().subVectors(head, origin);
12764
+ const toHead = new THREE51__namespace.Vector3().subVectors(head, origin);
12358
12765
  if (toHead.lengthSq() < 1e-12) return null;
12359
12766
  toHead.normalize();
12360
12767
  return direction === "toward-head" ? toHead : toHead.multiplyScalar(-1);
@@ -12404,8 +12811,8 @@ function matchHandPose(shape, definition, context) {
12404
12811
  if (!handAxis || !wanted) {
12405
12812
  consider(0, "orientation");
12406
12813
  } else {
12407
- const angle = THREE39__namespace.MathUtils.radToDeg(
12408
- Math.acos(THREE39__namespace.MathUtils.clamp(handAxis.dot(wanted), -1, 1))
12814
+ const angle = THREE51__namespace.MathUtils.radToDeg(
12815
+ Math.acos(THREE51__namespace.MathUtils.clamp(handAxis.dot(wanted), -1, 1))
12409
12816
  );
12410
12817
  const normalizedError = Math.max(0, angle - toleranceDegrees) / 90;
12411
12818
  consider(clamp01(1 - normalizedError / MATCH_FALLOFF), "orientation");
@@ -12483,7 +12890,7 @@ var _XRHandPoseSystem = class _XRHandPoseSystem {
12483
12890
  this.trackers = /* @__PURE__ */ new Map();
12484
12891
  this.shapes = /* @__PURE__ */ new Map();
12485
12892
  /** Reused so head-relative orientation checks allocate nothing per frame. */
12486
- this.headPosition = new THREE39__namespace.Vector3();
12893
+ this.headPosition = new THREE51__namespace.Vector3();
12487
12894
  this.elapsed = 0;
12488
12895
  this.inputSystem = inputSystem;
12489
12896
  }
@@ -13274,8 +13681,8 @@ var _World = class _World {
13274
13681
  * ```
13275
13682
  */
13276
13683
  raycast(origin, direction, near = 0, far = Infinity) {
13277
- const rayOrigin = new THREE39__namespace.Vector3(origin.x, origin.y, origin.z);
13278
- const rayDirection = new THREE39__namespace.Vector3(
13684
+ const rayOrigin = new THREE51__namespace.Vector3(origin.x, origin.y, origin.z);
13685
+ const rayDirection = new THREE51__namespace.Vector3(
13279
13686
  direction.x,
13280
13687
  direction.y,
13281
13688
  direction.z
@@ -13284,7 +13691,7 @@ var _World = class _World {
13284
13691
  return [];
13285
13692
  }
13286
13693
  rayDirection.normalize();
13287
- const raycaster = new THREE39__namespace.Raycaster(rayOrigin, rayDirection, near, far);
13694
+ const raycaster = new THREE51__namespace.Raycaster(rayOrigin, rayDirection, near, far);
13288
13695
  const intersections = raycaster.intersectObjects(
13289
13696
  this.scene.children,
13290
13697
  true
@@ -13318,14 +13725,14 @@ var _World = class _World {
13318
13725
  if (!sourceObject) {
13319
13726
  return [];
13320
13727
  }
13321
- const rayOrigin = new THREE39__namespace.Vector3();
13322
- const rayDirection = new THREE39__namespace.Vector3();
13728
+ const rayOrigin = new THREE51__namespace.Vector3();
13729
+ const rayDirection = new THREE51__namespace.Vector3();
13323
13730
  sourceObject.getWorldPosition(rayOrigin);
13324
13731
  sourceObject.getWorldDirection(rayDirection);
13325
13732
  if (rayDirection.lengthSq() === 0) {
13326
13733
  return [];
13327
13734
  }
13328
- const raycaster = new THREE39__namespace.Raycaster(rayOrigin, rayDirection, near, far);
13735
+ const raycaster = new THREE51__namespace.Raycaster(rayOrigin, rayDirection, near, far);
13329
13736
  const intersections = raycaster.intersectObjects(
13330
13737
  this.scene.children,
13331
13738
  true