diff --git a/public_html/index.html b/public_html/index.html
index 983e2b1..b231531 100644
--- a/public_html/index.html
+++ b/public_html/index.html
@@ -659,7 +659,9 @@
function fmt(ms){
if(ms < 0) ms = 0;
var t = Math.ceil(ms / 100) / 10;
- if(ms < 10000) return t.toFixed(1);
+ // <= so 10000ms renders as "10.0" rather than "0:10": both branches round up,
+ // so the coarse one reads a second high and 0:10 would flash for 1ms
+ if(ms <= 10000) return t.toFixed(1);
var s = Math.ceil(ms / 1000);
var m = Math.floor(s / 60);
s = s % 60;
@@ -679,6 +681,24 @@
return Math.max(0, st.reserve[i] - consumed(i));
}
+ /* ---- write only on change ----
+ render() runs 60 times a second but the digits turn over once a second, and
+ .time is a ~190px glyph run: rewriting its text node every frame forces a
+ style recalc and relayout for nothing, which is what makes the readout
+ stutter. The cached marker avoids reading the DOM back, which would flush
+ style by itself. */
+ function setText(node, value){
+ var s = String(value);
+ if(node.__v !== s){ node.__v = s; node.textContent = s; }
+ }
+ function setAttr(node, name, value){
+ if(node.getAttribute(name) !== value) node.setAttribute(name, value);
+ }
+ function setStyle(node, prop, value){
+ var k = "__s_" + prop; // per property, so a second one can't alias
+ if(node[k] !== value){ node[k] = value; node.style[prop] = value; }
+ }
+
/* ============ render ============ */
function render(){
var e = elapsed();
@@ -697,21 +717,23 @@
if(live && main <= 0 && st.phase === RUN){ flag(i); return; }
- el[i].time.textContent = fmt(main);
- el[i].moves.textContent = st.moves[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;
+ setText(el[i].time, fmt(main));
+ setText(el[i].moves, st.moves[i]);
+ setText(el[i].you, st.score[i]); // each panel is "You" to its own player
+ setText(el[i].them, st.score[1 - i]);
+ setText(el[i].target, cfg.points);
var showDelay = live && cfg.delay > 0 && dLeft > 0;
- el[i].delay.classList.toggle("on", showDelay);
+ el[i].delay.classList.toggle("on", showDelay); // no-op when already right
if(showDelay){
- el[i].fill.style.transform = "scaleX(" + (dLeft / cfg.delay) + ")";
- el[i].dnum.textContent = Math.ceil(dLeft / 1000);
+ // the bar really does move every frame, but transform is compositor-only
+ setStyle(el[i].fill, "transform", "scaleX(" + (dLeft / cfg.delay).toFixed(4) + ")");
+ setText(el[i].dnum, Math.ceil(dLeft / 1000));
}
- if(st.phase === FLAG && i === st.active) el[i].root.dataset.state = "flagged";
- else el[i].root.dataset.state = (i === st.active && st.phase !== IDLE) ? "active" : "idle";
+ setAttr(el[i].root, "data-state",
+ (st.phase === FLAG && i === st.active) ? "flagged"
+ : (i === st.active && st.phase !== IDLE) ? "active" : "idle");
}
}
diff --git a/public_html/sw.js b/public_html/sw.js
index 47e4768..61214cc 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-v6";
+const CACHE = "bgclock-v7";
const FILES = [
"./",
"./index.html",