Skip to content

Bikes & stats

The garage menu (HUD button, top-right) lets you pick a bike. The URL also accepts ?bike=cruiser|racer|stunt. The default is Racer.

Archetypes

Three flavors with explicit handling tradeoffs so picking a bike feels like a real choice, not a recolor.

CruiserRacerStunt
TaglineHeavy hitter — big top speed, plows through chopBalanced all-rounder — the defaultLight + agile — banks every wave
Mass (kg)16012090
Top speed (m/s)322825
Accel (m/s²)182226
Turn torque (rad/s²)3.54.55.5
Lateral drag678
Surface follow0.30.50.7
Hover spring242832
Hover damp765

Source of truth: src/game/bikes/variants.ts. The defaults each variant inherits live in stats.ts.

What each stat actually does

StatUnitsEffect
masskgRapier rigid-body mass. Higher mass = more inertia in collisions, less affected by impulses from mines/missiles.
accelm/s²Forward thrust at full throttle. Tapers off via speedFalloff as you approach topSpeed.
topSpeedm/sSoft cap on forward speed. Boost multiplies through this; you can briefly exceed it.
turnTorquerad/s²Yaw torque at full steer. Applied around world Y, not bike-local-up — see Conventions.
lateralDragm/s² per m/sHow aggressively the sim bleeds sideways drift. Higher values feel grippier; lower values feel slidy.
reverseScaleunitlessMultiplier on accel when throttle is negative. Default 0.4 — reverse is intentionally feeble.
boostMulunitlessThrottle multiplier while a Boost pickup is active. Default 1.6.
surfaceFollow0..1How much the bike kinematically tilts to match the wave surface normal. Faded by altitude — see below.
hoverSpringm/s² per mStiffness of the PD hover controller. Higher = punchier ride, more prone to overshoot.
hoverDampm/s² per m/sDamping coefficient on vertical velocity. Above water it's one-sided — only damps upward velocity, so dive momentum can punch through into the water.
hoverHeightmTarget ride height above the surface. The PD spring tracks this. Pitch input modulates it ±0.5 m.

Hover physics in one paragraph

The hover is a PD controller in acceleration form:

aUp = g + hoverSpring * (target - distance) - hoverDamp * vy

With g = 25 (matches Rapier gravity), aUp = g cancels gravity at rest. The bike sits at target = hoverHeight with no extra force. Above-water hoverDamp only fires on upward velocity (one-sided) so dive momentum off a ramp punches through. Underwater (groundDistance < 0 on water) the spring is replaced with depth-proportional buoyancy + asymmetric quadratic drag — see status.md §"Underwater dive feel" for the constants.

Surface follow is altitude-faded

surfaceFollow is the peak responsiveness. The runtime applies surfaceFollow * altitudeFactor, where the factor falls linearly from 1.0 at the water surface to 0 at the grounded/airborne boundary (groundDistance = hoverHeight * 1.6). At nominal hover the factor is ~0.37 — so a Racer's effective follow is ~0.19, not 0.5. Dipping into a trough kicks reaction back up; cresting a wave eases it off. This is what makes the bike read as a hovercraft rather than a jet ski.

Air control

Off a ramp (or off the Cliffside drop), the bike enters an airborne state:

  • 60 % gravity counter — effective fall rate ~10 m/s² instead of 25. Hang time is generous.
  • Pitch-vectored thrust — throttle while airborne pushes along the bike's real forward vector. Pitch up (E) extends air time; pitch down (Q) dives.

This is intentional, and tuned for the Cliffside cliff drop. Constants live in src/game/systems/hover.ts (AIR_LIFT_FRAC, AIR_THRUST_MUL).

Pitch + throttle on water — intentional

Holding Q (dive) at full throttle plants the nose into wave troughs and submerge-and-bounces. Speed swings 10 → 25 → 10 m/s as buoyancy kicks back. This is the desired Wave Race feel — diving into a wave should cost you. Don't "fix" it; it's the bike's collider being driven through the wave field at speed, not a thrust-direction bug.

Made with VitePress.