Split The code is public; the app answers only to the crew.

The AWP's scope zooms the view but not the mouse: 40° of view turns as fast as 90°, so a scoped flick overshoots #198

Merged opened this

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

Merged

The scope now has a sensitivity of its own, and the zoom has exactly one derivation. `src/client/zoom.ts` is that place: `HIP_FOV = 90`, the scope's field of view read off the gun's `zoom` in `weapons.ts`, `screenShare(fov) = tan(fov/2) / tan(HIP_FOV/2)`, and the ratio's limits. The camera takes its FOV from the same module's `fovFor(weapon, scoped)`, so `main.ts` no longer writes 40 and 90 down a…

shipped merged

opened this

The scope now has a sensitivity of its own, and the zoom has exactly one derivation. src/client/zoom.ts is that place: HIP_FOV = 90, the scope's field of view read off the gun's zoom in weapons.ts, screenShare(fov) = tan(fov/2) / tan(HIP_FOV/2), and the ratio's limits. The camera takes its FOV from the same module's fovFor(weapon, scoped), so main.ts no longer writes 40 and 90 down a second time — that is a one-line change there.

lookDelta in input.ts is the single point where a pointer movement becomes degrees of turn: the locked mouse and a look touch both go through it, so the pad gets the scaling for free. controls.scoped is set from world.me.scoped once a frame and controls.zoomRatio from the settings, so the pause overlay's field takes hold on the very next movement, mid-scope.

The setting is zoomRatio, bounded to 0.1..1, parsed by parseSettings like sensitivity and saved with it. Its default is 0.36 — tan 20° / tan 45°, rounded to the field's step — chosen because it is the one value that is not a taste: it makes a flick cross the same share of the screen scoped and unscoped, which is what the issue is about. 1 gives back the old behaviour exactly. The field is rendered by one zoomControl(id) into both the menu row and the pause row, with min/max/value read out of zoom.ts so a control can never offer a number the parser would clamp.

What to look at in the preview: buy an AWP, right-click, and flick — then set Scope sens to 1 in the pause overlay mid-round and flick again; the menu field follows and the change is remembered. On a phone, drag while scoped. Nothing in the simulation moved: no bot turn rate, nothing in observe.ts or the policy's numbers. bun run check passes (749 tests, types clean); the scaling tests fail with the scale forced to 1, which I verified. The README's Playing section says where the number lives, and readme.test.ts now reads the default and both FOVs out of the code so a changed zoom cannot leave the README lying.

🤖 Generated with Claude Code

Closes #182

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs