The pack
jetCombat
function jetCombat(): Pack<{ jetCombat: typeof api }>
Install the jet combat API.
Helpers
afterBurnerIIPreset
function afterBurnerIIPreset(o: AfterBurnerOptions = {}): JetConfig
After Burner II (Sega 1987): 23 stages, the throttle (and afterburner), 100 missiles at most, refuelling +50.
afterBurnerIIStages
function afterBurnerIIStages(seed = 1987): JetStage[]
After Burner II's 23 stages: base landings on 5 and 13, canyon runs on 8 and 17, the carrier on 23.
afterBurnerPreset
function afterBurnerPreset(o: AfterBurnerOptions = {}): JetConfig
After Burner (Sega 1987): 18 stages, no throttle, 50 missiles at most, refuelling before stages 3, 7, 10, 13, 15 and 17.
afterBurnerStages
function afterBurnerStages(seed = 1987): JetStage[]
After Burner's 19 stages: 18 battles in the arcade's order (canyons on 6 and 12) and the carrier landing.
ahead
function ahead(at: number, kind: string, count: number, shape: JetShape = "line", x = 0, y = 0, extra: Partial<JetWave> = {}): JetWave
A flight from ahead in a formation; it fires as it closes and peels off before it reaches the jet.
chaser
function chaser(at: number, x = 2, extra: Partial<JetWave> = {}): JetWave
BE CAREFUL: a homing missile from behind.
createJetCombat
function createJetCombat(config: JetConfig): JetCombat
Create a jet combat game from a configuration.
formation
function formation(shape: JetShape, count: number, spacing = 8): FormationSlot[]
Offsets for count members of a named shape, spacing units apart, centred on the formation's origin.
fromBehind
function fromBehind(at: number, kind: string, count: number, x = 0, extra: Partial<JetWave> = {}): JetWave
A set of jets from behind that overtakes, pulls ahead and turns back at you.
gunships
function gunships(at: number, count: number, x = 0, extra: Partial<JetWave> = {}): JetWave
Gunships closing to hover in front and fire.
JET_STEP
const JET_STEP: number
Simulation step (seconds).
jetDifficulty
function jetDifficulty(d: JetDifficulty): JetTuning
Difficulty multipliers: Arcade is the original tables.
jetKinds
function jetKinds(points = 2000, towersBreak = false): Record<string, JetKind>
The After Burner object table: every aircraft and ground target is worth 2,000 (After Burner II: 10,000, estimated).
jetProjectiles
function jetProjectiles(): Record<string, JetProjectile>
Enemy projectiles: straight missiles, homing missiles that commit close in, and the tail gunner's tracer.
jetTerrains
function jetTerrains(): Record<string, JetTerrain>
Every terrain of both presets by name (sea, coast, village, rocky, plains, marsh, canyon, snow, forest, ...).
lagger
function lagger(at: number, x = 4, extra: Partial<JetWave> = {}): JetWave
THE ENEMY: a jet that slides onto the tail and fires its cannon.
mirrorJetPath
function mirrorJetPath(p: DepthPathSpec): DepthPathSpec
The mirrored copy of a path (x negated).
scouts
function scouts(at: number, count: number, x = 0, extra: Partial<JetWave> = {}): JetWave
Unarmed jets streaking past close in front.
validateJet
function validateJet(c: JetConfig): void
Check a configuration and throw a clear error for anything unsupported.
Classes
JetCombat
class JetCombat
An After Burner style jet combat game (see the pack docs).
readonly config: JetConfig— The configuration the game was created with; it is not changed.readonly camera: DepthCamera— The view: its pose (and roll pivot, the jet) is set every step; draw with it.readonly field: DepthField— Every object: the jet, rounds, missiles, enemies, enemy fire, scenery, ground targets, tanker and carrier.state: JetState— The whole game state (plain data);snapshot()copies it.constructor(config: JetConfig)get stageDef(): JetStage— The stage being played.get ground(): DepthSurface— The ground surface under the jet now (the stage's, or the leg it has reached).get look(): Record<string, string>— Presentation colours now (the stage's look, or the leg's).get legAhead(): { depth: number; ground: DepthSurface; look: Record<string, string> } | null— The next terrain leg ahead in this stage and the camera depth where it begins (draw bands beyond it with its ground), or null.get playerObject(): DepthObject— The jet's field object.kind(name: string): JetKind | undefined— A kind's definition (undefined for the jet, rounds, missiles, projectiles and decorative scenery).get mach(): number— Mach number shown on the speed gauge.get sight(): { x: number; y: number }— Where the gun sight is on the (rolled) screen.pointerStick(sx: number, sy: number): { x: number; y: number }— A flight stick from a pointer on the screen (the arcade's analog stick: deflection follows the pointer).start(stage = this.config.startStage ?? 0): void— Start a new game (fromstartStageunless given), with the carrier take-off when configured.tick(seconds: number, input: JetInput = {}): void— Advance bysecondsin whole 1/60 s steps (at most 10 per call).drain(): JetEvent[]— Notifications since the last drain.snapshot(): JetSnapshot— Plain copy of the game.restore(s: JetSnapshot): void— Restore a snapshot taken from a game with the same configuration.step(input: JetInput = {}): void— One fixed step.addScore(points: number): void— Add points (extra lives and the top score follow).
Types
AfterBurnerOptions
interface AfterBurnerOptions
Options shared by both presets.
difficulty?: JetDifficulty— Difficulty tuning: easy, normal or arcade (the original tables); default normal.lives?: number— Lives (After Burner: 3; After Burner II's DIP: 3 or 4).startStage?: number— First stage, 1-based (default 1).stages?: number[]— Keep only these stage numbers (1-based), in order (default all).seed?: number— Seed of the game's random stream and of the scenery layout; default 1987.extraLives?: number[]— Extra-life score thresholds (default none: no arcade source documents one).extraEvery?: number | null— Points between extra lives onceextraLivesis used up; with no thresholds the first comes at this score (null or absent: none).
FormationSlot
interface FormationSlot
One member's offset in a formation (x right, y up, z deeper).
x: number— Offset to the right in world units.y: number— Offset upward in world units.z: number— Offset deeper into the screen (along the course) in world units.
JetConfig
interface JetConfig
A full game.
seed: number— Seed of the game's random stream.lives: number— Lives at the start of a game, 1 to 99;tuning.livesis added.view: JetView— The camera: screen size, horizon and depths.flight: JetFlight— How the jet flies.gun: JetGun— The vulcan cannon.missiles: JetMissiles— The lock-on missiles.kinds: Record<string, JetKind>— Every kind of enemy, ground target, wall and tower, by id.projectiles: Record<string, JetProjectile>— Every enemy projectile, by id.paths: Record<string, DepthPathSpec>— Camera-frame depth paths forpathmotions; each also exists mirrored asid~m.stages: JetStage[]— The stages, in order.startStage?: number— Index of the first stage (default 0).takeoff: boolean— Take off from the carrier before the first stage of a new game.ending: "end" | "loop"— After the last stage:end(mission complete) orloop.scoring: JetScoring— Scoring and extra lives.timing: JetTiming— Timings of the sequences between play.tuning: JetTuning— Difficulty multipliers.
JetDifficulty
type JetDifficulty = "easy" | "normal" | "arcade"
Easy / Normal / Arcade (Arcade = the original tables).
JetEvent
type JetEvent = | { kind: "stage-start"; stage: number; number: number; name: string; type: JetStageType } | { kind: "takeoff" } | { kind: "refuel-start" } | { kind: "refuel"; added: number; missiles: number } | { kind: "wave"; index: number; enemy: string } | { kind: "warning"; threat: "gun" | "missile"; id: string } | { kind: "lock"; id: string } | { kind: "missile"; id: string; target: string | null } | { kind: "shot"; id: string } | { kind: "hit"; target: string; x: number; y: number; z: number } | { kind: "deflect"; target: string; x: number; y: number; z: number } | { kind: "destroyed"; id: string; target: string; points: number; x: number; y: number; z: number; by: "gun" | "missile" } | { kind: "enemy-fire"; id: string; projectile: string } | { kind: "roll"; dir: number } | { kind: "player-hit"; cause: string; wreck: "wing" | "direct" } | { kind: "respawn" } | { kind: "extra-life"; lives: number } | { kind: "stage-clear"; stage: number; name: string; hits: number; appeared: number; bonus: number } | { kind: "game-over"; score: number } | { kind: "complete"; score: number }
Notifications for presentation.
JetFire
interface JetFire
An enemy's firing schedule.
projectile: string— Id of the projectile it fires, a key ofJetConfig.projectiles.every: number— Seconds between volleys;firstbefore the first one (defaultevery).first?: number— Seconds before the first volley; defaultevery. Scaled byJetTuning.fireEvery.jitter?: number— Random extra delay up to this many seconds per volley.burst?: number— Projectiles per volley and the gap between them.burstGap?: number— Seconds between the projectiles of a burst; default 0.12.minDepth?: number— Fires only while its depth lies in [minDepth, maxDepth] (in front: positive; behind the jet: any).maxDepth?: number— Farthest depth at which it fires; default 0.55 ofJetView.far.minDepthdefaults to the jet's plane plus 18.
JetFlight
interface JetFlight
How the jet flies.
w: number— Jet box: wingspan, height, length (world units).h: number— Jet box height in world units.d: number— Jet box length along the course in world units.offsetX: number— How far the jet moves across the screen with the stick (world units at its depth).offsetY: [number, number]— How far the jet moves down / up the screen with the stick.approach: number— Speed of the jet toward its stick position on screen (units per second).maxBank: number— Bank at full stick (radians) and bank rate (radians per second).bankRate: number— How fast the bank follows the stick (radians per second).turn: number— Lateral (heading) speed at full bank, units per second: turning scrolls the world sideways.climb: number— Climb or dive speed at full stick (units per second).altitude: [number, number]— Altitude range [min, max] and the altitude at the start. The arcade jet cannot fly into the ground.startAltitude: number— Altitude (camera height, world units) at the start of a game and after a respawn, clamped to the stage's range.roll: { /** Seconds for one full turn; no steering meanwhile and it cannot be cancelled. */ time: number; /** Seconds allowed between the two stick deflections. */ window: number; /** Stick deflection that counts (0..1). */ threshold: number; /** Sideways drift during the roll (units per second). */ shift: number; }— The barrel roll: stick hard one way then quickly the other way (withinwindowseconds).speed: { cruise: number; min: number; max: number; rate: number; throttle: boolean; mach: number }— Forward speed (units per second).throttlefalse: fixed atcruise(After Burner); true: a lever between min and max (After Burner II).invulnerable: number— Seconds of invulnerability after a respawn.
JetGun
interface JetGun
The vulcan cannon: continuous fire toward the sight while held.
every: number— Seconds between rounds while held.speed: number— Round speed relative to the jet (units per second).range: number— Distance before a round fades.max: number— Most rounds in flight.size: number— Round box size.
JetInput
interface JetInput
Player input for one step.
x?: number— Flight stick -1..1 (x right, y UP: climb).y?: number— Climb stick, -1..1 with up (climb) positive.fire?: boolean— Vulcan trigger held.missile?: boolean— Missile button held (a missile launches on each press).throttle?: number— Throttle lever movement -1..1 (pull back .. push forward), when the flight has a throttle.throttleLevel?: number— Absolute throttle position 0..1; overridesthrottle.roll?: number— Start a barrel roll to the left (-1) or right (1) directly, as the stick gesture does.
JetKind
interface JetKind
Anything that is not the jet: enemy aircraft, ground targets, canyon walls, towers, the tanker.
w: number— Box width in world units.h: number— Box height in world units.d?: number— Box depth along the course in world units; default the smaller of width and height.anchor?: "base" | "centre"—base: positioned by its bottom (things on the ground).hp: number | null— Hits to destroy; null: indestructible (blocks rounds).points: number— Score for destroying it.lethal: boolean— Touching it destroys the jet (ramming fighters, canyon walls, towers).lockable?: boolean— Missiles can lock on to it (default: true when it has hp).counts?: boolean— Counts toward HIT and the stage's shot-down ratio (default: true when it has hp and points).fire?: JetFire— Its firing schedule; omitted: it never fires.family?: string— Free text for presentation (fighter, helicopter, ground, wall ...).
JetLock
interface JetLock
A target boxed by the lock-on sight.
id: string— Field object id of the locked target.left: number— Seconds before the lock lapses unless the sight stays on the target.
JetMissiles
interface JetMissiles
Lock-on homing missiles from a finite stock.
start: number— Stock at the start of a game and the most the jet can carry.max: number— Most missiles the jet can carry; refuelling never goes above it.every: number— Seconds between launches.drop: number— Seconds a missile drops under the fuselage before its motor ignites and it starts homing.speed: number— Speed relative to the jet once lit, and its turn rate (radians per second).turn: number— Turn rate of a lit missile toward its target (radians per second).life: number— Seconds before it burns out.size: number— Missile box width and height in world units; its depth is three times this.lock: { radius: number; minDepth: number; maxDepth: number; hold: number; max: number }— The lock: targets withinradiuspx of the sight and between the depths are boxed forholdseconds.
JetMotion
type JetMotion = /** From ahead toward the jet; below `breakAt` depth it peels off sideways (`breakX`) and up (`breakY`). */ | { type: "head-on"; from: number; speed: number; breakAt?: number; breakX?: number; breakY?: number } /** From behind the camera, passing the jet and pulling away ahead; past `turnAt` it turns back head-on. */ | { type: "overtake"; from: number; speed: number; turnAt?: number; turnSpeed?: number } /** Closes to `hold` depth, keeps pace there for `time` seconds, then leaves up and sideways (gunships). */ | { type: "hover"; from: number; speed: number; hold: number; time: number } /** Slides in behind the jet and keeps station there firing, held between absolute speeds `min` and `max`: speed up or slow down to shake or overshoot it (THE ENEMY). */ | { type: "lagger"; from: number; hold: number; min: number; max: number; time: number } /** A homing missile closing from behind at absolute speed `speed` (BE CAREFUL): outrun it with the throttle or out-turn it. */ | { type: "chase"; from: number; speed: number; turn: number; commit?: number } /** Crosses the view sideways at a depth. */ | { type: "cross"; depth: number; speed: number } /** An authored camera-frame depth path (a path id in `JetConfig.paths`; `~m` is its mirror). */ | { type: "path"; path: string; end?: "remove" | "hold" | "continue" } /** A target on the ground, fixed in the world (`from`: depth ahead where it appears). */ | { type: "ground"; from: number }
How a wave flies. Speeds are absolute air speeds (units per second), so the throttle changes how fast things close or overtake; positions are relative to the jet when the member spawns.
JetPlayerState
interface JetPlayerState
The jet.
ox: number— Offset from the camera's line (x right, y up).oy: number— Offset from the camera's line, up (world units at the jet's depth).bank: number— Bank (radians, positive right wing down) and the barrel roll's extra turn (0 .. +-2 pi).spin: number— The barrel roll's extra turn in radians, 0 to +-2 pi; 0 when not rolling.rollDir: number— Roll direction and seconds left; 0 when not rolling.rollLeft: number— Seconds of the roll left; 0 when not rolling.pitch: number— Pitch input smoothed (-1 dive .. 1 climb), for the horizon and the sprite.throttle: number— Throttle lever 0..1 and forward speed (units per second).speed: number— Forward speed in units per second.altitude: number— Altitude (camera height) and heading (camera x).heading: number— Heading in world x, which is also the camera's x; turning scrolls the world sideways.invulnerable: number— Seconds of invulnerability left; 0 when vulnerable.alive: boolean— Whether the jet is flying (false while it falls after a hit).dying: number— Seconds since it was hit; 0 while alive.wreck: "" | "wing" | "direct"— Death presentation: a wing hit burns a wing and the jet spins in; a direct hit explodes.lastHard: number— Stick history for the roll gesture: last hard deflection direction and its age.lastHardAge: number— Seconds since that deflection; large (99) when there has been none.
JetProjectile
interface JetProjectile
An enemy projectile.
w: number— Box width in world units.h: number— Box height in world units.speed: number— Speed relative to the camera (front shots) or absolute air speed (chase: from behind).homing?: number— Turn rate toward the jet (radians per second); 0 or absent: straight at where the jet was.commit?: number— Homing stops this far from the jet's plane, so a late dodge works (default 6).shootable?: boolean— The vulcan and missiles can shoot it down.points?: number— Score for shooting it down; used only whenshootable; default 0.life?: number— Seconds before it fizzles (default 5).
JetScoring
interface JetScoring
Scoring and lives.
flight: { points: number; per: number }— Points for distance flown:pointseveryperunits (After Burner II scores while you fly; 0: none).extraLives: number[]— Scores that award an extra life, in order, and an interval after them (null: none).extraEvery: number | null— Points between extra lives once theextraLiveslist is used up; with an empty list the first comes at this score (null: none).topScore: number— The top score at the start of a game.clearBonus: { perHit: number; ratio: number } | null— Optional stage-clear bonus (not in either arcade preset: no source documents one):perHitpoints per enemy shot down in the stage, andratiopoints times the share of the stage's counted enemies shot down.
JetShape
type JetShape = "single" | "line" | "column" | "vee" | "diagonal" | "arc" | "circle" | "box" | "x" | "stack" | "wedge"
Named formation shapes; members are spaced spacing units apart.
JetSnapshot
interface JetSnapshot
A snapshot of a running game.
state: JetState— The game state (plain data).field: DepthFieldSnapshot— The scaled-depth field's snapshot: every object in the world.
JetStage
interface JetStage
One stage.
name: string— Stage name, announced with thestage-startandstage-clearevents.type: JetStageType—combat: dogfight to the end oflength;canyon: the bonus stages between rock walls with ground targets;base: an automatic landing at an airbase that restocks missiles, then take-off (After Burner II stages 5 and 13);carrier: the automatic landing on the carrier that ends the mission.length: number— Distance flown to clear it (combat and canyon).terrain: string— Terrain name for presentation (sea, forest, desert, canyon, snow, night, town, castle ...).ground: DepthSurface— Ground surface drawn in this stage, until the first oflegsbegins (ascaled-depthsurface).look?: Record<string, string>— Presentation colours: sky0 (top), sky1 (horizon), haze; free strings.legs?: { from: number; terrain: string; ground: DepthSurface; look?: Record<string, string> }[]— The terrain changes within the stage: from stage distancefromthe ground (and look) become these. Before the first leg the stage's owngroundapplies (After Burner's first stage leaves the carrier over open sea).scenery?: Omit<SceneryOptions, "seed" | "name"> & { seed?: number }— Scenery streamed by distance (z from the stage start, x relative to the heading when it appears).waves: JetWave[]— Waves of the stage, in increasing order of theiratdistance.refuel?: { missiles: number | "full" }— Air-to-air refuelling before the stage starts: missiles added (orfull).altitude?: [number, number]— Altitude range override (canyon stages fly low between the walls).
JetStageType
type JetStageType = "combat" | "canyon" | "base" | "carrier"
What a stage is.
JetState
interface JetState
The whole game state (plain data).
status: JetStatus— Where the game is in its sequence.statusTime: number— Seconds spent in the current status.stage: number— Index of the stage being played, 0 based.stageNumber: number— Stage number shown (1-based, counting loops).loop: number— Times the stage list has looped (0 on the first run through).distance: number— Distance flown in this stage, in world units.camZ: number— World z of the camera.stageZ: number— Camera z where this stage's course (scenery) starts.time: number— Seconds since the game was created or started.score: number— Current score.topScore: number— Highest score seen, kept across games.lives: number— Lives left, counting the jet being flown: a loss costs one, and the game ends when none are left.nextExtra: number— Score at which the next extra life is awarded; Infinity when there are no more.extraIndex: number— How many entries ofJetScoring.extraLiveshave been awarded.missiles: number— Missiles left in stock.gunClock: number— Seconds until the vulcan can fire again.missileClock: number— Seconds until a missile can launch again.missileHeld: boolean— Whether the missile button was held on the last step; a launch needs a fresh press.flightClock: number— Distance flown since the last flight score was awarded, in world units.player: JetPlayerState— The jet.locks: JetLock[]— Targets boxed by the lock-on sight, in the order they were locked; each launch takes the first.hits: number— Enemies shot down this stage (HIT) and counted enemies that appeared this stage.appeared: number— Counted enemies that have appeared this stage: the base of the shot-down ratio.wavesFired: number— Waves of this stage triggered so far; also the index of the next one.pending: { at: number; wave: number; member: number; x: number; y: number }[]— Members of triggered waves still waiting to appear:atis the state time (seconds) they are due,wavethe wave index in the stage,memberthe member index, andx,ythe jet's world x and eye height when the wave was triggered.acc: number— Fixed-step accumulator (seconds).stats: { shots: number; missiles: number; kills: number; deaths: number }— Counts for the game: vulcan rounds, missile launches, enemies destroyed and jets lost.rng: number[]— The seeded random stream's state: four words, from the kernel'srng.snapshot(). It advances in place and is saved with the state.
JetStatus
type JetStatus = "attract" | "takeoff" | "refuel" | "playing" | "dying" | "base" | "carrier" | "over" | "complete"
Game status.
JetTerrain
interface JetTerrain
A terrain: the ground pattern, the scenery rows laid over it and the sky colours.
ground: DepthSurface— Ground pattern of the terrain (ascaled-depthsurface).look: Record<string, string>— Presentation colours of the sky and haze: sky0 (top), sky1 (horizon), haze.rows: SceneryRow[]— Scenery rows laid over the ground, each a set of decoration kinds placed across a range of x.spacing: number— Distance between scenery slots.
JetTiming
interface JetTiming
Sequence timings in seconds.
takeoff: number— Seconds of the carrier take-off sequence.refuel: number— Seconds of the air-to-air refuelling sequence.base: number— Seconds of the airbase landing, restock and take-off sequence.carrier: number— Seconds of the carrier landing sequence that ends the mission.dying: number— Seconds the wreck falls before the jet respawns or the game ends.
JetTuning
interface JetTuning
Difficulty multipliers (see jetDifficulty).
fireEvery: number— Enemy fire interval multiplier (bigger: less fire).projectileSpeed: number— Enemy projectile speed multiplier.homing: number— Enemy homing turn rate multiplier.hitbox: number— Jet hit box multiplier.lives: number— Extra lives at the start.
JetView
interface JetView
The camera: a Super Scaler view that rolls about the jet.
width: number— Screen width and height in pixels (the arcade's 320 x 224).height: number— Screen height in pixels.focal: number— Pixels per world unit at depth 1.horizon: number— Screen row of the horizon in level flight.pitch: number— Horizon shift in px at full climb (positive: the horizon drops as the nose rises).playerDepth: number— Depth of the jet's plane in front of the camera.drop: number— The jet sits this far below the eye (world units), so it is drawn under the horizon.viewRoll: number— Share of the bank the world rolls (1: the camera is bolted to the jet; 0: the jet banks on a level view).sightDepth: number— Depth of the gun sight in front of the jet.far: number— Farthest depth drawn; objects enter here.behind: number— Units behind the camera before objects are dropped.
JetWave
interface JetWave
A wave: count members of kind in a formation, triggered at a stage distance.
at: number— Stage distance at which it starts.kind: string— Id of the kind of every member, a key ofJetConfig.kinds.count: number— Members in the wave; a named shape holds 1 to 64.shape?: JetShape— A named shape or explicit offsets (x right, y up, z deeper), cycled.offsets?: { x?: number; y?: number; z?: number }[]— Explicit member positions relative to the formation centre; member i uses entry i modulo the length. Overridesshape.spacing?: number— Spacing for named shapes (default 8).x?: number— Formation centre relative to the jet (x right, y up).y?: number— Formation centre height relative to the jet's eye line, in world units; default 0.every?: number— Seconds between members appearing (default 0).mirror?: boolean— Mirror x (also negates break and cross directions).motion: JetMotion— How the members fly.


