@realitycollective/webxr-interactions 0.1.0-preview.2 → 0.1.0-preview.3
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/CHANGELOG.md +14 -3
- package/dist/math.d.ts +1 -15
- package/dist/math.js +4 -25
- package/dist/math.js.map +1 -1
- package/dist/pointer-bridge.js +1 -1
- package/dist/pointer-bridge.js.map +1 -1
- package/dist/runtime.d.ts +12 -7
- package/dist/runtime.js +11 -6
- package/dist/runtime.js.map +1 -1
- package/dist/velocity-tracker.d.ts +2 -13
- package/dist/velocity-tracker.js +20 -6
- package/dist/velocity-tracker.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -13,20 +13,31 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
|
|
|
13
13
|
- `@realitycollective/iwsdk-interactions` - Meta IWSDK adapter: player-rig poses and stateful gamepads as the provider, IWSDK's own targeting (`Pressed` / `Grabbed` tags) forwarded as pre-resolved hints, and native grab fulfilment when the app enables IWSDK grabbing/physics. One-call `registerInteractions(world)` setup.
|
|
14
14
|
- `@realitycollective/xrblocks-interactions` - EXPERIMENTAL Google XR Blocks adapter, structurally typed against xrblocks v0.20.0 (`Input.getFrame()` ray sources and direct touches, pooled structs copied, no haptics upstream).
|
|
15
15
|
- `demos/playground` - the standalone interaction playground: the full station set from one portable `InteractionDescriptor`, with client-side audio cues, opt-in controller haptics and client-side toss ballistics.
|
|
16
|
-
- `@realitycollective/webxr-interactions` - per-source velocity. `VelocityTracker` differentiates the grip poses the runtime already samples into linear and angular velocity, and the runtime runs one by default (`velocity: false` turns it off, `{ smoothing }` averages it). A source on its first frame, or one that reappears after dropping out, reports no velocity rather than a jump from its last known pose, and a provider that supplies its own velocity keeps it. Read it from `runtime.onSample(...)` or `runtime.getSource(id)`. `
|
|
16
|
+
- `@realitycollective/webxr-interactions` - per-source velocity. `VelocityTracker` differentiates the grip poses the runtime already samples into linear and angular velocity, and the runtime runs one by default (`velocity: false` turns it off, `{ smoothing }` averages it). A source on its first frame, or one that reappears after dropping out, reports no velocity rather than a jump from its last known pose, and a provider that supplies its own velocity keeps it. Read it from `runtime.onSample(...)` or `runtime.getSource(id)`. The differentiation itself is `velocityBetween` from `@realitycollective/webxr-input`, re-exported here; `clampDeadzone` joins the math helpers.
|
|
17
17
|
- `@realitycollective/webxr-interactions` - `routeAudioToSink`, the audio counterpart to `routeHapticsToProvider`: an opt-in that plays the cues named in a map through a client-supplied sink. Cues absent from the map are ignored, so an app sonifies only the moments it has sounds for.
|
|
18
|
-
- `@realitycollective/iwsdk-interactions` and `@realitycollective/threejs-interactions` - presence control. `setPresenceVisible(target, visible)` shows and hides the hand and controller visuals per side; the IWSDK adapter adds `setPresenceModality(mode)` to force hands or controllers over the automatic choice, and the three.js adapter takes the app's own models through `registerVisual(handedness, root)`.
|
|
18
|
+
- `@realitycollective/iwsdk-interactions` and `@realitycollective/threejs-interactions` - presence control. `setPresenceVisible(target, visible)` shows and hides the hand and controller visuals per side; the IWSDK adapter adds `setPresenceModality(mode)` to force hands or controllers over the automatic choice, and the three.js adapter takes the app's own models through `registerVisual(handedness, root)`. Every provider reports whether it can do this through `capabilities.presence`; the XR Blocks adapter reports false, since XR Blocks exposes no way to hide its visuals.
|
|
19
19
|
- `@realitycollective/threejs-interactions` - native WebXR pose velocity. Where the browser reports `linearVelocity` or `angularVelocity` with a grip pose (or with the wrist joint a hand falls back to), the provider passes it through on the snapshot and the core's tracker leaves it alone; where it does not, the tracker derives velocity from consecutive poses as before. The desktop mouse source synthesises nothing: its grip rides the camera ray, so the derived velocity is camera motion, and hand mechanics should be gated on `handedness !== "none"`.
|
|
20
20
|
- `@realitycollective/babylon-interactions` - a Babylon.js adapter, the fourth engine. It reads a `WebXRDefaultExperience` (controllers, motion controller trigger and squeeze, hand-tracking joints, session manager) for input, with `scene.onPointerObservable` as the desktop fallback, haptics through the motion controller's `pulse`, and presence over the visuals Babylon builds - motion controller root meshes and hand meshes. Babylon picks the visual per input source, so there is no modality switch. Hit-testing is a sphere test over registered nodes, with an optional `pickWithRay` hook for mesh-accurate targeting; the transform port moves, rotates and scales Babylon nodes from rest. Structurally typed against the Babylon API rather than importing `@babylonjs/core`, as the XR Blocks adapter is, so an upstream release cannot break the install - and so the whole adapter is covered headlessly by structural fakes. Written against the documented Babylon 7 API and not yet exercised against a real Babylon runtime.
|
|
21
|
-
- Tests for `@realitycollective/iwsdk-interactions`, which had none. `@iwsdk/core` imports headlessly in node, so the provider is covered against a structural fake world with no module mocking, and a parity suite instantiates all
|
|
21
|
+
- Tests for `@realitycollective/iwsdk-interactions`, which had none. `@iwsdk/core` imports headlessly in node, so the provider is covered against a structural fake world with no module mocking, and a parity suite instantiates all four providers and runs the shared contract suite against each one. The package's coverage ratchet moves off zero, and the other three ratchets rise to the floor they now measure.
|
|
22
22
|
|
|
23
23
|
### Changed
|
|
24
24
|
|
|
25
|
+
- Every provider reports presence through `capabilities.presence`, the required key `@realitycollective/webxr-input` 0.1.1 adds to `InputCapabilities`. The class-level `supportsPresence` field the four adapters carried while that key was unpublished is gone. This fixes a client-visible defect on the IWSDK adapter, which built its capabilities without a `presence` key at all: an app that read `capabilities.presence` saw false and hid a feature that worked. The value each provider reports is the one its own field computed - always true on IWSDK, true once Babylon has built a visual to hide, true on three.js once a model is registered, and always false on XR Blocks.
|
|
26
|
+
- `@realitycollective/threejs-interactions` - `registerVisual` and the new `unregisterVisual` now re-derive capabilities and notify `onCapabilitiesChanged`. Presence on this adapter is genuinely conditional: your app builds its own hand and controller models, so `capabilities.presence` is false until you hand the first one over and false again once you take the last one back.
|
|
27
|
+
- The Input 0.1.1 types replace the local stand-ins that were waiting on them. `InputSourceSnapshot` now carries `linearVelocity` and `angularVelocity` itself, so the `InputSourceSnapshotWithVelocity` alias is gone; the local `poseVelocity` is gone in favour of the shipped `velocityBetween`; and the per-adapter `PresenceTarget` and `PresenceModality` declarations are gone. `PresenceModality` now comes from the contracts, and a presence target is written as the contract writes it, `Handedness | "all"`. All three names were re-exported from these packages and are removed from that surface.
|
|
28
|
+
- Every package now requires `@realitycollective/webxr-input` at `^0.1.1` rather than `^0.1.0`, because the code above uses members that only exist from 0.1.1. A fresh install resolved to 0.1.1 either way; the range says so now, so a consumer holding an older lockfile fails at install rather than at run time.
|
|
29
|
+
- The provider parity suite is now three lines over `inputProviderContractCases()` from `@realitycollective/webxr-input`, run against all four adapters, instead of a hand-written copy of the same checks. The shared cases are stricter: they assert the capability record has exactly the contract's keys and that every snapshot is well formed. Two adapter-specific checks stay on top of them.
|
|
30
|
+
- `@realitycollective/iwsdk-interactions` - `setPresenceVisible` and `setPresenceModality` write nothing when nothing changed. The provider holds what it last applied per side - visibility, modality and the hand-tracking capability presence is derived from - and skips a side whose three inputs are unchanged. An app pushing presence from a state subscription, which is the documented pattern, no longer walks every descendant of both visual families on every unrelated state change. The per-frame re-apply during `sample()` stays unconditional, because IWSDK re-asserts its own visuals from its update loop and a capability refresh can change the modality underneath the adapter.
|
|
31
|
+
|
|
25
32
|
- `@realitycollective/iwsdk-interactions` - `pulse` resolves the side from the handedness recorded while sampling, rather than parsing the source id. Parsing the id remains the fallback for an id the provider did not produce.
|
|
26
33
|
|
|
27
34
|
- `@realitycollective/iwsdk-interactions` targets **IWSDK 0.5.x**. Its peer range is now `>=0.5.0 <0.6.0` and it is developed and tested against `@iwsdk/core` 0.5.3. The adapter is source-compatible with 0.4.x and needed no code change, but 0.5 is the only line exercised, so it is the only line supported. Every symbol and runtime member the provider uses is present in both, and it already reads `world.input.xr.gamepads` rather than the accessor 0.5 deprecates.
|
|
28
35
|
- `demos/playground` no longer compiles UIKitML at build time. `@iwsdk/vite-plugin-uikitml` was discontinued at 0.4.2 and only ever did `JSON.stringify(parse(source))`, so the panel is served as `.uikitml` from `public/ui/` and parsed on load. The demo drops that plugin, and its station markup uses `rgba()` rather than `background-opacity`, which the 0.5 parser removed.
|
|
29
36
|
|
|
37
|
+
### Deprecated
|
|
38
|
+
|
|
39
|
+
- `@realitycollective/webxr-interactions` - `InteractionRuntime.onSourcesSampled` is deprecated in favour of `onSample`. They are the same stream, and since `InputSourceSnapshot` carries the velocity fields itself the two signatures are now identical, so only one name is needed. Nothing is removed: existing callers keep working and the method will go in a later major release.
|
|
40
|
+
|
|
30
41
|
### Notes
|
|
31
42
|
|
|
32
43
|
- All five packages depend on `@realitycollective/webxr-input`, released independently from the [WebXR-Input](https://github.com/realitycollective/WebXR-Input) repository. That package must be published before this one.
|
package/dist/math.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* plus the tuple vector/quaternion helpers the binder and behaviours need.
|
|
5
5
|
* No engine imports; everything is unit-tested headless.
|
|
6
6
|
*/
|
|
7
|
-
import type {
|
|
7
|
+
import type { QuatTuple, RayTuple, Vec3Tuple } from "@realitycollective/webxr-input";
|
|
8
8
|
/** Clamp to the unit interval. */
|
|
9
9
|
export declare function clamp01(t: number): number;
|
|
10
10
|
/**
|
|
@@ -66,19 +66,5 @@ export declare function rayPointDistance(ray: RayTuple, point: Vec3Tuple): {
|
|
|
66
66
|
};
|
|
67
67
|
/** Angular offset (radians) between a ray direction and the direction to a point. */
|
|
68
68
|
export declare function rayAngleTo(ray: RayTuple, point: Vec3Tuple): number;
|
|
69
|
-
/**
|
|
70
|
-
* Linear and angular velocity between two poses, in metres per second and
|
|
71
|
-
* radians per second. Linear is the position delta over `dtSeconds`;
|
|
72
|
-
* angular comes from the delta quaternion `next * conj(prev)`, taken along
|
|
73
|
-
* the shortest arc, as `axis * angle / dtSeconds`. Returns zeros when
|
|
74
|
-
* `dtSeconds` is zero, negative or not finite.
|
|
75
|
-
*
|
|
76
|
-
* Mirrors velocityBetween in @realitycollective/webxr-input 0.1.1; switch
|
|
77
|
-
* to the import once that ships.
|
|
78
|
-
*/
|
|
79
|
-
export declare function poseVelocity(prev: PoseTuple, next: PoseTuple, dtSeconds: number): {
|
|
80
|
-
linear: Vec3Tuple;
|
|
81
|
-
angular: Vec3Tuple;
|
|
82
|
-
};
|
|
83
69
|
/** Zero out a signal below `threshold`, leaving larger values untouched. */
|
|
84
70
|
export declare function clampDeadzone(value: number, threshold: number): number;
|
package/dist/math.js
CHANGED
|
@@ -161,32 +161,11 @@ export function rayAngleTo(ray, point) {
|
|
|
161
161
|
const d = vDot(vNormalize(ray.direction), dir);
|
|
162
162
|
return Math.acos(Math.min(1, Math.max(-1, d)));
|
|
163
163
|
}
|
|
164
|
-
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
* the shortest arc, as `axis * angle / dtSeconds`. Returns zeros when
|
|
169
|
-
* `dtSeconds` is zero, negative or not finite.
|
|
170
|
-
*
|
|
171
|
-
* Mirrors velocityBetween in @realitycollective/webxr-input 0.1.1; switch
|
|
172
|
-
* to the import once that ships.
|
|
164
|
+
/*
|
|
165
|
+
* Velocity between two poses lives in `@realitycollective/webxr-input` as
|
|
166
|
+
* `velocityBetween`, re-exported from this package's index. The local copy
|
|
167
|
+
* that stood in for it before Input 0.1.1 is gone.
|
|
173
168
|
*/
|
|
174
|
-
export function poseVelocity(prev, next, dtSeconds) {
|
|
175
|
-
if (!Number.isFinite(dtSeconds) || dtSeconds <= 0) {
|
|
176
|
-
return { linear: [0, 0, 0], angular: [0, 0, 0] };
|
|
177
|
-
}
|
|
178
|
-
const linear = vScale(vSub(next.position, prev.position), 1 / dtSeconds);
|
|
179
|
-
let delta = quatMultiply(next.quaternion, quatConjugate(prev.quaternion));
|
|
180
|
-
// Shortest arc: q and -q are the same rotation, so flip to the hemisphere
|
|
181
|
-
// where the angle is under half a turn.
|
|
182
|
-
if (delta[3] < 0)
|
|
183
|
-
delta = [-delta[0], -delta[1], -delta[2], -delta[3]];
|
|
184
|
-
const w = delta[3] < -1 ? -1 : delta[3] > 1 ? 1 : delta[3];
|
|
185
|
-
const angle = 2 * Math.acos(w);
|
|
186
|
-
// vNormalize guards the near-zero axis (no rotation this frame).
|
|
187
|
-
const axis = vNormalize([delta[0], delta[1], delta[2]]);
|
|
188
|
-
return { linear, angular: vScale(axis, angle / dtSeconds) };
|
|
189
|
-
}
|
|
190
169
|
/** Zero out a signal below `threshold`, leaving larger values untouched. */
|
|
191
170
|
export function clampDeadzone(value, threshold) {
|
|
192
171
|
return Math.abs(value) < threshold ? 0 : value;
|
package/dist/math.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"math.js","sourceRoot":"","sources":["../src/math.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure interaction math - the proven motion functions extracted from the\n * Pale Signal research (springs, hinge/dial normalisation, hoop scoring),\n * plus the tuple vector/quaternion helpers the binder and behaviours need.\n * No engine imports; everything is unit-tested headless.\n */\nimport type { PoseTuple, QuatTuple, RayTuple, Vec3Tuple } from \"@realitycollective/webxr-input\";\n\n/** Clamp to the unit interval. */\nexport function clamp01(t: number): number {\n return t < 0 ? 0 : t > 1 ? 1 : t;\n}\n\n/**\n * Normalize a measured displacement/angle against a signed range to 0..1.\n * Sign-agnostic: a range of `-π/2` maps `-π/2 → 1`.\n */\nexport function normalize01(value: number, range: number): number {\n if (range === 0) return 0;\n return clamp01(value / range);\n}\n\n/**\n * Did a tossed object pass *through* a hoop this frame? True when it crossed\n * the hoop plane in the scoring direction (downward - `prev` above, `curr`\n * at/below) while inside the ring (`radial <= radius`).\n */\nexport function passedThroughHoop(\n prevAlong: number,\n currAlong: number,\n planeAlong: number,\n radial: number,\n radius: number,\n): boolean {\n const crossedDown = prevAlong > planeAlong && currAlong <= planeAlong;\n return crossedDown && radial <= radius;\n}\n\n/**\n * One step of a damped harmonic oscillator (semi-implicit Euler).\n * `out[0]` = next value, `out[1]` = next velocity. An under-damped spring\n * (damping ratio ≈ 0.3-0.5) is what gives a pressed button its bounce.\n * `dt` is clamped to 1/30 s so a long frame can't blow the integrator up.\n */\nexport function springStep(\n value: number,\n velocity: number,\n target: number,\n stiffness: number,\n damping: number,\n dt: number,\n out: Float32Array = new Float32Array(2),\n): Float32Array {\n const h = Math.min(dt, 1 / 30);\n const accel = -stiffness * (value - target) - damping * velocity;\n const nextVelocity = velocity + accel * h;\n out[0] = value + nextVelocity * h;\n out[1] = nextVelocity;\n return out;\n}\n\n/** Exponential decay of `value` toward 0 over `dt` at `ratePerSec`. */\nexport function decay(value: number, ratePerSec: number, dt: number): number {\n const next = value * Math.exp(-ratePerSec * Math.max(dt, 0));\n return next < 1e-4 ? 0 : next;\n}\n\n/** Penner's ease-out-bounce on `t ∈ [0,1]`. */\nexport function easeOutBounce(t: number): number {\n const n1 = 7.5625;\n const d1 = 2.75;\n let x = clamp01(t);\n if (x < 1 / d1) return n1 * x * x;\n if (x < 2 / d1) return n1 * (x -= 1.5 / d1) * x + 0.75;\n if (x < 2.5 / d1) return n1 * (x -= 2.25 / d1) * x + 0.9375;\n return n1 * (x -= 2.625 / d1) * x + 0.984375;\n}\n\n/** Clamp a value to the symmetric range `[-|mag|, +|mag|]`. */\nexport function clampSym(x: number, mag: number): number {\n const m = Math.abs(mag);\n return x < -m ? -m : x > m ? m : x;\n}\n\n/**\n * Hinge angle for a position-driven lever: given the hand's offset from the\n * pivot resolved into the hinge plane - `alongRest` (toward the arm's rest\n * direction) and `alongSwing` (the in-plane perpendicular) - the angle the\n * arm should take to point at the hand, clamped to `±|maxMag|`.\n */\nexport function hingeAngleToHand(alongRest: number, alongSwing: number, maxMag: number): number {\n return clampSym(Math.atan2(alongSwing, alongRest), maxMag);\n}\n\n/**\n * Map a centered hinge angle in `[-|mag|, +|mag|]` to a 0..1 analog value\n * with the rest (0) at 0.5 - a bidirectional lever as one normalized value.\n */\nexport function centeredUnit(angle: number, mag: number): number {\n const m = Math.abs(mag);\n if (m < 1e-6) return 0.5;\n return clamp01(0.5 + (0.5 * angle) / m);\n}\n\n// ---------------------------------------------------------------------------\n// Tuple vector / quaternion helpers (allocation-light, no engine types).\n// ---------------------------------------------------------------------------\n\nexport function vSub(a: Vec3Tuple, b: Vec3Tuple): Vec3Tuple {\n return [a[0] - b[0], a[1] - b[1], a[2] - b[2]];\n}\n\nexport function vAdd(a: Vec3Tuple, b: Vec3Tuple): Vec3Tuple {\n return [a[0] + b[0], a[1] + b[1], a[2] + b[2]];\n}\n\nexport function vScale(a: Vec3Tuple, s: number): Vec3Tuple {\n return [a[0] * s, a[1] * s, a[2] * s];\n}\n\nexport function vDot(a: Vec3Tuple, b: Vec3Tuple): number {\n return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];\n}\n\nexport function vCross(a: Vec3Tuple, b: Vec3Tuple): Vec3Tuple {\n return [\n a[1] * b[2] - a[2] * b[1],\n a[2] * b[0] - a[0] * b[2],\n a[0] * b[1] - a[1] * b[0],\n ];\n}\n\nexport function vLength(a: Vec3Tuple): number {\n return Math.hypot(a[0], a[1], a[2]);\n}\n\nexport function vDistance(a: Vec3Tuple, b: Vec3Tuple): number {\n return Math.hypot(a[0] - b[0], a[1] - b[1], a[2] - b[2]);\n}\n\nexport function vNormalize(a: Vec3Tuple): Vec3Tuple {\n const l = vLength(a);\n return l < 1e-9 ? [0, 0, 0] : [a[0] / l, a[1] / l, a[2] / l];\n}\n\n/** Quaternion from an axis (normalised) and an angle in radians. */\nexport function quatFromAxisAngle(axis: Vec3Tuple, angle: number): QuatTuple {\n const half = angle / 2;\n const s = Math.sin(half);\n return [axis[0] * s, axis[1] * s, axis[2] * s, Math.cos(half)];\n}\n\nexport function quatMultiply(a: QuatTuple, b: QuatTuple): QuatTuple {\n const [ax, ay, az, aw] = a;\n const [bx, by, bz, bw] = b;\n return [\n aw * bx + ax * bw + ay * bz - az * by,\n aw * by - ax * bz + ay * bw + az * bx,\n aw * bz + ax * by - ay * bx + az * bw,\n aw * bw - ax * bx - ay * by - az * bz,\n ];\n}\n\nexport function quatConjugate(q: QuatTuple): QuatTuple {\n return [-q[0], -q[1], -q[2], q[3]];\n}\n\n/** Rotate a vector by a quaternion. */\nexport function vApplyQuat(v: Vec3Tuple, q: QuatTuple): Vec3Tuple {\n const [x, y, z] = v;\n const [qx, qy, qz, qw] = q;\n // t = 2 * cross(q.xyz, v)\n const tx = 2 * (qy * z - qz * y);\n const ty = 2 * (qz * x - qx * z);\n const tz = 2 * (qx * y - qy * x);\n // v + qw * t + cross(q.xyz, t)\n return [\n x + qw * tx + qy * tz - qz * ty,\n y + qw * ty + qz * tx - qx * tz,\n z + qw * tz + qx * ty - qy * tx,\n ];\n}\n\n/** Transform a world-space point into the local frame of `pose`. */\nexport function worldToLocal(\n point: Vec3Tuple,\n posePosition: Vec3Tuple,\n poseQuaternion: QuatTuple,\n): Vec3Tuple {\n return vApplyQuat(vSub(point, posePosition), quatConjugate(poseQuaternion));\n}\n\n/** Closest-approach distance from a ray to a point, and the along-ray t. */\nexport function rayPointDistance(ray: RayTuple, point: Vec3Tuple): { distance: number; t: number } {\n const toPoint = vSub(point, ray.origin);\n const t = vDot(toPoint, ray.direction);\n if (t <= 0) return { distance: vLength(toPoint), t: 0 };\n const closest = vAdd(ray.origin, vScale(ray.direction, t));\n return { distance: vDistance(closest, point), t };\n}\n\n/** Angular offset (radians) between a ray direction and the direction to a point. */\nexport function rayAngleTo(ray: RayTuple, point: Vec3Tuple): number {\n const dir = vNormalize(vSub(point, ray.origin));\n const d = vDot(vNormalize(ray.direction), dir);\n return Math.acos(Math.min(1, Math.max(-1, d)));\n}\n\n/**\n * Linear and angular velocity between two poses, in metres per second and\n * radians per second. Linear is the position delta over `dtSeconds`;\n * angular comes from the delta quaternion `next * conj(prev)`, taken along\n * the shortest arc, as `axis * angle / dtSeconds`. Returns zeros when\n * `dtSeconds` is zero, negative or not finite.\n *\n * Mirrors velocityBetween in @realitycollective/webxr-input 0.1.1; switch\n * to the import once that ships.\n */\nexport function poseVelocity(\n prev: PoseTuple,\n next: PoseTuple,\n dtSeconds: number,\n): { linear: Vec3Tuple; angular: Vec3Tuple } {\n if (!Number.isFinite(dtSeconds) || dtSeconds <= 0) {\n return { linear: [0, 0, 0], angular: [0, 0, 0] };\n }\n const linear = vScale(vSub(next.position, prev.position), 1 / dtSeconds);\n let delta = quatMultiply(next.quaternion, quatConjugate(prev.quaternion));\n // Shortest arc: q and -q are the same rotation, so flip to the hemisphere\n // where the angle is under half a turn.\n if (delta[3] < 0) delta = [-delta[0], -delta[1], -delta[2], -delta[3]];\n const w = delta[3] < -1 ? -1 : delta[3] > 1 ? 1 : delta[3];\n const angle = 2 * Math.acos(w);\n // vNormalize guards the near-zero axis (no rotation this frame).\n const axis = vNormalize([delta[0], delta[1], delta[2]]);\n return { linear, angular: vScale(axis, angle / dtSeconds) };\n}\n\n/** Zero out a signal below `threshold`, leaving larger values untouched. */\nexport function clampDeadzone(value: number, threshold: number): number {\n return Math.abs(value) < threshold ? 0 : value;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"math.js","sourceRoot":"","sources":["../src/math.ts"],"names":[],"mappings":"AAQA,kCAAkC;AAClC,MAAM,UAAU,OAAO,CAAC,CAAS;IAC/B,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,KAAa;IACtD,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAC1B,OAAO,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC;AAChC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAC/B,SAAiB,EACjB,SAAiB,EACjB,UAAkB,EAClB,MAAc,EACd,MAAc;IAEd,MAAM,WAAW,GAAG,SAAS,GAAG,UAAU,IAAI,SAAS,IAAI,UAAU,CAAC;IACtE,OAAO,WAAW,IAAI,MAAM,IAAI,MAAM,CAAC;AACzC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CACxB,KAAa,EACb,QAAgB,EAChB,MAAc,EACd,SAAiB,EACjB,OAAe,EACf,EAAU,EACV,MAAoB,IAAI,YAAY,CAAC,CAAC,CAAC;IAEvC,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;IAC/B,MAAM,KAAK,GAAG,CAAC,SAAS,GAAG,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,OAAO,GAAG,QAAQ,CAAC;IACjE,MAAM,YAAY,GAAG,QAAQ,GAAG,KAAK,GAAG,CAAC,CAAC;IAC1C,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,YAAY,GAAG,CAAC,CAAC;IAClC,GAAG,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC;IACtB,OAAO,GAAG,CAAC;AACb,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,KAAK,CAAC,KAAa,EAAE,UAAkB,EAAE,EAAU;IACjE,MAAM,IAAI,GAAG,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IAC7D,OAAO,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAChC,CAAC;AAED,+CAA+C;AAC/C,MAAM,UAAU,aAAa,CAAC,CAAS;IACrC,MAAM,EAAE,GAAG,MAAM,CAAC;IAClB,MAAM,EAAE,GAAG,IAAI,CAAC;IAChB,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACnB,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE;QAAE,OAAO,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE;QAAE,OAAO,EAAE,GAAG,CAAC,CAAC,IAAI,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;IACvD,IAAI,CAAC,GAAG,GAAG,GAAG,EAAE;QAAE,OAAO,EAAE,GAAG,CAAC,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC;IAC5D,OAAO,EAAE,GAAG,CAAC,CAAC,IAAI,KAAK,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC;AAC/C,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,QAAQ,CAAC,CAAS,EAAE,GAAW;IAC7C,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACxB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAiB,EAAE,UAAkB,EAAE,MAAc;IACpF,OAAO,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,SAAS,CAAC,EAAE,MAAM,CAAC,CAAC;AAC7D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa,EAAE,GAAW;IACrD,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACxB,IAAI,CAAC,GAAG,IAAI;QAAE,OAAO,GAAG,CAAC;IACzB,OAAO,OAAO,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1C,CAAC;AAED,8EAA8E;AAC9E,yEAAyE;AACzE,8EAA8E;AAE9E,MAAM,UAAU,IAAI,CAAC,CAAY,EAAE,CAAY;IAC7C,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,CAAY,EAAE,CAAY;IAC7C,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,CAAY,EAAE,CAAS;IAC5C,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,CAAY,EAAE,CAAY;IAC7C,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,CAAY,EAAE,CAAY;IAC/C,OAAO;QACL,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;KAC1B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,CAAY;IAClC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,CAAY,EAAE,CAAY;IAClD,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,CAAY;IACrC,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACrB,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,iBAAiB,CAAC,IAAe,EAAE,KAAa;IAC9D,MAAM,IAAI,GAAG,KAAK,GAAG,CAAC,CAAC;IACvB,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,CAAY,EAAE,CAAY;IACrD,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;IAC3B,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;IAC3B,OAAO;QACL,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;QACrC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;QACrC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;QACrC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;KACtC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,CAAY;IACxC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrC,CAAC;AAED,uCAAuC;AACvC,MAAM,UAAU,UAAU,CAAC,CAAY,EAAE,CAAY;IACnD,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;IACpB,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;IAC3B,0BAA0B;IAC1B,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;IACjC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;IACjC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;IACjC,+BAA+B;IAC/B,OAAO;QACL,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;QAC/B,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;QAC/B,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;KAChC,CAAC;AACJ,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,YAAY,CAC1B,KAAgB,EAChB,YAAuB,EACvB,cAAyB;IAEzB,OAAO,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,YAAY,CAAC,EAAE,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC;AAC9E,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,gBAAgB,CAAC,GAAa,EAAE,KAAgB;IAC9D,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;IACvC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IACxD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;IAC3D,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;AACpD,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,UAAU,CAAC,GAAa,EAAE,KAAgB;IACxD,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IAChD,MAAM,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,GAAG,CAAC,CAAC;IAC/C,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,CAAC;AAED;;;;GAIG;AAEH,4EAA4E;AAC5E,MAAM,UAAU,aAAa,CAAC,KAAa,EAAE,SAAiB;IAC5D,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AACjD,CAAC","sourcesContent":["/**\n * Pure interaction math - the proven motion functions extracted from the\n * Pale Signal research (springs, hinge/dial normalisation, hoop scoring),\n * plus the tuple vector/quaternion helpers the binder and behaviours need.\n * No engine imports; everything is unit-tested headless.\n */\nimport type { QuatTuple, RayTuple, Vec3Tuple } from \"@realitycollective/webxr-input\";\n\n/** Clamp to the unit interval. */\nexport function clamp01(t: number): number {\n return t < 0 ? 0 : t > 1 ? 1 : t;\n}\n\n/**\n * Normalize a measured displacement/angle against a signed range to 0..1.\n * Sign-agnostic: a range of `-π/2` maps `-π/2 → 1`.\n */\nexport function normalize01(value: number, range: number): number {\n if (range === 0) return 0;\n return clamp01(value / range);\n}\n\n/**\n * Did a tossed object pass *through* a hoop this frame? True when it crossed\n * the hoop plane in the scoring direction (downward - `prev` above, `curr`\n * at/below) while inside the ring (`radial <= radius`).\n */\nexport function passedThroughHoop(\n prevAlong: number,\n currAlong: number,\n planeAlong: number,\n radial: number,\n radius: number,\n): boolean {\n const crossedDown = prevAlong > planeAlong && currAlong <= planeAlong;\n return crossedDown && radial <= radius;\n}\n\n/**\n * One step of a damped harmonic oscillator (semi-implicit Euler).\n * `out[0]` = next value, `out[1]` = next velocity. An under-damped spring\n * (damping ratio ≈ 0.3-0.5) is what gives a pressed button its bounce.\n * `dt` is clamped to 1/30 s so a long frame can't blow the integrator up.\n */\nexport function springStep(\n value: number,\n velocity: number,\n target: number,\n stiffness: number,\n damping: number,\n dt: number,\n out: Float32Array = new Float32Array(2),\n): Float32Array {\n const h = Math.min(dt, 1 / 30);\n const accel = -stiffness * (value - target) - damping * velocity;\n const nextVelocity = velocity + accel * h;\n out[0] = value + nextVelocity * h;\n out[1] = nextVelocity;\n return out;\n}\n\n/** Exponential decay of `value` toward 0 over `dt` at `ratePerSec`. */\nexport function decay(value: number, ratePerSec: number, dt: number): number {\n const next = value * Math.exp(-ratePerSec * Math.max(dt, 0));\n return next < 1e-4 ? 0 : next;\n}\n\n/** Penner's ease-out-bounce on `t ∈ [0,1]`. */\nexport function easeOutBounce(t: number): number {\n const n1 = 7.5625;\n const d1 = 2.75;\n let x = clamp01(t);\n if (x < 1 / d1) return n1 * x * x;\n if (x < 2 / d1) return n1 * (x -= 1.5 / d1) * x + 0.75;\n if (x < 2.5 / d1) return n1 * (x -= 2.25 / d1) * x + 0.9375;\n return n1 * (x -= 2.625 / d1) * x + 0.984375;\n}\n\n/** Clamp a value to the symmetric range `[-|mag|, +|mag|]`. */\nexport function clampSym(x: number, mag: number): number {\n const m = Math.abs(mag);\n return x < -m ? -m : x > m ? m : x;\n}\n\n/**\n * Hinge angle for a position-driven lever: given the hand's offset from the\n * pivot resolved into the hinge plane - `alongRest` (toward the arm's rest\n * direction) and `alongSwing` (the in-plane perpendicular) - the angle the\n * arm should take to point at the hand, clamped to `±|maxMag|`.\n */\nexport function hingeAngleToHand(alongRest: number, alongSwing: number, maxMag: number): number {\n return clampSym(Math.atan2(alongSwing, alongRest), maxMag);\n}\n\n/**\n * Map a centered hinge angle in `[-|mag|, +|mag|]` to a 0..1 analog value\n * with the rest (0) at 0.5 - a bidirectional lever as one normalized value.\n */\nexport function centeredUnit(angle: number, mag: number): number {\n const m = Math.abs(mag);\n if (m < 1e-6) return 0.5;\n return clamp01(0.5 + (0.5 * angle) / m);\n}\n\n// ---------------------------------------------------------------------------\n// Tuple vector / quaternion helpers (allocation-light, no engine types).\n// ---------------------------------------------------------------------------\n\nexport function vSub(a: Vec3Tuple, b: Vec3Tuple): Vec3Tuple {\n return [a[0] - b[0], a[1] - b[1], a[2] - b[2]];\n}\n\nexport function vAdd(a: Vec3Tuple, b: Vec3Tuple): Vec3Tuple {\n return [a[0] + b[0], a[1] + b[1], a[2] + b[2]];\n}\n\nexport function vScale(a: Vec3Tuple, s: number): Vec3Tuple {\n return [a[0] * s, a[1] * s, a[2] * s];\n}\n\nexport function vDot(a: Vec3Tuple, b: Vec3Tuple): number {\n return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];\n}\n\nexport function vCross(a: Vec3Tuple, b: Vec3Tuple): Vec3Tuple {\n return [\n a[1] * b[2] - a[2] * b[1],\n a[2] * b[0] - a[0] * b[2],\n a[0] * b[1] - a[1] * b[0],\n ];\n}\n\nexport function vLength(a: Vec3Tuple): number {\n return Math.hypot(a[0], a[1], a[2]);\n}\n\nexport function vDistance(a: Vec3Tuple, b: Vec3Tuple): number {\n return Math.hypot(a[0] - b[0], a[1] - b[1], a[2] - b[2]);\n}\n\nexport function vNormalize(a: Vec3Tuple): Vec3Tuple {\n const l = vLength(a);\n return l < 1e-9 ? [0, 0, 0] : [a[0] / l, a[1] / l, a[2] / l];\n}\n\n/** Quaternion from an axis (normalised) and an angle in radians. */\nexport function quatFromAxisAngle(axis: Vec3Tuple, angle: number): QuatTuple {\n const half = angle / 2;\n const s = Math.sin(half);\n return [axis[0] * s, axis[1] * s, axis[2] * s, Math.cos(half)];\n}\n\nexport function quatMultiply(a: QuatTuple, b: QuatTuple): QuatTuple {\n const [ax, ay, az, aw] = a;\n const [bx, by, bz, bw] = b;\n return [\n aw * bx + ax * bw + ay * bz - az * by,\n aw * by - ax * bz + ay * bw + az * bx,\n aw * bz + ax * by - ay * bx + az * bw,\n aw * bw - ax * bx - ay * by - az * bz,\n ];\n}\n\nexport function quatConjugate(q: QuatTuple): QuatTuple {\n return [-q[0], -q[1], -q[2], q[3]];\n}\n\n/** Rotate a vector by a quaternion. */\nexport function vApplyQuat(v: Vec3Tuple, q: QuatTuple): Vec3Tuple {\n const [x, y, z] = v;\n const [qx, qy, qz, qw] = q;\n // t = 2 * cross(q.xyz, v)\n const tx = 2 * (qy * z - qz * y);\n const ty = 2 * (qz * x - qx * z);\n const tz = 2 * (qx * y - qy * x);\n // v + qw * t + cross(q.xyz, t)\n return [\n x + qw * tx + qy * tz - qz * ty,\n y + qw * ty + qz * tx - qx * tz,\n z + qw * tz + qx * ty - qy * tx,\n ];\n}\n\n/** Transform a world-space point into the local frame of `pose`. */\nexport function worldToLocal(\n point: Vec3Tuple,\n posePosition: Vec3Tuple,\n poseQuaternion: QuatTuple,\n): Vec3Tuple {\n return vApplyQuat(vSub(point, posePosition), quatConjugate(poseQuaternion));\n}\n\n/** Closest-approach distance from a ray to a point, and the along-ray t. */\nexport function rayPointDistance(ray: RayTuple, point: Vec3Tuple): { distance: number; t: number } {\n const toPoint = vSub(point, ray.origin);\n const t = vDot(toPoint, ray.direction);\n if (t <= 0) return { distance: vLength(toPoint), t: 0 };\n const closest = vAdd(ray.origin, vScale(ray.direction, t));\n return { distance: vDistance(closest, point), t };\n}\n\n/** Angular offset (radians) between a ray direction and the direction to a point. */\nexport function rayAngleTo(ray: RayTuple, point: Vec3Tuple): number {\n const dir = vNormalize(vSub(point, ray.origin));\n const d = vDot(vNormalize(ray.direction), dir);\n return Math.acos(Math.min(1, Math.max(-1, d)));\n}\n\n/*\n * Velocity between two poses lives in `@realitycollective/webxr-input` as\n * `velocityBetween`, re-exported from this package's index. The local copy\n * that stood in for it before Input 0.1.1 is gone.\n */\n\n/** Zero out a signal below `threshold`, leaving larger values untouched. */\nexport function clampDeadzone(value: number, threshold: number): number {\n return Math.abs(value) < threshold ? 0 : value;\n}\n"]}
|
package/dist/pointer-bridge.js
CHANGED
|
@@ -22,7 +22,7 @@ export function createPointerBridge(runtime, match = () => true) {
|
|
|
22
22
|
const move = new Emitter();
|
|
23
23
|
const release = new Emitter();
|
|
24
24
|
let activeSourceId = null;
|
|
25
|
-
const unsubscribe = runtime.
|
|
25
|
+
const unsubscribe = runtime.onSample((sources) => {
|
|
26
26
|
if (activeSourceId === null) {
|
|
27
27
|
for (const source of sources) {
|
|
28
28
|
if (!source.ray || !match(source.id))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pointer-bridge.js","sourceRoot":"","sources":["../src/pointer-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EACL,sBAAsB,EACtB,wBAAwB,GAIzB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAQtC;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAA2B,EAC3B,QAAuC,GAAG,EAAE,CAAC,IAAI;IAEjD,MAAM,KAAK,GAAG,IAAI,OAAO,EAAiB,CAAC;IAC3C,MAAM,IAAI,GAAG,IAAI,OAAO,EAAiB,CAAC;IAC1C,MAAM,OAAO,GAAG,IAAI,OAAO,EAAiB,CAAC;IAE7C,IAAI,cAAc,GAAkB,IAAI,CAAC;IAEzC,MAAM,WAAW,GAAG,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"pointer-bridge.js","sourceRoot":"","sources":["../src/pointer-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EACL,sBAAsB,EACtB,wBAAwB,GAIzB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAQtC;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAA2B,EAC3B,QAAuC,GAAG,EAAE,CAAC,IAAI;IAEjD,MAAM,KAAK,GAAG,IAAI,OAAO,EAAiB,CAAC;IAC3C,MAAM,IAAI,GAAG,IAAI,OAAO,EAAiB,CAAC;IAC1C,MAAM,OAAO,GAAG,IAAI,OAAO,EAAiB,CAAC;IAE7C,IAAI,cAAc,GAAkB,IAAI,CAAC;IAEzC,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,EAAE;QAC/C,IAAI,cAAc,KAAK,IAAI,EAAE,CAAC;YAC5B,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;gBAC7B,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;oBAAE,SAAS;gBAC/C,IAAI,MAAM,CAAC,MAAM,IAAI,sBAAsB,EAAE,CAAC;oBAC5C,cAAc,GAAG,MAAM,CAAC,EAAE,CAAC;oBAC3B,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC;oBAC3E,MAAM;gBACR,CAAC;YACH,CAAC;YACD,OAAO;QACT,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,cAAc,CAAC,CAAC;QAC5D,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,MAAM,IAAI,wBAAwB,EAAE,CAAC;YACxE,IAAI,MAAM,EAAE,GAAG,EAAE,CAAC;gBAChB,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC;YAC/E,CAAC;iBAAM,IAAI,cAAc,KAAK,IAAI,EAAE,CAAC;gBACnC,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC7D,CAAC;YACD,cAAc,GAAG,IAAI,CAAC;YACtB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,MAAM,EAAE;YACN,OAAO,EAAE,CAAC,CAAC,EAAe,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;YAC/C,MAAM,EAAE,CAAC,CAAC,EAAe,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;YAC7C,SAAS,EAAE,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;SACpD;QACD,OAAO,EAAE,WAAW;KACrB,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Pointer bridge - drive the UI Extensions (or anything speaking the\n * shared pointer contract) from the SAME input stack that drives the\n * interactions. One provider, both families: this is the coexistence\n * contract in code.\n *\n * The returned object implements `PointerInputSource` (structurally\n * identical in `@realitycollective/webxr-input` and\n * `@realitycollective/webxr-uiextensions`): press-move-release derived\n * from a source's ray + select signal, fed by the runtime's per-frame\n * sampling.\n */\nimport {\n SELECT_PRESS_THRESHOLD,\n SELECT_RELEASE_THRESHOLD,\n type PointerInputSource,\n type PointerSample,\n type Unsubscribe,\n} from \"@realitycollective/webxr-input\";\nimport { Emitter } from \"./events.js\";\nimport type { InteractionRuntime } from \"./runtime.js\";\n\nexport interface PointerBridge {\n source: PointerInputSource;\n dispose(): void;\n}\n\n/**\n * Create a pointer stream from the runtime's sampled sources.\n * `match` picks which source drives it (default: any source with a ray -\n * first pressed wins and holds until release).\n */\nexport function createPointerBridge(\n runtime: InteractionRuntime,\n match: (sourceId: string) => boolean = () => true,\n): PointerBridge {\n const press = new Emitter<PointerSample>();\n const move = new Emitter<PointerSample>();\n const release = new Emitter<PointerSample>();\n\n let activeSourceId: string | null = null;\n\n const unsubscribe = runtime.onSample((sources) => {\n if (activeSourceId === null) {\n for (const source of sources) {\n if (!source.ray || !match(source.id)) continue;\n if (source.select >= SELECT_PRESS_THRESHOLD) {\n activeSourceId = source.id;\n press.emit({ origin: source.ray.origin, direction: source.ray.direction });\n break;\n }\n }\n return;\n }\n const active = sources.find((s) => s.id === activeSourceId);\n if (!active || !active.ray || active.select <= SELECT_RELEASE_THRESHOLD) {\n if (active?.ray) {\n release.emit({ origin: active.ray.origin, direction: active.ray.direction });\n } else if (activeSourceId !== null) {\n release.emit({ origin: [0, 0, 0], direction: [0, 0, -1] });\n }\n activeSourceId = null;\n return;\n }\n move.emit({ origin: active.ray.origin, direction: active.ray.direction });\n });\n\n return {\n source: {\n onPress: (l): Unsubscribe => press.subscribe(l),\n onMove: (l): Unsubscribe => move.subscribe(l),\n onRelease: (l): Unsubscribe => release.subscribe(l),\n },\n dispose: unsubscribe,\n };\n}\n"]}
|
package/dist/runtime.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ import { type InteractionEventListener } from "./events.js";
|
|
|
20
20
|
import type { FeedbackListener } from "./feedback.js";
|
|
21
21
|
import { type DwellConfig } from "./gaze.js";
|
|
22
22
|
import type { HitTester, TransformPort } from "./ports.js";
|
|
23
|
-
import { type
|
|
23
|
+
import { type VelocityTrackerOptions } from "./velocity-tracker.js";
|
|
24
24
|
/** Interactor id used when gaze is synthesized from the head pose. */
|
|
25
25
|
export declare const HEAD_GAZE_INTERACTOR_ID = "head-gaze";
|
|
26
26
|
export interface InteractableState {
|
|
@@ -74,18 +74,23 @@ export declare class InteractionRuntime {
|
|
|
74
74
|
getInteractableIds(): string[];
|
|
75
75
|
onEvent(listener: InteractionEventListener): Unsubscribe;
|
|
76
76
|
onFeedback(listener: FeedbackListener): Unsubscribe;
|
|
77
|
-
/** Sampled sources for this frame - the UI Extensions pointer bridge hook. */
|
|
78
|
-
onSourcesSampled(listener: (sources: readonly InputSourceSnapshot[]) => void): Unsubscribe;
|
|
79
77
|
/**
|
|
80
|
-
*
|
|
81
|
-
*
|
|
78
|
+
* Sampled sources for this frame - the UI Extensions pointer bridge hook.
|
|
79
|
+
*
|
|
80
|
+
* @deprecated Use {@link onSample}. Both deliver the same stream: since
|
|
81
|
+
* `@realitycollective/webxr-input` 0.1.1 carries `linearVelocity` and
|
|
82
|
+
* `angularVelocity` on `InputSourceSnapshot`, the two signatures are
|
|
83
|
+
* identical and only one name is needed. This one is kept so existing
|
|
84
|
+
* callers keep working and will be removed in a later major release.
|
|
82
85
|
*/
|
|
83
|
-
|
|
86
|
+
onSourcesSampled(listener: (sources: readonly InputSourceSnapshot[]) => void): Unsubscribe;
|
|
87
|
+
/** This frame's sources, velocity included. */
|
|
88
|
+
onSample(listener: (sources: readonly InputSourceSnapshot[]) => void): Unsubscribe;
|
|
84
89
|
/**
|
|
85
90
|
* The last sample of one source, velocity included. Undefined before the
|
|
86
91
|
* first update, and once the source stops reporting.
|
|
87
92
|
*/
|
|
88
|
-
getSource(id: string):
|
|
93
|
+
getSource(id: string): InputSourceSnapshot | undefined;
|
|
89
94
|
getCapabilities(): InputCapabilities;
|
|
90
95
|
getProvider(): InputProvider;
|
|
91
96
|
update(dt: number): void;
|
package/dist/runtime.js
CHANGED
|
@@ -19,7 +19,7 @@ import { GrabBehaviour } from "./behaviours/grab.js";
|
|
|
19
19
|
import { Emitter } from "./events.js";
|
|
20
20
|
import { DwellState, resolveDwellConfig, DWELL_DEFAULTS } from "./gaze.js";
|
|
21
21
|
import { vApplyQuat } from "./math.js";
|
|
22
|
-
import { VelocityTracker
|
|
22
|
+
import { VelocityTracker } from "./velocity-tracker.js";
|
|
23
23
|
const DEFAULT_POKE_RADIUS = 0.05;
|
|
24
24
|
/** Interactor id used when gaze is synthesized from the head pose. */
|
|
25
25
|
export const HEAD_GAZE_INTERACTOR_ID = "head-gaze";
|
|
@@ -137,14 +137,19 @@ export class InteractionRuntime {
|
|
|
137
137
|
onFeedback(listener) {
|
|
138
138
|
return this.feedbackEmitter.subscribe(listener);
|
|
139
139
|
}
|
|
140
|
-
/**
|
|
140
|
+
/**
|
|
141
|
+
* Sampled sources for this frame - the UI Extensions pointer bridge hook.
|
|
142
|
+
*
|
|
143
|
+
* @deprecated Use {@link onSample}. Both deliver the same stream: since
|
|
144
|
+
* `@realitycollective/webxr-input` 0.1.1 carries `linearVelocity` and
|
|
145
|
+
* `angularVelocity` on `InputSourceSnapshot`, the two signatures are
|
|
146
|
+
* identical and only one name is needed. This one is kept so existing
|
|
147
|
+
* callers keep working and will be removed in a later major release.
|
|
148
|
+
*/
|
|
141
149
|
onSourcesSampled(listener) {
|
|
142
150
|
return this.afterSample.subscribe(listener);
|
|
143
151
|
}
|
|
144
|
-
/**
|
|
145
|
-
* This frame's sources, velocity included. The same stream as
|
|
146
|
-
* {@link onSourcesSampled} with the velocity fields declared.
|
|
147
|
-
*/
|
|
152
|
+
/** This frame's sources, velocity included. */
|
|
148
153
|
onSample(listener) {
|
|
149
154
|
return this.afterSample.subscribe(listener);
|
|
150
155
|
}
|
package/dist/runtime.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * InteractionRuntime - the engine-free orchestrator.\n *\n * Once per host frame the runtime pulls the input provider, resolves\n * targeting (provider hints first - provider power wins - then poke\n * proximity, then ray hits), applies press/grab transitions with\n * hysteresis, runs gaze gating + dwell, ticks every behaviour, and emits\n * interaction events and feedback intents. It never touches an engine:\n * space queries and transform writes go through the adapter-implemented\n * {@link HitTester} and {@link TransformPort}.\n *\n * Lifecycle is first-class (the pale-signal gap): interactables register,\n * unregister, enable and disable; behaviours disabled by capability\n * negotiation announce themselves with a `behaviourDisabled` event.\n */\nimport {\n SELECT_PRESS_THRESHOLD,\n SELECT_RELEASE_THRESHOLD,\n unmetRequirements,\n type InputCapabilities,\n type InputHitHint,\n type InputProvider,\n type InputSourceSnapshot,\n type PoseTuple,\n type RayTuple,\n type Unsubscribe,\n} from \"@realitycollective/webxr-input\";\nimport type { Behaviour, InteractorInfo } from \"./behaviours/behaviour.js\";\nimport {\n createBehaviour,\n type BehaviourConfig,\n type BehaviourFactoryContext,\n} from \"./behaviours/factory.js\";\nimport { GrabBehaviour } from \"./behaviours/grab.js\";\nimport type { InteractableDescriptor } from \"./descriptor.js\";\nimport { Emitter, type InteractionEvent, type InteractionEventListener } from \"./events.js\";\nimport type { FeedbackIntent, FeedbackListener } from \"./feedback.js\";\nimport { DwellState, resolveDwellConfig, DWELL_DEFAULTS, type DwellConfig } from \"./gaze.js\";\nimport { vApplyQuat } from \"./math.js\";\nimport type { HitTester, TransformPort } from \"./ports.js\";\nimport {\n VelocityTracker,\n type InputSourceSnapshotWithVelocity,\n type VelocityTrackerOptions,\n} from \"./velocity-tracker.js\";\n\nconst DEFAULT_POKE_RADIUS = 0.05;\n/** Interactor id used when gaze is synthesized from the head pose. */\nexport const HEAD_GAZE_INTERACTOR_ID = \"head-gaze\";\n\nexport interface InteractableState {\n id: string;\n enabled: boolean;\n hovered: boolean;\n gazeHovered: boolean;\n pressed: boolean;\n grabbed: boolean;\n /** Primary behaviour's logical value. */\n value: number;\n /** Gaze-dwell meter 0..1 (0 when dwell is not enabled). */\n dwell: number;\n}\n\ninterface BehaviourSlot {\n instance: Behaviour;\n config: BehaviourConfig;\n disabled: boolean;\n disabledReason: string;\n}\n\ninterface Registered {\n def: InteractableDescriptor;\n behaviours: BehaviourSlot[];\n transform: TransformPort | undefined;\n enabled: boolean;\n pokeRadius: number;\n gazeRequired: boolean;\n dwellConfig: Required<DwellConfig> | null;\n dwell: DwellState;\n gazeHovered: boolean;\n hoveredBy: Set<string>;\n pressedBy: Set<string>;\n grabbedBy: string | null;\n}\n\ninterface SourceRuntimeState {\n hoverTarget: string | null;\n pressed: boolean;\n pressTarget: string | null;\n grabbed: boolean;\n grabTarget: string | null;\n}\n\nexport interface InteractionRuntimeOptions {\n provider: InputProvider;\n hitTester?: HitTester;\n dwellDefaults?: DwellConfig;\n /**\n * Per-source velocity tracking. On by default with no smoothing; pass\n * `false` to skip it, or options to smooth. The tracker only fills in\n * what the provider did not supply.\n */\n velocity?: VelocityTrackerOptions | false;\n}\n\nexport interface RegisterPorts {\n transform?: TransformPort;\n}\n\nexport class InteractionRuntime {\n private readonly provider: InputProvider;\n private hitTester: HitTester | null;\n private readonly dwellDefaults: Required<DwellConfig>;\n\n private readonly interactables = new Map<string, Registered>();\n private readonly sourceStates = new Map<string, SourceRuntimeState>();\n private readonly events = new Emitter<InteractionEvent>();\n private readonly feedbackEmitter = new Emitter<FeedbackIntent>();\n private readonly afterSample = new Emitter<readonly InputSourceSnapshotWithVelocity[]>();\n private readonly velocityTracker: VelocityTracker | null;\n private lastSources = new Map<string, InputSourceSnapshotWithVelocity>();\n private capabilities: InputCapabilities;\n private readonly unsubscribeCaps: Unsubscribe;\n private disposed = false;\n\n constructor(options: InteractionRuntimeOptions) {\n this.provider = options.provider;\n this.hitTester = options.hitTester ?? null;\n const d = options.dwellDefaults;\n this.dwellDefaults = {\n holdSeconds: d?.holdSeconds ?? DWELL_DEFAULTS.holdSeconds,\n decayFactor: d?.decayFactor ?? DWELL_DEFAULTS.decayFactor,\n rearmBelow: d?.rearmBelow ?? DWELL_DEFAULTS.rearmBelow,\n };\n this.velocityTracker =\n options.velocity === false ? null : new VelocityTracker(options.velocity ?? {});\n this.capabilities = this.provider.getCapabilities();\n this.unsubscribeCaps = this.provider.onCapabilitiesChanged((caps) => {\n this.capabilities = caps;\n this.renegotiateAll();\n });\n }\n\n // -- registry -------------------------------------------------------------\n\n registerInteractable(def: InteractableDescriptor, ports: RegisterPorts = {}): void {\n if (this.interactables.has(def.id)) {\n throw new Error(`Interactable \"${def.id}\" is already registered`);\n }\n const context: BehaviourFactoryContext = {\n grabFulfilment: this.capabilities.grabs === \"native\" ? \"native\" : \"poseOnly\",\n };\n const registered: Registered = {\n def,\n behaviours: def.behaviours.map((config) => ({\n instance: createBehaviour(config, context),\n config,\n disabled: false,\n disabledReason: \"\",\n })),\n transform: ports.transform,\n enabled: def.enabled !== false,\n pokeRadius: def.pokeRadius ?? DEFAULT_POKE_RADIUS,\n gazeRequired: def.gaze?.required === true,\n dwellConfig: resolveDwellConfig(def.gaze?.dwell, this.dwellDefaults),\n dwell: new DwellState(),\n gazeHovered: false,\n hoveredBy: new Set(),\n pressedBy: new Set(),\n grabbedBy: null,\n };\n this.interactables.set(def.id, registered);\n this.renegotiate(def.id, registered);\n }\n\n unregisterInteractable(id: string): void {\n const registered = this.interactables.get(id);\n if (!registered) return;\n this.releaseAllHolds(id);\n this.interactables.delete(id);\n }\n\n setInteractableEnabled(id: string, enabled: boolean): void {\n const registered = this.interactables.get(id);\n if (!registered || registered.enabled === enabled) return;\n registered.enabled = enabled;\n if (!enabled) this.releaseAllHolds(id);\n this.events.emit({\n type: enabled ? \"interactableEnabled\" : \"interactableDisabled\",\n interactableId: id,\n });\n }\n\n setHitTester(hitTester: HitTester | null): void {\n this.hitTester = hitTester;\n }\n\n /** Reach a live behaviour instance for tuning (playground steppers). */\n getBehaviour<T extends Behaviour = Behaviour>(interactableId: string, kind: string): T | undefined {\n const registered = this.interactables.get(interactableId);\n return registered?.behaviours.find((b) => b.instance.kind === kind)?.instance as T | undefined;\n }\n\n getState(id: string): InteractableState | undefined {\n const r = this.interactables.get(id);\n if (!r) return undefined;\n const primary = r.behaviours.find((b) => !b.disabled)?.instance;\n return {\n id,\n enabled: r.enabled,\n hovered: r.hoveredBy.size > 0 || r.gazeHovered,\n gazeHovered: r.gazeHovered,\n pressed: r.pressedBy.size > 0,\n grabbed: r.grabbedBy !== null,\n value: primary?.getValue() ?? 0,\n dwell: r.dwell.getProgress(),\n };\n }\n\n getInteractableIds(): string[] {\n return [...this.interactables.keys()];\n }\n\n // -- subscriptions ----------------------------------------------------------\n\n onEvent(listener: InteractionEventListener): Unsubscribe {\n return this.events.subscribe(listener);\n }\n\n onFeedback(listener: FeedbackListener): Unsubscribe {\n return this.feedbackEmitter.subscribe(listener);\n }\n\n /** Sampled sources for this frame - the UI Extensions pointer bridge hook. */\n onSourcesSampled(listener: (sources: readonly InputSourceSnapshot[]) => void): Unsubscribe {\n return this.afterSample.subscribe(listener);\n }\n\n /**\n * This frame's sources, velocity included. The same stream as\n * {@link onSourcesSampled} with the velocity fields declared.\n */\n onSample(listener: (sources: readonly InputSourceSnapshotWithVelocity[]) => void): Unsubscribe {\n return this.afterSample.subscribe(listener);\n }\n\n /**\n * The last sample of one source, velocity included. Undefined before the\n * first update, and once the source stops reporting.\n */\n getSource(id: string): InputSourceSnapshotWithVelocity | undefined {\n return this.lastSources.get(id);\n }\n\n getCapabilities(): InputCapabilities {\n return this.capabilities;\n }\n\n getProvider(): InputProvider {\n return this.provider;\n }\n\n // -- frame ------------------------------------------------------------------\n\n update(dt: number): void {\n if (this.disposed) return;\n const sampled = this.provider.sample();\n const sources = this.velocityTracker ? this.velocityTracker.update(sampled, dt) : sampled;\n const hints = this.provider.sampleHints?.() ?? [];\n this.lastSources = new Map(sources.map((source) => [source.id, source]));\n this.afterSample.emit(sources);\n\n const hintBySource = new Map<string, InputHitHint[]>();\n for (const hint of hints) {\n const list = hintBySource.get(hint.sourceId);\n if (list) list.push(hint);\n else hintBySource.set(hint.sourceId, [hint]);\n }\n\n const seen = new Set<string>();\n for (const source of sources) {\n seen.add(source.id);\n this.updateSource(source, hintBySource.get(source.id) ?? []);\n }\n // Sources that vanished mid-hold release everything they held.\n for (const [id, state] of this.sourceStates) {\n if (!seen.has(id)) {\n this.forceRelease(id, state);\n this.sourceStates.delete(id);\n }\n }\n\n this.updateGaze(sources, dt);\n this.tickBehaviours(sources, dt);\n }\n\n dispose(): void {\n this.disposed = true;\n this.unsubscribeCaps();\n this.interactables.clear();\n this.sourceStates.clear();\n this.lastSources.clear();\n this.velocityTracker?.reset();\n }\n\n // -- internals ---------------------------------------------------------------\n\n private sourceState(id: string): SourceRuntimeState {\n let state = this.sourceStates.get(id);\n if (!state) {\n state = { hoverTarget: null, pressed: false, pressTarget: null, grabbed: false, grabTarget: null };\n this.sourceStates.set(id, state);\n }\n return state;\n }\n\n private interactorInfo(source: InputSourceSnapshot): InteractorInfo {\n const info: InteractorInfo = {\n id: source.id,\n kind: source.kind,\n select: source.select,\n squeeze: source.squeeze,\n };\n if (source.ray) info.ray = source.ray;\n if (source.gripPose) info.gripPose = source.gripPose;\n if (source.indexTip) info.indexTip = source.indexTip;\n return info;\n }\n\n /** Resolve this source's target: hints beat poke beats ray. */\n private resolveTarget(source: InputSourceSnapshot, hints: InputHitHint[]): string | null {\n const hint =\n hints.find((h) => h.state === \"grab\") ??\n hints.find((h) => h.state === \"press\") ??\n hints.find((h) => h.state === \"hover\");\n if (hint && this.targetable(hint.targetId)) return hint.targetId;\n if (source.indexTip && this.hitTester) {\n const poke = this.hitTester.hitProximity(source.indexTip, DEFAULT_POKE_RADIUS);\n if (poke && this.targetable(poke.interactableId)) return poke.interactableId;\n }\n if (source.ray && this.hitTester) {\n const hit = this.hitTester.hitRay(source.ray);\n if (hit && this.targetable(hit.interactableId)) return hit.interactableId;\n }\n return null;\n }\n\n private targetable(id: string): boolean {\n const registered = this.interactables.get(id);\n return registered !== undefined && registered.enabled;\n }\n\n private flags(registered: Registered): { pressable: boolean; grabbable: boolean } {\n let pressable = false;\n let grabbable = false;\n for (const slot of registered.behaviours) {\n if (slot.disabled) continue;\n if (slot.instance.onPressStart) pressable = true;\n if (slot.instance.grabbable) grabbable = true;\n }\n return { pressable, grabbable };\n }\n\n private updateSource(source: InputSourceSnapshot, hints: InputHitHint[]): void {\n const state = this.sourceState(source.id);\n const target = this.resolveTarget(source, hints);\n\n // Hover transitions.\n if (state.hoverTarget !== target) {\n if (state.hoverTarget) this.setHover(state.hoverTarget, source.id, false);\n if (target) this.setHover(target, source.id, true);\n state.hoverTarget = target;\n }\n\n const registered = target ? this.interactables.get(target) : undefined;\n const roles = registered ? this.flags(registered) : { pressable: false, grabbable: false };\n\n // Signal resolution. A pinching hand (or a 2D pointer click) acts as a\n // grab when the target is grab-only; controllers keep trigger=press,\n // squeeze=grab.\n const selectAsGrab = roles.grabbable && !roles.pressable && source.kind !== \"controller\";\n const pressSignal = selectAsGrab ? 0 : source.select;\n const grabSignal = Math.max(source.squeeze, selectAsGrab ? source.select : 0);\n\n const hintPress = hints.some((h) => h.state === \"press\");\n const hintGrab = hints.some((h) => h.state === \"grab\") || source.nativeGrabbing === true;\n\n // Press with hysteresis (hints override).\n const pressActive = hintPress || (state.pressed\n ? pressSignal > SELECT_RELEASE_THRESHOLD\n : pressSignal >= SELECT_PRESS_THRESHOLD);\n if (pressActive && !state.pressed) {\n state.pressed = true;\n if (target && registered && roles.pressable && this.gazeAllows(registered)) {\n state.pressTarget = target;\n this.routePressStart(target, registered, this.interactorInfo(source));\n }\n } else if (!pressActive && state.pressed) {\n state.pressed = false;\n if (state.pressTarget) {\n this.routePressEnd(state.pressTarget, source.id, this.interactorInfo(source));\n state.pressTarget = null;\n }\n }\n\n // Grab with hysteresis (hints / native grabbing override).\n const grabActive = hintGrab || (state.grabbed\n ? grabSignal > SELECT_RELEASE_THRESHOLD\n : grabSignal >= SELECT_PRESS_THRESHOLD);\n if (grabActive && !state.grabbed) {\n state.grabbed = true;\n const hintTargetId = hints.find((h) => h.state === \"grab\")?.targetId;\n const grabTargetId = hintTargetId && this.targetable(hintTargetId) ? hintTargetId : target;\n const grabTarget = grabTargetId ? this.interactables.get(grabTargetId) : undefined;\n if (\n grabTargetId &&\n grabTarget &&\n this.flags(grabTarget).grabbable &&\n grabTarget.grabbedBy === null &&\n this.gazeAllows(grabTarget)\n ) {\n state.grabTarget = grabTargetId;\n grabTarget.grabbedBy = source.id;\n const info = this.interactorInfo(source);\n for (const slot of grabTarget.behaviours) {\n if (!slot.disabled && slot.instance.grabbable) {\n slot.instance.onGrabStart?.(this.contextFor(grabTargetId, grabTarget, 0), info);\n }\n }\n }\n } else if (!grabActive && state.grabbed) {\n state.grabbed = false;\n if (state.grabTarget) {\n this.endGrab(state.grabTarget, source.id, this.interactorInfo(source));\n state.grabTarget = null;\n }\n }\n }\n\n private gazeAllows(registered: Registered): boolean {\n return !registered.gazeRequired || registered.gazeHovered;\n }\n\n private setHover(id: string, sourceId: string, hovered: boolean): void {\n const registered = this.interactables.get(id);\n if (!registered) return;\n if (hovered) {\n registered.hoveredBy.add(sourceId);\n if (registered.hoveredBy.size === 1) {\n this.events.emit({ type: \"hoverEnter\", interactableId: id, interactorId: sourceId });\n this.feedbackEmitter.emit({\n cue: \"hover\",\n interactableId: id,\n sourceId,\n intensity: 0.1,\n durationMs: 10,\n });\n }\n } else {\n registered.hoveredBy.delete(sourceId);\n if (registered.hoveredBy.size === 0) {\n this.events.emit({ type: \"hoverExit\", interactableId: id, interactorId: sourceId });\n }\n }\n }\n\n private routePressStart(id: string, registered: Registered, info: InteractorInfo): void {\n registered.pressedBy.add(info.id);\n this.events.emit({ type: \"pressStart\", interactableId: id, interactorId: info.id });\n const ctx = this.contextFor(id, registered, 0);\n for (const slot of registered.behaviours) {\n if (!slot.disabled) slot.instance.onPressStart?.(ctx, info);\n }\n }\n\n private routePressEnd(id: string, sourceId: string, info: InteractorInfo): void {\n const registered = this.interactables.get(id);\n if (!registered) return;\n registered.pressedBy.delete(sourceId);\n this.events.emit({ type: \"pressEnd\", interactableId: id, interactorId: sourceId });\n const ctx = this.contextFor(id, registered, 0);\n for (const slot of registered.behaviours) {\n if (!slot.disabled) slot.instance.onPressEnd?.(ctx, info);\n }\n }\n\n private endGrab(id: string, sourceId: string, info: InteractorInfo): void {\n const registered = this.interactables.get(id);\n if (!registered || registered.grabbedBy !== sourceId) return;\n registered.grabbedBy = null;\n const ctx = this.contextFor(id, registered, 0);\n for (const slot of registered.behaviours) {\n if (!slot.disabled && slot.instance.grabbable) slot.instance.onGrabEnd?.(ctx, info);\n }\n }\n\n private forceRelease(sourceId: string, state: SourceRuntimeState): void {\n const info: InteractorInfo = { id: sourceId, kind: \"other\", select: 0, squeeze: 0 };\n if (state.pressTarget) this.routePressEnd(state.pressTarget, sourceId, info);\n if (state.grabTarget) this.endGrab(state.grabTarget, sourceId, info);\n if (state.hoverTarget) this.setHover(state.hoverTarget, sourceId, false);\n }\n\n private releaseAllHolds(id: string): void {\n for (const [sourceId, state] of this.sourceStates) {\n if (state.pressTarget === id) {\n this.routePressEnd(id, sourceId, { id: sourceId, kind: \"other\", select: 0, squeeze: 0 });\n state.pressTarget = null;\n state.pressed = false;\n }\n if (state.grabTarget === id) {\n this.endGrab(id, sourceId, { id: sourceId, kind: \"other\", select: 0, squeeze: 0 });\n state.grabTarget = null;\n state.grabbed = false;\n }\n if (state.hoverTarget === id) {\n this.setHover(id, sourceId, false);\n state.hoverTarget = null;\n }\n }\n }\n\n private updateGaze(sources: readonly InputSourceSnapshot[], dt: number): void {\n let gazeRay: RayTuple | null = null;\n let gazeId = HEAD_GAZE_INTERACTOR_ID;\n const gazeSource = sources.find((s) => s.kind === \"gaze\");\n if (gazeSource?.ray) {\n gazeRay = gazeSource.ray;\n gazeId = gazeSource.id;\n } else if (this.capabilities.headPose && this.provider.getHeadPose) {\n const head: PoseTuple = this.provider.getHeadPose();\n gazeRay = {\n origin: head.position,\n direction: vApplyQuat([0, 0, -1], head.quaternion),\n };\n }\n\n const gazeTarget =\n gazeRay && this.hitTester ? this.hitTester.hitRay(gazeRay)?.interactableId ?? null : null;\n\n for (const [id, registered] of this.interactables) {\n const hovered = registered.enabled && gazeTarget === id;\n if (hovered !== registered.gazeHovered) {\n registered.gazeHovered = hovered;\n this.events.emit({\n type: hovered ? \"hoverEnter\" : \"hoverExit\",\n interactableId: id,\n interactorId: gazeId,\n });\n }\n if (registered.dwellConfig && registered.enabled) {\n const tick = registered.dwell.update(hovered, dt, registered.dwellConfig);\n if (tick.changed) {\n this.events.emit({\n type: \"dwellProgress\",\n interactableId: id,\n interactorId: gazeId,\n value: tick.progress,\n });\n }\n if (tick.fired) {\n // A completed dwell is a synthesized click: press + release.\n const info: InteractorInfo = { id: gazeId, kind: \"gaze\", select: 1, squeeze: 0 };\n this.routePressStart(id, registered, info);\n this.routePressEnd(id, gazeId, { ...info, select: 0 });\n this.feedbackEmitter.emit({\n cue: \"dwellComplete\",\n interactableId: id,\n intensity: 0.6,\n durationMs: 50,\n });\n }\n }\n }\n }\n\n private tickBehaviours(sources: readonly InputSourceSnapshot[], dt: number): void {\n const bySourceId = new Map(sources.map((s) => [s.id, s]));\n for (const [id, registered] of this.interactables) {\n if (!registered.enabled) continue;\n const holderSource = registered.grabbedBy ? bySourceId.get(registered.grabbedBy) : undefined;\n const holder = holderSource ? this.interactorInfo(holderSource) : undefined;\n const ctx = this.contextFor(id, registered, dt);\n for (const slot of registered.behaviours) {\n if (slot.disabled) continue;\n slot.instance.update(ctx, slot.instance.grabbable ? holder : undefined);\n }\n }\n }\n\n private contextFor(id: string, registered: Registered, dt: number) {\n return {\n dt,\n interactableId: id,\n transform: registered.transform,\n emit: (event: Omit<InteractionEvent, \"interactableId\">) =>\n this.events.emit({ ...event, interactableId: id }),\n feedback: (intent: Omit<FeedbackIntent, \"interactableId\">) =>\n this.feedbackEmitter.emit({ ...intent, interactableId: id }),\n getWorldPose: (otherId: string) =>\n this.interactables.get(otherId)?.transform?.getWorldPose(),\n };\n }\n\n private renegotiate(id: string, registered: Registered): void {\n const fulfilment = this.capabilities.grabs === \"native\" ? \"native\" : \"poseOnly\";\n for (const slot of registered.behaviours) {\n if (slot.instance instanceof GrabBehaviour) {\n slot.instance.setFulfilment(fulfilment);\n }\n const unmet = [...unmetRequirements(this.capabilities, slot.instance.requires)];\n for (const group of slot.instance.requiresAnyOf ?? []) {\n if (group.length > 0 && unmetRequirements(this.capabilities, group).length === group.length) {\n unmet.push(group[0]!);\n }\n }\n const disabled = unmet.length > 0;\n if (disabled !== slot.disabled) {\n slot.disabled = disabled;\n slot.disabledReason = disabled ? `unmet input capabilities: ${unmet.join(\", \")}` : \"\";\n this.events.emit({\n type: disabled ? \"behaviourDisabled\" : \"behaviourEnabled\",\n interactableId: id,\n behaviourKind: slot.instance.kind,\n ...(disabled ? { reason: slot.disabledReason } : {}),\n });\n }\n }\n }\n\n private renegotiateAll(): void {\n for (const [id, registered] of this.interactables) {\n this.renegotiate(id, registered);\n }\n }\n}\n\n/** Build a runtime's interactables from a portable descriptor. */\nexport function registerDescriptor(\n runtime: InteractionRuntime,\n descriptor: { interactables: InteractableDescriptor[] },\n portsFor: (id: string) => RegisterPorts = () => ({}),\n): void {\n for (const interactable of descriptor.interactables) {\n runtime.registerInteractable(interactable, portsFor(interactable.id));\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * InteractionRuntime - the engine-free orchestrator.\n *\n * Once per host frame the runtime pulls the input provider, resolves\n * targeting (provider hints first - provider power wins - then poke\n * proximity, then ray hits), applies press/grab transitions with\n * hysteresis, runs gaze gating + dwell, ticks every behaviour, and emits\n * interaction events and feedback intents. It never touches an engine:\n * space queries and transform writes go through the adapter-implemented\n * {@link HitTester} and {@link TransformPort}.\n *\n * Lifecycle is first-class (the pale-signal gap): interactables register,\n * unregister, enable and disable; behaviours disabled by capability\n * negotiation announce themselves with a `behaviourDisabled` event.\n */\nimport {\n SELECT_PRESS_THRESHOLD,\n SELECT_RELEASE_THRESHOLD,\n unmetRequirements,\n type InputCapabilities,\n type InputHitHint,\n type InputProvider,\n type InputSourceSnapshot,\n type PoseTuple,\n type RayTuple,\n type Unsubscribe,\n} from \"@realitycollective/webxr-input\";\nimport type { Behaviour, InteractorInfo } from \"./behaviours/behaviour.js\";\nimport {\n createBehaviour,\n type BehaviourConfig,\n type BehaviourFactoryContext,\n} from \"./behaviours/factory.js\";\nimport { GrabBehaviour } from \"./behaviours/grab.js\";\nimport type { InteractableDescriptor } from \"./descriptor.js\";\nimport { Emitter, type InteractionEvent, type InteractionEventListener } from \"./events.js\";\nimport type { FeedbackIntent, FeedbackListener } from \"./feedback.js\";\nimport { DwellState, resolveDwellConfig, DWELL_DEFAULTS, type DwellConfig } from \"./gaze.js\";\nimport { vApplyQuat } from \"./math.js\";\nimport type { HitTester, TransformPort } from \"./ports.js\";\nimport { VelocityTracker, type VelocityTrackerOptions } from \"./velocity-tracker.js\";\n\nconst DEFAULT_POKE_RADIUS = 0.05;\n/** Interactor id used when gaze is synthesized from the head pose. */\nexport const HEAD_GAZE_INTERACTOR_ID = \"head-gaze\";\n\nexport interface InteractableState {\n id: string;\n enabled: boolean;\n hovered: boolean;\n gazeHovered: boolean;\n pressed: boolean;\n grabbed: boolean;\n /** Primary behaviour's logical value. */\n value: number;\n /** Gaze-dwell meter 0..1 (0 when dwell is not enabled). */\n dwell: number;\n}\n\ninterface BehaviourSlot {\n instance: Behaviour;\n config: BehaviourConfig;\n disabled: boolean;\n disabledReason: string;\n}\n\ninterface Registered {\n def: InteractableDescriptor;\n behaviours: BehaviourSlot[];\n transform: TransformPort | undefined;\n enabled: boolean;\n pokeRadius: number;\n gazeRequired: boolean;\n dwellConfig: Required<DwellConfig> | null;\n dwell: DwellState;\n gazeHovered: boolean;\n hoveredBy: Set<string>;\n pressedBy: Set<string>;\n grabbedBy: string | null;\n}\n\ninterface SourceRuntimeState {\n hoverTarget: string | null;\n pressed: boolean;\n pressTarget: string | null;\n grabbed: boolean;\n grabTarget: string | null;\n}\n\nexport interface InteractionRuntimeOptions {\n provider: InputProvider;\n hitTester?: HitTester;\n dwellDefaults?: DwellConfig;\n /**\n * Per-source velocity tracking. On by default with no smoothing; pass\n * `false` to skip it, or options to smooth. The tracker only fills in\n * what the provider did not supply.\n */\n velocity?: VelocityTrackerOptions | false;\n}\n\nexport interface RegisterPorts {\n transform?: TransformPort;\n}\n\nexport class InteractionRuntime {\n private readonly provider: InputProvider;\n private hitTester: HitTester | null;\n private readonly dwellDefaults: Required<DwellConfig>;\n\n private readonly interactables = new Map<string, Registered>();\n private readonly sourceStates = new Map<string, SourceRuntimeState>();\n private readonly events = new Emitter<InteractionEvent>();\n private readonly feedbackEmitter = new Emitter<FeedbackIntent>();\n private readonly afterSample = new Emitter<readonly InputSourceSnapshot[]>();\n private readonly velocityTracker: VelocityTracker | null;\n private lastSources = new Map<string, InputSourceSnapshot>();\n private capabilities: InputCapabilities;\n private readonly unsubscribeCaps: Unsubscribe;\n private disposed = false;\n\n constructor(options: InteractionRuntimeOptions) {\n this.provider = options.provider;\n this.hitTester = options.hitTester ?? null;\n const d = options.dwellDefaults;\n this.dwellDefaults = {\n holdSeconds: d?.holdSeconds ?? DWELL_DEFAULTS.holdSeconds,\n decayFactor: d?.decayFactor ?? DWELL_DEFAULTS.decayFactor,\n rearmBelow: d?.rearmBelow ?? DWELL_DEFAULTS.rearmBelow,\n };\n this.velocityTracker =\n options.velocity === false ? null : new VelocityTracker(options.velocity ?? {});\n this.capabilities = this.provider.getCapabilities();\n this.unsubscribeCaps = this.provider.onCapabilitiesChanged((caps) => {\n this.capabilities = caps;\n this.renegotiateAll();\n });\n }\n\n // -- registry -------------------------------------------------------------\n\n registerInteractable(def: InteractableDescriptor, ports: RegisterPorts = {}): void {\n if (this.interactables.has(def.id)) {\n throw new Error(`Interactable \"${def.id}\" is already registered`);\n }\n const context: BehaviourFactoryContext = {\n grabFulfilment: this.capabilities.grabs === \"native\" ? \"native\" : \"poseOnly\",\n };\n const registered: Registered = {\n def,\n behaviours: def.behaviours.map((config) => ({\n instance: createBehaviour(config, context),\n config,\n disabled: false,\n disabledReason: \"\",\n })),\n transform: ports.transform,\n enabled: def.enabled !== false,\n pokeRadius: def.pokeRadius ?? DEFAULT_POKE_RADIUS,\n gazeRequired: def.gaze?.required === true,\n dwellConfig: resolveDwellConfig(def.gaze?.dwell, this.dwellDefaults),\n dwell: new DwellState(),\n gazeHovered: false,\n hoveredBy: new Set(),\n pressedBy: new Set(),\n grabbedBy: null,\n };\n this.interactables.set(def.id, registered);\n this.renegotiate(def.id, registered);\n }\n\n unregisterInteractable(id: string): void {\n const registered = this.interactables.get(id);\n if (!registered) return;\n this.releaseAllHolds(id);\n this.interactables.delete(id);\n }\n\n setInteractableEnabled(id: string, enabled: boolean): void {\n const registered = this.interactables.get(id);\n if (!registered || registered.enabled === enabled) return;\n registered.enabled = enabled;\n if (!enabled) this.releaseAllHolds(id);\n this.events.emit({\n type: enabled ? \"interactableEnabled\" : \"interactableDisabled\",\n interactableId: id,\n });\n }\n\n setHitTester(hitTester: HitTester | null): void {\n this.hitTester = hitTester;\n }\n\n /** Reach a live behaviour instance for tuning (playground steppers). */\n getBehaviour<T extends Behaviour = Behaviour>(interactableId: string, kind: string): T | undefined {\n const registered = this.interactables.get(interactableId);\n return registered?.behaviours.find((b) => b.instance.kind === kind)?.instance as T | undefined;\n }\n\n getState(id: string): InteractableState | undefined {\n const r = this.interactables.get(id);\n if (!r) return undefined;\n const primary = r.behaviours.find((b) => !b.disabled)?.instance;\n return {\n id,\n enabled: r.enabled,\n hovered: r.hoveredBy.size > 0 || r.gazeHovered,\n gazeHovered: r.gazeHovered,\n pressed: r.pressedBy.size > 0,\n grabbed: r.grabbedBy !== null,\n value: primary?.getValue() ?? 0,\n dwell: r.dwell.getProgress(),\n };\n }\n\n getInteractableIds(): string[] {\n return [...this.interactables.keys()];\n }\n\n // -- subscriptions ----------------------------------------------------------\n\n onEvent(listener: InteractionEventListener): Unsubscribe {\n return this.events.subscribe(listener);\n }\n\n onFeedback(listener: FeedbackListener): Unsubscribe {\n return this.feedbackEmitter.subscribe(listener);\n }\n\n /**\n * Sampled sources for this frame - the UI Extensions pointer bridge hook.\n *\n * @deprecated Use {@link onSample}. Both deliver the same stream: since\n * `@realitycollective/webxr-input` 0.1.1 carries `linearVelocity` and\n * `angularVelocity` on `InputSourceSnapshot`, the two signatures are\n * identical and only one name is needed. This one is kept so existing\n * callers keep working and will be removed in a later major release.\n */\n onSourcesSampled(listener: (sources: readonly InputSourceSnapshot[]) => void): Unsubscribe {\n return this.afterSample.subscribe(listener);\n }\n\n /** This frame's sources, velocity included. */\n onSample(listener: (sources: readonly InputSourceSnapshot[]) => void): Unsubscribe {\n return this.afterSample.subscribe(listener);\n }\n\n /**\n * The last sample of one source, velocity included. Undefined before the\n * first update, and once the source stops reporting.\n */\n getSource(id: string): InputSourceSnapshot | undefined {\n return this.lastSources.get(id);\n }\n\n getCapabilities(): InputCapabilities {\n return this.capabilities;\n }\n\n getProvider(): InputProvider {\n return this.provider;\n }\n\n // -- frame ------------------------------------------------------------------\n\n update(dt: number): void {\n if (this.disposed) return;\n const sampled = this.provider.sample();\n const sources = this.velocityTracker ? this.velocityTracker.update(sampled, dt) : sampled;\n const hints = this.provider.sampleHints?.() ?? [];\n this.lastSources = new Map(sources.map((source) => [source.id, source]));\n this.afterSample.emit(sources);\n\n const hintBySource = new Map<string, InputHitHint[]>();\n for (const hint of hints) {\n const list = hintBySource.get(hint.sourceId);\n if (list) list.push(hint);\n else hintBySource.set(hint.sourceId, [hint]);\n }\n\n const seen = new Set<string>();\n for (const source of sources) {\n seen.add(source.id);\n this.updateSource(source, hintBySource.get(source.id) ?? []);\n }\n // Sources that vanished mid-hold release everything they held.\n for (const [id, state] of this.sourceStates) {\n if (!seen.has(id)) {\n this.forceRelease(id, state);\n this.sourceStates.delete(id);\n }\n }\n\n this.updateGaze(sources, dt);\n this.tickBehaviours(sources, dt);\n }\n\n dispose(): void {\n this.disposed = true;\n this.unsubscribeCaps();\n this.interactables.clear();\n this.sourceStates.clear();\n this.lastSources.clear();\n this.velocityTracker?.reset();\n }\n\n // -- internals ---------------------------------------------------------------\n\n private sourceState(id: string): SourceRuntimeState {\n let state = this.sourceStates.get(id);\n if (!state) {\n state = { hoverTarget: null, pressed: false, pressTarget: null, grabbed: false, grabTarget: null };\n this.sourceStates.set(id, state);\n }\n return state;\n }\n\n private interactorInfo(source: InputSourceSnapshot): InteractorInfo {\n const info: InteractorInfo = {\n id: source.id,\n kind: source.kind,\n select: source.select,\n squeeze: source.squeeze,\n };\n if (source.ray) info.ray = source.ray;\n if (source.gripPose) info.gripPose = source.gripPose;\n if (source.indexTip) info.indexTip = source.indexTip;\n return info;\n }\n\n /** Resolve this source's target: hints beat poke beats ray. */\n private resolveTarget(source: InputSourceSnapshot, hints: InputHitHint[]): string | null {\n const hint =\n hints.find((h) => h.state === \"grab\") ??\n hints.find((h) => h.state === \"press\") ??\n hints.find((h) => h.state === \"hover\");\n if (hint && this.targetable(hint.targetId)) return hint.targetId;\n if (source.indexTip && this.hitTester) {\n const poke = this.hitTester.hitProximity(source.indexTip, DEFAULT_POKE_RADIUS);\n if (poke && this.targetable(poke.interactableId)) return poke.interactableId;\n }\n if (source.ray && this.hitTester) {\n const hit = this.hitTester.hitRay(source.ray);\n if (hit && this.targetable(hit.interactableId)) return hit.interactableId;\n }\n return null;\n }\n\n private targetable(id: string): boolean {\n const registered = this.interactables.get(id);\n return registered !== undefined && registered.enabled;\n }\n\n private flags(registered: Registered): { pressable: boolean; grabbable: boolean } {\n let pressable = false;\n let grabbable = false;\n for (const slot of registered.behaviours) {\n if (slot.disabled) continue;\n if (slot.instance.onPressStart) pressable = true;\n if (slot.instance.grabbable) grabbable = true;\n }\n return { pressable, grabbable };\n }\n\n private updateSource(source: InputSourceSnapshot, hints: InputHitHint[]): void {\n const state = this.sourceState(source.id);\n const target = this.resolveTarget(source, hints);\n\n // Hover transitions.\n if (state.hoverTarget !== target) {\n if (state.hoverTarget) this.setHover(state.hoverTarget, source.id, false);\n if (target) this.setHover(target, source.id, true);\n state.hoverTarget = target;\n }\n\n const registered = target ? this.interactables.get(target) : undefined;\n const roles = registered ? this.flags(registered) : { pressable: false, grabbable: false };\n\n // Signal resolution. A pinching hand (or a 2D pointer click) acts as a\n // grab when the target is grab-only; controllers keep trigger=press,\n // squeeze=grab.\n const selectAsGrab = roles.grabbable && !roles.pressable && source.kind !== \"controller\";\n const pressSignal = selectAsGrab ? 0 : source.select;\n const grabSignal = Math.max(source.squeeze, selectAsGrab ? source.select : 0);\n\n const hintPress = hints.some((h) => h.state === \"press\");\n const hintGrab = hints.some((h) => h.state === \"grab\") || source.nativeGrabbing === true;\n\n // Press with hysteresis (hints override).\n const pressActive = hintPress || (state.pressed\n ? pressSignal > SELECT_RELEASE_THRESHOLD\n : pressSignal >= SELECT_PRESS_THRESHOLD);\n if (pressActive && !state.pressed) {\n state.pressed = true;\n if (target && registered && roles.pressable && this.gazeAllows(registered)) {\n state.pressTarget = target;\n this.routePressStart(target, registered, this.interactorInfo(source));\n }\n } else if (!pressActive && state.pressed) {\n state.pressed = false;\n if (state.pressTarget) {\n this.routePressEnd(state.pressTarget, source.id, this.interactorInfo(source));\n state.pressTarget = null;\n }\n }\n\n // Grab with hysteresis (hints / native grabbing override).\n const grabActive = hintGrab || (state.grabbed\n ? grabSignal > SELECT_RELEASE_THRESHOLD\n : grabSignal >= SELECT_PRESS_THRESHOLD);\n if (grabActive && !state.grabbed) {\n state.grabbed = true;\n const hintTargetId = hints.find((h) => h.state === \"grab\")?.targetId;\n const grabTargetId = hintTargetId && this.targetable(hintTargetId) ? hintTargetId : target;\n const grabTarget = grabTargetId ? this.interactables.get(grabTargetId) : undefined;\n if (\n grabTargetId &&\n grabTarget &&\n this.flags(grabTarget).grabbable &&\n grabTarget.grabbedBy === null &&\n this.gazeAllows(grabTarget)\n ) {\n state.grabTarget = grabTargetId;\n grabTarget.grabbedBy = source.id;\n const info = this.interactorInfo(source);\n for (const slot of grabTarget.behaviours) {\n if (!slot.disabled && slot.instance.grabbable) {\n slot.instance.onGrabStart?.(this.contextFor(grabTargetId, grabTarget, 0), info);\n }\n }\n }\n } else if (!grabActive && state.grabbed) {\n state.grabbed = false;\n if (state.grabTarget) {\n this.endGrab(state.grabTarget, source.id, this.interactorInfo(source));\n state.grabTarget = null;\n }\n }\n }\n\n private gazeAllows(registered: Registered): boolean {\n return !registered.gazeRequired || registered.gazeHovered;\n }\n\n private setHover(id: string, sourceId: string, hovered: boolean): void {\n const registered = this.interactables.get(id);\n if (!registered) return;\n if (hovered) {\n registered.hoveredBy.add(sourceId);\n if (registered.hoveredBy.size === 1) {\n this.events.emit({ type: \"hoverEnter\", interactableId: id, interactorId: sourceId });\n this.feedbackEmitter.emit({\n cue: \"hover\",\n interactableId: id,\n sourceId,\n intensity: 0.1,\n durationMs: 10,\n });\n }\n } else {\n registered.hoveredBy.delete(sourceId);\n if (registered.hoveredBy.size === 0) {\n this.events.emit({ type: \"hoverExit\", interactableId: id, interactorId: sourceId });\n }\n }\n }\n\n private routePressStart(id: string, registered: Registered, info: InteractorInfo): void {\n registered.pressedBy.add(info.id);\n this.events.emit({ type: \"pressStart\", interactableId: id, interactorId: info.id });\n const ctx = this.contextFor(id, registered, 0);\n for (const slot of registered.behaviours) {\n if (!slot.disabled) slot.instance.onPressStart?.(ctx, info);\n }\n }\n\n private routePressEnd(id: string, sourceId: string, info: InteractorInfo): void {\n const registered = this.interactables.get(id);\n if (!registered) return;\n registered.pressedBy.delete(sourceId);\n this.events.emit({ type: \"pressEnd\", interactableId: id, interactorId: sourceId });\n const ctx = this.contextFor(id, registered, 0);\n for (const slot of registered.behaviours) {\n if (!slot.disabled) slot.instance.onPressEnd?.(ctx, info);\n }\n }\n\n private endGrab(id: string, sourceId: string, info: InteractorInfo): void {\n const registered = this.interactables.get(id);\n if (!registered || registered.grabbedBy !== sourceId) return;\n registered.grabbedBy = null;\n const ctx = this.contextFor(id, registered, 0);\n for (const slot of registered.behaviours) {\n if (!slot.disabled && slot.instance.grabbable) slot.instance.onGrabEnd?.(ctx, info);\n }\n }\n\n private forceRelease(sourceId: string, state: SourceRuntimeState): void {\n const info: InteractorInfo = { id: sourceId, kind: \"other\", select: 0, squeeze: 0 };\n if (state.pressTarget) this.routePressEnd(state.pressTarget, sourceId, info);\n if (state.grabTarget) this.endGrab(state.grabTarget, sourceId, info);\n if (state.hoverTarget) this.setHover(state.hoverTarget, sourceId, false);\n }\n\n private releaseAllHolds(id: string): void {\n for (const [sourceId, state] of this.sourceStates) {\n if (state.pressTarget === id) {\n this.routePressEnd(id, sourceId, { id: sourceId, kind: \"other\", select: 0, squeeze: 0 });\n state.pressTarget = null;\n state.pressed = false;\n }\n if (state.grabTarget === id) {\n this.endGrab(id, sourceId, { id: sourceId, kind: \"other\", select: 0, squeeze: 0 });\n state.grabTarget = null;\n state.grabbed = false;\n }\n if (state.hoverTarget === id) {\n this.setHover(id, sourceId, false);\n state.hoverTarget = null;\n }\n }\n }\n\n private updateGaze(sources: readonly InputSourceSnapshot[], dt: number): void {\n let gazeRay: RayTuple | null = null;\n let gazeId = HEAD_GAZE_INTERACTOR_ID;\n const gazeSource = sources.find((s) => s.kind === \"gaze\");\n if (gazeSource?.ray) {\n gazeRay = gazeSource.ray;\n gazeId = gazeSource.id;\n } else if (this.capabilities.headPose && this.provider.getHeadPose) {\n const head: PoseTuple = this.provider.getHeadPose();\n gazeRay = {\n origin: head.position,\n direction: vApplyQuat([0, 0, -1], head.quaternion),\n };\n }\n\n const gazeTarget =\n gazeRay && this.hitTester ? this.hitTester.hitRay(gazeRay)?.interactableId ?? null : null;\n\n for (const [id, registered] of this.interactables) {\n const hovered = registered.enabled && gazeTarget === id;\n if (hovered !== registered.gazeHovered) {\n registered.gazeHovered = hovered;\n this.events.emit({\n type: hovered ? \"hoverEnter\" : \"hoverExit\",\n interactableId: id,\n interactorId: gazeId,\n });\n }\n if (registered.dwellConfig && registered.enabled) {\n const tick = registered.dwell.update(hovered, dt, registered.dwellConfig);\n if (tick.changed) {\n this.events.emit({\n type: \"dwellProgress\",\n interactableId: id,\n interactorId: gazeId,\n value: tick.progress,\n });\n }\n if (tick.fired) {\n // A completed dwell is a synthesized click: press + release.\n const info: InteractorInfo = { id: gazeId, kind: \"gaze\", select: 1, squeeze: 0 };\n this.routePressStart(id, registered, info);\n this.routePressEnd(id, gazeId, { ...info, select: 0 });\n this.feedbackEmitter.emit({\n cue: \"dwellComplete\",\n interactableId: id,\n intensity: 0.6,\n durationMs: 50,\n });\n }\n }\n }\n }\n\n private tickBehaviours(sources: readonly InputSourceSnapshot[], dt: number): void {\n const bySourceId = new Map(sources.map((s) => [s.id, s]));\n for (const [id, registered] of this.interactables) {\n if (!registered.enabled) continue;\n const holderSource = registered.grabbedBy ? bySourceId.get(registered.grabbedBy) : undefined;\n const holder = holderSource ? this.interactorInfo(holderSource) : undefined;\n const ctx = this.contextFor(id, registered, dt);\n for (const slot of registered.behaviours) {\n if (slot.disabled) continue;\n slot.instance.update(ctx, slot.instance.grabbable ? holder : undefined);\n }\n }\n }\n\n private contextFor(id: string, registered: Registered, dt: number) {\n return {\n dt,\n interactableId: id,\n transform: registered.transform,\n emit: (event: Omit<InteractionEvent, \"interactableId\">) =>\n this.events.emit({ ...event, interactableId: id }),\n feedback: (intent: Omit<FeedbackIntent, \"interactableId\">) =>\n this.feedbackEmitter.emit({ ...intent, interactableId: id }),\n getWorldPose: (otherId: string) =>\n this.interactables.get(otherId)?.transform?.getWorldPose(),\n };\n }\n\n private renegotiate(id: string, registered: Registered): void {\n const fulfilment = this.capabilities.grabs === \"native\" ? \"native\" : \"poseOnly\";\n for (const slot of registered.behaviours) {\n if (slot.instance instanceof GrabBehaviour) {\n slot.instance.setFulfilment(fulfilment);\n }\n const unmet = [...unmetRequirements(this.capabilities, slot.instance.requires)];\n for (const group of slot.instance.requiresAnyOf ?? []) {\n if (group.length > 0 && unmetRequirements(this.capabilities, group).length === group.length) {\n unmet.push(group[0]!);\n }\n }\n const disabled = unmet.length > 0;\n if (disabled !== slot.disabled) {\n slot.disabled = disabled;\n slot.disabledReason = disabled ? `unmet input capabilities: ${unmet.join(\", \")}` : \"\";\n this.events.emit({\n type: disabled ? \"behaviourDisabled\" : \"behaviourEnabled\",\n interactableId: id,\n behaviourKind: slot.instance.kind,\n ...(disabled ? { reason: slot.disabledReason } : {}),\n });\n }\n }\n }\n\n private renegotiateAll(): void {\n for (const [id, registered] of this.interactables) {\n this.renegotiate(id, registered);\n }\n }\n}\n\n/** Build a runtime's interactables from a portable descriptor. */\nexport function registerDescriptor(\n runtime: InteractionRuntime,\n descriptor: { interactables: InteractableDescriptor[] },\n portsFor: (id: string) => RegisterPorts = () => ({}),\n): void {\n for (const interactable of descriptor.interactables) {\n runtime.registerInteractable(interactable, portsFor(interactable.id));\n }\n}\n"]}
|
|
@@ -13,18 +13,7 @@
|
|
|
13
13
|
* that frame, so a reconnecting controller cannot report a metres-per-
|
|
14
14
|
* second jump from wherever it was last seen.
|
|
15
15
|
*/
|
|
16
|
-
import type
|
|
17
|
-
/**
|
|
18
|
-
* A sampled source carrying the velocity the tracker measured.
|
|
19
|
-
* Collapses into `InputSourceSnapshot` in
|
|
20
|
-
* `@realitycollective/webxr-input` 0.1.1, which adds these two fields.
|
|
21
|
-
*/
|
|
22
|
-
export type InputSourceSnapshotWithVelocity = InputSourceSnapshot & {
|
|
23
|
-
/** Metres per second, world space. */
|
|
24
|
-
linearVelocity?: Vec3Tuple;
|
|
25
|
-
/** Radians per second about each world axis. */
|
|
26
|
-
angularVelocity?: Vec3Tuple;
|
|
27
|
-
};
|
|
16
|
+
import { type InputSourceSnapshot } from "@realitycollective/webxr-input";
|
|
28
17
|
export interface VelocityTrackerOptions {
|
|
29
18
|
/**
|
|
30
19
|
* Exponential moving average factor in `(0, 1]`. 1 (the default) is no
|
|
@@ -43,7 +32,7 @@ export declare class VelocityTracker {
|
|
|
43
32
|
* added to those the provider left without it. Sources with no grip pose
|
|
44
33
|
* pass through untouched and hold no state.
|
|
45
34
|
*/
|
|
46
|
-
update(sources: readonly InputSourceSnapshot[], dt: number): readonly
|
|
35
|
+
update(sources: readonly InputSourceSnapshot[], dt: number): readonly InputSourceSnapshot[];
|
|
47
36
|
/** Forget every tracked source (session end, teleport, scene change). */
|
|
48
37
|
reset(): void;
|
|
49
38
|
}
|
package/dist/velocity-tracker.js
CHANGED
|
@@ -1,4 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* VelocityTracker - per-source linear and angular velocity, derived from
|
|
3
|
+
* consecutive grip poses.
|
|
4
|
+
*
|
|
5
|
+
* Throw, flick and swipe all need to know how fast a hand was moving at
|
|
6
|
+
* the moment it let go. WebXR does not report that, and most engines do
|
|
7
|
+
* not either, so the core differentiates the poses it already samples.
|
|
8
|
+
* A provider that CAN report velocity keeps its own numbers - the tracker
|
|
9
|
+
* only fills gaps.
|
|
10
|
+
*
|
|
11
|
+
* The tracker is deliberately conservative. A source seen for the first
|
|
12
|
+
* time (or seen again after dropping out of tracking) gets no velocity
|
|
13
|
+
* that frame, so a reconnecting controller cannot report a metres-per-
|
|
14
|
+
* second jump from wherever it was last seen.
|
|
15
|
+
*/
|
|
16
|
+
import { velocityBetween, } from "@realitycollective/webxr-input";
|
|
2
17
|
const DEFAULT_SMOOTHING = 1;
|
|
3
18
|
export class VelocityTracker {
|
|
4
19
|
smoothing;
|
|
@@ -35,7 +50,7 @@ export class VelocityTracker {
|
|
|
35
50
|
out.push(source);
|
|
36
51
|
continue;
|
|
37
52
|
}
|
|
38
|
-
const raw =
|
|
53
|
+
const raw = velocityBetween(previous.pose, pose, dt);
|
|
39
54
|
const linear = smooth(previous.linear, raw.linear, this.smoothing);
|
|
40
55
|
const angular = smooth(previous.angular, raw.angular, this.smoothing);
|
|
41
56
|
stored.linear = linear;
|
|
@@ -43,15 +58,14 @@ export class VelocityTracker {
|
|
|
43
58
|
this.tracked.set(source.id, stored);
|
|
44
59
|
// The provider's own numbers always win - it may have them from the
|
|
45
60
|
// platform, which knows better than a difference of two samples.
|
|
46
|
-
const
|
|
47
|
-
const
|
|
48
|
-
const needsAngular = supplied.angularVelocity === undefined;
|
|
61
|
+
const needsLinear = source.linearVelocity === undefined;
|
|
62
|
+
const needsAngular = source.angularVelocity === undefined;
|
|
49
63
|
if (!needsLinear && !needsAngular) {
|
|
50
64
|
out.push(source);
|
|
51
65
|
continue;
|
|
52
66
|
}
|
|
53
67
|
out.push({
|
|
54
|
-
...
|
|
68
|
+
...source,
|
|
55
69
|
...(needsLinear ? { linearVelocity: linear } : {}),
|
|
56
70
|
...(needsAngular ? { angularVelocity: angular } : {}),
|
|
57
71
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"velocity-tracker.js","sourceRoot":"","sources":["../src/velocity-tracker.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"velocity-tracker.js","sourceRoot":"","sources":["../src/velocity-tracker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EACL,eAAe,GAIhB,MAAM,gCAAgC,CAAC;AAkBxC,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAE5B,MAAM,OAAO,eAAe;IACT,SAAS,CAAS;IAClB,OAAO,GAAG,IAAI,GAAG,EAAmB,CAAC;IAEtD,YAAY,UAAkC,EAAE;QAC9C,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,iBAAiB,CAAC;QACzD,IAAI,CAAC,SAAS,GAAG,SAAS,GAAG,CAAC,IAAI,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,CAAC;IACnF,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,OAAuC,EAAE,EAAU;QACxD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,MAAM,GAAG,GAA0B,EAAE,CAAC;QAEtC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC;YAC7B,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACjB,SAAS;YACX,CAAC;YACD,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACpB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC7C,MAAM,MAAM,GAAY;gBACtB,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE;gBAC9D,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,IAAI;gBAChC,OAAO,EAAE,QAAQ,EAAE,OAAO,IAAI,IAAI;aACnC,CAAC;YAEF,sEAAsE;YACtE,uEAAuE;YACvE,IAAI,QAAQ,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;gBAC9D,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;gBACpC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACjB,SAAS;YACX,CAAC;YAED,MAAM,GAAG,GAAG,eAAe,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;YACrD,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;YACnE,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;YACtE,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;YACvB,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;YACzB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;YAEpC,oEAAoE;YACpE,iEAAiE;YACjE,MAAM,WAAW,GAAG,MAAM,CAAC,cAAc,KAAK,SAAS,CAAC;YACxD,MAAM,YAAY,GAAG,MAAM,CAAC,eAAe,KAAK,SAAS,CAAC;YAC1D,IAAI,CAAC,WAAW,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACjB,SAAS;YACX,CAAC;YACD,GAAG,CAAC,IAAI,CAAC;gBACP,GAAG,MAAM;gBACT,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAClD,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACtD,CAAC,CAAC;QACL,CAAC;QAED,mEAAmE;QACnE,KAAK,MAAM,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YAC1C,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,yEAAyE;IACzE,KAAK;QACH,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;CACF;AAED,SAAS,MAAM,CAAC,QAA0B,EAAE,GAAc,EAAE,MAAc;IACxE,IAAI,QAAQ,KAAK,IAAI,IAAI,MAAM,IAAI,CAAC;QAAE,OAAO,GAAG,CAAC;IACjD,OAAO;QACL,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM;QAC7C,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM;QAC7C,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM;KAC9C,CAAC;AACJ,CAAC","sourcesContent":["/**\n * VelocityTracker - per-source linear and angular velocity, derived from\n * consecutive grip poses.\n *\n * Throw, flick and swipe all need to know how fast a hand was moving at\n * the moment it let go. WebXR does not report that, and most engines do\n * not either, so the core differentiates the poses it already samples.\n * A provider that CAN report velocity keeps its own numbers - the tracker\n * only fills gaps.\n *\n * The tracker is deliberately conservative. A source seen for the first\n * time (or seen again after dropping out of tracking) gets no velocity\n * that frame, so a reconnecting controller cannot report a metres-per-\n * second jump from wherever it was last seen.\n */\nimport {\n velocityBetween,\n type InputSourceSnapshot,\n type PoseTuple,\n type Vec3Tuple,\n} from \"@realitycollective/webxr-input\";\n\nexport interface VelocityTrackerOptions {\n /**\n * Exponential moving average factor in `(0, 1]`. 1 (the default) is no\n * smoothing - every frame reports the raw difference. Lower values trade\n * responsiveness for steadiness; 0.3 is a reasonable starting point when\n * the pose stream is noisy.\n */\n smoothing?: number;\n}\n\ninterface Tracked {\n pose: PoseTuple;\n linear: Vec3Tuple | null;\n angular: Vec3Tuple | null;\n}\n\nconst DEFAULT_SMOOTHING = 1;\n\nexport class VelocityTracker {\n private readonly smoothing: number;\n private readonly tracked = new Map<string, Tracked>();\n\n constructor(options: VelocityTrackerOptions = {}) {\n const smoothing = options.smoothing ?? DEFAULT_SMOOTHING;\n this.smoothing = smoothing > 0 && smoothing <= 1 ? smoothing : DEFAULT_SMOOTHING;\n }\n\n /**\n * Measure this frame's sources. Returns the same sources, with velocity\n * added to those the provider left without it. Sources with no grip pose\n * pass through untouched and hold no state.\n */\n update(sources: readonly InputSourceSnapshot[], dt: number): readonly InputSourceSnapshot[] {\n const seen = new Set<string>();\n const out: InputSourceSnapshot[] = [];\n\n for (const source of sources) {\n const pose = source.gripPose;\n if (!pose) {\n out.push(source);\n continue;\n }\n seen.add(source.id);\n const previous = this.tracked.get(source.id);\n const stored: Tracked = {\n pose: { position: pose.position, quaternion: pose.quaternion },\n linear: previous?.linear ?? null,\n angular: previous?.angular ?? null,\n };\n\n // First sighting, or a frame with no elapsed time: store the pose and\n // report nothing. Differentiating either would be a fabricated number.\n if (previous === undefined || !Number.isFinite(dt) || dt <= 0) {\n this.tracked.set(source.id, stored);\n out.push(source);\n continue;\n }\n\n const raw = velocityBetween(previous.pose, pose, dt);\n const linear = smooth(previous.linear, raw.linear, this.smoothing);\n const angular = smooth(previous.angular, raw.angular, this.smoothing);\n stored.linear = linear;\n stored.angular = angular;\n this.tracked.set(source.id, stored);\n\n // The provider's own numbers always win - it may have them from the\n // platform, which knows better than a difference of two samples.\n const needsLinear = source.linearVelocity === undefined;\n const needsAngular = source.angularVelocity === undefined;\n if (!needsLinear && !needsAngular) {\n out.push(source);\n continue;\n }\n out.push({\n ...source,\n ...(needsLinear ? { linearVelocity: linear } : {}),\n ...(needsAngular ? { angularVelocity: angular } : {}),\n });\n }\n\n // A source that stopped reporting starts fresh when it comes back.\n for (const id of [...this.tracked.keys()]) {\n if (!seen.has(id)) this.tracked.delete(id);\n }\n return out;\n }\n\n /** Forget every tracked source (session end, teleport, scene change). */\n reset(): void {\n this.tracked.clear();\n }\n}\n\nfunction smooth(previous: Vec3Tuple | null, raw: Vec3Tuple, factor: number): Vec3Tuple {\n if (previous === null || factor >= 1) return raw;\n return [\n previous[0] + (raw[0] - previous[0]) * factor,\n previous[1] + (raw[1] - previous[1]) * factor,\n previous[2] + (raw[2] - previous[2]) * factor,\n ];\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@realitycollective/webxr-interactions",
|
|
3
|
-
"version": "0.1.0-preview.
|
|
3
|
+
"version": "0.1.0-preview.3",
|
|
4
4
|
"description": "Engine-free core of the Reality Collective Interaction Extensions: interactables, interactors, behaviours (press, hinge, dial, slide, grab, toss-scoring, pulse, gaze-dwell), capability negotiation and feedback hooks - driven through the shared @realitycollective/webxr-input contracts. Pair with an engine adapter: threejs-interactions, iwsdk-interactions or xrblocks-interactions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"realitycollective",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@realitycollective/webxr-input": "^0.1.
|
|
34
|
+
"@realitycollective/webxr-input": "^0.1.1"
|
|
35
35
|
},
|
|
36
36
|
"repository": {
|
|
37
37
|
"type": "git",
|