
input-keyboard-mouse-touch
Use this skill when handling user input in Phaser 4. Covers keyboard keys, mouse clicks and movement, touch events, pointer handling, drag and drop, hit areas, interactive objects, and gamepad support. Triggers on: keyboard, mouse, touch, pointer, drag, drop, click, input, gamepad, cursor keys.
- Installs
- 952
- Last 24h
- —
- Trending rank
- —
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/phaserjs/phaser --skill input-keyboard-mouse-touch- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads input-keyboard-mouse-touch automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
Input: Keyboard, Mouse, Touch, and Gamepad
Phaser provides a unified input system accessed via
this.inputin any Scene. It supports keyboard polling and events, mouse/pointer interaction with Game Objects (click, hover, drag), multi-touch, mouse wheel, and gamepad input. Input can be handled through event listeners or by polling state each frame.
Key source paths: src/input/InputPlugin.js, src/input/Pointer.js, src/input/keyboard/KeyboardPlugin.js, src/input/keyboard/keys/Key.js, src/input/keyboard/keys/KeyCodes.js, src/input/keyboard/combo/KeyCombo.js, src/input/gamepad/GamepadPlugin.js, src/input/gamepad/Gamepad.js, src/input/events/, src/input/keyboard/events/
Related skills: ../sprites-and-images/SKILL.md, ../events-system/SKILL.md, ../scenes/SKILL.md
Quick Start (basic keyboard + pointer input)
class MyScene extends Phaser.Scene {
create() {
// Keyboard: create cursor keys (up, down, left, right, space, shift)
this.cursors = this.input.keyboard.createCursorKeys();
// Keyboard: listen for a specific key event
this.input.keyboard.on('keydown-SPACE', (event) => {
console.log('Space pressed');
});
// Pointer: listen for click/tap anywhere on the game canvas
this.input.on('pointerdown', (pointer) => {
console.log('Clicked at', pointer.x, pointer.y);
});
// Pointer: make a Game Object interactive and clickable
const sprite = this.add.sprite(400, 300, 'player');
sprite.setInteractive();
sprite.on('pointerdown', (pointer, localX, localY, event) => {
console.log('Sprite clicked at local', localX, localY);
});
}
update() {
// Poll cursor keys each frame
if (this.cursors.left.isDown) {
// move left
}
if (this.cursors.right.isDown) {
// move right
}
if (Phaser.Input.Keyboard.JustDown(this.cursors.space)) {
// fire once per press
}
}
}
Core Concepts
The Input Plugin (this.input)
Accessed via this.input in any Scene. It is an EventEmitter that handles all input for that Scene.
Key properties:
this.input.enabled(boolean) - toggle input processing for the Scenethis.input.topOnly(boolean, defaulttrue) - only emit events from the top-most Game Object under the pointerthis.input.keyboard- the KeyboardPlugin instancethis.input.gamepad- the GamepadPlugin instancethis.input.mouse- the MouseManager referencethis.input.activePointer- the most recently active Pointerthis.input.mousePointer- the mouse Pointer (pointers[0], distinct from pointer1 which is the first touch)this.input.pointer1throughthis.input.pointer10- individual pointer referencesthis.input.dragDistanceThreshold(number, default 0) - pixels a pointer must move before drag startsthis.input.dragTimeThreshold(number, default 0) - ms a pointer must be held before drag startsthis.input.pollRate(number, default -1) - how often pointers are polled; 0 = every frame, -1 = only on movement
Key methods:
addPointer(quantity)- add extra pointers for multi-touch (default is 2; max 10)setHitArea(gameObjects, hitArea, hitAreaCallback)- set custom hit area on Game ObjectssetHitAreaCircle(gameObjects, x, y, radius, callback)setHitAreaEllipse(gameObjects, x, y, width, height, callback)setHitAreaRectangle(gameObjects, x, y, width, height, callback)setHitAreaTriangle(gameObjects, x1, y1, x2, y2, x3, y3, callback)setHitAreaFromTexture(gameObjects, callback)- use the texture frame dimensionssetDraggable(gameObjects, value)- enable or disable draggingmakePixelPerfect(alphaTolerance)- returns a callback for pixel-perfect hit testing
Pointers
A Pointer object encapsulates both mouse and touch input. By default Phaser creates 2 pointers. Use this.input.addPointer(quantity) for more (up to 10 total).
Key properties:
x,y- position in screen space (read fromposition.x,position.y)worldX,worldY- position translated through the most recent CameradownX,downY- position when button was pressedupX,upY- position when button was releasedisDown(boolean) - true if any button is heldprimaryDown(boolean) - true if primary button (left click / touch) is heldbutton(number) - which button was pressed/released (0=left, 1=middle, 2=right)buttons(number) - bitmask of currently held buttons (1=left, 2=right, 4=middle, 8=back, 16=forward)wasTouch(boolean) - true if input came from touchvelocity(Vector2) - smoothed velocity of pointer movementangle(number) - angle of movement in radiansdistance(number) - smoothed distance moved per framemovementX,movementY- relative movement when pointer is lockeddeltaX,deltaY,deltaZ- mouse wheel scroll amountslocked(boolean) - whether pointer lock is activecamera- the Camera this Pointer last interacted with
Key methods:
leftButtonDown(),rightButtonDown(),middleButtonDown(),backButtonDown(),forwardButtonDown()- check specific buttonsleftButtonReleased(),rightButtonReleased(),middleButtonReleased()- check recent releasegetDistance()- distance between down position and current/up positiongetDistanceX(),getDistanceY()- horizontal/vertical distancegetDuration()- ms between down and current time or up timegetAngle()- angle between down and current/up positionupdateWorldPoint(camera)- recalculate worldX/worldY for a given camerapositionToCamera(camera, output)- translate pointer position through a camera
Interactive Game Objects (setInteractive)
Call gameObject.setInteractive() to enable input on a Game Object. This uses the texture frame as the hit area by default.
// Default hit area from texture
sprite.setInteractive();
// Custom shape hit areas (Rectangle, Circle, Ellipse, Triangle, Polygon)
sprite.setInteractive(new Phaser.Geom.Circle(32, 32, 32), Phaser.Geom.Circle.Contains);
sprite.setInteractive(new Phaser.Geom.Ellipse(50, 50, 100, 60), Phaser.Geom.Ellipse.Contains);
sprite.setInteractive(new Phaser.Geom.Triangle(0,64,32,0,64,64), Phaser.Geom.Triangle.Contains);
sprite.setInteractive(new Phaser.Geom.Polygon(points), Phaser.Geom.Polygon.Contains);
// Pixel-perfect hit testing (expensive — use sparingly)
sprite.setInteractive({ pixelPerfect: true, alphaTolerance: 1 });
sprite.setInteractive(this.input.makePixelPerfect());
// With alpha tolerance (default 1):
sprite.setInteractive(this.input.makePixelPerfect(150));
// Config object with multiple options
sprite.setInteractive({
draggable: true,
dropZone: false,
useHandCursor: true,
cursor: 'pointer',
pixelPerfect: true,
alphaTolerance: 1
});
// Containers must specify a shape or call setSize first
container.setSize(200, 200);
container.setInteractive();
Common Patterns
Keyboard Input (cursors, addKey, isDown, JustDown)
Cursor keys return an object with up, down, left, right, space, shift Key objects:
this.cursors = this.input.keyboard.createCursorKeys();
// In update():
if (this.cursors.up.isDown) { /* held */ }
if (this.cursors.space.isDown) { /* held */ }
addKey creates a Key object for any key:
// By string name
const keyW = this.input.keyboard.addKey('W');
// By key code
const keySpace = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE);
// With options: addKey(key, enableCapture, emitOnRepeat)
const keyA = this.input.keyboard.addKey('A', true, false);
addKeys creates multiple keys at once:
// Comma-separated string returns { W, S, A, D } Key objects
const keys = this.input.keyboard.addKeys('W,S,A,D');
if (keys.W.isDown) { /* ... */ }
// Object form with custom names
const keys = this.input.keyboard.addKeys({
up: Phaser.Input.Keyboard.KeyCodes.W,
down: Phaser.Input.Keyboard.KeyCodes.S,
left: Phaser.Input.Keyboard.KeyCodes.A,
right: Phaser.Input.Keyboard.KeyCodes.D
});
Polling vs events:
// Polling in update() - check every frame
if (keyW.isDown) { /* key is currently held */ }
if (keyW.isUp) { /* key is currently released */ }
// JustDown - returns true only once per press, resets after check
if (Phaser.Input.Keyboard.JustDown(keyW)) { /* fire once */ }
if (Phaser.Input.Keyboard.JustUp(keyW)) { /* released once */ }
// checkDown with duration - throttled polling
if (this.input.keyboard.checkDown(keySpace, 250)) {
// true at most once every 250ms while held
}
// Event-driven: listen for specific key
this.input.keyboard.on('keydown-SPACE', (event) => { /* ... */ });
this.input.keyboard.on('keyup-SPACE', (event) => { /* ... */ });
// Event-driven: listen for any key
this.input.keyboard.on('keydown', (event) => {
console.log(event.key); // native DOM KeyboardEvent
});
// Event on a Key object itself
const spaceBar = this.input.keyboard.addKey('SPACE');
spaceBar.on('down', (key, event) => { /* Key object + native event */ });
spaceBar.on('up', (key, event) => { /* ... */ });
Key object properties:
isDown/isUp(boolean)keyCode(number)altKey,ctrlKey,shiftKey,metaKey(boolean) - modifier state when pressedduration(number) - ms held in previous down-up cycletimeDown,timeUp(number) - timestampsrepeats(number) - repeat count while heldemitOnRepeat(boolean) - if true, fires 'down' event on each repeatenabled(boolean) - can this key be processed
Prevent browser default behavior:
// Capture specific keys to prevent browser scrolling etc.
this.input.keyboard.addCapture('SPACE,UP,DOWN,LEFT,RIGHT');
this.input.keyboard.addCapture([ 32, 37, 38, 39, 40 ]);
this.input.keyboard.removeCapture('SPACE');
// Note: captures are global across all Scenes
Common KeyCodes: BACKSPACE(8), TAB(9), ENTER(13), SHIFT(16), CTRL(17), ALT(18), ESC(27), SPACE(32), LEFT(37), UP(38), RIGHT(39), DOWN(40), A-Z(65-90), ZERO-NINE(48-57), F1-F12(112-123). Access via Phaser.Input.Keyboard.KeyCodes.SPACE etc.
Mouse/Pointer Click and Hover
Scene-level pointer events (fire anywhere on the canvas):
this.input.on('pointerdown', (pointer, currentlyOver) => {
// pointer: Pointer object, currentlyOver: array of interactive Game Objects under pointer
});
this.input.on('pointerup', (pointer, currentlyOver) => { /* ... */ });
this.input.on('pointermove', (pointer, currentlyOver) => { /* ... */ });
this.input.on('wheel', (pointer, currentlyOver, deltaX, deltaY, deltaZ) => { /* ... */ });
Game Object pointer events (require setInteractive):
sprite.setInteractive();
// pointerdown on this specific object
sprite.on('pointerdown', (pointer, localX, localY, event) => {
// localX/localY are relative to the Game Object's top-left
// event.stopPropagation() prevents the event from going further
});
sprite.on('pointerup', (pointer, localX, localY, event) => { /* ... */ });
sprite.on('pointermove', (pointer, localX, localY, event) => { /* ... */ });
sprite.on('pointerover', (pointer, localX, localY, event) => { /* ... */ });
sprite.on('pointerout', (pointer, event) => { /* ... */ });
sprite.on('wheel', (pointer, deltaX, deltaY, deltaZ, event) => { /* ... */ });
Right-click handling:
this.input.on('pointerdown', (pointer) => {
if (pointer.rightButtonDown()) {
// right-click
}
});
// Disable context menu
this.input.mouse.disableContextMenu();
Pointer lock (FPS-style mouse capture):
// Request lock on click
this.input.on('pointerdown', () => {
this.input.mouse.requestPointerLock();
});
this.input.on('pointerlockchange', (event, locked) => {
// locked: boolean
});
// Read relative movement while locked
// pointer.movementX, pointer.movementY
Drag and Drop
const sprite = this.add.sprite(400, 300, 'item');
sprite.setInteractive();
this.input.setDraggable(sprite);
// Or use config:
// sprite.setInteractive({ draggable: true });
// Drag events on the Scene input
this.input.on('dragstart', (pointer, gameObject) => {
gameObject.setTint(0xff0000);
});
this.input.on('drag', (pointer, gameObject, dragX, dragY) => {
gameObject.x = dragX;
gameObject.y = dragY;
});
this.input.on('dragend', (pointer, gameObject) => {
gameObject.clearTint();
});
// Drop zones
const zone = this.add.zone(600, 300, 200, 200).setRectangleDropZone(200, 200);
this.input.on('drop', (pointer, gameObject, dropZone) => {
gameObject.x = dropZone.x;
gameObject.y = dropZone.y;
});
this.input.on('dragenter', (pointer, gameObject, dropZone) => { /* ... */ });
this.input.on('dragleave', (pointer, gameObject, dropZone) => { /* ... */ });
this.input.on('dragover', (pointer, gameObject, dropZone) => { /* ... */ });
Game Object-level drag events are also available:
sprite.on('drag', (pointer, dragX, dragY) => {
sprite.x = dragX;
sprite.y = dragY;
});
sprite.on('dragstart', (pointer, dragX, dragY) => { /* ... */ });
sprite.on('dragend', (pointer, dragX, dragY) => { /* ... */ });
sprite.on('drop', (pointer, dropZone) => { /* ... */ });
Drag thresholds:
this.input.dragDistanceThreshold = 16; // must move 16px before drag starts
this.input.dragTimeThreshold = 200; // must hold 200ms before drag starts
Three Levels of Pointer Events
Pointer events fire at three levels (see reference for details):
- Game Object:
gameObject.on('pointerdown', (pointer, localX, localY, event) => {}) - Scene per-object:
this.input.on('gameobjectdown', (pointer, gameObject, event) => {}) - Scene global:
this.input.on('pointerdown', (pointer, currentlyOver) => {})
Input Debug, topOnly, and Multi-touch Config
// Debug visualize hit areas
this.input.enableDebug(gameObject);
this.input.enableDebug(gameObject, 0xff00ff);
this.input.removeDebug(gameObject);
// Let all objects under pointer receive events (not just top-most)
this.input.topOnly = false;
this.input.setTopOnly(false);
Multi-touch: set config.input.activePointers to reserve pointer slots at startup, or call this.input.addPointer(num) at runtime. Access via this.input.pointer1 through pointer10.
Gamepad Input
Enable gamepads in the game config:
const config = {
input: {
gamepad: true
}
};
Access via this.input.gamepad. Gamepads are available as pad1 through pad4:
// Wait for connection
this.input.gamepad.once('connected', (pad) => {
console.log('Gamepad connected:', pad.id);
});
// If already connected, check total
if (this.input.gamepad.total > 0) {
const pad = this.input.gamepad.pad1;
}
Polling gamepad state in update():
update() {
const pad = this.input.gamepad.pad1;
if (!pad) return;
// D-pad (boolean properties)
if (pad.up) { /* d-pad up */ }
if (pad.down) { /* d-pad down */ }
if (pad.left) { /* d-pad left */ }
if (pad.right) { /* d-pad right */ }
// Face buttons (boolean) - Xbox naming convention
if (pad.A) { /* bottom button (Xbox A / PS X) */ }
if (pad.B) { /* right button (Xbox B / PS Circle) */ }
if (pad.X) { /* left button (Xbox X / PS Square) */ }
if (pad.Y) { /* top button (Xbox Y / PS Triangle) */ }
// Shoulder buttons (float 0-1)
if (pad.L1 > 0) { /* left shoulder top (LB) */ }
if (pad.L2 > 0) { /* left shoulder bottom / trigger (LT) */ }
if (pad.R1 > 0) { /* right shoulder top (RB) */ }
if (pad.R2 > 0) { /* right shoulder bottom / trigger (RT) */ }
// Analog sticks (Vector2, values -1 to 1)
const lx = pad.leftStick.x; // left stick horizontal
const ly = pad.leftStick.y; // left stick vertical
const rx = pad.rightStick.x;
const ry = pad.rightStick.y;
// Raw axis/button access
pad.getAxisValue(0); // float
pad.getButtonValue(0); // float 0-1
pad.isButtonDown(0); // boolean
pad.setAxisThreshold(0.1); // ignore values below threshold
}
Gamepad events:
// Plugin-level events (any gamepad)
this.input.gamepad.on('connected', (pad, event) => { /* ... */ });
this.input.gamepad.on('disconnected', (pad, event) => { /* ... */ });
this.input.gamepad.on('down', (pad, button, value) => { /* any button on any pad */ });
this.input.gamepad.on('up', (pad, button, value) => { /* ... */ });
// Gamepad-instance events
pad.on('down', (index, value, button) => { /* button on this specific pad */ });
pad.on('up', (index, value, button) => { /* ... */ });
Vibration (experimental, hardware/browser dependent):
if (pad.vibration) {
pad.vibration.playEffect('dual-rumble', {
duration: 200,
strongMagnitude: 1.0,
weakMagnitude: 0.5
});
}
Key Combos
Listen for a sequence of keys:
// String-based combo
this.input.keyboard.createCombo('PHASER');
// Array of key codes (Konami code)
this.input.keyboard.createCombo(
[ 38, 38, 40, 40, 37, 39, 37, 39, 66, 65, 13 ],
{ resetOnMatch: true }
);
// Listen for match
this.input.keyboard.on('keycombomatch', (keyCombo, event) => {
console.log('Combo matched!');
});
createCombo(keys, config):
keys: a string (each character is a key) or an array of key codes / Key objectsconfig.resetOnWrongKey(boolean, default true) - reset progress if wrong key is pressedconfig.maxKeyDelay(number, default 0) - max ms between key presses; 0 = no limitconfig.resetOnMatch(boolean, default false) - reset combo after a successful matchconfig.deleteOnMatch(boolean, default false) - remove combo after first match
For detailed configuration options, API reference tables, and source file maps, see the reference guide.
FAQ
What does the input-keyboard-mouse-touch skill do?
Use this skill when handling user input in Phaser 4. Covers keyboard keys, mouse clicks and movement, touch events, pointer handling, drag and drop, hit areas, interactive objects, and gamepad support. Triggers on: keyboard, mouse, touch, pointer, drag, drop, click, input, gamepad, cursor keys.
How do I install input-keyboard-mouse-touch?
Run npx skills add https://github.com/phaserjs/phaser --skill input-keyboard-mouse-touch in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/input-keyboard-mouse-touch/ (personal) or .claude/skills/input-keyboard-mouse-touch/ (project).
Which AI agents can use input-keyboard-mouse-touch?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is input-keyboard-mouse-touch safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains input-keyboard-mouse-touch?
It is published by phaserjs in phaserjs/phaser. It has 952 recorded installs.
More from phaserjs/phaser
game-setup-and-config
phaserjs/phaser
Use this skill when creating a new Phaser 4 game instance or configuring GameConfig options. Covers renderer selection, canvas setup, scaling, pixel art, FPS settings, boot sequence, and all config sub-objects. Triggers on: new Phaser.Game, GameConfig, game setup, renderer, pixel art, FPS.
sprites-and-images
phaserjs/phaser
Use this skill when creating Sprites or Images in Phaser 4. Covers factory methods, texture/frame selection, position, scale, rotation, tint, flip, alpha, origin, depth, and the component mixin system. Triggers on: Sprite, Image, this.add.sprite, this.add.image, texture, setTint, setAlpha.
animations
phaserjs/phaser
Use this skill when creating or controlling sprite animations in Phaser 4. Covers spritesheets, atlases, AnimationManager, AnimationState, play/stop/chain, frame callbacks, and animation events. Triggers on: sprite animation, spritesheet, play animation, animation frames.
tilemaps
phaserjs/phaser
Use this skill when working with tilemaps in Phaser 4. Covers loading Tiled JSON maps, creating tilemap layers, tile collision, dynamic tiles, tile properties, and tilemap camera culling. Triggers on: Tilemap, Tiled, tilemap layer, tile collision, tile properties.
v4-new-features
phaserjs/phaser
Use this skill when learning about new features, game objects, components, and rendering capabilities added in Phaser 4. Covers Filters, RenderNodes, CaptureFrame, Gradient, Noise, SpriteGPULayer, TilemapGPULayer, Lighting component, RenderSteps, and new tint modes. Triggers on: new in v4, Phaser 4 features, RenderNode, SpriteGPULayer, CaptureFrame, Gradient game object, Noise game object, new tint modes. For migrating v3 code to v4, see the v3-to-v4-migration skill instead.
scenes
phaserjs/phaser
Use this skill when working with Phaser 4 scenes. Covers scene lifecycle methods, scene transitions, parallel scenes, scene communication, sleeping, pausing, restarting, and the SceneManager. Triggers on: Scene, scene lifecycle, preload, create, update, scene transition, SceneManager.
Popular other skills
hyperframes-cli
heygen-com/hyperframes
The HyperFrames CLI by job - scaffold, check, look at frames, edit the timeline, preview, render locally or in the cloud, publish, project history - plus reading its JSON and recovering from build or render failures.
triage
mattpocock/skills
Move issues and external PRs through a state machine of triage roles, categorise, verify, grill if needed, and write agent-ready briefs.
ask-matt
mattpocock/skills
Ask which skill or flow fits your situation. A router over the skills in this repo.
to-questionnaire
mattpocock/skills
Turn a decision you can't fully answer into a questionnaire for someone else to fill in.
loop-me
mattpocock/skills
Grill me about specs for the workflows I want to build, within this workspace.