diff --git a/app/static/script.js b/app/static/script.js
index 57ea4ad..75d6094 100644
--- a/app/static/script.js
+++ b/app/static/script.js
@@ -40,6 +40,13 @@ function renderLiveGame(game) {
const dot = running ? `` : '';
+ // Tick the clock locally when the clock is running or during intermission
+ const shouldTick = running || intermission;
+ const rawSeconds = timeToSeconds(time);
+ const clockAttrs = shouldTick
+ ? `data-seconds="${rawSeconds}" data-received-at="${Date.now()}"`
+ : '';
+
const hype = !intermission ? `
Hype Meter
@@ -53,7 +60,7 @@ function renderLiveGame(game) {
@@ -132,6 +139,31 @@ function updateGauges() {
});
}
+// ── Clock ─────────────────────────────────────────────
+
+function timeToSeconds(str) {
+ if (!str || str === 'END') return 0;
+ const [m, s] = str.split(':').map(Number);
+ return m * 60 + s;
+}
+
+function secondsToTime(s) {
+ if (s <= 0) return 'END';
+ const m = Math.floor(s / 60);
+ const sec = s % 60;
+ return `${String(m).padStart(2, '0')}:${String(sec).padStart(2, '0')}`;
+}
+
+function tickClocks() {
+ const now = Date.now();
+ document.querySelectorAll('[data-seconds][data-received-at]').forEach(el => {
+ const seconds = parseInt(el.dataset.seconds, 10);
+ const receivedAt = parseInt(el.dataset.receivedAt, 10);
+ const elapsed = Math.floor((now - receivedAt) / 1000);
+ el.textContent = secondsToTime(Math.max(0, seconds - elapsed));
+ });
+}
+
// ── Helpers ──────────────────────────────────────────
function ordinalPeriod(period) {
@@ -149,4 +181,7 @@ function autoRefresh() {
setTimeout(autoRefresh, 5000);
}
-window.addEventListener('load', autoRefresh);
+window.addEventListener('load', () => {
+ autoRefresh();
+ setInterval(tickClocks, 1000);
+});