Persist the three menu fields that are not persisted, so a returning player presses one button instead of filling the form in again.
src/client/settings.ts remembers mute, volume, sensitivity, difficulty, map, the crosshair and every key binding — each one validated on the way in, so an unknown string can never reach the game. The menu (src/pages/game.ts:279-289) has three more fields that are not in that record: Name, Match (short / long, read straight off the select at main.ts:609) and Side (ct / t). So a player who always plays Competitive as a terrorist under the same name is handed Short, Counter-Terrorists and an empty box every single visit, while the map and difficulty they picked last time are right where they left them.
Done looks like
[ ] Settings gains the three fields, each guarded the way difficulty and map already are: a Side is ct or t and nothing else, a match length is one of the two rules keys, and a name is trimmed and capped at the same maxlength="24" the input carries — never a NaN, never an unknown string, never markup.
[ ] The menu loads them and writes them back on change, exactly as the map select does; main.ts:609 reads the remembered length rather than the raw select.
[ ] A name is still what the match calls you and goes nowhere near the board — this stores it in localStorage beside the other settings, and nothing about POST /api/match changes.
[ ] Settings saved before these fields existed, and a corrupt record, load as the current defaults rather than throwing: the same test settings.test.ts already makes for difficulty and map.
[ ] Tests that fail without it: each of the three round-trips through save and load; each rejects a value outside its set; an empty stored name loads as the default placeholder behaviour, not as a name.
[ ] README: the sentence under Playing that lists what is remembered gains the three.
Files I expect to change:src/client/settings.ts, src/client/settings.test.ts, src/client/main.ts, README.md.
Risks: the name is the one player-typed string in the app — it is drawn into the HUD and the scoreboard, so keep it escaped exactly where it is escaped today and do not widen the cap. Pulls #156 and #159 both touch main.ts; the change there is a handful of lines, so rebase rather than restructure.
Persist the three menu fields that are not persisted, so a returning player presses one button instead of filling the form in again.
src/client/settings.tsremembers mute, volume, sensitivity, difficulty, map, the crosshair and every key binding — each one validated on the way in, so an unknown string can never reach the game. The menu (src/pages/game.ts:279-289) has three more fields that are not in that record: Name, Match (short/long, read straight off the select atmain.ts:609) and Side (ct/t). So a player who always plays Competitive as a terrorist under the same name is handed Short, Counter-Terrorists and an empty box every single visit, while the map and difficulty they picked last time are right where they left them.Done looks like
Settingsgains the three fields, each guarded the waydifficultyandmapalready are: aSideisctortand nothing else, a match length is one of the two rules keys, and a name is trimmed and capped at the samemaxlength="24"the input carries — never a NaN, never an unknown string, never markup.main.ts:609reads the remembered length rather than the raw select.localStoragebeside the other settings, and nothing aboutPOST /api/matchchanges.settings.test.tsalready makes for difficulty and map.Files I expect to change:
src/client/settings.ts,src/client/settings.test.ts,src/client/main.ts,README.md.Risks: the name is the one player-typed string in the app — it is drawn into the HUD and the scoreboard, so keep it escaped exactly where it is escaped today and do not widen the cap. Pulls #156 and #159 both touch
main.ts; the change there is a handful of lines, so rebase rather than restructure.Brief that fits: scout.