Phaser AE

Lander missions

Pro packv3.0.0-32DArcade

Landing games on a thrusting-craft flight model, in two rule sets: touchdowns, where you set a lander down on lit pads with the fuel you have, and taxi runs, where you carry passengers from pad to pad for fares and tips. Either set takes any craft, and nothing is drawn, so the same rules suit vector lines or a lit 3D surface.

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

Released October 14, 2026 · updated October 20, 2026

Lander missions: 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

landerMissions

function landerMissions(): Pack<{ landerMissions: typeof api }>

Install the lander missions API.

Helpers

clock

function clock(seconds: number): string

Format seconds as m:ss.

createTaxi

function createTaxi(def: TaxiDef): Taxi

Build a taxi game.

createTouchdown

function createTouchdown(def: TouchdownDef): Touchdown

Build a touchdown game.

lunarCraft

function lunarCraft(): TouchdownCraft

The lunar module's flight and landing figures.

lunarLanderPreset

function lunarLanderPreset(opts: LunarLanderOptions = {}): TouchdownDef

Lunar Lander (Atari 1979).

lunarMissions

function lunarMissions(): TouchdownMission[]

The four missions, from the cabinet cards and the ROM's mission tables.

lunarModuleHull

function lunarModuleHull(): Vec2[]

The lunar module: a cabin on a descent stage with two splayed legs (feet are hull points 3 and 4).

lunarSites

function lunarSites(): TouchdownSite[]

The fifteen landing sites.

lunarTerrain

function lunarTerrain(): Vec2[]

The Lunar Lander landscape as a world-space heightfield.

spaceTaxiHull

function spaceTaxiHull(): Vec2[]

The taxi cab: 24 x 10 with its gear legs at the bottom corners.

spaceTaxiPreset

function spaceTaxiPreset(opts: SpaceTaxiOptions = {}): TaxiDef

Space Taxi (Muse 1984).

spaceTaxiScreens

function spaceTaxiScreens(): TaxiScreen[]

Every authored screen, in shift order. 7:00 Teleports, 8:00 Puzzler (gates toggled by touching dots), 11:00 Magnets and the screens after 12:00 are not reproduced.

Constants

LUNAR_FUEL

const LUNAR_FUEL: Record<LanderDifficulty, number>

Fuel per coin for each difficulty: all three are the cabinet's own DIP settings.

LUNAR_HEIGHT

const LUNAR_HEIGHT: number

World and far-view height.

LUNAR_LEVER

const LUNAR_LEVER: number[]

The ROM's thrust lever table (16 positions) as fractions of full thrust.

LUNAR_WIDTH

const LUNAR_WIDTH: number

World width (one wide view; the landscape wraps).

TAXI_H

const TAXI_H: 180

Playfield height (C64 pixels inside the border).

TAXI_SHIFTS

const TAXI_SHIFTS: Record<string, number[] | { random: number }>

Shifts: the morning's screens, a later set with hazards, everything in order, or ten at random.

TAXI_W

const TAXI_W: 320

Playfield size (C64 pixels inside the border).

Types

LanderDifficulty

type LanderDifficulty = "easy" | "normal" | "arcade"

Easy / Normal / Arcade. Arcade is the original's tables; each rules block says what the other two change.

LunarLanderOptions

interface LunarLanderOptions

Options for the Lunar Lander preset.

  • difficulty?: LanderDifficulty — Easy (1550 fuel a coin), Normal (1100) or Arcade (750, the factory setting). Default 'normal'.
  • fuelPerCoin?: number — Override fuel per coin (the operator settings are 450, 600, 750, 900, 1100, 1300, 1550, 1800).
  • mission?: number — Starting mission: 0 Training, 1 Cadet, 2 Prime, 3 Command. Default 0.
  • lit?: [number, number] — Lit sites per round as [2x sites, 3x-5x sites]. Default [2, 2].
  • startSpeed?: number — Starting horizontal speed (an estimate). Default 30.
  • seed?: number — Seed for lit sites and messages. Default 1979.

SpaceTaxiOptions

