@relu-interactives/spatial-ecs 0.3.9 → 0.3.11

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-B6I4y1lj.d.ts} +117 -14
  2. package/dist/{XRHandPose-VuSbe4iz.d.cts → XRHandPose-C-KJeYcJ.d.cts} +117 -14
  3. package/dist/{chunk-KIKIWCEB.js → chunk-FSHRPY65.js} +4 -4
  4. package/dist/{chunk-KIKIWCEB.js.map → chunk-FSHRPY65.js.map} +1 -1
  5. package/dist/{chunk-W5TSYV6Q.js → chunk-KLU2M43M.js} +836 -212
  6. package/dist/chunk-KLU2M43M.js.map +1 -0
  7. package/dist/{chunk-KVGGAL5V.js → chunk-TXEGYR76.js} +26 -5
  8. package/dist/chunk-TXEGYR76.js.map +1 -0
  9. package/dist/{chunk-L5BP727H.js → chunk-Y3AC3VZ2.js} +3 -3
  10. package/dist/{chunk-L5BP727H.js.map → chunk-Y3AC3VZ2.js.map} +1 -1
  11. package/dist/components/index.cjs +23 -2
  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 +55 -3
  17. package/dist/factories/index.cjs +22 -2
  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-Bi_wIo1o.d.ts} +107 -1
  23. package/dist/{index-BxdXgqiI.d.ts → index-CEZp7qLL.d.ts} +9 -3
  24. package/dist/{index-BIQoaKAA.d.cts → index-DPRnnSI-.d.cts} +9 -3
  25. package/dist/{index-DyN50JZo.d.cts → index-jlgDou9W.d.cts} +107 -1
  26. package/dist/index.cjs +978 -331
  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 +885 -239
  32. package/dist/systems/index.cjs.map +1 -1
  33. package/dist/systems/index.d.cts +1 -1
  34. package/dist/systems/index.d.ts +1 -1
  35. package/dist/systems/index.js +3 -3
  36. package/package.json +1 -1
  37. package/dist/chunk-KVGGAL5V.js.map +0 -1
  38. package/dist/chunk-W5TSYV6Q.js.map +0 -1
