Skip to content
Development
Skill

/phaser-core

Sets up and debugs Phaser 4 games (and pinned Phaser 3.90): Game config, Scene lifecycle, the loader, scene transitions and Phaser 3 to 4 migration. Use when code imports phaser, or on a black screen, assets undefined in create, or a HUD scene behind the game. Not for colliders

From plugin
awesome-gamedev-agent-skills
8.6k79 skills

Claude Code

$ npx -y skills add gamedev-skills/awesome-gamedev-agent-skills --skill phaser-core --agent claude-code

SKILL.md

phaser-core.SKILL.md
name: phaser-core
description: >
  Sets up and debugs Phaser 4 games (and pinned Phaser 3.90): Game config, Scene lifecycle, the
  loader, scene transitions and Phaser 3 to 4 migration. Use when code imports phaser, or on a
  black screen, assets undefined in create, or a HUD scene behind the game. Not for colliders
  (`phaser-arcade-physics`), HUD layout (`game-ui-ux`) or PixiJS (`pixijs-rendering`).

Phaser 4 core

Builds the foundation of a Phaser game: one `Phaser.Game`, a scene per screen, assets loaded per scene into a global cache, and a clear split between game rules and the scenes that draw them. New projects target **Phaser 4.2**. A project pinned to Phaser 3.90 stays on 3.x unless the user asks for a migration.

When to use

  • Starting a Phaser game, structuring scenes, loading assets, wiring cameras, passing data

between scenes, or porting Phaser 3 code to Phaser 4.

  • The project has `phaser` in `package.json`, `import Phaser from 'phaser'`, or classes that

extend `Phaser.Scene`.

  • Not for bodies, colliders and movement (`phaser-arcade-physics`), Matter.js physics, or

engine-neutral menu and HUD design (`game-ui-ux`; load it next to this skill for UI work).

Workflow

1. **Read the installed major.** Check `package.json` and the lockfile. Phaser 3 and 4 share the scene model but not the renderer, so a v3 snippet can run and still look wrong in v4. 2. **Keep rules out of scenes.** Put state and rules (score, turns, inventory, AI) in plain modules with no Phaser import. A scene reads that state, draws it, and sends input actions back. The rules then run under `node --test` without a browser, and a restart is just new state. 3. **Create one game from a config** with `type: Phaser.AUTO`, a size, a `scale` mode and a `scene` array. The first scene in the array (and any with `active: true`) starts on boot. 4. **One `Scene` subclass per screen** with a unique key. Reset run state in `init()`, queue assets in `preload()`, build objects in `create()`, step in `update(time, delta)`. 5. **Move between screens with the right verb** (`start`, `launch`, `run`, `switch`, `sleep`; see Patterns 4) and share data through `this.registry` or a scene's `events`. 6. **Pick where UI lives.** A score or health readout fits a parallel HUD scene. Text-heavy menus and settings work better as HTML over the canvas (`this.add.dom` or a plain overlay). 7. **Verify** with the build and the headless smoke check in [Verify](#verify).

Patterns

1. Game config and boot

// main.js: one Game owns the renderer, loop, cache and Scene Manager.
import Phaser from 'phaser';
import BootScene from './scenes/BootScene.js';
import PlayScene from './scenes/PlayScene.js';
import HudScene from './scenes/HudScene.js';

const config = {
  type: Phaser.AUTO,               // WebGL, Canvas only as a fallback
  parent: 'game',                  // id of the element that holds the canvas
  width: 800,
  height: 600,
  backgroundColor: '#1d1d28',
  scale: { mode: Phaser.Scale.FIT, autoCenter: Phaser.Scale.CENTER_BOTH },
  dom: { createContainer: true },  // only if you use this.add.dom(); needs `parent`
  scene: [BootScene, PlayScene, HudScene], // later in the list = drawn on top
};

const game = new Phaser.Game(config);
Object.assign(window, { game }); // for the smoke check and console debugging (TS-safe)

2. A scene with the full lifecycle

// scenes/PlayScene.js
import Phaser from 'phaser';
import { createRun, stepRun } from '../rules/run.js'; // plain module, no Phaser import

export default class PlayScene extends Phaser.Scene {
  constructor() {
    super('play');
  }

  init(data) {
    this.run = createRun({ level: data.level ?? 1 }); // runs on every (re)start
  }

  preload() {
    this.load.image('player', 'assets/player.png');
    this.load.spritesheet('coin', 'assets/coin.png', { frameWidth: 16, frameHeight: 16 });
  }

  create() {
    this.player = this.add.sprite(400, 300, 'player');
    this.cursors = this.input.keyboard.createCursorKeys();
    if (!this.scene.isActive('hud')) this.scene.launch('hud');
  }

  update(time, delta) {
    const dir = (this.cursors.right.isDown ? 1 : 0) - (this.cursors.left.isDown ? 1 : 0);
    stepRun(this.run, { dir }, delta / 1000); // delta is milliseconds
    this.player.x = this.run.playerX;
    this.registry.set('score', this.run.score);
  }
}

3. Cross-scene data and events

// HUD scene: react to registry changes instead of polling every frame.
create() {
  this.scoreText = this.add.text(10, 10, 'Score: 0', { fontSize: '20px', color: '#fff' });
  const onScore = (_parent, value) => this.scoreText.setText(`Score: ${value}`);
  this.registry.events.on('changedata-score', onScore);
  // The registry outlives scenes: remove the listener or it stacks on every restart.
  this.events.once('shutdown', () => this.registry.events.off('changedata-score', onScore));
}

// Talk to another running scene directly through its event emitter.
this.scene.get('hud').events.emit('show-message', 'Level cleared!');

4. Scene transitions

this.scene.start('gameover', { score }); // stop this scene, start the target
this.scene.launch('hud');                // run in parallel; restarts it if already running
this.scene.run('hud');                   // wake if asleep, resume if paused, else start
this.scene.switch('menu');               // sleep this scene, start or wake the target
this.scene.pause();                      // stop updating, keep drawing (modal menus)
this.scene.sleep();                      // stop updating and drawing, keep state
this.scene.bringToTop('hud');            // draw order follows the scene list

5. HTML over the canvas

// Requires dom.createContainer and parent in the game config (Pattern 1).
const panel = this.add.dom(400, 300).createFromHTML(`
  <form class="settings"><label>Volume <input name="vol" type="range"></label></form>`);
panel.addListener('input');
Read more
@gamedev-skills
Ships withawesome-gamedev-agent-skills

<img src="docs/assets/awesome-gamedev-agent-skills-banner.png" width="820" alt="awesome-gamedev-agent-skills — game-dev skills for AI coding agents.

Stars on GitHub

Momentum

stars in total
8.6k
Star history of gamedev-skills/awesome-gamedev-agent-skills on GitHub, a chart by star-history.com

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills13d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc2w293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react4d252k
@facebook@facebookInstall Skill

Questions about phaser-core.

Which coding agents can use phaser-core?
phaser-core installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.