Keyboard
input/keyboard.ts:74 Extends AbstractGameComponent
Game-scoped input sampler that tracks the set of physical keys currently held on the keyboard.
Like Keyboard's sibling import('./mouse').Mouse, this
component lives at the Game tier rather than on a World:
keyboard events are page-global, fire whether a world is mounted or not,
and the same physical keyboard is shared across world swaps (menu →
gameplay → game-over). Game code reads keyboard state via the
convenience accessors on the game or world — game.getKeyboardState()
or world.getKeyboardState() — rather than touching this component
directly; the class itself is exported so callers writing custom
bootstrap, or users who want to swap in a custom input source (e.g. a
recorded-input variant for tests), have something concrete to construct
and register.
Physical vs logical keys
Held state is keyed by KeyboardEvent.code (the physical key) rather
than KeyboardEvent.key (the logical character). This is the standard
choice for game input — WASD movement keeps working on AZERTY or Dvorak
layouts without per-layout remapping, because the four keys in the
top-left of the letter block always report as KeyW/KeyA/KeyS/
KeyD regardless of what character they actually produce. See
KeyboardState for the cross-reference to MDN's code-value list.
Snapshot semantics
The component follows the canonical "input sampler" pattern, identical
to import('./mouse').Mouse:
- DOM events update a private pending set as they arrive — this is asynchronous and can happen at any time relative to the engine's update tick.
- Keyboard.onPreUpdate copies the pending set into a private snapshot once per game tick, before the active world's update phase runs.
- Keyboard.getState returns a KeyboardState derived from the snapshot, so every component reading the keyboard during a single tick sees the same held-key set.
Event sourcing
Listeners are attached during Keyboard.onAdded and removed in Keyboard.onDestroy:
keydownandkeyupare listened onwindow. The canvas itself does not receive keyboard events unless explicitly focused (which requires atabindexand is fragile across browsers), so window- level listening is the standard choice for browser games.bluronwindowclears the pending set. Without this, a key held when the user alt-tabs away never receives itskeyupand stays "stuck down" forever — a class of bug that's both common and very annoying to debug.
The engine does not call event.preventDefault() on any of these — game
code is free to do that itself if it wants to suppress browser defaults
like Space scrolling the page or Tab moving focus. Suppressing globally
here would break browser UX for any non-gameplay UI rendered on the
same page.
Auto-repeat
Browsers fire repeated keydown events while a key is held, with
event.repeat === true. The component does not filter these — adding
to the pending set is idempotent and the held-state semantics are
unchanged. Edge-triggered "just pressed this frame" detection is not
provided by this component; layer that on at the
action-mapping/GameControls tier when it lands.
Constructors
Properties
enabled: boolean Per-component gate on the three update hooks (onPreUpdate,
onUpdate, onPostUpdate). When explicitly false, the engine skips
all three for this component during the host's tick — useful for
temporarily pausing behaviour (e.g. a freeze powerup) without removing
the component and losing its internal state.
Does not gate onAdded or onDestroy; those always fire so a host can
never end up with a half-attached component.
Accessors
game: Game The Game this component is attached to — identical to
AbstractComponent.host at this tier, exposed under the
game name so subclass code reads the same on every tier.
Methods
getState(): KeyboardState Returns a fresh KeyboardState per call — game code may stash
the returned object for the duration of a frame without worrying
about mid-frame mutation. The contained downKeys set is a fresh
clone of the internal snapshot, exposed as ReadonlySet<string> so
callers cannot accidentally mutate engine state through it.
Returns
KeyboardState onAdded(): void Lifecycle hook that is called when the component is added to the host object. Should not be called directly.
Returns
void onDestroy(): void Lifecycle hook that is called when the host object is destroyed. Should not be called directly.
Returns
void onPreUpdate(): void Returns
void onUpdate(_update: WorldUpdate, _deps: Record): void Lifecycle hook for the main update phase. Called once per world
tick, after every component's onPreUpdate and before any
onPostUpdate.
Parameters
-
_updateWorldUpdate -
_depsRecord
Returns
void