@@ -1,6 +1,6 @@
1
- export { A as AnimationComponent, a as AnimationComponentOptions, b as AudioComponent, C as CameraComponent, c as CameraComponentOptions, d as CameraProjection, e as CameraRuntimeType, f as ColliderShape, g as ColliderState, h as CubeMeshParameters, D as DEFAULT_COLLIDER_STATE, i as DEFAULT_INSTANCED_MESH_PARAMETERS, j as DEFAULT_INSTANCE_TRANSFORM, k as DEFAULT_MESH_GEOMETRY_PARAMETERS, l as DEFAULT_PHYSICS_STATE, m as DEFAULT_POSE_CURLS, n as DEFAULT_RIGIDBODY_STATE, E as EditableMeshObjectKind, o as EntityType, I as ImageComponent, p as ImageTarget, q as ImageTargetAnchor, r as ImageTargetAnchorOptions, s as ImageTargetReference, t as InstanceSlotComponent, u as InstanceTransform, v as InstancedMeshComponent, w as InstancedMeshKind, L as LightComponent, x as LightValueState, M as MaterialComponent, y as MaterialTypeValue, z as MaterialValueState, B as MeshComponent, F as MeshGeometryComponent, G as MeshGeometryParameters, H as MeshGeometryParametersByKind, J as ModelComponent, N as Name, O as Object3DRef, P as PhysicsComponent, K as PhysicsState, Q as PlaneMeshParameters, R as RadiusHeightMeshParameters, S as RadiusMeshParameters, T as RigidbodyState, U as RigidbodyType, V as ScriptComponent, W as ScriptEntry, X as ScriptObjectComponent, Y as ScriptObjectComponentInput, Z as ScriptObjectRuntimeState, _ as Selectable, $ as SelectionTransformState, a0 as SpriteComponent, a1 as TextureFilteringValue, a2 as TransformModeValue, a3 as TransformSpaceValue, a4 as VRTeleportAreaComponent, a5 as VRTeleportAreaOptions, a6 as VideoComponent, a7 as VrTeleportShape, a8 as XRHandPoseComponent, a9 as XRHandPoseOptions, aa as XRInteractableComponent, ab as XRInteractableOptions, ac as XRInteractorComponent, ad as XRInteractorOptions, ae as XRInteractorSideComponent, af as XRRigComponent, ag as XRRigOptions, ah as XrGrabMode, ai as XrHandPoseEntry, aj as XrHandPreset, ak as XrInteractorSide, al as XrInteractorType, am as XrLocomotionMode, an as XrTrackingOrigin, ao as createHandPoseEntry, ap as defaultMaterialValue, aq as handPoseDefinitionFor, ar as normalizePhysicsState, as as setPhysicsLiveRef } from '../XRHandPose-VuSbe4iz.cjs';
1
+ export { A as AnimationComponent, a as AnimationComponentOptions, b as AudioComponent, C as CameraComponent, c as CameraComponentOptions, d as CameraProjection, e as CameraRuntimeType, f as ColliderShape, g as ColliderState, h as CubeMeshParameters, D as DEFAULT_COLLIDER_STATE, i as DEFAULT_INSTANCED_MESH_PARAMETERS, j as DEFAULT_INSTANCE_TRANSFORM, k as DEFAULT_MESH_GEOMETRY_PARAMETERS, l as DEFAULT_PHYSICS_STATE, m as DEFAULT_POSE_CURLS, n as DEFAULT_RIGIDBODY_STATE, E as EditableMeshObjectKind, o as EntityType, I as ImageComponent, p as ImageTarget, q as ImageTargetAnchor, r as ImageTargetAnchorOptions, s as ImageTargetReference, t as InstanceSlotComponent, u as InstanceTransform, v as InstancedMeshComponent, w as InstancedMeshKind, L as LightComponent, x as LightValueState, M as MaterialComponent, y as MaterialTypeValue, z as MaterialValueState, B as MeshComponent, F as MeshGeometryComponent, G as MeshGeometryParameters, H as MeshGeometryParametersByKind, J as ModelComponent, N as Name, O as Object3DRef, P as PhysicsComponent, K as PhysicsState, Q as PlaneMeshParameters, R as RadiusHeightMeshParameters, S as RadiusMeshParameters, T as RigidbodyState, U as RigidbodyType, V as ScriptComponent, W as ScriptEntry, X as ScriptObjectComponent, Y as ScriptObjectComponentInput, Z as ScriptObjectRuntimeState, _ as Selectable, $ as SelectionTransformState, a0 as SpriteComponent, a1 as TextureFilteringValue, a2 as TransformModeValue, a3 as TransformSpaceValue, a4 as VRTeleportAreaComponent, a5 as VRTeleportAreaOptions, a6 as VideoComponent, a7 as VrTeleportShape, a8 as XRHandPoseComponent, a9 as XRHandPoseOptions, aa as XRInteractableComponent, ab as XRInteractableOptions, ac as XRInteractorComponent, ad as XRInteractorOptions, ae as XRInteractorSideComponent, af as XRRigComponent, ag as XRRigOptions, ah as XrAttachPoint, ai as XrDistanceGrabBehavior, aj as XrGrabGesture, ak as XrGrabHands, al as XrGrabReach, am as XrHandPoseEntry, an as XrHandPreset, ao as XrInteractorSide, ap as XrInteractorType, aq as XrLocomotionMode, ar as XrTrackingOrigin, as as XrTwoHandRotation, at as createAttachPoint, au as createHandPoseEntry, av as defaultMaterialValue, aw as handPoseDefinitionFor, ax as normalizePhysicsState, ay as setPhysicsLiveRef } from '../XRHandPose-C-KJeYcJ.cjs';
2
2
  export { D as DEFAULT_ENVIRONMENT_STATE, a as DEFAULT_POSTPROCESSING_STATE, E as Environment, b as EnvironmentFogState, c as EnvironmentFogType, d as EnvironmentGradientEffect, e as EnvironmentSkyboxState, f as EnvironmentSkyboxType, g as EnvironmentState, P as ParentId, h as Postprocessing, i as PostprocessingState, T as TransformComponent, j as TransformData, V as Vec3 } from '../System-31wk-A0g.cjs';
3
- export { P as PrefabInstance, a as PrefabNode } from '../index-BIQoaKAA.cjs';
3
+ export { P as PrefabInstance, a as PrefabNode } from '../index-DPRnnSI-.cjs';
4
4
  import 'three';
