1f3dda180f04101d0e5e81d0d5b8c738aacfaf17
Looked at the felt at three times scale and the seats were falling off it. Not
sitting at a rail — hanging past the outer edge of the table into the page,
half a puck on green and half on nothing. Measured:
1280x900, nine-handed five of nine seats past the rail, worst 49px
844x390, six-handed all six, worst 20px
430x932, six-handed two, worst 12px
360x640, nine-handed none
The ring sat at a flat 44% by 42% of the seat layer at every size, two numbers
picked against a phone. A fixed pair can only be right for one ratio of puck to
felt, and the felt's ratio changes with every viewport — so it was a different
amount of wrong on each one, which is exactly what makes something look like a
mistake rather than a choice.
The radius is derived now: the widest ring whose outermost seat still finishes
inside the table, worked out from the measured table, seat layer and puck. It
can only ever pull seats in — the old pair is kept as the ceiling — and it falls
back to that pair whenever there is nothing to measure, which is every call from
the unit tests and the first render before the felt is laid out.
Three things this turned up on the way, each caught by the sweep:
* The seat layer is not centred on the table. Its insets differ top from
bottom, so the first version — which assumed symmetry and worked from half
widths — left a phone with 12px still over the rail. It works in absolute
pixels against the nearer edge now.
* The radius and the puck size depend on each other: the ring is limited by
how big a puck is, the puck is sized by the `seatsTight` class, and that
class was decided from the gaps between seats, measured at a radius that
hadn't been worked out yet. Fixing the gap measurement then made a
nine-handed phone overhang that had been fine, because the two were chasing
each other. It is settled by trying the candidates in preference order
instead: the roomy layout if everything fits, the tight one if not, and if
neither fits, tight pucks on a ring widened only as far as it takes to stop
seats colliding — because two seats fighting over a tap is a worse failure
than a puck over the rail. A dealer can see an overhang; they cannot see
that the seat they pressed wasn't the one that answered.
* The spacing threshold was a flat 84px, the figure a 96px puck was judged
against. Asking a 68px tight puck to keep a 96px puck's distance is a test
it can never pass, so every landscape table fell through to the fallback and
took an overhang it didn't need. It is a ratio now, not a number.
Result: worst overhang anywhere goes 49px to 9px, and 59 of 65 configurations
are completely clean. Desktop, tablet and every phone held upright: nothing over
the rail at all.
Residual, reported rather than tuned away: six configurations still overhang by
1-9px, all of them landscape at 640x360 and 667x375, where the felt is about
110-125px tall and no ring puts readable pucks inside that. The audit check is
left strict so they stay visible.
uiAudit gains "seats and chips stay on the table", which runs at every viewport
in the sweep. Fault-injected: putting the flat 44/42 back reproduces the original
failure exactly, including seat 3 at 49px.
Faster, too, because the measuring got hoisted out of the per-seat loops while I
was in there:
renderSeats 7.3ms -> 1.8ms
renderAll 12.4ms -> 6.8ms
619 tests, 0 failures. 65 layout audits across 13 viewports x 5 table sizes.
Offline re-verified: a whole hand with the network cut, $800 conserved.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015bnp7xKUPFFSpwkYNFaPgb
Description
No description provided
142 MiB
Languages
JavaScript
68.4%
CSS
14.1%
C#
8%
HTML
4.5%
C++
4.4%
Other
0.5%