anvilsign in

collin/mahjong · 582ad803

Build the wall as a hash, and give the whole table one tile size

Collin Richards · 2026-08-19 14:55 UTC · 582ad803c208eae202fc2ffa9355b8281dc02b25 · parent 63e2e36a · browse files

modifiedsrc/styles.css+51 −17
⋯ 30 unchanged lines
3131 contents to be cut off. */
3232 --tile-fit: calc((var(--depth) - 122px) / 2.57);
3333
34+ /* One size for every tile on the table — in a hand, in the wall, and lying in
35+ the middle. They are the same tiles, so drawing them at different sizes was
36+ always a lie, and a visible one: a tile that shrank as it was thrown read as
37+ being dropped away from you rather than skidded across a flat table.
38+
39+ Taken from whichever way round is tighter, so all four hands match rather
40+ than the side seats getting their own size off `--v-len`. */
41+ --tile-w: min(
42+ calc((var(--h-len) - 40px) / 18),
43+ calc((var(--v-len) - 40px) / 18),
44+ var(--tile-fit),
45+ 72px
46+ );
47+
3448 --felt: #0f4534;
3549 --felt-2: #0a3126;
3650 --ivory: #f6f0e2;
⋯ 118 unchanged lines
155169 overflow: hidden;
156170 transition: background 0.2s;
157171 }
172+/* `--tile-w` is the table's, set once in :root — a seat only says how long its
173+ own strip is. */
158174 .slot-bottom .seat,
159175 .slot-top .seat {
160176 width: var(--h-len);
161- --tile-w: min(calc((var(--h-len) - 40px) / 18), var(--tile-fit), 72px);
162177 }
163178 .slot-left .seat,
164179 .slot-right .seat {
165180 width: var(--v-len);
166- --tile-w: min(calc((var(--v-len) - 40px) / 18), var(--tile-fit), 72px);
167181 }
168182 .seat.active {
169183 background: linear-gradient(to top, rgba(217, 180, 92, 0.22), transparent 70%);
⋯ 430 unchanged lines
600614 }
601615 /* The wall: a square of four staggered sides, 18 stacks of two each, drawn
602616 with the tileset's own blank tile. Sits behind the centre readout. */
617+/* The wall, built the way it is built on a table: four walls of eighteen stacks
618+ laid out like a # rather than mitred into a closed square. Each one runs the
619+ full eighteen and overhangs the corner of the next, which leaves the corners
620+ open and — the point of it — means the opening in the middle no longer has to
621+ be as long as a wall. That is what lets every tile on the table be the same
622+ size: a closed square of eighteen full-size stacks a side needs about 560px in
623+ the middle, which most windows have not got, so something had to shrink. Here
624+ the tails simply run out under the players' strips instead.
625+
626+ `.wall-ring` is the opening, not the outside: the sides hang off its edges. */
603627 .wall-ring {
604628 position: absolute;
605629 top: 50%;
606630 left: 50%;
607- --ring: min(calc(100vh - 2 * var(--depth) - 16px), calc(100vw - 2 * var(--depth) - 16px), 560px);
608- --ws: calc(var(--ring) / 19.375);
631+ --ws: var(--tile-w);
609632 --wd: calc(var(--ws) * 1.375);
633+ --wall-len: calc(var(--ws) * 18);
634+ --ring: min(
635+ calc(100vh - 2 * var(--depth) - 16px),
636+ calc(100vw - 2 * var(--depth) - 16px),
637+ var(--wall-len)
638+ );
639+ /* How far a wall runs past the opening. Nothing at all once the middle is big
640+ enough to take a whole wall, which is when a plain square is right anyway. */
641+ --over: calc(var(--wall-len) - var(--ring));
610642 width: var(--ring);
611643 height: var(--ring);
612644 transform: translate(-50%, -50%);
⋯ 4 unchanged lines
617649 position: absolute;
618650 display: flex;
619651 }
620-/* Pinwheel: each side starts where the previous one ended. */
652+/* Each wall sits outside its edge of the opening and overhangs one end of it,
653+ the same way round each time — which is what turns four straight walls into a
654+ pinwheel with its corners open. */
621655 .wall-side.top {
622- top: 0;
623- left: var(--wd);
624- right: 0;
656+ top: calc(-1 * var(--wd));
657+ left: calc(-1 * var(--over));
658+ width: var(--wall-len);
625659 height: var(--wd);
626660 }
627661 .wall-side.right {
628- top: var(--wd);
629- right: 0;
630- bottom: 0;
662+ right: calc(-1 * var(--wd));
663+ top: calc(-1 * var(--over));
631664 width: var(--wd);
665+ height: var(--wall-len);
632666 flex-direction: column;
633667 }
634668 .wall-side.bottom {
635- bottom: 0;
636- left: 0;
637- right: var(--wd);
669+ bottom: calc(-1 * var(--wd));
670+ right: calc(-1 * var(--over));
671+ width: var(--wall-len);
638672 height: var(--wd);
639673 flex-direction: row-reverse;
640674 }
641675 .wall-side.left {
642- top: 0;
643- left: 0;
644- bottom: var(--wd);
676+ left: calc(-1 * var(--wd));
677+ bottom: calc(-1 * var(--over));
645678 width: var(--wd);
679+ height: var(--wall-len);
646680 flex-direction: column-reverse;
647681 }
648682 .wall-stack {
⋯ 1288 unchanged lines
modifiedsrc/table/geometry.ts+9 −9
⋯ 68 unchanged lines
6969 const stacks = wallStacks(state);
7070 const walls: Rect[] = [];
7171 // A stack element is --ws by --wd (or the other way round on the left and
72- // right sides), which gives us both the tile size and the wall's thickness
73- // without knowing either number.
72+ // right sides), so its narrower side is the tile's width whichever wall it is
73+ // in — the fallback for sizing a pool tile before any hand has been dealt.
7474 let short = 0;
75- let long = 0;
7675 for (const el of ring.querySelectorAll<HTMLElement>('[data-stack]')) {
7776 const i = Number(el.dataset.stack);
7877 const r = local(el.getBoundingClientRect());
7978 short = Math.max(short, Math.min(r.w, r.h));
80- long = Math.max(long, Math.max(r.w, r.h));
8179 const stack = stacks[i];
8280 if (stack && isBarrier(stack)) walls.push(r);
8381 }
8482 if (short === 0) return null;
8583
86- // The pool is the square the wall encloses, less the wall's own thickness.
84+ // `.wall-ring` is the opening itself — the walls hang off its edges — so the
85+ // pool is simply its box. (It used to be the wall's outside, which is why this
86+ // had to subtract the wall's own thickness.)
8787 const ringRect = local(ring.getBoundingClientRect());
8888 const pool: Rect = {
89- x: ringRect.x + long,
90- y: ringRect.y + long,
91- w: Math.max(short, ringRect.w - long * 2),
92- h: Math.max(short, ringRect.h - long * 2),
89+ x: ringRect.x,
90+ y: ringRect.y,
91+ w: Math.max(short, ringRect.w),
92+ h: Math.max(short, ringRect.h),
9393 };
9494
9595 const launch: Partial<Record<SeatId, Point>> = {};
⋯ 155 unchanged lines