5
5
  import '@dimforge/rapier3d-compat';
6
6
  import '../handPose-dFxqbFFY.cjs';
@@ -1,6 +1,6 @@
1
- export { A as AnimationComponent, a as AnimationComponentOptions, b as AudioComponent, C as CameraComponent, c as CameraComponentOptions, d as CameraProjection, e as CameraRuntimeType, f as ColliderShape, g as ColliderState, h as CubeMeshParameters, D as DEFAULT_COLLIDER_STATE, i as DEFAULT_INSTANCED_MESH_PARAMETERS, j as DEFAULT_INSTANCE_TRANSFORM, k as DEFAULT_MESH_GEOMETRY_PARAMETERS, l as DEFAULT_PHYSICS_STATE, m as DEFAULT_POSE_CURLS, n as DEFAULT_RIGIDBODY_STATE, E as EditableMeshObjectKind, o as EntityType, I as ImageComponent, p as ImageTarget, q as ImageTargetAnchor, r as ImageTargetAnchorOptions, s as ImageTargetReference, t as InstanceSlotComponent, u as InstanceTransform, v as InstancedMeshComponent, w as InstancedMeshKind, L as LightComponent, x as LightValueState, M as MaterialComponent, y as MaterialTypeValue, z as MaterialValueState, B as MeshComponent, F as MeshGeometryComponent, G as MeshGeometryParameters, H as MeshGeometryParametersByKind, J as ModelComponent, N as Name, O as Object3DRef, P as PhysicsComponent, K as PhysicsState, Q as PlaneMeshParameters, R as RadiusHeightMeshParameters, S as RadiusMeshParameters, T as RigidbodyState, U as RigidbodyType, V as ScriptComponent, W as ScriptEntry, X as ScriptObjectComponent, Y as ScriptObjectComponentInput, Z as ScriptObjectRuntimeState, _ as Selectable, $ as SelectionTransformState, a0 as SpriteComponent, a1 as TextureFilteringValue, a2 as TransformModeValue, a3 as TransformSpaceValue, a4 as VRTeleportAreaComponent, a5 as VRTeleportAreaOptions, a6 as VideoComponent, a7 as VrTeleportShape, a8 as XRHandPoseComponent, a9 as XRHandPoseOptions, aa as XRInteractableComponent, ab as XRInteractableOptions, ac as XRInteractorComponent, ad as XRInteractorOptions, ae as XRInteractorSideComponent, af as XRRigComponent, ag as XRRigOptions, ah as XrGrabMode, ai as XrHandPoseEntry, aj as XrHandPreset, ak as XrInteractorSide, al as XrInteractorType, am as XrLocomotionMode, an as XrTrackingOrigin, ao as createHandPoseEntry, ap as defaultMaterialValue, aq as handPoseDefinitionFor, ar as normalizePhysicsState, as as setPhysicsLiveRef } from '../XRHandPose-CxPz8VBp.js';
1
+ export { A as AnimationComponent, a as AnimationComponentOptions, b as AudioComponent, C as CameraComponent, c as CameraComponentOptions, d as CameraProjection, e as CameraRuntimeType, f as ColliderShape, g as ColliderState, h as CubeMeshParameters, D as DEFAULT_COLLIDER_STATE, i as DEFAULT_INSTANCED_MESH_PARAMETERS, j as DEFAULT_INSTANCE_TRANSFORM, k as DEFAULT_MESH_GEOMETRY_PARAMETERS, l as DEFAULT_PHYSICS_STATE, m as DEFAULT_POSE_CURLS, n as DEFAULT_RIGIDBODY_STATE, E as EditableMeshObjectKind, o as EntityType, I as ImageComponent, p as ImageTarget, q as ImageTargetAnchor, r as ImageTargetAnchorOptions, s as ImageTargetReference, t as InstanceSlotComponent, u as InstanceTransform, v as InstancedMeshComponent, w as InstancedMeshKind, L as LightComponent, x as LightValueState, M as MaterialComponent, y as MaterialTypeValue, z as MaterialValueState, B as MeshComponent, F as MeshGeometryComponent, G as MeshGeometryParameters, H as MeshGeometryParametersByKind, J as ModelComponent, N as Name, O as Object3DRef, P as PhysicsComponent, K as PhysicsState, Q as PlaneMeshParameters, R as RadiusHeightMeshParameters, S as RadiusMeshParameters, T as RigidbodyState, U as RigidbodyType, V as ScriptComponent, W as ScriptEntry, X as ScriptObjectComponent, Y as ScriptObjectComponentInput, Z as ScriptObjectRuntimeState, _ as Selectable, $ as SelectionTransformState, a0 as SpriteComponent, a1 as TextureFilteringValue, a2 as TransformModeValue, a3 as TransformSpaceValue, a4 as VRTeleportAreaComponent, a5 as VRTeleportAreaOptions, a6 as VideoComponent, a7 as VrTeleportShape, a8 as XRHandPoseComponent, a9 as XRHandPoseOptions, aa as XRInteractableComponent, ab as XRInteractableOptions, ac as XRInteractorComponent, ad as XRInteractorOptions, ae as XRInteractorSideComponent, af as XRRigComponent, ag as XRRigOptions, ah as XrAttachPoint, ai as XrDistanceGrabBehavior, aj as XrGrabGesture, ak as XrGrabHands, al as XrGrabReach, am as XrHandPoseEntry, an as XrHandPreset, ao as XrInteractorSide, ap as XrInteractorType, aq as XrLocomotionMode, ar as XrTrackingOrigin, as as XrTwoHandRotation, at as createAttachPoint, au as createHandPoseEntry, av as defaultMaterialValue, aw as handPoseDefinitionFor, ax as normalizePhysicsState, ay as setPhysicsLiveRef } from '../XRHandPose-B6I4y1lj.js';
2
2
  export { D as DEFAULT_ENVIRONMENT_STATE, a as DEFAULT_POSTPROCESSING_STATE, E as Environment, b as EnvironmentFogState, c as EnvironmentFogType, d as EnvironmentGradientEffect, e as EnvironmentSkyboxState, f as EnvironmentSkyboxType, g as EnvironmentState, P as ParentId, h as Postprocessing, i as PostprocessingState, T as TransformComponent, j as TransformData, V as Vec3 } from '../System-31wk-A0g.js';
