From 0f69c78b741a5282fac376c807ecd5422cbf7798 Mon Sep 17 00:00:00 2001 From: Hans de Zwart Date: Tue, 11 Aug 2026 15:11:31 +0200 Subject: [PATCH] Resume the clock on leaving the score sheet, and split the readout in three MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closing the score sheet left the clock paused, so glancing at the score or nudging a clock cost a tap on play. It now picks the turn back up on the way out. openScore() records whether it was the thing that paused the clock, so a pause the players set themselves survives. After a score change there is nothing to resume — newGame() has already moved to IDLE — and resumeNow() only acts on PAUSE, so that case needs no special handling. The scrim behaves the same, since dismissing discards the staged edits and leaves the turn live. togglePause() had the resume arithmetic inline; it splits out as resumeNow() to match pauseNow(), leaving the play button and the sheet on one path. The score line becomes three labelled lines: You: 2 out of 5 Them: 1 Moves: 7 .head is a two-column grid with a max-content label column, so the values line up whatever the system font renders — no hand-tuned em width to drift between iOS and Android. Each line is a display:contents wrapper, which keeps one element per line to hide when a one-point match drops the score. The gap above Moves rides on that row's two cells, since a display:contents row can't carry a margin, and a :not([hidden]) guard drops it when there is no score line above to separate from. Each half reads from its own side of the board, so both players see their own score on the You line. st.score is already indexed by side, so the mirroring costs nothing. Co-Authored-By: Claude Opus 5 --- public_html/README.md | 39 +++++++++++++------- public_html/index.html | 84 +++++++++++++++++++++++++++--------------- public_html/sw.js | 2 +- 3 files changed, 81 insertions(+), 44 deletions(-) diff --git a/public_html/README.md b/public_html/README.md index 06c6be6..75fa9f6 100644 --- a/public_html/README.md +++ b/public_html/README.md @@ -56,8 +56,10 @@ except installation and the service worker. unwinds around it — and a second tap within those two seconds does it. One stray thumb can't wipe a live match. - **Pause** freezes mid-turn and resumes exactly where it stopped, delay - included. Opening either sheet pauses automatically, and leaves it paused so - the clock only restarts when both players are ready. + included. Opening either sheet pauses automatically. The settings sheet leaves + it paused — everything in there resets the clocks anyway — while the score + sheet picks the turn back up when you close it, so glancing at the score + doesn't cost you a tap on play. Backgammon clocks pause between games, and after a cocked die the delay is normally restarted — use pause and reset for those. @@ -68,26 +70,37 @@ Set **Match** in the settings to the number of points you're playing to — 1, 3 5 and up to 29. The time you set is *per point*, so a 5-point match at 2:00 a point puts 10:00 on each clock, and the settings sheet shows you that sum. -At **1 point** there's no match to keep score of, so the score line and the -score-sheet icon both disappear and you get the plain single-game clock. Set -the match to 3 or more and they come back. +Each half reads the state from that player's own side of the board: -The score sheet is the middle icon in the bar. It reads **You** for whoever is -holding the phone — the bottom half — and **Them** for the far end, and each -panel shows its own score first, so both players read their own score on the -left: `Score: 1 - 3, out of 5`. +``` +You: 1 out of 5 +Them: 3 +Moves: 7 +``` + +So "You" always means whoever is sitting at that end — both players read their +own score on the top line, and the two halves show mirrored numbers. + +At **1 point** there's no match to keep score of, so the score lines and the +score-sheet icon all disappear and you get the plain single-game clock with just +its move count. Set the match to 3 or more and they come back. + +The score sheet is the middle icon in the bar. It's filled in from the phone +holder's side: **You** is the bottom half, **Them** the far end. Nothing in that sheet takes effect until you press **Done**: - **Done with nothing changed** leaves everything exactly as it was — same turn, - same delay part-spent, same move counts. Tapping outside the sheet is the same - as changing nothing, so a stray tap can't restart a game. + same delay part-spent, same move counts — and the clock picks up where it left + off. Tapping outside the sheet is the same as changing nothing, so a stray tap + can't restart a game. A pause you set yourself before opening the sheet + survives; only the sheet's own pause is undone. - **Change a score** and the game restarts when you press Done: move counters back to zero and the turn back to the first tap, waiting on whoever rolls the lower die. The clocks keep whatever they were showing. - **Change only a clock** — the sheet also lets you correct either player's time - to the second — and the game carries on undisturbed: same turn, same delay - position, same moves. + to the second — and the game carries on undisturbed and running: same turn, + same delay position, same moves. Shortening the match to fewer points than someone has already won pulls their score down to fit. diff --git a/public_html/index.html b/public_html/index.html index 61c7b91..983e2b1 100644 --- a/public_html/index.html +++ b/public_html/index.html @@ -75,25 +75,30 @@ .panel--top .inner{padding:14px 20px max(14px,env(safe-area-inset-top))} .panel--bottom .inner{padding:14px 20px max(14px,env(safe-area-inset-bottom))} + /* the label column sizes itself to the widest label, so the three values + line up whatever the system font turns out to be */ .head{ - display:flex;flex-direction:column;align-items:flex-start; - gap:3px; + display:grid; + grid-template-columns:max-content max-content; + justify-content:start; + gap:3px 8px; order:-1; - } - .score[hidden]{display:none} - .score,.moves{ font-size:clamp(13px,3.7vw,20px); font-weight:700; letter-spacing:.01em; color:var(--idle-mute); white-space:nowrap; } - .panel[data-state="active"] .score, - .panel[data-state="active"] .moves, - .panel[data-state="flagged"] .score, - .panel[data-state="flagged"] .moves{color:var(--accent-mute)} - .panel[data-state="flagged"] .score, - .panel[data-state="flagged"] .moves{color:rgba(255,255,255,.55)} + .line{display:contents} + .line[hidden]{display:none} + /* set the moves line apart from the score — a display:contents row can't take + a margin itself, so both its cells carry it and the row shifts down evenly. + The guard drops the space when there's no score line above to separate from. */ + .line:not([hidden]) + .line--moves > *{margin-top:7px} + + .panel[data-state="active"] .head, + .panel[data-state="flagged"] .head{color:var(--accent-mute)} + .panel[data-state="flagged"] .head{color:rgba(255,255,255,.55)} .stack{ flex:1; @@ -313,8 +318,9 @@
- -
Moves: 0
+ + + Moves:0
3:00
@@ -373,8 +379,9 @@
- -
Moves: 0
+ + + Moves:0
3:00
@@ -571,9 +578,10 @@ root: p, time: p.querySelector("[data-time]"), moves: p.querySelector("[data-moves]"), - score: p.querySelector("[data-score]"), + you: p.querySelector("[data-you]"), + them: p.querySelector("[data-them]"), target: p.querySelector("[data-target]"), - scoreLine: p.querySelector(".score"), + scoreLines: [].slice.call(p.querySelectorAll(".line:not(.line--moves)")), delay: p.querySelector("[data-delay]"), fill: p.querySelector("[data-fill]"), dnum: p.querySelector("[data-dnum]") @@ -691,7 +699,8 @@ el[i].time.textContent = fmt(main); el[i].moves.textContent = st.moves[i]; - el[i].score.textContent = st.score[i] + " - " + st.score[1 - i]; + el[i].you.textContent = st.score[i]; // each panel is "You" to its own player + el[i].them.textContent = st.score[1 - i]; el[i].target.textContent = cfg.points; var showDelay = live && cfg.delay > 0 && dLeft > 0; @@ -753,18 +762,19 @@ saveGame(); } - function togglePause(){ - if(st.phase === RUN){ - pauseNow(); - return; - }else if(st.phase === PAUSE){ - st.turnAt = performance.now() - st.held; - st.phase = RUN; - }else return; + function resumeNow(){ + if(st.phase !== PAUSE) return; + st.turnAt = performance.now() - st.held; // pick the turn up where it stopped + st.phase = RUN; paintPlay(); saveGame(); } + function togglePause(){ + if(st.phase === RUN) pauseNow(); + else resumeNow(); + } + /* SVG elements aren't HTMLElements, so they have no .hidden property — setting it only makes a JS expando. The attribute has to be set by hand. */ function showIcon(btn, name, on){ @@ -902,7 +912,7 @@ if(many) node.removeAttribute("hidden"); else node.setAttribute("hidden", ""); } show(btnScore); - el.forEach(function(e){ show(e.scoreLine); }); + el.forEach(function(e){ e.scoreLines.forEach(show); }); } function clock(ms){ // m:ss, for copy rather than the big readout @@ -1003,12 +1013,23 @@ document.getElementById("done").addEventListener("click", closeSheet); // tapping outside the score sheet discards the staged edits rather than // committing them — a stray tap must never restart a game - scrim.addEventListener("click", closeSheet); + scrim.addEventListener("click", function(){ + if(openNode === scoreSheet) closeScore(); else closeSheet(); + }); /* ============ score sheet ============ */ // Edits are staged here and only reach `st` on Done, so opening the sheet, // fiddling and tapping away changes nothing. - var edit = null, before = null; + var edit = null, before = null, resumeOnClose = false; + + // leaving the sheet with the turn still live carries straight on. After a score + // change there is no turn to resume — newGame() has already moved us to IDLE, + // which the PAUSE check below quietly skips. + function closeScore(){ + if(resumeOnClose) resumeNow(); + resumeOnClose = false; + closeSheet(); + } function paintScore(){ document.getElementById("v-you").textContent = edit.score[1]; @@ -1021,6 +1042,9 @@ } function openScore(){ + // only the sheet's own pause gets undone on the way out; a pause the players + // set themselves survives + resumeOnClose = (st.phase === RUN); pauseNow(); disarm(); // seed from what the panels are showing, not from the banked reserve — for @@ -1074,7 +1098,7 @@ document.getElementById("score").addEventListener("click", openScore); document.getElementById("score-done").addEventListener("click", function(){ applyScore(); - closeSheet(); + closeScore(); }); btnReset.addEventListener("click", armReset); diff --git a/public_html/sw.js b/public_html/sw.js index 33dd73b..47e4768 100644 --- a/public_html/sw.js +++ b/public_html/sw.js @@ -1,5 +1,5 @@ /* Cache-first: once installed the clock never touches the network again. */ -const CACHE = "bgclock-v5"; +const CACHE = "bgclock-v6"; const FILES = [ "./", "./index.html",