@realitycollective/webxr-input
v0.1.9
Published
Shared, engine-free input contracts for the Reality Collective WebXR extension families: normalised input sources (rays, pinches, pokes, grips, hand joints, gaze, 2D pointers), capability negotiation, a pull-based provider interface, and pointer streams -
Maintainers
Readme
@realitycollective/webxr-input
Plain TypeScript types describing XR input: where a hand or controller is pointing, what it is touching, and what the device can actually do.
No dependency on any 3D engine, and no runtime dependencies at all. A test enforces both.
npm install @realitycollective/webxr-inputWhat it is
A shared vocabulary for input. It lets an interaction library, a UI library and an engine adapter agree on what "input" means, without any of them importing a 3D engine.
| Concept | What it gives you |
| --- | --- |
| Input sources | Normalised rays, pinches, pokes, grips, hand joints, gaze and 2D pointers, addressed by handedness rather than array index |
| Capabilities | What the current device can actually do, so a feature can switch itself off and say so rather than failing silently |
| Eye gaze | The gaze-and-pinch rule Meta IWSDK 1.0.0 applies when a session grants eye tracking (the primary input on Meta VR Glasses), as pure logic every provider runs: EyeGazeInput, EYE_GAZE_DEFAULTS, EyeGazeFilter. See src/eye-gaze.ts |
| Provider | The interface an engine adapter implements once. Consumers ask it for the current state each frame; it never pushes at them |
| Pointer streams | Press, move and release events for one input source, with no reference to the engine's scene graph |
| Pointer arbitration | PointerArbiter: one decision per source (touch, grab or ray) across every target set that offers candidates, with IWSDK's priority and selection lock; PointerVisuals name the panel or object the pointer is on |
| Pointer display | PointerDisplay and POINTER_DISPLAY_DEFAULTS (IWSDK 1.0.0's look): the app's ray and cursor settings, and pointerDrawing(), which turns a decision into what a binding draws |
| Conformance suite | inputProviderContractCases(), the checks every provider must pass, shipped as data; MemoryInputProvider is the in-memory reference provider for tests and tools |
It deliberately contains no raycasting, no scene-graph types and no session management - those belong to the engine adapters that sit on top.
Who consumes it
@realitycollective/webxr-interactions- interactables, interactors and behaviours@realitycollective/webxr-uiextensions- spatial windowing, docking and controls
Both families read the same contracts, so one engine adapter feeds both. That includes the native one: @realitycollective/native-interactions implements InputProvider over the input slice a native XR app provides, so an app built on these contracts runs unchanged in a native host.
Usage
import {
satisfies,
unmetRequirements,
type InputCapabilityRequirement,
type InputProvider,
} from "@realitycollective/webxr-input";
// Ask what the current runtime supports before enabling a behaviour. A
// requirement is a name from INPUT_CAPABILITY_REQUIREMENTS: "rays", "pokes",
// "grabs" (pose-only or native), "grabsNative", "handJoints", "pinch",
// "buttonsAxes", "gaze", "eyeGaze", "pointer2d", "headPose", "haptics" or "presence".
const required: InputCapabilityRequirement[] = ["rays", "grabsNative"];
// satisfies() checks one requirement; unmetRequirements() filters a list.
if (!satisfies(provider.capabilities, "rays")) {
console.warn("no ray targeting on this runtime");
}
const missing = unmetRequirements(provider.capabilities, required);
if (missing.length > 0) {
console.warn("degraded:", missing); // e.g. ["grabsNative"] on a runtime without native grab
}The two rules every family shares beyond the contracts themselves:
PointerArbiterdecides once per source which pointer (touch, grab or ray) owns it, across registered interactables and UI panels alike, as IWSDK'sMultiPointerdoes; the Interactions runtime and the UI Extensions window hosts register a target set each and offer their candidates. Pass one arbiter to both setups (pointers) so a touch on a panel retires the ray over an object and a panel cursor is reported.PointerDisplayholds the app's ray and cursor settings (ray: "never" | "always" | "whileHitting",cursorOnObjects,cursorOnPanels,rayOnlyOnPanels, the look), IWSDK 1.0.0's values by default, settable at run time;pointerDrawing()turns the arbiter's decision into what a binding draws.
Guarantees
- No engine imports.
three,@iwsdk/*,@pmndrs/*andxrblocksare all forbidden insrc/and gated by a test that fails the build if one appears. - No runtime dependencies.
dependenciesandpeerDependenciesare asserted empty by the same test, so adding this package can never pull an engine into a consumer's tree.
Documentation
The full ecosystem survey, the prior-art comparison and the rationale for a separate contracts package live in the repository README.
License
MIT - see LICENSE.
