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