InputController

Maps mouse, touch, wheel and pinch input onto a piece's axes.

Maps mouse buttons, finger counts, the wheel and pinches onto axes. On the core and in three.js it's an InputControllerDom from @pmndrs/klipp/dom that takes the axes themselves. In React, <InputController> finds them by name in the piece it's placed in. Placed directly in a <VirtualCamera>, it finds them in any of the camera's pieces.

Settings

SettingDescriptionDefault
mouseButtonsWhat each mouse button drives: { left, right, middle }.
touchesWhat each finger count drives: { one, two, three }.
wheelWhat the mouse wheel drives. Scrolling up is positive, like spreading a pinch.
pinchWhat a pinch drives, with two fingers or on a trackpad, as the change in ln(scale). Spreading is positive.
enabledTurns input on or off.true
suppressContextMenuDisable the right-click menu on the canvas. On inputSystem on the core and in three.js.false
interactiveAreaOnly take drags, scrolls and pinches that start inside part of the canvas: { x, y, width, height } from 0 to 1, measured from the top-left corner. On inputSystem on the core and in three.js.whole canvas
lockTouchAxisFor two-finger gestures, pick either pinch or rotate instead of both. On inputSystem on the core and in three.js.false
waitForBlendIgnore input until the blend into this camera has finished. An option of klipp.whileOnScreen on the core and in three.js.true
targetReact only. Something else with axes to control, or a ref to it (for example a PanTiltAimThree), instead of the piece it's placed in.parent piece, or the camera

Mapping a source

List only the sources you use. Each button and finger count takes the same config:

{
  axes: { x: 'pan', y: 'tilt' }, // which axis receives the horizontal and vertical drag: names in React, the axes themselves elsewhere
  gain: 0.15,                    // multiplier from pixels to axis units
  invert: { y: true },           // flip one or both directions, or `true` for both
}

Leave x or y out to ignore that direction: axes: { x: 'pan' } turns only horizontal drags into input.

Wheel and pinch

wheel and pinch each drive a single axis:

{
  axis: 'radial', // a name in React, the axis itself elsewhere
  gain: 0.002,
  invert: true,
}

A pinch feels the same on a touch screen and on a trackpad, and adds up to the same amount however far you are zoomed in. That suits a zoom stored as ln of its scale. The wheel moves in pixels, so it needs its own gain.

The page keeps scrolling over the canvas until wheel is mapped, and a trackpad pinch keeps zooming the page until pinch is mapped.

Pointer lock

For mouse look without holding a button, request pointer lock on the controller's inputSystem. While locked, mouse movement goes to mouseButtons.left.

Raw input

input holds this frame's raw deltas, for example wheelDeltaY, pinchDelta or leftDx, if you want to handle something yourself.

Usage

import { InputControllerDom } from '@pmndrs/klipp/dom';

const look = { axes: { x: aim.pan, y: aim.tilt }, gain: 0.15 };
const controller = new InputControllerDom({
  mouseButtons: { right: look },
  touches: { one: look },
});
controller.inputSystem.suppressContextMenu = true;
klipp.whileOnScreen(camera, () => {
  controller.connect(canvas);
  return () => controller.disconnect();
});
klipp.registerUpdate(() => controller.update());

whileOnScreen connects it only while its camera is on screen, so several cameras don't react to the same drag. controller.enabled = false keeps it connected but ignores input.

Pointer lock

// in a click handler
controller.inputSystem.requestPointerLock();
controller.inputSystem.exitPointerLock();

Raw input

klipp.registerUpdate(() => {
  controller.update();
  roll += controller.input.twistDelta;
});