Phaser AE

Boarding queue puzzles

Pro packv3.0.0-3Grid

The rules of the bus-boarding colour puzzles: passengers board buses of their own colour, and the few spaces for the wrong ones are what make it a puzzle. Two modes, seeded levels with a checked solution, and an explanation when the player is stuck.

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

Boarding queue 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

boardingQueue

function boardingQueue(): Pack<{ boardingQueue: typeof kit; }>

Compose the boarding-queue public rules and generator helpers.

Helpers

createBoardingQueue

const createBoardingQueue = (config: BoardingConfig, solution?: BoardingAction[])=> …

Create a boarding puzzle. Throws on a configuration it refuses (out-of-range sizes, overlapping passengers, seats per colour that do not match passengers) or a solution that does not replay to a win.

generateBoardingQueue

function generateBoardingQueue(options: BoardingGenerateOptions): BoardingLevel

Generate a level whose solution is replayed before it is returned. Throws on out-of-range options, a crowd that does not fit its board (generation: requested groups exceed layout capacity) or a lot the traffic generator cannot build.

Classes

BoardingQueue

class BoardingQueue

A boarding puzzle's rules, with undo, redo and a bounded solver. Get one from createBoardingQueue.

  • constructor(config: BoardingConfig, solution: BoardingAction[] = [])
  • get config(): BoardingConfig — A copy of the configuration.
  • get state(): BoardingState — A copy of the current state.
  • get solved(): boolean — True when every bus has filled up and left.
  • get lost(): boolean — True when the puzzle is unfinished and no move is legal (see deadlock() for why). A position can be hopeless before this turns true; only solve can tell.
  • activeVehicle(): BoardingVehicle | null — Passenger mode: the bus now loading (a copy), or null once all have left or in vehicle mode.
  • accessible(): { id: string; path: Cell[]; }[] — Passenger mode: the passengers who can walk out now, each with its path from an entrance to the passenger (empty cells only).
  • dispatchRoutes(id: string): string[] — Vehicle mode: the ids of the routes bus id can drive out by now (whole route clear); empty in passenger mode.
  • preview(a: BoardingAction): ActionResult<BoardingEvent> — What apply would return for a, without playing it.
  • apply(a: BoardingAction): ActionResult<BoardingEvent> — Play a move. Returns { valid: true, events }, or { valid: false, reason, events: [] } and changes nothing; reasons include inaccessible-passenger, waiting-full, bays-full, wrong-mode, unknown-item, already-complete and the traffic pack's route reasons (blocked).
  • legalActions(): BoardingAction[] — Every legal move now, those that serve the wanted colour first.
  • deadlock(): BoardingDeadlock — Why the player is stuck, or deadlocked: false.
  • solve(maxStates = 20000): SearchResult<BoardingAction> — A winning continuation from here, without changing anything: the rest of the creation certificate when it still applies, otherwise a depth-first search of at most maxStates positions (default 20,000). unsolvable is a proof; budget-exhausted is not.
  • undo(): boolean — Take back the last move; 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

BoardingAction

type BoardingAction = { type: 'passenger'; id: string; } | { type: 'dispatch'; id: string; route: string; }

A move: walk a passenger out (passenger mode), or drive bus id out by its route route (vehicle mode).

BoardingConfig

type BoardingConfig = PassengerBoardingConfig | VehicleBoardingConfig

A boarding puzzle: Bus Jam (mode: 'passengers') or Bus Out (mode: 'vehicles').

BoardingDeadlock

interface BoardingDeadlock

Why the player is stuck, from deadlock().

  • deadlocked: boolean — True when the puzzle is unfinished and no move is legal.
  • reason: 'none' | 'waiting-full' | 'bays-full' | 'inaccessible-queue' | 'no-matching-vehicle' — waiting-full (every waiting space holds the wrong colour), inaccessible-queue (the needed passengers are walled in), bays-full (every bay holds a bus whose colour is not at the front), no-matching-vehicle (no bus of the front colour can get out), or none.
  • neededKey: string | null — The colour wanted now: the loading bus's (passenger mode) or the front passenger's (vehicle mode); null when none is.
  • waiting: string[] — Ids of the passengers in the waiting spaces.
  • bays: string[] — Ids of the buses in the loading bays.
  • blocked: string[] — Ids that cannot move now: passengers with no free path to an entrance, or buses with no clear exit route.

BoardingDifficulty

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

Generator tier: bigger crowds, more colours, fewer waiting spaces and more interleaving as it rises.

BoardingEvent

type BoardingEvent = { type: 'waiting' | 'boarded'; id: string; vehicle: string; } | { type: 'departed'; id: string; } | { type: 'dispatched'; id: string; route: string; }

What a move did, in order: a passenger took a waiting space (waiting) or a seat (boarded; in vehicle mode its id is line-<index>), a bus was dispatched to a bay (dispatched) or filled up and left (departed).

BoardingGenerateOptions

interface BoardingGenerateOptions

