Skip to content

XP and levels

Every finished race pays XP next to its cash. XP decides the player’s level, and the level decides which decals the decal shop sells; every paint, a custom colour included, is free from level 1. Levels change nothing in the race itself, and districts still open through stars and bosses (see Career). The design and the reasons behind it are in docs/2026-11-07-top-bar-and-levels-design.md.

XP is GarageState.xp, kept by the race server like cash: the game never sends it (player/garageSync.ts leaves it out).

Race XP Settled in
Career, first win 60 m, plus 20 m per star settleRace (player/career/progress.ts)
Career, boss beaten the first time 120 m the same
Career, replay with new stars 20 m per new star the same
Career, replay without new stars 20 m the same
Career, loss after crossing the line 10 m the same
Online heat, win / finished loss 40 / 15 payOnlineXp (party/src/race/onlineXp.ts)

m is the district’s weight: Street 1, Harbor 2, Chinatown 3, Strip 4. The numbers are in careerRaceXp (player/level/xp.ts). Single races, tournaments and boss fights all go through settleRace, which puts the XP on the RaceAward; each caller adds it to the garage next to the cash.

Online, the server writes the XP into each racer’s garage after it judged the heat, next to the leaderboard times. Only the first ONLINE_HEATS_PER_DAY (20) heats of a UTC day pay (settleOnlineHeat, player/level/onlineXp.ts, counter in GarageState.onlineXp), so two accounts racing each other cannot farm levels. The game reloads its garage when it leaves the online screens (net/leaveToMenu.ts).

Going from level n to n + 1 takes 100 + 25 (n - 1) XP (levelOf in player/level/xp.ts). There is no cap. Each level-up fills the fuel tank (addXp, see Fuel). Winning every career race with all stars and beating every boss pays 13,200 XP:

After XP Level
Street 1,320 8
Harbor 3,960 15
Chinatown 7,920 22
Strip 13,200 30

tests/xp.test.ts keeps the full career between level 25 and 35.

player/level/unlocks.ts lists the level each decal needs; anything not listed is free from level 1 (the number styles, two stripes and some sponsors and graphics). Paints have no level: the paint shop sells all of them, and any colour from its picker, from the start. Everything opens by level 30.

  • Decal shop. DecalPicker draws a padlock and the level over a locked decal (ui/lockBadge.ts). A locked decal can still be picked and previewed on the car; Apply then refuses with “Digital camo needs level 28.”
  • Rules. The decals garage action (player/garageActions.ts) refuses a design holding a locked decal or stripe, and the race server runs the same rules, so a modified game cannot buy one.

In the top bar, past the name and the XP bar, a shield with a car shows the level as a rank (player/level/rank.ts): the metal changes every 15 levels (bronze, silver, gold, platinum, then diamond with wings from level 61), and inside a metal the chevrons go 1, 2, 3 every 5 levels. Diamond stays at 3 chevrons from level 71 on. It is drawn in code (menu/topBar/rankBadge.ts, the shield shape in shield.ts) until there is art for it.

  • Main menu top bar (menu/topBar/): portrait, LVL n | NAME, the bar, then the rank badge and the gold achievements shield toward the next level. The name is the leaderboard nickname. Tapping the portrait opens the picker of the six racer portraits (player/portraits.ts), a free field the game syncs.
  • Result screens: the career results, tournament, boss round and pink slip screens show the XP the race earned with addXpGain (ui/xpGain.ts): the bar fills, a level-up turns the line into “LEVEL UP”, and the new decals are listed under it. Online result screens show nothing: the daily cap is applied on the server after the race.