feat(public): venue/projector mode for public competitions (#77) - #141
Merged
Conversation
A full-screen, unauthenticated big-screen display for in-person events, toggled in-page from the existing /public/[id] spectator view via ?venue=1 (bookmarkable, refresh-safe) and implied by the same public_scoreboard opt-in — no new competition column. It auto-rotates three widgets (scoreboard, insights, points timeline) at a 15s cadence (?interval= override), with a first-blood takeover overlay using the app's house lightning glyph. Operator controls: fullscreen button, arrow keys, space to pause, Esc to exit. Backend adds one read-only public endpoint — GET /activity — returning recent awarded solves tagged is_first_blood, freeze-aware and under the same opt-in/ archived gating as the board, so a frozen competition emits no splash. The first-blood definition is refactored into one shared helper so the feed and the insights leaderboard can't disagree. Polling only (no WebSocket), so no ADR needed. StatTiles/Highlights extracted to a shared component and the first-blood icon shared so the static and venue views don't fork. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Closes #77. A full-screen, unauthenticated venue/projector mode for putting a live competition on the big screen at an in-person event. It's an in-page toggle on the existing
/public/[id]spectator view (?venue=1, bookmarkable and refresh-safe) and implied by the samepublic_scoreboardopt-in — no new competition column, permission, event, or WebSocket.The stage auto-rotates three widgets — scoreboard, insights (stats + highlights), points timeline — at 15s each (
?interval=override), with a first-blood takeover overlay using the app's house amber-lightning glyph. Operator controls: a fullscreen button, arrow keys to step, space to pause, Esc to exit.Decisions (confirmed with the owner)
?venue=1so it's still castable/bookmarkable.?interval=override.FirstBloodIcon, not a droplet — consistent with the rest of the app.Backend — one read-only endpoint
GET /api/public/competitions/{id}/activity→ recent awarded solves, each taggedis_first_blood. Freeze-aware (computed as offreeze_cutoff), so a frozen competition emits no post-cutoff solves — the splash goes silent during a freeze rather than leaking hidden movement. Same opt-in/archived 404 gating as the board; short in-process memo (public_activity_cache_seconds, 5s)._first_solvershelper so the feed and the insights leaderboard can't disagree.Frontend
?venue=1toggle on the spectator page (Suspense-wrappeduseSearchParams);usePublicActivitypolls only while venue mode is on.components/public/venue/venue-mode.tsx— the overlay: rotation, first-blood splash queue (primed on first load so pre-existing bloods don't storm), fullscreen + keyboard controls.StatTiles/Highlights(shared with the static page, no fork) and theFirstBloodIcon(shared with the challenges page).lib/venue.ts(parseRotateSeconds,pickNewFirstBloods) — unit-tested.Verification
tsc/eslint/vitest(197, incl. 17 new) /next build./activityfeed and zero console errors.Checklist
role=tablist/aria-pressed/role=alert)🤖 Generated with Claude Code