Input
The InputManager (packages/engine/src/input/input-manager.ts) maps raw device events to
named actions so your gameplay code asks “is jump pressed?” rather than “is Space
down?”. It’s polled once per frame in the input phase.
The frame discipline
Section titled “The frame discipline”await input.loadMap('inputmaps/default.inputmap.json');// each frame:input.poll(); // at the start (input phase)if (input.isPressed('jump')) { /* … */ }if (input.isJustPressed('attack')) { /* … */ }input.endFrame(); // at the end — clears per-frame diffspoll() reads gamepad state and computes the just-pressed / just-released edges for this
frame; endFrame() clears those per-frame diffs. The engine runtime wires this for you.
Queries
Section titled “Queries”isPressed(action)— held this frame.isJustPressed(action)— became pressed this frame.isJustReleased(action)— became released this frame.getMouseDelta()— accumulated mouse movement this frame.setLookStick(x, y)— feed a virtual look stick (e.g. from on-screen touch controls); its value is injected as mouse delta duringpoll().registerAction(name, bindings)— define an action in code.requestPointerLock(element)— request pointer lock (for FPS-style mouse look).setEnabled(enabled)/isEnabled()— gate input delivery without removing listeners; disabling flushes held keys and buttons so nothing sticks on re-enable (the editor uses this to isolate play-mode input).dispose()— remove listeners.
Keydown events are also ignored while a text field (input, textarea, or a
contenteditable element) has focus, so typing a name into an editor panel or an
in-game chat box never triggers game actions.
Binding types (.inputmap.json)
Section titled “Binding types (.inputmap.json)”An input map is a versioned file of actions, each with a list of bindings.
The Zod schema (packages/engine/src/input/schema.ts) validates every
map at loadMap — a malformed file throws an AssetParseError naming the
file, instead of failing deep inside a query method:
| Binding | Fields |
|---|---|
key | code (from KeyboardEvent.code, e.g. "KeyW") |
mouse_button | button (0 = left, 1 = middle, 2 = right) |
gamepad_button | button |
gamepad_axis | axis, direction (positive / negative), deadzone? |
Two declared binding kinds — mouse_move and gamepad_axis_pair — have
no runtime reader (no query method ever handles them), so authoring
either one throws at parse (the dead-field rule). Mouse look is read
out-of-band via getMouseDelta()/setLookStick(), not through a binding.
See also
Section titled “See also”- The game loop & phases — the
inputphase. - Capstone: FPS — pointer lock + actions in a build.
- Quick start: write your first component — reading input from a component.