Put mute, volume, look sensitivity and a scope control where a player can reach them mid-match, because two of those cannot be changed at all today and the third does not exist on a phone.
What is wrong:
src/client/audio.ts:18 declares muted and nothing in the repository ever writes it; there is no volume anywhere. The game opens loud and stays loud.
src/client/main.ts reads #sens once in start(). You find out the sensitivity is wrong after the match has begun, and the only way to change it is to leave.
input.ts raises the scope action from a right mouse button under pointer lock only — KEY_ACTIONS has no scope key and #touch has no scope button — so on a touch screen the AWP, the one gun with zoom, can never be scoped.
Done looks like:
[ ] The pause overlay carries settings: mute/volume and look sensitivity, both taking effect immediately, without leaving the match.
[ ] Both persist in localStorage beside cs.name, are read at boot, and are validated on the way in — a missing, malformed or out-of-range value falls back to the default and never puts NaN into controls.sensitivity.
[ ] Volume is one gain node the whole of audio.ts goes through, not a multiplier copied into each sound; mute is silence, not a quieter gun. A volume set before the first click survives ensure() creating the context.
[ ] A scope control a thumb can reach: a button in #touch and a key binding, both going through the same setAction("scope", …) and both held rather than toggled, so they behave like the mouse.
[ ] Every new control is at least 44px, keyboard-reachable, and the pause overlay still works at 360px wide with no horizontal scroll.
[ ] The menu's existing sensitivity field and the in-match one agree — one source of truth, not two.
[ ] Tests: reading and validating the stored settings is a pure function with a test (missing, bad, out of range), and the press/input tests cover scope arriving from a button.
[ ] bun test passes.
Files:src/pages/game.ts (the pause overlay and the touch pad), src/client/main.ts, src/client/audio.ts, src/client/input.ts, a small src/client/settings.ts and its test.
Risks: the pause overlay is a dialog over a live match — a key press in one of its fields must not reach the game, and the existing blur / press.clear() path is what keeps that honest. Don't grow the bundle noticeably for four controls. Don't put a settings panel on the menu and on pause with two separate implementations.
Put mute, volume, look sensitivity and a scope control where a player can reach them mid-match, because two of those cannot be changed at all today and the third does not exist on a phone.
What is wrong:
src/client/audio.ts:18declaresmutedand nothing in the repository ever writes it; there is no volume anywhere. The game opens loud and stays loud.src/client/main.tsreads#sensonce instart(). You find out the sensitivity is wrong after the match has begun, and the only way to change it is to leave.input.tsraises thescopeaction from a right mouse button under pointer lock only —KEY_ACTIONShas no scope key and#touchhas no scope button — so on a touch screen the AWP, the one gun withzoom, can never be scoped.Done looks like:
localStoragebesidecs.name, are read at boot, and are validated on the way in — a missing, malformed or out-of-range value falls back to the default and never putsNaNintocontrols.sensitivity.audio.tsgoes through, not a multiplier copied into each sound; mute is silence, not a quieter gun. A volume set before the first click survivesensure()creating the context.scopecontrol a thumb can reach: a button in#touchand a key binding, both going through the samesetAction("scope", …)and both held rather than toggled, so they behave like the mouse.press/inputtests coverscopearriving from a button.bun testpasses.Files:
src/pages/game.ts(the pause overlay and the touch pad),src/client/main.ts,src/client/audio.ts,src/client/input.ts, a smallsrc/client/settings.tsand its test.Risks: the pause overlay is a dialog over a live match — a key press in one of its fields must not reach the game, and the existing
blur/press.clear()path is what keeps that honest. Don't grow the bundle noticeably for four controls. Don't put a settings panel on the menu and on pause with two separate implementations.Suggested: scout.