Stop re-typing the layout audit into a console every round #53

Closed
jheaps wants to merge 1 commits from feature/casino-holdem-layout-audit into feature/casino-holdem-blind-fairness
Owner

Last round I found a regression I'd shipped two rounds earlier — the standings table's player-name column at zero pixels wide, at every viewport. It survived because the audit that would have caught it only existed in a previous session's scrollback. These checks have been re-written by hand at least six times, and each time they covered only whatever had just changed. Stacked on #52.

So they're a file now. uiAudit.js runs in the page — no build step, no package.json, no dependency — and runUiAudit.js drives it over the table, all five overlays and Quick Split at thirteen viewports.

node tests/holdem/runUiAudit.js

Deliberately outside CI: the unit suite is dependency-free and runs in a second, this needs a browser and a running site. No Playwright to hand? Paste uiAudit.js into devtools and call LayoutAudit.runAll().

Three real faults it found on its first run

Fields were 13.3px on every iPad. The 16px minimum that stops iOS zooming the page on focus went in inside a max-width: 700px block — and every iPad is wider than that. So a dealer on a tablet, the device this is most likely to be propped up on, got the table zoomed every time they touched the blind amount. The reason for that rule was never "narrow screen", it was "iOS". Font size applies at all widths now, and the 44px touch targets key off hover: none, which is what actually distinguishes a finger from a mouse.

The seat menu couldn't be scrolled. No height limit, no overflow — so on a phone held sideways its first two actions, Fold and All-in, sat below the bottom of the screen with no way to reach them. A dealer in landscape could long-press a seat and then not fold it.

The pot wizard sat under the action bar. Every other overlay is z-index 90–98; the wizard alone was at 50, below both the action bar (55) and the toast (80). In landscape one of its inputs was completely covered by the Fold button, and a toast could sit over "Confirm Winner(s)". The odd one out rather than a decision.

Three faults in the audit itself

Recording these because each would have had me "fix" something that wasn't broken:

  • An ellipsised name looked like it was painting outside its seat. A Range measures laid-out text, which runs past the element while overflow: hidden quietly clips it. Only overflow that's actually visible can paint over a neighbour.
  • Every link below the fold was reported as off-screen. Something under the fold on a page that scrolls is perfectly reachable. The check now asks whether scrolling can bring it into view.
  • A button in the newly-scrollable seat menu came back "covered by null". elementFromPoint returns null for a point outside a scrollable ancestor's clip — scrolled out of view, not covered by anything.

A toast partly over a control is a warning now rather than a failure: it dismisses itself, carries a close button, and on a desktop necessarily lands over a table that fills the content column. Fully covered by a toast is still a failure — that was a real bug once, where a seat sat exactly under the Undo button.

Validation

Final sweep: 13 viewports · 65 overlay checks · 13 full-page audits · 4 Quick Split audits — zero failures, one warning (the desktop toast overlap above, correctly classified). 137 unit tests still passing. No console errors.