3
- export { P as PrefabInstance, a as PrefabNode } from '../index-BxdXgqiI.js';
3
+ export { P as PrefabInstance, a as PrefabNode } from '../index-CEZp7qLL.js';
4
4
  import 'three';
5
5
  import '@dimforge/rapier3d-compat';
6
6
  import '../handPose-dFxqbFFY.js';
@@ -1,4 +1,4 @@
1
- export { AnimationComponent, AudioComponent, CameraComponent, DEFAULT_COLLIDER_STATE, DEFAULT_ENVIRONMENT_STATE, DEFAULT_INSTANCED_MESH_PARAMETERS, DEFAULT_INSTANCE_TRANSFORM, DEFAULT_MESH_GEOMETRY_PARAMETERS, DEFAULT_PHYSICS_STATE, DEFAULT_POSE_CURLS, DEFAULT_POSTPROCESSING_STATE, DEFAULT_RIGIDBODY_STATE, EntityType, Environment, ImageComponent, ImageTarget, ImageTargetAnchor, InstanceSlotComponent, InstancedMeshComponent, LightComponent, MaterialComponent, MeshComponent, MeshGeometryComponent, ModelComponent, Name, Object3DRef, ParentId, PhysicsComponent, Postprocessing, PrefabInstance, PrefabNode, ScriptComponent, ScriptObjectComponent, Selectable, SelectionTransformState, SpriteComponent, TransformComponent, VRTeleportAreaComponent, VideoComponent, XRHandPoseComponent, XRInteractableComponent, XRInteractorComponent, XRInteractorSideComponent, XRRigComponent, createHandPoseEntry, defaultMaterialValue, handPoseDefinitionFor, normalizePhysicsState, setPhysicsLiveRef } from '../chunk-KVGGAL5V.js';
1
+ export { AnimationComponent, AudioComponent, CameraComponent, DEFAULT_COLLIDER_STATE, DEFAULT_ENVIRONMENT_STATE, DEFAULT_INSTANCED_MESH_PARAMETERS, DEFAULT_INSTANCE_TRANSFORM, DEFAULT_MESH_GEOMETRY_PARAMETERS, DEFAULT_PHYSICS_STATE, DEFAULT_POSE_CURLS, DEFAULT_POSTPROCESSING_STATE, DEFAULT_RIGIDBODY_STATE, EntityType, Environment, ImageComponent, ImageTarget, ImageTargetAnchor, InstanceSlotComponent, InstancedMeshComponent, LightComponent, MaterialComponent, MeshComponent, MeshGeometryComponent, ModelComponent, Name, Object3DRef, ParentId, PhysicsComponent, Postprocessing, PrefabInstance, PrefabNode, ScriptComponent, ScriptObjectComponent, Selectable, SelectionTransformState, SpriteComponent, TransformComponent, VRTeleportAreaComponent, VideoComponent, XRHandPoseComponent, XRInteractableComponent, XRInteractorComponent, XRInteractorSideComponent, XRRigComponent, createAttachPoint, createHandPoseEntry, defaultMaterialValue, handPoseDefinitionFor, normalizePhysicsState, setPhysicsLiveRef } from '../chunk-TXEGYR76.js';
2
2
  import '../chunk-OY7ZODZP.js';
