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",