Phaser AE

Vehicle handling

Pro packv3.0.0-32DArcade

How an arcade car, bike, kart or boat moves: the engine and gears, boosts, steering, grip, skids and spins, surfaces, bike lean, jumps and the response to every collision. It runs on a road or on a flat top-down plane with the same parameters, so one model serves every kind of racer.

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

Released October 14, 2026 · updated October 19, 2026

Vehicle handling: 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

vehicleHandling

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

Install the vehicle handling API.

Helpers

ASSISTS

const ASSISTS: Readonly<Record<"easy" | "normal" | "arcade", Readonly<Assist>>>

The three difficulty levels as data. arcade is the researched preset unchanged.

calibrateCurvePush

function calibrateCurvePush(spec: VehicleSpec, o: { curvature: number; lock: number; speed?: number; skidAt?: number; grip?: number }): VehicleSpec

Road frame: set road.centrifugal so that holding the line on curvature at speed (default the top gear's top speed) takes lock (0..1) of full steering; set grip.lateral to grip (default 1) times that cornering demand (below 1 the vehicle slides out there) and grip.skidSlip so the tyres start to squeal at skidAt (default 0.85) of that speed. Use it to fit a preset to your track's curvature scale.

cornerSpeed

function cornerSpeed(spec: VehicleSpec, curvature: number, frame: "road" | "planar" = "road", surface: SurfaceSpec = SURFACES.tarmac): number

The fastest speed at which a vehicle holds a curve: below the grip limit and within its steering authority (road frame), or below the grip limit (planar). For traffic, drones and rival AI braking points.

createVehicle

function createVehicle(o: VehicleOptions): Vehicle

Create a vehicle in the road or planar frame.

evalCurve

function evalCurve(c: Curve, x: number): number

Evaluate a constant or a piecewise-linear [x, y] table at x, clamped at both ends.

PRESETS

const PRESETS: Readonly<{ outRunCar: () => VehicleSpec; chaseHQCar: () => VehicleSpec; sciCar: () => VehicleSpec; polePositionCar: () => VehicleSpec; nightDriverCar: () => VehicleSpec; ... 11 more ...; arcadeBike: () => VehicleSpec; }> …

Every preset by name.

REFERENCE_CURVATURE

const REFERENCE_CURVATURE: number

The curvature the road presets are fitted to: a hard pseudo-3D bend of 150 m radius. A road whose hardest bends differ calls calibrateCurvePush(spec, { curvature, lock }) to keep the same feel.

resolveVehicles

function resolveVehicles(a: Vehicle, b: Vehicle, normal: { x: number; y: number }, depth?: number): [ContactResult, ContactResult]

Resolve a contact between two vehicles in the same frame: mass-weighted exchange of the closing velocity with restitution (knock-back), separation by depth, and a classification for each. normal points from b to a.

routeCurvature

function routeCurvature(curve: number, segmentLength: number): number

Convert the route pack's RoadPiece.curve (a lateral shift per segment squared) into curvature in route world units: curve / segmentLength^2. Multiply by world units per metre if the vehicle runs in metres.

scaleSpec

function scaleSpec(spec: VehicleSpec, unitsPerMetre: number): VehicleSpec

Express a spec in other length units: unitsPerMetre world units per metre (pixels per metre on a top-down track, road units per metre on a pseudo-3D road). Every speed, acceleration, length and speed breakpoint is scaled; aerodynamic drag (per length) is divided. Surface drag, gravity on hills and surface spin speeds follow through unitsPerMetre. Scaling twice multiplies.

steerToward

function steerToward(state: Readonly<VehicleState>, target: { x: number; y: number } | number, o: { gain?: number } = {}): number

A steering value toward a target, for drones and traffic that drive the same handling as the player. Planar: target is a point and the result turns the heading toward it. Road: target is a lateral position.

stoppingDistance

function stoppingDistance(spec: VehicleSpec, from: number, to = 0, surface: SurfaceSpec = SURFACES.tarmac): number

Distance to brake from from to to (default 0) at full brake on a surface, with the spec's resistances.

SURFACES

const SURFACES: Readonly<Record<string, SurfaceSpec | undefined>> & { readonly tarmac: SurfaceSpec }

Built-in surfaces. Drag is m/s^2 (scaled by a scaled spec's unitsPerMetre); every multiplier is 1 on tarmac. The off-road ones (grass, sand, gravel, offroad, verge, median) carry offroad: true; dirt, mud, water, snow are racing surfaces for off-road games (Badlands, Super Off Road) and are not off the road by default.

upgradeSpec

function upgradeSpec( spec: VehicleSpec, levels: { grip?: number; accel?: number; top?: number }, per: { grip?: number; accel?: number; top?: number } = {}, ): VehicleSpec

Upgrades as multipliers per level: Super Sprint's wrenches buy traction, turbo acceleration and top speed. levels counts upgrades bought for each; per is the gain per level (default 10% grip, 12% acceleration, 6% top speed). Gear tops, auto shift points and the acceleration curves' breakpoints all follow.

withAssist

function withAssist(spec: VehicleSpec, level: "easy" | "normal" | "arcade" | Assist): VehicleSpec

Apply a difficulty assist ('easy' | 'normal' | 'arcade' or a custom Assist). Grip, curve push, steering and crash thresholds are applied at run time; off-road penalties are softened; spins from slip, bike falls and the manual gearbox can be switched off. Surface hazards (oil's spin on entry) and forced spins stay: they are rules.

Functions

curveMax

function curveMax(c: Curve): number

The largest y of a curve.

scaleCurve

function scaleCurve(c: Curve, kx: number, ky: number): Curve

Scale a curve's x and y axes.

Classes

Vehicle

class Vehicle

One vehicle on a fixed step. Deterministic, renderer-free, snapshot-able. Create it with createVehicle. See docs/design/ARCADE-PACK-7-VEHICLE-HANDLING.md for the step model.

  • readonly frame: "road" | "planar" — The frame of reference this vehicle moves in.
  • constructor(o: VehicleOptions)
  • get state(): Readonly<VehicleState> — The live state (read it, do not write it).
  • get params(): Readonly<VehicleSpec> — The current spec.
  • get fixedStep(): number — The fixed step in seconds.
  • display(speed = this.s.speed): number — Speed in the spec's speedometer units (km/h for the metre presets).
  • setSpec(spec: VehicleSpec, opts: { surfaces?: Readonly<Record<string, SurfaceSpec>> } = {}): void — Replace the spec (upgrades, difficulty, the car becoming a boat). State is kept; the gear is clamped. opts.surfaces replaces the vehicle's consumer surface table at the same time.
  • refillBoost(charges?: number): void — Refill the timed boost to charges (default the spec's): a new round, a continue (Chase H.Q.'s turbos).
  • setSurfaces(surfaces: Readonly<Record<string, SurfaceSpec>>): void — Replace the consumer surface table.
  • surfaceOf(ref: SurfaceRef): Readonly<SurfaceSpec> — Resolve a surface as this vehicle sees it (spec overrides, consumer table, built-ins, assist).
  • place(at: RoadPose | PlanarPose, o: { speed?: number; heading?: number; gear?: number } = {}): void — Respawn or teleport. Clears crashes, spins, slides, jumps and lean. Snap the sprite (no interpolation).
  • crash(): void — Enter the crashed state: inputs ignored, decelerates to a stop (stalled). The consumer animates.
  • rebase(d: { ds?: number; dx?: number; dy?: number }): void — Shift the frame without touching the dynamics: slides, skids, spins, lean, knock and speed are kept. Road: ds along, dx lateral (a road split rebasing onto the chosen branch's centre). Planar: dx, dy.
  • knock(k: { speed?: number; vx?: number; skid?: number; time?: number }): void — A rules-driven knock that keeps everything else: set the forward speed, a lateral knock velocity vx (road: added to the lateral motion and held for time s before decaying; planar: added to the world velocity across the heading), and force skid intensity skid for time s. Out Run's traffic rebound (speed to the traffic's speed - 80 km/h, a sideways skid away from the car) is one call.
  • spin(time?: number, dir?: number): void — Start a spin-out now, at any speed (tornado, mine, oil the consumer detects itself). dir +1 clockwise.
  • tip(side: number, time?: number): void — Tip onto two wheels (Buggy Boy's rocks): side -1 drives on the left wheels, 1 on the right, for time s (default spec.tip.time), with steering scaled by spec.tip.steer. Needs spec.tip.
  • launch(upSpeed: number): void — Jump: airborne with this upward speed until it lands, under spec.gravity (or air.gravity), steering by air.steer, landing by air.landing. Ramps in the environment call this themselves.
  • drain(): VehicleEvent[] — Events queued since the last drain (every step's events and contacts).
  • snapshot(): VehicleSnapshot — Plain-JSON snapshot of the state, bookkeeping and queued events (not the spec).
  • restore(snap: VehicleSnapshot): void — Restore a snapshot taken from a vehicle with the same frame.
  • contact(c: Contact): ContactResult — Collision response hook. The consumer detected the contact; this changes the velocity, pushes out by depth, classifies and reports it. Road frame: the plane is { x: lateral, y: along s }.
  • step(input: DriveInput = {}, env: RoadEnv | PlanarEnv = {}): VehicleEvent[] — Advance one fixed step. Returns this step's events (also queued for drain).
  • static resolvePair(a: Vehicle, b: Vehicle, normal: { x: number; y: number }, depth = 0): [ContactResult, ContactResult] — Two vehicles in the same frame, mass-weighted. normal points from b toward a.

Types

AirSpec

interface AirSpec

Flight parameters.

  • gravity?: number — Override of spec.gravity while airborne.
  • steer: number — Fraction of steering kept in the air (0 keeps heading and velocity exactly).
  • crests?: boolean — Road frame: leave the ground over crests when the road falls away faster than gravity. Default true.
  • landing?: LandingSpec — Landing consequences. Default: clean landings.

Assist

interface Assist

Difficulty assists, as multipliers and switches. ASSISTS.arcade is the identity.

  • grip: number — Multiplier on grip.
  • centrifugal: number — Multiplier on the road curve push.
  • offroad: number — 0..1: how much of an off-road surface's penalty applies (1 = all).
  • spin: boolean — Spin-outs from slip enabled.
  • fall: boolean — Bike falls enabled.
  • autoGears: boolean — Force an automatic gearbox.
  • steer: number — Multiplier on steering authority.
  • crash: number — Multiplier on the crash threshold (higher forgives more).

BoostSpec

interface BoostSpec

A boost: turbo, nitro or Super Hang-On's turbo button.

  • accel: number — Extra acceleration while boosting.
  • top: number — Extra top speed while boosting.
  • mode: "hold" | "timed" — hold boosts while the input is held; timed fires for time seconds per press.
  • time?: number — Seconds per timed boost. Default 1.
  • charges?: number — Boosts available (timed). Omitted = unlimited.
  • cooldown?: number — Seconds after a timed boost before another may start. Default 0.
  • minSpeed?: number — Boosting is only possible at or above this speed (Super Hang-On: 280 km/h). Default 0.
  • steer?: number — Steering multiplier while boosting (harder to steer). Default 1.

Contact

interface Contact

A collision handed to the vehicle by the consumer, which did the detection.

  • normal: { x: number; y: number } — Unit normal from the obstacle toward this vehicle, in the frame's plane (road: x lateral, y along s).
  • depth?: number — Penetration to push out along the normal. Default 0.
  • other?: { vx: number; vy: number; mass: number } | null — A moving other body; absent or null = immovable.
  • kind?: "wall" | "vehicle" | "object" — What was hit: sets sideswipe (vehicle) versus wall-slide classification. Default vehicle if other, else wall.
  • restitution?: number — Bounce override.
  • friction?: number — Tangential friction override.

ContactResult

interface ContactResult

How a contact was classified and what it did.

  • kind: "scrape" | "bump" | "sideswipe" | "wall-slide" | "crash" — The classification; the consumer decides what happens (animation, explosion, nothing).
  • normalSpeed: number — Closing speed along the normal (>= 0).
  • tangentSpeed: number — Relative speed along the surface.
  • impactSpeed: number — Relative speed magnitude.
  • angle: number — 0 grazing .. PI/2 head-on.
  • impulse: { x: number; y: number } — Velocity change applied to this vehicle, in the frame's plane.

Curve

type Curve = number | ReadonlyArray<readonly [x: number, y: number]>

A constant, or a piecewise-linear table of [x, y] points sorted by x (clamped at both ends).

DriveInput

interface DriveInput

One step's controls. Missing fields are 0 / no change.

  • throttle?: number — Accelerator 0..1.
  • brake?: number — Brake 0..1 (reverse from a standstill when the spec has one).
  • steer?: number — -1 full left .. 1 full right.
  • gear?: number | "up" | "down" — Manual: a gear index (a lever position) or a sequential shift. Ignored by an automatic box.
  • boost?: boolean — Boost button (held, or pressed for a timed boost).

GearboxSpec

interface GearboxSpec

The drivetrain.

  • mode: "auto" | "manual" — auto shifts by speed; manual follows DriveInput.gear (a lever position or up/down presses).
  • gears: ReadonlyArray<GearSpec> — At least one gear, lowest first.
  • start?: number — Starting gear index. Default 0.
  • shiftTime?: number — Seconds without drive during a shift. Default 0.
  • overSpeedDecel?: number — Deceleration while above the current cap (a low gear at high speed, a surface cap, a throttle target).

GearSpec

interface GearSpec

One gear of a gearbox.

  • name?: string — Name shown by a HUD ("LOW", "HIGH", "3"). Default: the 1-based gear number.
  • top: number — Top speed in this gear.
  • accel: Curve — Drive acceleration at full throttle, by speed (a curve over speed).
  • up?: number — Automatic box: shift up at or above this speed. Default 0.95 x top.
  • down?: number — Automatic box: shift down below this speed. Default 0.7 x the previous gear's top.
  • offroadTop?: number — Speed-cap multiplier on off-road surfaces in this gear, replacing the surface's topSpeed. Out Run cuts the accelerator to 60% in LOW and 30% in HIGH off the road, so LOW is faster on the grass.

LandingSpec

interface LandingSpec

What landing does, by vertical impact speed and attitude. Every threshold is data.

  • bounce: number — Fraction of the impact speed bounced back up (0 = none).
  • bounceMin: number — Below this impact speed a landing is clean (no bounce).
  • spinAbove?: number — At or above this impact speed the vehicle spins out on landing. Omitted = never.
  • crashAbove?: number — At or above this impact speed the vehicle crashes. Omitted = never.
  • rollLimit?: number — Landing rolled further than this (rad) crashes (tipped, or on a wall). Omitted = never.
  • yawLimit?: number — Landing with a slip angle (planar) or yaw (road) beyond this (rad) spins. Omitted = never.
  • speedLoss?: number — Fraction of forward speed lost per 10 m/s of impact. Default 0.

PlanarEnv

interface PlanarEnv

Planar environment for one step.

  • surface?: SurfaceRef — Surface under the vehicle. Default tarmac.
  • slope?: { x: number; y: number } — Downhill acceleration vector for hilly tracks.
  • ramp?: { angle: number; heading?: number } | null — A ramp under the vehicle: launch at speed x tan(angle) (along heading if given).
  • ceiling?: number — Clearance above the ground (an overpass, a tunnel).
  • tunnel?: boolean — Inside a tunnel or under cover.

PlanarPose

type PlanarPose = { … }

A planar pose.

  • x: number
  • y: number
  • heading?: number

PresetName

type PresetName = keyof typeof PRESETS

A preset name.

RoadEnv

interface RoadEnv

Road-frame environment for one step.

  • curvature?: number — Signed 1/radius, positive bends right. Default 0.
  • grade?: number — Rise over run, positive uphill. Default 0.
  • halfWidth?: number — Half width when left/right are omitted. Default 6 (metres, scaled with the spec).
  • left?: number — Left road edge (lateral position).
  • right?: number — Right road edge.
  • road?: SurfaceRef — Surface between the edges. Default tarmac.
  • off?: SurfaceRef — Surface outside the edges. Default grass.
  • kerb?: number — Kerb width just inside each edge. Default 0.
  • kerbSurface?: SurfaceRef — Kerb surface. Default kerb.
  • bands?: ReadonlyArray<SurfaceBand> — Bands checked first, last listed wins (oil patch over a puddle over the road).
  • surface?: SurfaceRef — Force one surface.
  • vertical?: number — Change of grade per unit distance (1/m): negative over a crest. With air, a crest taken fast launches.
  • bank?: number — Road bank (camber, rad): positive raises the right side; gravity pulls toward the low side.
  • walls?: { left?: RoadWall | null; right?: RoadWall | null } — Walls beside the road, starting at the road edges.
  • ramps?: ReadonlyArray<RoadRamp> — Ramps across the road here.
  • tunnel?: boolean — Inside a tunnel (reported as state.tunnel, with events).
  • ceiling?: number — Clearance above the road (a tunnel roof): a jump is stopped there.
  • drop?: { left?: number; right?: number } — The road is a deck above the ground (an elevated circuit): the fall beyond the left / right edge to the ground. A vehicle whose centre crosses an edge with a drop leaves the deck and falls (edge); once below the deck it cannot come back over it; reaching the ground is a fell event and a crash. A jump that lands beyond an edge keeps falling. Road-data's env reports it wherever a road with a ground plane has no barrier.
  • minX?: number — Hard lateral limits this step (Out Run's off-road bounds, a split branch's edges): x is clamped, vx zeroed.
  • maxX?: number — Hard right limit this step.

RoadPose

type RoadPose = { … }

A road-frame pose.

  • s: number
  • x: number

RoadRamp

interface RoadRamp

A ramp across part of the road (logs, kickers): crossing it on the ground launches the vehicle.

  • from: number — One lateral edge.
  • to: number — The other lateral edge.
  • angle: number — Launch angle (rad): upward speed = speed x tan(angle).

RoadWall

interface RoadWall

A ridable (or solid) wall beside the road: Buggy Boy's banked sides.

  • angle: number — Slope from horizontal (rad). Near PI/2 is a vertical wall.
  • height: number — Height of the wall's top above the road.
  • ridable?: boolean — Can be driven up (otherwise its foot is a solid wall). Default true when angle < 69 degrees (road-data's rule).

SurfaceBand

interface SurfaceBand

A band of surface across the road between two lateral positions.

  • from: number — One lateral edge.
  • to: number — The other lateral edge.
  • surface: SurfaceRef — The surface between them.

SurfaceRef

type SurfaceRef = string | SurfaceSpec

A surface given by id (looked up in the spec's, the vehicle's, then the built-in table) or inline.

SurfaceSpec

interface SurfaceSpec

How a vehicle reacts to a surface: every multiplier is 1 on dry tarmac.

  • id: string — Surface id.
  • grip: number — Multiplier on the cornering grip limit.
  • traction: number — Multiplier on drive and braking.
  • drag: number — Extra deceleration (m/s^2, scaled with the spec).
  • topSpeed: number — Multiplier on the speed cap.
  • damping?: number — Multiplier on road-frame lateral damping and on planar re-grip (ice and oil well below 1). Default 1.
  • steer?: number — Multiplier on steering authority. Default 1.
  • rumble?: number — Vibration 0..1, reported as state.rumble for shake and sound. Default 0.
  • offroad?: boolean — Counts as off the road (offroad events, state.offroad, the off-road assist, gear.offroadTop).
  • spinOnEntry?: number — Entering this surface faster than this speed (m/s, scaled) starts a spin, e.g. oil. Omitted = never.
  • slideTime?: number — Seconds this surface's grip loss persists after leaving it (oil on the tyres). Default 0.

VehicleEvent

type VehicleEvent = | { type: "gear"; from: number; to: number } | { type: "shift-end"; gear: number } | { type: "skid-start" } | { type: "skid-end" } | { type: "spin-start"; dir: number } | { type: "spin-end" } | { type: "offroad" } | { type: "onroad" } | { type: "surface"; id: string; prev: string } | { type: "boost-start" } | { type: "boost-end" } | { type: "over-lean"; lean: number; limit: number } | { type: "fall"; lean: number } | { type: "airborne"; vz: number } | { type: "landed"; impact: number; result: "clean" | "bounce" | "spin" | "crash" } | { type: "ramp"; angle: number } | { type: "ceiling" } /** Left the deck over an edge with a drop (`side` -1 left, 1 right). */ | { type: "edge"; side: number } /** Reached the ground below the deck (`drop` metres under the road): a crash. */ | { type: "fell"; drop: number; impact: number } | { type: "tunnel-enter" } | { type: "tunnel-exit" } | { type: "wall-ride"; side: number } | { type: "wall-leave" } | { type: "tip-start"; side: number } | { type: "tip-end" } | { type: "stalled" } | { type: "contact"; result: ContactResult }

Events a vehicle reports.

VehicleOptions

interface VehicleOptions

Options for createVehicle.

  • frame: "road" | "planar" — road (distance along a road and lateral offset) or planar (top-down x, y, heading).
  • spec: VehicleSpec — The handling parameters (a preset, scaled and assisted as needed).
  • at?: RoadPose | PlanarPose — Starting pose: { s, x } on the road, { x, y, heading } on the plane. Default the origin.
  • speed?: number — Starting speed. Default 0.
  • gear?: number — Starting gear. Default gearbox.start.
  • surfaces?: Readonly<Record<string, SurfaceSpec>> — Consumer surfaces by id (puddle, bridge, a custom oil patch), looked up before the built-in SURFACES.
  • unknownSurface?: SurfaceRef — Used for a surface id nobody defines (a road file naming its own strips). Omitted: an unknown id throws a clear error, so typos surface during development.

VehicleSnapshot

interface VehicleSnapshot

A vehicle's complete saved state. Plain JSON.

  • state: VehicleState — The public state.
  • internal: Internal — Timers and bookkeeping (shift, residue, lean, spin, knock).
  • queue: VehicleEvent[] — Events queued and not yet drained.

VehicleSpec

interface VehicleSpec

The handling parameters of one vehicle. Presets return these; consumers may author their own.

  • name: string — A display name.
  • kind: "car" | "bike" — Cars steer; bikes lean.
  • dt?: number — Fixed step in seconds. Default 1/60.
  • unitsPerMetre?: number — Units per metre this spec is expressed in (set by scaleSpec). Default 1.
  • length: number — Body length, for consumers' contact geometry.
  • width: number — Body width.
  • mass: number — Relative mass, for knock-back.
  • speedo?: number — Speedometer units per speed unit (3.6 for km/h from m/s). Default 3.6 / unitsPerMetre.
  • throttle?: { mode?: "force" | "target"; curve?: Curve } — Throttle pedal: force scales the drive; target sets a target speed as a fraction of the gear's top (Out Run).
  • brake: { decel: number; curve?: Curve } — Brake: full deceleration and a pedal curve (0..1 to 0..1).
  • reverse?: { accel: number; top: number } | null — Reverse gear, or none.
  • gearbox: GearboxSpec — Drivetrain.
  • resist: { rolling: number; aero: number; coast?: number } — Resistances: rolling (m/s^2), aero (decel = aero x v^2), coast (extra decel with the throttle closed).
  • hill?: number — Multiplier on g x grade (0 = hills are only visual). Default 0.
  • boost?: BoostSpec | null — Boost, or none.
  • steer: { /** 1/s: steering position follows the input. */ response: number; /** Planar: yaw rate (rad/s) at full lock, by speed. */ rate: Curve; /** Road: lateral speed at full lock, by speed. */ lateral: Curve; /** Planar: steering flips when reversing. Default true. */ reverseSteer?: boolean; } — Steering.
  • grip: { /** Cornering limit (m/s^2) on traction 1. */ lateral: number; /** Planar: 0..1 blend of the front-grip yaw limit (runs wide at speed). */ understeer: number; /** Planar: yaw allowed beyond the grip limit, as a fraction (the tail steps out into a drift). */ oversteer: number; /** Planar: slip angle (rad) at which a slide in the turn's direction cancels the steering yaw. Default 1.2. */ align?: number; /** 0..1: grip while already sliding, as a fraction of the limit (holds a drift). Default 1. */ slideGrip?: number; /** Planar: slip angle (rad) where skidding starts. Road: fraction of the grip limit where it starts. */ skidSlip: number; /** Speed lost while skidding (m/s^2 at full skid). Default 0. */ skidDrag?: number; /** Skid intensity when skidding starts (0..1). Default 0.3. */ skidFloor?: number; /** How far past the skid threshold (as a ratio) the skid reaches full intensity. Default 1. */ skidRamp?: number; } — Grip.
  • road?: { /** Multiplier on the outward curve push curvature x v^2. */ centrifugal: number; /** 1/s: lateral velocity relaxes toward the steering target at this rate (lower = slidier). */ damping: number; /** Multiplier on the push beyond the grip limit (sliding out). Default 1. */ slide?: number; /** How far beyond either road edge the vehicle may go. Default unlimited. */ bounds?: number; /** * Speed exponent of the curve push: 2 (default) pushes with curvature x v^2; 1 pushes with * curvature x v x vTop (Out Run's set_curve_adjust is linear in speed). Both agree at the top gear's top speed. */ exponent?: number; /** 1/s decay of a lateral knock (contacts, \knock()`). Default 4. / knockDamping?: number; /* Multiplier on gravity's sideways pull on banked road and ridable walls. Default 1. */ bankScale?: number; }` — Road-frame lateral behaviour.
  • spin?: { /** Slip angle (rad, planar) beyond which a slide becomes a spin. */ slip: number; /** No slip spins below this speed. */ minSpeed: number; /** Seconds a spin lasts. */ time: number; /** Yaw rate (rad/s) at the start of a spin. */ rate: number; /** Grip multiplier while spinning. */ grip: number; /** Brake applied while spinning (0..1). Default 0.3. */ brake?: number; /** Fraction of \rate` left at the end of the spin (it eases down linearly). Default 0.35. */ endRate?: number; } | null` — Spin-outs, or none.
  • bike?: { /** Safe lean (rad) by speed. */ maxLean: Curve; /** Lean at full input (rad). Default: the largest maxLean value. */ fullLean?: number; /** rad/s toward the target lean. */ rate: number; /** rad/s back to upright with no input. Default \rate`. / returnRate?: number; /* 0..1 opposite lateral response while a lean builds. / counterSteer: number; /* Falling: past the safe lean by `lean` rad, or past it for `time` s. null = the lean is clamped instead. */ fall?: { lean: number; time: number } | null; } | null` — Bike lean, or none.
  • gravity?: number — Gravity (m/s^2, scaled with the spec). Drives hills (hill), banking and ridable walls, jumps, crests and landings. Default 9.81.
  • air?: AirSpec | null — Jumps and flight. null = never leaves the ground (crests are ignored; launch still works with gravity).
  • tip?: { angle: number; time: number; steer: number } | null — Tipping onto two wheels (Buggy Boy's rocks), started by tip(). null = tip() does nothing.
  • impact: { scrape: number; crash: number; sideswipeAngle: number; restitution: number; friction: number; crashDecel?: number; } — Impact classification and response.
  • surfaces?: Readonly<Record<string, Partial<SurfaceSpec>>> — How THIS vehicle treats surfaces: overrides by id (a boat makes water drivable and land off-road).
  • assist?: Assist — The assist applied by withAssist, kept for runtime use.

VehicleState

interface VehicleState

A vehicle's live state. Plain data; frame-specific fields are always present (unused ones stay 0).

  • frame: "road" | "planar" — Frame of reference.
  • speed: number — Forward speed (planar: along the heading, negative when reversing).
  • gear: number — Current gear index.
  • gearName: string — Current gear name.
  • shifting: boolean — True during a shift (no drive).
  • revs: number — 0..1 through the gear (over 1 when over-speeding a low gear).
  • throttle: number — Applied throttle after its curve.
  • brake: number — Applied brake after its curve.
  • steer: number — Smoothed steering position -1..1.
  • surface: string — Surface id under the vehicle.
  • offroad: boolean — Off the road.
  • rumble: number — Vibration 0..1.
  • shake: number — Deterministic -1..1 jitter x rumble for sprite shake.
  • sliding: boolean — Grip exceeded (or spinning).
  • skid: number — Skid intensity 0..1.
  • spinning: boolean — Spin-out in progress.
  • spinTime: number — Seconds of spin left.
  • spinAngle: number — Visual rotation accumulated by a road-frame spin (planar spins turn heading).
  • boosting: boolean — Boost active.
  • boostTime: number — Seconds of timed boost left.
  • boostCharges: number — Timed boosts left (-1 unlimited).
  • boostCooldown: number — Seconds before another timed boost.
  • crashed: boolean — Set by crash() or a fall; cleared by place().
  • airborne: boolean — In a jump.
  • z: number — Jump height.
  • vz: number — Jump vertical speed.
  • pitch: number — Nose-up pitch for drawing (rad): the flight path while airborne.
  • roll: number — Body roll for drawing (rad, + right side up): bank, a ridden wall or a tip onto two wheels.
  • bank: number — Road bank under the vehicle (rad).
  • wall: number — -1 / 1 while riding up the left / right wall, else 0.
  • wallHeight: number — Height up a ridden wall.
  • tunnel: boolean — In a tunnel.
  • tipped: number — -1 / 1 while on two wheels (tipped onto the left / right side), else 0.
  • tipTime: number — Seconds of tip left.
  • turn: number — -1..1 for sprite frame choice (steering, lean or drift).
  • s: number — Road: distance along.
  • x: number — Road: lateral position. Planar: world x.
  • y: number — Planar: world y.
  • heading: number — Planar: heading.
  • vx: number — Lateral velocity (road) or world x velocity (planar).
  • vy: number — Planar: world y velocity.
  • yaw: number — Road: visual heading relative to the road.
  • angVel: number — Planar yaw rate.
  • slip: number — Planar slip angle.
  • lean: number — Bike lean (rad, + right).
  • leanLimit: number — Current safe lean (rad).
  • fallen: boolean — The rider fell.
  • tick: number — Steps taken.