3
3
  //# sourceMappingURL=index.js.map
4
4
  //# sourceMappingURL=index.js.map
@@ -39,11 +39,15 @@ Add an **XR Interactable** component in the inspector. The useful fields:
39
39
  - **Reach** — `physical` (hand must touch it), `distance` (grab along the pointer ray), or `both`.
40
40
  - **At Distance** — `snap` brings it to the hand, `remote` manipulates it where it stands.
41
41
  - **Gesture** — `pinch`, `full` grip, or `any`.
42
- - **Grab Mode** — `kinematic` follows the hand exactly; `physics` keeps the body simulated.
43
42
  - **Hold Offset** — where the object sits in the hand once held.
44
- - **Throw on Release** — carries hand momentum into the body.
43
+ - **Throw on Release** — carries hand momentum into the body (on by default).
44
+ - **Hover** — `Outline`, `Grow`, `Outline + grow`, or `None`, plus the colour and grow amount.
45
45
 
46
- For a throwable ball, the object needs a **dynamic rigidbody**, Grab Mode `physics`, and Throw on Release enabled. Release velocity is taken from the peak of a short window of hand motion, so throws match the motion the user made rather than the frame they opened their hand.
46
+ A held object follows the hand exactly and does not collide with the world while held.
47
+
48
+ **To make something throwable, give it a Physics component with a DYNAMIC rigidbody.** That is the only requirement — throwing is on by default. Release velocity is taken from the peak of a short window of hand motion, so throws match the motion the user made rather than the frame they opened their hand.
49
+
50
+ The pointer ray stops at whatever it is pointing at, and hover feedback tells the user what they are about to pick up.
47
51
 
48
52
  ```ts
49
53
  import { Behaviour } from "@relu-interactives/spatial-ecs";
@@ -60,6 +64,54 @@ export default class Basketball extends Behaviour {
60
64
  }
61
65
  ```
62
66
 
