scale by whole pixels, and make the stage small enough to matter
Two halves of the same problem: the picture was sharp everywhere and wrong overall. ── whole-number scaling ── The canvas is now sized to the largest WHOLE number of device pixels per source pixel that fits the panel, measured with a ResizeObserver and the device pixel ratio. Below 1x it takes a unit fraction instead, so the rows that survive are evenly spaced rather than dropped in clumps. This is a 16px-per-cell bitmap from 1995. At a fractional scale one cell gets three screen pixels and its neighbour gets two, the grid goes uneven and the digits wobble — which reads as "not quite right" rather than as blur, and `image-rendering: pixelated` does not help because unevenness is not blur. A fractional devicePixelRatio produces exactly this at what looks like 1:1. It is also allowed to scale UP past the framebuffer's own size, which was the other half of it: `max-w-full` only ever shrinks, so on a wide panel the canvas sat at its intrinsic size using a fraction of the pixels available. ── a smaller stage ── 800x600 down to 560x400. The stage is what gets scaled to fill the panel, so every pixel of empty surround is panel the game does not get, and the whole- number steps are far apart: in an 1866-device-pixel panel, 800 wide lands on 2x and 560 wide lands on 3x. Same panel, half again as much game. 560x400 is expert (504x342, measured on this machine) plus a margin. A custom board bigger than the stage is now clipped at the right and bottom rather than shrunk; `centre` clamps at zero so the menu bar stays reachable. Widen the two constants if that turns out to be the wrong trade. Verified: beginner centres at 204,93 on the new stage, which is exact. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Officer-Session: de3ed4e6-f88a-429c-94e6-a760336ba83b
This commit is contained in:
+14
-4
@@ -47,11 +47,21 @@ export type SessionStatus = {
|
||||
* player mid-game, and it was wrong by the 3x29 wine puts between the root origin and the window, which
|
||||
* showed as a black strip on top and a row of cut-off cells at the bottom.
|
||||
*
|
||||
* 800x600 is generous on beginner and that is deliberate: it holds the largest board Minesweeper X can
|
||||
* make (30x24 custom, 504x470) with room to spare, so no difficulty ever reaches an edge.
|
||||
* ── Why it is this small ──
|
||||
*
|
||||
* The stage is what gets scaled to fill the panel, so every pixel of empty surround is panel the game
|
||||
* does not get. The client scales by whole numbers only — fractional scaling makes a 16px grid uneven —
|
||||
* so the size here decides which step it lands on, and the steps are far apart. In a 1866-device-pixel
|
||||
* panel: 800 wide gives 2x, 560 wide gives 3x. Same panel, half again as much game.
|
||||
*
|
||||
* 560x400 is expert (504x342) plus a margin, which is what the three standard difficulties need. A
|
||||
* CUSTOM board larger than this is clipped at the right and bottom edges rather than shrunk — `centre`
|
||||
* clamps at zero so the menu bar stays reachable. That is the trade: the sizes people actually play are
|
||||
* as large as they can be, and the one that is not is still playable. Widen these two numbers if that
|
||||
* turns out to be the wrong way round.
|
||||
*/
|
||||
const SCREEN_W = 800;
|
||||
const SCREEN_H = 600;
|
||||
const SCREEN_W = 560;
|
||||
const SCREEN_H = 400;
|
||||
|
||||
/**
|
||||
* How often to check whether the board changed size.
|
||||
|
||||
Reference in New Issue
Block a user