XR Input Overview
Updated: Sep 4, 2026
IWSDK turns browser and WebXR device input into reusable actions, pointer events, gamepad state, tracked spaces, and input visuals.
- Input actions express intent such as move, turn, jump, or select without coupling a system to one device.
- Pointer events handle hover, press, click, and drag behavior across browser and XR pointers.
- StatefulGamepad exposes mapped buttons, axes, and edge transitions for device-specific logic.
- XR origin spaces provide tracked head, ray, and grip transforms for attached objects.
- Input visuals render and animate controller and hand models.
XRInputSource and browser input
↓
Actions, StatefulGamepad, and MultiPointer
↓
Application systems and pointer event handlers
World.create() creates the input manager and player rig. Access them from world.input and world.player.
const world = await World.create(container, {
input: { canvasPointerEvents: true },
});
const move = world.input.actions.getAxis2D('locomotion.move');
const rightPointer = world.input.xr.multiPointers.right;
const rightGamepad = world.input.xr.gamepads.right;
Canvas pointer forwarding is enabled by default. XR input updates from the active XRFrame inside IWSDK’s render loop.
Each hand has a MultiPointer that coordinates three pointer kinds:
touch for fingertip proximity and contact;grab for near manipulation;ray for pointing at distant content.
When several pointers have candidates, priority is Touch > Grab > Ray. A pointer that begins selecting remains active until release.
See
Pointers for interaction tags and public controls.
Use XRInputManager directly only when an application owns its Three.js renderer instead of using World.
import {
Clock,
PerspectiveCamera,
Scene,
WebGLRenderer,
XRInputManager,
} from '@iwsdk/core';
const scene = new Scene();
const camera = new PerspectiveCamera(60, innerWidth / innerHeight, 0.01, 100);
const renderer = new WebGLRenderer({ antialias: true });
const clock = new Clock();
renderer.xr.enabled = true;
const xrInput = new XRInputManager({ scene, camera });
scene.add(xrInput.xrOrigin);
renderer.setAnimationLoop((timeMs) => {
xrInput.update(renderer.xr, clock.getDelta(), timeMs / 1000);
renderer.render(scene, camera);
});
The constructor takes scene, camera, and optional assetLoader, inputDevices, and pointerSettings fields. A Three.js renderer does not expose a clock; create one explicitly when using this standalone path.