Phaser AE

Traffic release puzzles

Pro packv3.0.0-3Grid

The rules of tap-to-release puzzles: tap a car or a block and it leaves along its route, but only if that route is clear right now. Flat road grids and 3D voxel stacks are the same rules, and a seeded generator makes levels screened for how tangled they are.

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

Released October 14, 2026 · updated October 19, 2026

Traffic release 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

trafficRelease

function trafficRelease(): Pack<{ trafficRelease: TrafficReleaseApi }>

Install pure rules; no renderer, DOM or simulation hook is required.

Helpers

createTrafficRelease

const createTrafficRelease = (config: TrafficConfig, solution?: TrafficAction[])=> …

Create a traffic puzzle. Throws on a configuration it refuses (out-of-range sizes, overlaps, a route that does not start at its piece, jumps or does not leave the board) or a solution that does not replay to a win.

generateTrafficRelease

function generateTrafficRelease(options: TrafficGenerateOptions): TrafficLevel

Generate a seeded level whose solution is replayed before it is returned. Candidates are tried until one has at most maxInitialChoices open routes and a blocking chain at least minDependencyDepth long; throws generation: no ... level met ... when attempts run out, and on out-of-range options.

straightTrafficRoute

function straightTrafficRoute(cells: Voxel[], direction: Voxel, bounds: Pick<TrafficConfig, 'width' | 'height' | 'depth'>, id = 'exit'): TrafficRoute

A straight route for cells: one step at a time along direction (a unit axis such as { x: 1, y: 0, z: 0 }) until wholly outside bounds. Throws on any other direction or a route longer than 64 steps.

Classes

TrafficRelease

class TrafficRelease

A traffic puzzle's rules, with undo, redo and a solver. Get one from createTrafficRelease.

  • constructor(config: TrafficConfig, solution: TrafficAction[] = [])
  • get config(): TrafficConfig — A copy of the configuration.
  • get state(): TrafficState — A copy of the current state.
  • get solved(): boolean — True when every piece has left the board.
  • get lost(): boolean — True when maxMistakes blocked releases have been made with pieces still on the board. A release-only puzzle has no other way to lose.
  • cells(id: string): Voxel[] — The cells piece id covers now (part way along its route if it is moving); empty once it has left or for an unknown id.
  • hazardCells(): { id: string; cells: Voxel[]; }[] — Where each hazard is at the current tick.
  • inspect(id: string, route: string): TrafficClearance — What stands in the way of piece id leaving by route now, step by step; changes nothing.
  • preview(a: TrafficAction): ActionResult<TrafficEvent> — What apply would return for a, without playing it; never costs a mistake.
  • apply(a: TrafficAction): ActionResult<TrafficEvent> — Play a move. Returns { valid: true, events }, or { valid: false, reason, events: [] } with a reason: blocked, reserved-lane, hazard, already-moving, unknown-piece, unknown-route or mistake-limit. A blocked release counts as a mistake (and goes in the history) when maxMistakes is set.
  • legalActions(): TrafficAction[] — Every release that is clear now, then { type: 'tick' } while the puzzle is unsolved.
  • solve(maxStates = 20000): SearchResult<TrafficAction> — A winning continuation, without changing anything: the rest of the creation certificate when it still applies, otherwise a greedy plan (release the first clear piece, else wait a tick). Greedy is exact here: a piece that leaves never blocks anything again, so no release can spoil the puzzle. unsolvable after 120 idle ticks or at the mistake limit; budget-exhausted after maxStates steps (default 20,000).
  • undo(): boolean — Take back the last move (a tick, a release or a mistake); false when there is none.
  • redo(): boolean — Replay the move last taken back; false when there is none.
  • reset(): void — Return to the start and clear the undo and redo history.

Types

TrafficAction

type TrafficAction = { type: 'release'; id: string; route: string; } | { type: 'tick'; }

A move: release piece id along its route route, or let one tick of time pass (moving pieces advance a step, hazards a phase).

