v0.8.0.6 — your move waits its turn, the lit pile keeps asking to be looked at

Your actions are put away while the board is catching up. The board on screen is
behind the game, so a move offered there is a move against a position that has
already moved on — and the screen had grown to four things competing at once: the
district, the history, the catching-up row, and a lit pile. Skip is one click away,
so the wait stays voluntary.

That could have locked a player out of their own game. Hiding actions behind busy()
makes that flag the thing standing between a player and their turn, and without
requestAnimationFrame nothing ever advances the queue — so busy() would never
clear. Caught by the DOM-stub test that has been proving this page still starts
since long before any of this existed. No rAF now means draw everything at once,
which is what pace 0 does deliberately, and a queue that throws empties itself
rather than stranding anyone.

The lit pile was never brief: measured, it stays lit for 6997ms at 10x. It was a
single flash over a dark fill, easy to miss while watching the district — a state
that settles stops asking to be looked at. It pulses now for as long as the move is
up.

And the pace ceiling was not theoretical. 10x was the top of the ladder and was
reported still a bit fast; it runs to 20 now. A control whose limit is reached in
ordinary use has the wrong limit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X6cF1iYvJ1kNmzYBzu4QX6
This commit is contained in:
Jesse.Markowitz
2026-09-10 05:49:01 -04:00
co-authored by Claude Opus 5
parent 3fca325699
commit 64e8ce584f
7 changed files with 152 additions and 11 deletions
+52 -2
View File
@@ -184,6 +184,20 @@ function drainIntoQueue(): void {
const reset = session.takeDisplayReset();
if (reset) stepQueue.reset(reset);
stepQueue.push(session.takeDisplaySteps());
/**
* NOWHERE TO ANIMATE MEANS DO NOT QUEUE AT ALL.
*
* Without `requestAnimationFrame` nothing ever advances the queue, so `busy()` would stay true for
* good — and since "Your Move" is now put away while the board is catching up, that would hide a
* player's own actions permanently, leaving Skip as the only way to play the game. Drawing
* everything at once is exactly what `pace = 0` does deliberately, so that is the honest fallback
* rather than a broken page. Caught by `test/web.test.ts`, whose DOM stub has no `rAF` — the same
* stub that has been proving this page still starts since long before any of this existed.
*/
if (typeof requestAnimationFrame !== 'function') {
stepQueue.skip();
return;
}
if (stepQueue.busy()) startAnimationLoop();
}
@@ -316,12 +330,25 @@ function startAnimationLoop(): void {
*/
console.error('display queue stopped:', err);
animating = false;
// Do not strand the player behind a queue that can no longer advance: jump the board to the
// live position, which brings "Your Move" back with it.
try {
stepQueue.skip();
} catch {
/* nothing further to try — the authoritative Frame is still what the rest of the page draws */
}
render();
return;
}
if (!stepQueue.busy()) {
animating = false;
// One last render so the "N behind" row collapses the moment the board is level.
renderWatching();
/**
* A FULL RENDER, not just the row. The board being level again is what brings "Your Move"
* back and clears the last lit pile, so redrawing only the catching-up row would leave the
* action list hidden until something else happened to trigger a render — which, when the game
* is waiting on this player, is nothing at all.
*/
render();
return;
}
requestAnimationFrame(tick);
@@ -1987,6 +2014,29 @@ function renderActions(
renderEnding(el, f);
return;
}
/**
* YOUR MOVE IS PUT AWAY WHILE THE BOARD IS CATCHING UP — Jesse, 2026-09-10: *"your actions should
* be hidden while catching up."*
*
* Two reasons, and the second is the one that changed my mind about it. The board on screen is
* behind the game, so a move offered here is a move against a position that has already moved on —
* the menu is computed from the CURRENT state and would be acted on while looking at an older one.
* And the display had grown to four things demanding attention at once — the district, the history,
* the catching-up row and now a lit pile — which is what made the pile highlight so easy to miss.
* Taking the action list out of that competition while there is nothing to decide anyway is the
* cheapest way to quieten it.
*
* NOT A BLOCK. Skip is one click away and sits at the left of the row, so the wait is always
* voluntary; this replaces the buttons with the reason they are gone, rather than leaving a live
* menu over a stale board.
*/
if (stepQueue.busy()) {
el.innerHTML =
'<div class="dim">Catching up on what everyone else did — your move is here when the board is ' +
'level with the game. <b>Skip</b> jumps straight to it.</div>';
return;
}
// The game is running, so the next ending — an extended Day's, or a fresh game's — is entitled to
// put its results up unasked again (Gitea#11).
resultsShown = false;