summaryrefslogtreecommitdiffstats
path: root/assets/presenter.js
diff options
context:
space:
mode:
authorLeonardo Bishop <me@leonardobishop.net>2026-02-13 17:07:34 +0000
committerLeonardo Bishop <me@leonardobishop.net>2026-02-13 17:08:01 +0000
commitbbe07c2788b00711e011f7805e14fa0933bf2d73 (patch)
tree7a80a05fd793fe572b901e442576ccbf5f3accc2 /assets/presenter.js
Initial commitHEADmaster
Diffstat (limited to 'assets/presenter.js')
-rw-r--r--assets/presenter.js70
1 files changed, 70 insertions, 0 deletions
diff --git a/assets/presenter.js b/assets/presenter.js
new file mode 100644
index 0000000..bfe41b8
--- /dev/null
+++ b/assets/presenter.js
@@ -0,0 +1,70 @@
+const overlayEl = document.getElementById("solve-overlay");
+const firstBloodEl = document.getElementById("solve-first");
+const teamEl = document.getElementById("solve-team");
+const challengeEl = document.getElementById("solve-challenge");
+const valueEl = document.getElementById("solve-value");
+const scoreboardFrameEl = document.getElementById("scoreboard-frame");
+
+const solveQueue = [];
+let isShowingOverlay = false;
+
+function pollNextSolve() {
+ if (isShowingOverlay) {
+ return;
+ }
+
+ if (solveQueue.length > 0) {
+ const nextSolve = solveQueue.shift();
+ showSolve(nextSolve.team, nextSolve.challenge, nextSolve.value, nextSolve.first);
+ }
+}
+
+function showSolve(team, challenge, value, first) {
+ teamEl.textContent = team;
+ teamEl.setAttribute("data-text", team);
+ challengeEl.textContent = challenge;
+ challengeEl.setAttribute("data-text", challenge);
+ valueEl.textContent = `+${value}`;
+ valueEl.setAttribute("data-text", `+${value}`);
+
+ if (first) {
+ firstBloodEl.classList.add("visible");
+ }
+
+ overlayEl.classList.add("visible");
+ isShowingOverlay = true;
+
+ setTimeout(() => {
+ overlayEl.classList.remove("visible");
+ firstBloodEl.classList.remove("visible");
+
+ setTimeout(() => {
+ isShowingOverlay = false;
+ pollNextSolve();
+ }, 1000);
+ }, first ? 8500 : 4500);
+}
+
+let reloadTimeout = null;
+
+function reloadScoreboard(delay = 1000) {
+ if (reloadTimeout) {
+ clearTimeout(reloadTimeout);
+ }
+
+ reloadTimeout = setTimeout(() => {
+ scoreboardFrameEl.src = "/scoreboard?ts=" + Date.now();
+ reloadTimeout = null;
+ }, delay);
+}
+
+const es = new EventSource("/presenter/events");
+
+es.onmessage = (e) => {
+ const data = JSON.parse(e.data);
+ if (data.type === "solve") {
+ solveQueue.push(data);
+ reloadScoreboard();
+ pollNextSolve();
+ }
+};