Keyboard Input
Open the editor to try keyboard-controlled sketches live.
How It Works
The keys object tracks which keys are currently held. Each key is a property set to true while pressed and false when released.
javascript
if (keys.ArrowUp) {
state.y -= 100 * dt;
}
if (keys[' ']) {
// space bar held
}WARNING
keys is read-only. Do not assign keys.foo = true.
Key Naming
Names come from event.key:
| Key | keys property |
|---|---|
| Arrow Up | keys.ArrowUp |
| Arrow Down | keys.ArrowDown |
| Arrow Left | keys.ArrowLeft |
| Arrow Right | keys.ArrowRight |
| W / w | keys.w |
| A / a | keys.a |
| S / s | keys.s |
| D / d | keys.d |
| R / r | keys.r |
| Space | keys[' '] |
| Enter | keys.Enter |
| Shift | keys.Shift |
| Any letter | Lowercase, e.g. keys.p |
Check multiple keys to support both arrow and WASD control:
javascript
if (keys.ArrowUp || keys.w) state.dir = { x: 0, y: -1 };
if (keys.ArrowDown || keys.s) state.dir = { x: 0, y: 1 };Game Loop Pattern
For games, use a timer-based tick inside your frame function:
javascript
if (!state.init) {
// game state init
state.timer = 0;
state.tickInterval = 0.12; // seconds per game tick
state.init = true;
}
state.timer += dt;
if (state.timer >= state.tickInterval) {
state.timer = 0;
// read keys, update game state, check collisions
}Common Patterns
Continuous Movement (Platformer)
javascript
if (!state.init) {
state.x = w / 2;
state.y = h / 2;
state.vx = 0;
state.vy = 0;
state.init = true;
}
const speed = 200;
const jumpForce = -400;
const gravity = 800;
// Horizontal input
if (keys.ArrowLeft || keys.a) state.vx = -speed;
else if (keys.ArrowRight || keys.d) state.vx = speed;
else state.vx *= 0.8; // friction
// Jump (only when grounded)
if ((keys.ArrowUp || keys.w || keys[' ']) && state.y >= h - 20) {
state.vy = jumpForce;
}
// Gravity
state.vy += gravity * dt;
// Integrate
state.x += state.vx * dt;
state.y += state.vy * dt;
// Floor
if (state.y > h - 20) {
state.y = h - 20;
state.vy = 0;
}
return {
particles: [{ x: state.x, y: state.y, r: 12, color: '#8B5CF6' }],
text: { x: state.x.toFixed(0), y: state.y.toFixed(0) },
};Restart on Key Press
javascript
if (state.gameOver && keys.r) {
state.init = false; // triggers re-init next frame
}Toggle with Single Press
Since keys tracks held state (not edge triggers), use a cooldown or flag:
javascript
if (!state.init) {
state.showTrail = true;
state.init = true;
}
if (keys.t && !state.lastT) {
state.showTrail = !state.showTrail;
}
state.lastT = keys.t;Multi-Key Combos
javascript
// diagonal movement
let dx = 0, dy = 0;
if (keys.ArrowLeft || keys.a) dx -= 1;
if (keys.ArrowRight || keys.d) dx += 1;
if (keys.ArrowUp || keys.w) dy -= 1;
if (keys.ArrowDown || keys.s) dy += 1;
// normalize diagonal
if (dx !== 0 && dy !== 0) {
dx *= 0.707;
dy *= 0.707;
}
state.x += dx * speed * dt;
state.y += dy * speed * dt;Lifecycle
Key pressed
→ keys[key] = true (on keydown)
→ your frame code reads it
→ Key released
→ keys[key] = false (on keyup)
→ Window loses focus
→ all keys cleared (on blur)Limitations
- No
keypressevents (character input) — only raw key state - Keys persist for the duration of the press; check every frame or use a tick timer
- Browser shortcuts may intercept some keys (e.g.
Ctrl+R,F5) - Module files do not receive
keys— pass it as a function argument
See Also
- Cheatsheet - globals overview
- Mouse & Click Tracking - click input
- Snake Game - full game example