@relu-interactives/spatial-ecs 0.3.18 → 0.3.20
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/{XRHandPose-B8xxFb9A.d.cts → XRHandPose-CLl4MiHx.d.cts} +12 -2
- package/dist/{XRHandPose-ubMe5Igc.d.ts → XRHandPose-CrzI57JA.d.ts} +12 -2
- package/dist/{chunk-7SSOZWXM.js → chunk-CDSE7476.js} +82 -6
- package/dist/chunk-CDSE7476.js.map +1 -0
- package/dist/{chunk-PFE2SDXR.js → chunk-D6KXWNYT.js} +3 -3
- package/dist/{chunk-PFE2SDXR.js.map → chunk-D6KXWNYT.js.map} +1 -1
- package/dist/{chunk-J3EUNW57.js → chunk-H6DQ7JRE.js} +48 -18
- package/dist/chunk-H6DQ7JRE.js.map +1 -0
- package/dist/{chunk-KRWBNC6Y.js → chunk-P42OE3RU.js} +4 -4
- package/dist/{chunk-KRWBNC6Y.js.map → chunk-P42OE3RU.js.map} +1 -1
- package/dist/components/index.cjs +33 -10
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.d.cts +3 -3
- package/dist/components/index.d.ts +3 -3
- package/dist/components/index.js +1 -1
- package/dist/docs/guide/vr-and-hand-poses.md +167 -0
- package/dist/factories/index.cjs +8 -0
- package/dist/factories/index.cjs.map +1 -1
- package/dist/factories/index.d.cts +2 -2
- package/dist/factories/index.d.ts +2 -2
- package/dist/factories/index.js +3 -3
- package/dist/{handPose-dFxqbFFY.d.cts → handPose-DlcTtqgx.d.cts} +26 -1
- package/dist/{handPose-dFxqbFFY.d.ts → handPose-DlcTtqgx.d.ts} +26 -1
- package/dist/{index-D7aSZ-e9.d.ts → index-6l4hn2Sh.d.ts} +15 -1
- package/dist/{index-7CFf45fo.d.cts → index-C2I5PxCI.d.cts} +15 -1
- package/dist/{index-DhWfxUgL.d.ts → index-JRcoel9F.d.ts} +3 -2
- package/dist/{index-CA9fqh4Z.d.cts → index-g777AmFv.d.cts} +3 -2
- package/dist/index.cjs +123 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -8
- package/dist/index.d.ts +11 -8
- package/dist/index.js +8 -8
- package/dist/systems/index.cjs +114 -16
- package/dist/systems/index.cjs.map +1 -1
- package/dist/systems/index.d.cts +2 -2
- package/dist/systems/index.d.ts +2 -2
- package/dist/systems/index.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-7SSOZWXM.js.map +0 -1
- package/dist/chunk-J3EUNW57.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,
|
|
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_POSE_DIRECTIONS, o as DEFAULT_RIGIDBODY_STATE, E as EditableMeshObjectKind, p as EntityType, I as ImageComponent, q as ImageTarget, r as ImageTargetAnchor, s as ImageTargetAnchorOptions, t as ImageTargetReference, u as InstanceSlotComponent, v as InstanceTransform, w as InstancedMeshComponent, x as InstancedMeshKind, L as LightComponent, y as LightValueState, M as MaterialComponent, z as MaterialTypeValue, B as MaterialValueState, F as MeshComponent, G as MeshGeometryComponent, H as MeshGeometryParameters, J as MeshGeometryParametersByKind, K as ModelComponent, N as Name, O as Object3DRef, P as PhysicsComponent, Q as PhysicsState, R as PlaneMeshParameters, S as RadiusHeightMeshParameters, T as RadiusMeshParameters, U as RigidbodyState, V as RigidbodyType, W as ScriptComponent, X as ScriptEntry, Y as ScriptObjectComponent, Z as ScriptObjectComponentInput, _ as ScriptObjectRuntimeState, $ as Selectable, a0 as SelectionTransformState, a1 as SpriteComponent, a2 as TextureFilteringValue, a3 as TransformModeValue, a4 as TransformSpaceValue, a5 as VRTeleportAreaComponent, a6 as VRTeleportAreaOptions, a7 as VideoComponent, a8 as VrTeleportShape, a9 as XRHandPoseComponent, aa as XRHandPoseOptions, ab as XRInteractableComponent, ac as XRInteractableOptions, ad as XRInteractorComponent, ae as XRInteractorOptions, af as XRInteractorSideComponent, ag as XRRigComponent, ah as XRRigOptions, ai as XrAttachPoint, aj as XrDistanceGrabBehavior, ak as XrGrabGesture, al as XrGrabHands, am as XrGrabReach, an as XrHandPoseEntry, ao as XrHandPreset, ap as XrInteractorSide, aq as XrInteractorType, ar as XrLocomotionMode, as as XrTrackingOrigin, at as XrTwoHandRotation, au as createAttachPoint, av as createHandPoseEntry, aw as defaultMaterialValue, ax as handPoseDefinitionFor, ay as normalizePhysicsState, az as setPhysicsLiveRef } from '../XRHandPose-CLl4MiHx.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-BhnLw0fZ.cjs';
|
|
3
|
-
export { P as PrefabInstance, a as PrefabNode } from '../index-
|
|
3
|
+
export { P as PrefabInstance, a as PrefabNode } from '../index-g777AmFv.cjs';
|
|
4
4
|
import 'three';
|
|
5
5
|
import '@dimforge/rapier3d-compat';
|
|
6
|
-
import '../handPose-
|
|
6
|
+
import '../handPose-DlcTtqgx.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,
|
|
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_POSE_DIRECTIONS, o as DEFAULT_RIGIDBODY_STATE, E as EditableMeshObjectKind, p as EntityType, I as ImageComponent, q as ImageTarget, r as ImageTargetAnchor, s as ImageTargetAnchorOptions, t as ImageTargetReference, u as InstanceSlotComponent, v as InstanceTransform, w as InstancedMeshComponent, x as InstancedMeshKind, L as LightComponent, y as LightValueState, M as MaterialComponent, z as MaterialTypeValue, B as MaterialValueState, F as MeshComponent, G as MeshGeometryComponent, H as MeshGeometryParameters, J as MeshGeometryParametersByKind, K as ModelComponent, N as Name, O as Object3DRef, P as PhysicsComponent, Q as PhysicsState, R as PlaneMeshParameters, S as RadiusHeightMeshParameters, T as RadiusMeshParameters, U as RigidbodyState, V as RigidbodyType, W as ScriptComponent, X as ScriptEntry, Y as ScriptObjectComponent, Z as ScriptObjectComponentInput, _ as ScriptObjectRuntimeState, $ as Selectable, a0 as SelectionTransformState, a1 as SpriteComponent, a2 as TextureFilteringValue, a3 as TransformModeValue, a4 as TransformSpaceValue, a5 as VRTeleportAreaComponent, a6 as VRTeleportAreaOptions, a7 as VideoComponent, a8 as VrTeleportShape, a9 as XRHandPoseComponent, aa as XRHandPoseOptions, ab as XRInteractableComponent, ac as XRInteractableOptions, ad as XRInteractorComponent, ae as XRInteractorOptions, af as XRInteractorSideComponent, ag as XRRigComponent, ah as XRRigOptions, ai as XrAttachPoint, aj as XrDistanceGrabBehavior, ak as XrGrabGesture, al as XrGrabHands, am as XrGrabReach, an as XrHandPoseEntry, ao as XrHandPreset, ap as XrInteractorSide, aq as XrInteractorType, ar as XrLocomotionMode, as as XrTrackingOrigin, at as XrTwoHandRotation, au as createAttachPoint, av as createHandPoseEntry, aw as defaultMaterialValue, ax as handPoseDefinitionFor, ay as normalizePhysicsState, az as setPhysicsLiveRef } from '../XRHandPose-CrzI57JA.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-BhnLw0fZ.js';
|
|
3
|
-
export { P as PrefabInstance, a as PrefabNode } from '../index-
|
|
3
|
+
export { P as PrefabInstance, a as PrefabNode } from '../index-JRcoel9F.js';
|
|
4
4
|
import 'three';
|
|
5
5
|
import '@dimforge/rapier3d-compat';
|
|
6
|
-
import '../handPose-
|
|
6
|
+
import '../handPose-DlcTtqgx.js';
|
package/dist/components/index.js
CHANGED
|
@@ -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, createAttachPoint, createHandPoseEntry, defaultMaterialValue, handPoseDefinitionFor, normalizePhysicsState, setPhysicsLiveRef } from '../chunk-
|
|
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_POSE_DIRECTIONS, 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-H6DQ7JRE.js';
|
|
2
2
|
import '../chunk-OY7ZODZP.js';
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
|
@@ -125,6 +125,66 @@ Vision Pro drives WebXR entirely through **gaze and pinch**. There are no contro
|
|
|
125
125
|
- Hand tracking (and therefore hand poses) is available on visionOS 2 and later, but asks the user for a second permission. The OS draws the user's real hands.
|
|
126
126
|
- `immersive-ar` is not supported by Safari on visionOS, so VR projects are the only kind that run there.
|
|
127
127
|
|
|
128
|
+
### Scripting VR interactions
|
|
129
|
+
|
|
130
|
+
A few patterns that cover most scenes.
|
|
131
|
+
|
|
132
|
+
**Score when a thrown object passes through something.** Give the ball a dynamic rigidbody and an XR Interactable; the throw itself is handled for you.
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
import { Behaviour, type XrInputState } from "@relu-interactives/spatial-ecs";
|
|
136
|
+
|
|
137
|
+
export default class Ball extends Behaviour {
|
|
138
|
+
onRelease(input: XrInputState) {
|
|
139
|
+
// Fires the moment it leaves the hand — the engine has already applied the
|
|
140
|
+
// velocity, so this is where scoring or audio goes.
|
|
141
|
+
console.log("released by", input.handedness);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**A panel you point at but cannot pick up.** Set `pointable: true` and `grabbable: false`, then act on the pointer.
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
export default class Button extends Behaviour {
|
|
150
|
+
onSelectStart() {
|
|
151
|
+
this.world.emit?.("door:open");
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**React to a two-handed hold.** Useful for steadying a weapon, showing a bipod, or gating an action on both hands being committed.
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
export default class Rifle extends Behaviour {
|
|
160
|
+
private braced = false;
|
|
161
|
+
|
|
162
|
+
onSecondaryGrab() {
|
|
163
|
+
this.braced = true;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
onSecondaryRelease() {
|
|
167
|
+
this.braced = false;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
onUpdate() {
|
|
171
|
+
if (this.braced) { /* tighter aim, less sway… */ }
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Adapt to the device.** Branch on what the session granted, never on a device name.
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
onXRSessionStart(capabilities: XrCapabilities) {
|
|
180
|
+
if (!capabilities.handTracking) {
|
|
181
|
+
// Controllers only — hide anything that depends on finger poses.
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Two rules worth internalising: **move the rig, never the camera** (the headset owns the camera while presenting and overwrites it every frame), and give any destructive gesture a longer **Hold Time** so it cannot fire in passing.
|
|
187
|
+
|
|
128
188
|
## Hand poses
|
|
129
189
|
|
|
130
190
|
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.
|
|
@@ -154,6 +214,46 @@ export default class Portal extends Behaviour {
|
|
|
154
214
|
|
|
155
215
|
`XrHandPoseEventDetail` is `{ poseId, poseName, handedness, confidence }`. Match on `poseId` — it is the id set in the inspector, not the preset name.
|
|
156
216
|
|
|
217
|
+
**Changing another object's colour from a pose.** `MaterialComponent.updateValue` takes an index and a PATCH OBJECT — `updateValue(0, { color })`, not `updateValue(0, "color", value)`.
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
import {
|
|
221
|
+
Behaviour,
|
|
222
|
+
MaterialComponent,
|
|
223
|
+
type EntityInput,
|
|
224
|
+
type WorldEntityView,
|
|
225
|
+
type XrHandPoseEventDetail,
|
|
226
|
+
} from "@relu-interactives/spatial-ecs";
|
|
227
|
+
|
|
228
|
+
export default class PoseColor extends Behaviour {
|
|
229
|
+
data = { target: { type: "entity", value: null } as unknown as EntityInput };
|
|
230
|
+
private original = "#ffffff";
|
|
231
|
+
|
|
232
|
+
init() {
|
|
233
|
+
const material = this.material();
|
|
234
|
+
const current = material?.values?.[0]?.color;
|
|
235
|
+
if (typeof current === "string") this.original = current;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
onHandPoseStart(event: XrHandPoseEventDetail) {
|
|
239
|
+
if (event.poseId === "approve") this.material()?.updateValue(0, { color: "#0066ff" });
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
onHandPoseEnd() {
|
|
243
|
+
this.material()?.updateValue(0, { color: this.original });
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
private material() {
|
|
247
|
+
const target = this.data.target.value as WorldEntityView | null;
|
|
248
|
+
return target
|
|
249
|
+
? this.world.getComponent(target.entityId, MaterialComponent)
|
|
250
|
+
: null;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
**Hand poses require HAND TRACKING.** They are read from the 25 tracked finger joints, so nothing fires while the user is holding controllers — put them down and enable hand tracking on the headset. If a scene has poses configured and no tracked hand is seen for a few seconds, the runtime says so in the console.
|
|
256
|
+
|
|
157
257
|
### Presets
|
|
158
258
|
|
|
159
259
|
`fist`, `open-palm`, `point`, `thumbs-up`, `thumbs-down`, `peace`, `pinch`, `ok`, `gun`, `rock`, `shaka`, `palm-up`.
|
|
@@ -164,6 +264,14 @@ A custom pose is five curl values, `0` (finger straight) to `1` (fully closed),
|
|
|
164
264
|
|
|
165
265
|
Optionally add a **direction** requirement: which way the palm, fingers, or thumb must point (`up`, `down`, `forward`, `back`, `left`, `right`, `toward-head`, `away-from-head`) within an angle tolerance. This is what separates thumbs-up from thumbs-down, which are the same hand shape.
|
|
166
266
|
|
|
267
|
+
### Per-finger direction
|
|
268
|
+
|
|
269
|
+
Curl says how *bent* a finger is; direction says where it *points*. "Index extended, pointing up" and "index extended, pointing at the user" are different gestures with identical curls, so direction is what tells them apart.
|
|
270
|
+
|
|
271
|
+
In the editor, click a finger on the hand and pick the directions it may point: `Up`, `Down`, `Forward`, `Back`, `Left`, `Right`, `At user`, `Away`. Picking **several means any one of them counts** — that is how "thumb up or diagonally up" stays a single pose. Pick none to leave the finger free.
|
|
272
|
+
|
|
273
|
+
**Angle Tolerance** is how far a finger may point from an accepted direction. 45° by default: direction is a coarse signal, and a tight cone makes a pose that looks right to the user fail to register.
|
|
274
|
+
|
|
167
275
|
### Tuning
|
|
168
276
|
|
|
169
277
|
- **Tolerance** — raise it if a pose is hard to trigger, lower it if it fires by accident.
|
|
@@ -171,6 +279,65 @@ Optionally add a **direction** requirement: which way the palm, fingers, or thum
|
|
|
171
279
|
|
|
172
280
|
A pose does not re-fire while held, and survives a brief hand-tracking dropout rather than flickering.
|
|
173
281
|
|
|
282
|
+
### Driving game logic
|
|
283
|
+
|
|
284
|
+
The hooks fire on the entity that declares the pose, so put the component on the object that should react. A few patterns worth knowing:
|
|
285
|
+
|
|
286
|
+
**Fire once per gesture.** `onHandPoseStart` fires when the pose begins, not every frame, so it is safe to spawn or play something directly.
|
|
287
|
+
|
|
288
|
+
```ts
|
|
289
|
+
import { Behaviour, type XrHandPoseEventDetail } from "@relu-interactives/spatial-ecs";
|
|
290
|
+
|
|
291
|
+
export default class Spellcaster extends Behaviour {
|
|
292
|
+
onHandPoseStart(event: XrHandPoseEventDetail) {
|
|
293
|
+
if (event.poseId !== "cast") return;
|
|
294
|
+
this.spawnPrefab("assets/fireball.prefab", {
|
|
295
|
+
position: this.transform.position,
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
**Hold a state while the pose lasts.** Use both hooks when the pose should gate something continuous.
|
|
302
|
+
|
|
303
|
+
```ts
|
|
304
|
+
export default class Shield extends Behaviour {
|
|
305
|
+
private raised = false;
|
|
306
|
+
|
|
307
|
+
onHandPoseStart(event: XrHandPoseEventDetail) {
|
|
308
|
+
if (event.poseId === "open-palm") this.raised = true;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
onHandPoseEnd(event: XrHandPoseEventDetail) {
|
|
312
|
+
if (event.poseId === "open-palm") this.raised = false;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
onUpdate() {
|
|
316
|
+
if (this.raised) { /* absorb damage, drift the shield toward the hand… */ }
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
**React per hand.** `event.handedness` is `"left"` or `"right"`, so one pose can drive two behaviours.
|
|
322
|
+
|
|
323
|
+
```ts
|
|
324
|
+
onHandPoseStart(event: XrHandPoseEventDetail) {
|
|
325
|
+
if (event.poseId !== "point") return;
|
|
326
|
+
if (event.handedness === "right") this.aim();
|
|
327
|
+
else this.selectMenu();
|
|
328
|
+
}
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
**Require a confident match.** `event.confidence` is 0–1 at the moment the pose fired. Gate on it when a gesture is destructive.
|
|
332
|
+
|
|
333
|
+
```ts
|
|
334
|
+
onHandPoseStart(event: XrHandPoseEventDetail) {
|
|
335
|
+
if (event.poseId === "delete-all" && event.confidence > 0.95) this.clearScene();
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
Two things to design around: **match on `poseId`, not the pose name** — the id is the contract, the name is a label — and give a destructive gesture a longer **Hold Time** so it cannot fire in passing.
|
|
340
|
+
|
|
174
341
|
## Locomotion
|
|
175
342
|
|
|
176
343
|
Movement is a property of the **XR Rig**, not of scripts: tracking origin (floor or eye level), locomotion mode, move speed, snap turn, and — when locomotion is teleport — the arc's **Color**, **Blocked Color** and **Thickness**. The arc starts a short way out from the head so it never draws through the user's own view, which matters on Vision Pro where the aim ray originates between the eyes. Teleport destinations are **Teleport Area** entities. Scripts should move the rig, never the camera — while a session is presenting, the headset owns the camera and writes its pose every frame.
|
package/dist/factories/index.cjs
CHANGED
|
@@ -2304,6 +2304,14 @@ function createHandPoseEntry(partial) {
|
|
|
2304
2304
|
preset: partial.preset ?? null,
|
|
2305
2305
|
curls: { ...DEFAULT_POSE_CURLS, ...partial.curls },
|
|
2306
2306
|
tolerance: partial.tolerance ?? 0.25,
|
|
2307
|
+
directions: {
|
|
2308
|
+
thumb: [...partial.directions?.thumb ?? []],
|
|
2309
|
+
index: [...partial.directions?.index ?? []],
|
|
2310
|
+
middle: [...partial.directions?.middle ?? []],
|
|
2311
|
+
ring: [...partial.directions?.ring ?? []],
|
|
2312
|
+
pinky: [...partial.directions?.pinky ?? []]
|
|
2313
|
+
},
|
|
2314
|
+
directionTolerance: partial.directionTolerance ?? 45,
|
|
2307
2315
|
hand: partial.hand ?? null,
|
|
2308
2316
|
orientation: partial.orientation ?? null,
|
|
2309
2317
|
minHoldSeconds: partial.minHoldSeconds ?? 0.15,
|