CTF scoreboard
The scoreboard streams over WebSockets: solves, score adjustments, and awards move the board the moment they land, for everyone watching.
The board opens when the competition starts and stays readable after it ends as a final, read-only result — competition status is a separate axis from both pause and freeze. While a competition is still Not started, the scoreboard is closed to competitors (staff can see it).
What the board shows
Section titled “What the board shows”- Standings per team (team mode) or competitor (individual mode) — total points are the sum of solve awards, judge/automation score adjustments, hint costs, and award points. Ties follow the standard CTF convention: equal points rank by the earliest time the subject reached its current score.
- First blood — the first solve of each challenge is marked (a lightning-bolt icon next to the solver).
- Dynamic values — decay-scored challenges re-value all their solvers on each new solve, so the board always reflects current worth.
- Divisions — when the competition defines brackets, a division filter ranks within the selected division; staff assign divisions inline from the board.
- The top-10 chart — a bar chart of the leaders above the table, with per-bar labels and a detail tooltip on hover or keyboard focus.
- Score over time (v1.6.0) — beside the standings, a line chart plots the
top ten entrants’ cumulative score as it climbed over the event, so you
can watch overtakes and stalls instead of just the final ordering. Each
series ends exactly on that subject’s table total — the chart and the table
are the same numbers, drawn two ways. It respects the freeze and the
division filter like the rest of the board: competitors see the frozen
picture, and a
scoreboard_freezeholder viewing the live board sees the live lines; a bracket filter scopes the series to that division. It rides the same activity connection as the board — no manual refresh — needschallenge_view, and only appears once the competition has started.
Freezing the board
Section titled “Freezing the board”A freeze stops the public board from moving — competitors keep solving and their points still count; the standings just stop updating publicly until the unfreeze. This is the classic end-game tension mechanic.
- Freezing requires the
scoreboard_freezepermission and shows a confirmation explaining exactly these semantics; the frozen board carries a persistent note. - The board everyone sees is computed as of the freeze instant — dynamic values by solve count at that moment; later solves, adjustments, awards, and hint costs excluded.
- The freeze covers every competitor-visible solve surface, not just the board: per-challenge solver lists and solve counts, dashboards, the participants roster, and the spectator insights all apply the same cutoff (tightened in v1.2.0 — GHSA-q69m-7mgh-r2gh — and v1.4.0 closed the last gap: the per-challenge detail view’s solve count and dynamic value now clamp to the cutoff like every other read), so a frozen board can’t be reconstructed from side channels.
- Staff can still read the live board (
?live=true— the UI does this for staff automatically). - Freeze and unfreeze emit
scoreboard.frozen/scoreboard.unfrozen, and both exist as automation actions — a common rule is oncompetition.ended→ freeze the board.
Freezing is different from pausing: a pause stops competitors submitting; a freeze only stops the public board moving.
Public spectator board
Section titled “Public spectator board”An explicit per-competition opt-in (Settings → General) exposes a read-only, unauthenticated scoreboard for projectors and spectators:
/publiclists every competition that opted in;/public/<competition-id>is the standalone board (no login, branded with your site settings).- Only public, non-archived, opted-in competitions are served — anything else 404s, so private events are never disclosed.
- Beyond the table, the page shows competition insight cards (most solved, most attempted, first-blood leader, fastest solve) and a live cumulative points timeline of the top ten, so spectators can watch overtakes as they happen.
- The spectator board respects the freeze like any competitor view — and so does every score-derived insight and the timeline, so the page never leaks what the frozen board hides.
Venue / projector mode
Section titled “Venue / projector mode”Since v1.3.0, the spectator page carries a big-screen mode for live,
in-person events. A Venue mode button on /public/<competition-id>
(or ?venue=1 directly — bookmarkable and refresh-safe) switches to a
full-screen display that auto-rotates through the scoreboard (top
twelve), the insight stats and highlights, and the points timeline every
15 seconds (?interval=<seconds> overrides, clamped 5–120).
- First-blood splashes — a new first blood interrupts the rotation with a five-second full-screen takeover, driven by a recent-solves feed the page polls every few seconds.
- Controls — arrow keys change slide, Space pauses, F toggles fullscreen, +/− nudge the display zoom (0.6×–2×, v1.4.0), Esc exits, with on-screen buttons and slide dots for the mouse.
- Scales to the display (v1.4.0) — type and layout grow with the screen, from a laptop up to a 4K projector wall, with the +/− keys as an operator fine-tune.
- Same opt-in, same freeze rules — venue mode rides the spectator board’s per-competition opt-in (no separate setting), and a frozen competition emits no post-cutoff solves, so no splash can leak what the board hides.
CTFtime feed
Section titled “CTFtime feed”A second per-competition opt-in exposes
GET /api/public/competitions/<id>/ctftime in the
CTFtime scoreboard-feed format
({"standings":[{"pos","team","score"}]}), so rated events can plug straight
into CTFtime. The feed URL is shown on Settings → General once enabled.
Adjustments and awards
Section titled “Adjustments and awards”Judges with score_override can adjust scores (bonus or penalty, with a
reason — emits score.adjusted) and grant point-carrying
awards. Both fold into the board live and
appear in the audit log.