Phaser AE

Scrolling shooters

Pro packv3.0.0-32DArcade

The rules of a vertical or horizontal scrolling shooter, from the first formation to the boss and the tally, as one definition your game plays and draws. Two arcade-style presets show the range; every count, layout, timing and rule in them is configuration.

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

Scrolling shooters: 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

scrollingShooter

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

Install the renderer-independent scrolling shooter API.

Helpers

ambient1942

function ambient1942(until: number)

The dead-air guard for 1942 stages: pairs of fighters whenever the sky has been empty for 1.2 s.

arcSegments

function arcSegments(cx: number, cy: number, r: number, from: number, sweep: number): PathSegmentData[]

Cubic segments for an arc about (cx, cy) of radius r from angle from turning sweep degrees (positive = clockwise on screen).

createShooter

function createShooter(config: ShooterConfig)

Create an independent scrolling shooter. No renderer or kernel clock is required.

fighterStream1942

function fighterStream1942(from: number, to: number, every = 80, phase = 0): ScriptEntry[]

The arcade's traffic: a small-fighter formation every every pixels of scroll (2.5 s at 32 px/s) from from to to, cycling through the approaches from phase, so the next group is already arriving while the last one is still on screen.

gradiusMeter

function gradiusMeter(maxOptions = 4, speedSteps = 5, shieldHits = 15): MeterSlot[]

The arcade power meter: SPEED UP, MISSILE, DOUBLE, LASER, OPTION, ?.

gradiusPreset

function gradiusPreset(o: GradiusPresetOptions = {}): ShooterConfig

Konami's Gradius (1985) as a scrolling-shooter definition: a 256 x 224 screen scrolling right; the power meter (SPEED UP, MISSILE, DOUBLE, LASER, OPTION, ?) advanced by red capsules and taken with the power-up button, DOUBLE and LASER exclusive, up to four Options trailing the ship's path, the front force field, blue capsules every sixteenth drop, Fan formations that pay a capsule, ground turrets that aim, hatches, Duckers and Jumpers on the terrain, fatal terrain, the volcano eruption, Big Core with four barrier walls and a time limit, checkpoint restarts that strip the ship, loops with revenge bullets and rank.

items1942

function items1942(): ItemDef[]

Items of the 1942 preset: one POW per colour and the Yashichi. Every POW is worth 1,000; an upgrade already held pays the 1,000 alone.

itemsGradius

function itemsGradius(): ItemDef[]

Capsules: a red one advances the meter; after every 15 reds the next drop is blue and destroys every small enemy on screen.

kinds1942

function kinds1942(): EnemyKind[]

Enemy kinds of the 1942 preset. Scores from the StrategyWiki tables; hit points and timings are estimates.

kindsGradius

function kindsGradius(): EnemyKind[]

Enemy kinds of the Gradius preset. Big Core's 5,000 and 100 per barrier and the hatch's 1,000 are documented; other scores, hit points and timings are estimates.

loopRamp

function loopRamp(r: LoopRamp, loop: number)

Evaluate a loop ramp for a 0-based loop.

paths1942

function paths1942()

Screen paths of the 1942 preset (224 x 256, y down). Authored for one side; waves mirror them.

pathsGradius

function pathsGradius()

Screen paths of the Gradius preset (256 x 224).

preset1942

function preset1942(o: Preset1942Options = {}): ShooterConfig

Capcom's 1942 (1984) as a scrolling-shooter definition: a 224 x 256 portrait screen scrolling up over the Pacific; the P-38's twin gun (quad with the POW), three loops per stage that dodge everything, red formations that leave the stage's POW, side fighters, the smart-bomb POW, medium and large bombers, the Ayako boss, the shoot-down bonus table, stages counted down from 32, restart before the last red formation, 20,000 / 80,000 extra lives.

route

function route(start: [number, number], ...segments: (PathSegmentData | PathSegmentData[])[]): PathData

A path from a start point and segments.

stages1942

function stages1942(bossEveryStage = false): StageDef[]

The authored stages 32 (Midway, quad-gun POW), 31 (smart-bomb POW) and 30 (side-fighter POW, ending with Ayako): a continuous stream of small fighters with the stage's red formations, medium and large bombers, Fukusuke and BVD jets laid over it, and a dead-air guard.

volcanoStage

function volcanoStage(): StageDef

Stage 1, the volcano stage: the space section, the land with its turrets, hatches, Duckers and Jumpers, the eruption and Big Core.

volcanoTerrain

function volcanoTerrain()

Stage 1 terrain: open space, mountains below, a cave roof, then the twin volcanoes (floor and roof).

Classes

ScrollingShooter

