Phaser AE

Cockpit instruments

Pro packv3.0.0-32DArcade

The readouts of a vector cockpit, drawn as glowing strokes beside your line art: bars, dials, lamps, a radar scope, a scanner strip, a map screen, a frame, a gunsight and a lives tally. Each is one call, and a panel declares a whole HUD once.

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

Cockpit instruments: 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

instruments

function instruments(): Pack<{ instruments: InstrumentsApi }>

The instruments pack. Pure logic, so it needs no backend and runs headless.

Helpers

bar

function bar(t: InstrumentTarget, o: BarOptions): void

A bar gauge: an outline, a fill and optional divisions. The fill is drawn as horizontal (or vertical) strokes rather than a solid, because that is what a beam can do and what the panels of the era actually looked like.

createPanel

function createPanel(items: PanelItem[]): Panel

Creates a Panel from a list of items. The same as new Panel(items).

crosshair

function crosshair(t: InstrumentTarget, o: CrosshairOptions): void

The gunsight: Star Wars, Tail Gunner, Starhawk, Red Baron.

dial

function dial(t: InstrumentTarget, o: DialOptions): void

A round gauge with a needle — speedo, rev counter, shield strength.

formatScore

function formatScore(value: number, digits = 6): string

4200 → '004200'. Leading zeros are the look.

formatTime

function formatTime(seconds: number, showTenths = false): string

95.4 → '1:35'; over an hour it grows a field rather than wrapping.

frame

function frame(t: InstrumentTarget, o: FrameOptions): void

A viewport frame with corner ticks — the cockpit surround, a scope bezel — or, with box, a plain outline.

lamp

function lamp(t: InstrumentTarget, o: LampOptions): void

A warning lamp. Pair with flash() from scoreboard, or a Panel lamp with flashing, for a blinking one.

mapView

function mapView(t: InstrumentTarget, o: MapOptions): void

A room graph as a map screen, scaled to fit the box. Takes the plain shapes RoomGraph hands out (graph.all, graph.doors), so the map is a VIEW of the live topology rather than a second copy of the level that can drift.

radar

function radar(t: InstrumentTarget, o: RadarOptions): void

The Battlezone scope. Everything is drawn in the owner's frame: rotate a contact by the owner's heading and the blip sits where the thing IS relative to where you are pointing, which is the only reason the display works.

scanner

function scanner(t: InstrumentTarget, o: ScannerOptions): void

Aztarac's scanner: the whole world shrunk into a box, with the visible window marked. Where a radar answers "what is near me", this answers "what is happening somewhere else" — the difference matters in a game about defending outposts you cannot see.

tally

function tally(t: InstrumentTarget, o: TallyOptions): void

A row of ship/life/ball icons drawn as small closed outlines, left to right.

Classes

Panel

class Panel

A panel is a list of widgets bound to READERS, so the HUD is declared once and never touched again — the gauge follows the meter rather than the game remembering to push a number at it every frame.

const panel = createPanel([
  { kind: 'bar', x: 20, y: 40, w: 140, h: 14, label: 'OXYGEN',
    read: () => res.oxygen.frac, warn: 0.25, warnStyle: { color: '#ff5fa2' } },
  { kind: 'lamp', x: 200, y: 47, label: 'SONAR', flashing: true,
    read: () => sub.sonarDamaged },
]);
panel.draw(game.vector, time);
  • readonly items: PanelItem[] — The widgets the panel draws, in order.
  • flashHz: number — Flash rate for lamps with flashing. Default 4 Hz.
  • constructor(items: PanelItem[])
  • add(item: PanelItem): this — Adds one item to the panel. Returns the panel, so calls can chain.
  • draw(t: InstrumentTarget, time = 0): void — Calls each item's read() and draws every widget. Pass the current time in seconds so flashing lamps blink.

Types

BarOptions

interface BarOptions

Options for bar(): the box, the fill fraction and the styles.

  • x: number — The left edge of the bar, in world units.
  • y: number — The top edge of the bar, in world units.
  • w: number — The width of the bar, in world units.
  • h: number — The height of the bar, in world units.
  • frac: number — 0..1.
  • warn?: number — Fill below this fraction uses warnStyle. Default 0 (never).
  • ticks?: number — Divisions drawn across the track. Default 0.
  • vertical?: boolean — Fill bottom-up instead of left-to-right. Default false.
  • label?: string — Text drawn above the bar.
  • labelSize?: number — The text size of the label, in world units. Default 11.
  • style?: Style — The style of the outline, the ticks and the label.
  • fillStyle?: Style — The style of the fill strokes. Default: style.
  • warnStyle?: Style — The fill style while frac is at or below warn. Default: fillStyle.

Contact

interface Contact extends XY

One thing a radar or scanner shows. Its x/y are a world position.

  • kind?: string — Picks a style out of blipStyles.

CrosshairOptions

interface CrosshairOptions

