Phaser AE

Key-and-door tile puzzles

Pro packv3.0.0-12DArcade

The rules of the top-down tile-effect puzzle: walk a tile at a time, collect the chips, open the socket and reach the exit, through doors, elements, sliding floors and monsters. Levels are text maps, and a solver finds the way through your own.

This is a Pro pack. Upgrade to Phaser Pro to use it in your games.See Phaser Pro →

Released October 19, 2026 · updated October 20, 2026

Key-and-door tile puzzles: a screenshot of its demo
A note about these graphics

Expansion packs don't come with graphics. This screenshot is one way of drawing what the pack does, made for its demo: none of the sprites, tiles or backgrounds in it are in the pack.

That's by design. A pack is a game's logic, mechanics and effects, and it works with whatever art you give it. Some packs draw effects, backdrops or 3D scenes of their own, but none carries a game's sprites.

So the look is yours. Make the art on phaser.io, bring your own, or let your agent draw it in code: the same pack can look like anything.

The pack

chipsChallenge

function chipsChallenge(): Pack<{ chipsChallenge: ChipsChallengeApi }>

The chips-challenge pack: game.chipsChallenge, Chip's Challenge's rules. No options.

Helpers

chipsLevels

const chipsLevels: LevelDef[]

The built-in levels: keys and doors; the elements and their boots; monsters and blocks; switches, tanks, teleports and bombs. Each carries a solution for attract modes.

createChips

function createChips(options: ChipsOptions = {}): ChipsGame

Start a game. Throws, with every fault, on options validateChips refuses.

createChipsAutopilot

function createChipsAutopilot(game: ChipsGame): ChipsAutopilot

The game's autopilot: each level's solution, or one it finds.

MOVER_CHARS

const MOVER_CHARS: Record<string, MoverKind>

The characters of a map: movers, each on floor.

readLevel

function readLevel(level: LevelDef): { width: number; height: number; terrain: Terrain[]; movers: Omit<Mover, 'id'>[] } | string

Read a level's map: its terrain and movers, or what is wrong with it.

solveLevel

function solveLevel(level: LevelDef, options: { nodes?: number; step?: number } = {}): string | null

Find a way through a level: moves as U, R, D, L and . (wait), or null within the bounds. It searches breadth first for the nearest next chip (or, with the chips in, the exit), over the whole state of the game, monsters included, then on from there: quick, and right for levels that do not punish the order chips are taken in.

TILE_CHARS

const TILE_CHARS: Record<string, Terrain>

The characters of a map: terrain.

validateChips

function validateChips(options: ChipsOptions = {}): string[]

Check a game's options. Empty when it can be played.

Types

ChipsAutopilot

interface ChipsAutopilot

A player that plays each level's way through.

  • next(): Dir | null — The way to hold now.

ChipsChallengeApi

interface ChipsChallengeApi

What the chips-challenge pack adds to a game: game.chipsChallenge.

  • create: typeof createChips — Start a game.
  • validate: typeof validateChips — Check a game's options.
  • levels: typeof chipsLevels — The built-in levels.
  • autopilot: typeof createChipsAutopilot — A player that plays a level's way through, for an attract mode.

ChipsEvent

type ChipsEvent = | { kind: 'level'; level: number; name: string } | { kind: 'move' } | { kind: 'chip'; left: number } | { kind: 'open' } | { kind: 'key'; colour: string } | { kind: 'door'; colour: string } | { kind: 'boots'; boots: string } | { kind: 'thief' } | { kind: 'push' } | { kind: 'splash' } | { kind: 'bomb' } | { kind: 'teleport' } | { kind: 'toggle' } | { kind: 'tanks' } | { kind: 'slide' } | { kind: 'die'; cause: NonNullable<ChipsState['cause']> } | { kind: 'clear'; level: number } | { kind: 'won' }

Something that happened.

ChipsGame

interface ChipsGame

A game.

  • readonly state: ChipsState — The live state, changed in place as the game steps; take a view() to keep a copy.
  • readonly width: number — Width of the current level's map in cells.
  • readonly height: number — Height of the current level's map in cells.
  • readonly levels: readonly LevelDef[] — The levels, in order.
  • move(dir: Dir | null): void — Hold a way to go, or null to stand.
  • restart(): void — Start the level again.
  • terrainAt(x: number, y: number): Terrain — The terrain at cell column x, row y (0 at the top left); wall outside the map.
  • step(dt: number): void — Advance dt seconds, taking one tick for each ChipsOptions.step of them; a dt above 0.25 counts as 0.25. Throws unless dt is 0 or more.
  • view(): ChipsView — What is where: copies of the state, the terrain and the movers.
  • drain(): ChipsEvent[] — The events since the last call, oldest first (at most the latest 512 are kept).
  • snapshot(): ChipsSave — A plain-data copy of the whole game, which restore accepts.
  • restore(save: ChipsSave): void — Return to a saved game of the same levels. Clears undrained events.