TrafficClearance

interface TrafficClearance

What stands in a route's way, from inspect.

  • clear: boolean — True when nothing does: the piece can be released by this route now.
  • blockers: { /** A parked \piece`, a `wall`, a moving piece's `reservation` or a `hazard` at the tick of that step. / kind: 'piece' | 'wall' | 'reservation' | 'hazard'; /* The blocking piece's or hazard's id; `'wall'` for a wall. / id: string; /* The cell where it blocks. / cell: Voxel; /* The route step (footprint index) that meets it. */ frame: number; }[]` — Everything in the way, by route step.
  • swept: Voxel[] — Every cell the route sweeps, corners of turns included: what a presenter highlights.

TrafficConfig

interface TrafficConfig

A level: the board's size, the pieces and their routes, and optional walls, hazards and a mistake limit.

  • width: number — Cells across, 1 to 24.
  • height: number — Cells deep (rows of a flat board), 1 to 24.
  • depth: number — Cells high, 1 to 24; 1 for a flat board.
  • pieces: TrafficPiece[] — The pieces, 1 to 256, with unique ids and no shared cells.
  • walls?: Voxel[] — Cells that are always blocked (barriers, kerbs); inside the board and on no piece.
  • hazards?: TrafficHazard[] — Moving obstacles, checked against each route step at the tick it would happen.
  • maxMistakes?: number — Blocked release attempts allowed before the level is lost, 0 to 100; 0 (the default) means no limit.

TrafficDifficulty

type TrafficDifficulty = 'easy' | 'medium' | 'hard' | 'very-hard'

Generator tier: a larger board and, from medium up, fewer open routes and longer chains of blockers.

TrafficEvent

type TrafficEvent = { type: 'released' | 'departed'; id: string; } | { type: 'tick'; tick: number; } | { type: 'mistake'; reason: string; }

What a move did: a piece was released or has departed (left the board), a tick passed, or a blocked release cost a mistake.

TrafficGenerateOptions

interface TrafficGenerateOptions

What generateTrafficRelease takes; everything but seed has a default.

  • seed: number — Unsigned 32-bit seed (0 included); the same options give the same level.
  • difficulty?: TrafficDifficulty — Tier; default 'medium'.
  • preset?: TrafficPreset — What to build; default 'parking'.
  • layout?: TrafficLayout — The shape filled; default 'rectangle' (flat) or 'cube' (voxels).
  • size?: number — Board side in cells: 2 to 12 flat (default 4, 6, 8, 10 by tier; parking adds a one-cell border) or 2 to 6 for voxels (default 2, 3, 4, 5).
  • density?: number — Share of the shape's places that get a piece, 0.35 to 1; default 1.
  • hazards?: boolean — Flat presets: add a pedestrian just off the left edge of row floor(size / 2), there for 2 ticks in every 6, so a car leaving that way must wait for a gap; default false.
  • maxMistakes?: number — Blocked releases allowed before the level is lost, 0 to 100; default 0 (no limit).
  • attempts?: number — Candidate levels to try before throwing, 1 to 1,000; default 40.
  • maxInitialChoices?: number — Most pieces that may be clear at the start, 1 to 256; default by tier (streets 256, 5, 3, 3; voxels 256, 5, 3, 2, and 6 for a diamond; parking 256).
  • minDependencyDepth?: number — Least length of the longest chain of pieces blocking one another, 1 to 256; default by tier (1, 4, 7, 10; parking 1).

TrafficHazard

interface TrafficHazard

A moving obstacle (a pedestrian, a train) that repeats: at tick t it covers phases[t % phases.length].

  • id: string — Unique non-empty id.
  • phases: Voxel[][] — 1 to 30 phases of cells it covers; an empty phase is a safe moment to cross. All hazards together repeat within 120 ticks.

TrafficLayout

type TrafficLayout = 'rectangle' | 'courtyard' | 'staggered' | 'cube' | 'pyramid' | 'arch' | 'diamond'

The shape filled: rectangle, courtyard (a hole in the middle) or staggered (a notched edge) for flat presets; cube, pyramid, arch or diamond for voxels.

TrafficLevel

interface TrafficLevel

A generated level: its configuration, a winning solution and what was measured.

  • seed: number — The seed asked for (the accepted candidate may have been drawn from a later one, but this seed reproduces it).
  • difficulty: TrafficDifficulty — The tier asked for.
  • parameters: Required<Omit<TrafficGenerateOptions, 'attempts' | 'maxInitialChoices' | 'minDependencyDepth'>> — The settings used, defaults filled in.
  • config: TrafficConfig — The level, ready for createTrafficRelease.
  • solution: TrafficAction[] — A replay-checked winning sequence of releases and ticks.
  • metrics: { /** Pieces on the board. */ pieces: number; /** Pieces clear to leave at the start. */ initialChoices: number; /** Pieces with no clear route at the start. */ blockedPieces: number; /** Longest chain of pieces each blocking the next along the solution's routes. */ dependencyDepth: number; /** Solution routes that turn a corner (streets). */ turningRoutes: number; /** Whether the level met the targets below; always true for a returned level. */ difficultyTargetMet: boolean; /** The open-route target the level met. */ maxInitialChoices?: number; /** The chain-depth target the level met. */ minDependencyDepth?: number; } — The level's structure; none of it claims a shortest plan or a human difficulty.

TrafficMotion

interface TrafficMotion

A piece on its way out.

  • id: string — The piece's id.
  • route: string — The route it took.
  • frame: number — Which of the route's footprints it is on now.
  • reserved: Voxel[] — Every cell its route sweeps, held until it is off the board, so nothing else may cross its path.

TrafficPiece

interface TrafficPiece

A car, block or voxel with the routes it can leave by.

  • id: string — Unique non-empty id.
  • key?: string — Optional colour or kind for the presenter (and for boarding-queue's buses); the rules ignore it.
  • cells: Voxel[] — The cells it covers, 1 to 64, inside the board and on no other piece or wall.
  • routes: TrafficRoute[] — Its ways out, at least one. Releasing takes one of them whole.

TrafficPreset

type TrafficPreset = 'parking' | 'streets' | 'voxels'

What generateTrafficRelease builds: streets (Traffic Escape: cars on a road grid, some turning), voxels (Tap Away: a block of cubes, each leaving along one of six axes) or parking (a walled lot whose cars can leave either way along their axis; Bus Out's lot).

TrafficReleaseApi

type TrafficReleaseApi = typeof kit & { /** Same seeded generator off-thread; frame-delivered results require a started game. */ generateTrafficReleaseAsync(options?: kit.TrafficGenerateOptions, job?: { signal?: AbortSignal }): Promise<kit.TrafficLevel>; }

Public headless traffic release puzzles helpers.

TrafficRoute

interface TrafficRoute

One way out for a piece: its footprint at every step, from where it stands to wholly off the board.

  • id: string — Non-empty id, unique among the piece's routes; actions name it.
  • frames: Voxel[][] — 2 to 65 footprints. The first is the piece's cells; each next one keeps the same cells in the same order, each moved at most two steps (so a turn can pivot); the last lies wholly outside the board.

TrafficState

interface TrafficState

Where a traffic puzzle stands.

  • remaining: string[] — Ids of the pieces still on the board, moving ones included.
  • moving: TrafficMotion[] — The pieces on their way out.
  • departed: string[] — Ids of the pieces that have left, in order.
  • tick: number — Ticks played.
  • moves: number — Releases played.
  • mistakes: number — Blocked releases counted against maxMistakes.

Voxel

interface Voxel

A cell, in whole numbers from -64 to 64: x across, y the board's depth (rows on a flat board), z height (0 on a flat board).

  • x: number — Column across the board.
  • y: number — Row, or depth into a volume.
  • z: number — Layer up from the floor; 0 on a flat board.