@realitycollective/webxr-interactions 0.1.0-preview.3 → 0.1.0-preview.4
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 +7 -0
- package/dist/pointer-bridge.d.ts +5 -0
- package/dist/pointer-bridge.js +5 -0
- package/dist/pointer-bridge.js.map +1 -1
- package/dist/runtime.d.ts +12 -1
- package/dist/runtime.js +12 -1
- package/dist/runtime.js.map +1 -1
- package/dist/velocity-tracker.d.ts +5 -0
- package/dist/velocity-tracker.js +5 -0
- package/dist/velocity-tracker.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -33,11 +33,18 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
|
|
|
33
33
|
|
|
34
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.
|
|
35
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.
|
|
36
|
+
- `@realitycollective/iwsdk-interactions` - the approximate hit tester the bridge keeps for gaze and poke targeting resolves each registered entity's world position once per frame instead of on every query. The core asks it five questions a frame (a poke and a ray test per side, plus the gaze ray) and each one walked every entity's parent chain again through `getWorldPosition`; the bridge now calls `beginFrame()` before the runtime ticks and the five answers come from one resolution. Measured 3.6x to 4x faster on the tester in the gate-1 benchmarks, 32 us to 9 us a frame at 50 entities on desktop, with the same answers. Its ray test also no longer allocates a tuple per entity per query.
|
|
37
|
+
- `@realitycollective/threejs-interactions` - `ThreeHitTester` uses three-mesh-bvh when the app has installed its prototype hooks, which IWSDK does by default: geometries are given a bounds tree as they are registered and the raycaster asks for the first hit only, so a ray against a detailed mesh costs microseconds instead of the near-millisecond a plain triangle walk takes. `three-mesh-bvh` is declared as an optional peer; without it the plain raycast is used and the README explains collider proxies. The roots list handed to the raycaster and the intersections array are now reused between calls rather than built per call, and `hitProximity` reads each object's position and scale straight off its world matrix after one matrix update instead of two updates and a decompose, measured 4x faster at 50 registered objects.
|
|
38
|
+
- `@realitycollective/webxr-interactions` - `onSample`, `getSource` and the pointer bridge document the snapshot ownership rule `@realitycollective/webxr-input` 0.1.3 states: a snapshot handed over is the receiver's to keep and is never written to again. The velocity tracker and the pointer bridge already relied on it.
|
|
36
39
|
|
|
37
40
|
### Deprecated
|
|
38
41
|
|
|
39
42
|
- `@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
43
|
|
|
44
|
+
### Fixed
|
|
45
|
+
|
|
46
|
+
- `@realitycollective/threejs-interactions` - `ThreeHitTester.hitProximity` reported the object's world scale as the hit `point`. The bounding-radius lookup reused the scratch vector holding the world position, so a box at (2, 1, -3) came back with `point: [1, 1, 1]`. The core only reads the id, so targeting was unaffected; anything reading `point` from a proximity hit on three.js or XR Blocks got the wrong answer.
|
|
47
|
+
|
|
41
48
|
### Notes
|
|
42
49
|
|
|
43
50
|
- 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/pointer-bridge.d.ts
CHANGED
|
@@ -9,6 +9,11 @@
|
|
|
9
9
|
* `@realitycollective/webxr-uiextensions`): press-move-release derived
|
|
10
10
|
* from a source's ray + select signal, fed by the runtime's per-frame
|
|
11
11
|
* sampling.
|
|
12
|
+
*
|
|
13
|
+
* Samples hand over the snapshot's own ray tuples. A provider never writes
|
|
14
|
+
* to a snapshot it has already delivered (the ownership rule on
|
|
15
|
+
* `InputSourceSnapshot`), so a consumer may keep a sample - a drag holds
|
|
16
|
+
* its press-time origin - without copying it.
|
|
12
17
|
*/
|
|
13
18
|
import { type PointerInputSource } from "@realitycollective/webxr-input";
|
|
14
19
|
import type { InteractionRuntime } from "./runtime.js";
|
package/dist/pointer-bridge.js
CHANGED
|
@@ -9,6 +9,11 @@
|
|
|
9
9
|
* `@realitycollective/webxr-uiextensions`): press-move-release derived
|
|
10
10
|
* from a source's ray + select signal, fed by the runtime's per-frame
|
|
11
11
|
* sampling.
|
|
12
|
+
*
|
|
13
|
+
* Samples hand over the snapshot's own ray tuples. A provider never writes
|
|
14
|
+
* to a snapshot it has already delivered (the ownership rule on
|
|
15
|
+
* `InputSourceSnapshot`), so a consumer may keep a sample - a drag holds
|
|
16
|
+
* its press-time origin - without copying it.
|
|
12
17
|
*/
|
|
13
18
|
import { SELECT_PRESS_THRESHOLD, SELECT_RELEASE_THRESHOLD, } from "@realitycollective/webxr-input";
|
|
14
19
|
import { Emitter } from "./events.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pointer-bridge.js","sourceRoot":"","sources":["../src/pointer-bridge.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"pointer-bridge.js","sourceRoot":"","sources":["../src/pointer-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;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 *\n * Samples hand over the snapshot's own ray tuples. A provider never writes\n * to a snapshot it has already delivered (the ownership rule on\n * `InputSourceSnapshot`), so a consumer may keep a sample - a drag holds\n * its press-time origin - without copying it.\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
|
@@ -84,11 +84,22 @@ export declare class InteractionRuntime {
|
|
|
84
84
|
* callers keep working and will be removed in a later major release.
|
|
85
85
|
*/
|
|
86
86
|
onSourcesSampled(listener: (sources: readonly InputSourceSnapshot[]) => void): Unsubscribe;
|
|
87
|
-
/**
|
|
87
|
+
/**
|
|
88
|
+
* This frame's sources, velocity included.
|
|
89
|
+
*
|
|
90
|
+
* The snapshots are the provider's own objects for this frame and are
|
|
91
|
+
* never written to again once delivered (the ownership rule on
|
|
92
|
+
* `InputSourceSnapshot`), so a listener may keep one, or a tuple inside
|
|
93
|
+
* it, across frames without copying.
|
|
94
|
+
*/
|
|
88
95
|
onSample(listener: (sources: readonly InputSourceSnapshot[]) => void): Unsubscribe;
|
|
89
96
|
/**
|
|
90
97
|
* The last sample of one source, velocity included. Undefined before the
|
|
91
98
|
* first update, and once the source stops reporting.
|
|
99
|
+
*
|
|
100
|
+
* The snapshot is the caller's to keep: it is never mutated after the
|
|
101
|
+
* frame it was sampled in, and it is not refreshed in place, so call
|
|
102
|
+
* again for a newer one.
|
|
92
103
|
*/
|
|
93
104
|
getSource(id: string): InputSourceSnapshot | undefined;
|
|
94
105
|
getCapabilities(): InputCapabilities;
|
package/dist/runtime.js
CHANGED
|
@@ -149,13 +149,24 @@ export class InteractionRuntime {
|
|
|
149
149
|
onSourcesSampled(listener) {
|
|
150
150
|
return this.afterSample.subscribe(listener);
|
|
151
151
|
}
|
|
152
|
-
/**
|
|
152
|
+
/**
|
|
153
|
+
* This frame's sources, velocity included.
|
|
154
|
+
*
|
|
155
|
+
* The snapshots are the provider's own objects for this frame and are
|
|
156
|
+
* never written to again once delivered (the ownership rule on
|
|
157
|
+
* `InputSourceSnapshot`), so a listener may keep one, or a tuple inside
|
|
158
|
+
* it, across frames without copying.
|
|
159
|
+
*/
|
|
153
160
|
onSample(listener) {
|
|
154
161
|
return this.afterSample.subscribe(listener);
|
|
155
162
|
}
|
|
156
163
|
/**
|
|
157
164
|
* The last sample of one source, velocity included. Undefined before the
|
|
158
165
|
* first update, and once the source stops reporting.
|
|
166
|
+
*
|
|
167
|
+
* The snapshot is the caller's to keep: it is never mutated after the
|
|
168
|
+
* frame it was sampled in, and it is not refreshed in place, so call
|
|
169
|
+
* again for a newer one.
|
|
159
170
|
*/
|
|
160
171
|
getSource(id) {
|
|
161
172
|
return this.lastSources.get(id);
|
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 { 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"]}
|
|
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 /**\n * This frame's sources, velocity included.\n *\n * The snapshots are the provider's own objects for this frame and are\n * never written to again once delivered (the ownership rule on\n * `InputSourceSnapshot`), so a listener may keep one, or a tuple inside\n * it, across frames without copying.\n */\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 * The snapshot is the caller's to keep: it is never mutated after the\n * frame it was sampled in, and it is not refreshed in place, so call\n * again for a newer one.\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"]}
|
|
@@ -12,6 +12,11 @@
|
|
|
12
12
|
* time (or seen again after dropping out of tracking) gets no velocity
|
|
13
13
|
* that frame, so a reconnecting controller cannot report a metres-per-
|
|
14
14
|
* second jump from wherever it was last seen.
|
|
15
|
+
*
|
|
16
|
+
* It keeps last frame's `position` and `quaternion` arrays by reference
|
|
17
|
+
* rather than copying them. The ownership rule on `InputSourceSnapshot`
|
|
18
|
+
* permits that: a provider never writes to a snapshot it has already
|
|
19
|
+
* handed over, so last frame's tuples still hold last frame's numbers.
|
|
15
20
|
*/
|
|
16
21
|
import { type InputSourceSnapshot } from "@realitycollective/webxr-input";
|
|
17
22
|
export interface VelocityTrackerOptions {
|
package/dist/velocity-tracker.js
CHANGED
|
@@ -12,6 +12,11 @@
|
|
|
12
12
|
* time (or seen again after dropping out of tracking) gets no velocity
|
|
13
13
|
* that frame, so a reconnecting controller cannot report a metres-per-
|
|
14
14
|
* second jump from wherever it was last seen.
|
|
15
|
+
*
|
|
16
|
+
* It keeps last frame's `position` and `quaternion` arrays by reference
|
|
17
|
+
* rather than copying them. The ownership rule on `InputSourceSnapshot`
|
|
18
|
+
* permits that: a provider never writes to a snapshot it has already
|
|
19
|
+
* handed over, so last frame's tuples still hold last frame's numbers.
|
|
15
20
|
*/
|
|
16
21
|
import { velocityBetween, } from "@realitycollective/webxr-input";
|
|
17
22
|
const DEFAULT_SMOOTHING = 1;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"velocity-tracker.js","sourceRoot":"","sources":["../src/velocity-tracker.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"velocity-tracker.js","sourceRoot":"","sources":["../src/velocity-tracker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;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 *\n * It keeps last frame's `position` and `quaternion` arrays by reference\n * rather than copying them. The ownership rule on `InputSourceSnapshot`\n * permits that: a provider never writes to a snapshot it has already\n * handed over, so last frame's tuples still hold last frame's numbers.\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.4",
|
|
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",
|