Last round I found a regression I'd shipped **two rounds earlier** — the standings table's player-name column at zero pixels wide, at every viewport. It survived because the audit that would have caught it only existed in a previous session's scrollback. These checks have been re-written by hand at least six times, and each time they covered only whatever had just changed. Stacked on #52. So they're a file now. `uiAudit.js` runs in the page — no build step, no `package.json`, no dependency — and `runUiAudit.js` drives it over the table, all five overlays and Quick Split at thirteen viewports. ```bash node tests/holdem/runUiAudit.js ``` Deliberately outside CI: the unit suite is dependency-free and runs in a second, this needs a browser and a running site. No Playwright to hand? Paste `uiAudit.js` into devtools and call `LayoutAudit.runAll()`. ## Three real faults it found on its first run **Fields were 13.3px on every iPad.** The 16px minimum that stops iOS zooming the page on focus went in inside a `max-width: 700px` block — and every iPad is wider than that. So a dealer on a tablet, the device this is most likely to be propped up on, got the table zoomed every time they touched the blind amount. The reason for that rule was never "narrow screen", it was "iOS". Font size applies at all widths now, and the 44px touch targets key off `hover: none`, which is what actually distinguishes a finger from a mouse. **The seat menu couldn't be scrolled.** No height limit, no overflow — so on a phone held sideways its first two actions, **Fold and All-in**, sat below the bottom of the screen with no way to reach them. A dealer in landscape could long-press a seat and then not fold it. **The pot wizard sat under the action bar.** Every other overlay is z-index 90–98; the wizard alone was at **50**, below both the action bar (55) and the toast (80). In landscape one of its inputs was completely covered by the Fold button, and a toast could sit over "Confirm Winner(s)". The odd one out rather than a decision. ## Three faults in the audit itself Recording these because each would have had me "fix" something that wasn't broken: - **An ellipsised name looked like it was painting outside its seat.** A `Range` measures *laid-out* text, which runs past the element while `overflow: hidden` quietly clips it. Only overflow that's actually visible can paint over a neighbour. - **Every link below the fold was reported as off-screen.** Something under the fold on a page that scrolls is perfectly reachable. The check now asks whether scrolling can bring it into view. - **A button in the newly-scrollable seat menu came back "covered by null".** `elementFromPoint` returns null for a point outside a scrollable ancestor's clip — scrolled out of view, not covered by anything. A toast partly over a control is a **warning** now rather than a failure: it dismisses itself, carries a close button, and on a desktop necessarily lands over a table that fills the content column. *Fully* covered by a toast is still a failure — that was a real bug once, where a seat sat exactly under the Undo button. ## Validation Final sweep: **13 viewports · 65 overlay checks · 13 full-page audits · 4 Quick Split audits — zero failures**, one warning (the desktop toast overlap above, correctly classified). 137 unit tests still passing. No console errors.
jheaps added 1 commit 2026-09-01 08:32:03 -06:00
Last round I found a regression I'd shipped two rounds earlier: the standings
table's player-name column was zero pixels wide, at every viewport, and nobody
noticed because the audit that would have caught it only ever existed in a
previous session's scrollback. These checks have been re-written by hand at least
six times, and each time they covered only whatever had just changed.

So they're a file now. uiAudit.js runs in the page — no build step, no
package.json, no dependency — and checks touch-action and tap highlights, that
fields stay selectable and are big enough not to trigger iOS zoom, that nothing
important is covered or stranded off-screen, that no grid column has collapsed to
nothing, and that no text is painted outside its box. runUiAudit.js drives it over
the table, all five overlays and Quick Split at thirteen viewports. Deliberately
outside CI: the unit suite is dependency-free and runs in a second, this one needs
a browser and a running site.

Three real faults it found on its first run

Fields were 13.3px on every iPad. The 16px minimum that stops iOS zooming the page
on focus went in inside a max-width:700px block, and every iPad is wider than
that — so a dealer on a tablet, which is the device this is most likely to be
propped up on, got the table zoomed every time they touched the blind amount. The
reason for that rule was never "narrow screen", it was "iOS". Font size applies at
all widths now, and the 44px touch targets key off hover:none, which is what
actually distinguishes a finger from a mouse.

The seat menu couldn't be scrolled. It had no height limit and no overflow, so on
a phone held sideways its first two actions — Fold and All-in — sat below the
bottom of the screen with no way to reach them. A dealer in landscape could
long-press a seat and then not fold it.

The pot wizard sat under the action bar. Every other overlay is z-index 90-98; the
wizard alone was at 50, below both the action bar at 55 and the toast at 80. In
landscape one of its inputs was completely covered by the Fold button, and a toast
could sit over "Confirm Winner(s)". It was the odd one out rather than a decision.

Three faults in the audit itself, found by checking before acting

Worth recording, because each would have had me "fix" something that wasn't broken:

- an ellipsised name was reported as painting outside its seat. A Range measures
  laid-out text, which runs past the element while overflow:hidden quietly clips
  it. Only overflow that is actually visible can paint over a neighbour.
- every link below the fold was reported as off-screen. Something under the fold on
  a page that scrolls is reachable; the check now asks whether scrolling can bring
  it into view, which is the thing that actually matters.
- a button in the newly-scrollable seat menu came back "covered by null".
  elementFromPoint returns null for a point outside a scrollable ancestor's clip —
  scrolled out of view, not covered by anything.

A toast partly over a control is a warning rather than a failure now: it dismisses
itself and carries a close button, and on a desktop it necessarily lands over a
table that fills the content column. Fully covered by a toast is still a failure,
because that was a real bug once — a seat sat exactly under the Undo button.

Final sweep: 13 viewports, 65 overlay checks, 13 full-page audits, 4 Quick Split
audits, zero failures, one warning. 137 unit tests still passing.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015bnp7xKUPFFSpwkYNFaPgb
jheaps closed this pull request 2026-09-01 09:32:18 -06:00

Pull request closed

Please reopen this pull request to perform a merge.
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: jheaps/JoshHeaps.Net#53