class ScrollingShooter

Owns a scrolling shooter: the scroll and world bounds, distance/time-keyed stage scripts, enemies on authored paths and ground surfaces, air and ground hit layers, terrain collision, guns, power meter or pickups, Options and side fighters, the evasive loop, bosses with parts and time limits, stage tallies, lives, extra lives, checkpoints, loops and rank. Renderer-independent and deterministic.

  • readonly config: ShooterConfig — The validated definition (a private copy).
  • constructor(config: ShooterConfig)
  • get span() — Screen length of the scroll axis.
  • along(p: Vec) — Along coordinate (from the trailing edge) of a screen point.
  • cross(p: Vec) — Cross coordinate of a screen point.
  • point(a: number, c: number): Vec — Screen point from along and cross.
  • forward(f: number, s: number): Vec — Screen delta of a forward-frame offset.
  • forwardAngle(a: number) — Screen angle (degrees) of a forward-frame angle.
  • get terrain(): TerrainEnvelope | null — The current stage's terrain, or null.
  • floorAt(a: number) — Floor cross coordinate at a screen along coordinate (Infinity without terrain).
  • ceilingAt(a: number) — Ceiling cross coordinate at a screen along coordinate (-Infinity without terrain).
  • terrainColumns(step = 4) — Terrain columns across the screen every step pixels, for drawing: along, floor and ceiling cross coordinates (null when absent).
  • get stage(): StageDef — The stage definition being played.
  • get state(): ShooterState — A copy of the whole state.
  • get rank() — Current rank (0 without rank rules).
  • get fireRate() — Enemy fire-rate multiplier now (difficulty, loop and rank).
  • get bulletSpeed() — Enemy bullet-speed multiplier now.
  • slotAvailable(index: number) — Can a meter slot be taken now?
  • tick(seconds: number, input: ShooterInput = {}) — Advance by real seconds in fixed steps.
  • step(input: ShooterInput = {}) — Advance exactly one fixed step.
  • startWave(w: WaveDef, late = 0) — Start a wave now (script entries call this; a presenter or test may too). late is how far the scroll has passed the wave's trigger: ground members are placed as if they had appeared on time.
  • smartBomb() — Destroy every ordinary enemy on screen; heavy enemies take smartDamage, bosses and part-built enemies are unharmed.
  • drain() — Take the events since the last drain.
  • kind(id: string) — The enemy kind definition.
  • item(id: string) — The item definition.
  • snapshot() — Serializable snapshot of the whole game.
  • restore(snap: ReturnType<ScrollingShooter["snapshot"]>) — Restore a snapshot taken from the same configuration.
  • reset(stage = 0, loop = 0) — New game from stage index stage (0-based, default 0), on loop loop (default 0).

Constants

POW_1942

const POW_1942: { readonly quad: "pow-quad"; readonly bomb: "pow-bomb"; readonly wing: "pow-wing"; readonly life: "pow-life"; readonly cease: "pow-cease"; readonly loop: "pow-loop"; readonly points: "pow-points"; }

POW item ids of the 1942 preset, by colour.

Types

AmbientRules

interface AmbientRules

The dead-air guard. Whenever no live target has been on screen (and none is about to enter) for maxQuiet seconds of play, the next of waves starts (in turn), until the scroll passes until. Authored scripts set the pace; this bounds the lulls however quickly the player clears them.

  • waves: WaveDef[] — Filler waves, used in turn.
  • maxQuiet: number — Longest quiet stretch allowed (seconds).
  • until?: number — No filler once the scroll distance reaches this (default: the stage length).

BossRules

interface BossRules

Boss behaviour.

  • timeLimit?: number — Seconds after appearing before it self-destructs without paying (Gradius). Omit for none.
  • selfDestruct?: number — Seconds of the self-destruct sequence. Default 2.
  • clearsStage?: boolean — Destroying it (or its time running out) ends the stage. Default true.

Difficulty1942

type Difficulty1942 = "easy" | "normal" | "hard" | "very-hard"

Difficulty DIP setting of the 1942 preset.

EnemyFire

interface EnemyFire

How an enemy shoots.

  • pattern: ProjectilePattern — Pattern from projectile-patterns (aimed, fan, ring, burst, ...); its speed is px/s.
  • aim?: "player" | "lead" | number — player aims at the ship, lead at where it is heading, a number is a screen angle in degrees. Default player.
  • every: number — Seconds between volleys (scaled by difficulty).
  • first?: number — Seconds before the first volley (default a seeded fraction of every).
  • chance?: number — Chance each opportunity fires. Default 1.
  • ports?: Vec[] — Muzzles, screen offsets from the centre. Default the centre.
  • max?: number — Volleys per life. Default unlimited.
  • minDistance?: number — No volley while the ship is nearer than this. Default 0.
  • whileStanding?: boolean — Only fires while standing still (walkers, trackers).
  • w?: number — Bullet box. Default 3 x 3.
  • h?: number — Bullet box. Default 3 x 3.
  • tag?: string — Presentation tag for the bullets.

