
The API
A game engine built for AI agents and made for the web. Its kernel is small enough for an agent to hold in full: the loop, the clock, the objects on stage and the services every game needs. Everything else plugs in as an expansion pack.
- 53 files
- 9,491 lines
- 26 modules
- 358 packs plug in
Version 3.0.0-2 · releases
Why it exists
A game engine for AI agents, made for the web.
- Phaser 4 was built for people. We spent fourteen years crafting the Phaser API for developers who write every line of code by hand, and it grew to be the most popular open-source framework for making web games.
- Then agents started writing the code instead. Language models write Phaser 4 code well, but to do it they have to hold a large API in memory, and spend much of their time working out what is what, when all you want is a kart racer on screen.
- So we built an engine for them. Phaser AE's kernel is small enough for an agent to hold in full. Everything a game needs beyond it is an expansion pack, and a game takes only the packs it uses.
Phaser 4.1.0's API docs run to 708 pages. The Phaser AE kernel's run to 26, one a module: 206 exports in 53 files, with 358 expansion packs to add as a game needs them.
Phaser 4.1.0708 pages of API docs
Built for people, over fourteen years.
The Phaser AE kernel26 pages of API docs
206 exports in 53 files, and 358 packs to add as a game needs them.
What it can do
Everything a modern web game needs.
- WebGPUWebGL2
WebGPU, and WebGL2 where it isn't
The engine draws with WebGPU, and with WebGL2 on devices without it yet. It picks for you, and never falls back to a backend a game can't use.
2D, 3D and vector
Three cores in one engine: 2D, 3D and vector. A 3D game with a 2D HUD uses one backend for both.
Hundreds of thousands of sprites
A screen crowded with sprites stays fast, because they draw in batches from shared atlas pages.
- Windows · ChromeMac · Safarisame seed, same input, same bits
Multiplayer: deterministic to the bit
Fixed steps, a seeded random source, and a
Mathof its own:sin,cos,atan2,powand the rest are ported from fdlibm and give the same bits in any browser, on any machine. The same seed and the same input replay the same game anywhere, which is what multiplayer and replays need. Atlases built as you load
Sprites, glyphs and drawn pictures are packed onto atlas pages as they load. The atlas never runs out of room, because a new page opens whenever one fills.
PBR materials
Physically based 3D materials with texture maps, cascaded sun shadows, and reflections of a sky that bakes its own environment map.
A vector renderer
Shapes, fonts and effects drawn as vectors, in 2D and in 3D, crisp at any scale.
- Aa×16, still sharp
Text that stays sharp
MSDF text, drawn natively on WebGPU and WebGL2, on screen and in 2D and 3D worlds: sharp at any size, shaping any script and mixing fonts, with outlines, shadows and gradients.
- Play
UI built in
Panels, windows, buttons, toggles, sliders, progress bars, text inputs, lists and dropdowns, styled as data, with 125 icons.
The idea
Small on purpose.
- The kernel runs the game. The loop, the clock, the objects on stage, scenes, input, loading, timers, random numbers, and the signals and hooks that connect them.
- Packs do the rest. Drawing, physics, sound, menus, worlds and whole kinds of game are all packs. A game lists the packs it uses, and only those are in it.
- The kernel never imports a pack. Packs plug into it and reach each other only through the game, its signals, its hooks and a registry. You can swap any pack, and adding one changes nothing else.
- Your agent can read all of it. The kernel and the packs a game uses arrive in its folder as source code, each with a page of docs, never as a compiled binary.
What's inside
26 modules, 206 exports.
The game
- The game3createGame, the Game that owns every service, the frame loop, boot, stop and destroy, the host contract
- Packs8Pack (what a pack is), Kernel (what its attach receives), GameBase (the kernel's half of game), GameOptions
- Verbs13the verbs: hide, kill, move, moveTo, play, rotate, scale, show, tag, teleport, tint, untag
Time and flow
- Clock5the fixed-step clock, pause, time scale, hold and advance; the TickSource that fires frames
- Scenes2the scene stack: go, push, pop, and suspension beneath a push
- Timers3after and every: timers on the game clock, owned by a scene
- Signals4step-batched signals, declared per topic
- Hooks4the lifecycle hooks: boot, frame, assets, scene, input, app, debug
- Frame graph4the render pass graph, the simulation list, and the before/after ordering both use
On stage
- Roster13Handle, SpawnSpec, the roster's queries, blend modes and vertex deformers
- Camera1the camera record a world transforms through and a rig drives
- Screen3the screen policy (fit), the surface backends draw to, safe-area insets
- Rendering contract12the world/backend contract: instance tables, aggregates, deformers, drawers
- 2D and 3D worlds11the shared gathers that build instance tables, and the 2D and 3D camera transforms
The player
Content and maths
- Assets9the loader, asset packs (assets.json), the atlas, pictures in textures of their own, paint, pixels
- Random, color and units22the seeded rng (and createRng for code without a game), the one colour parser, toroidal wrapping, shared units
- Deterministic maths3deterministicMath, a Math whose 22 implementation-approximated functions are ported from fdlibm and give the same bits on every engine; the module the bakery injects as every bundle's Math; installDeterministicMath() for a Node host
- 3D maths40pure 3D maths (matrices, rays, quaternions, directions) and the three drag conventions
- Curves6Catmull–Rom: a span in any dimension (uniform, centripetal or chordal), the scalar form for value curves, and an arc-length spline through points
Tools
- Inspection7game.inspect(), game.advance() and what they report
- Workers4the worker pool and its job protocol
- Undo, redo and replay7createHistory: undo, redo, seek and replay for deterministic rules, with refusals, checkpoints and validated saves
- WebGL24what the WebGL2 backend shares with packs, and the program compiler every pack uses
One frame
The same loop on any machine.
Time comes from the clock. The simulation runs in fixed steps, in seconds. Pausing is one flag and slow motion is one number. Nothing in a game reads the wall clock.
Random numbers come from the seed. They all come from the seeded rng, and even Math gives the same bits in any browser. The same seed and the same input replay the same game.
Order comes from names. Steps, passes and hooks say what they run before or after, by name. No pack depends on the order it was imported in.
How a pack plugs in
A pack is an id and an attach function.
A whole pack
import type { Pack } from '@phaser-ae/kernel';
/** Everything tagged 'falls' falls, at a speed the game can change. */
export function fall(speed = 120): Pack<{ fall: { speed: number } }> {
return {
id: 'fall',
attach(k) {
const api = { speed };
// a fixed step, ordered by name against other packs' steps
k.simulate.add('fall', { before: 'collision' }, dt => {
for (const h of k.roster.tagged('falls')) {
h.y += api.speed * dt;
}
});
return { fall: api }; // becomes game.fall
},
};
}A game using it
import { game } from './engine.js';
game.scenes.register({
name: 'play',
enter() {
const ship = game.spawn({
id: 'ship', texture: 'ship', x: 360, y: 1100,
});
game.every(0.6, () => game.spawn({
id: 'rock', texture: 'rock', tags: ['falls'],
x: game.rng.between(40, 680), y: -40,
}));
game.step('steer', dt => {
if (game.input.keyDown('ArrowLeft')) ship.x -= 300 * dt;
if (game.input.keyDown('ArrowRight')) ship.x += 300 * dt;
});
},
});
game.scenes.go('play');The bake
From a manifest to a game.
manifest.json
{
"name": "rock-dodge",
"screen": { "width": 720, "height": 1280, "fit": "letterbox" },
"seed": 1,
"packs": [
{ "id": "core-2d" },
{ "id": "bars" },
{ "id": "fall", "options": { "speed": 160 } }
]
}- The manifest names the packs, in order, each with its options.
- The bake composes them into the game's
engine.ts, writes each pack's page into the game'sdocs/, and typesgamewith each pack's API. - The build checks the game with strict TypeScript and the kernel's rules, then bundles it into one file. Add a pack and bake again, and its API is there.
The rules
The kernel's 7 rules.
- 1Everything on stage is a roster object. The roster is the single ground truth of what exists; a thing not in it does not draw.
- 2No unattributed pixels. Game code cannot reach the canvas or the GPU.
- 3All time flows from the clock. Simulation runs in fixed steps, in seconds.
- 4All chance flows from the rng. Every random number comes from the seeded
rng, so a seed and the same input replay the same game. - 5One conventions page. Units are set once, in
docs/reference/CONVENTIONS.md: world units, y down in 2D, y up and right-handed in 3D, radians, seconds, positions at the centre, CSS colour strings at the boundary. - 6Garbage fails loud. In dev mode a non-finite number, an unknown name or a write to a killed object throws; in production it is ignored.
- 7The kernel never imports a pack. Packs reach each other only through the composed game's keys, signals, hooks and the definitions registry.
Events and cleanup
Hooks, signals, and scenes that clean up.
A hook is a call made the moment something happens. A signal is recorded instead, and what one step emits, the next step reads as a list. Because the simulation uses signals, a step's result never depends on which listener ran first.
Objects, timers and steps belong to the scene that made them, and go when it exits. A pause scene pushed on top freezes the scenes beneath it.
Built on it
Just some of the expansion packs.
Try it
Ask your agent.
Start a game from nothing
Make a Phaser AE game called Rock Dodge: a little ship dodges falling rocks, faster every level, with a score and a game-over screen. Start it with `npx -y @phaser-ae/cli blank rock-dodge --idea "A ship dodges falling rocks, faster every level."`, then build it, play it and publish it.
See one frame
In this Phaser AE game, read docs/00-kernel.md, then walk me through one frame of the game: which of my steps run, in what order, and where the packs' steps and render passes come in.
Add a pack
Add the bars pack to this Phaser AE game and show the player's health as a bar in the top-left corner that turns red as it empties. Search the packs first with `npm run -s packs -- search "health bar"`.
Replay a run
This Phaser AE game is deterministic, thanks to the kernel's seeded rng. Add an instant replay of the player's last life, using the kernel's createHistory.
Pause everything
Add a pause button to this Phaser AE game with the ui pack's pauseButton, and check that timers, animations and steps all stop while it's paused.
Paste one into Claude Code, Codex, Cursor or another coding agent with the Phaser AE CLI. Set up the CLI →
Phaser Pro
163 packs are free. 195 more come with Pro.
Everyone gets the same kernel. Pro unlocks all of the expansion packs, including whole kinds of game, 3D worlds and the showpiece effects, plus new packs as they're released.
Upgrade to ProThe source
The source comes with your game.
Each engine release puts the kernel's full source and docs in your game's folder (phaser/engine/kernel), where your agent reads them as it builds. Version 3.0.0-2, from commit c164d62f.
The kernel is source-available under the PolyForm Shield License 1.0.0, with an additional permission to make and sell games.













