@relu-interactives/spatial-ecs 0.3.7 → 0.3.9
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.
- package/dist/{System-TmC2EijF.d.cts → System-31wk-A0g.d.cts} +1 -1
- package/dist/{System-TmC2EijF.d.ts → System-31wk-A0g.d.ts} +1 -1
- package/dist/{XRInteractor-CCUzSqg9.d.ts → XRHandPose-CxPz8VBp.d.ts} +139 -20
- package/dist/{XRInteractor-I2q6TKtF.d.cts → XRHandPose-VuSbe4iz.d.cts} +139 -20
- package/dist/{chunk-FQTOC7HK.js → chunk-KIKIWCEB.js} +14 -5
- package/dist/chunk-KIKIWCEB.js.map +1 -0
- package/dist/{chunk-N4GKZ7IV.js → chunk-KVGGAL5V.js} +227 -3
- package/dist/chunk-KVGGAL5V.js.map +1 -0
- package/dist/{chunk-JRJ3CL5H.js → chunk-L5BP727H.js} +3 -3
- package/dist/{chunk-JRJ3CL5H.js.map → chunk-L5BP727H.js.map} +1 -1
- package/dist/{chunk-O6FJA4XW.js → chunk-W5TSYV6Q.js} +946 -50
- package/dist/chunk-W5TSYV6Q.js.map +1 -0
- package/dist/components/index.cjs +98 -0
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.d.cts +4 -3
- package/dist/components/index.d.ts +4 -3
- package/dist/components/index.js +1 -1
- package/dist/docs/guide/vr-and-hand-poses.md +111 -0
- package/dist/factories/index.cjs +58 -0
- package/dist/factories/index.cjs.map +1 -1
- package/dist/factories/index.d.cts +6 -3
- package/dist/factories/index.d.ts +6 -3
- package/dist/factories/index.js +3 -3
- package/dist/handPose-dFxqbFFY.d.cts +240 -0
- package/dist/handPose-dFxqbFFY.d.ts +240 -0
- package/dist/{index-BltjPEhg.d.cts → index-BIQoaKAA.d.cts} +9 -3
- package/dist/{index-W8pUajCW.d.ts → index-BxdXgqiI.d.ts} +9 -3
- package/dist/{index-_q9TVDI5.d.ts → index-C7XQyrgE.d.ts} +79 -7
- package/dist/{index-B9nwRDf9.d.cts → index-DyN50JZo.d.cts} +79 -7
- package/dist/index.cjs +1205 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +118 -9
- package/dist/index.d.ts +118 -9
- package/dist/index.js +8 -8
- package/dist/systems/index.cjs +1161 -45
- package/dist/systems/index.cjs.map +1 -1
- package/dist/systems/index.d.cts +3 -2
- package/dist/systems/index.d.ts +3 -2
- package/dist/systems/index.js +3 -3
- package/dist/types.d.cts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/worldSnapshotUtils.d.cts +1 -1
- package/dist/worldSnapshotUtils.d.ts +1 -1
- package/package.json +1 -1
- package/dist/chunk-FQTOC7HK.js.map +0 -1
- package/dist/chunk-N4GKZ7IV.js.map +0 -1
- package/dist/chunk-O6FJA4XW.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -2611,6 +2611,218 @@ function createVRTeleportAreaComponent(world, entityId, ...args) {
|
|
|
2611
2611
|
}
|
|
2612
2612
|
__name(createVRTeleportAreaComponent, "createVRTeleportAreaComponent");
|
|
2613
2613
|
|
|
2614
|
+
// core/xr/handPosePresets.ts
|
|
2615
|
+
var WIDE = 0.35;
|
|
2616
|
+
var NARROW = 0.25;
|
|
2617
|
+
var EXTENDED = { curl: 0.05, tolerance: WIDE };
|
|
2618
|
+
var CURLED = { curl: 0.95, tolerance: WIDE };
|
|
2619
|
+
var THUMB_TUCKED = { curl: 0.7, tolerance: NARROW + 0.1 };
|
|
2620
|
+
var THUMB_RELAXED = { curl: 0.6, tolerance: 0.4 };
|
|
2621
|
+
function fingers(thumb, index, middle, ring, pinky) {
|
|
2622
|
+
return { thumb, index, middle, ring, pinky };
|
|
2623
|
+
}
|
|
2624
|
+
__name(fingers, "fingers");
|
|
2625
|
+
var THUMB_UP = {
|
|
2626
|
+
axis: "thumb",
|
|
2627
|
+
direction: "up",
|
|
2628
|
+
toleranceDegrees: 45
|
|
2629
|
+
};
|
|
2630
|
+
var THUMB_DOWN = {
|
|
2631
|
+
axis: "thumb",
|
|
2632
|
+
direction: "down",
|
|
2633
|
+
toleranceDegrees: 45
|
|
2634
|
+
};
|
|
2635
|
+
var HAND_POSE_PRESETS = {
|
|
2636
|
+
fist: {
|
|
2637
|
+
id: "fist",
|
|
2638
|
+
name: "Fist",
|
|
2639
|
+
fingers: fingers(THUMB_TUCKED, CURLED, CURLED, CURLED, CURLED)
|
|
2640
|
+
},
|
|
2641
|
+
"open-palm": {
|
|
2642
|
+
id: "open-palm",
|
|
2643
|
+
name: "Open Palm",
|
|
2644
|
+
fingers: fingers(EXTENDED, EXTENDED, EXTENDED, EXTENDED, EXTENDED)
|
|
2645
|
+
},
|
|
2646
|
+
point: {
|
|
2647
|
+
id: "point",
|
|
2648
|
+
name: "Point",
|
|
2649
|
+
fingers: fingers(THUMB_RELAXED, EXTENDED, CURLED, CURLED, CURLED)
|
|
2650
|
+
},
|
|
2651
|
+
"thumbs-up": {
|
|
2652
|
+
id: "thumbs-up",
|
|
2653
|
+
name: "Thumbs Up",
|
|
2654
|
+
fingers: fingers(EXTENDED, CURLED, CURLED, CURLED, CURLED),
|
|
2655
|
+
orientation: THUMB_UP
|
|
2656
|
+
},
|
|
2657
|
+
"thumbs-down": {
|
|
2658
|
+
id: "thumbs-down",
|
|
2659
|
+
name: "Thumbs Down",
|
|
2660
|
+
fingers: fingers(EXTENDED, CURLED, CURLED, CURLED, CURLED),
|
|
2661
|
+
orientation: THUMB_DOWN
|
|
2662
|
+
},
|
|
2663
|
+
peace: {
|
|
2664
|
+
id: "peace",
|
|
2665
|
+
name: "Peace",
|
|
2666
|
+
fingers: fingers(THUMB_RELAXED, EXTENDED, EXTENDED, CURLED, CURLED)
|
|
2667
|
+
},
|
|
2668
|
+
pinch: {
|
|
2669
|
+
id: "pinch",
|
|
2670
|
+
name: "Pinch",
|
|
2671
|
+
// Curl is left loose: what defines a pinch is the tips MEETING, and people
|
|
2672
|
+
// pinch with wildly different amounts of finger bend.
|
|
2673
|
+
fingers: fingers(
|
|
2674
|
+
{ curl: 0.5, tolerance: 0.5 },
|
|
2675
|
+
{ curl: 0.5, tolerance: 0.5 },
|
|
2676
|
+
{ curl: 0.5, tolerance: 0.5 },
|
|
2677
|
+
{ curl: 0.5, tolerance: 0.5 },
|
|
2678
|
+
{ curl: 0.5, tolerance: 0.5 }
|
|
2679
|
+
),
|
|
2680
|
+
pinch: { finger: "index", target: 1, tolerance: 0.25 }
|
|
2681
|
+
},
|
|
2682
|
+
ok: {
|
|
2683
|
+
id: "ok",
|
|
2684
|
+
name: "OK Sign",
|
|
2685
|
+
// Thumb and index meet in a ring while the rest stay up — that contrast with
|
|
2686
|
+
// a plain pinch is the whole gesture, so the other three are constrained.
|
|
2687
|
+
fingers: fingers(
|
|
2688
|
+
{ curl: 0.5, tolerance: 0.4 },
|
|
2689
|
+
{ curl: 0.55, tolerance: 0.35 },
|
|
2690
|
+
EXTENDED,
|
|
2691
|
+
EXTENDED,
|
|
2692
|
+
EXTENDED
|
|
2693
|
+
),
|
|
2694
|
+
pinch: { finger: "index", target: 1, tolerance: 0.3 }
|
|
2695
|
+
},
|
|
2696
|
+
gun: {
|
|
2697
|
+
id: "gun",
|
|
2698
|
+
name: "Gun",
|
|
2699
|
+
fingers: fingers(EXTENDED, EXTENDED, CURLED, CURLED, CURLED)
|
|
2700
|
+
},
|
|
2701
|
+
rock: {
|
|
2702
|
+
id: "rock",
|
|
2703
|
+
name: "Rock Horns",
|
|
2704
|
+
fingers: fingers(THUMB_TUCKED, EXTENDED, CURLED, CURLED, EXTENDED)
|
|
2705
|
+
},
|
|
2706
|
+
shaka: {
|
|
2707
|
+
id: "shaka",
|
|
2708
|
+
name: "Shaka",
|
|
2709
|
+
fingers: fingers(EXTENDED, CURLED, CURLED, CURLED, EXTENDED)
|
|
2710
|
+
},
|
|
2711
|
+
"palm-up": {
|
|
2712
|
+
id: "palm-up",
|
|
2713
|
+
name: "Palm Up",
|
|
2714
|
+
fingers: fingers(EXTENDED, EXTENDED, EXTENDED, EXTENDED, EXTENDED),
|
|
2715
|
+
orientation: {
|
|
2716
|
+
axis: "palm-normal",
|
|
2717
|
+
direction: "up",
|
|
2718
|
+
toleranceDegrees: 40
|
|
2719
|
+
}
|
|
2720
|
+
}
|
|
2721
|
+
};
|
|
2722
|
+
var HAND_POSE_PRESET_IDS = Object.keys(HAND_POSE_PRESETS);
|
|
2723
|
+
function getHandPosePreset(id) {
|
|
2724
|
+
const preset = HAND_POSE_PRESETS[id];
|
|
2725
|
+
if (!preset) return null;
|
|
2726
|
+
return cloneHandPose(preset);
|
|
2727
|
+
}
|
|
2728
|
+
__name(getHandPosePreset, "getHandPosePreset");
|
|
2729
|
+
function cloneHandPose(definition) {
|
|
2730
|
+
return {
|
|
2731
|
+
...definition,
|
|
2732
|
+
fingers: {
|
|
2733
|
+
thumb: { ...definition.fingers.thumb },
|
|
2734
|
+
index: { ...definition.fingers.index },
|
|
2735
|
+
middle: { ...definition.fingers.middle },
|
|
2736
|
+
ring: { ...definition.fingers.ring },
|
|
2737
|
+
pinky: { ...definition.fingers.pinky }
|
|
2738
|
+
},
|
|
2739
|
+
pinch: definition.pinch ? { ...definition.pinch } : void 0,
|
|
2740
|
+
orientation: definition.orientation ? { ...definition.orientation } : void 0
|
|
2741
|
+
};
|
|
2742
|
+
}
|
|
2743
|
+
__name(cloneHandPose, "cloneHandPose");
|
|
2744
|
+
function handPoseFromCurls(id, name, curls, options) {
|
|
2745
|
+
const tolerance = options?.tolerance ?? NARROW;
|
|
2746
|
+
const target = /* @__PURE__ */ __name((curl) => ({
|
|
2747
|
+
curl: Math.min(1, Math.max(0, curl)),
|
|
2748
|
+
tolerance
|
|
2749
|
+
}), "target");
|
|
2750
|
+
return {
|
|
2751
|
+
id,
|
|
2752
|
+
name,
|
|
2753
|
+
fingers: {
|
|
2754
|
+
thumb: target(curls.thumb),
|
|
2755
|
+
index: target(curls.index),
|
|
2756
|
+
middle: target(curls.middle),
|
|
2757
|
+
ring: target(curls.ring),
|
|
2758
|
+
pinky: target(curls.pinky)
|
|
2759
|
+
},
|
|
2760
|
+
pinch: options?.pinch,
|
|
2761
|
+
orientation: options?.orientation,
|
|
2762
|
+
hand: options?.hand
|
|
2763
|
+
};
|
|
2764
|
+
}
|
|
2765
|
+
__name(handPoseFromCurls, "handPoseFromCurls");
|
|
2766
|
+
|
|
2767
|
+
// core/components/XRHandPose.ts
|
|
2768
|
+
var DEFAULT_POSE_CURLS = {
|
|
2769
|
+
thumb: 0,
|
|
2770
|
+
index: 0,
|
|
2771
|
+
middle: 0,
|
|
2772
|
+
ring: 0,
|
|
2773
|
+
pinky: 0
|
|
2774
|
+
};
|
|
2775
|
+
function createHandPoseEntry(partial) {
|
|
2776
|
+
return {
|
|
2777
|
+
id: partial.id,
|
|
2778
|
+
name: partial.name ?? partial.id,
|
|
2779
|
+
preset: partial.preset ?? null,
|
|
2780
|
+
curls: { ...DEFAULT_POSE_CURLS, ...partial.curls },
|
|
2781
|
+
tolerance: partial.tolerance ?? 0.25,
|
|
2782
|
+
hand: partial.hand ?? null,
|
|
2783
|
+
orientation: partial.orientation ?? null,
|
|
2784
|
+
minHoldSeconds: partial.minHoldSeconds ?? 0.15,
|
|
2785
|
+
enabled: partial.enabled ?? true
|
|
2786
|
+
};
|
|
2787
|
+
}
|
|
2788
|
+
__name(createHandPoseEntry, "createHandPoseEntry");
|
|
2789
|
+
function handPoseDefinitionFor(entry, resolvePreset) {
|
|
2790
|
+
if (entry.preset) {
|
|
2791
|
+
const preset = resolvePreset(entry.preset);
|
|
2792
|
+
if (!preset) return null;
|
|
2793
|
+
return {
|
|
2794
|
+
...preset,
|
|
2795
|
+
id: entry.id,
|
|
2796
|
+
name: entry.name,
|
|
2797
|
+
hand: entry.hand ?? preset.hand,
|
|
2798
|
+
orientation: entry.orientation ?? preset.orientation
|
|
2799
|
+
};
|
|
2800
|
+
}
|
|
2801
|
+
return handPoseFromCurls(entry.id, entry.name, entry.curls, {
|
|
2802
|
+
tolerance: entry.tolerance,
|
|
2803
|
+
orientation: entry.orientation ?? void 0,
|
|
2804
|
+
hand: entry.hand ?? void 0
|
|
2805
|
+
});
|
|
2806
|
+
}
|
|
2807
|
+
__name(handPoseDefinitionFor, "handPoseDefinitionFor");
|
|
2808
|
+
var _XRHandPoseComponent = class _XRHandPoseComponent extends Component {
|
|
2809
|
+
constructor(options) {
|
|
2810
|
+
super();
|
|
2811
|
+
this.enabled = options?.enabled ?? true;
|
|
2812
|
+
this.poses = (options?.poses ?? []).map((pose) => createHandPoseEntry(pose));
|
|
2813
|
+
}
|
|
2814
|
+
};
|
|
2815
|
+
__name(_XRHandPoseComponent, "XRHandPoseComponent");
|
|
2816
|
+
var XRHandPoseComponent = _XRHandPoseComponent;
|
|
2817
|
+
|
|
2818
|
+
// core/factories/components/XRHandPoseFactory.ts
|
|
2819
|
+
function createXRHandPoseComponent(world, entityId, ...args) {
|
|
2820
|
+
const component = new XRHandPoseComponent(...args);
|
|
2821
|
+
world.addComponent(entityId, component);
|
|
2822
|
+
return component;
|
|
2823
|
+
}
|
|
2824
|
+
__name(createXRHandPoseComponent, "createXRHandPoseComponent");
|
|
2825
|
+
|
|
2614
2826
|
// core/components/XRInteractable.ts
|
|
2615
2827
|
var _XRInteractableComponent = class _XRInteractableComponent extends Component {
|
|
2616
2828
|
constructor(options) {
|
|
@@ -2619,6 +2831,22 @@ var _XRInteractableComponent = class _XRInteractableComponent extends Component
|
|
|
2619
2831
|
this.grabbable = options?.grabbable ?? true;
|
|
2620
2832
|
this.pointable = options?.pointable ?? true;
|
|
2621
2833
|
this.grabMode = options?.grabMode ?? "kinematic";
|
|
2834
|
+
this.grabReach = options?.grabReach ?? "both";
|
|
2835
|
+
this.distanceBehavior = options?.distanceBehavior ?? "snap";
|
|
2836
|
+
this.grabGesture = options?.grabGesture ?? "any";
|
|
2837
|
+
this.grabRadius = options?.grabRadius ?? 0.15;
|
|
2838
|
+
this.grabOffsetPosition = options?.grabOffsetPosition ?? {
|
|
2839
|
+
x: 0,
|
|
2840
|
+
y: 0,
|
|
2841
|
+
z: 0
|
|
2842
|
+
};
|
|
2843
|
+
this.grabOffsetRotation = options?.grabOffsetRotation ?? {
|
|
2844
|
+
x: 0,
|
|
2845
|
+
y: 0,
|
|
2846
|
+
z: 0
|
|
2847
|
+
};
|
|
2848
|
+
this.throwOnRelease = options?.throwOnRelease ?? true;
|
|
2849
|
+
this.throwStrength = options?.throwStrength ?? 1;
|
|
2622
2850
|
this.highlightOnHover = options?.highlightOnHover ?? true;
|
|
2623
2851
|
}
|
|
2624
2852
|
};
|
|
@@ -2683,6 +2911,7 @@ function registerDefaultComponentFactories(objectManagementSystem) {
|
|
|
2683
2911
|
objectManagementSystem.registerComponentFactory("image", createImageComponent);
|
|
2684
2912
|
objectManagementSystem.registerComponentFactory("xrRig", createXRRigComponent);
|
|
2685
2913
|
objectManagementSystem.registerComponentFactory("vrTeleportArea", createVRTeleportAreaComponent);
|
|
2914
|
+
objectManagementSystem.registerComponentFactory("xrHandPose", createXRHandPoseComponent);
|
|
2686
2915
|
objectManagementSystem.registerComponentFactory("xrInteractable", createXRInteractableComponent);
|
|
2687
2916
|
objectManagementSystem.registerComponentFactory("xrInteractor", createXRInteractorComponent);
|
|
2688
2917
|
objectManagementSystem.registerComponentFactory("xrInteractorSide", createXRInteractorSideComponent);
|
|
@@ -3705,6 +3934,7 @@ __export(components_exports, {
|
|
|
3705
3934
|
DEFAULT_INSTANCE_TRANSFORM: () => DEFAULT_INSTANCE_TRANSFORM,
|
|
3706
3935
|
DEFAULT_MESH_GEOMETRY_PARAMETERS: () => DEFAULT_MESH_GEOMETRY_PARAMETERS,
|
|
3707
3936
|
DEFAULT_PHYSICS_STATE: () => DEFAULT_PHYSICS_STATE,
|
|
3937
|
+
DEFAULT_POSE_CURLS: () => DEFAULT_POSE_CURLS,
|
|
3708
3938
|
DEFAULT_POSTPROCESSING_STATE: () => DEFAULT_POSTPROCESSING_STATE,
|
|
3709
3939
|
DEFAULT_RIGIDBODY_STATE: () => DEFAULT_RIGIDBODY_STATE,
|
|
3710
3940
|
EntityType: () => EntityType,
|
|
@@ -3734,11 +3964,14 @@ __export(components_exports, {
|
|
|
3734
3964
|
TransformComponent: () => TransformComponent,
|
|
3735
3965
|
VRTeleportAreaComponent: () => VRTeleportAreaComponent,
|
|
3736
3966
|
VideoComponent: () => VideoComponent,
|
|
3967
|
+
XRHandPoseComponent: () => XRHandPoseComponent,
|
|
3737
3968
|
XRInteractableComponent: () => XRInteractableComponent,
|
|
3738
3969
|
XRInteractorComponent: () => XRInteractorComponent,
|
|
3739
3970
|
XRInteractorSideComponent: () => XRInteractorSideComponent,
|
|
3740
3971
|
XRRigComponent: () => XRRigComponent,
|
|
3972
|
+
createHandPoseEntry: () => createHandPoseEntry,
|
|
3741
3973
|
defaultMaterialValue: () => defaultMaterialValue,
|
|
3974
|
+
handPoseDefinitionFor: () => handPoseDefinitionFor,
|
|
3742
3975
|
normalizePhysicsState: () => normalizePhysicsState,
|
|
3743
3976
|
setPhysicsLiveRef: () => setPhysicsLiveRef
|
|
3744
3977
|
});
|
|
@@ -4427,6 +4660,10 @@ function buildComponentValueMaps(snapshot) {
|
|
|
4427
4660
|
snapshot.components,
|
|
4428
4661
|
"XRInteractorComponent"
|
|
4429
4662
|
),
|
|
4663
|
+
xrHandPoseValues: readByComponent(
|
|
4664
|
+
snapshot.components,
|
|
4665
|
+
"XRHandPoseComponent"
|
|
4666
|
+
),
|
|
4430
4667
|
xrInteractorSideValues: readByComponent(
|
|
4431
4668
|
snapshot.components,
|
|
4432
4669
|
"XRInteractorSideComponent"
|
|
@@ -4540,13 +4777,9 @@ function restorePostCreateComponents(world, objectManagementSystem, targetEntity
|
|
|
4540
4777
|
runtimeMessage: typeof entry.runtimeMessage === "string" ? entry.runtimeMessage : void 0
|
|
4541
4778
|
};
|
|
4542
4779
|
}).filter((entry) => entry.className || entry.scriptUrl) : [];
|
|
4543
|
-
if (
|
|
4544
|
-
|
|
4780
|
+
if (entries.length) {
|
|
4781
|
+
world.addComponent(targetEntityId, new ScriptComponent(entries));
|
|
4545
4782
|
}
|
|
4546
|
-
world.addComponent(
|
|
4547
|
-
targetEntityId,
|
|
4548
|
-
new ScriptComponent(entries)
|
|
4549
|
-
);
|
|
4550
4783
|
}
|
|
4551
4784
|
const sourceScriptObject = asRecord3(values.scriptObjectValues.get(sourceEntityId));
|
|
4552
4785
|
if (sourceScriptObject) {
|
|
@@ -4595,10 +4828,14 @@ function restorePostCreateComponents(world, objectManagementSystem, targetEntity
|
|
|
4595
4828
|
const sourceInteractable = asRecord3(
|
|
4596
4829
|
values.xrInteractableValues.get(sourceEntityId)
|
|
4597
4830
|
);
|
|
4598
|
-
|
|
4831
|
+
let interactable = world.getComponent(
|
|
4599
4832
|
targetEntityId,
|
|
4600
4833
|
XRInteractableComponent
|
|
4601
4834
|
);
|
|
4835
|
+
if (sourceInteractable && !interactable) {
|
|
4836
|
+
interactable = new XRInteractableComponent();
|
|
4837
|
+
world.addComponent(targetEntityId, interactable);
|
|
4838
|
+
}
|
|
4602
4839
|
if (sourceInteractable && interactable) {
|
|
4603
4840
|
if (typeof sourceInteractable.enabled === "boolean") {
|
|
4604
4841
|
interactable.enabled = sourceInteractable.enabled;
|
|
@@ -4612,11 +4849,69 @@ function restorePostCreateComponents(world, objectManagementSystem, targetEntity
|
|
|
4612
4849
|
if (typeof sourceInteractable.grabMode === "string") {
|
|
4613
4850
|
interactable.grabMode = sourceInteractable.grabMode;
|
|
4614
4851
|
}
|
|
4852
|
+
if (typeof sourceInteractable.grabReach === "string") {
|
|
4853
|
+
interactable.grabReach = sourceInteractable.grabReach;
|
|
4854
|
+
}
|
|
4855
|
+
if (typeof sourceInteractable.distanceBehavior === "string") {
|
|
4856
|
+
interactable.distanceBehavior = sourceInteractable.distanceBehavior;
|
|
4857
|
+
}
|
|
4858
|
+
if (typeof sourceInteractable.grabGesture === "string") {
|
|
4859
|
+
interactable.grabGesture = sourceInteractable.grabGesture;
|
|
4860
|
+
}
|
|
4861
|
+
if (typeof sourceInteractable.grabRadius === "number") {
|
|
4862
|
+
interactable.grabRadius = sourceInteractable.grabRadius;
|
|
4863
|
+
}
|
|
4864
|
+
if (typeof sourceInteractable.throwOnRelease === "boolean") {
|
|
4865
|
+
interactable.throwOnRelease = sourceInteractable.throwOnRelease;
|
|
4866
|
+
}
|
|
4867
|
+
if (typeof sourceInteractable.throwStrength === "number") {
|
|
4868
|
+
interactable.throwStrength = sourceInteractable.throwStrength;
|
|
4869
|
+
}
|
|
4870
|
+
const grabPos = asRecord3(sourceInteractable.grabOffsetPosition);
|
|
4871
|
+
if (grabPos) {
|
|
4872
|
+
interactable.grabOffsetPosition = {
|
|
4873
|
+
x: typeof grabPos.x === "number" ? grabPos.x : 0,
|
|
4874
|
+
y: typeof grabPos.y === "number" ? grabPos.y : 0,
|
|
4875
|
+
z: typeof grabPos.z === "number" ? grabPos.z : 0
|
|
4876
|
+
};
|
|
4877
|
+
}
|
|
4878
|
+
const grabRot = asRecord3(sourceInteractable.grabOffsetRotation);
|
|
4879
|
+
if (grabRot) {
|
|
4880
|
+
interactable.grabOffsetRotation = {
|
|
4881
|
+
x: typeof grabRot.x === "number" ? grabRot.x : 0,
|
|
4882
|
+
y: typeof grabRot.y === "number" ? grabRot.y : 0,
|
|
4883
|
+
z: typeof grabRot.z === "number" ? grabRot.z : 0
|
|
4884
|
+
};
|
|
4885
|
+
}
|
|
4615
4886
|
if (typeof sourceInteractable.highlightOnHover === "boolean") {
|
|
4616
4887
|
interactable.highlightOnHover = sourceInteractable.highlightOnHover;
|
|
4617
4888
|
}
|
|
4618
4889
|
}
|
|
4619
4890
|
}
|
|
4891
|
+
{
|
|
4892
|
+
const sourceHandPose = asRecord3(
|
|
4893
|
+
values.xrHandPoseValues.get(sourceEntityId)
|
|
4894
|
+
);
|
|
4895
|
+
let handPose = world.getComponent(targetEntityId, XRHandPoseComponent);
|
|
4896
|
+
if (sourceHandPose && !handPose) {
|
|
4897
|
+
handPose = new XRHandPoseComponent();
|
|
4898
|
+
world.addComponent(targetEntityId, handPose);
|
|
4899
|
+
}
|
|
4900
|
+
if (sourceHandPose && handPose) {
|
|
4901
|
+
if (typeof sourceHandPose.enabled === "boolean") {
|
|
4902
|
+
handPose.enabled = sourceHandPose.enabled;
|
|
4903
|
+
}
|
|
4904
|
+
if (Array.isArray(sourceHandPose.poses)) {
|
|
4905
|
+
handPose.poses = sourceHandPose.poses.map((entry) => asRecord3(entry)).filter(
|
|
4906
|
+
(entry) => entry !== null && typeof entry.id === "string"
|
|
4907
|
+
).map(
|
|
4908
|
+
(entry) => createHandPoseEntry(
|
|
4909
|
+
entry
|
|
4910
|
+
)
|
|
4911
|
+
);
|
|
4912
|
+
}
|
|
4913
|
+
}
|
|
4914
|
+
}
|
|
4620
4915
|
{
|
|
4621
4916
|
const sourceInteractor = asRecord3(
|
|
4622
4917
|
values.xrInteractorValues.get(sourceEntityId)
|
|
@@ -9178,6 +9473,17 @@ var _Behaviour = class _Behaviour {
|
|
|
9178
9473
|
*
|
|
9179
9474
|
* @param input - The source doing the grabbing.
|
|
9180
9475
|
*/
|
|
9476
|
+
/**
|
|
9477
|
+
* A hand pose declared on this entity started being held.
|
|
9478
|
+
*
|
|
9479
|
+
* Fires once the pose has been sustained for its hold time, not the instant
|
|
9480
|
+
* the fingers pass through it.
|
|
9481
|
+
*/
|
|
9482
|
+
onHandPoseStart(_event) {
|
|
9483
|
+
}
|
|
9484
|
+
/** A held hand pose ended, or its hand stopped being tracked. */
|
|
9485
|
+
onHandPoseEnd(_event) {
|
|
9486
|
+
}
|
|
9181
9487
|
onGrab(input) {
|
|
9182
9488
|
}
|
|
9183
9489
|
/** Called when this entity is released. Optional XR hook. */
|
|
@@ -10320,13 +10626,65 @@ function blankState(source) {
|
|
|
10320
10626
|
squeezeEnd: false,
|
|
10321
10627
|
axes: [],
|
|
10322
10628
|
hasAxes: false,
|
|
10323
|
-
buttons: []
|
|
10629
|
+
buttons: [],
|
|
10630
|
+
joints: null
|
|
10324
10631
|
};
|
|
10325
10632
|
}
|
|
10326
10633
|
__name(blankState, "blankState");
|
|
10634
|
+
var JOINT_MATRIX_BUFFER = new Float32Array(25 * 16);
|
|
10635
|
+
function readHandJoints(frame, hand, referenceSpace, rigMatrix, existing) {
|
|
10636
|
+
const names = [];
|
|
10637
|
+
const spaces = [];
|
|
10638
|
+
for (const [name, space] of hand) {
|
|
10639
|
+
names.push(name);
|
|
10640
|
+
spaces.push(space);
|
|
10641
|
+
}
|
|
10642
|
+
if (spaces.length === 0) return null;
|
|
10643
|
+
const target = existing ?? {};
|
|
10644
|
+
const matrix = new THREE39__namespace.Matrix4();
|
|
10645
|
+
const buffer = spaces.length * 16 <= JOINT_MATRIX_BUFFER.length ? JOINT_MATRIX_BUFFER : new Float32Array(spaces.length * 16);
|
|
10646
|
+
const fillPoses = frame.fillPoses;
|
|
10647
|
+
if (typeof fillPoses === "function") {
|
|
10648
|
+
let filled = false;
|
|
10649
|
+
try {
|
|
10650
|
+
filled = fillPoses.call(frame, spaces, referenceSpace, buffer);
|
|
10651
|
+
} catch {
|
|
10652
|
+
filled = false;
|
|
10653
|
+
}
|
|
10654
|
+
if (filled) {
|
|
10655
|
+
for (let i = 0; i < names.length; i += 1) {
|
|
10656
|
+
matrix.fromArray(buffer, i * 16).premultiply(rigMatrix);
|
|
10657
|
+
const vector = target[names[i]] ?? new THREE39__namespace.Vector3();
|
|
10658
|
+
vector.setFromMatrixPosition(matrix);
|
|
10659
|
+
target[names[i]] = vector;
|
|
10660
|
+
}
|
|
10661
|
+
return target;
|
|
10662
|
+
}
|
|
10663
|
+
}
|
|
10664
|
+
let anyTracked = false;
|
|
10665
|
+
for (let i = 0; i < names.length; i += 1) {
|
|
10666
|
+
const pose = frame.getJointPose?.(
|
|
10667
|
+
spaces[i],
|
|
10668
|
+
referenceSpace
|
|
10669
|
+
);
|
|
10670
|
+
if (!pose) {
|
|
10671
|
+
target[names[i]] = void 0;
|
|
10672
|
+
continue;
|
|
10673
|
+
}
|
|
10674
|
+
matrix.fromArray(pose.transform.matrix).premultiply(rigMatrix);
|
|
10675
|
+
const vector = target[names[i]] ?? new THREE39__namespace.Vector3();
|
|
10676
|
+
vector.setFromMatrixPosition(matrix);
|
|
10677
|
+
target[names[i]] = vector;
|
|
10678
|
+
anyTracked = true;
|
|
10679
|
+
}
|
|
10680
|
+
return anyTracked ? target : null;
|
|
10681
|
+
}
|
|
10682
|
+
__name(readHandJoints, "readHandJoints");
|
|
10327
10683
|
var _XRInputSystem = class _XRInputSystem {
|
|
10328
10684
|
constructor() {
|
|
10329
10685
|
this.records = /* @__PURE__ */ new Map();
|
|
10686
|
+
/** Reference-space → world matrix, rebuilt each frame from the XR rig. */
|
|
10687
|
+
this.referenceToWorld = new THREE39__namespace.Matrix4();
|
|
10330
10688
|
this.session = null;
|
|
10331
10689
|
this.onSelectStart = /* @__PURE__ */ __name((event) => this.mark(event, "pendingSelectStart"), "onSelectStart");
|
|
10332
10690
|
this.onSelectEnd = /* @__PURE__ */ __name((event) => this.mark(event, "pendingSelectEnd"), "onSelectEnd");
|
|
@@ -10406,6 +10764,14 @@ var _XRInputSystem = class _XRInputSystem {
|
|
|
10406
10764
|
const referenceSpace = renderer.xr.getReferenceSpace();
|
|
10407
10765
|
const frame = renderer.xr.getFrame?.();
|
|
10408
10766
|
const live = /* @__PURE__ */ new Set();
|
|
10767
|
+
const rigMatrix = this.referenceToWorld;
|
|
10768
|
+
const rig = world.getCamera().parent;
|
|
10769
|
+
if (rig) {
|
|
10770
|
+
rig.updateMatrixWorld();
|
|
10771
|
+
rigMatrix.copy(rig.matrixWorld);
|
|
10772
|
+
} else {
|
|
10773
|
+
rigMatrix.identity();
|
|
10774
|
+
}
|
|
10409
10775
|
for (const source of session.inputSources) {
|
|
10410
10776
|
live.add(source);
|
|
10411
10777
|
const record = this.ensureRecord(source);
|
|
@@ -10416,7 +10782,7 @@ var _XRInputSystem = class _XRInputSystem {
|
|
|
10416
10782
|
if (frame && referenceSpace && source.targetRaySpace) {
|
|
10417
10783
|
const pose = frame.getPose(source.targetRaySpace, referenceSpace);
|
|
10418
10784
|
if (pose) {
|
|
10419
|
-
const m = new THREE39__namespace.Matrix4().fromArray(pose.transform.matrix);
|
|
10785
|
+
const m = new THREE39__namespace.Matrix4().fromArray(pose.transform.matrix).premultiply(rigMatrix);
|
|
10420
10786
|
state.rayOrigin.setFromMatrixPosition(m);
|
|
10421
10787
|
state.rayDirection.set(0, 0, -1).applyQuaternion(
|
|
10422
10788
|
new THREE39__namespace.Quaternion().setFromRotationMatrix(m)
|
|
@@ -10426,7 +10792,7 @@ var _XRInputSystem = class _XRInputSystem {
|
|
|
10426
10792
|
if (frame && referenceSpace && source.gripSpace) {
|
|
10427
10793
|
const gripPose = frame.getPose(source.gripSpace, referenceSpace);
|
|
10428
10794
|
if (gripPose) {
|
|
10429
|
-
const m = new THREE39__namespace.Matrix4().fromArray(gripPose.transform.matrix);
|
|
10795
|
+
const m = new THREE39__namespace.Matrix4().fromArray(gripPose.transform.matrix).premultiply(rigMatrix);
|
|
10430
10796
|
state.gripPosition ?? (state.gripPosition = new THREE39__namespace.Vector3());
|
|
10431
10797
|
state.gripQuaternion ?? (state.gripQuaternion = new THREE39__namespace.Quaternion());
|
|
10432
10798
|
state.gripPosition.setFromMatrixPosition(m);
|
|
@@ -10436,6 +10802,17 @@ var _XRInputSystem = class _XRInputSystem {
|
|
|
10436
10802
|
state.gripPosition = null;
|
|
10437
10803
|
state.gripQuaternion = null;
|
|
10438
10804
|
}
|
|
10805
|
+
if (frame && referenceSpace && source.hand) {
|
|
10806
|
+
state.joints = readHandJoints(
|
|
10807
|
+
frame,
|
|
10808
|
+
source.hand,
|
|
10809
|
+
referenceSpace,
|
|
10810
|
+
rigMatrix,
|
|
10811
|
+
state.joints
|
|
10812
|
+
);
|
|
10813
|
+
} else {
|
|
10814
|
+
state.joints = null;
|
|
10815
|
+
}
|
|
10439
10816
|
const gamepad = source.gamepad;
|
|
10440
10817
|
if (gamepad) {
|
|
10441
10818
|
state.axes = Array.from(gamepad.axes);
|
|
@@ -10500,20 +10877,86 @@ var _XRInputSystem = class _XRInputSystem {
|
|
|
10500
10877
|
};
|
|
10501
10878
|
__name(_XRInputSystem, "XRInputSystem");
|
|
10502
10879
|
var XRInputSystem = _XRInputSystem;
|
|
10880
|
+
var VELOCITY_SAMPLES = 5;
|
|
10881
|
+
var MAX_SAMPLE_AGE_SECONDS = 0.2;
|
|
10882
|
+
var MAX_PLAUSIBLE_SPEED = 20;
|
|
10883
|
+
var _ThrowVelocityTracker = class _ThrowVelocityTracker {
|
|
10884
|
+
constructor() {
|
|
10885
|
+
this.samples = [];
|
|
10886
|
+
}
|
|
10887
|
+
/** Record where the hand is now. Call once per frame while held. */
|
|
10888
|
+
record(position, time) {
|
|
10889
|
+
this.samples.push({ position: position.clone(), time });
|
|
10890
|
+
if (this.samples.length > VELOCITY_SAMPLES) {
|
|
10891
|
+
this.samples.shift();
|
|
10892
|
+
}
|
|
10893
|
+
}
|
|
10894
|
+
/**
|
|
10895
|
+
* Velocity to release with, in metres/second.
|
|
10896
|
+
*
|
|
10897
|
+
* Uses the FASTEST segment inside the window rather than the most recent or
|
|
10898
|
+
* the window average. Users decelerate as they open their hand, so the last
|
|
10899
|
+
* segment understates the throw and the average washes it out; peak speed is
|
|
10900
|
+
* what matches the motion the user actually felt they made.
|
|
10901
|
+
*/
|
|
10902
|
+
computeVelocity(now) {
|
|
10903
|
+
const fresh = this.samples.filter(
|
|
10904
|
+
(sample) => now - sample.time <= MAX_SAMPLE_AGE_SECONDS
|
|
10905
|
+
);
|
|
10906
|
+
if (fresh.length < 2) return new THREE39__namespace.Vector3();
|
|
10907
|
+
let best = new THREE39__namespace.Vector3();
|
|
10908
|
+
let bestSpeed = 0;
|
|
10909
|
+
for (let i = 1; i < fresh.length; i += 1) {
|
|
10910
|
+
const previous = fresh[i - 1];
|
|
10911
|
+
const current = fresh[i];
|
|
10912
|
+
const dt = current.time - previous.time;
|
|
10913
|
+
if (dt <= 1e-5) continue;
|
|
10914
|
+
const velocity = new THREE39__namespace.Vector3().subVectors(current.position, previous.position).divideScalar(dt);
|
|
10915
|
+
const speed = velocity.length();
|
|
10916
|
+
if (speed > MAX_PLAUSIBLE_SPEED) continue;
|
|
10917
|
+
if (speed > bestSpeed) {
|
|
10918
|
+
bestSpeed = speed;
|
|
10919
|
+
best = velocity;
|
|
10920
|
+
}
|
|
10921
|
+
}
|
|
10922
|
+
return best;
|
|
10923
|
+
}
|
|
10924
|
+
clear() {
|
|
10925
|
+
this.samples.length = 0;
|
|
10926
|
+
}
|
|
10927
|
+
};
|
|
10928
|
+
__name(_ThrowVelocityTracker, "ThrowVelocityTracker");
|
|
10929
|
+
var ThrowVelocityTracker = _ThrowVelocityTracker;
|
|
10930
|
+
function angularVelocityFrom(previous, current, deltaTime) {
|
|
10931
|
+
if (deltaTime <= 1e-5) return new THREE39__namespace.Vector3();
|
|
10932
|
+
const delta = current.clone().multiply(previous.clone().invert());
|
|
10933
|
+
if (delta.w < 0) {
|
|
10934
|
+
delta.set(-delta.x, -delta.y, -delta.z, -delta.w);
|
|
10935
|
+
}
|
|
10936
|
+
const angle = 2 * Math.acos(THREE39__namespace.MathUtils.clamp(delta.w, -1, 1));
|
|
10937
|
+
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);
|
|
10940
|
+
}
|
|
10941
|
+
__name(angularVelocityFrom, "angularVelocityFrom");
|
|
10942
|
+
|
|
10943
|
+
// core/systems/XRInteractionSystem.ts
|
|
10503
10944
|
var RAYLESS_HOLD_DISTANCE = 0.5;
|
|
10504
10945
|
var _XRInteractionSystem = class _XRInteractionSystem {
|
|
10505
10946
|
constructor(inputSystem) {
|
|
10506
10947
|
this.raycaster = new THREE39__namespace.Raycaster();
|
|
10507
|
-
/** Which entity each source is holding. Keyed by source state identity. */
|
|
10508
10948
|
this.grabs = /* @__PURE__ */ new Map();
|
|
10509
10949
|
this.hoveredEntityId = null;
|
|
10950
|
+
/** Monotonic seconds, accumulated from deltaTime for velocity sampling. */
|
|
10951
|
+
this.elapsed = 0;
|
|
10510
10952
|
this.inputSystem = inputSystem;
|
|
10511
10953
|
}
|
|
10512
|
-
update(world) {
|
|
10954
|
+
update(world, deltaTime) {
|
|
10513
10955
|
if (!world.isXrPresenting()) {
|
|
10514
10956
|
this.releaseAll(world);
|
|
10515
10957
|
return;
|
|
10516
10958
|
}
|
|
10959
|
+
this.elapsed += Math.max(0, deltaTime);
|
|
10517
10960
|
const inputs = this.inputSystem.getInputs();
|
|
10518
10961
|
const interactables = this.collectInteractables(world);
|
|
10519
10962
|
this.hoveredEntityId = null;
|
|
@@ -10524,32 +10967,105 @@ var _XRInteractionSystem = class _XRInteractionSystem {
|
|
|
10524
10967
|
}
|
|
10525
10968
|
const held = this.grabs.get(input);
|
|
10526
10969
|
if (held) {
|
|
10527
|
-
this.moveHeld(world, input, held);
|
|
10528
|
-
if (
|
|
10970
|
+
this.moveHeld(world, input, held, deltaTime);
|
|
10971
|
+
if (this.wantsRelease(world, input, held)) {
|
|
10972
|
+
this.release(world, input);
|
|
10973
|
+
}
|
|
10529
10974
|
continue;
|
|
10530
10975
|
}
|
|
10531
|
-
const
|
|
10532
|
-
if (
|
|
10976
|
+
const candidate = this.findGrabCandidate(world, input, interactables);
|
|
10977
|
+
if (candidate === null) continue;
|
|
10533
10978
|
if (this.hoveredEntityId === null) {
|
|
10534
|
-
this.hoveredEntityId =
|
|
10979
|
+
this.hoveredEntityId = candidate.entityId;
|
|
10535
10980
|
}
|
|
10536
10981
|
const interactable = world.getComponent(
|
|
10537
|
-
|
|
10982
|
+
candidate.entityId,
|
|
10538
10983
|
XRInteractableComponent
|
|
10539
10984
|
);
|
|
10540
|
-
if (
|
|
10541
|
-
|
|
10985
|
+
if (interactable?.grabbable && this.gestureMatches(
|
|
10986
|
+
input,
|
|
10987
|
+
interactable,
|
|
10988
|
+
/* starting */
|
|
10989
|
+
true
|
|
10990
|
+
)) {
|
|
10991
|
+
this.grab(world, input, candidate.entityId, candidate.viaDistance);
|
|
10992
|
+
}
|
|
10993
|
+
}
|
|
10994
|
+
}
|
|
10995
|
+
/** Whether the grab gesture for this object is currently starting. */
|
|
10996
|
+
gestureMatches(input, interactable, starting) {
|
|
10997
|
+
const pinch = starting ? input.selectStart : input.select;
|
|
10998
|
+
const full = starting ? input.squeezeStart : input.squeeze;
|
|
10999
|
+
switch (interactable.grabGesture) {
|
|
11000
|
+
case "pinch":
|
|
11001
|
+
return pinch;
|
|
11002
|
+
case "full":
|
|
11003
|
+
return full;
|
|
11004
|
+
default:
|
|
11005
|
+
return pinch || full;
|
|
11006
|
+
}
|
|
11007
|
+
}
|
|
11008
|
+
/** True once the gesture that started the grab has ended. */
|
|
11009
|
+
wantsRelease(world, input, held) {
|
|
11010
|
+
const interactable = world.getComponent(
|
|
11011
|
+
held.entityId,
|
|
11012
|
+
XRInteractableComponent
|
|
11013
|
+
);
|
|
11014
|
+
if (!interactable) return true;
|
|
11015
|
+
switch (interactable.grabGesture) {
|
|
11016
|
+
case "pinch":
|
|
11017
|
+
return input.selectEnd || !input.select;
|
|
11018
|
+
case "full":
|
|
11019
|
+
return input.squeezeEnd || !input.squeeze;
|
|
11020
|
+
default:
|
|
11021
|
+
return !input.select && !input.squeeze;
|
|
11022
|
+
}
|
|
11023
|
+
}
|
|
11024
|
+
/**
|
|
11025
|
+
* Find what this hand would grab: a physically-reachable object first, then
|
|
11026
|
+
* one along the pointer ray.
|
|
11027
|
+
*
|
|
11028
|
+
* Proximity wins over the ray so that reaching for something you are touching
|
|
11029
|
+
* never picks up a distant object behind it, which feels broken.
|
|
11030
|
+
*/
|
|
11031
|
+
findGrabCandidate(world, input, interactables) {
|
|
11032
|
+
const hand = this.handPosition(input);
|
|
11033
|
+
let nearestId = null;
|
|
11034
|
+
let nearestDistance = Number.POSITIVE_INFINITY;
|
|
11035
|
+
for (const entry of interactables) {
|
|
11036
|
+
const interactable2 = world.getComponent(
|
|
11037
|
+
entry.entityId,
|
|
11038
|
+
XRInteractableComponent
|
|
11039
|
+
);
|
|
11040
|
+
if (!interactable2) continue;
|
|
11041
|
+
if (interactable2.grabReach === "distance") continue;
|
|
11042
|
+
const position = new THREE39__namespace.Vector3();
|
|
11043
|
+
entry.object.getWorldPosition(position);
|
|
11044
|
+
const distance = position.distanceTo(hand);
|
|
11045
|
+
if (distance <= interactable2.grabRadius && distance < nearestDistance) {
|
|
11046
|
+
nearestDistance = distance;
|
|
11047
|
+
nearestId = entry.entityId;
|
|
10542
11048
|
}
|
|
10543
11049
|
}
|
|
11050
|
+
if (nearestId !== null) {
|
|
11051
|
+
return { entityId: nearestId, viaDistance: false };
|
|
11052
|
+
}
|
|
11053
|
+
const hitId = this.raycast(input, interactables);
|
|
11054
|
+
if (hitId === null) return null;
|
|
11055
|
+
const interactable = world.getComponent(hitId, XRInteractableComponent);
|
|
11056
|
+
const viaDistanceAllowed = interactable?.grabReach === "distance" || interactable?.grabReach === "both";
|
|
11057
|
+
return { entityId: hitId, viaDistance: viaDistanceAllowed };
|
|
10544
11058
|
}
|
|
10545
11059
|
collectInteractables(world) {
|
|
10546
11060
|
const out = [];
|
|
10547
11061
|
for (const entityId of world.query(XRInteractableComponent, Object3DRef)) {
|
|
10548
11062
|
const interactable = world.getComponent(entityId, XRInteractableComponent);
|
|
10549
|
-
if (!interactable?.enabled
|
|
11063
|
+
if (!interactable?.enabled) continue;
|
|
10550
11064
|
if (!world.isEntityVisible(entityId)) continue;
|
|
10551
11065
|
const object = world.getComponent(entityId, Object3DRef)?.object;
|
|
10552
|
-
if (object)
|
|
11066
|
+
if (object) {
|
|
11067
|
+
out.push({ entityId, object, pointable: interactable.pointable });
|
|
11068
|
+
}
|
|
10553
11069
|
}
|
|
10554
11070
|
return out;
|
|
10555
11071
|
}
|
|
@@ -10557,9 +11073,11 @@ var _XRInteractionSystem = class _XRInteractionSystem {
|
|
|
10557
11073
|
raycast(input, interactables) {
|
|
10558
11074
|
if (interactables.length === 0) return null;
|
|
10559
11075
|
this.raycaster.set(input.rayOrigin, input.rayDirection);
|
|
11076
|
+
this.raycaster.far = Number.POSITIVE_INFINITY;
|
|
10560
11077
|
let nearestId = null;
|
|
10561
11078
|
let nearestDistance = Number.POSITIVE_INFINITY;
|
|
10562
11079
|
for (const entry of interactables) {
|
|
11080
|
+
if (!entry.pointable) continue;
|
|
10563
11081
|
const hit = this.raycaster.intersectObject(entry.object, true)[0];
|
|
10564
11082
|
if (!hit) continue;
|
|
10565
11083
|
if (hit.distance < nearestDistance) {
|
|
@@ -10569,43 +11087,120 @@ var _XRInteractionSystem = class _XRInteractionSystem {
|
|
|
10569
11087
|
}
|
|
10570
11088
|
return nearestId;
|
|
10571
11089
|
}
|
|
10572
|
-
grab(world, input, entityId) {
|
|
11090
|
+
grab(world, input, entityId, viaDistance) {
|
|
10573
11091
|
const transform = world.getComponent(entityId, TransformComponent);
|
|
10574
|
-
|
|
11092
|
+
const interactable = world.getComponent(entityId, XRInteractableComponent);
|
|
11093
|
+
if (!transform || !interactable) return;
|
|
10575
11094
|
const hand = this.handPosition(input);
|
|
10576
|
-
const
|
|
10577
|
-
|
|
10578
|
-
|
|
10579
|
-
|
|
10580
|
-
)
|
|
11095
|
+
const handQuaternion = this.handQuaternion(input);
|
|
11096
|
+
const remote = viaDistance && interactable.distanceBehavior === "remote";
|
|
11097
|
+
let offset;
|
|
11098
|
+
let remoteDistance = 0;
|
|
11099
|
+
if (remote) {
|
|
11100
|
+
const position = new THREE39__namespace.Vector3(
|
|
11101
|
+
transform.position.x,
|
|
11102
|
+
transform.position.y,
|
|
11103
|
+
transform.position.z
|
|
11104
|
+
);
|
|
11105
|
+
remoteDistance = position.distanceTo(input.rayOrigin);
|
|
11106
|
+
offset = new THREE39__namespace.Vector3();
|
|
11107
|
+
} else if (viaDistance) {
|
|
11108
|
+
offset = new THREE39__namespace.Vector3(
|
|
11109
|
+
interactable.grabOffsetPosition.x,
|
|
11110
|
+
interactable.grabOffsetPosition.y,
|
|
11111
|
+
interactable.grabOffsetPosition.z
|
|
11112
|
+
);
|
|
11113
|
+
} else {
|
|
11114
|
+
offset = new THREE39__namespace.Vector3(
|
|
11115
|
+
transform.position.x - hand.x,
|
|
11116
|
+
transform.position.y - hand.y,
|
|
11117
|
+
transform.position.z - hand.z
|
|
11118
|
+
);
|
|
11119
|
+
}
|
|
10581
11120
|
const physics = world.getComponent(entityId, PhysicsComponent);
|
|
10582
11121
|
let restoreBodyType = null;
|
|
10583
|
-
|
|
10584
|
-
if (physics && interactable?.grabMode === "kinematic") {
|
|
11122
|
+
if (physics) {
|
|
10585
11123
|
restoreBodyType = physics.values.rigidbody.type;
|
|
10586
11124
|
physics.values.rigidbody.type = "kinematicPosition";
|
|
10587
11125
|
}
|
|
10588
|
-
|
|
11126
|
+
const tracker = new ThrowVelocityTracker();
|
|
11127
|
+
tracker.record(hand, this.elapsed);
|
|
11128
|
+
this.grabs.set(input, {
|
|
11129
|
+
entityId,
|
|
11130
|
+
offset,
|
|
11131
|
+
rotationOffset: new THREE39__namespace.Quaternion().setFromEuler(
|
|
11132
|
+
new THREE39__namespace.Euler(
|
|
11133
|
+
interactable.grabOffsetRotation.x,
|
|
11134
|
+
interactable.grabOffsetRotation.y,
|
|
11135
|
+
interactable.grabOffsetRotation.z
|
|
11136
|
+
)
|
|
11137
|
+
),
|
|
11138
|
+
remoteDistance,
|
|
11139
|
+
remote,
|
|
11140
|
+
restoreBodyType,
|
|
11141
|
+
tracker,
|
|
11142
|
+
lastHandQuaternion: handQuaternion.clone(),
|
|
11143
|
+
angularVelocity: new THREE39__namespace.Vector3()
|
|
11144
|
+
});
|
|
10589
11145
|
this.dispatch(world, entityId, (b) => b.onGrab(input));
|
|
10590
11146
|
}
|
|
10591
|
-
moveHeld(world, input, held) {
|
|
11147
|
+
moveHeld(world, input, held, deltaTime) {
|
|
10592
11148
|
const transform = world.getComponent(held.entityId, TransformComponent);
|
|
10593
11149
|
if (!transform) return;
|
|
10594
11150
|
const hand = this.handPosition(input);
|
|
10595
|
-
|
|
10596
|
-
|
|
10597
|
-
|
|
11151
|
+
if (held.remote) {
|
|
11152
|
+
const target = new THREE39__namespace.Vector3().copy(input.rayDirection).multiplyScalar(held.remoteDistance).add(input.rayOrigin);
|
|
11153
|
+
transform.position.x = target.x;
|
|
11154
|
+
transform.position.y = target.y;
|
|
11155
|
+
transform.position.z = target.z;
|
|
11156
|
+
} else {
|
|
11157
|
+
transform.position.x = hand.x + held.offset.x;
|
|
11158
|
+
transform.position.y = hand.y + held.offset.y;
|
|
11159
|
+
transform.position.z = hand.z + held.offset.z;
|
|
11160
|
+
}
|
|
11161
|
+
held.tracker.record(
|
|
11162
|
+
held.remote ? new THREE39__namespace.Vector3(
|
|
11163
|
+
transform.position.x,
|
|
11164
|
+
transform.position.y,
|
|
11165
|
+
transform.position.z
|
|
11166
|
+
) : hand,
|
|
11167
|
+
this.elapsed
|
|
11168
|
+
);
|
|
11169
|
+
const handQuaternion = this.handQuaternion(input);
|
|
11170
|
+
held.angularVelocity = angularVelocityFrom(
|
|
11171
|
+
held.lastHandQuaternion,
|
|
11172
|
+
handQuaternion,
|
|
11173
|
+
deltaTime
|
|
11174
|
+
);
|
|
11175
|
+
held.lastHandQuaternion = handQuaternion;
|
|
10598
11176
|
}
|
|
10599
11177
|
release(world, input) {
|
|
10600
11178
|
const held = this.grabs.get(input);
|
|
10601
11179
|
if (!held) return;
|
|
10602
11180
|
this.grabs.delete(input);
|
|
10603
|
-
|
|
10604
|
-
|
|
10605
|
-
|
|
10606
|
-
|
|
11181
|
+
const interactable = world.getComponent(
|
|
11182
|
+
held.entityId,
|
|
11183
|
+
XRInteractableComponent
|
|
11184
|
+
);
|
|
11185
|
+
const physics = world.getComponent(held.entityId, PhysicsComponent);
|
|
11186
|
+
if (held.restoreBodyType !== null && physics) {
|
|
11187
|
+
physics.values.rigidbody.type = held.restoreBodyType;
|
|
11188
|
+
const body = physics.rigidBody;
|
|
11189
|
+
const dynamic = held.restoreBodyType === "dynamic";
|
|
11190
|
+
if (body && dynamic && interactable?.throwOnRelease) {
|
|
11191
|
+
const velocity = held.tracker.computeVelocity(this.elapsed).multiplyScalar(interactable.throwStrength);
|
|
11192
|
+
try {
|
|
11193
|
+
body.setLinvel(
|
|
11194
|
+
{ x: velocity.x, y: velocity.y, z: velocity.z },
|
|
11195
|
+
true
|
|
11196
|
+
);
|
|
11197
|
+
const spin = held.angularVelocity;
|
|
11198
|
+
body.setAngvel({ x: spin.x, y: spin.y, z: spin.z }, true);
|
|
11199
|
+
} catch {
|
|
11200
|
+
}
|
|
10607
11201
|
}
|
|
10608
11202
|
}
|
|
11203
|
+
held.tracker.clear();
|
|
10609
11204
|
this.dispatch(world, held.entityId, (b) => b.onRelease(input));
|
|
10610
11205
|
}
|
|
10611
11206
|
releaseAll(world) {
|
|
@@ -10614,14 +11209,25 @@ var _XRInteractionSystem = class _XRInteractionSystem {
|
|
|
10614
11209
|
}
|
|
10615
11210
|
}
|
|
10616
11211
|
/**
|
|
10617
|
-
* Where the "hand" is
|
|
10618
|
-
*
|
|
10619
|
-
*
|
|
11212
|
+
* Where the "hand" is. Controllers and tracked hands report a grip pose;
|
|
11213
|
+
* gaze and transient-pointer sources have none, so we hold the object a fixed
|
|
11214
|
+
* distance along the ray instead — which is what makes Vision Pro work.
|
|
10620
11215
|
*/
|
|
10621
11216
|
handPosition(input) {
|
|
10622
11217
|
if (input.gripPosition) return input.gripPosition;
|
|
10623
11218
|
return new THREE39__namespace.Vector3().copy(input.rayDirection).multiplyScalar(RAYLESS_HOLD_DISTANCE).add(input.rayOrigin);
|
|
10624
11219
|
}
|
|
11220
|
+
/**
|
|
11221
|
+
* Hand orientation. Grip-less sources (gaze / transient-pointer) have none,
|
|
11222
|
+
* so we derive one from the aim direction — enough for spin on release.
|
|
11223
|
+
*/
|
|
11224
|
+
handQuaternion(input) {
|
|
11225
|
+
if (input.gripQuaternion) return input.gripQuaternion.clone();
|
|
11226
|
+
return new THREE39__namespace.Quaternion().setFromUnitVectors(
|
|
11227
|
+
new THREE39__namespace.Vector3(0, 0, -1),
|
|
11228
|
+
input.rayDirection.clone().normalize()
|
|
11229
|
+
);
|
|
11230
|
+
}
|
|
10625
11231
|
dispatch(world, entityId, visit) {
|
|
10626
11232
|
const script = world.getComponent(entityId, ScriptComponent);
|
|
10627
11233
|
const instances = script?.scriptInstances;
|
|
@@ -11191,6 +11797,7 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
|
|
|
11191
11797
|
this.handStyleSignature = "";
|
|
11192
11798
|
this.handMaterial = null;
|
|
11193
11799
|
this.interactionSystem = options?.interactionSystem ?? null;
|
|
11800
|
+
this.inputSystem = options?.inputSystem ?? null;
|
|
11194
11801
|
this.group.name = "XRControllerVisuals";
|
|
11195
11802
|
this.group.userData.ecsPreviewHidden = true;
|
|
11196
11803
|
}
|
|
@@ -11207,8 +11814,11 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
|
|
|
11207
11814
|
for (const { index, side } of SLOTS) {
|
|
11208
11815
|
const visuals = this.slots.get(index);
|
|
11209
11816
|
if (!visuals) continue;
|
|
11210
|
-
|
|
11211
|
-
|
|
11817
|
+
const liveKind = this.liveKindFor(side);
|
|
11818
|
+
const hasController = liveKind === null || liveKind === "controller";
|
|
11819
|
+
const hasHand = liveKind === null || liveKind === "hand";
|
|
11820
|
+
visuals.controllerModel.visible = showControllers && hasController;
|
|
11821
|
+
visuals.handModel.visible = showHands && hasHand;
|
|
11212
11822
|
visuals.ray.visible = this.shouldShowRay(interactor);
|
|
11213
11823
|
if (showHands && this.handMaterial) {
|
|
11214
11824
|
applyHandMaterial(visuals.handModel, this.handMaterial);
|
|
@@ -11216,6 +11826,20 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
|
|
|
11216
11826
|
this.syncCustomContent(world, visuals, side);
|
|
11217
11827
|
}
|
|
11218
11828
|
}
|
|
11829
|
+
/**
|
|
11830
|
+
* What kind of source is currently driving this hand, or null when we cannot
|
|
11831
|
+
* tell (no input system wired) — in which case callers fall back to showing
|
|
11832
|
+
* everything rather than hiding the user's hands entirely.
|
|
11833
|
+
*/
|
|
11834
|
+
liveKindFor(side) {
|
|
11835
|
+
if (!this.inputSystem) return null;
|
|
11836
|
+
const inputs = this.inputSystem.getInputs();
|
|
11837
|
+
if (inputs.length === 0) return null;
|
|
11838
|
+
for (const input of inputs) {
|
|
11839
|
+
if (input.handedness === side && input.connected) return input.kind;
|
|
11840
|
+
}
|
|
11841
|
+
return "none";
|
|
11842
|
+
}
|
|
11219
11843
|
/** The scene's interactor config, if one was authored. */
|
|
11220
11844
|
resolveInteractor(world) {
|
|
11221
11845
|
const entityId = world.query(XRInteractorComponent)[0];
|
|
@@ -11475,6 +12099,511 @@ var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
|
|
|
11475
12099
|
};
|
|
11476
12100
|
__name(_XRTeleportVisualSystem, "XRTeleportVisualSystem");
|
|
11477
12101
|
var XRTeleportVisualSystem = _XRTeleportVisualSystem;
|
|
12102
|
+
var XR_FINGERS = [
|
|
12103
|
+
"thumb",
|
|
12104
|
+
"index",
|
|
12105
|
+
"middle",
|
|
12106
|
+
"ring",
|
|
12107
|
+
"pinky"
|
|
12108
|
+
];
|
|
12109
|
+
var PINCH_FINGERS = [
|
|
12110
|
+
"index",
|
|
12111
|
+
"middle",
|
|
12112
|
+
"ring",
|
|
12113
|
+
"pinky"
|
|
12114
|
+
];
|
|
12115
|
+
var FINGER_CHAINS = {
|
|
12116
|
+
thumb: [
|
|
12117
|
+
"thumb-metacarpal",
|
|
12118
|
+
"thumb-phalanx-proximal",
|
|
12119
|
+
"thumb-phalanx-distal",
|
|
12120
|
+
"thumb-tip"
|
|
12121
|
+
],
|
|
12122
|
+
index: [
|
|
12123
|
+
"index-finger-metacarpal",
|
|
12124
|
+
"index-finger-phalanx-proximal",
|
|
12125
|
+
"index-finger-phalanx-intermediate",
|
|
12126
|
+
"index-finger-phalanx-distal",
|
|
12127
|
+
"index-finger-tip"
|
|
12128
|
+
],
|
|
12129
|
+
middle: [
|
|
12130
|
+
"middle-finger-metacarpal",
|
|
12131
|
+
"middle-finger-phalanx-proximal",
|
|
12132
|
+
"middle-finger-phalanx-intermediate",
|
|
12133
|
+
"middle-finger-phalanx-distal",
|
|
12134
|
+
"middle-finger-tip"
|
|
12135
|
+
],
|
|
12136
|
+
ring: [
|
|
12137
|
+
"ring-finger-metacarpal",
|
|
12138
|
+
"ring-finger-phalanx-proximal",
|
|
12139
|
+
"ring-finger-phalanx-intermediate",
|
|
12140
|
+
"ring-finger-phalanx-distal",
|
|
12141
|
+
"ring-finger-tip"
|
|
12142
|
+
],
|
|
12143
|
+
pinky: [
|
|
12144
|
+
"pinky-finger-metacarpal",
|
|
12145
|
+
"pinky-finger-phalanx-proximal",
|
|
12146
|
+
"pinky-finger-phalanx-intermediate",
|
|
12147
|
+
"pinky-finger-phalanx-distal",
|
|
12148
|
+
"pinky-finger-tip"
|
|
12149
|
+
]
|
|
12150
|
+
};
|
|
12151
|
+
var TIP_JOINTS = {
|
|
12152
|
+
thumb: "thumb-tip",
|
|
12153
|
+
index: "index-finger-tip",
|
|
12154
|
+
middle: "middle-finger-tip",
|
|
12155
|
+
ring: "ring-finger-tip",
|
|
12156
|
+
pinky: "pinky-finger-tip"
|
|
12157
|
+
};
|
|
12158
|
+
var METACARPAL_JOINTS = {
|
|
12159
|
+
thumb: "thumb-metacarpal",
|
|
12160
|
+
index: "index-finger-metacarpal",
|
|
12161
|
+
middle: "middle-finger-metacarpal",
|
|
12162
|
+
ring: "ring-finger-metacarpal",
|
|
12163
|
+
pinky: "pinky-finger-metacarpal"
|
|
12164
|
+
};
|
|
12165
|
+
var FALLBACK_HAND_SCALE = 0.08;
|
|
12166
|
+
var STRAIGHT_COS = 0.95;
|
|
12167
|
+
var CURLED_COS = 0.55;
|
|
12168
|
+
function clamp01(value) {
|
|
12169
|
+
return value < 0 ? 0 : value > 1 ? 1 : value;
|
|
12170
|
+
}
|
|
12171
|
+
__name(clamp01, "clamp01");
|
|
12172
|
+
function boneDirections(joints, finger) {
|
|
12173
|
+
const chain = FINGER_CHAINS[finger];
|
|
12174
|
+
const directions = [];
|
|
12175
|
+
for (let i = 1; i < chain.length; i += 1) {
|
|
12176
|
+
const from = joints[chain[i - 1]];
|
|
12177
|
+
const to = joints[chain[i]];
|
|
12178
|
+
if (!from || !to) return null;
|
|
12179
|
+
const direction = new THREE39__namespace.Vector3().subVectors(to, from);
|
|
12180
|
+
if (direction.lengthSq() < 1e-12) return null;
|
|
12181
|
+
directions.push(direction.normalize());
|
|
12182
|
+
}
|
|
12183
|
+
return directions.length >= 2 ? directions : null;
|
|
12184
|
+
}
|
|
12185
|
+
__name(boneDirections, "boneDirections");
|
|
12186
|
+
function bendAmounts(directions) {
|
|
12187
|
+
const bends = [];
|
|
12188
|
+
for (let i = 1; i < directions.length; i += 1) {
|
|
12189
|
+
const cos = directions[i - 1].dot(directions[i]);
|
|
12190
|
+
const straightness = clamp01((cos - CURLED_COS) / (STRAIGHT_COS - CURLED_COS));
|
|
12191
|
+
bends.push(1 - straightness);
|
|
12192
|
+
}
|
|
12193
|
+
return bends;
|
|
12194
|
+
}
|
|
12195
|
+
__name(bendAmounts, "bendAmounts");
|
|
12196
|
+
function average(values) {
|
|
12197
|
+
if (values.length === 0) return 0;
|
|
12198
|
+
let sum = 0;
|
|
12199
|
+
for (const value of values) sum += value;
|
|
12200
|
+
return sum / values.length;
|
|
12201
|
+
}
|
|
12202
|
+
__name(average, "average");
|
|
12203
|
+
function computeFingerCurl(joints, finger) {
|
|
12204
|
+
const directions = boneDirections(joints, finger);
|
|
12205
|
+
if (!directions) return null;
|
|
12206
|
+
const bends = bendAmounts(directions);
|
|
12207
|
+
if (bends.length === 0) return null;
|
|
12208
|
+
return {
|
|
12209
|
+
baseCurl: bends[0],
|
|
12210
|
+
tipCurl: average(bends.slice(1)) || bends[bends.length - 1],
|
|
12211
|
+
curl: average(bends)
|
|
12212
|
+
};
|
|
12213
|
+
}
|
|
12214
|
+
__name(computeFingerCurl, "computeFingerCurl");
|
|
12215
|
+
function computePalmWidth(joints) {
|
|
12216
|
+
const index = joints["index-finger-metacarpal"];
|
|
12217
|
+
const pinky = joints["pinky-finger-metacarpal"];
|
|
12218
|
+
if (!index || !pinky) return null;
|
|
12219
|
+
const width = index.distanceTo(pinky);
|
|
12220
|
+
return width > 1e-6 ? width : null;
|
|
12221
|
+
}
|
|
12222
|
+
__name(computePalmWidth, "computePalmWidth");
|
|
12223
|
+
function estimateHandScale(joints) {
|
|
12224
|
+
const measurements = [];
|
|
12225
|
+
const width = computePalmWidth(joints);
|
|
12226
|
+
if (width !== null) measurements.push(width);
|
|
12227
|
+
const wrist = joints.wrist;
|
|
12228
|
+
const middleTip = joints["middle-finger-tip"];
|
|
12229
|
+
if (wrist && middleTip) {
|
|
12230
|
+
const span = wrist.distanceTo(middleTip);
|
|
12231
|
+
if (span > 1e-6) measurements.push(span * 0.5);
|
|
12232
|
+
}
|
|
12233
|
+
if (measurements.length === 0) return FALLBACK_HAND_SCALE;
|
|
12234
|
+
return average(measurements);
|
|
12235
|
+
}
|
|
12236
|
+
__name(estimateHandScale, "estimateHandScale");
|
|
12237
|
+
function computePinch(joints, finger) {
|
|
12238
|
+
const thumbTip = joints["thumb-tip"];
|
|
12239
|
+
const fingerTip = joints[TIP_JOINTS[finger]];
|
|
12240
|
+
if (!thumbTip || !fingerTip) return null;
|
|
12241
|
+
const scale = estimateHandScale(joints);
|
|
12242
|
+
const distance = thumbTip.distanceTo(fingerTip);
|
|
12243
|
+
return clamp01(1 - distance / (scale * 0.7));
|
|
12244
|
+
}
|
|
12245
|
+
__name(computePinch, "computePinch");
|
|
12246
|
+
function computeSpread(joints, a, b) {
|
|
12247
|
+
const aBase = joints[METACARPAL_JOINTS[a]];
|
|
12248
|
+
const aTip = joints[TIP_JOINTS[a]];
|
|
12249
|
+
const bBase = joints[METACARPAL_JOINTS[b]];
|
|
12250
|
+
const bTip = joints[TIP_JOINTS[b]];
|
|
12251
|
+
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);
|
|
12254
|
+
if (dirA.lengthSq() < 1e-12 || dirB.lengthSq() < 1e-12) return null;
|
|
12255
|
+
return clamp01((1 - dirA.normalize().dot(dirB.normalize())) / 0.45);
|
|
12256
|
+
}
|
|
12257
|
+
__name(computeSpread, "computeSpread");
|
|
12258
|
+
function computePalmPose(joints, handedness) {
|
|
12259
|
+
const wrist = joints.wrist;
|
|
12260
|
+
const indexBase = joints["index-finger-metacarpal"];
|
|
12261
|
+
const pinkyBase = joints["pinky-finger-metacarpal"];
|
|
12262
|
+
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);
|
|
12266
|
+
if (normal.lengthSq() < 1e-12) return null;
|
|
12267
|
+
normal.normalize();
|
|
12268
|
+
if (handedness === "left") normal.multiplyScalar(-1);
|
|
12269
|
+
const right = new THREE39__namespace.Vector3().subVectors(indexBase, pinkyBase);
|
|
12270
|
+
if (right.lengthSq() < 1e-12) return null;
|
|
12271
|
+
right.normalize();
|
|
12272
|
+
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);
|
|
12275
|
+
return {
|
|
12276
|
+
center,
|
|
12277
|
+
normal,
|
|
12278
|
+
right,
|
|
12279
|
+
up,
|
|
12280
|
+
width: computePalmWidth(joints) ?? FALLBACK_HAND_SCALE
|
|
12281
|
+
};
|
|
12282
|
+
}
|
|
12283
|
+
__name(computePalmPose, "computePalmPose");
|
|
12284
|
+
function computeHandShape(joints, handedness) {
|
|
12285
|
+
const fingers2 = {};
|
|
12286
|
+
let tracked = 0;
|
|
12287
|
+
for (const finger of XR_FINGERS) {
|
|
12288
|
+
const curl = computeFingerCurl(joints, finger);
|
|
12289
|
+
if (curl) {
|
|
12290
|
+
fingers2[finger] = curl;
|
|
12291
|
+
tracked += 1;
|
|
12292
|
+
} else {
|
|
12293
|
+
fingers2[finger] = { baseCurl: 0, tipCurl: 0, curl: 0 };
|
|
12294
|
+
}
|
|
12295
|
+
}
|
|
12296
|
+
if (tracked === 0) return null;
|
|
12297
|
+
const pinch = {};
|
|
12298
|
+
for (const finger of PINCH_FINGERS) {
|
|
12299
|
+
pinch[finger] = computePinch(joints, finger) ?? 0;
|
|
12300
|
+
}
|
|
12301
|
+
const thumbBase = joints["thumb-metacarpal"];
|
|
12302
|
+
const thumbTip = joints["thumb-tip"];
|
|
12303
|
+
let thumbDirection = null;
|
|
12304
|
+
if (thumbBase && thumbTip) {
|
|
12305
|
+
const direction = new THREE39__namespace.Vector3().subVectors(thumbTip, thumbBase);
|
|
12306
|
+
if (direction.lengthSq() > 1e-12) thumbDirection = direction.normalize();
|
|
12307
|
+
}
|
|
12308
|
+
return {
|
|
12309
|
+
handedness,
|
|
12310
|
+
fingers: fingers2,
|
|
12311
|
+
pinch,
|
|
12312
|
+
spread: {
|
|
12313
|
+
thumbIndex: computeSpread(joints, "thumb", "index") ?? 0,
|
|
12314
|
+
indexMiddle: computeSpread(joints, "index", "middle") ?? 0,
|
|
12315
|
+
middleRing: computeSpread(joints, "middle", "ring") ?? 0,
|
|
12316
|
+
ringPinky: computeSpread(joints, "ring", "pinky") ?? 0
|
|
12317
|
+
},
|
|
12318
|
+
palm: computePalmPose(joints, handedness),
|
|
12319
|
+
scale: estimateHandScale(joints),
|
|
12320
|
+
thumbDirection
|
|
12321
|
+
};
|
|
12322
|
+
}
|
|
12323
|
+
__name(computeHandShape, "computeHandShape");
|
|
12324
|
+
var MATCH_FALLOFF = 0.25;
|
|
12325
|
+
var NO_MATCH = {
|
|
12326
|
+
matched: false,
|
|
12327
|
+
confidence: 0,
|
|
12328
|
+
worstConstraint: null
|
|
12329
|
+
};
|
|
12330
|
+
function scoreAgainst(actual, target, tolerance) {
|
|
12331
|
+
const error = Math.abs(actual - target);
|
|
12332
|
+
if (error <= tolerance) return 1;
|
|
12333
|
+
return clamp01(1 - (error - tolerance) / MATCH_FALLOFF);
|
|
12334
|
+
}
|
|
12335
|
+
__name(scoreAgainst, "scoreAgainst");
|
|
12336
|
+
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)
|
|
12343
|
+
};
|
|
12344
|
+
function axisVector(shape, axis) {
|
|
12345
|
+
if (axis === "thumb") return shape.thumbDirection;
|
|
12346
|
+
if (!shape.palm) return null;
|
|
12347
|
+
return axis === "palm-normal" ? shape.palm.normal : shape.palm.up;
|
|
12348
|
+
}
|
|
12349
|
+
__name(axisVector, "axisVector");
|
|
12350
|
+
function resolveDirection(direction, shape, context) {
|
|
12351
|
+
if (direction !== "toward-head" && direction !== "away-from-head") {
|
|
12352
|
+
return WORLD_DIRECTIONS[direction];
|
|
12353
|
+
}
|
|
12354
|
+
const head = context?.headPosition;
|
|
12355
|
+
const origin = shape.palm?.center;
|
|
12356
|
+
if (!head || !origin) return null;
|
|
12357
|
+
const toHead = new THREE39__namespace.Vector3().subVectors(head, origin);
|
|
12358
|
+
if (toHead.lengthSq() < 1e-12) return null;
|
|
12359
|
+
toHead.normalize();
|
|
12360
|
+
return direction === "toward-head" ? toHead : toHead.multiplyScalar(-1);
|
|
12361
|
+
}
|
|
12362
|
+
__name(resolveDirection, "resolveDirection");
|
|
12363
|
+
function matchHandPose(shape, definition, context) {
|
|
12364
|
+
if (definition.hand && definition.hand !== shape.handedness) return NO_MATCH;
|
|
12365
|
+
let confidence = 1;
|
|
12366
|
+
let worstScore = 1;
|
|
12367
|
+
let worstConstraint = null;
|
|
12368
|
+
const consider = /* @__PURE__ */ __name((score, label) => {
|
|
12369
|
+
if (score < confidence) confidence = score;
|
|
12370
|
+
if (score < worstScore) {
|
|
12371
|
+
worstScore = score;
|
|
12372
|
+
worstConstraint = label;
|
|
12373
|
+
}
|
|
12374
|
+
}, "consider");
|
|
12375
|
+
for (const finger of XR_FINGERS) {
|
|
12376
|
+
const target = definition.fingers[finger];
|
|
12377
|
+
if (!target) continue;
|
|
12378
|
+
const actual = shape.fingers[finger];
|
|
12379
|
+
consider(scoreAgainst(actual.curl, target.curl, target.tolerance), finger);
|
|
12380
|
+
if (target.baseCurl !== void 0) {
|
|
12381
|
+
consider(
|
|
12382
|
+
scoreAgainst(actual.baseCurl, target.baseCurl, target.tolerance),
|
|
12383
|
+
`${finger} knuckle`
|
|
12384
|
+
);
|
|
12385
|
+
}
|
|
12386
|
+
if (target.tipCurl !== void 0) {
|
|
12387
|
+
consider(
|
|
12388
|
+
scoreAgainst(actual.tipCurl, target.tipCurl, target.tolerance),
|
|
12389
|
+
`${finger} tip`
|
|
12390
|
+
);
|
|
12391
|
+
}
|
|
12392
|
+
}
|
|
12393
|
+
if (definition.pinch) {
|
|
12394
|
+
const { finger, target, tolerance } = definition.pinch;
|
|
12395
|
+
consider(
|
|
12396
|
+
scoreAgainst(shape.pinch[finger], target, tolerance),
|
|
12397
|
+
`${finger} pinch`
|
|
12398
|
+
);
|
|
12399
|
+
}
|
|
12400
|
+
if (definition.orientation) {
|
|
12401
|
+
const { axis, direction, toleranceDegrees } = definition.orientation;
|
|
12402
|
+
const handAxis = axisVector(shape, axis);
|
|
12403
|
+
const wanted = resolveDirection(direction, shape, context);
|
|
12404
|
+
if (!handAxis || !wanted) {
|
|
12405
|
+
consider(0, "orientation");
|
|
12406
|
+
} else {
|
|
12407
|
+
const angle = THREE39__namespace.MathUtils.radToDeg(
|
|
12408
|
+
Math.acos(THREE39__namespace.MathUtils.clamp(handAxis.dot(wanted), -1, 1))
|
|
12409
|
+
);
|
|
12410
|
+
const normalizedError = Math.max(0, angle - toleranceDegrees) / 90;
|
|
12411
|
+
consider(clamp01(1 - normalizedError / MATCH_FALLOFF), "orientation");
|
|
12412
|
+
}
|
|
12413
|
+
}
|
|
12414
|
+
return {
|
|
12415
|
+
matched: confidence >= 1,
|
|
12416
|
+
confidence,
|
|
12417
|
+
worstConstraint: confidence >= 1 ? null : worstConstraint
|
|
12418
|
+
};
|
|
12419
|
+
}
|
|
12420
|
+
__name(matchHandPose, "matchHandPose");
|
|
12421
|
+
var DEFAULT_ENTER_CONFIDENCE = 0.8;
|
|
12422
|
+
var DEFAULT_EXIT_CONFIDENCE = 0.55;
|
|
12423
|
+
var DEFAULT_MIN_HOLD_SECONDS = 0.15;
|
|
12424
|
+
var DEFAULT_LOST_GRACE_SECONDS = 0.25;
|
|
12425
|
+
var _HandPoseTracker = class _HandPoseTracker {
|
|
12426
|
+
constructor(options) {
|
|
12427
|
+
this.active = false;
|
|
12428
|
+
this.holdingSince = null;
|
|
12429
|
+
this.lostSince = null;
|
|
12430
|
+
this.enterConfidence = options?.enterConfidence ?? DEFAULT_ENTER_CONFIDENCE;
|
|
12431
|
+
const exit = options?.exitConfidence ?? DEFAULT_EXIT_CONFIDENCE;
|
|
12432
|
+
this.exitConfidence = Math.min(exit, this.enterConfidence - 1e-3);
|
|
12433
|
+
this.minHoldSeconds = options?.minHoldSeconds ?? DEFAULT_MIN_HOLD_SECONDS;
|
|
12434
|
+
this.lostGraceSeconds = options?.lostGraceSeconds ?? DEFAULT_LOST_GRACE_SECONDS;
|
|
12435
|
+
}
|
|
12436
|
+
isActive() {
|
|
12437
|
+
return this.active;
|
|
12438
|
+
}
|
|
12439
|
+
/** Feed this frame's confidence. Returns an event on a transition. */
|
|
12440
|
+
update(confidence, now) {
|
|
12441
|
+
this.lostSince = null;
|
|
12442
|
+
if (this.active) {
|
|
12443
|
+
if (confidence < this.exitConfidence) {
|
|
12444
|
+
this.active = false;
|
|
12445
|
+
this.holdingSince = null;
|
|
12446
|
+
return "end";
|
|
12447
|
+
}
|
|
12448
|
+
return null;
|
|
12449
|
+
}
|
|
12450
|
+
if (confidence >= this.enterConfidence) {
|
|
12451
|
+
if (this.holdingSince === null) this.holdingSince = now;
|
|
12452
|
+
if (now - this.holdingSince >= this.minHoldSeconds) {
|
|
12453
|
+
this.active = true;
|
|
12454
|
+
return "start";
|
|
12455
|
+
}
|
|
12456
|
+
return null;
|
|
12457
|
+
}
|
|
12458
|
+
this.holdingSince = null;
|
|
12459
|
+
return null;
|
|
12460
|
+
}
|
|
12461
|
+
/** Feed a frame where the hand isn't tracked at all. */
|
|
12462
|
+
miss(now) {
|
|
12463
|
+
this.holdingSince = null;
|
|
12464
|
+
if (!this.active) return null;
|
|
12465
|
+
if (this.lostSince === null) this.lostSince = now;
|
|
12466
|
+
if (now - this.lostSince < this.lostGraceSeconds) return null;
|
|
12467
|
+
this.active = false;
|
|
12468
|
+
this.lostSince = null;
|
|
12469
|
+
return "end";
|
|
12470
|
+
}
|
|
12471
|
+
reset() {
|
|
12472
|
+
this.active = false;
|
|
12473
|
+
this.holdingSince = null;
|
|
12474
|
+
this.lostSince = null;
|
|
12475
|
+
}
|
|
12476
|
+
};
|
|
12477
|
+
__name(_HandPoseTracker, "HandPoseTracker");
|
|
12478
|
+
var HandPoseTracker = _HandPoseTracker;
|
|
12479
|
+
|
|
12480
|
+
// core/systems/XRHandPoseSystem.ts
|
|
12481
|
+
var _XRHandPoseSystem = class _XRHandPoseSystem {
|
|
12482
|
+
constructor(inputSystem) {
|
|
12483
|
+
this.trackers = /* @__PURE__ */ new Map();
|
|
12484
|
+
this.shapes = /* @__PURE__ */ new Map();
|
|
12485
|
+
/** Reused so head-relative orientation checks allocate nothing per frame. */
|
|
12486
|
+
this.headPosition = new THREE39__namespace.Vector3();
|
|
12487
|
+
this.elapsed = 0;
|
|
12488
|
+
this.inputSystem = inputSystem;
|
|
12489
|
+
}
|
|
12490
|
+
update(world, deltaTime) {
|
|
12491
|
+
if (!world.isXrPresenting()) {
|
|
12492
|
+
this.resetAll();
|
|
12493
|
+
return;
|
|
12494
|
+
}
|
|
12495
|
+
this.elapsed += deltaTime;
|
|
12496
|
+
this.refreshShapes();
|
|
12497
|
+
const entries = this.collectEntries(world);
|
|
12498
|
+
if (entries.length === 0) return;
|
|
12499
|
+
world.getCamera().getWorldPosition(this.headPosition);
|
|
12500
|
+
const context = { headPosition: this.headPosition };
|
|
12501
|
+
for (const { entityId, entry } of entries) {
|
|
12502
|
+
const definition = handPoseDefinitionFor(entry, getHandPosePreset);
|
|
12503
|
+
if (!definition) continue;
|
|
12504
|
+
for (const handedness of ["left", "right"]) {
|
|
12505
|
+
if (entry.hand && entry.hand !== handedness) continue;
|
|
12506
|
+
const key = `${entityId}:${entry.id}`;
|
|
12507
|
+
const trackers = this.trackersFor(handedness);
|
|
12508
|
+
let tracker = trackers.get(key);
|
|
12509
|
+
if (!tracker) {
|
|
12510
|
+
tracker = new HandPoseTracker({
|
|
12511
|
+
minHoldSeconds: entry.minHoldSeconds
|
|
12512
|
+
});
|
|
12513
|
+
trackers.set(key, tracker);
|
|
12514
|
+
}
|
|
12515
|
+
const shape = this.shapes.get(handedness) ?? null;
|
|
12516
|
+
if (!shape) {
|
|
12517
|
+
if (tracker.miss(this.elapsed) === "end") {
|
|
12518
|
+
this.dispatch(world, entityId, "end", {
|
|
12519
|
+
poseId: entry.id,
|
|
12520
|
+
poseName: entry.name,
|
|
12521
|
+
handedness,
|
|
12522
|
+
confidence: 0
|
|
12523
|
+
});
|
|
12524
|
+
}
|
|
12525
|
+
continue;
|
|
12526
|
+
}
|
|
12527
|
+
const match = matchHandPose(shape, definition, context);
|
|
12528
|
+
const event = tracker.update(match.confidence, this.elapsed);
|
|
12529
|
+
if (event) {
|
|
12530
|
+
this.dispatch(world, entityId, event, {
|
|
12531
|
+
poseId: entry.id,
|
|
12532
|
+
poseName: entry.name,
|
|
12533
|
+
handedness,
|
|
12534
|
+
confidence: match.confidence
|
|
12535
|
+
});
|
|
12536
|
+
}
|
|
12537
|
+
}
|
|
12538
|
+
}
|
|
12539
|
+
}
|
|
12540
|
+
/** Derive each hand's shape once for the whole frame. */
|
|
12541
|
+
refreshShapes() {
|
|
12542
|
+
for (const handedness of ["left", "right"]) {
|
|
12543
|
+
const input = this.inputSystem.getInput(handedness);
|
|
12544
|
+
const joints = input?.joints ?? null;
|
|
12545
|
+
this.shapes.set(
|
|
12546
|
+
handedness,
|
|
12547
|
+
joints ? computeHandShape(joints, handedness) : null
|
|
12548
|
+
);
|
|
12549
|
+
}
|
|
12550
|
+
}
|
|
12551
|
+
collectEntries(world) {
|
|
12552
|
+
const collected = [];
|
|
12553
|
+
for (const entityId of world.query(XRHandPoseComponent)) {
|
|
12554
|
+
const component = world.getComponent(entityId, XRHandPoseComponent);
|
|
12555
|
+
if (!component?.enabled) continue;
|
|
12556
|
+
for (const entry of component.poses) {
|
|
12557
|
+
if (entry.enabled) collected.push({ entityId, entry });
|
|
12558
|
+
}
|
|
12559
|
+
}
|
|
12560
|
+
return collected;
|
|
12561
|
+
}
|
|
12562
|
+
trackersFor(handedness) {
|
|
12563
|
+
let trackers = this.trackers.get(handedness);
|
|
12564
|
+
if (!trackers) {
|
|
12565
|
+
trackers = /* @__PURE__ */ new Map();
|
|
12566
|
+
this.trackers.set(handedness, trackers);
|
|
12567
|
+
}
|
|
12568
|
+
return trackers;
|
|
12569
|
+
}
|
|
12570
|
+
/**
|
|
12571
|
+
* Deliver to the entity's own Behaviours.
|
|
12572
|
+
*
|
|
12573
|
+
* Scoped to the entity that declared the pose rather than broadcast, so two
|
|
12574
|
+
* objects listening for the same gesture stay independent.
|
|
12575
|
+
*/
|
|
12576
|
+
dispatch(world, entityId, event, detail) {
|
|
12577
|
+
const script = world.getComponent(entityId, ScriptComponent);
|
|
12578
|
+
const instances = script?.scriptInstances;
|
|
12579
|
+
if (!instances) return;
|
|
12580
|
+
for (const instance of instances.values()) {
|
|
12581
|
+
if (!(instance instanceof Behaviour)) continue;
|
|
12582
|
+
try {
|
|
12583
|
+
if (event === "start") instance.onHandPoseStart(detail);
|
|
12584
|
+
else instance.onHandPoseEnd(detail);
|
|
12585
|
+
} catch (error) {
|
|
12586
|
+
console.error("[XRHandPoseSystem] Behaviour hook failed:", error);
|
|
12587
|
+
}
|
|
12588
|
+
}
|
|
12589
|
+
}
|
|
12590
|
+
resetAll() {
|
|
12591
|
+
for (const trackers of this.trackers.values()) {
|
|
12592
|
+
for (const tracker of trackers.values()) tracker.reset();
|
|
12593
|
+
}
|
|
12594
|
+
this.shapes.clear();
|
|
12595
|
+
}
|
|
12596
|
+
/** Live shape for a hand — powers the editor's pose readout. */
|
|
12597
|
+
getHandShape(handedness) {
|
|
12598
|
+
return this.shapes.get(handedness) ?? null;
|
|
12599
|
+
}
|
|
12600
|
+
/** Whether a given entity's pose is currently held. */
|
|
12601
|
+
isPoseActive(entityId, poseId, handedness) {
|
|
12602
|
+
return this.trackers.get(handedness)?.get(`${entityId}:${poseId}`)?.isActive() ?? false;
|
|
12603
|
+
}
|
|
12604
|
+
};
|
|
12605
|
+
__name(_XRHandPoseSystem, "XRHandPoseSystem");
|
|
12606
|
+
var XRHandPoseSystem = _XRHandPoseSystem;
|
|
11478
12607
|
|
|
11479
12608
|
// core/World.ts
|
|
11480
12609
|
var _World = class _World {
|
|
@@ -12858,15 +13987,27 @@ exports.AnimationStateManager = AnimationStateManager;
|
|
|
12858
13987
|
exports.AnimationSystem = AnimationSystem;
|
|
12859
13988
|
exports.AudioSystem = AudioSystem;
|
|
12860
13989
|
exports.Behaviour = Behaviour;
|
|
13990
|
+
exports.CURLED_COS = CURLED_COS;
|
|
12861
13991
|
exports.CameraSyncSystem = CameraSyncSystem;
|
|
12862
13992
|
exports.Component = Component;
|
|
12863
13993
|
exports.CoreComponents = components_exports;
|
|
13994
|
+
exports.DEFAULT_ENTER_CONFIDENCE = DEFAULT_ENTER_CONFIDENCE;
|
|
13995
|
+
exports.DEFAULT_EXIT_CONFIDENCE = DEFAULT_EXIT_CONFIDENCE;
|
|
13996
|
+
exports.DEFAULT_LOST_GRACE_SECONDS = DEFAULT_LOST_GRACE_SECONDS;
|
|
13997
|
+
exports.DEFAULT_MIN_HOLD_SECONDS = DEFAULT_MIN_HOLD_SECONDS;
|
|
12864
13998
|
exports.EnvironmentSyncSystem = EnvironmentSyncSystem;
|
|
13999
|
+
exports.FALLBACK_HAND_SCALE = FALLBACK_HAND_SCALE;
|
|
14000
|
+
exports.HAND_POSE_PRESETS = HAND_POSE_PRESETS;
|
|
14001
|
+
exports.HAND_POSE_PRESET_IDS = HAND_POSE_PRESET_IDS;
|
|
12865
14002
|
exports.HYDRATABLE_ENTITY_KINDS = HYDRATABLE_ENTITY_KINDS;
|
|
14003
|
+
exports.HandPoseTracker = HandPoseTracker;
|
|
12866
14004
|
exports.InputSystem = InputSystem;
|
|
12867
14005
|
exports.InstancedMeshSystem = InstancedMeshSystem;
|
|
12868
14006
|
exports.KeyboardKeys = KeyboardKeys;
|
|
12869
14007
|
exports.LightSyncSystem = LightSyncSystem;
|
|
14008
|
+
exports.MATCH_FALLOFF = MATCH_FALLOFF;
|
|
14009
|
+
exports.MAX_PLAUSIBLE_SPEED = MAX_PLAUSIBLE_SPEED;
|
|
14010
|
+
exports.MAX_SAMPLE_AGE_SECONDS = MAX_SAMPLE_AGE_SECONDS;
|
|
12870
14011
|
exports.MaterialSyncSystem = MaterialSyncSystem;
|
|
12871
14012
|
exports.MeshGeometrySystem = MeshGeometrySystem;
|
|
12872
14013
|
exports.NODE_KEY_SEPARATOR = NODE_KEY_SEPARATOR;
|
|
@@ -12875,6 +14016,7 @@ exports.OVERRIDE_DIFF_EXCLUDED_COMPONENTS = OVERRIDE_DIFF_EXCLUDED_COMPONENTS;
|
|
|
12875
14016
|
exports.OVERRIDE_ROOT_EXCLUDED_COMPONENTS = OVERRIDE_ROOT_EXCLUDED_COMPONENTS;
|
|
12876
14017
|
exports.ObjectManagementSystem = ObjectManagementSystem;
|
|
12877
14018
|
exports.ObjectVisibilitySystem = ObjectVisibilitySystem;
|
|
14019
|
+
exports.PINCH_FINGERS = PINCH_FINGERS;
|
|
12878
14020
|
exports.PREFAB_FILE_VERSION = PREFAB_FILE_VERSION;
|
|
12879
14021
|
exports.PREFAB_FILE_VERSION_NESTED = PREFAB_FILE_VERSION_NESTED;
|
|
12880
14022
|
exports.PhysicsSyncSystem = PhysicsSyncSystem;
|
|
@@ -12882,19 +14024,25 @@ exports.PostprocessingSyncSystem = PostprocessingSyncSystem;
|
|
|
12882
14024
|
exports.RenderSystem = RenderSystem;
|
|
12883
14025
|
exports.SCRIPT_OBJECT_ROOT_FLAG = SCRIPT_OBJECT_ROOT_FLAG;
|
|
12884
14026
|
exports.SHARED_MODEL_RESOURCE_FLAG = SHARED_MODEL_RESOURCE_FLAG;
|
|
14027
|
+
exports.STRAIGHT_COS = STRAIGHT_COS;
|
|
12885
14028
|
exports.ScriptBehaviourSystem = ScriptBehaviourSystem;
|
|
12886
14029
|
exports.ScriptObject = ScriptObject;
|
|
12887
14030
|
exports.ScriptObjectSystem = ScriptObjectSystem;
|
|
14031
|
+
exports.ThrowVelocityTracker = ThrowVelocityTracker;
|
|
12888
14032
|
exports.TransformSyncSystem = TransformSyncSystem;
|
|
14033
|
+
exports.VELOCITY_SAMPLES = VELOCITY_SAMPLES;
|
|
12889
14034
|
exports.VRTeleportAreaSystem = VRTeleportAreaSystem;
|
|
12890
14035
|
exports.VideoSystem = VideoSystem;
|
|
12891
14036
|
exports.World = World;
|
|
12892
14037
|
exports.XRControllerVisualSystem = XRControllerVisualSystem;
|
|
14038
|
+
exports.XRHandPoseSystem = XRHandPoseSystem;
|
|
12893
14039
|
exports.XRInputSystem = XRInputSystem;
|
|
12894
14040
|
exports.XRInteractionSystem = XRInteractionSystem;
|
|
12895
14041
|
exports.XRLocomotionSystem = XRLocomotionSystem;
|
|
12896
14042
|
exports.XRSessionSystem = XRSessionSystem;
|
|
12897
14043
|
exports.XRTeleportVisualSystem = XRTeleportVisualSystem;
|
|
14044
|
+
exports.XR_FINGERS = XR_FINGERS;
|
|
14045
|
+
exports.angularVelocityFrom = angularVelocityFrom;
|
|
12898
14046
|
exports.applyHandMaterial = applyHandMaterial;
|
|
12899
14047
|
exports.applyPrefabToSnapshotInstances = applyPrefabToSnapshotInstances;
|
|
12900
14048
|
exports.arcGroundCrossing = arcGroundCrossing;
|
|
@@ -12904,11 +14052,18 @@ exports.buildNodeMapsFromSnapshot = buildNodeMapsFromSnapshot;
|
|
|
12904
14052
|
exports.canonicalizeComponentValue = canonicalizeComponentValue;
|
|
12905
14053
|
exports.clearModelCache = clearModelCache;
|
|
12906
14054
|
exports.clearPrefabCache = clearPrefabCache;
|
|
14055
|
+
exports.cloneHandPose = cloneHandPose;
|
|
12907
14056
|
exports.collectDiffPaths = collectDiffPaths;
|
|
12908
14057
|
exports.collectDirectPrefabDependencies = collectDirectPrefabDependencies;
|
|
12909
14058
|
exports.collectEntitySubtree = collectEntitySubtree;
|
|
12910
14059
|
exports.collectSnapshotSubtreeIds = collectSnapshotSubtreeIds;
|
|
14060
|
+
exports.computeFingerCurl = computeFingerCurl;
|
|
14061
|
+
exports.computeHandShape = computeHandShape;
|
|
12911
14062
|
exports.computeInstanceOverrides = computeInstanceOverrides;
|
|
14063
|
+
exports.computePalmPose = computePalmPose;
|
|
14064
|
+
exports.computePalmWidth = computePalmWidth;
|
|
14065
|
+
exports.computePinch = computePinch;
|
|
14066
|
+
exports.computeSpread = computeSpread;
|
|
12912
14067
|
exports.createAnimationComponent = createAnimationComponent;
|
|
12913
14068
|
exports.createAudioComponent = createAudioComponent;
|
|
12914
14069
|
exports.createCameraComponent = createCameraComponent;
|
|
@@ -12938,6 +14093,7 @@ exports.createSpriteComponent = createSpriteComponent;
|
|
|
12938
14093
|
exports.createTransformComponent = createTransformComponent;
|
|
12939
14094
|
exports.createVRTeleportAreaComponent = createVRTeleportAreaComponent;
|
|
12940
14095
|
exports.createVideoComponent = createVideoComponent;
|
|
14096
|
+
exports.createXRHandPoseComponent = createXRHandPoseComponent;
|
|
12941
14097
|
exports.createXRInteractableComponent = createXRInteractableComponent;
|
|
12942
14098
|
exports.createXRInteractorComponent = createXRInteractorComponent;
|
|
12943
14099
|
exports.createXRInteractorSideComponent = createXRInteractorSideComponent;
|
|
@@ -12945,15 +14101,19 @@ exports.createXRRigComponent = createXRRigComponent;
|
|
|
12945
14101
|
exports.decanonicalizeComponentValue = decanonicalizeComponentValue;
|
|
12946
14102
|
exports.despawnPrefab = despawnPrefab;
|
|
12947
14103
|
exports.encodeOverride = encodeOverride;
|
|
14104
|
+
exports.estimateHandScale = estimateHandScale;
|
|
12948
14105
|
exports.findSnapshotRootEntityIds = findSnapshotRootEntityIds;
|
|
12949
14106
|
exports.findTopLevelNestedRegions = findTopLevelNestedRegions;
|
|
14107
|
+
exports.getHandPosePreset = getHandPosePreset;
|
|
12950
14108
|
exports.groupOverridePaths = groupOverridePaths;
|
|
14109
|
+
exports.handPoseFromCurls = handPoseFromCurls;
|
|
12951
14110
|
exports.hydrateWorldFromSnapshot = hydrateWorldFromSnapshot;
|
|
12952
14111
|
exports.hydrateWorldFromSnapshotDetailed = hydrateWorldFromSnapshotDetailed;
|
|
12953
14112
|
exports.indexSnapshotByEntity = indexSnapshotByEntity;
|
|
12954
14113
|
exports.instantiateSubtree = instantiateSubtree;
|
|
12955
14114
|
exports.loadPrefab = loadPrefab;
|
|
12956
14115
|
exports.loadSharedGltf = loadSharedGltf;
|
|
14116
|
+
exports.matchHandPose = matchHandPose;
|
|
12957
14117
|
exports.mergeComponentValue = mergeComponentValue;
|
|
12958
14118
|
exports.parseOverride = parseOverride;
|
|
12959
14119
|
exports.parsePrefabAsset = parsePrefabAsset;
|