Public: anyone can read this; the crew can change it.

forked from trevato/cs

Aiming while scoped is the same hand: the sensitivity scales with the zoom, the way Counter-Strike's does #231

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

Pulling up the scope no longer doubles your sensitivity. `src/client/look.ts` is the new module: the two fields of view this game is seen through (90° across, 40° through the scope), `zoomScale(fov, fovDefault) = tan(fov/2) / tan(fovDefault/2)` — unitless, degrees in — and `lookAt(delta, fov, fovDefault)`, a look delta in degrees in and a look delta out. `main.ts` applies it where it reads the loo…

shipped production is serving it deploy ae07c2d

opened this

Pulling up the scope no longer doubles your sensitivity. src/client/look.ts is the new module: the two fields of view this game is seen through (90° across, 40° through the scope), zoomScale(fov, fovDefault) = tan(fov/2) / tan(fovDefault/2) — unitless, degrees in — and lookAt(delta, fov, fovDefault), a look delta in degrees in and a look delta out. main.ts applies it where it reads the look, to yaw and pitch alike, so the engine's controls still hand back plain degrees and still know nothing about scopes.

Unscoped the scale is exactly 1 (t / t is 1 to the bit in IEEE 754), so lookAt returns the delta byte-for-byte and a player's Sensitivity setting means what it always did; the golden digests are untouched, because the mouse is input and not simulation. Coming out of the scope, the frame whose steps unscope you is the last one scaled — that is the frame the mouse moved under — and the next movement is the plain sensitivity, with no jump in the view, since all any of this scales is a delta. spectate.ts now takes its 40 and 90 from look.ts instead of keeping a second copy, so a second zoom level is one constant in one place and every function here takes a field of view rather than a boolean.

Worth looking at: src/client/look.test.ts, where the hand calculation is written out — 10 counts at 2.2°/count is 22° unscoped and 22 × 0.3639702342662024 = 8.0073° scoped — plus a check that both turns cross the same fraction of their own screen, and the 2.747× the bug used to give. src/client/main.test.ts plays it end to end through the right mouse button on an AWP at the menu's real 0.484° per 10 counts. bun run test (typecheck + 995 tests) passes, and static/app.df3a822521.js is rebuilt, 89,174 B raw against its 98,000 ceiling. I did not touch the unscoped feel, and I did not make the camera read the AWP's own zoom field — today it is the same 40, and making the fov per-weapon means changing the camera and the scale together, which is a larger change than this issue.

🤖 Generated with Claude Code

Closes #136

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs