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

forked from trevato/cs

Crisp at 125%: a fractional device pixel ratio keeps the crosshair centred and the HUD sharp #311

Closed opened this
opened this

Windows ships display scaling at 125% and 150% far more often than anything else does, and this app has never been looked at under one. The drawing buffer is Math.round(clientWidth * dpr) (src/engine/renderer.ts:295-297) while every 2D overlay is drawn in CSS pixels scaled by the same ratio (src/client/main.ts:872, :1270, src/range/main.ts:266, src/example/main.ts:116) — so at 1.25 a one-pixel crosshair line lands on a quarter of a pixel, a centred cross is half a pixel off centre, and text is resampled. On a 1.0 laptop none of that shows, which is why it reads as "buggy on Windows" rather than as "blurry everywhere".

This is the cheapest of the #307 issues and the most visible: the crosshair is the one thing a player stares at for an hour.

Done looks like

  • [ ] The crosshair is exact: its centre is the canvas's centre in device pixels, and its arms are a whole number of device pixels wide, at 1, 1.25, 1.5, 2 and 3 — computed, not nudged. A one-pixel line is one pixel, on the pixel.
  • [ ] The HUD's text and bars are laid out so that a fractional ratio does not resample them: state the rule chosen (round the backing store, snap positions to device pixels, or draw at a whole-number scale and let the layout breathe) and why, in the module's own comment.
  • [ ] No layout shift and no stretch: the canvas's CSS size is untouched, the aspect ratio is exact, and a window resized to an odd width does not leave a seam at the right edge.
  • [ ] The same treatment for all three games, because all three draw an overlay this way, and the arithmetic lives in one place rather than four.
  • [ ] Tests that would fail without this: the crosshair's drawn coordinates, recorded through the existing paint recorder, are whole device pixels and symmetrical about the centre at each of the five ratios; a 1.25 ratio and a 1.0 ratio both put the centre exactly in the middle; the backing-store size stays what the renderer chose.
  • [ ] The pull says what it looked like before and after at 125% — the one place a screenshot earns its bytes.

Files I expect to change

src/client/hud.ts, src/client/main.ts, src/range/readout.ts, src/range/main.ts, src/example/main.ts, possibly src/engine/overlay.ts if the snapping belongs behind the door (say which and why), and the tests beside each.

Risks

  • #297 gives the renderer a pixel scale it picks from the frame time, which multiplies the very ratio this issue is about. Whichever lands second must keep the other's guarantee: the overlay is not scaled by the adaptive factor, and the pull says how that was checked.
  • Snapping the wrong thing makes the HUD jitter as it animates. Snap the crosshair and the static furniture; do not snap a moving bar's fill.

Suggested: Vesper.

commented

Delivered by #329 (be13c27): src/engine/pixels.ts is the one place that says how big a backing store is and where a bar of pixels starts, the overlay draws in device pixels, and the crosshair is held whole at 1, 1.25, 1.5, 2 and 3. Closing.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs