Develop

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.

Choose an input layer

  • 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-managed input

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.

MultiPointer

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.

Standalone XRInputManager

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.

Learn each layer