67
+ ### Two hands, hand-off, and attach points
68
+
69
+ An object decides how many hands may hold it, via **Hands**:
70
+
71
+ | Setting | Behaviour |
72
+ | --- | --- |
73
+ | `handOff` (default) | Grabbing with the other hand **takes** it — passing something between your hands. |
74
+ | `two` | Both hands hold it. The first anchors it, the second aims it. |
75
+ | `single` | Stays with whichever hand grabbed first. |
76
+
77
+ **Attach points** are authored hand-holds: a local position and rotation, optionally restricted to one `hand`, and given a `role`. The `primary` role is the anchoring hand (a rifle's trigger grip) and `secondary` the steering hand (the foregrip) — setting roles is what makes a two-hand grab assemble correctly no matter which hand grabs first. Among eligible points the nearest to the hand wins, so reaching for the foregrip picks the foregrip.
78
+
79
+ Leave the list empty and hands grab wherever they touch. Two-hand grabbing and resizing still work in that case, anchored wherever the hands landed.
80
+
81
+ For a two-handed rifle: **Hands** `two`, **Second Hand** `Aims the object`, and two attach points — one `primary` at the grip, one `secondary` at the foregrip.
82
+
83
+ The primary hand is anchored and the secondary steers. Twist about the line between the hands comes from the primary hand's own roll, so banking your trigger hand banks the weapon.
84
+
85
+ ### Two-hand resizing
86
+
87
+ Turn on **Resize** and moving both hands apart or together scales the object. Scale is uniform — two grab points give one distance measurement, so there is nothing to drive a second axis independently — and limited by **Min/Max Size**, which bound a single gesture relative to the size when the second hand grabbed. Repeated gestures compound.
88
+
89
+ A small deadzone means ordinary hand drift while carrying something does not resize it.
90
+
91
+ Releasing one hand does not drop the object. Let go with the support hand and the anchoring hand keeps it; let go with the anchoring hand and the other is promoted, so a two-hand hold released one hand at a time can still be thrown.
92
+
93
+ ### Reacting to grabs in script
94
+
95
+ ```ts
96
+ import { Behaviour, type XrInputState } from "@relu-interactives/spatial-ecs";
97
+
98
+ export default class Rifle extends Behaviour {
99
+ onGrab(input: XrInputState) {
100
+ console.log("held by", input.handedness);
101
+ }
102
+
103
+ onSecondaryGrab() {
104
+ // Both hands are on it now — steady the aim, show a bipod, whatever.
105
+ }
106
+
107
+ onSecondaryRelease() {
108
+ // Back to one hand.
109
+ }
110
+ }
111
+ ```
112
+
113
+ Every grab setting is a plain field on the component, so a script can change it mid-session — switch on resizing, retune throw strength, or move an attach point in response to what the player is doing.
114
+
63
115
  ## Hand poses
64
116
 
65
117
  Add an **XR Hand Pose** component and list the poses to watch for. Each is either a built-in preset or a custom set of finger curls.
@@ -2333,7 +2333,6 @@ var _XRInteractableComponent = class _XRInteractableComponent extends Component
2333
2333
  this.enabled = options?.enabled ?? true;
2334
2334
  this.grabbable = options?.grabbable ?? true;
2335
2335
  this.pointable = options?.pointable ?? true;
2336
- this.grabMode = options?.grabMode ?? "kinematic";
2337
2336
  this.grabReach = options?.grabReach ?? "both";
2338
2337
  this.distanceBehavior = options?.distanceBehavior ?? "snap";
2339
2338
  this.grabGesture = options?.grabGesture ?? "any";
@@ -2348,13 +2347,34 @@ var _XRInteractableComponent = class _XRInteractableComponent extends Component
2348
2347
  y: 0,
2349
2348
  z: 0
2350
2349
  };
2350
+ this.grabHands = options?.grabHands ?? "handOff";
2351
+ this.twoHandRotation = options?.twoHandRotation ?? "align";
2352
+ this.allowTwoHandScale = options?.allowTwoHandScale ?? false;
2353
+ this.minScale = options?.minScale ?? 0.25;
2354
+ this.maxScale = options?.maxScale ?? 4;
2355
+ this.attachPoints = (options?.attachPoints ?? []).map(
2356
+ (point) => createAttachPoint(point)
2357
+ );
2351
2358
  this.throwOnRelease = options?.throwOnRelease ?? true;
2352
2359
  this.throwStrength = options?.throwStrength ?? 1;
2353
- this.highlightOnHover = options?.highlightOnHover ?? true;
2360
+ this.hoverBehavior = options?.hoverBehavior ?? "color";
2361
+ this.hoverColor = options?.hoverColor ?? "#4da3ff";
2362
+ this.hoverScale = options?.hoverScale ?? 1.06;
2354
2363
  }
2355
2364
  };
2356
2365
  __name(_XRInteractableComponent, "XRInteractableComponent");
2357
2366
  var XRInteractableComponent = _XRInteractableComponent;
2367
+ function createAttachPoint(partial) {
2368
+ return {
2369
+ id: partial.id,
2370
+ name: partial.name ?? partial.id,
2371
+ position: { x: 0, y: 0, z: 0, ...partial.position },
2372
+ rotation: { x: 0, y: 0, z: 0, ...partial.rotation },
2373
+ hand: partial.hand ?? "any",
2374
+ role: partial.role ?? "any"
2375
+ };
2376
+ }
2377
+ __name(createAttachPoint, "createAttachPoint");
2358
2378
 
2359
2379
  // core/factories/components/XRInteractableFactory.ts
2360
2380
  function createXRInteractableComponent(world, entityId, ...args) {