What generateBoardingQueue takes; everything but seed defaults from difficulty.

  • seed: number — Unsigned 32-bit seed (0 included); the same options give the same level.
  • mode?: 'passengers' | 'vehicles' — 'passengers' (Bus Jam, the default) or 'vehicles' (Bus Out).
  • difficulty?: BoardingDifficulty — Tier that sets the other defaults; default 'medium'.
  • layout?: BoardingLayout — Passenger mode: the floor plan; default 'rectangle'. Ignored in vehicle mode.
  • groups?: number — Passenger mode: how many buses, 2 to 32; default 4, 8, 12 or 18 by tier. Vehicle mode takes its fleet from traffic.
  • colors?: number — Distinct colours, 2 to 8; default 3, 4, 6 or 8 by tier.
  • seats?: number — Seats on every bus, 2 to 8; default 3.
  • waitingCapacity?: number — Waiting spaces (passenger mode) or loading bays (vehicle mode), 1 to 12; default 7, 5, 3 or 2 by tier.
  • lookahead?: number — How many later buses' passengers are mixed into each bus's turn, 0 to the smaller of waitingCapacity and colors - 1 (vehicle mode: below waitingCapacity); default 0, 1, 2, 2 (vehicles 0, 1, 2, 1) by tier. Higher means more of the waiting space is needed.
  • traffic?: Omit<TrafficGenerateOptions, 'seed'> — Vehicle mode: options for the bus lot, passed to generateTrafficRelease; default the parking preset at size 4, 6, 8 or 10 by tier and density 0.7. Hazards and mistakes are always off.

BoardingLayout

type BoardingLayout = 'rectangle' | 'aisles' | 'courtyard'

Generated Bus Jam floor plan: a solid rectangle, aisles (a free column every third) or a courtyard (a wall down the middle).

BoardingLevel

interface BoardingLevel

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

  • seed: number — The seed asked for.
  • difficulty: BoardingDifficulty — The tier asked for.
  • parameters: { /** \'passengers'` or `'vehicles'`. / mode: 'passengers' | 'vehicles'; /* The floor plan (passenger mode). / layout: BoardingLayout; /* Buses asked for (passenger mode). / groups: number; /* Distinct colours. / colors: number; /* Seats per bus. / seats: number; /* Waiting spaces or loading bays. / waitingCapacity: number; /* Later buses' passengers mixed into each turn. */ lookahead: number; }` — The settings used, defaults filled in.
  • config: BoardingConfig — The level, ready for createBoardingQueue.
  • solution: BoardingAction[] — A replay-checked winning sequence; pass it to createBoardingQueue so solve can use it.
  • metrics: { /** Moves in the solution. */ items: number; /** Legal moves at the start. */ initialChoices: number; /** Most waiting spaces the solution fills at once. */ certificatePeakWaiting: number; /** Most loading bays the solution fills at once. */ certificatePeakBays: number; /** Buses. */ departures: number; /** Whether the solution really uses the interleaving: fills at least \lookahead` waiting spaces (Bus Out: has a bus waiting in a bay when `lookahead` > 0). Always true on easy. */ difficultyTargetMet: boolean; }` — What the solution needs, not how hard a person finds it; nothing here claims a shortest plan.

BoardingPassenger

interface BoardingPassenger extends Cell

A coloured passenger standing on a walkable cell (x column, y row, whole numbers from 0).

  • id: string — Unique non-empty id; actions and events name it.
  • key: string — Colour key: the passenger boards only a vehicle with the same key. Non-empty.

BoardingState

interface BoardingState

Where a boarding puzzle stands.

  • remaining: string[] — Ids still on the board: passengers in the crowd (passenger mode) or buses still parked (vehicle mode).
  • waiting: string[] — Passenger mode: ids of passengers in the waiting spaces, oldest first.
  • bays: { /** The bus id. */ id: string; /** Seats taken so far. */ loaded: number; }[] — Vehicle mode: the buses in the loading bays, oldest first, with the seats taken on each.
  • vehicleIndex: number — Passenger mode: index in vehicles of the bus now loading.
  • loaded: number — Passenger mode: seats taken on the bus now loading.
  • lineIndex: number — Vehicle mode: index in passengerLine of the passenger at the front of the queue.
  • departed: string[] — Ids of the buses that have filled up and left, in order.
  • moves: number — Moves played.

BoardingVehicle

interface BoardingVehicle

A bus: its colour and how many passengers fill it.

  • id: string — Unique non-empty id. In vehicle mode it is also the id of its piece in the traffic layout.
  • key: string — Colour key: only passengers with the same key board it. Non-empty.
  • capacity: number — Seats, 1 to 16. The bus departs when every seat is taken.

PassengerBoardingConfig

interface PassengerBoardingConfig

Bus Jam: a crowd on a floor plan, buses arriving in order and a few waiting spaces.

  • mode: 'passengers' — 'passengers': the player taps passengers.
  • width: number — Board width in cells, 1 to 16.
  • height: number — Board height in cells, 1 to 24.
  • walkable: Cell[] — The floor: unique cells inside the board that passengers can stand on and walk through. Any shape.
  • entrances: Cell[] — Walkable cells where walking paths start (the edge nearest the buses); at least one.
  • passengers: BoardingPassenger[] — The crowd, 1 to 384 passengers, each on its own walkable cell.
  • vehicles: BoardingVehicle[] — The buses, 1 to 128, in arrival order. Seats per colour must equal that colour's passengers exactly.
  • waitingCapacity: number — Waiting spaces for passengers whose bus has not come yet, 0 to 12.

VehicleBoardingConfig

interface VehicleBoardingConfig

Bus Out: a packed lot of buses that must drive out, a few loading bays and one passenger queue.

  • mode: 'vehicles' — 'vehicles': the player taps buses.
  • traffic: TrafficConfig — The lot, as a traffic-release layout: one piece per bus, with its exit routes. No hazards and no mistake limit.
  • vehicles: BoardingVehicle[] — One bus per traffic piece, matched by id; order does not matter.
  • passengerLine: string[] — The passenger queue, front first, as colour keys. Seats per colour must equal that colour's passengers exactly.
  • bayCapacity: number — Loading bays, 1 to 12: how many dispatched buses can wait for their passengers at once.