Achievements
Achievements are badges only: they pay no cash, XP or items. An achievement is done while its condition holds on the save, so nothing records the moment it unlocks. Old saves get theirs as soon as the game loads, and the race server and the game can never disagree about them. The design is in docs/2026-11-08-achievements-inbox-design.md.
The rules
Section titled “The rules”player/achievements/ holds the list, with no Phaser, so the server could run it too. Each entry is { id, name, description, icon, done(state) }:
careerAchievements.ts: first win, each district’s boss, every star in each district (the “sweep”), and all four bosses. Bosses are named by district, so a locked badge gives nothing of the story away.garageAchievements.ts: owning 3 and 5 cars, a car with every part insim/upgrades.tsfitted, a repainted car, a car with decals, and 1, 10 and 50 online wins.
Adding one is a new entry in either file. tests/achievements.test.ts checks the ids are unique and that a new game has none.
Online wins
Section titled “Online wins”The save does not otherwise know how many online races a player won, so settleOnlineHeat (player/level/onlineXp.ts) adds one to onlineWins when the race server pays the XP for a won heat. It counts only heats inside the daily XP cap (20 a day), so two accounts racing each other cannot farm the badge. The game’s sync never sends the field (player/garageSync.ts): only the server writes it.
Where the player sees it
Section titled “Where the player sees it”- Top bar (
menu/topBar/achievementsButton.ts): the gold shield with a star next to the rank badge opens the screen. - Achievements screen (
achievements/scenes/Achievements.ts, its own feature module): every badge in a grid, done ones lit gold, with the count done at the top. The glyphs are drawn in code (achievements/view/achievementIcons.ts) until there is art.