EnemyKind

interface EnemyKind

An enemy type.

  • id: string — Unique id.
  • hp: number — Hits to destroy; 0 = not a target (shots pass through), e.g. a volcano vent.
  • score: number — Points when destroyed.
  • hitScore?: number — Points per damaging hit that does not destroy it (1942 large planes: 100).
  • layer: HitLayer — Air or ground target.
  • w: number — Box width.
  • h: number — Box height.
  • contact?: boolean — Touching it destroys the ship. Default: true in the air, false on the ground.
  • motion: EnemyMotion — Movement.
  • fire?: EnemyFire[] — Shooting: one or more volleys, used in turn (a boss alternating patterns).
  • spawner?: EnemySpawner — Children.
  • parts?: EnemyPart[] — Damageable pieces; when present only the parts can be hit.
  • boss?: BossRules — Boss rules.
  • drop?: string — Item dropped when it is destroyed (red-coloured capsule carriers).
  • heavy?: boolean — Smart bombs damage it by smartDamage instead of destroying it, and a ceasefire does not silence it.
  • smartDamage?: number — Damage a smart bomb deals to a heavy enemy. Default 0.
  • counts?: boolean — Counts toward the shoot-down ratio. Default true when score > 0.
  • chain?: { /** Added per consecutive kill. */ step: number; /** Score ceiling. */ max: number; } — Each kill of this kind without losing a life adds step, up to max (1942 Daihiryu: 2,000 + 500, to 9,000).
  • solid?: boolean — Destroyed without score when it touches terrain (falling rocks).
  • revenge?: boolean — May fire a revenge bullet when destroyed, with the loop's difficulty.revenge chance.

EnemyMotion

type EnemyMotion = /** Fly an authored path (from the wave, or `path`) at `speed`; it leaves when the path ends. */ | { type: "path"; speed: number; path?: string } /** Straight flight from the spawn point at `angle` (or at the player with `aim`), homing `turn` deg/s for `homeSeconds`, falling with `gravity`, optionally carried by the scroll (`world`). */ | { type: "line"; speed: number; angle?: number; aim?: boolean; turn?: number; homeSeconds?: number; gravity?: number; world?: boolean } /** Fixed to the scrolling ground; optionally sits on a terrain `surface`, walks (`walk` px/s, `walkFor`/`standFor` cycle, `chase` = walk to get `ahead` of the player), and `hop`s while walking. */ | { type: "ground"; surface?: "floor" | "ceiling" | "none"; walk?: number; walkFor?: number; standFor?: number; chase?: boolean; ahead?: number; hop?: number; } /** Carried by the ground until launched; climbs across the axis to the player's line at `climb`, then darts toward the trailing edge at `dart` (Gradius Rush). */ | { type: "dart"; climb: number; dart: number } /** Flies to a screen `station` at `speed`, then sways (`sway`) or tracks the player across the axis in `step`-pixel moves (`track`), and leaves after `leaveAfter` seconds toward `leaveTo`. */ | { type: "station"; speed: number; station: Vec; sway?: { along: number; cross: number; period: number }; track?: { step: number; speed: number; pause: number; min: number; max: number }; leaveAfter?: number; leaveTo?: "leading" | "trailing"; }

How an enemy moves. Screen pixels and seconds; angles in screen degrees (0 = right, 90 = down).

EnemyPart

interface EnemyPart