ChipsOptions

interface ChipsOptions

A game's options.

  • seed?: number — Default 1: walkers and blobs.
  • levels?: LevelDef[] — The levels, in order. Default chipsLevels.
  • level?: number — The level to start at, from 0. Default 0.
  • step?: number — Seconds a move takes. Default 0.2.

ChipsSave

interface ChipsSave

A game saved as plain JSON.

  • state: ChipsState — The state.
  • terrain: Terrain[] — The terrain of every cell as it now stands, counted along the rows.
  • movers: Mover[] — Every mover that is alive.
  • serial: number — The last mover id handed out; the next is one more.
  • ticks: number — Ticks since the level began.
  • carry: number — Seconds of play not yet making a tick.
  • wait: number — Seconds left of the pause after Chip dies or clears a level.
  • rng: RngState — The seeded random stream's state, from the kernel's rng.snapshot().

ChipsState

interface ChipsState

Where the game stands.

  • phase: 'play' | 'dead' | 'clear' | 'won' — play while the level runs; dead and clear pause briefly before the level restarts or the next begins; won after the last level.
  • level: number — Index of the level being played, from 0.
  • chips: number — Chips still needed.
  • time: number — Seconds left (or since the start, untimed).
  • keys: Record<'red' | 'blue' | 'yellow' | 'green', number> — Keys held of each colour; green keys are never used up.
  • boots: Record<'flippers' | 'fire-boots' | 'skates' | 'suction', boolean> — Which boots Chip has picked up.
  • cause: 'water' | 'fire' | 'monster' | 'bomb' | 'time' | null — Why he died, if he did.
  • hint: string | null — The hint he is standing on.
  • moves: number — Chip's moves, and the game's ticks, since the level began.
  • tick: number — Game ticks since the level began; one tick passes each ChipsOptions.step seconds of play.

ChipsView

interface ChipsView

What is where.

  • state: ChipsState — The state, a copy.
  • width: number — Width of the map in cells.
  • height: number — Height of the map in cells.
  • terrain: Terrain[] — The terrain of every cell, counted along the rows (y * width + x); a copy.
  • movers: Mover[] — Every mover that is alive, Chip and the blocks included; a copy.
  • chip: Mover — Chip, a copy.

Dir

type Dir = 'up' | 'right' | 'down' | 'left'

A way to go.

LevelDef

interface LevelDef

A level.

  • name: string — The level's name, announced in the level event.
  • map: string[] — Rows of text, all the same length. See TILE_CHARS and MOVER_CHARS.
  • chips?: number — Chips needed to open the sockets. Default every chip in the map.
  • time?: number — Seconds allowed; 0 for none. Default 0.
  • hint?: string — Text shown while Chip stands on a hint tile.
  • facing?: [number, number, Dir][] — Movers' first directions by cell, as [x, y, dir]; the rest start facing up.
  • solution?: string — A way through, as moves (U, R, D, L, and . to wait a move), for an attract mode.

Mover

interface Mover

A mover in a level.

  • id: number — Unique id within a game, handed out in order as movers are loaded.
  • kind: MoverKind — What it is: Chip, a block or a kind of monster.
  • cell: number — Where it is, as a cell index counted along the rows: y * width + x.
  • dir: Dir — The way it faces, which is the way it moves next.
  • alive: boolean — False once it has drowned, blown up or otherwise gone; dead movers are removed at the end of the tick.

MoverKind

type MoverKind = 'chip' | 'block' | 'bug' | 'paramecium' | 'fireball' | 'glider' | 'ball' | 'tank' | 'walker' | 'blob' | 'teeth'

Something that moves.

Terrain

type Terrain = | 'floor' | 'wall' | 'chip' | 'socket' | 'exit' | 'water' | 'fire' | 'ice' | 'force-up' | 'force-right' | 'force-down' | 'force-left' | 'dirt' | 'gravel' | 'toggle-closed' | 'toggle-open' | 'green-button' | 'blue-button' | 'bomb' | 'thief' | 'hint' | 'teleport' | 'popup' | 'key-red' | 'key-blue' | 'key-yellow' | 'key-green' | 'door-red' | 'door-blue' | 'door-yellow' | 'door-green' | 'flippers' | 'fire-boots' | 'skates' | 'suction'

A tile under everything.