Input from data

Steer a camera from your own code, the network or a recording.

An axis is plain data, so anything that produces numbers can steer a camera: your own code, an AI, another player over the network, or a recording of earlier input. None of it needs a mouse or a DOM.

Changing an axis

CallUse it forRecentering
applyDelta(delta)Moving by an amount, the way a drag does. Eases with the axis's damping.Waits, since the axis is in use.
held = trueHolding still, like a finger resting on the screen.Waits while held.
setValue(value)Jumping straight to a value, for a teleport or a reset.Carries on. A jump isn't input.

Use setValue for jumps. Writing value directly doesn't last: the axis eases back to where its input left it.

In the same frame

Feed the axes from a function passed to registerUpdate. It runs every frame before the cameras, so the camera answers in that same frame. While your data keeps changing on its own, return true from it, so on-demand rendering keeps asking for frames.

Usage

const remote = { pan: 0, tilt: 0 }; // filled by your network code

klipp.registerUpdate(() => {
  aim.pan.applyDelta(remote.pan);
  aim.tilt.applyDelta(remote.tilt);
  remote.pan = 0;
  remote.tilt = 0;
});

aim.pan.setValue(0); // face forward again

Recording and replay

An InputController from @pmndrs/klipp reads its input from its input field. Copy what a live controller read each frame, then play it back into another controller with the same mapping. Here live is an InputControllerDom set up as usual, updated in the recording function:

import { InputController, type ConsumedInput } from '@pmndrs/klipp';

const frames: ConsumedInput[] = [];
klipp.registerUpdate(() => {
  live.update();
  frames.push({ ...live.input });
});

// later
const replay = new InputController(live.config);
let frame = 0;
klipp.registerUpdate(() => {
  if (frame >= frames.length) return false;
  Object.assign(replay.input, frames[frame++]);
  replay.update();
  return true;
});

The replay plays one recorded frame per frame.