A separately damageable piece of a large enemy (Big Core's barriers and core).

  • id: string — Unique within the kind.
  • x: number — Centre offset from the enemy (screen).
  • y: number — Centre offset from the enemy (screen).
  • w: number — Box width.
  • h: number — Box height.
  • hp?: number — Hits to destroy; omit for armour that only absorbs shots.
  • score?: number — Points when destroyed.
  • core?: boolean — Destroying it destroys the enemy.
  • guardedBy?: string[] — Absorbs shots without damage until every listed part is destroyed.

EnemyShot

interface EnemyShot

An enemy bullet.

  • id: number — Unique id.
  • x: number — Centre.
  • y: number — Centre.
  • vx: number — Velocity.
  • vy: number — Velocity.
  • w: number — Box.
  • h: number — Box.
  • tag: string — Presentation tag.

EnemySpawner

interface EnemySpawner

A child launched by an enemy: hatches, volcanoes.

  • kind: string — Kind spawned.
  • every: number — Seconds between launches.
  • first?: number — Seconds before the first. Default every.
  • burst?: number — Children per launch. Default 1.
  • max?: number — Total launches. Default unlimited.
  • until?: number — Stops this many seconds after the parent appears.
  • speed?: [number, number] — Launch speed range for line children (px/s).
  • angle?: [number, number] — Launch angle range for line children (screen degrees).
  • at?: Vec — Screen offset of the launch point.

EvadeRules

interface EvadeRules

1942 loop: a limited, fully invulnerable evasive manoeuvre.

  • charges: number — Charges at the start of a stage (and of the game).
  • seconds: number — Seconds it lasts.
  • fire: boolean — Can fire while evading.
  • resetEachStage: boolean — Charges reset at every stage start.
  • refillOnDeath: boolean — Charges reset after a lost life.
  • bonusPerCharge: number — Stage-end bonus per unused charge.

GradiusPresetOptions

interface GradiusPresetOptions

Options for gradiusPreset.

  • lives?: number — Ships, including the one in play (DIP: 3, 4, 5 or 7; default 3).
  • maxOptions?: number — Most Options at once (arcade: 4).
  • speedSteps?: number — SPEED UPs available (arcade: 5).
  • shieldHits?: number — Front hits the ? force field absorbs (default 15; the arcade figure is undocumented).
  • autofire?: number | null — Seconds between shots while fire is held; null = tap for every shot (default 0.2).
  • extraLives?: [number, number] — First extra ship and the interval after it (Japan default: 30,000 then every 80,000).
  • seed?: number — Seed (default 1).

GunDef

interface GunDef

A weapon: what one press fires and how often.

  • shots: ShotSpec[] — The volley.
  • limit: number — Live projectiles of this gun allowed per emitter; a volley fires only if all of it fits.
  • cooldown: number — Minimum seconds between volleys.
  • hold: number | null — Seconds between volleys while the button is held; null = the button must be released.

HitLayer

type HitLayer = "air" | "ground"

Hit layer: air targets are hit by air shots; ground targets by shots that list ground.

ItemDef

interface ItemDef

A pickup that can be dropped and collected.

  • id: string — Unique id.
  • w: number — Pickup box width.
  • h: number — Pickup box height.
  • score?: number — Points on collection. Default 0.
  • effect?: PowerEffect — Applied on collection.
  • meter?: boolean — Collecting it advances the power meter cursor.
  • drift?: Vec — Screen velocity (px/s). Default none.
  • world?: boolean — Also moves with the scrolling ground.
  • life?: number — Removed after this many seconds (default: when it leaves the screen).
  • fallback?: string — Collected while its effect would change nothing: this item is applied instead (1942: the 1,000-point POW).
  • every?: { /** Drops of this item before the substitute. */ count: number; /** The substitute item. */ item: string; } — Every count drops of this item, the next one is item instead (Gradius: a blue capsule after 15 red).

Loadout

interface Loadout

Ship loadout.

  • speed: number — SPEED UPs taken.
  • gun: string — Main gun id.
  • secondary: string | null — Secondary gun id, or null.
  • options: number — Options.
  • shield: number — Shield hits left.
  • wingmen: boolean[] — Side fighters alive, by slot.

LoopRamp

interface LoopRamp

A value that changes with the loop (completed passes through the stage list): base + perLoop * loop, clamped to max.

  • base: number — Value on the first pass.
  • perLoop?: number — Added per completed loop.
  • max?: number — Upper clamp.

MeterSlot

interface MeterSlot

One box of a Gradius-style power meter.

  • label: string — Label shown in the box.
  • effect: PowerEffect — Applied when selected.

Offset

interface Offset

A point in the forward frame of the ship.

  • f: number — Along the direction of flight (positive = ahead).
  • s: number — Across it (positive = toward the floor side).

OptionRules

interface OptionRules

Gradius Options: satellites that trail the ship's path and copy its weapons.

  • max: number — Most at once.
  • gap: number — Ship moves (fixed steps in which it moved) between one follower and the next.

PlayerDef

interface PlayerDef

Ship options and rules.

  • start: Vec — Spawn point (screen).
  • bounds: { /** Leftmost centre x. */ minX: number; /** Rightmost centre x. */ maxX: number; /** Highest centre y. */ minY: number; /** Lowest centre y. */ maxY: number; } — Movement bounds (screen).
  • speed: number — Base speed (px/s).
  • speedStep: number — Added per SPEED UP.
  • w: number — Hit box.
  • h: number — Hit box.
  • lives: number — Ships, including the one in play.
  • gun: string — Starting main gun.
  • secondary?: string | null — Starting secondary weapon, or null.
  • secondaryOnFire?: boolean — Fires the secondary weapon with the fire button instead of its own.

PlayerShot

interface PlayerShot

A player projectile.

  • id: number — Unique id.
  • owner: string — Emitter: ship, option0.., wing0...
  • gun: string — Gun id.
  • x: number — Centre.
  • y: number — Centre.
  • vx: number — Velocity.
  • vy: number — Velocity.
  • hw: number — Half extents of the hit box.
  • hh: number — Half extents of the hit box.
  • damage: number — Damage.
  • layers: HitLayer[] — Layers it hits.
  • pierce: boolean — Pierces.
  • motion: "straight" | "hug" | "lob" | "beam" — Motion.
  • grounded: boolean — Riding the floor (hug).
  • travel: number — Distance flown (lob) / beam length.
  • limit: number — Lob range / beam maximum.
  • attached: boolean — Beam still held at the muzzle.
  • extra: number — Hug floor speed / lob radius / beam speed.
  • climb: number — Hug climb limit.
  • hits: number[] — Ids already pierced.
  • tag: string — Presentation tag.
  • angle: number — Screen angle of travel (degrees).

PowerEffect

type PowerEffect = | { kind: "speed"; max: number } | { kind: "gun"; gun: string } | { kind: "gun-chain"; chain: string[] } | { kind: "secondary"; gun: string } | { kind: "option"; max: number } | { kind: "wingmen" } | { kind: "shield"; hits: number } | { kind: "smart-bomb" } | { kind: "evade"; add: number } | { kind: "life" } | { kind: "points"; score: number } | { kind: "ceasefire"; seconds: number }

What a power-up does.

Preset1942Options

interface Preset1942Options

Options for preset1942.

  • lives?: number — Ships, including the one in play (DIP: 1, 2, 3 or 5; default 3).
  • extraLives?: [number, number] — First extra ship and the interval after it (default 20,000 then every 80,000).
  • difficulty?: Difficulty1942 — Enemy fire rate and bullet speed (default normal).
  • loops?: number — Loops (rolls) per stage (default 3).
  • stages?: number — Authored stages to play before the list loops, 1 to 3 (default 3: stages 32, 31 and 30).
  • bossEveryStage?: boolean — Large-bomber boss Ayako ends every stage, not just stage 30 (default false).
  • seed?: number — Seed for chances (default 1).

RankRules

interface RankRules

Gradius-style rank: a hidden difficulty that grows with survival, progress and power.

  • seconds: number — Rank per this many seconds alive.
  • perStage: number — Rank per stage cleared.
  • guns: Record<string, number> — Rank per weapon held, by gun id (main or secondary).
  • shield: number — Rank while the shield is up.
  • perOption: number — Rank per Option.
  • fullOptions: number — Extra rank with every Option.
  • divisor: number — The sum is divided by this.
  • cap: number — Rank ceiling.
  • fireRate: number — Enemy fire rate multiplier per rank point.
  • bulletSpeed: number — Enemy bullet speed multiplier per rank point.

RespawnRules

interface RespawnRules

What a lost life costs and where play resumes.

  • mode: "in-place" | "checkpoint" — in-place: the stage carries on; checkpoint: it rewinds to the last restart point.
  • deathSeconds: number — Seconds of the death sequence.
  • invulnerable: number — Invulnerable seconds after reappearing.
  • lose: Array<"speed" | "gun" | "secondary" | "options" | "shield" | "wingmen" | "meter"> — Loadout lost.

Satellite

interface Satellite

A satellite position for drawing and collision.

  • kind: "option" | "wing" — option or wing.
  • index: number — Index.
  • x: number — Centre.
  • y: number — Centre.

ScriptEntry

interface ScriptEntry

One line of a stage script. Exactly one trigger (at or time) and at least one action.

  • at?: number — Fires once the scroll distance reaches this.
  • time?: number — Or once this many seconds of the stage have been played.
  • delay?: number — Extra seconds after the trigger.
  • wave?: WaveDef — Enemies to start.
  • scroll?: number — New scroll speed (px/s); 0 holds the scroll.
  • checkpoint?: boolean — A restart point (checkpoint respawn).
  • label?: string — Presentation label (announced in an event).

ScrollAxis

type ScrollAxis = "vertical" | "horizontal"

Which way the world scrolls.

ShooterConfig

interface ShooterConfig

Complete scrolling-shooter definition; the presets build the arcade ones.

  • width: number — Screen width (model px).
  • height: number — Screen height (model px).
  • hz: number — Fixed steps per second.
  • seed?: number — Seed for chances, launch spreads and aim jitter.
  • axis: ScrollAxis — Scroll axis.
  • margin?: number — Off-screen margin before things are removed. Default 32.
  • player: PlayerDef — The ship.
  • guns: Record<string, GunDef> — Weapons by id.
  • kinds: EnemyKind[] — Enemy kinds.
  • items: ItemDef[] — Pickups.
  • paths: Record<string, PathData> — Named screen paths (path pack notation).
  • meter: MeterSlot[] | null — Power meter (Gradius) or null for direct pickups (1942).
  • options: OptionRules | null — Trailing Options, or null.
  • wingmen: WingmenRules | null — Side fighters, or null.
  • evade: EvadeRules | null — Evasive loop, or null.
  • respawn: RespawnRules — Lost-life rules.
  • extraLives: number[] — Extra-life thresholds; after the last, another every extraEvery (0 = none).
  • extraEvery: number — See extraLives.
  • stages: StageDef[] — Stages in order; after the last the list loops with loop + 1.
  • numbering: { /** Number of the first stage. */ first: number; /** Counting up or down. */ direction: "up" | "down"; } — Stage numbering: from first, counting up or down (1942 counts down from 32).
  • timing: { /** Seconds of the stage intro (take-off, START). */ intro: number; /** Seconds of the stage-clear tally (landing). */ clear: number; } — Seconds of the stage intro and the stage-clear tally.
  • tally: { table: { percent: number; bonus: number }[] } | null — Stage-end shoot-down bonus (1942), or null.
  • smartScores?: boolean — Smart bombs score what they destroy. Default true.
  • bulletsHitTerrain?: boolean — Enemy bullets stop at terrain. Default true.
  • difficulty: { /** Enemy fire rate multiplier. */ fireRate: LoopRamp; /** Enemy bullet speed multiplier. */ bulletSpeed: LoopRamp; /** Chance by loop (last repeats) that a \revenge` kind fires a bullet when destroyed. / revenge: number[]; /* A new loop strips the loadout (Gradius). */ stripOnLoop: boolean; }` — Difficulty.
  • rank: RankRules | null — Hidden rank, or null.
  • bonusWave: { every: number; fromStage: number; wave: WaveDef } | null — A bonus wave every every kills from stage fromStage (1942's Yashichi carrier), or null.

ShooterEnemy

interface ShooterEnemy

One enemy.

  • id: number — Unique id.
  • kind: string — Kind id.
  • wave: number — Wave track index, or -1.
  • wait: number — Seconds until it appears (members of a wave enter one by one).
  • x: number — Centre.
  • y: number — Centre.
  • vx: number — Velocity for line and leaving motions (screen px/s).
  • vy: number — See vx.
  • heading: number — Direction of travel (screen degrees).
  • aim: number — Angle to the player (screen degrees), for turrets.
  • hp: number — Hits left (kinds without parts).
  • age: number — Seconds since it appeared.
  • path: string — Path name for path motion.
  • mirror: boolean — Path mirrored.
  • ox: number — Path offset.
  • oy: number — Path offset.
  • dist: number — Distance flown along the path.
  • surface: "floor" | "ceiling" | "none" — Terrain surface a ground enemy rides.
  • mode: string — Motion phase: walk/stand, enter/hold/wait/move/leave, climb/dart, timeout.
  • modeTime: number — Seconds in the motion phase.
  • target: number — Walking direction or track target.
  • fireClock: number — Seconds to the next volley.
  • fired: number — Volleys fired.
  • spawnClock: number — Seconds to the next child.
  • spawned: number — Children launched.
  • parts: Record<string, number> — Part hits left, by part id.
  • drop: string | null — Drop on death (resolved).
  • tag: string — Presentation tag.
  • timeout: boolean — Boss self-destruct begun.
  • hitTime: number — Seconds since the last damaging hit (for a flash).
  • seen: boolean — Has been fully on screen.

ShooterEvent

type ShooterEvent = | { kind: "stage-start"; stage: number; label: number; name: string; loop: number } | { kind: "playing" } | { kind: "script"; label: string } | { kind: "ambient"; wave: string } | { kind: "checkpoint"; distance: number } | { kind: "player-fire"; gun: string; owner: string } | { kind: "secondary-fire"; gun: string } | { kind: "enemy-fire"; id: number; enemy: string; x: number; y: number } | { kind: "enemy-hit"; id: number; enemy: string; part: string | null; x: number; y: number } | { kind: "part-destroyed"; id: number; enemy: string; part: string; score: number; x: number; y: number } | { kind: "enemy-killed"; id: number; enemy: string; score: number; x: number; y: number; boss: boolean; by: "shot" | "smart" | "contact" } | { kind: "enemy-escaped"; id: number; enemy: string } | { kind: "boss-start"; id: number; enemy: string } | { kind: "boss-timeout"; id: number; enemy: string } | { kind: "wave-cleared"; wave: number; tag: string; x: number; y: number; drop: string | null } | { kind: "item-drop"; id: number; item: string; x: number; y: number } | { kind: "pickup"; item: string; applied: string; x: number; y: number; score: number } | { kind: "meter"; cursor: number } | { kind: "power-up"; label: string; effect: PowerEffect["kind"] } | { kind: "smart-bomb"; destroyed: number } | { kind: "evade"; left: number } | { kind: "shield-hit"; left: number } | { kind: "wingman-lost"; index: number; x: number; y: number } | { kind: "bomb-land"; x: number; y: number; radius: number } | { kind: "player-hit"; x: number; y: number; cause: "bullet" | "enemy" | "terrain" } | { kind: "player-ready" } | { kind: "rewind"; distance: number } | { kind: "extra-life"; lives: number } | { kind: "stage-clear"; stage: number; label: number; percent: number; bonus: number; evadeBonus: number } | { kind: "game-over" }

Ordered notifications for presentation; drain() them each frame.

ShooterInput

interface ShooterInput

One fixed step of player input.

  • x?: number — -1..1 across the screen.
  • y?: number — -1..1 down the screen.
  • to?: Vec | null — Screen point to steer toward at the ship's speed (pointer / touch drag); overrides x/y.
  • fire?: boolean — Fire held.
  • bomb?: boolean — Secondary weapon held (missile / bomb).
  • select?: boolean — Power-meter select held.
  • evade?: boolean — Evasive loop held.

ShooterItem

interface ShooterItem

A pickup on screen.

  • id: number — Unique id.
  • item: string — Item id.
  • x: number — Centre.
  • y: number — Centre.
  • age: number — Seconds since dropped.

ShooterPlayer

interface ShooterPlayer

The ship's state.

  • x: number — Centre x.
  • y: number — Centre y.
  • alive: boolean — In play (false during the death sequence).
  • deadTime: number — Seconds since it was destroyed.
  • invulnerable: number — Seconds of respawn invulnerability left.
  • evading: number — Seconds of the evasive loop left.
  • evades: number — Loop charges left.
  • fireHeld: boolean — Fire was held on the last step.
  • bombHeld: boolean — The secondary trigger was held on the last step.
  • selectHeld: boolean — Select was held on the last step.
  • evadeHeld: boolean — Evade was held on the last step.
  • fireClock: number — Seconds until the main gun may fire again.
  • bombClock: number — Seconds until the secondary may fire again.
  • heldTime: number — Seconds fire has been held since the last volley.
  • bombHeldTime: number — Seconds the secondary has been held since its last volley.
  • vx: number — Velocity this step (px/s), for leading aim.
  • vy: number — Velocity this step (px/s).

ShooterState

interface ShooterState

Serializable game state; read it through state.

  • time: number — Seconds since the game began.
  • status: ShooterStatus — Status.
  • statusTime: number — Seconds in the status.
  • stage: number — Stages begun, from 1.
  • stageIndex: number — Index of the stage definition.
  • loop: number — Completed loops through the stage list.
  • label: number — Displayed stage number.
  • cleared: number — Stages cleared.
  • distance: number — Scroll distance in this stage.
  • scroll: number — Current scroll speed.
  • stageTime: number — Seconds played in this stage.
  • alive: number — Seconds alive (rank).
  • score: number — Score.
  • lives: number — Ships, including the one in play.
  • extraAwarded: number — Extra ships awarded.
  • player: ShooterPlayer — The ship.
  • loadout: Loadout — Loadout.
  • meter: number — Power meter cursor (-1 = none lit).
  • drops: Record<string, number> — Drops per item id (for every).
  • trail: Vec[] — Ship positions for trailing Options, oldest first.
  • satellites: Satellite[] — Options and wingmen this step.
  • enemies: ShooterEnemy[] — Enemies.
  • shots: PlayerShot[] — Player shots.
  • bullets: EnemyShot[] — Enemy bullets.
  • pending: { enemy: number; port: number; angle: number; due: number; speed: number }[] — Pending pattern bullets: enemy, port, angle, due time.
  • items: ShooterItem[] — Pickups.
  • waves: { size: number; killed: number; escaped: number; drop: string | null; tag: string; x: number; y: number }[] — Waves of this stage: size, destroyed, escaped, drop, tag, last kill point.
  • fired: boolean[] — Script entries fired.
  • armed: number[] — Script entries triggered and waiting out their delay: stage time due, or -1.
  • checkpoint: { /** Scroll distance of the restart point. */ distance: number; /** Stage seconds at the restart point. */ time: number; /** Script entry that set it (-1: the stage start). */ entry: number; } — Last restart point.
  • appeared: number — Enemies that appeared / were destroyed this stage (shoot-down ratio).
  • downed: number — See appeared.
  • kills: number — Kills this game (bonus waves).
  • bonusSent: number — Bonus waves sent.
  • chain: Record<string, number> — Chain counts by kind.
  • ceasefire: number — Seconds of enemy ceasefire left.
  • bossDone: boolean — A boss ended the stage.
  • quiet: number — Seconds with no live target on screen.
  • ambient: number — Filler waves started this stage.
  • tally: { percent: number; bonus: number; evadeBonus: number; downed: number; appeared: number } | null — Last stage tally.
  • nextId: number — Next id.
  • random: number[] — Where the game's seeded stream stands: the four words of the kernel's rng.snapshot(), drawn from in place.

ShooterStatus

type ShooterStatus = "intro" | "playing" | "clear" | "game-over"

Game status.

ShotSpec

interface ShotSpec

One projectile of a gun volley.

  • f?: number — Muzzle offset ahead of the emitter. Default 0.
  • s?: number — Muzzle offset across (toward the floor side). Default 0.
  • angle?: number — Degrees from forward, positive toward the floor side. Default 0.
  • speed: number — Pixels per second.
  • w: number — Length along travel.
  • h: number — Thickness across travel.
  • damage?: number — Damage per hit. Default 1.
  • layers?: HitLayer[] — Layers it can hit. Default ['air'].
  • pierce?: boolean — Passes through what it hits (each target once). Default false.
  • motion?: "straight" | "hug" | "lob" — straight flies on; hug (Gradius missile) flies at angle until it meets the floor and then runs along it, bursting against a rise steeper than climb; lob (Xevious-style bomb) flies range pixels and lands, damaging ground targets within radius, hitting nothing in flight.
  • hugSpeed?: number — hug: speed along the floor (default speed).
  • climb?: number — hug: largest floor rise per pixel it can climb. Default 1.5.
  • range?: number — lob: distance flown before landing.
  • radius?: number — lob: blast radius on landing.
  • beam?: number — A beam (Gradius laser): while fire is held its tail stays at the muzzle and follows the ship across, growing to beam pixels; release or full length lets it go.
  • tag?: string — Presentation tag (sprite choice).

StageDef

interface StageDef

One stage.

  • name: string — Display name.
  • length: number — Distance after which the stage may end (once its script has run and no boss is alive).
  • scroll: number — Starting scroll speed (px/s).
  • terrain?: TerrainDef | null — Collidable terrain.
  • script: ScriptEntry[] — The script.
  • reward?: string — Item that drop: 'stage' waves leave (1942: each stage's POW type).
  • holdFire?: boolean — Only heavy enemies fire (1942 "% AND POINT UP" stages).
  • ambient?: AmbientRules | null — Dead-air guard: filler waves that keep the screen from staying empty, or null.

TerrainDef

interface TerrainDef

A terrain heightfield pair: x is world along distance, y the cross coordinate.

  • floor: Vec[] — The floor side (screen bottom for horizontal, screen right for vertical).
  • ceiling?: Vec[] | null — The ceiling side (screen top / screen left), or null.

Vec

interface Vec

Screen-space point or velocity.

  • x: number — Screen x.
  • y: number — Screen y.

WaveDef

interface WaveDef

One group of enemies started by a script entry.

  • kind: string — Enemy kind.
  • count?: number — Members. Default 1.
  • gap?: number — Seconds between members. Default 0.
  • path?: string — Path for path kinds (overrides the kind's).
  • mirror?: boolean | "player" — Mirror the path across the axis (true), or toward the side the player is on (player).
  • at?: Vec — Screen offset for the path, or the spawn point for other motions.
  • spacing?: Vec — Added per member.
  • surface?: "floor" | "ceiling" — Ground members snap to this terrain surface (default from the kind's motion).
  • drop?: string — Item the last member drops when every member is destroyed; stage = the stage's reward.
  • memberDrop?: string — Overrides the kind's own drop for every member.
  • tag?: string — Presentation tag (e.g. red).

WingmenRules

interface WingmenRules

1942 side fighters: escorts at fixed offsets that fire with the ship and can be shot away.

  • slots: Offset[] — Positions in the forward frame.
  • gun: string — Gun they fire.
  • w: number — Hit box.
  • h: number — Hit box.