Options for crosshair(): the position, the size and the style of the gunsight.

  • x: number — The x position of the centre, in world units.
  • y: number — The y position of the centre, in world units.
  • size: number — Arm length.
  • gap?: number — Empty space at the centre. Default a third of size.
  • ring?: boolean — Draw a ring at size. Default false.
  • lock?: number — Pull the arms in to show a lock. 0..1, default 0.
  • style?: Style — The line style of the crosshair.

DialOptions

interface DialOptions

Options for dial(): the face, the needle value and the styles.

  • x: number — The x position of the dial's centre, in world units.
  • y: number — The y position of the dial's centre, in world units.
  • r: number — The radius of the face, in world units.
  • frac: number — 0..1 round the sweep.
  • from?: number — Start of the sweep, radians. Default 0.75π (bottom left).
  • to?: number — End of the sweep. Default 2.25π (bottom right) — a 270° face.
  • ticks?: number — Marks round the face. Default 8.
  • label?: string — Text drawn inside the lower half of the face.
  • style?: Style — The style of the face, the ticks and the label.
  • needleStyle?: Style — The style of the needle. Default: style.

FrameOptions

interface FrameOptions

Options for frame(): the box to surround and its style.

  • x: number — The left edge of the frame, in world units.
  • y: number — The top edge of the frame, in world units.
  • w: number — The width of the frame, in world units.
  • h: number — The height of the frame, in world units.
  • tick?: number — Corner tick length. Default: a tenth of the short side.
  • box?: boolean — Draw the whole box outline instead of the corner ticks. Default false (corner ticks only).
  • style?: Style — The line style of the frame.

InstrumentsApi

type InstrumentsApi = typeof kit

game.instruments — every function and type this pack carries, as one namespace.

InstrumentTarget

interface InstrumentTarget

game.vector is one of these. So is any object with the same four verbs.

  • seg(x0: number, y0: number, x1: number, y1: number, style?: Style): void — Draws one line segment from (x0, y0) to (x1, y1).
  • poly(points: readonly XY[], style?: Style & { closed?: boolean }): void — Draws a polyline through the points. closed joins the last point to the first, and it lives IN THE STYLE — v2 took it as a third argument, and game.vector.poly does not, so a call that passed it positionally type-checked (a narrower function is assignable to a wider one) and had the argument silently dropped. Every closed instrument shape drew as an open path: the lives tally lost the base of its ship and read as a chevron.
  • arc(cx: number, cy: number, r: number, from: number, to: number, style?: Style, steps?: number): void — Draws an arc round (cx, cy) with radius r, from angle from to to in radians.
  • text?(str: string, x: number, y: number, opts?: TextOptions): void — Draws a line of text. Optional: an instrument skips its labels when this is absent.

LampOptions

interface LampOptions

Options for lamp(): the position, the state and the styles.

  • x: number — The x position of the lamp's centre, in world units.
  • y: number — The y position of the lamp's centre, in world units.
  • r?: number — The radius of the lamp, in world units. Default 7.
  • on: boolean — True lights the lamp: an inner ring is added. False draws it with offStyle.
  • label?: string — Text drawn to the right of the lamp.
  • style?: Style — The style of the lit lamp, and of the label.
  • offStyle?: Style — The style of the unlit lamp. Default: style.

MapDoor

interface MapDoor

One connection between two rooms, drawn by mapView() as a line.

  • a: string — The id of the room at one end.
  • b: string — The id of the room at the other end.
  • locked?: boolean — Draw the door with lockedStyle. Default false.
  • hidden?: boolean — Do not draw the door at all. Default false.

MapOptions

interface MapOptions

Options for mapView(): the box, the room graph and the styles.

  • x: number — The left edge of the map box, in world units.
  • y: number — The top edge of the map box, in world units.
  • w: number — The width of the map box, in world units.
  • h: number — The height of the map box, in world units.
  • rooms: readonly MapRoom[] — The rooms to draw. graph.all from a RoomGraph fits as-is.
  • doors: readonly MapDoor[] — The doors to draw as lines between rooms. graph.doors fits as-is.
  • current?: string | null — The room the player is in — drawn ringed.
  • route?: readonly string[] — Highlight this run of room ids (a planned or escape route).
  • fogged?: boolean — Hide rooms not yet visited. Default true.
  • node?: number — Half-size of a room marker. Default 7.
  • style?: Style — The base line style for rooms and doors.
  • visitedStyle?: Style — The style for rooms with visited set. Default: style.
  • currentStyle?: Style — The style of the ring round the current room. Default: the room's own style.
  • routeStyle?: Style — The style for doors with both rooms on the route. Default: style.
  • lockedStyle?: Style — The style for locked doors. Default: style with dash: 6.
  • tagStyles?: Record<string, Style> — Room ids by tag get their own style: { reactor: {...} }.

MapRoom

interface MapRoom extends XY

One room on the map screen, for mapView(). Its x/y place it in the graph.

  • id: string — The unique id of the room. Doors refer to rooms by id.
  • visited?: boolean — True once the player has entered the room. A fogged map hides unvisited rooms.
  • cleared?: boolean — True once the room is cleared. Game data — mapView() does not read it.
  • tags?: string[] — Tags that pick a style out of tagStyles.

