solveSpeedKmh + gearing) across a grade×power grid, five routes, a gear/cadence ladder and a standing-start acceleration table, then audits working points against independent cycling calculators. Every number is reproducible — tweak the equipment, air, wind and surface and watch it react, or copy the whole audit out. The competitive targets are built on this too: each leaderboard's par time (Time-Trial medals + the OutRide Arcade Rating) is this same solveSpeedKmh model run for a reference rider of your W/kg class — so a flat sprint and a mountain climb are compared on honest physics, not a lookup table.EQUIPMENT — “our values”
ENVIRONMENT — air, wind & surface
ρ is computed from altitude + temperature (barometric formula); Crr comes from the surface. Thinner air up high = faster on the flat; a headwind or gravel = slower. Wind feeds the grade×power matrix and the routes; the audit + acceleration stay at the windless calibration.
GAME ROAD SURFACES — the story-ride consequence · docs/fable/48
Each story-ride road surface carries a REAL rolling-resistance cost, not just a texture. The speed multiplier below is derived from THIS page's own solver at a reference operating point (200 W, flat, reference rider) — the same watts cover this fraction of the ground on that surface vs. smooth asphalt, so a muddy or cobbled sector is felt as lost distance, never a faked watt. Soft ground (dirt/snow/mud/sand) bites harder on climbs (the tyre sinks — a term the steady-state balance alone misses); the last column shows the total at an 8% climb.
| Surface | Rolling Crr | Flat speed × | At 8% climb × |
|---|---|---|---|
| asphalt | 0.0050 | 1.000 | 1.000 |
| dirt | 0.0100 | 0.928 | 0.905 |
| cobbles | 0.0110 | 0.913 | 0.913 |
| snow | 0.0140 | 0.871 | 0.829 |
| mud | 0.0160 | 0.843 | 0.783 |
| desert | 0.0170 | 0.830 | 0.776 |
| regolith | 0.0060 | 0.985 | 0.985 |
| marsdust | 0.0070 | 0.971 | 0.971 |
| racetrack | 0.0040 | 1.015 | 1.015 |
| chocolate | 0.0050 | 1.000 | 1.000 |
| rainbow | 0.0050 | 1.000 | 1.000 |
VALIDATION AUDIT — vs independent calculators · reference rider, sea level / 15 °C
| Working point | Power | Grade | Expected | Ours | Δ | Δ% | Reference implies | |
|---|---|---|---|---|---|---|---|---|
| Endurance, flat physics.ts / bikecalculator | 200 W | 0% | 30.0 ±2.5 | 32.1 | +2.1 | +7% | CdA 0.450 ours 0.36 | PASS |
| Easy spin, flat bikecalculator | 100 W | 0% | 24.0 ±3 | 24.4 | +0.4 | +2% | CdA 0.382 ours 0.36 | PASS |
| Threshold, flat bikecalculator | 300 W | 0% | 35.5 ±3 | 37.4 | +1.9 | +5% | CdA 0.426 ours 0.36 | PASS |
| Sprint power, flat bikecalculator | 450 W | 0% | 41.5 ±3.5 | 43.4 | +1.9 | +5% | CdA 0.414 ours 0.36 | PASS |
| Endurance, 5 % climb physics.ts / bikecalculator | 200 W | 5% | 14.0 ±1.5 | 14.3 | +0.3 | +2% | 86.4 kg ours 84.5 kg | PASS |
| Threshold, 8 % climb Gribble | 300 W | 8% | 13.5 ±1.8 | 14.2 | +0.7 | +5% | 89.6 kg ours 84.5 kg | PASS |
| Steady, 10 % wall Gribble | 250 W | 10% | 9.2 ±1.5 | 9.9 | +0.7 | +7% | 91.2 kg ours 84.5 kg | PASS |
| Coasting, −5 % descent terminal velocity (Gribble) | 0 W | -5% | 44.0 ±5 | 46.8 | +2.8 | +6% | CdA 0.407 ours 0.36 | PASS |
Run at the reference rider — 84.5 kg · CdA 0.36 · Crr 0.005 · ρ 1.225 · η 0.97, sea level / 15 °C. Fixed on purpose: the sliders above move every other table on this page, but they must not be able to paint this one green. The two flat/5 %-climb anchors are the ones already cited in lib/physics.ts.
We sit high on all 8 of them — 8/8 fast, mean +5.0 %. That is an offset, not scatter, so here is where it comes from rather than an average that hides it. The references were not all taken at one setup: hold everything else and ask what single value would make our own solver land exactly on each published speed — the last column. Where air resistance sets the speed they imply CdA 0.38–0.45 m²; where gravity does, 86–91 kg total. Ours is a 0.36 m² hoods/tops position at 84.5 kg — more aero and lighter than what those numbers describe, which is the whole gap. Feed a rider back in at roughly CdA 0.41 / 89 kg and the deltas scatter either side of zero instead of stacking up. So the offset is a difference in who is riding, not in the physics: 8/8 land inside a tolerance band that was set before any of this was measured.
SPEED MATRIX — km/h (grade × power)
| grade \ W | 100 | 150 | 200 | 250 | 300 | 350 | 400 |
|---|---|---|---|---|---|---|---|
| -8% | 63.0 | 64.2 | 65.3 | 66.4 | 67.5 | 68.5 | 69.5 |
| -4% | 46.3 | 48.4 | 50.2 | 51.9 | 53.4 | 54.9 | 56.2 |
| -2% | 36.1 | 39.0 | 41.5 | 43.7 | 45.6 | 47.4 | 49.0 |
| 0% | 24.4 | 28.8 | 32.1 | 35.0 | 37.4 | 39.6 | 41.6 |
| +2% | 14.4 | 19.3 | 23.3 | 26.6 | 29.5 | 32.0 | 34.3 |
| +4% | 9.0 | 13.0 | 16.6 | 19.9 | 22.7 | 25.4 | 27.7 |
| +6% | 6.4 | 9.5 | 12.4 | 15.1 | 17.7 | 20.1 | 22.4 |
| +8% | 4.9 | 7.4 | 9.7 | 12.0 | 14.2 | 16.3 | 18.4 |
| +10% | 4.0 | 6.0 | 8.0 | 9.9 | 11.8 | 13.6 | 15.4 |
| +12% | 3.4 | 5.1 | 6.7 | 8.4 | 10.0 | 11.6 | 13.2 |
| +15% | 2.7 | 4.1 | 5.5 | 6.8 | 8.2 | 9.5 | 10.8 |
Each cell is solveSpeedKmh(power, grade, rider) — the exact value the ride uses. Read down a column and you can see the balance tip: At 250 W the flat is aero-dominated, the 8 % climb is gravity-dominated.
ROUTE SIMULATIONS
| Route | Dist | Time | Avg | Min | Max | Ascent | Descent | Gear @avg | rpm | Climb gear |
|---|---|---|---|---|---|---|---|---|---|---|
| Pancake Flat 10 km dead flat — the aero/rolling baseline. | 10 km | 17:03 | 35.2 | 35.2 | 35.2 | 0 m | 0 m | 54/17 | 88 | — |
| Rolling Hills 12 km of ±3 % rollers — punchy, never steep. | 12 km | 23:00 | 31.3 | 23.2 | 48.0 | 180 m | 180 m | 39/14 | 89 | 141 rpm @ 3% |
| Alpine Climb 8 km at a steady 7 % — a real mountain pass. | 8 km | 35:16 | 13.6 | 13.6 | 13.6 | 560 m | 0 m | 39/30 | 83 | 83 rpm @ 7% |
| Fast Descent 6 km at −6 % — coasting / pedalling downhill. | 6 km | 6:03 | 59.6 | 59.6 | 59.6 | 0 m | 360 m | 54/11 | 96 | — |
| Mixed Classic 4 km @ 5 % up · 4 km @ −5 % down · 4 km flat. | 12 km | 24:51 | 29.0 | 17.5 | 55.9 | 200 m | 200 m | 54/21 | 89 | 106 rpm @ 5% |
Each route integrates the steady-state speed segment-by-segment at a constant 3.0 W/kg. “rpm” is the cadence in the gear closest to 90 — yellow means no gear in the All-round (54/39 × 11-30) drivetrain keeps you in the 80–100 band at that speed.
LEADERBOARD PAR — “the target you race”
The OutRide Arcade Rating + Time-Trial medals rank you against a par time, not raw speed — so a flat sprint and a mountain climb compare fairly. Each par below is stageTargetSec = this same solveSpeedKmh model run for a reference rider of that W/kg class (equipment-neutral, 90% of class FTP). Notice steep climbs cost a weak (E) rider far more than a lookup table would ever guess — that's gravity, done honestly.
| Stage | A 4.3 W/kg | B 3.6 W/kg | C 2.9 W/kg | D 2.1 W/kg | E 1.5 W/kg |
|---|---|---|---|---|---|
| 1 km · flat | 1:37 | 1:44 | 1:54 | 2:07 | 2:27 |
| 1 km · rolling +2.5% | 2:07 | 2:22 | 2:44 | 3:19 | 4:20 |
| 1 km · hilly +4.5% | 2:41 | 3:04 | 3:42 | 4:42 | 6:28 |
| 1 km · climb +7% | 3:33 | 4:09 | 5:07 | 6:42 | 9:25 |
| 1 km · descent −3% | 1:15 | 1:18 | 1:21 | 1:26 | 1:31 |
| 5 km · flat | 8:07 | 8:41 | 9:30 | 10:38 | 12:20 |
Ride under your class's par → positive Arcade Rating (1000 = par). Because it's par-relative, no single fork line is a “farm” — every route rewards the same relative effort equally.
ROLLING PENALTY — “same average, not the same time”
A 10 km course that averages 2.0% is not one time — how the climb is distributed changes it a lot. profileTimeSec integrates the same solveSpeedKmhfoot-by-foot over the real elevation profile — the honest way to time a course, and the model behind profile-aware ghost + par times. Rolling terrain is genuinely slower: the time lost grinding steep pitches dwarfs the time won on the descents (drag caps downhill speed), so a “Rollers” course with 30% descent is the slowest of all, not the fastest. All at 3.0 W/kg.
| Profile | Grade range | Descent | Time (10 km) | vs constant |
|---|---|---|---|---|
| Constant | 2.0…2.0% | 0% | 22:20 | — |
| Front-load | 0.0…4.0% | 0% | 22:43 | +23s (+1.7%) |
| Back-load | 0.0…4.0% | 0% | 22:42 | +23s (+1.7%) |
| Wave | 0.0…4.0% | 0% | 22:54 | +34s (+2.6%) |
| Plateau | 0.8…3.2% | 0% | 23:34 | +75s (+5.6%) |
| Rollers | -1.6…5.6% | 31% | 24:04 | +104s (+7.8%) |
| Valley | -1.4…5.4% | 30% | 23:53 | +94s (+7.0%) |
At 0% average every shape is identical (nothing to distribute). The penalty grows with the average grade and the “peakiness” of the profile — which is exactly why a naive average-grade lookup would hand out unfair targets on a hilly course. Same physics, done honestly.
ACCELERATION — standing start (real F = m·a)
| Scenario | Power | Grade | Terminal | 0 → 30 km/h | → 90 % terminal | Distance |
|---|---|---|---|---|---|---|
| Easy roll-out | 150 W | 0% | 28.8 km/h | — | 29.2 s | 149 m |
| Endurance flat | 250 W | 0% | 35.0 km/h | 20.2 s | 24.5 s | 154 m |
| Sprint jump | 600 W | 0% | 48.1 km/h | 6.3 s | 18.2 s | 160 m |
| Tempo, 4 % climb | 250 W | 4% | 19.9 km/h | — | 14.6 s | 50 m |
| Attack, 8 % climb | 350 W | 8% | 16.3 km/h | — | 8.7 s | 23 m |
Driven by the actual ride integrator step() from a standstill. The terminal speed is identical to the solver — only the wind-up is now Newtonian, so a 84.5 kg rider on this equipment shows real launch lag and a sprint has punch. Heavier mass or less power = slower to wind up.
GEAR / CADENCE LADDER — All-round (54/39 × 11-30)
| Speed | Easiest gear rpm | Hardest gear rpm | 80–100 band reachable? |
|---|---|---|---|
| 12 km/h | 73 | 19 | no gear in band |
| 18 km/h | 110 | 29 | yes |
| 24 km/h | 146 | 39 | yes |
| 30 km/h | 183 | 48 | yes |
| 36 km/h | 219 | 58 | yes |
| 42 km/h | 256 | 68 | yes |
| 48 km/h | 292 | 77 | yes |
| 54 km/h | 329 | 87 | yes |
A row marked has a gear that holds the target cadence band at that speed; at the top and bottom of the range you’d spin out or grind — exactly what a real drivetrain does.