interface SpaceTaxiOptions

Options for the Space Taxi preset.

  • difficulty?: LanderDifficulty — Easy, Normal or Arcade (the estimated original): landing speed bands, fuel use and hazard speed. Default 'normal'.
  • shift?: "morning" | "day" | "standard" | "random" | number[] — Which shift. Default 'morning'.
  • fleet?: number — Cabs in the fleet. Default 6.
  • gravity?: number — Gravity. Default 30.
  • seed?: number — Seed. Default 1984.

Taxi

interface Taxi

A running taxi game.

  • readonly def: TaxiDef — The definition the game was built from.
  • readonly state: TaxiState — The session state (plain data; snapshot saves it).
  • readonly world: ThrustWorld — The world of the current screen.
  • readonly craftId: string — The taxi's craft id in world.
  • screen(): TaxiScreen — The current screen.
  • start(): void — Start a shift.
  • attract(): void — Back to attract.
  • step(input?: TaxiInput): void — Advance one fixed step.
  • drain(): TaxiEvent[] — Take queued events.
  • pad(id: string): TaxiPad | undefined — A pad on the current screen.
  • hourLabel(): string — The current hour label ("1:00").
  • snapshot(): unknown — Capture.
  • restore(s: unknown): void — Restore.

TaxiCraft

interface TaxiCraft

