Hold'em dealer: 55 polish rounds, one merge #101

Merged
jheaps merged 71 commits from release/casino-holdem-polish into master 2026-09-02 10:00:15 -06:00
2 changed files with 79 additions and 3 deletions
Showing only changes of commit 3d1ce1f45c - Show all commits
+48 -3
View File
@@ -308,9 +308,22 @@ button,
#pokerTableWrap {
position: relative;
/* The shape is stated once, and both the height and the cap below are derived from
it. It used to be a `padding-bottom: 72%` box, which has a trap in it: percentage
padding resolves against the *containing block's* width, not the element's own,
so narrowing the wrap left it exactly as tall as before. Capping the width was
therefore no way to shorten the table — measured, after trying it: the felt went
822px wide to 746px and stayed 617px tall, and the bottom seat sat as far into
the action bar as it had. aspect-ratio ties the two together properly. */
--feltAspect: 0.72;
width: 100%;
padding-bottom: 72%;
aspect-ratio: 1 / var(--feltAspect);
margin: 0 auto;
/* Capping the width is how the felt is told to stay above the action bar.
--feltRoomPx is published by actionBar.js with the bar's real height and the
bottom seat's overhang already taken out; the fallback leaves the table its full
size if that ever fails to arrive. */
max-width: calc(var(--feltRoomPx, 100vh) / var(--feltAspect));
}
@@ -2126,6 +2139,23 @@ body.hasActionBar #holdemSidebar {
margin-top: 0.1rem;
}
/* "ALL IN" takes the stack line's place, so it has to not read as a stack. Wider
letters and a warm colour separate it from the grey money above it at a glance —
which is the whole job, because the dealer is scanning the ring for who can still
be bet at. */
.seatPuckStack.seatPuckAllIn {
color: #ffcf6b;
font-weight: 700;
letter-spacing: 0.06em;
}
/* And the seat itself carries a hint of it, so the mark survives being read out of
the corner of an eye. Deliberately quieter than .seatActing — all-in is a standing
fact about a player, not a request for the dealer's attention. */
.seat.seatAllIn {
border-color: rgba(255, 207, 107, 0.45);
}
/* Tournament-sized amounts. A number has no spaces to break on, so an amount too
wide for the 64px puck neither wraps nor ellipsises — it draws straight out over
the seat next to it. These step the size down so every digit stays on its own
@@ -2504,6 +2534,16 @@ body.hasActionBar #toastHost {
}
@media (max-width: 700px) {
/* The narrow layout already had an answer for the bar: it reserves the bar's height
as scroll room below the table, and a phone is a thing you scroll. Capping the
felt here as well was measured and rejected — at 360x640 it took the table from
321px to 226px, which fixed the six-seat ring but broke the nine-seat one, two
covered seats traded for two seats whose centre landed on a neighbour. The cap is
for the wide layout, which never consulted the bar's height at all. */
#pokerTableWrap {
max-width: none;
}
/* Stacked, with the action that ends the hand furthest from a stray thumb. */
.potWizardActions {
flex-direction: column-reverse;
@@ -2519,8 +2559,9 @@ body.hasActionBar #toastHost {
grid-template-columns: 1fr;
}
/* One column, so the table has the full width and can afford to be round. */
#pokerTableWrap {
padding-bottom: 100%;
--feltAspect: 1;
}
.seat {
@@ -2845,7 +2886,11 @@ body.hasActionBar #toastHost {
width: 100%;
height: var(--feltRoom);
min-height: 7rem;
padding-bottom: 0;
/* This branch sets its own height outright, so neither the aspect ratio nor the
cap derived from it has anything to say here — and the cap would only narrow
a table that is already as short as the screen allows. */
aspect-ratio: auto;
max-width: none;
}
/* The header ate 148px of a 390px-tall window, which was most of the reason the
@@ -29,6 +29,7 @@ const ActionBar = {
const visible = !host.hidden;
const height = visible ? host.getBoundingClientRect().height : 0;
document.documentElement.style.setProperty("--actionBarHeight", `${Math.round(height)}px`);
this.publishFeltRoom(height);
};
if (typeof ResizeObserver === "function") {
@@ -40,6 +41,36 @@ const ActionBar = {
publish();
},
// Half a seat, the gap left under the lowest one, and the smallest felt worth
// drawing. A seat is about 73px tall at every width — the puck is text-sized, not
// table-sized — so the overhang is a constant rather than something read back off
// the layout this is about to change. Measuring it would mean shrinking the felt,
// moving the seats, and getting a different answer on the next pass.
SEAT_OVERHANG_PX: 37,
FELT_GAP_PX: 8,
FELT_MIN_PX: 220,
// How tall the felt can be and still leave the whole ring of seats above the bar.
//
// Publishing the bar's height was only half the job. The wide layout never used it:
// the felt sizes itself from its own width — a box 72% as tall as it is wide — and
// so has no idea what is underneath it. The bar meanwhile grows with the hand, from
// 117px to 172px the moment there's a side pot to show, which is exactly when the
// dealer most needs to see who is still in. Measured with two side pots, the bottom
// seat sat 22px into the bar at 1280x900, 54px at 1600x1000, 23px at 768x1024.
//
// The wrap's offset is taken in document space rather than viewport space, so
// scrolling the page doesn't resize the table under the dealer's hands.
publishFeltRoom(barHeight) {
const wrap = document.getElementById("pokerTableWrap");
if (!wrap) return;
const topInDocument = wrap.getBoundingClientRect().top + window.scrollY;
const room = window.innerHeight - barHeight - topInDocument -
this.SEAT_OVERHANG_PX - this.FELT_GAP_PX;
document.documentElement.style.setProperty(
"--feltRoomPx", `${Math.max(this.FELT_MIN_PX, Math.round(room))}px`);
},
// Anything to act on? A hand with nobody dealt in doesn't get a bar — and that
// still holds during setup, because a seated player is a live seat whether or not
// the betting has been opened. An empty table stays uncluttered.