InputSystem
Captures and normalizes keyboard and mouse input events from the browser, then exposes a clean query API accessible directly on this.world inside Behaviour scripts.
Overview
InputSystem manages input state for the current frame and is responsible for:
- Listening to
keydown/keyupDOM events and tracking which keys are currently held, newly pressed (down), or just released (up) this frame. - Listening to
mousedown/mouseup/mousemove/wheelevents for left, middle, and right buttons plus pointer position and scroll deltas. - Flushing pending input changes at the start of each frame so
getKeyDown/getKeyUpare onlytruefor a single frame. - Providing pointer-lock support: when a lock target element is set, mouse position and delta calculations are bounded to that element's rect.
API exposed to scripts
Call these methods directly on this.world from any Behaviour script. There is no world.input accessor.
| Method | Description |
|---|---|
this.world.getKey(key) | true while the key is held this frame. |
this.world.getKeyDown(key) | true only on the first frame the key is pressed. |
this.world.getKeyUp(key) | true only on the frame the key is released. |
this.world.getMouse(button) | true while the mouse button is held. |
this.world.getMouseDown(button) | true only on the first frame the button is pressed. |
this.world.getMouseUp(button) | true only on the frame the button is released. |
this.world.getMousePosition() | { x, y } in viewport pixels. |
this.world.getMouseDelta() | { x, y } movement delta since the previous frame. |
this.world.consumeMouseDelta() | { x, y } movement delta; zeroes after reading. |
this.world.getScrollDelta() | { x, y } scroll delta since the previous frame. |
Mouse buttons can be specified as "left", "middle", or "right" (or the numeric indices 0, 1, 2).
KeyboardKeys reference
Import KeyboardKeys from @relu-interactives/spatial-ecs to access all available key constants with full TypeScript autocomplete.
import { KeyboardKeys } from "@relu-interactives/spatial-ecs";Letters
| Constant | Value |
|---|---|
KeyboardKeys.A … KeyboardKeys.Z | "a" … "z" |
Digits
| Constant | Value |
|---|---|
KeyboardKeys.Digit0 … KeyboardKeys.Digit9 | "0" … "9" |
Navigation & editing
| Constant | Value |
|---|---|
KeyboardKeys.ArrowUp | "arrowup" |
KeyboardKeys.ArrowDown | "arrowdown" |
KeyboardKeys.ArrowLeft | "arrowleft" |
KeyboardKeys.ArrowRight | "arrowright" |
KeyboardKeys.Space | " " |
KeyboardKeys.Enter | "enter" |
KeyboardKeys.Escape | "escape" |
KeyboardKeys.Tab | "tab" |
KeyboardKeys.Backspace | "backspace" |
KeyboardKeys.Delete | "delete" |
KeyboardKeys.Insert | "insert" |
KeyboardKeys.Home | "home" |
KeyboardKeys.End | "end" |
KeyboardKeys.PageUp | "pageup" |
KeyboardKeys.PageDown | "pagedown" |
Modifier keys
Generic variants match either left or right physical key. Use the specific variants when the side matters.
| Constant | Value | Notes |
|---|---|---|
KeyboardKeys.Shift | "shift" | Either shift key |
KeyboardKeys.ShiftLeft | "shiftleft" | Left Shift only |
KeyboardKeys.ShiftRight | "shiftright" | Right Shift only |
KeyboardKeys.Control | "control" | Either Ctrl key |
KeyboardKeys.ControlLeft | "controlleft" | Left Ctrl only |
KeyboardKeys.ControlRight | "controlright" | Right Ctrl only |
KeyboardKeys.Alt | "alt" | Alt / Option |
KeyboardKeys.Meta | "meta" | Cmd (macOS) / Win (Windows) |
KeyboardKeys.CapsLock | "capslock" |
Function keys
| Constant | Value |
|---|---|
KeyboardKeys.F1 … KeyboardKeys.F12 | "f1" … "f12" |
Punctuation & symbols
| Constant | Value |
|---|---|
KeyboardKeys.Minus | "-" |
KeyboardKeys.Equal | "=" |
KeyboardKeys.BracketLeft | "[" |
KeyboardKeys.BracketRight | "]" |
KeyboardKeys.Backslash | "\\" |
KeyboardKeys.Semicolon | ";" |
KeyboardKeys.Quote | "'" |
KeyboardKeys.Backquote | "`" |
KeyboardKeys.Comma | "," |
KeyboardKeys.Period | "." |
KeyboardKeys.Slash | "/" |
Other
| Constant | Value |
|---|---|
KeyboardKeys.NumLock | "numlock" |
KeyboardKeys.ScrollLock | "scrolllock" |
KeyboardKeys.Pause | "pause" |
KeyboardKeys.PrintScreen | "printscreen" |
KeyboardKeys.ContextMenu | "contextmenu" |
Script examples
Basic movement
Move an object along the X/Z plane with WASD and sprint with Shift.
import { KeyboardKeys, Behaviour } from "@relu-interactives/spatial-ecs";
export default class PlayerMovement extends Behaviour {
speed = 5;
sprintMultiplier = 2;
protected onUpdate() {
const sprint = this.world.getKey(KeyboardKeys.Shift) ? this.sprintMultiplier : 1;
const step = this.speed * sprint * this.deltaTime;
if (this.world.getKey(KeyboardKeys.W)) this.transform.position.z -= step;
if (this.world.getKey(KeyboardKeys.S)) this.transform.position.z += step;
if (this.world.getKey(KeyboardKeys.A)) this.transform.position.x -= step;
if (this.world.getKey(KeyboardKeys.D)) this.transform.position.x += step;
}
}One-shot action on key press
Toggle visibility on Space, fire on left-click.
import { KeyboardKeys, Behaviour } from "@relu-interactives/spatial-ecs";
export default class ActionHandler extends Behaviour {
protected onUpdate() {
// getKeyDown fires only on the first frame the key is pressed.
if (this.world.getKeyDown(KeyboardKeys.Space)) {
this.transform.visible = !this.transform.visible;
}
// Left mouse button
if (this.world.getMouseDown("left")) {
console.log("Fired!");
}
}
}Distinguishing left vs right modifier
import { KeyboardKeys, Behaviour } from "@relu-interactives/spatial-ecs";
export default class ModifierDemo extends Behaviour {
protected onUpdate() {
if (this.world.getKeyDown(KeyboardKeys.ControlLeft)) {
console.log("Left Ctrl pressed");
}
if (this.world.getKeyDown(KeyboardKeys.ControlRight)) {
console.log("Right Ctrl pressed");
}
// Generic: matches either left or right Shift
if (this.world.getKey(KeyboardKeys.Shift)) {
console.log("A Shift key is held");
}
}
}Reading mouse delta (camera look)
import { Behaviour } from "@relu-interactives/spatial-ecs";
export default class CameraLook extends Behaviour {
sensitivity = 0.002;
protected onUpdate() {
const { x, y } = this.world.consumeMouseDelta();
this.transform.rotation.y -= x * this.sensitivity;
this.transform.rotation.x -= y * this.sensitivity;
}
}Behavior notes
- Frame flush — pending input queued during the previous frame's browser event callbacks is promoted to the current frame's
down/upsets at the start ofupdate(). This guaranteesgetKeyDownis never missed even if the frame rate drops. - Key normalization — key names are lowercased before storage so
"ArrowUp"and"arrowup"are treated identically. - Left/right modifiers — the system tracks both
event.key(e.g."shift") andevent.code(e.g."shiftleft") so generic and specific modifier queries both work simultaneously. - Register / unregister — call
register(element)to attach all DOM listeners to a specific element, andunregister()to remove them. This should be called during world setup and teardown.
API reference
- Source:
core/systems/InputSystem.ts - Related:
KeyboardKeytype alias for valid key string constants.

