AI Implementation feature(911): Scoreboard: Ranking, Matrix, Event Log and Score Graph 1.01 (#54)
This commit was merged in pull request #54.
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
---
|
||||
type: guide
|
||||
title: Scoreboard Page
|
||||
description: How a signed-in player navigates /scoreboard, uses the four tabs (Ranking, Matrix, Event Log, Score Graph), and watches live solve updates arriving over the authenticated SSE stream.
|
||||
description: How a signed-in player navigates /scoreboard, uses the four tabs, distinguishes up to ten visible players by collision-resolved colors, and watches live solve updates.
|
||||
tags: [guide, scoreboard, sse, live, ranking, matrix, event-log, score-graph, tester]
|
||||
timestamp: 2026-07-23T05:41:00Z
|
||||
timestamp: 2026-07-23T06:01:38Z
|
||||
---
|
||||
|
||||
# Overview
|
||||
@@ -58,9 +58,14 @@ A table (`data-testid="scoreboard-ranking"`) with columns **Rank**,
|
||||
|
||||
* Each row has `data-testid="ranking-row-<playerId>"` and a
|
||||
`data-rank="<n>"` attribute.
|
||||
* Each player name is prefixed with a colored swatch (10-entry
|
||||
`PLAYER_COLOR_PALETTE` chosen by `stablePlayerColorIndex`) so the
|
||||
same player keeps the same color across all four tabs.
|
||||
* Each player name is prefixed with a colored swatch from the 10-entry
|
||||
`PLAYER_COLOR_PALETTE`. `stablePlayerColorIndex` supplies the preferred
|
||||
color; `assignUniquePlayerColors` keeps that color when available and
|
||||
linearly selects the next free palette slot after a collision. Ranking,
|
||||
Matrix, and Score Graph apply this assignment in their current display
|
||||
order after initial REST loading and after live updates, so up to ten
|
||||
simultaneously displayed players remain visually distinct within each
|
||||
projection.
|
||||
* Ranking uses competition ranks: equal-point players share the same
|
||||
`rank` (1, 2, 2, 4, …). Zero-solve players are still listed at the
|
||||
bottom in user-id order.
|
||||
@@ -121,7 +126,9 @@ points for the **top 10 players** over the configured event window
|
||||
(`startUtc` → `endUtc`):
|
||||
|
||||
* Above the chart, a legend (`data-testid="score-graph-legend-<playerId>"`)
|
||||
lists each player with their colored swatch.
|
||||
lists each player with their colored swatch. The top ten visible series
|
||||
receive distinct palette colors, including when two player IDs hash to
|
||||
the same preferred color.
|
||||
* Each player has a `polyline` element
|
||||
(`data-testid="score-graph-line-<playerId>"`) using the same color
|
||||
index as the Ranking and Matrix tabs.
|
||||
@@ -152,9 +159,11 @@ The same `solve` frame that lights up the
|
||||
`awardedPoints`, `solvedCount` increments by 1, and the list is
|
||||
re-sorted (with competition ranks applied). If the player is new,
|
||||
they are appended with `points = awardedPoints`, `solvedCount = 1`.
|
||||
Colors are reassigned in sorted ranking order to avoid palette collisions.
|
||||
* **Matrix**: the cell at `[<playerId>, <challengeId>]` becomes `1`,
|
||||
`2`, or `3` if the new `position` is in 1–3, otherwise `'solved'`.
|
||||
New players are appended to the matrix row list.
|
||||
New players are appended to the matrix row list, then visible row colors
|
||||
are collision-resolved in matrix order.
|
||||
* **Event Log**: a new `EventLogRow` is prepended to the list
|
||||
(deduplicated by `solveId` so reconnects don't duplicate) and the
|
||||
list is capped at 200. The SSE solve frame carries
|
||||
@@ -166,7 +175,8 @@ The same `solve` frame that lights up the
|
||||
* **Score Graph**: the matching player's series receives a new
|
||||
`{tUtc: awardedAtUtc, value: prevValue + awardedPoints}` point,
|
||||
the series list is re-sorted by final value DESC and trimmed to the
|
||||
top 10.
|
||||
top 10. Those ten series are then assigned unique palette slots in
|
||||
graph order.
|
||||
|
||||
On `ngOnDestroy`, `store.stop()` aborts the SSE transport and clears
|
||||
the reconnect timer so no callbacks fire after the page leaves the
|
||||
@@ -256,6 +266,21 @@ DOM.
|
||||
tabs and matches the same player's swatch in the challenges board
|
||||
modal solvers list.
|
||||
|
||||
## Verifying collision-resolved player colors
|
||||
|
||||
1. Seed or create up to ten visible players, including player IDs whose
|
||||
preferred palette hashes collide.
|
||||
2. Open `/scoreboard` and inspect **Ranking**. Every one of the first ten
|
||||
displayed players has a distinct swatch; players without a collision keep
|
||||
their preferred hashed color.
|
||||
3. Open **Matrix**. Up to ten visible player rows likewise use distinct
|
||||
swatches in matrix row order.
|
||||
4. Open **Score Graph**. Its ten legend swatches and matching polylines use
|
||||
ten distinct palette colors.
|
||||
5. Trigger a solve. Ranking and graph order may change, but each projection
|
||||
resolves its displayed colors again and remains collision-free for up to
|
||||
ten players.
|
||||
|
||||
# See also
|
||||
|
||||
- [Challenges Endpoints](/api/challenges.md) — `/api/v1/scoreboard/*` request/response shapes.
|
||||
|
||||
+3
-3
@@ -11,7 +11,7 @@ scoreboard, an event window with a public countdown, theming, and admin
|
||||
controls.
|
||||
|
||||
The docs below are organized by purpose so agents can pull just the slice
|
||||
they need. Last regenerated 2026-07-23T05:41:00Z.
|
||||
they need. Last regenerated 2026-07-23T06:01:38Z.
|
||||
|
||||
# Architecture
|
||||
|
||||
@@ -119,8 +119,8 @@ they need. Last regenerated 2026-07-23T05:41:00Z.
|
||||
broadcast to clients (public unauthenticated stream + authenticated
|
||||
`/api/v1/events`).
|
||||
* [Scoreboard Page](/guides/scoreboard-page.md) - How a signed-in player
|
||||
navigates `/scoreboard`, uses the 4 tabs (Ranking, Matrix, Event Log,
|
||||
Score Graph), and watches live solve updates.
|
||||
navigates `/scoreboard`, uses the 4 tabs, verifies collision-resolved
|
||||
colors for up to ten visible players, and watches live solve updates.
|
||||
* [Notifications](/guides/notifications.md) - The root notification
|
||||
store + global HTTP error interceptor that translate backend error
|
||||
codes and statuses into friendly user-facing messages.
|
||||
|
||||
Reference in New Issue
Block a user