Install
Terminal · npx$
npx skills add https://github.com/chongdashu/phaserjs-tinyswords --skill phaser-gamedevWorks with Paperclip
How Phaser Gamedev fits into a Paperclip company.
Phaser Gamedev drops into any Paperclip agent that handles this kind of work. Assign it to a specialist inside a pre-configured PaperclipOrg company and the skill becomes available on every heartbeat — no prompt engineering, no tool wiring.
S
SaaS FactoryPaired
Pre-configured AI company — 18 agents, 18 skills, one-time purchase.
$27$59
Explore packSource file
SKILL.md691 linesExpandCollapse
---name: phaser-gamedevdescription: > Build 2D games with Phaser 3 framework. Covers scene lifecycle, sprites, physics (Arcade/Matter), tilemaps, animations, input handling, and game architecture. Trigger: "create phaser game", "add phaser scene", "phaser sprite", "phaser physics", "game development with phaser".--- # Phaser Game Development Build fast, polished 2D browser games using Phaser 3's scene-based architecture and physics systems. ## Philosophy: Games as Living Systems Games are not static UIs—they are **dynamic systems** where entities interact, state evolves, and player input drives everything. Before writing code, think architecturally. **Before building, ask**:- What **scenes** does this game need? (Boot, Menu, Game, Pause, GameOver)- What **entities** exist and how do they interact?- What **state** must persist across scenes?- What **physics** model fits? (Arcade for speed, Matter for realism)- What **input methods** will players use? **Core principles**:1. **Scene-First Architecture**: Structure games around scenes, not global state2. **Composition Over Inheritance**: Build entities from game objects and components3. **Physics-Aware Design**: Choose physics system before coding collisions4. **Asset Pipeline Discipline**: Preload everything, reference by key5. **Frame-Rate Independence**: Use delta time, not frame counting --- ## Game Configuration Every Phaser game starts with a configuration object. ### Minimal Configuration ```javascriptconst config = { type: Phaser.AUTO, // WebGL with Canvas fallback width: 800, height: 600, scene: [BootScene, GameScene]}; const game = new Phaser.Game(config);``` ### Full Configuration Pattern ```javascriptconst config = { type: Phaser.AUTO, width: 800, height: 600, parent: 'game-container', // DOM element ID backgroundColor: '#2d2d2d', scale: { mode: Phaser.Scale.FIT, autoCenter: Phaser.Scale.CENTER_BOTH }, physics: { default: 'arcade', arcade: { gravity: { y: 300 }, debug: false // Enable during development } }, scene: [BootScene, MenuScene, GameScene, GameOverScene]};``` ### Physics System Choice | System | Use When ||--------|----------|| **Arcade** | Platformers, shooters, most 2D games. Fast, simple AABB collisions || **Matter** | Physics puzzles, ragdolls, realistic collisions. Slower, more accurate || **None** | Menu scenes, visual novels, card games | --- ## Scene Architecture Scenes are the fundamental organizational unit. Each scene has a lifecycle. ### Scene Lifecycle Methods ```javascriptclass GameScene extends Phaser.Scene { constructor() { super('GameScene'); // Scene key for reference } init(data) { // Called first. Receive data from previous scene this.level = data.level || 1; } preload() { // Load assets. Runs before create() this.load.image('player', 'assets/player.png'); this.load.spritesheet('enemy', 'assets/enemy.png', { frameWidth: 32, frameHeight: 32 }); } create() { // Set up game objects, physics, input this.player = this.physics.add.sprite(100, 100, 'player'); this.cursors = this.input.keyboard.createCursorKeys(); } update(time, delta) { // Game loop. Called every frame // delta = milliseconds since last frame this.player.x += this.speed * (delta / 1000); }}``` ### Scene Transitions ```javascript// Start a new scene (stops current)this.scene.start('GameOverScene', { score: this.score }); // Launch scene in parallel (both run)this.scene.launch('UIScene'); // Pause/resume scenesthis.scene.pause('GameScene');this.scene.resume('GameScene'); // Stop a scenethis.scene.stop('UIScene');``` ### Recommended Scene Structure ```scenes/├── BootScene.js # Asset loading, progress bar├── MenuScene.js # Title screen, options├── GameScene.js # Main gameplay├── UIScene.js # HUD overlay (launched parallel)├── PauseScene.js # Pause menu overlay└── GameOverScene.js # End screen, restart option``` --- ## Game Objects Everything visible in Phaser is a Game Object. ### Common Game Objects ```javascript// Images (static)this.add.image(400, 300, 'background'); // Sprites (can animate, physics-enabled)const player = this.add.sprite(100, 100, 'player'); // Textconst score = this.add.text(16, 16, 'Score: 0', { fontSize: '32px', fill: '#fff'}); // Graphics (draw shapes)const graphics = this.add.graphics();graphics.fillStyle(0xff0000);graphics.fillRect(100, 100, 50, 50); // Containers (group objects)const container = this.add.container(400, 300, [sprite1, sprite2]); // Tilemapsconst map = this.make.tilemap({ key: 'level1' });``` ### Sprite Creation Patterns ```javascript// Basic spriteconst sprite = this.add.sprite(x, y, 'textureKey'); // Sprite with physics bodyconst sprite = this.physics.add.sprite(x, y, 'textureKey'); // From spritesheet frameconst sprite = this.add.sprite(x, y, 'sheet', frameIndex); // From atlasconst sprite = this.add.sprite(x, y, 'atlas', 'frameName');``` --- ## Physics Systems ### Arcade Physics (Recommended Default) Fast, simple physics for most 2D games. ```javascript// Enable physics on spritethis.physics.add.sprite(x, y, 'player'); // Or add physics to existing spritethis.physics.add.existing(sprite); // Configure bodysprite.body.setVelocity(200, 0);sprite.body.setBounce(0.5);sprite.body.setCollideWorldBounds(true);sprite.body.setGravityY(300); // Collision detectionthis.physics.add.collider(player, platforms);this.physics.add.overlap(player, coins, collectCoin, null, this); function collectCoin(player, coin) { coin.disableBody(true, true); // Remove from physics and hide this.score += 10;}``` ### Physics Groups ```javascript// Static group (platforms, walls)const platforms = this.physics.add.staticGroup();platforms.create(400, 568, 'ground').setScale(2).refreshBody(); // Dynamic group (enemies, bullets)const enemies = this.physics.add.group({ key: 'enemy', repeat: 5, setXY: { x: 100, y: 0, stepX: 70 }}); enemies.children.iterate(enemy => { enemy.setBounce(Phaser.Math.FloatBetween(0.4, 0.8));});``` ### Matter Physics For realistic physics simulations. ```javascript// Configphysics: { default: 'matter', matter: { gravity: { y: 1 }, debug: true }} // Create bodiesconst ball = this.matter.add.circle(400, 100, 25);const box = this.matter.add.rectangle(400, 400, 100, 50, { isStatic: true }); // Sprite with Matter bodyconst player = this.matter.add.sprite(100, 100, 'player');player.setFriction(0.005);player.setBounce(0.9);``` --- ## Input Handling ### Keyboard Input ```javascript// Cursor keysthis.cursors = this.input.keyboard.createCursorKeys(); // In update()if (this.cursors.left.isDown) { player.setVelocityX(-160);} else if (this.cursors.right.isDown) { player.setVelocityX(160);} if (this.cursors.up.isDown && player.body.touching.down) { player.setVelocityY(-330); // Jump} // Custom keysthis.spaceKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE); // Key eventsthis.input.keyboard.on('keydown-SPACE', () => { this.fire();});``` ### Pointer/Mouse Input ```javascript// Click/tapthis.input.on('pointerdown', (pointer) => { console.log(pointer.x, pointer.y);}); // Make object interactivesprite.setInteractive();sprite.on('pointerdown', () => { sprite.setTint(0xff0000);});sprite.on('pointerup', () => { sprite.clearTint();}); // Dragthis.input.setDraggable(sprite);this.input.on('drag', (pointer, obj, dragX, dragY) => { obj.x = dragX; obj.y = dragY;});``` --- ## Animations ### Creating Animations ```javascript// In create() - define oncethis.anims.create({ key: 'walk', frames: this.anims.generateFrameNumbers('player', { start: 0, end: 3 }), frameRate: 10, repeat: -1 // Loop forever}); this.anims.create({ key: 'jump', frames: [{ key: 'player', frame: 4 }], frameRate: 20}); // From atlasthis.anims.create({ key: 'explode', frames: this.anims.generateFrameNames('atlas', { prefix: 'explosion_', start: 1, end: 8, zeroPad: 2 }), frameRate: 16, hideOnComplete: true});``` ### Playing Animations ```javascript// Play animationsprite.anims.play('walk', true); // true = ignore if already playing // Play oncesprite.anims.play('jump'); // Stopsprite.anims.stop(); // Animation eventssprite.on('animationcomplete', (anim, frame) => { if (anim.key === 'die') { sprite.destroy(); }});``` --- ## Asset Loading ### Preload Patterns ```javascriptpreload() { // Images this.load.image('sky', 'assets/sky.png'); // Spritesheets this.load.spritesheet('player', 'assets/player.png', { frameWidth: 32, frameHeight: 48 }); // Atlases (TexturePacker) this.load.atlas('sprites', 'assets/sprites.png', 'assets/sprites.json'); // Tilemaps this.load.tilemapTiledJSON('map', 'assets/level1.json'); this.load.image('tiles', 'assets/tileset.png'); // Audio this.load.audio('bgm', 'assets/music.mp3'); this.load.audio('sfx', ['assets/sound.ogg', 'assets/sound.mp3']); // Progress tracking this.load.on('progress', (value) => { console.log(`Loading: ${Math.round(value * 100)}%`); });}``` ### Boot Scene Pattern ```javascriptclass BootScene extends Phaser.Scene { constructor() { super('BootScene'); } preload() { // Loading bar const width = this.cameras.main.width; const height = this.cameras.main.height; const progressBar = this.add.graphics(); const progressBox = this.add.graphics(); progressBox.fillStyle(0x222222, 0.8); progressBox.fillRect(width/2 - 160, height/2 - 25, 320, 50); this.load.on('progress', (value) => { progressBar.clear(); progressBar.fillStyle(0xffffff, 1); progressBar.fillRect(width/2 - 150, height/2 - 15, 300 * value, 30); }); // Load all game assets here this.load.image('player', 'assets/player.png'); // ... more assets } create() { this.scene.start('MenuScene'); }}``` --- ## Tilemaps (Tiled Integration) ### Loading and Creating ```javascriptpreload() { this.load.tilemapTiledJSON('map', 'assets/map.json'); this.load.image('tiles', 'assets/tileset.png');} create() { const map = this.make.tilemap({ key: 'map' }); const tileset = map.addTilesetImage('tileset-name-in-tiled', 'tiles'); // Create layers (match names from Tiled) const backgroundLayer = map.createLayer('Background', tileset, 0, 0); const groundLayer = map.createLayer('Ground', tileset, 0, 0); // Enable collision on specific tiles groundLayer.setCollisionByProperty({ collides: true }); // Or by tile index groundLayer.setCollisionBetween(1, 100); // Add collision with player this.physics.add.collider(this.player, groundLayer);}``` ### Object Layers ```javascript// Spawn points from Tiled object layerconst spawnPoint = map.findObject('Objects', obj => obj.name === 'spawn');this.player = this.physics.add.sprite(spawnPoint.x, spawnPoint.y, 'player'); // Create objects from layerconst coins = map.createFromObjects('Objects', { name: 'coin', key: 'coin'});this.physics.world.enable(coins);``` --- ## Project Structure ### Recommended Organization ```game/├── src/│ ├── scenes/│ │ ├── BootScene.js│ │ ├── MenuScene.js│ │ ├── GameScene.js│ │ └── UIScene.js│ ├── gameObjects/│ │ ├── Player.js│ │ ├── Enemy.js│ │ └── Collectible.js│ ├── systems/│ │ ├── InputManager.js│ │ └── AudioManager.js│ ├── config/│ │ └── gameConfig.js│ └── main.js├── assets/│ ├── images/│ ├── audio/│ ├── tilemaps/│ └── fonts/├── index.html└── package.json``` ### ES Module Setup ```javascript// main.jsimport Phaser from 'phaser';import BootScene from './scenes/BootScene';import GameScene from './scenes/GameScene';import { gameConfig } from './config/gameConfig'; const config = { ...gameConfig, scene: [BootScene, GameScene]}; new Phaser.Game(config);``` --- ## Anti-Patterns to Avoid ❌ **Global State Soup**: Storing game state on `window` or module globals**Why bad**: Untrackable bugs, scene transitions break state**Better**: Use scene data, registries, or dedicated state managers ❌ **Loading in Create**: Loading assets in `create()` instead of `preload()`**Why bad**: Assets may not be ready when referenced**Better**: Always load in `preload()`, use Boot scene for all assets ❌ **Frame-Dependent Logic**: Using frame count instead of delta time**Why bad**: Game speed varies with frame rate**Better**: `this.speed * (delta / 1000)` for consistent movement ❌ **Physics Overkill**: Using Matter for simple platformer collisions**Why bad**: Performance hit, unnecessary complexity**Better**: Arcade physics handles 90% of 2D game needs ❌ **Monolithic Scenes**: One giant scene with all game logic**Why bad**: Unmaintainable, hard to add features**Better**: Separate scenes for menus, gameplay, UI overlays ❌ **Magic Numbers**: Hardcoded values scattered in code**Why bad**: Impossible to balance, inconsistent**Better**: Config objects, constants files ❌ **Ignoring Object Pooling**: Creating/destroying objects every frame**Why bad**: Memory churn, garbage collection stutters**Better**: Use groups with `setActive(false)` / `setVisible(false)` ❌ **Synchronous Asset Access**: Assuming assets load instantly**Why bad**: Race conditions, undefined textures**Better**: Chain scene starts, use load events ❌ **Assuming Spritesheet Frame Dimensions**: Using guessed frame sizes without verifying**Why bad**: Wrong dimensions cause silent frame corruption; off-by-pixels compounds into broken visuals**Better**: Open asset file, measure frames, calculate with spacing/margin, verify math adds up ❌ **Ignoring Spritesheet Spacing**: Not specifying `spacing` for gapped spritesheets**Why bad**: Frames shift progressively; later frames read wrong pixel regions**Better**: Check source asset for gaps between frames; use `spacing: N` in loader config ❌ **Hardcoding Nine-Slice Colors**: Using single background color for all UI panel variants**Why bad**: Transparent frame edges reveal wrong color for different asset color schemes**Better**: Per-asset background color config; sample from center frame (frame 4) ❌ **Nine-Slice with Padded Frames**: Treating the full frame as the slice region when the art is centered/padded inside each tile**Why bad**: Edge tiles contribute interior fill, showing up as opaque “side bars” inside the panel**Better**: Trim tiles to their effective content bounds (alpha bbox) and composite/cache a texture; add ~1px overlap + disable smoothing to avoid seams ❌ **Scaling Discontinuous UI Art**: Stretching a cropped ribbon/banner row that contains internal transparent gaps**Why bad**: The transparent gutters get stretched, so the UI looks segmented or the fill disappears behind the frame.**Better**: Slice the asset into caps/center, stretch only the center, and stitch the pieces (with ~1px overlap + smoothing disabled) before rendering at pivot sizes. --- ## Variation Guidance **IMPORTANT**: Game implementations should vary based on: - **Game Genre**: Platformer physics differ from top-down shooter physics- **Target Platform**: Mobile needs touch input, desktop can use keyboard- **Art Style**: Pixel art uses nearest-neighbor scaling, HD art uses linear- **Performance Needs**: Many sprites → object pooling; few sprites → simple creation- **Complexity**: Simple games can inline; complex games need class hierarchies **Avoid converging on**:- Always using 800x600 resolution- Always using Arcade physics- Always using the same scene structure- Copy-pasting boilerplate without adaptation --- ## Quick Reference ### Common Physics Properties ```javascriptbody.setVelocity(x, y)body.setVelocityX(x)body.setBounce(x, y)body.setGravityY(y)body.setCollideWorldBounds(true)body.setImmovable(true) // For static-like dynamic bodiesbody.setDrag(x, y)body.setMaxVelocity(x, y)``` ### Useful Scene Properties ```javascriptthis.cameras.main // Main camerathis.physics.world // Physics worldthis.input.keyboard // Keyboard managerthis.sound // Audio managerthis.time // Time/clock managerthis.tweens // Tween managerthis.anims // Animation managerthis.registry // Cross-scene data storethis.data // Scene-specific data store``` ### Essential Events ```javascript// Scene eventsthis.events.on('pause', callback)this.events.on('resume', callback)this.events.on('shutdown', callback) // Physics eventsthis.physics.world.on('worldbounds', callback) // Game object eventssprite.on('destroy', callback)sprite.on('animationcomplete', callback)``` --- ## See Also - **references/arcade-physics.md** - Deep dive into Arcade physics- **references/tilemaps.md** - Advanced tilemap techniques- **references/performance.md** - Optimization strategies- **references/spritesheets-nineslice.md** - Spritesheet loading (spacing/margin), nine-slice UI panels, asset inspection --- ## Remember Phaser gives you powerful primitives—scenes, sprites, physics, input—but **architecture is your responsibility**. Think in systems: What scenes do you need? What entities exist? How do they interact? Answer these questions before writing code, and your game will be maintainable as it grows. **Claude is capable of building complete, polished Phaser games. These guidelines illuminate the path—they don't fence it.**Related skills
1password
Install 1password skill for Claude Code from steipete/clawdis.
3d Web Experience
Install 3d Web Experience skill for Claude Code from sickn33/antigravity-awesome-skills.
Ab Test Setup
This handles the full A/B testing workflow from hypothesis formation to statistical analysis. It walks you through proper test design, calculates sample sizes,