1. Quick start
The predictor runs a Monte-Carlo simulation of a Zwift ladder race
between two teams of three, four, or five riders. It pulls each
rider's real power and phenotype data from
zwiftracing.app, runs the chosen route on Zwift physics,
and reports each team's win probability plus an animated replay of a
representative ("median") race.
- Pick a format: 3 vs 3, 4 vs 4, or 5 vs 5.
- Type a name for each team.
- For every rider, paste their Zwift ID (the number in the URL of
zwiftracing.app/riders/<ID>) and click Look up to verify the name and stats. - Optionally override the rider's Strategy and assign a Team role.
- Pick a Track; type in the filter box to narrow down the 287 official Zwift routes.
- Set Simulations (default 500) and Noise σ (default 0.5).
- Click Run Monte Carlo. After 30–90 s the results appear: race-win and ladder-win probabilities, a per-rider table, the four-panel result plot, and a playable replay of the median race.
Your team setup is saved automatically in your browser's local storage. It never leaves your device unless you click Run. Visiting the page again — even days later — restores everything.
2. The race-setup form
Format
Choose how many riders per team. The Monte-Carlo engine works for any size; the ladder-points table scales automatically (1st gets 10 points, 2nd 9, etc., down to last place).
Team A / Team B
Each team has a name (free text — appears in plots and tables) and an ordered list of riders. Order matters only for display; the simulator treats all riders on the same team symmetrically.
Zwift ID
The integer in the URL of a rider's profile at
zwiftracing.app/riders/<ID>. The same ID Zwift uses
internally — you can also find it in ZwiftPower or via the rider's
Zwift Companion profile. The Look up button next to
each ID fetches the rider's name, weight, FTP, and detected archetype
so you can verify before running.
Strategy (archetype)
Defaults to Auto, which means "use the archetype the
rider's zwiftracing.app phenotype scores indicate".
See section 3 for when to override.
Team role
Defaults to Free. This is the rider's tactical role within the team — leader, lead-out, domestique, etc. — independent of their physiological archetype. See section 4.
Track
287 official Zwift routes are available. Type in the filter box to narrow the list. Selecting a route shows its slug below; the first time a route is used the GPX file is parsed into segments and cached.
Simulations
How many independent races to run. More runs give smoother win probabilities but take longer. 500 is a good balance; 100 is quick but noisy; 2000+ is very precise. Each rider's "day form" is randomised once per simulation, so simulations differ even with identical inputs.
Noise σ (day-form variance)
Standard deviation of the per-race power-multiplier drawn for each
rider. Each rider's power output for an entire simulation is multiplied
by a single value drawn from N(1, σ), clamped to ±20%.
3. Strategy (archetype) override
Each rider has a primary archetype: a physiological
type that drives their tactical decisions. By default, the predictor
uses zwiftracing.app's phenotype scores — the highest
percentile is the primary, the second-highest the secondary.
You override the archetype only when you have specific reason to believe the rider will race differently than usual. The archetype affects power-curve effort durations, attack-trigger conditions, and defensive thresholds (W' reserve, terrain affinity).
The seven archetypes
- Sprinter (SPR)
- Sits in the wheels, conserves W' until the closing kilometres, launches a sprint inside the final 380 m. Survives climbs but does not attack on gradient. Reserve threshold: 50% of W'. Suffers on long climbs (terrain affinity ×0.92 above 5%).
- Puncheur (PUN)
- Attacks on every gradient ≥ 3% with W' available, plus late-race punches inside 800 m. Sprint-capable. Reserve threshold: 30%. Slightly weaker on long sustained climbs (×0.95 above 6%).
- Pursuiter (PUR)
- Breakaway specialist. Higher probabilistic attack rate on flat and rolling terrain (sustained 5-min effort), aggressive at bridging to riders up the road. Reserve threshold: 30%.
- Climber (CLI)
- Patient on flat. Attacks on gradients ≥ 7% when W' is sufficient. Reserve threshold: 40% — protects W' for the queen climb. Saves 3% on flat terrain via terrain affinity (×0.97 below 1%).
- Time Trialist (TT)
- Pure tempo pacing, no attacks. Closes only catastrophically large gaps (> 15 m). Crosses the line with a controlled effort, no real sprint. Reserve threshold: 70% — TTs don't dig deep voluntarily. Best on rolling/flat terrain (×1.02 between -1% and +2%).
- Domestique (DOM)
- (As an archetype; see also team role.) Controlled tempo, climbs on slopes ≥ 3.5%, only line-crossing sprint. Designed for rider-curve shapes that don't fit one of the four phenotype types. Reserve threshold: 25%.
- All-rounder (ALL)
- Default fallback. Probabilistic attacks early in the race based on attack-bias and W' fraction; sprints on traits, climbs on slopes. Reserve threshold: 35%.
When to override
Leave it on Auto in 90% of cases. Override when:
4. Team roles
Independent of their physiological archetype, every rider can be assigned a tactical team role. This represents what the team plans for them this race: who's protected, who pulls, who lights the fuse for the sprint. Defaults to Free (no override; behave by archetype only).
Free (default)
No team-role override. The rider behaves purely according to their archetype. Use this for the majority of riders or when team tactics are unspecified.
Leader
The team's protected rider. Sits in the draft and refuses to attack until the final 500 m; will follow on climbs but won't lead them. After 500 m, defers to their archetype — so a leader who's a sprinter will sprint, a leader who's a climber will hold tempo, etc.
Use this for riders you've identified as your best card on this course. Effect: significantly improves their finish position by saving W' for the decisive moment, at the cost of doing nothing for the rest of the race.
Co-leader
Currently behaves identically to Free at the simulator level — placeholder for future logic. Useful as a label so you can see in the results who you'd intended as a backup card.
Lead-out
Sacrificial role for sprint trains. The lead-out goes full gas in the 1.5 km – 500 m window before the finish (ignoring the normal attack cooldown), then drops into recover phase for the closing 500 m. Doesn't sprint at the line — they've done their job.
Pair with a Leader who's a sprinter. The lead-out's job is to deliver them through the second-to-last kilometre with W' intact while burning off the rivals. Effect: the lead-out's personal finish position drops, but the leader's win probability goes up.
Domestique
Pure pacing role: holds tempo throughout the race, never attacks, never sprints (except to cross the line at 100 m). Climbs on slopes ≥ 3.5%. Sacrifices entirely for the team.
Use for the team's third or fourth strongest rider on courses where you want to control the tempo or shelter your leader. Effect: your leader gets cleaner air; your domestique finishes near the back.
5. Worked example team setups
Sprint train (flat or sprint-finish course)
On Crit City or any pure flat route, this configuration typically wins by 5–15 percentage points more than the same riders all set to Free.
Climber GC team (hilly / mountain course)
On Ventoux or any course with a major climb in the final third, the leader's reserve threshold is highest (40%), so they enter the climb with W' intact and can attack inside the final 7%+ slope.
Mixed (rolling course, no obvious finish)
When you don't know what kind of finish to plan for, let the archetypes do their thing. The simulator's Tier 1–7 logic produces coherent races even without team-role overrides.
6. Reading the results
Team cards
Two large cards at the top show:
Riders table
One row per rider, sorted by mean finishing rank.
Plots (four-panel figure)
7. The race replay
The animated replay below the rider table shows a single representative race — specifically, the simulation whose finishing positions deviate least from each rider's average rank across all sims. This is the "median race" — what's most likely to happen on race day.
The horizontal panel shows the route's elevation profile (filled silhouette, X = distance, Y = elevation), with each rider as a colored pin (blue = Team A, red = Team B). As the replay plays, pins glide left to right at 1× / 5× / 20× / 50× speed (configurable).
Hover any pin for a live tooltip with the rider's W' balance (% and absolute kJ), current power, speed, position, and gap to the leader. The scrubber lets you jump to any point in the race. Riders who've finished fade to 45% opacity.
What to look for: where W' drops sharply (an attack); where W' refills (recover phase or descent); where the gap-to-leader column opens up (the decisive moment). Comparing two replays with different team-role configurations is the cleanest way to see what the changes actually do tactically.
8. The simulation model
Physics
Per-tick Newtonian forces:
F_aero = 0.5 × ρ × CdA × v² (ρ = 1.225 kg/m³) F_grav = m × g × sin(θ) (gradient) F_roll = m × g × Crr × cos(θ) (Crr = 0.004) CdA = 0.0293 × h^0.725 × m^0.425 × 0.88 (Zwift tuck position)
Each timestep (1 s by default) the rider's equilibrium speed is computed for the current power output and gradient via binary search. The simulator does not model inertia — speed is instantaneous given power and slope. This is a known approximation.
Drafting
Draft benefit by gap to the rider directly ahead:
< 1.5 m 100% draft (full wheel) < 3.0 m 85% < 5.0 m 60% < 8.0 m 35% < 12 m 10% ≥ 12 m 0%
Draft reduces effective CdA by up to 25% on flat terrain, less on climbs (gradient-dependent draft scale). The Van Buren power-up boosts draft benefit by 40% for 10 s.
W' balance (Skiba & Clarke 2021)
Above CP: W'bal(t) = W'bal(t-1) − (P − CP) × dt
Below CP: τ = 546 × exp(−0.01 × (CP − P)) + 316 [seconds]
W'bal(t) = W'bal(t-1) + (W' − W'bal(t-1)) × (1 − exp(−dt / τ))
Linear depletion when above CP, exponential recovery when below. The time constant τ depends on how far below CP the rider is — bigger deficit means faster recovery.
Long-term fatigue (TSS-proxy)
tss_proxy += (P / FTP)² × dt fatigue = min(0.25, tss_proxy × 5.56e-5) effective_CP = CP × (1 − 0.5 × fatigue)
Accumulated effort gradually reduces effective CP over the course of the race, capped at 12.5% reduction (matching ~10% drop after a hard hour at FTP).
Power curve
Each rider has a CP curve from zwiftracing.app: peak
power in W/kg at 5, 15, 30, 60, 120, 300, and 1200 seconds. The
simulator picks an effort duration based on phase (e.g., 8 s for a
sprint, 90 s for a steep climb, 480 s for a long climb) and reads the
appropriate point off the curve.
Tactical layers
On top of physics + physiology, seven layers of decision-making determine each rider's phase tick-by-tick:
- Tier 1 — W' reserve / recover phase
- Each archetype defends a minimum W' fraction (sprinter 50%, climber 40%, etc.). Below threshold, the rider enters a hysteresis-guarded recover phase, riding sub-CP in the draft until W' is back above threshold + 10%.
- Tier 2 — Attack cooldown
- After every attack/surge the rider gets a 30–60 s refractory period (shorter for puncheurs). While in cooldown, all attack/surge decisions are suppressed. Models physiological reality: you can't attack twice in 30 seconds.
- Tier 3 — End-game prioritisation
-
Inside the last 1 km, only sprinters and puncheurs are allowed to
attack. Probabilistic breakaway triggers (pursuiter / all-rounder)
are scaled by
min(1, dist_left/5000), so attacks taper to zero in the final 5 km. - Tier 4 — Phenotype-terrain affinity
- Multiplier on tempo/steady/recover power based on (archetype, slope). Sprinter on long climb ×0.92, climber on flat ×0.97, TT on rolling ×1.02, etc. Captures "this isn't my domain" continuously, not just at attack moments.
- Tier 5 — Team-role overrides
- Tactical overlay independent of archetype. Domestique paces and never attacks; lead-out goes full gas in 1.5 km – 500 m then drops off; leader sits in draft until the final 500 m. See section 4.
- Tier 6 — Race-state awareness
- Each tick the simulator computes the live ladder score. Riders don't surge to chase teammates up the road. When the team is comfortably ahead, attacks are suppressed (×0.65 aggression); when behind in the late race, attacks are boosted (×1.30).
- Tier 7 — Per-rider decision noise
- Each rider perceives gradient, distance, and W'-fraction thresholds with small per-sim offsets (±0.6 percentage points on gradient, ±10% on distance, ±0.06 on W' fraction). Two pursuiters no longer attack at the exact same 7.0% gradient — one might go at 6.7%, the other at 7.3%.
Power-ups
Six in-game Zwift power-ups are modelled. Each rider draws one at every power-up arch on the route (frequency: every ~3 km).
Monte-Carlo variance
Each simulation draws a per-rider "day form" multiplier from
N(1, σ), clamped to [0.80, 1.20], that scales every
power output for the whole race. This is the primary source of
variance. Smaller sources: Tier 7 decision noise (per-sim), per-tick
micro-jitter (±0.5%), and probabilistic attack/breakaway triggers.
9. Data sources
Rider data — zwiftracing.app
All rider statistics come from the public profile pages at
zwiftracing.app/riders/<ID>. No login, cookie, or
API key is required — the data is in a JSON payload embedded in the
page HTML and visible to any browser. Per rider: name, weight, height,
full CP curve in W/kg from 5 s to 1200 s, Critical Power (CP) in watts,
W' (AWC) in joules, and phenotype percentile scores for the five
archetypes.
Route data — local GPX files
287 official Zwift routes, mirrored from
zwift-tracks-dl.
Each .gpx file is parsed into ~250 m segments with
average gradient and terrain classification (flat / rolling / climb /
descent / sprint). Conversion happens once per route on first use and
the result is cached.
10. Privacy and storage
Your form configuration (team names, Zwift IDs, strategy overrides,
team roles, simulations, noise) is stored in the browser's
localStorage under the key zwiftLadderTeams.
It never leaves your device unless you click Run.
When you click Run, the Zwift IDs are sent to the backend, which
fetches each rider's public profile from zwiftracing.app.
No personal information beyond the Zwift IDs you typed is transmitted.
The simulation runs server-side in memory; no rider data is persisted
on the server.
Storage is per-browser and per-format: switching between Chrome and Firefox, or between desktop and mobile, won't share your saved teams. Use the "Clear saved data" link on the form to wipe everything.