Skip to main content
Family 01 · Input

The contracts every adapter speaks.

WebXR Input describes XR input in plain TypeScript types: where a hand or controller is pointing, what it is touching, and what the device can actually do. It has no dependency on any 3D engine and no runtime dependencies at all, and a test enforces both. That is what lets the Interactions and UI Extensions families share one description of input, so an engine adapter is written once and feeds both.

Released, 0.1.4 on npmMITZero dependencies
webxr-input
types · capabilities · provider · pointer streams · velocity · conformance cases
webxr-interactions
consumes it
webxr-uiextensions
consumes it
engine adapters
implement InputProvider · three.js, Babylon.js, IWSDK, XR Blocks

How it is built

Every Reality Toolkit WebXR family has the same shape. The logic lives in an engine-free core that carries the tests. A thin adapter binds that core to one engine, depends on it, and re-exports it, so your app installs one package. Where families need to agree on a shape, they share plain contracts rather than importing each other.

Your app

Owns the content: meshes, panels, placement, physics and sound files. Installs one adapter per family and wires families together with subscriptions in the one place where both halves are in scope.

One adapter per engine

The only place an engine name appears. It reads the engine each frame, feeds the core, applies the core's results back, and reports anything the engine cannot do instead of failing silently.

The engine-free core

All the logic, as plain TypeScript with no engine import. An architecture test fails the build the moment one lands, which is what lets the same behaviour run unchanged on every engine, and be tested without a headset.

Your appcontent, physics, the wiring between familiesOne adapterthreejs-, babylon-, iwsdk-, xrblocks-interactions and the UI adapters implement InputProviderEngine-free corewebxr-input · types, capabilities, provider, pointer streams, conformance casesArrows only point down. Families never reference each other.

Where it sits in the stack

Four families, one rule: no package references a sibling family, not even a type. What crosses a boundary is a subscription your app makes, such as playing an Environment cue when an Interactions press fires.

The Service Framework for the web sits beside these four and keeps its own site: serviceframework.realitycollective.net. The layering rule explains the boundaries in full.

Why you would use it

01

One description of input

A ray, a grip pose, a fingertip, select and squeeze as numbers from 0 to 1. Plain tuples, no engine types anywhere, so a pose means the same thing to every family.

02

Capabilities from the live session

What a provider can deliver is derived from the session that is actually running, and consumers gate behaviour on it with satisfies and unmetRequirements.

03

Conformance as data

The provider contract ships as a list of named cases, not as tests. An adapter loops over them in its own test runner and proves it conforms.

Who implements it

Apps never install this package. Every adapter in the Interactions and UI Extensions families implements the provider interface and re-exports the contracts, so an app reads these types through the adapter it already has.

Interactions adapters

threejs-, babylon-, iwsdk-, xrblocks-interactions

Each implements InputProvider over its engine and hands the samples to the interaction core.

four adaptersRead more →

UI Extensions adapters

iwsdk-, xrblocks-uiextensions

Drive windows and controls through the shared pointer contract, so one input stack serves both families.

two adaptersRead more →

Your own adapter

implement InputProvider

Pull-based sample(), capability-change events, optional haptics and presence. Run inputProviderContractCases() to prove it.

guideRead more →

Who does what

Read the ladder top to bottom. The middle column is the stage every engine goes through; the core owns the left, the adapter you install owns the right.

The core
Stage
The adapter
InputSourceSnapshot, plain tuples, opaque ids, handedness
Describe input
Fills one snapshot per source every frame from its engine
The capability keys, satisfies and unmetRequirements
Declare capabilities
Derives the keys from the live session and raises change events
The pull-based InputProvider contract
Sample
Reads controllers, hands, mouse or touch and returns the samples
Optional pulse, setPresenceVisible, setPresenceModality
Haptics and presence
Forwards to the engine where it can, leaves the member out where it cannot
inputProviderContractCases() as data
Prove conformance
Runs every case in its own test runner

Five words you will meet

Snapshotone normalised input source per frame: ray, grip, fingertip, select, squeeze
Capabilitieswhat a provider can deliver, derived from the live session
Providerthe single interface an engine adapter implements
Pointer samplea press-move-release stream, shared with the UI family
Contract casea named conformance check an adapter runs in its own test runner