diff --git a/public_html/README.md b/README.md similarity index 89% rename from public_html/README.md rename to README.md index 73cece9..d4b3d6f 100644 --- a/public_html/README.md +++ b/README.md @@ -12,8 +12,9 @@ Chrome will only offer a real install over HTTPS, so the file needs a host. GitHub Pages is free and takes about two minutes: 1. Create a new public repository, e.g. `bgclock`. -2. Upload all six files to the root: `index.html`, `manifest.webmanifest`, - `sw.js`, `icon-192.png`, `icon-512.png`, `icon-maskable-512.png`. +2. Upload all six files from `public_html/` to the root: `index.html`, + `manifest.webmanifest`, `sw.js`, `icon-192.png`, `icon-512.png`, + `icon-maskable-512.png`. 3. **Settings → Pages → Source: Deploy from a branch → `main` / `(root)` → Save.** 4. Wait a minute, then open `https://.github.io/bgclock/` on your phone. 5. **Android, Chrome:** menu (⋮) → **Add to Home screen** → **Install**. @@ -41,8 +42,8 @@ On iOS a few things behave differently, none of them fatal: If you're using a different path than `/bgclock/`, edit the `"id"` field in `manifest.webmanifest` to match, or just delete that line. -To try it before hosting, open `index.html` in any browser — everything works -except installation and the service worker. +To try it before hosting, open `public_html/index.html` in any browser — +everything works except installation and the service worker. ## Using it @@ -52,19 +53,26 @@ except installation and the service worker. - A tap counts when you **lift** your finger, and only if it didn't move. A swipe does nothing, so Android's swipe-up-from-the-bottom and the status-bar pull-down work over either half without costing anyone their turn — and a hand dragged - across the panel won't change it either. The clock still switches at the moment - you pressed, not when you let go. + across the panel won't change it either. +- Your clock runs until you lift. Holding a finger on the panel costs you the + time you can see counting off, and holding it past zero flags you, exactly as + if you hadn't touched it at all. - The bar under the big time is the delay draining. When it empties you get a soft tick and your reserve starts moving. That's the moment worth hearing. - **Reset** starts a whole new match: clocks back to full *and* the score back to 0–0. It takes two taps: the first arms the button — it lights up and a ring unwinds around it — and a second tap within those two seconds does it. One - stray thumb can't wipe a live match. + stray thumb can't wipe a live match. It's absent on a fresh match, where there + is nothing yet to wipe. - **Pause** freezes mid-turn and resumes exactly where it stopped, delay 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. + doesn't cost you a tap on play. It's absent before each game's first tap, with + no clock running to freeze. + +Both buttons keep their space in the bar while they're away, so nothing shifts +under your thumb — the same as the gear. - **Settings are only reachable before a match starts.** Every control in that sheet resets both clocks, so the gear disappears the moment the first tap starts the clock and comes back after a reset. Its space in the bar is kept diff --git a/public_html/index.html b/public_html/index.html index e242191..ae95975 100644 --- a/public_html/index.html +++ b/public_html/index.html @@ -761,8 +761,13 @@ } // here rather than in the mutators, so it can never go stale; the - // two-argument toggle leaves the DOM alone when the state already matches - btnSettings.classList.toggle("btn--vacant", !matchPristine()); + // two-argument toggle leaves the DOM alone when the state already matches. + // Settings and Reset are exact opposites: before the match you can change + // the setup and have nothing to reset, and once it's running, the reverse. + var pristine = matchPristine(); + btnSettings.classList.toggle("btn--vacant", !pristine); + btnReset.classList.toggle("btn--vacant", pristine); // nothing played to reset + btnPlay.classList.toggle("btn--vacant", st.phase === IDLE); // nothing running to pause } function loop(){ render(); requestAnimationFrame(loop); } @@ -778,13 +783,12 @@ saveGame(); } - // `at` is when the finger landed. A tap is only confirmed once it lifts, but - // the turn has to change at the press or every switch drifts by however long - // the finger rested on the panel. - function tap(side, at){ + function tap(side){ if(st.phase === FLAG) return; if(st.phase === PAUSE) return; - var now = at || performance.now(); + // the lift, not the press: your clock runs for as long as your finger is + // down, so a held thumb costs you exactly the time it was seen counting off + var now = performance.now(); if(st.phase === IDLE){ st.active = 1 - side; // you tap your own side to start your opponent @@ -798,7 +802,8 @@ } if(side !== st.active) return; // the waiting player can't stop the clock - // not elapsed(): that measures to *now*, and this has to measure to the press + // the same instant charges the outgoing turn and starts the incoming one, + // so nothing falls between the two and goes to neither player var e = now - st.turnAt; st.reserve[side] = Math.max(0, st.reserve[side] - Math.max(0, e - cfg.delay)); st.moves[side]++; @@ -1177,7 +1182,7 @@ p.addEventListener("pointerdown", function(ev){ ev.preventDefault(); audio(); // unlocking on the press is a valid gesture and earlier is better - down = { id: ev.pointerId, x: ev.clientX, y: ev.clientY, t: ev.timeStamp }; + down = { id: ev.pointerId, x: ev.clientX, y: ev.clientY }; // so the lift still lands here if the finger drifts onto the other panel try{ p.setPointerCapture(ev.pointerId); }catch(e){} }); @@ -1197,7 +1202,7 @@ document.documentElement.requestFullscreen().catch(function(){}); } } - tap(side, d.t); + tap(side); }); // the branch Android's home gesture takes diff --git a/public_html/sw.js b/public_html/sw.js index 7bdb194..5f439b0 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-v11"; +const CACHE = "bgclock-v12"; const FILES = [ "./", "./index.html",