The taxi. Speeds in units per second.

  • hull: Vec2[] — Local hull (nose +x; use thrust-craft's fromUpright).
  • feet: number[] — Hull indices of the landing gear feet.
  • thrust: { up: number; down: number; left: number; right: number } — Thruster accelerations.
  • maxSpeed: number — Speed cap.
  • fuel: number — Fuel tank.
  • idleBurn: number — Fuel per second while flying.
  • thrustBurn: number — Extra fuel per second at full thrust.
  • gearTime: number — Seconds for the gear to come down.
  • safe: { vertical: number; horizontal: number } — Safe landing: vertical and horizontal speed.
  • rough: { vertical: number; horizontal: number } — Rough but survivable landing.

TaxiDef

interface TaxiDef

Everything a taxi game is built from.

  • screens: TaxiScreen[] — The screens.
  • shift: number[] | { random: number } — The shift: screen indices in play order, or 'random' over all of them.
  • gravity: number — Default gravity.
  • taxi: TaxiCraft — The taxi.
  • fleet: number — Taxis in the fleet.
  • fares: TaxiFares — Money.
  • timing: { intro: number; beam: number; walkSpeed: number; nextFare: number; crash: number; lowFuel: number } — Timings, seconds.
  • messages: { hail: string; pad: string; up: string; thanks: string; hey: string } — Messages.
  • step?: number — Fixed step. Default 1/60.
  • gearLocksSideways?: boolean — The gear disables the side thrusters while it is out. Default true.
  • firstPad?: string — The first passenger on each screen hails from the pad with this label (Space Taxi: "1"). Default any.
  • hazardSpeed?: number — Hazard speed multiplier (difficulty scaling). Default 1.
  • seed?: number — Seed.
  • difficulty?: LanderDifficulty — The difficulty this was built for (informational).

TaxiEvent

type TaxiEvent = | { type: "screen"; screen: number; name: string; hour: number } | { type: "hail"; pad: string } | { type: "board"; to: string } | { type: "deliver"; pad: string; fare: number; tip: number } | { type: "hey"; penalty: number } | { type: "gate"; open: boolean } | { type: "crash"; at: Vec2; cause: string } | { type: "landed"; pad: string | null; rough: boolean } | { type: "refuel"; units: number; cost: number } | { type: "extra-taxi" } | { type: "low-fuel" } | { type: "over"; money: number } | { type: "shift-done"; money: number }

Events for a presenter.

TaxiFares

interface TaxiFares

Money rules (dollars).

  • local: number — Fare for a ride within a screen.
  • between: number — Fare for a ride from the previous screen.
  • tipMin: number — Tip at the hail: a random amount between these.
  • tipMax: number — Highest hail tip in dollars; the tip is a random amount from tipMin to this.
  • tipDecay: number — Tip lost per second from the hail until delivery.
  • roughForfeits?: boolean — A rough landing during the ride forfeits the tip. Default true.
  • landOnPassenger: number — Landing on the waiting passenger.
  • hey: number — Sitting on a new passenger's spot: charged every heyEvery seconds until the taxi moves.
  • heyEvery: number — Seconds between "HEY!"s.
  • fuelPrice: number — Price of a unit of fuel.
  • refuelRate: number — Fuel units a second while refuelling.
  • extraTaxi: number[] — Earnings at which an extra taxi is given.

TaxiHazard

interface TaxiHazard

Something on a screen that destroys the taxi on contact.

  • id: string — Hazard id.
  • x: number — Start position.
  • y: number — Start position.
  • radius: number — Collision radius.
  • motion?: TaxiMotion — Motion. Default static.
  • phase?: number — Time offset, seconds (phases several movers apart).
  • blink?: { on: number; off: number } — Switch on and off: seconds on, seconds off (a laser, a force field).
  • look?: string — Presentation hint ("ball", "star", "laser", "mine", "bird"...).
  • box?: { w: number; h: number } — Half extents for a box-shaped hazard (a laser beam); the radius is ignored when given.

TaxiInput

interface TaxiInput

Player input.

  • x?: number — Thrust -1..1 each axis (x right, y down).
  • y?: number — Thrust on the y axis, -1 (up) to 1 (down). Default 0.
  • gear?: boolean — The fire button: gear down (or up while flying).

TaxiMotion

type TaxiMotion = /** Stays put. */ | { kind: "static" } /** Along waypoints at a speed, looping or back and forth. */ | { kind: "path"; points: Vec2[]; speed: number; pingPong?: boolean } /** Bounces inside a box like a ball. */ | { kind: "bounce"; vx: number; vy: number; box: { x0: number; y0: number; x1: number; y1: number } } /** Falls (a shooting star) from a start band to an end, then starts again after `gap` seconds. */ | { kind: "fall"; from: Vec2; to: Vec2; speed: number; gap?: number; spread?: number }

How a hazard moves.

TaxiPad

interface TaxiPad

A landing pad on a screen.

  • id: string — Pad id.
  • label: string — What the passenger calls it ("1".."9"). Fuel pads are "F".
  • x: number — Centre x of the landing surface.
  • y: number — y of the landing surface (y down).
  • width: number — Width of the landing surface.
  • fuel?: boolean — A fuel pad: refuelling, never a fare.

TaxiPassenger

interface TaxiPassenger

A passenger.

  • phase: "beam" | "wait" | "walk-in" | "ride" | "walk-out" — wait (hailing on a pad), walk-in, ride, walk-out.
  • from: string — Pickup pad.
  • to: string — Destination pad id, or 'up'.
  • x: number — Position (on a pad, or the taxi's).
  • y: number — Vertical position, world units: on the pad while waiting, the taxi's while riding.
  • tip: number — Tip meter.
  • rough: boolean — A rough landing happened during the ride.
  • between: boolean — Came from the previous screen (pays the between-screens fare).
  • t: number — Seconds in this phase.

TaxiScreen

interface TaxiScreen

One authored screen.

  • id: string — Screen id.
  • name: string — The name shown before it starts.
  • width: number — Playfield width.
  • height: number — Playfield height.
  • gravity?: number — Gravity (down). Default the definition's.
  • wells?: WellDef[] — Point wells (magnets, a black hole).
  • walls: TerrainDef[] — Solid walls: any touch destroys the taxi.
  • pads: TaxiPad[] — Landing pads.
  • gate: { x: number; width: number; y?: number } — The force field in the top wall: an opening that opens for an "up" passenger.
  • start: Vec2 — Where the taxi enters (from the gate) and restarts after a crash.
  • hazards?: TaxiHazard[] — Hazards.
  • fares?: number — Deliveries this screen needs before a rider asks to go up. Default: once every fare pad has been served (picked up from or delivered to).
  • data?: Record<string, unknown> — Free data for a presenter (colours, decoration).

TaxiState

interface TaxiState

The session state (plain data).

  • phase: "attract" | "intro" | "play" | "crash" | "over" | "done" — attract before a shift, intro while the screen's name shows, play, crash while a new taxi is awaited, over when the fleet is gone, done when the shift is finished.
  • hour: number — Index into the shift.
  • screen: number — Screen index into def.screens.
  • money: number — Earnings, dollars.
  • taxis: number — Taxis left (including the one flying).
  • extrasGiven: number — Extra taxis awarded so far, one for each threshold of fares.extraTaxi reached.
  • passenger: TaxiPassenger | null — The passenger on this screen, or null when none is hailing or riding.
  • served: string[] — Pads served this screen.
  • rides: number — Fares completed this screen.
  • gateOpen: boolean — Whether the force field in the top wall is open (while an 'up' passenger rides).
  • message: string — The current spoken line.
  • messageT: number — Seconds the current message has been showing.
  • nextT: number — Seconds to the next passenger.
  • t: number — Seconds in the current phase.
  • speedLight: "blue" | "yellow" | "red" — The taxi's dashboard.
  • takeoffLight: "yellow" | "red" — Dashboard light: red while a passenger walks to or from the taxi (take-off is held), else yellow.
  • lowFuel: boolean — Whether fuel is below timing.lowFuel of the tank.
  • heyT: number — Seconds until the next "HEY!" charge while the taxi sits on a new passenger's spot.
  • hazards: Array<{ id: string; x: number; y: number; vx: number; vy: number; on: boolean; t: number; seg: number; dir: number }> — Run-time state of each hazard of the screen, in its order: position, velocity, whether it is on, its clock and its path segment and direction.
  • order: number[] — Screen indices in play order for this shift (the definition's shift, or random picks).
  • rng: number[] — The seeded random stream's state: four words, from the kernel's rng.snapshot(). It advances in place and is saved with the state.

Touchdown

interface Touchdown

A running touchdown game.

  • readonly def: TouchdownDef — The definition the game was built from.
  • readonly world: ThrustWorld — The thrust-craft world that flies the lander.
  • readonly state: TouchdownState — The session state (plain data; snapshot saves it).
  • readonly craftId: string — The lander's craft id in world.
  • insertCoin(): void — Add one coin's fuel (any time; capped).
  • start(freePlay?: boolean): void — Start a game (free play adds a coin when there is no fuel).
  • select(): void — The SELECT button: next mission (any time).
  • setMission(index: number): void — Choose a mission.
  • step(input?: TouchdownInput): void — Advance one fixed step.
  • drain(): TouchdownEvent[] — Take queued events.
  • readout(): TouchdownReadout — The HUD values.
  • site(id: string): TouchdownSite | undefined — A site by id.
  • groundAt(x: number): number — The ground y at x.
  • attract(): void — Back to attract.
  • snapshot(): unknown — Capture the whole game.
  • restore(s: unknown): void — Restore a snapshot.

TouchdownAbort

interface TouchdownAbort

The abort button: right the craft, kill horizontal speed, then burn hard upward.

  • turnRate: number — Righting rate, rad/s.
  • accel: number — Abort engine acceleration (once upright).
  • burn: number — Abort fuel per second.
  • brake: number — Horizontal braking, units/s^2.
  • minTime: number — Shortest burn, seconds.
  • maxTime: number — Longest burn, seconds.
  • climb: number — Stop early once climbing at least this fast (after minTime).
  • upright?: number — Counts as upright within this tilt. Default one heading step.

TouchdownCraft

interface TouchdownCraft

The lander craft. Speeds are world units per second, angles radians.

  • hull: Vec2[] — Local hull, nose along +x (use thrust-craft's fromUpright).
  • feet: number[] — Hull indices of the feet.
  • thrust: number — Full-throttle engine acceleration.
  • levels: number[] — Throttle lever levels as fractions of full (the input snaps to them).
  • burn: number — Fuel per second at full throttle.
  • turnRate: number — Turn rate, rad/s (controlled rotation; momentum's spin cap is spinCap).
  • steps: number — Headings (32 on the arcade).
  • turnBurn?: number — Fuel per second while a rotate button is held. Default 0.
  • spinCap?: number — Momentum rotation: spin cap, rad/s. Default 4 x turnRate.
  • spinAccel?: number — Momentum rotation: spin acceleration while held, rad/s^2. Default 2 x turnRate.
  • spinDeadband?: number — Momentum rotation: a released spin slower than this stops, rad/s. Default 0.1.
  • good: { vertical: number; horizontal: number; angle: number } — Good landing: highest vertical and horizontal speed and tilt.
  • hard: { vertical: number; horizontal: number; angle: number } — Hard landing: highest vertical and horizontal speed and tilt.
  • footTolerance?: number — Both feet must be within this of the ground (flat ground only). Default 2.
  • flat?: number — Steepest ground counted as flat, radians. Default 0.03.

TouchdownDef

interface TouchdownDef

Everything a touchdown game is built from.

  • width: number — World width (wraps horizontally).
  • view: TouchdownView — The view and zoom rule; view.height is the world height.
  • terrain: Vec2[] — Terrain heightfield across the world, y down, first and last heights equal so it wraps.
  • sites: TouchdownSite[] — Flat landing sites.
  • lit: Array<{ multipliers: number[]; count: number }> — Which sites light each round: draws from groups of multipliers.
  • craft: TouchdownCraft — The lander.
  • missions: TouchdownMission[] — Missions; mission picks the starting one.
  • mission?: number — Starting mission index. Default 0.
  • fuel: { perCoin: number; max: number; lowAt: number; overDelay: number } — Fuel economy.
  • scoring: TouchdownScoring — Scoring.
  • start: { x: number; y: number; vx: number; vy: number; angle: number } — Where each round starts.
  • abort?: TouchdownAbort | null — The abort button. Null: none.
  • messages: TouchdownMessages — Messages.
  • resultTime: number — Seconds a result shows before the next round.
  • step?: number — Fixed step. Default 1/60.
  • seed?: number — Seed for lit sites and messages.
  • difficulty?: LanderDifficulty — The difficulty this definition was built for (informational).

TouchdownEvent

type TouchdownEvent = | { type: "round"; lit: string[] } | { type: "landed"; result: TouchdownResult } | { type: "crashed"; result: TouchdownResult } | { type: "abort" } | { type: "coin"; fuel: number } | { type: "mission"; mission: number } | { type: "zoom"; zoom: number } | { type: "low-fuel" } | { type: "out-of-fuel" } | { type: "over"; score: number } | { type: "start" }

Events for a presenter.

TouchdownInput

interface TouchdownInput

Player input for one step.

  • turn?: number — Rotate: -1 left (anticlockwise), 1 right.
  • lever?: number — Thrust lever 0..1 (snaps to the lever levels).
  • abort?: boolean — The abort button (held or pressed).

TouchdownMessages

interface TouchdownMessages

The messages shown after a landing or crash. The second line is picked at random.

  • good: string — Good landing headline.
  • goodLines: string[] — Good landing second lines.
  • hard: string — Hard landing headline.
  • hardLines: string[] — Hard landing second lines.
  • crashLines: string[] — Crash lines (no headline).
  • auxTanks: string[] — Fuel-penalty lines; {n} is the units lost.
  • points: string — Points line; {n} is the points.
  • lowFuel: string — Low fuel warning.
  • outOfFuel: string — Out of fuel.
  • perCoin: string — Attract line; {n} is fuel per coin.

TouchdownMission

interface TouchdownMission

One mission (Lunar Lander's TRAINING, CADET, PRIME, COMMAND).

  • id: string — Mission id.
  • name: string — Display name.
  • card?: string[] — The mission card lines.
  • gravity: number — Gravity, units/s^2 (down).
  • drag?: number — Atmospheric friction: linear drag per second. Default 0.
  • thrustScale?: number — Engine acceleration multiplier. Default 1.
  • burnScale?: number — Engine fuel-burn multiplier (not the abort). Default 1.
  • rotation?: "controlled" | "momentum" — Rotation: controlled turns at the fixed rate; momentum builds and keeps spin. Default 'controlled'.
  • tiltLimit?: number — Largest tilt from upright, radians (Training: PI/2, never upside down). Default unlimited.

TouchdownReadout

interface TouchdownReadout

The HUD values, rounded as the arcade shows them.

  • score: number — Score so far.
  • time: number — Seconds flown in the current round.
  • fuel: number — Fuel left, whole units.
  • altitude: number — Height above the ground below, world units, rounded; 0 when there is none.
  • horizontal: number — Horizontal speed, units per second, rounded.
  • horizontalDir: number — -1 left, 1 right, 0 none.
  • vertical: number — Vertical speed, units per second, rounded.
  • verticalDir: number — -1 up, 1 down, 0 none.

TouchdownResult

interface TouchdownResult

What the last landing or crash produced.

  • kind: "good" | "hard" | "crash" — How the landing was graded: good, hard or crash.
  • site: string | null — Id of the lit site landed on, or null when the craft came down elsewhere.
  • multiplier: number — Score multiplier applied: the lit site's, or TouchdownScoring.unlit (default 1) off a lit site.
  • points: number — Points awarded: the grade's base points times multiplier.
  • fuelLost: number — Fuel taken as the crash penalty (units); 0 unless crashed.
  • fuelGained: number — Fuel given for a good landing (units); 0 otherwise.
  • lines: string[] — Message lines to show: headline, second line and the points line, with {n} filled in.
  • at: Vec2 — Where it happened, world units.

TouchdownScoring

interface TouchdownScoring

Points and fuel rules.

  • good: number — Good landing points (times the multiplier).
  • hard: number — Hard landing points.
  • crash: number — Crash points.
  • goodFuel: number — Fuel added after a good landing.
  • crashAllowance: number — Crash penalty: fuel allowed per second of flight; any allowance not used is lost. 0 = none.
  • unlit?: number — Multiplier on unlit flat ground. Default 1.

TouchdownSite

interface TouchdownSite

A flat landing site cut into the terrain.

  • id: string — Site id.
  • x: number — Centre x.
  • width: number — Width of the flat.
  • multiplier: number — Score multiplier while the site is lit.

TouchdownState

interface TouchdownState

The session state (plain data).

  • phase: "attract" | "flying" | "result" | "over" — attract before a game, flying, result while a landing result shows, over when the game has ended.
  • mission: number — Index into TouchdownDef.missions of the mission in force.
  • score: number — Points scored this game.
  • coins: number — Coins inserted since the last attract.
  • roundTime: number — Seconds flown in the current round.
  • roundFuel: number — Fuel the craft had when the round began, in fuel units (used for the crash penalty).
  • rounds: number — Rounds started this game.
  • lit: string[] — Ids of the sites lit this round.
  • lever: number — Thrust lever position now, 0..1.
  • aborting: { t: number } | null — The abort burn in progress and the seconds it has run, or null.
  • result: TouchdownResult | null — The last landing or crash, or null while flying.
  • resultT: number — Seconds the result has been showing.
  • outOfFuelT: number | null — Seconds since the fuel ran out, or null while fuel remains.
  • lowFuel: boolean — Whether fuel is above 0 but below fuel.lowAt.
  • view: { zoom: number; x: number; y: number; w: number; h: number } — The camera rectangle now: zoom factor (1 is the far view), centre x and y and size w by h, in world units.
  • rng: number[] — The seeded random stream's state: four words, from the kernel's rng.snapshot(). It advances in place and is saved with the state.

TouchdownView

interface TouchdownView

The camera rule: the far view scrolls at its edges and zooms in near the ground.

  • width: number — Far view width, world units.
  • height: number — Far view height (also the world height).
  • edge?: number — Edge zone that scrolls the view, fraction of the view width or height. Default 1/8.
  • zoom?: { factor: number; inBelow: number; outAbove: number } | null — Zoom: factor, zoom in below inBelow altitude, out at or above outAbove near the top. Null: never zoom.