The pack
trackRacer
function trackRacer(): Pack<{ trackRacer: typeof api }>
Install the track racer API.
Helpers
BADLANDS_LOOKS
const BADLANDS_LOOKS: CarLook[]
Badlands' cars: blue (left player), red (right player or a drone), green (always a drone).
BADLANDS_TRACKS
const BADLANDS_TRACKS: CircuitDef[]
The eight arenas in the manual's order: City, Desert, Freeway, Volcano, Junkyard, Military Base, Prison Yard, Refinery.
badlandsPreset
function badlandsPreset(o: BadlandsOptions = {}): TrackRacerDef
The Badlands game definition.
badlandsVehicle
function badlandsVehicle(): VehicleSpec
The Badlands car: vehicle-handling's badlandsCar, livelier off the line (the arenas are short: about 0 to 100
pixels a second in a second, as the champions' 7 to 12 second laps need), with a crash speed suited to the
arenas' tight walls and short, snappy jumps.
createTrackRacer
function createTrackRacer(def: TrackRacerDef, settings: Partial<RacerSettings> = {}): TrackRacer
Create a session from a definition and settings.
FIGURE_EIGHT
const FIGURE_EIGHT: CircuitDef
A figure-eight with one bridge, to show the layer model: the diagonal from top-left to bottom-right is a deck (level 1) joined to the ground at its two ends (the transition zones); the other diagonal passes under it. Not a Super Sprint track; a demonstration level in the same style.
pointInPolygon
function pointInPolygon(pts: ReadonlyArray<Pt>, x: number, y: number): boolean
Point in polygon (even-odd).
SUPER_SPRINT_LOOKS
const SUPER_SPRINT_LOOKS: CarLook[]
Super Sprint's car slots: blue (left wheel), red (centre), yellow (right), green (always a drone).
SUPER_SPRINT_TRACKS
const SUPER_SPRINT_TRACKS: CircuitDef[]
The eight circuits in track-number order (track 1 first).
superSprintPreset
function superSprintPreset(o: SuperSprintOptions = {}): TrackRacerDef
The Super Sprint game definition.
superSprintVehicle
function superSprintVehicle(): VehicleSpec
The Super Sprint car: vehicle-handling's superSprintCar re-paced to the lap times in the Winner's Circle
captures (a 6.8 s average and 5.9 s best lap on track 1, about 1,400 pixels a lap): the arcade cars cross the
512-pixel screen in under two seconds, so top speed, acceleration and grip are raised together; the handling
shape (rotate with momentum, understeer, slides) is the pack's. The wheel also turns a car that is standing
still (pinned nose-first against a wall it would otherwise never get free), and turns the same way when a wall
bounce rolls the car backwards (there is no reverse gear to steer).
Functions
badlandsUpgrades
function badlandsUpgrades(cost = 1): UpgradeDef[]
The shop: the manual's five custom car options.
chooseNext
function chooseNext(c: Circuit, road: number, open: (road: number) => boolean, rand: () => number, skill: DroneSkill): number | null
Choose the next road at the end of road.
droneDrive
function droneDrive(v: DroneView): { steer: number; gas: number; fire: boolean }
One step of a drone's controls.
newDriverMemory
function newDriverMemory(road: number, phase: number): DriverMemory
A fresh memory for a drone on road.
superSprintUpgrades
function superSprintUpgrades(levels = 5): UpgradeDef[]
The upgrade screen: CHOOSE AN ITEM FOR YOUR CAR.
updateRoute
function updateRoute(c: Circuit, mem: DriverMemory, road: number, d: number, ahead: number, open: (road: number) => boolean, rand: () => number, skill: DroneSkill): void
Keep the route starting at the car's road and at least ahead long past it.
Classes
Circuit
class Circuit
A baked circuit. Build it once per track; it is immutable apart from gate and block state, which the race owns and passes in.
readonly def: CircuitDef— The definition the circuit was baked from.readonly track: Track— Thetracknetwork the roads were baked from.readonly roads: Road[]— The baked roads, in the order ofdef.edges.readonly lapLength: number— Length of the main lap.readonly mainLap: number[]— Road indices of the main lap in order, starting at the line.readonly toFinish: Map<string, number>— Distance from each node to the line along the main lap.readonly levels: number[]— Levels in use, ascending.constructor(def: CircuitDef)remaining(road: number, d: number): number— Distance left to the line from distancedalong roadroad(main-lap metric; a shortcut drops it).project(road: number, x: number, y: number): Projection— The nearest point of one road.pointAt(road: number, d: number, lat = 0): { x: number; y: number; heading: number; hw: number }— Centre-line point, heading and half width at distancedalong a road, offsetlatto the right.candidates(road: number, x?: number, y?: number): number[]— Roads a car onroadat(x, y)is tested against: every road of its own level, plus a road of another level only inside the transition zone where the two meet. A car under a bridge never meets the deck, and a car on the deck never meets the road below, wherever they overlap on screen.inJoint(road: number, to: number, x: number, y: number): boolean— Is(x, y)inside a transition zone ofroadleading to roadto?transitions(): Array<{ x: number; y: number; r: number; from: number; to: number }>— Every transition zone (for debugging overlays): centre, radius and the two levels.decks(): Array<{ level: number; points: Array<{ x: number; y: number }> }>— The outlines of every road on a level above the ground (bridge decks and their ramps), for occlusion.locate(road: number, x: number, y: number): Projection— Track a point that was onroadlast step: the road it is on now (staying put through junction overlaps, moving to the next road past a node, or to any road of its level when it has left its own: a cut across).inside(x: number, y: number, r: number, among: number[], level?: number): boolean— Is the point inside the drivable union of roadsamongwith a marginr?wallHit(road: number, x: number, y: number, rad: number, gates: ReadonlyMap<string, boolean>, liveBlocks: ReadonlyArray<BlockDef>): WallHit | null— Wall contact for a circle of radiusradat(x, y)on roadroad: the union edge, closed gates and solid blocks of its level.gatesmaps gate ids to open state;blockslists the live blocks.grid(count: number): Array<{ x: number; y: number; heading: number; road: number }>— The default or authored grid slots, front first.line(): { x: number; y: number; heading: number; hw: number }— The start/finish line: centre, heading of travel and half width.turnAhead(route: number[], d: number, dist: number): number— Signed heading change over the nextdistunits of a route starting atdonroad(curvature probe).routePoint(route: number[], d: number, lat: number): { x: number; y: number; heading: number; hw: number; road: number }— A pointdalong a route of roads (the first road starting at 0), offsetlatto the right.ribbon(road: number, caps = true): Array<{ x: number; y: number }>— Drawable outline of one road's ribbon (left side out, right side back), for filling;caps: falsesquares the ends.walls(): WallLine[]— The union boundary of each level as wall polylines (each point carries the unit normal toward the road).randomSpot(rand: () => number, margin: number): { x: number; y: number; road: number }— A random point on the main lap at leastmarginfrom the walls, usingrand()in [0, 1).
TrackRacer
class TrackRacer
A session of a track-racer game. Create with createTrackRacer.
readonly def: TrackRacerDef— The game definition the session was made from.readonly settings: RacerSettings— The settings in force: difficulty, seed and any drone or hazard override.readonly circuits: Circuit[]— Baked circuits, by index indef.circuits.state!: RacerState— Everything the presenter reads; plain JSON, replaced byrestore.constructor(def: TrackRacerDef, settings: Partial<RacerSettings> = {})reset(): void— Back to attract mode with a demo race on the first circuit.get circuit(): Circuit— The circuit being raced.vehicle(car: number): Readonly<VehicleState>— A car's full vehicle state.spec(car: number): VehicleSpec— A car's scaled vehicle spec (after upgrades).operator(): { drones: OperatorLevel; hazards: OperatorLevel }— The operator settings in force.standings(): RacerCar[]— Cars by race position, leader first.gateOpen(id: string): boolean— Gate open?roadOpen(road: number): boolean— Is a road passable now: its gate (if any) open and no destructible block still standing across it?liveBlocks(): BlockDef[]— Blocks currently solid (authored blocks still standing plus temporary debris).patches(): PatchDef[]— Surface patches currently on the track (authored, spills and patch hazards), topmost last.droneSkill(): DroneSkill— The effective skill of a drone this heat.drain(): RacerEvent[]— Events since the last drain.join(seat: number): void— Start a game forseat(from attract), or join one in progress at the next race.newGame(seats: number[]): void— Begin a new game for the given seats.step(input: RacerInput | ReadonlyArray<RacerInput> = {}): void— Advance one fixed step with each seat's controls (a single input drives seat 0).upgradeCost(seat: number, id: string): number | null— Cost of the next level of an upgrade, or null when it is maxed.buy(seat: number, id: string): boolean— Buy the next level of an upgrade for a seat (the shop's confirm).qualified(seat: number): boolean— Did this seat qualify in the last race?snapshot(): RacerSnapshot— Plain JSON of the whole session.restore(snap: RacerSnapshot): void— Restore a snapshot taken from a session with the same definition.
Constants
BADLANDS_DIFFICULTY
const BADLANDS_DIFFICULTY: Record<RacerDifficulty, { drones: OperatorLevel; hazards: OperatorLevel; assist: RacerDifficulty; catchUp: number }>
Easy / Normal / Arcade for Badlands. Arcade is the manual's recommended Moderate.
BADLANDS_DRONES
const BADLANDS_DRONES: Record<OperatorLevel, DroneSkill>
Drone skill per the operator's Difficulty Level (Easy / Moderate / Hard / Hardest), estimates.
BADLANDS_SURFACES
const BADLANDS_SURFACES: Record<string, SurfaceSpec>
Lava (the Volcano): slows hard and spins a car that drives in fast.
SUPER_SPRINT_DIFFICULTY
const SUPER_SPRINT_DIFFICULTY: Record<RacerDifficulty, { drones: OperatorLevel; hazards: OperatorLevel; assist: RacerDifficulty; catchUp: number }>
What Easy, Normal and Arcade mean for Super Sprint. Arcade is the operator's recommended Medium / Medium.
SUPER_SPRINT_DRONES
const SUPER_SPRINT_DRONES: Record<OperatorLevel, DroneSkill>
Drone skill per operator Drone Difficulty switch (estimates; the manual names the four settings only).
Types
AreaDef
interface AreaDef
Extra drivable surface: a polygon joined to the roads of its level (a wide apron, a sweep round an island).
points: ReadonlyArray<Pt>— Outline, any winding.level?: number— Level (default 0).surface?: string— Surface id (defaulttarmac).
BadlandsOptions
interface BadlandsOptions
Options for badlandsPreset.
laps?: number— Laps per race (manual: four).cars?: number— Cars per race (three).seats?: number— Player seats (two wheels).circuits?: CircuitDef[]— Circuits and their order (default the eight arenas in the manual's order).order?: number[]— The circuit cycle, as indices intocircuits; the race goes through them in turn.missiles?: number— Missiles each player starts a game with (estimate).wrenchesPerItem?: number— Wrenches per shop item (estimate; the manual gives no prices).dronesFire?: boolean— Drones fire their cannons.vehicle?: VehicleSpec— The car, in metres.
BlockDef
interface BlockDef
A solid obstacle: a convex or concave polygon on one level.
id?: string— Optional id (a destructible block is addressed by it).points: ReadonlyArray<Pt>— Outline, any winding.level?: number— Level (default 0).hp?: number— Hit points if weapons can destroy it (Badlands walls opened by missiles); omit for indestructible.score?: number— Score when destroyed.
CarLook
interface CarLook
A car slot: its colour and the name the HUD shows.
id: string— Stable id (blue,red,yellow,green).color: string— CSS colour for the presenter.name: string— HUD name for a human driver ("BLUE CAR").
CarVehicle
type CarVehicle = Readonly<VehicleState>
Read-only handle on a car's vehicle state, for presenters that want more than the copied fields.
CircuitDef
interface CircuitDef
A circuit definition: plain data, any number of roads, levels and gates.
id: string— Unique id.name: string— Display name.size: { w: number; h: number }— World size (one screen).width: number— Default full road width.nodes: Record<string, Pt>— Named node positions.edges: CircuitEdgeDef[]— Roads, directed in the racing direction.finish: string— The node the start/finish line sits on.grid?: ReadonlyArray<{ x: number; y: number; heading: number }>— Explicit grid slots (front first); default: two by two behind the line.gridSpacing?: readonly [number, number]— Spacing of the default grid:[along, across]in world units.checkpoints?: number— Scoring checkpoints per lap (default 14, the Sprint games' count).areas?: AreaDef[]— Extra drivable aprons.blocks?: BlockDef[]— Solid obstacles.gates?: GateDef[]— Gates.patches?: PatchDef[]— Fixed surface patches.par?: { average: number; best: number }— Par lap times in seconds for the lap bonuses: 100 points per second under par (Winner's Circle).difficulty?: string— Difficulty label shown on the select screen (EASY, MEDIUM, HARD, VERY HARD).startWrenches?: number— Bonus wrenches for starting a game here.spots?: ReadonlyArray<Pt>— Candidate hazard and pickup positions; default: anywhere along the main lap.props?: PropDef[]— Shootable targets, turrets and wrecks (armed games).timed?: TimedEvent[]— Scenery events on timers.data?: Record<string, unknown>— Free data for the presenter (theme, colours, scenery).
CircuitEdgeDef
interface CircuitEdgeDef
One road of a circuit, directed in the racing direction.
from: string— Node the road leaves.to: string— Node the road arrives at.via?: PathSegmentData[]— Curve geometry in thepathnotation, continuing fromfrom; omit for a straight road.width?: number | readonly [number, number]— Full road width, constant or[at from, at to](default: the circuit'swidth).level?: number— Level: 0 is the ground, higher is a bridge over it (default 0).kind?: "road" | "ramp" | "gap"—road(default);ramplaunches a car that crosses it fast enough;gapis open air: a car on it that is not airborne falls.surface?: string— Surface id under the whole road (defaulttarmac).shortcut?: boolean— A shortcut: not part of the main lap; progress is measured along the main lap it rejoins.gate?: string— Gate id that closes this road's mouth (the AI only takes the road while it is open).blockedBy?: string— Id of a destructible block that stands across this road until it is destroyed (a wall to blow open).weight?: number— Preference at a branch for computer drivers (default 1).
Debris
interface Debris
A temporary solid block from an effect (a rock fall, a fallen power line).
id: number— Unique among the session's wrenches, hazards, shots and spills.block: BlockDef— The block the effect laid.t: number— Seconds since it appeared.life: number— Seconds it lasts.
DriverMemory
interface DriverMemory
A drone's memory between steps (plain JSON, part of the session snapshot).
route: number[]— Roads ahead, the first being the one it is on.lane: number— Current lane, fraction of the half width (+ right).passCar: number— Car being passed and the side chosen, untilpassTruns out.passSide: number— The side chosen to pass on: -1 left, 1 right.passT: number— Seconds of passing left before it settles back into its lane.avoidId: number— Hazard being avoided and the side chosen.avoidSide: number— The side chosen to steer round it on: -1 left, 1 right, 0 to drive straight on.mark: number— Progress mark and time without progress; recovery time left.stuck: number— Seconds without progress; past 1.2 it starts a recovery.recover: number— Seconds of recovery manoeuvre left.phase: number— Phase of its line wobble.lifting: boolean— Gas latch (hysteresis).bias: number— This driver's own preferred lane offset (so a field spreads out).
DroneSkill
interface DroneSkill
How well a computer driver drives. Every field is a plain number so tables can be authored and scaled.
pace: number— Fraction of the car's top speed it allows itself (0..1+).corner: number— Fraction of the grip-limited corner speed it carries into a bend (0.6 timid .. 1.1 over-driving).look: number— Look-ahead, seconds of travel (plus a fixed distance).gain: number— Steering gain.wobble: number— Weaving error of its line, fraction of the half width.overtake: number— Tendency to pull out and pass a car ahead, 0..1.shortcut: number— Chance of taking an open shortcut, 0..1.avoid: number— Chance of steering round a hazard it sees, 0..1.fire: number— Chance per second of firing the cannon at a car in its sights (armed games).
DroneView
interface DroneView
What a drone sees when it decides.
circuit: Circuit— The circuit being raced.car: RacerCar— The drone's car.state: Readonly<VehicleState>— Its vehicle's state.spec: VehicleSpec— The drone's own (scaled) spec.skill: DroneSkill— Its skill this heat.mem: DriverMemory— Its memory between steps; the decision updates it in place.cars: ReadonlyArray<RacerCar>— Every car in the race, its own included.hazards: ReadonlyArray<Hazard>— The hazards on the track.open: (road: number) => boolean— Is a road passable now (its gate open, no wall standing across it)?rand: () => number— The session's seeded random source: a number from 0 up to but not including 1.dt: number— Seconds of this step.pace: number— Throttle-cap multiplier from the rubber band (1 = none).armed: boolean— The drone's car carries a cannon.
GateDef
interface GateDef
A gate across a road: a wall segment that opens and closes on its own timer.
id: string— Id, referenced byCircuitEdgeDef.gate.a: Pt— End points of the closed gate.b: Pt— The other end of the closed gate.level?: number— Level (default 0).open?: boolean— Starts open (default false).openTime: readonly [number, number]— Seconds open,[min, max]chosen at random each time.closedTime: readonly [number, number]— Seconds closed,[min, max].
Hazard
interface Hazard
A hazard on the track.
id: number— Unique among the session's wrenches, hazards, shots and spills; events refer to it.kind: string— The id of itsHazardKind.x: number— World x of its centre.y: number— World y of its centre.r: number— Radius, world units.level: number— The level it is on.vx: number— Velocity x, world units a second (roamers; 0 for the others).vy: number— Velocity y, world units a second (roamers; 0 for the others).t: number— Seconds since it appeared.life: number— Seconds it lasts before it leaves; Infinity for a patch laid for the whole race.tx: number— World x of the spot a roamer is heading for.ty: number— World y of the spot a roamer is heading for.
HazardKind
interface HazardKind
A hazard kind laid on the track at the start of a race (oil, water) or roaming (tornado).
id: string— Id (oil,water,tornado,mud,mine...).kind: "patch" | "roamer" | "mine"—patch: lies where it is put;roamer: wanders over the track;mine: explodes under a car.radius: number— Radius in world units.surface?: string— Surface a car on it drives on (patches).spins?: boolean— Spins a car that touches it (tornado, mud).speed?: number— Roamer speed, world units per second.life?: number— Roamer life before it leaves, seconds.weight?: number— Relative chance when a hazard is placed.from?: Partial<Record<OperatorLevel, number>>— First heat (0-based count of heats raced) it may appear in, per hazard setting.
OperatorLevel
type OperatorLevel = "easy" | "medium" | "medium-hard" | "hard"
The operator's four-step settings (Super Sprint's drone and track-hazard switches).
PatchDef
interface PatchDef
A fixed patch of another surface (a puddle painted on the track, a sand trap).
at: Pt— Centre.rx: number— Radii (an ellipse);rydefaults torx.ry?: number— Vertical radius, world units. Defaultrx.surface: string— Surface id.level?: number— Level (default 0).
Projection
interface Projection
The nearest point of a road to a query point.
road: number— Index of the road incircuit.roads.d: number— Distance along the road.dist: number— Distance from the centre line.lat: number— Signed lateral offset, positive to the right of the direction of travel.hw: number— Half width there.x: number— The centre-line point.y: number— World y of the centre-line point.heading: number— Road heading there.
PropDef
interface PropDef
A shootable or timed piece of scenery that changes the track (Badlands' animated backgrounds).
id: string— Id.at: Pt— Position.r: number— Hit radius.hp?: number— Hits to destroy (cannon 1, missilemissileDamage); omit for an indestructible turret.score?: number— Score when destroyed.missiles?: number— Missiles awarded to the destroyer.effect?: PropEffect— What happens when it is destroyed.fire?: { every: number; speed: number; range: number; life?: number }— A turret: fires at the nearest car in range.respawn?: number— Respawn after this many seconds (targets that come back each lap).touch?: "explode" | "solid"— Explodes when a car drives into it (Junkyard wrecks); the car spins out.level?: number— Level (default 0).look?: string— Free data for the presenter (sprite, colour).
PropEffect
interface PropEffect
A change to the track: a spill, a fallen obstacle, a wall knocked down, a blast.
patch?: PatchDef & { life?: number }— A surface patch appears forlifeseconds (water from a tower, an oil spill, lava).block?: BlockDef & { life?: number }— A solid block appears forlifeseconds (rock fall, a fallen power line).remove?: string— A block is removed (a wall blown open to make a shortcut).blast?: { at?: Pt; radius: number }— A blast that spins every car withinradius.
PropState
interface PropState
A prop's live state.
id: string— The id of thePropDefit belongs to.hp: number— Hit points left; Infinity for a prop that cannot be destroyed.alive: boolean— False once destroyed, until it respawns (if it does).t: number— Seconds since it was destroyed, counting towards its respawn.cool: number— Seconds until a turret fires again.
Pt
type Pt = readonly [number, number]
[x, y] in world units.
RacerCar
interface RacerCar
A car in the race.
id: number— Slot index.look: string— Look id and colour.color: string— CSS colour of the car, from its look.seat: number | null— Human seat, or null for a drone.x: number— Pose and handling (copied from the vehicle every step).y: number— World y, in world units.heading: number— Direction it faces, radians; 0 faces along +x.speed: number— Speed, world units a second.skid: number— Skid intensity, 0 (gripping) to 1 (full skid).spinning: boolean— True during a spin-out.airborne: boolean— True while it is in a jump.z: number— Height above the track in a jump, world units; 0 on the ground.road: number— Road, distance along it, signed lateral offset, level.d: number— Distance travelled along that road, world units.lat: number— Signed lateral offset from the road's centre line, world units; positive to the right of the direction of travel.level: number— The level it is on: 0 the ground, higher a bridge deck.r: number— Distance left to the line on this lap, race progress (laps x lap length + distance done).progress: number— Race progress, world units: laps completed times the lap length plus the distance done on this lap; negative on the grid.lap: number— Lap number in progress (0 on the grid behind the line), next checkpoint, best checkpoint count reached.next: number— The checkpoint it must pass next on this lap, counting from 0.reached: number— The highest checkpoint reached, counted across laps:(lap - 1) x checkpoints + checkpoint.lapStart: number— Race time this lap began, lap times, best lap.laps: number[]— Times of its completed laps, seconds, in order.best: number | null— Its fastest lap, seconds; null before it has completed one.finished: boolean— Finished, finishing place (1-based) and time.place: number— Finishing place, 1 for first; 0 until it has finished.finishTime: number— Race time at which it finished, seconds; 0 until it has.position: number— Live race position (1-based).score: number— Totals across the game.wrenches: number— Wrenches it holds, to spend in the shop.upgrades: Record<string, number>— Levels bought, by upgrade id.status: "grid" | "racing" | "exploding" | "airlift" | "finished"—grid,racing,exploding,airlift,finished.t: number— Seconds in the current status.missiles: number— Armament.shields: number— Shield charges held.shieldTime: number— Seconds of protection left from a shield charge that has been used.cooldown: number— Seconds until the cannon can fire again.heli: { x: number; y: number; fromX: number; fromY: number; toX: number; toY: number; heading: number; phase: "in" | "hover" | "out"; t: number; carried: boolean } | null— The rescue helicopter while it is out for this car.
RacerDifficulty
type RacerDifficulty = "easy" | "normal" | "arcade"
The three difficulty presets every rules pack exposes. Arcade is the original operator defaults.
RacerEvent
type RacerEvent = | { type: "phase"; phase: RacerPhase } | { type: "green" } | { type: "white-flag" } | { type: "checkpoint"; car: number; points: number } | { type: "lap"; car: number; lap: number; time: number } | { type: "finish"; car: number; place: number } | { type: "wrench-spawn"; id: number; x: number; y: number } | { type: "wrench"; car: number; id: number } | { type: "wrench-gone"; id: number } | { type: "skid"; car: number } | { type: "spin"; car: number } | { type: "bump"; a: number; b: number; speed: number } | { type: "wall"; car: number; kind: string; speed: number } | { type: "crash"; car: number; cause: "wall" | "fall" | "missile" | "blast"; x: number; y: number } | { type: "helicopter"; car: number; phase: "in" | "drop" | "out" } | { type: "respawn"; car: number } | { type: "jump"; car: number } | { type: "land"; car: number } | { type: "gate"; id: string; open: boolean } | { type: "hazard"; id: number; kind: string; x: number; y: number } | { type: "hazard-hit"; car: number; kind: string } | { type: "fire"; car: number; kind: "shell" | "missile" | "turret" } | { type: "hit"; car: number; by: number; kind: "shell" | "missile" | "turret"; x: number; y: number } | { type: "shield"; car: number } | { type: "shot-hit"; kind: "shell" | "missile" | "turret"; x: number; y: number; what: "wall" | "block" | "prop" } | { type: "prop"; id: string; x: number; y: number; by: number } | { type: "effect"; x: number; y: number; what: "patch" | "block" | "remove" | "blast" } | { type: "event-warning"; index: number } | { type: "upgrade"; seat: number; item: string; level: number } | { type: "join"; seat: number } | { type: "continue"; seat: number } | { type: "out"; seat: number } | { type: "results" } | { type: "game-over" }
Events for sound and effects, drained by the presenter.
RacerInput
interface RacerInput
One seat's controls for one step. Steering is -1..1 (left, right); gas 0..1 or a boolean.
steer?: number— Steering from -1 (full left) to 1 (full right); values outside are clamped. Default 0.gas?: number | boolean— The gas pedal: true, or a number above 0.5, is on; anything else is off. The car is either off the gas or on it.fire?: boolean— Fires the cannon while held (armed games). Default false.missile?: boolean— Fires a missile on each press (armed games). Default false.start?: boolean— The START button: on a press it starts a game from attract or game over, joins a seat, or keeps a beaten player in. Default false.
RacerPhase
type RacerPhase = "attract" | "select" | "grid" | "race" | "results" | "shop" | "continue" | "over"
Session phase.
RacerSettings
interface RacerSettings
Settings chosen for a game (the operator switches and the gallery panel).
difficulty: RacerDifficulty— Easy, normal or arcade: picks the drone and hazard settings, the handling assist and the rubber band fromTrackRacerDef.difficulties. The session defaults to normal.drones?: OperatorLevel— Override the drone setting the difficulty implies.hazards?: OperatorLevel— Override the hazard setting the difficulty implies.seed: number— Seed.
RacerSnapshot
interface RacerSnapshot
A plain-JSON snapshot of a session. rng is where the session's seeded stream stands (a kernel Rng snapshot).
state: RacerState— The session state.vehicles: VehicleSnapshot[]— Each car's vehicle, by car id.rng: RngState— The state of the session's random stream.
RacerState
interface RacerState
The whole session state (plain JSON).
phase: RacerPhase— Where the session is: attract, circuit select, grid, race, results, shop, continue or game over.t: number— Seconds in this phase.raceTime: number— Seconds since the green flag.slot: number— Index intoorderof the circuit being raced, the circuit index, heats raced so far (the level).circuit: number— Index intoTrackRacerDef.circuitsof the circuit being raced.heat: number— Heats raced so far in this game; raises the drones' skill and the hazards.seats: boolean[]— Human seats in the game, and seats waiting for the next race (PLEASE STAND BY).waiting: boolean[]— Per seat: true while it waits out the race in progress for the next one (PLEASE STAND BY).cursor: number— Select screen cursor (index intoorder).cars: RacerCar[]— Cars of the current race.keep: Array<{ score: number; wrenches: number; upgrades: Record<string, number>; missiles: number; shields: number } | null>— Totals kept for seats between races (score, wrenches, upgrades, missiles, shields).droneScores: number[]— Drone scores carried between races by slot (the drones keep scores too).wrenches: Wrench[]— Wrenches lying on the track.hazards: Hazard[]— Hazards on the track.shots: Shot[]— Shells, missiles and turret shots in flight.gates: Array<{ id: string; open: boolean; t: number }>— Each gate of the circuit: its id, whether it is open, and the seconds until it changes.blocks: Array<{ id: string; hp: number }>— Live block ids (destructible blocks not yet destroyed), with hit points.props: PropState[]— The live state of each prop of the circuit.spills: Spill[]— Temporary surface patches laid by effects.debris: Debris[]— Temporary blocks laid by effects.nextWrench: number— Timers: next wrench, next roamer, timed events.nextRoam: number— Seconds until the next roaming hazard may appear.nextEvent: number[]— Seconds until each of the circuit's timed events happens, by index intimed.results: Array<{ car: number; place: number; placeBonus: number; average: number | null; averageBonus: number; best: number | null; bestBonus: number }>— Winner's circle order (car ids, first first) and bonus lines.shop: Array<{ cursor: number; done: boolean } | null>— Shop cursors per seat (index intoupgrades), done flags.continueFor: Array<number | null>— Continue countdown per seat (null when not offered).leaderLap: number— Leading lap, for the white flag.message: string— A banner the presenter shows ("GO", "WHITE FLAG", "PLEASE STAND BY" ...).nextId: number— Next id for wrenches, hazards, shots and spills.bestEver: number | null— Best lap ever (this session).drivers: Array<DriverMemory | null>— Drone memories by car id (null for human cars).held: Array<{ steer: number; gas: boolean; fire: boolean; missile: boolean; start: boolean }>— Last step's controls per seat, for presses.touching: number[]— Per car: the hazard id it is touching (to report a hit once).finishClock: number | null— Time since the first car finished (null before).demo: boolean— The attract race is running (title screen demo).
Road
interface Road
A road after baking: samples every few units with distance, half width and heading.
index: number— Index incircuit.roads.def: CircuitEdgeDef— The edge definition it was baked from.from: string— Node the road leaves.to: string— Node the road arrives at.level: number— Level: 0 the ground, higher a bridge deck.kind: "road" | "ramp" | "gap"—road, arampthat launches a fast car, or agapof open air.surface: string— Surface id under the whole road.shortcut: boolean— True for a shortcut: not part of the main lap.gate: string | null— Id of the gate that closes its mouth, or null.blockedBy: string | null— Destructible block across this road, or null.weight: number— Preference at a branch for computer drivers.length: number— Length of the road along its curve, world units.xs: Float64Array— World x of each sample along the centre line.ys: Float64Array— World y of each sample along the centre line.ds: Float64Array— Cumulative distance at each sample.hw: Float64Array— Half width at each sample.next: number[]— Indices of roads leavingto.prev: number[]— Indices of roads arriving atfrom.touching: number[]— Roads sharing a node with this one.joints: Array<{ road: number; x: number; y: number; r: number }>— Transition zones: roads of ANOTHER level sharing a node with this one, and the zone round that node.rEnd: number— Distance from the end of this road to the line along the main lap.
Shot
interface Shot
A cannon shell or missile (or a turret shot: owner -1).
id: number— Unique among the session's wrenches, hazards, shots and spills.kind: "shell" | "missile" | "turret"— A cannonshell, amissileor aturretshot.owner: number— The id of the car that fired it; -1 for a turret.x: number— World x of the shot.y: number— World y of the shot.vx: number— Velocity x, world units a second.vy: number— Velocity y, world units a second.t: number— Seconds it has flown.level: number— The level it flies on; it hits only cars and walls of that level.road: number— Index of the road the firer was on (a turret: the target car's road).
Spill
interface Spill
A temporary patch or block from an effect.
id: number— Unique among the session's wrenches, hazards, shots and spills.patch: PatchDef— The surface patch the effect laid.t: number— Seconds since it appeared.life: number— Seconds it lasts.
SuperSprintOptions
interface SuperSprintOptions
Options for superSprintPreset. Everything defaults to the arcade operator's recommended settings.
laps?: number— Laps per race (manual: four).cars?: number— Cars per race (four); drones fill the seats players leave.seats?: number— Player seats (three wheels).wrenchesPerBonus?: number— Wrenches per car bonus (operator switch: 2, 3, 4 or 5; shipped at 3).upgradeLevels?: number— Levels of each car bonus (five).circuits?: CircuitDef[]— Circuits (default the eight) and their cycle (default 1, 3, 7, 6, 2, 5, 8, 4 as indices).order?: number[]— The circuit cycle, as indices intocircuits; the race goes through them in turn.select?: boolean— First player chooses the starting track (true).vehicle?: VehicleSpec— The car, in metres.qualify?: "beat-drones" | "win"— Who goes on: every player must beat every drone (the arcade), or only win.
TimedEvent
interface TimedEvent
A scenery event on a timer (the mountain rumbles, lava spills).
every: readonly [number, number]— Seconds between events,[min, max].after?: number— First event no earlier than this many seconds into the race.effect: PropEffect— The effect.warn?: number— Seconds of warning before it happens (anevent-warningis emitted).
TrackRacerDef
interface TrackRacerDef
The whole game: cars, circuits, laps, scoring, wrenches, upgrades, drones, hazards and timings.
name: string— Game name.seats: number— Human seats (Super Sprint 3, Badlands 2).cars: number— Cars in every race; drones fill the seats humans leave.looks: CarLook[]— Car slots in order; human seat n drives slot n, drones the rest.circuits: CircuitDef[]— Circuits.order: number[]— The circuit cycle (indices intocircuits); after the last it starts again at a higher level.select: boolean— The first player picks the starting circuit fromorder.laps: number— Laps per race.unitsPerMetre: number— World units per metre for the vehicle spec.vehicle: VehicleSpec— The car, in metres (a vehicle-handling spec). Drones drive the same car.surfaces?: Record<string, SurfaceSpec>— Extra surfaces (lava ...), metres.qualify: "beat-drones" | "win"— Who goes on:beat-drones(every human must finish ahead of every drone) orwin.continues: boolean— Can a beaten human continue (the add-a-coin)?timing: { select: number; ready: number; finishGrace: number; results: number; shop: number; continue: number }— Timings in seconds.scoring: { /** Points per checkpoint passed in order. */ checkpoint: number; /** Place bonuses, first first. */ place: number[]; /** Points per second under the circuit's par for the average and best lap. */ perSecond: number; /** Default par lap times when a circuit has none. */ par: { average: number; best: number }; }— Scoring.wrenches: { /** Wrenches per upgrade. */ cost: number; /** Seconds between appearances \[min, max]`. / interval: readonly [number, number]; /* Seconds one stays on the track. / life: number; /* Most on the track at once. / max: number; /* Pick-up radius. / radius: number; /* Bonus wrenches for the winner of a race (Badlands: one). / firstPlace: number; /* Drones can pick wrenches up (they take them away). */ dronesCollect: boolean; }` — Wrenches.upgrades: UpgradeDef[]— Upgrade menu.drones: { /** Skill per operator setting. */ skill: Record<OperatorLevel, DroneSkill>; /** Added to \pace` and `corner` per heat raced (drones of increasing skill). / perHeat: number; /* Cap on the per-heat increase. / maxHeatBonus: number; /* Rubber band: pace change per lap of distance from the leading human (0 = none). */ catchUp: number; }` — Drones.hazards: { kinds: HazardKind[]; /** Patches at the start of a race per setting: \base + per heat`, capped. / count: Record<OperatorLevel, { base: number; perHeat: number; max: number }>; /* Roamers: seconds between appearances. */ roamEvery: readonly [number, number]; }` — Hazards.crash: { /** Seconds of explosion before the helicopter sets off. */ explode: number; /** Helicopter speed, world units per second. */ heliSpeed: number; /** Seconds the helicopter hovers to lower the car. */ hover: number; /** Wall impacts at or above the vehicle's \impact.crash` speed explode the car. */ walls: boolean; }` — Crashes and the rescue helicopter.jump: { minSpeed: number; up: number }— Jumps: a ramp launches a car moving at leastminSpeed(world units/s) upward atupworld units/s (a fixed hop: the faster the car, the further it flies).weapons?: WeaponsDef— Armament (Badlands).difficulties: Record<RacerDifficulty, { drones: OperatorLevel; hazards: OperatorLevel; assist: RacerDifficulty; catchUp: number }>— What Easy, Normal and Arcade mean: operator settings, handling assist, rubber band.dt: number— Seconds per simulation step.
UpgradeDef
interface UpgradeDef
One item on the between-races upgrade screen.
id: string— Id (traction,speed,turbo,score,missiles,shields...).label: string— Screen label.levels?: number— Maximum level; omit for unlimited (Increase Score, missiles).cost?: number— Wrenches per purchase (defaultwrenches.cost).effect: UpgradeEffect— Effect per level.
UpgradeEffect
interface UpgradeEffect
What one level of an upgrade does. Multipliers compound per level: grip: 0.1 is +10% a level.
grip?: number— Cornering grip (Super Traction, Badlands Tires).accel?: number— Acceleration (Turbo Acceleration, Badlands Turbo).top?: number— Top speed (Higher Top Speed, Badlands Speed).score?: number— Points added at once (Increase Score).missiles?: number— Missiles added at once.shields?: number— Shield charges added at once.
WallHit
interface WallHit
A wall push: unit normal toward the drivable area and penetration depth.
normal: { x: number; y: number }— Unit vector pointing from the wall toward the drivable area.depth: number— How far the car's circle sinks into the wall, world units.what: "edge" | "block" | "gate"— What was hit.id?: string— Block or gate id when it was one.
WallLine
interface WallLine
A drawable wall polyline on one level, with the side the road is on.
level: number— The level the wall is on.points: Array<{ x: number; y: number; nx: number; ny: number }>— The vertices in order, each with the unit normal (nx,ny) that points toward the drivable area.
WeaponsDef
interface WeaponsDef
Badlands-style armament. Omit weapons for an unarmed racer.
cannon: { interval: number; speed: number; life: number; radius: number; slow: number }— Front cannon: held to fire. Hits slow the target down.missile: { speed: number; life: number; radius: number; damage: number; start: number }— Missiles: one per press, destroy a car or damage a block.shield: { time: number; start: number }— A shield charge absorbs one shot, missile or crash, then protects fortimeseconds.dronesFire: boolean— Computer drivers fire their cannons.
Wrench
interface Wrench
A wrench lying on the track.
id: number— Unique among the session's wrenches, hazards, shots and spills; events refer to it.x: number— World x of the wrench.y: number— World y of the wrench.level: number— The level it lies on.t: number— Seconds it has lain there; it goes atwrenches.life.