PanelItem

type PanelItem = /** A `bar()` whose `frac` is `read()` each draw. */ | ({ kind: 'bar'; read(): number } & Omit<BarOptions, 'frac'>) /** A `dial()` whose `frac` is `read()` each draw. */ | ({ kind: 'dial'; read(): number } & Omit<DialOptions, 'frac'>) /** A `lamp()` lit while `read()` is true; `flashing` blinks it at the panel's `flashHz`. */ | ({ kind: 'lamp'; read(): boolean; flashing?: boolean } & Omit<LampOptions, 'on'>) /** A line of text from `read()`; skipped when the target has no `text`. */ | { kind: 'text'; x: number; y: number; read(): string; size?: number; align?: 'left' | 'center' | 'right'; style?: Style } /** Anything else: `draw` is called with the target and the time in seconds. */ | { kind: 'custom'; draw(t: InstrumentTarget, time: number): void }

One widget in a Panel: an instrument's options plus a read() function. The panel calls read() on each draw to get the live value.

RadarOptions

interface RadarOptions

Options for radar(): the scope, what it is centred on and the contacts.

  • x: number — The x position of the scope's centre, in world units.
  • y: number — The y position of the scope's centre, in world units.
  • r: number — The radius of the scope, in world units.
  • centre: XY — What the scope is centred on.
  • range: number — World units the scope's radius covers.
  • heading?: number — Which way the owner is facing, radians. Contacts are rotated by -heading so FORWARD IS UP, which is what makes a radar readable at a glance; leave it out for a north-up map scope.
  • contacts: readonly Contact[] — The contacts to draw as blips, at world positions.
  • blip?: number — Radius of a blip. Default 3.
  • clampEdge?: boolean — Show contacts beyond range pinned to the rim instead of dropping them.
  • sweep?: number — Angle of a rotating sweep line, radians. Omit for none.
  • fov?: number — Half-angle of the "in front of me" wedge to outline. Omit for none.
  • style?: Style — The line style of the scope rings. Also the last-resort blip style.
  • blipStyle?: Style — The style of a blip. Default: style.
  • blipStyles?: Record<string, Style> — Styles by contact kind. A contact without a match uses blipStyle.
  • sweepStyle?: Style — The style of the sweep line. Default: style.

ScannerOptions

interface ScannerOptions

Options for scanner(): the box, the world it shrinks and the contacts.

  • x: number — The left edge of the scanner box, in world units.
  • y: number — The top edge of the scanner box, in world units.
  • w: number — The width of the scanner box, in world units.
  • h: number — The height of the scanner box, in world units.
  • world: { x: number; y: number; w: number; h: number } — The whole playfield the scanner covers.
  • view?: { x: number; y: number; w: number; h: number } — The part of it currently on screen — drawn as a box inside the scanner.
  • contacts: readonly Contact[] — The contacts to draw as dots, at world positions.
  • style?: Style — The line style of the scanner outline. Also the last-resort blip style.
  • viewStyle?: Style — The style of the view box. Default: style.
  • blipStyle?: Style — The style of a contact dot. Default: style.
  • blipStyles?: Record<string, Style> — Styles by contact kind. A contact without a match uses blipStyle.

Style

interface Style

Structurally a subset of the vector layer's LineStyle.

  • color?: string — The stroke color, as a CSS color string.
  • color2?: string — The color at the far end of each stroke — a gradient along the line.
  • width?: number — The stroke width, in world units.
  • glow?: number — The intensity of the phosphor halo. 0 gives a clean line.
  • alpha?: number — The opacity of the stroke, 0..1.
  • dash?: number — The dash period, in world units. 0 gives a solid line.
  • dwell?: number — Beam dwell 0..1: how much the ends of each stroke brighten and fatten.
  • z?: number — The depth of the stroke in the vector pass. Bigger is in front.

TallyOptions

interface TallyOptions

Options for tally(): where the row starts, how many icons and their shape.

  • x: number — The x position of the first icon's centre, in world units.
  • y: number — The y position of the icons' centres, in world units.
  • count: number — How many icons to draw (lives, bombs, ammo).
  • size?: number — Half the icon's height, in world units: the shape is scaled by it. Default 10.
  • gap?: number — Distance between icon centres, in world units. Default 1.8 × size.
  • shape?: readonly XY[] — The icon as a closed outline in units of size, centred on (0, 0), y down. Default a ship chevron.
  • style?: Style — The line style of the icons.

TextOptions

interface TextOptions

Options for InstrumentTarget.text(). A subset of the vector layer's text options.

  • size?: number — Cap height of the text, in world units.
  • align?: 'left' | 'center' | 'right' — Horizontal anchor of the text at its x position.
  • spacing?: number — Gap between glyphs, as a fraction of size.
  • style?: Style — The line style of the text strokes.

XY

interface XY

A 2D point: x across, y down. Contacts and map rooms extend it; poly() takes a list of them.

  • x: number — The x position, across.
  • y: number — The y position, down.