Leaderboards are project-scoped ranked score boards. A board springs into existence the first time a player submits to it, and every player holds at most one entry per board — resubmitting updates that entry according to the board's mode. Boards persist across sessions and servers, and you manage them from the dashboard.
Board names match ^[a-z0-9_.\-]{1,64}$ (lowercase letters, digits, _, ., -).
Submitting scores
await SpawnWeaver.start()
var result := await SpawnWeaver.leaderboard_submit("highscore", 4200)
if result.ok:
print("Best: ", result.value["best"], " rank #", result.value["rank"])
if not result.value["updated"]:
print("Didn't beat your stored score.")
leaderboard_submit(board, score, mode) resolves with {best, rank, updated}:
| Field | Meaning |
|---|---|
best |
The score stored for you after the submit |
rank |
Your 1-based rank on the board |
updated |
false when the submit didn't beat your stored score (max/min modes) |
The display name set with set_display_name() is stored with your entry, so listings
can show names instead of player ids.
Modes
The third argument picks how a resubmit interacts with your stored score:
| Mode | Behavior | Use for |
|---|---|---|
"max" (default) |
Keep the higher score | Highscores, most kills, longest streak |
"min" |
Keep the lower score; ranks read ascending | Lap times, speedruns, fewest moves |
"latest" |
Always overwrite | Season ratings, ELO-style values you compute |
Use the same mode for every submit to a given board — the mode travels with the submit, not the board.
Reading the board
# The top 10, best first (value: Array[SWLeaderboardEntry]):
var top := await SpawnWeaver.leaderboard_top("highscore")
if top.ok:
for entry in top.value:
print("#", entry.rank, " ", entry.display_name(), " ", entry.score)
# The window around you (great for "you are #17" UIs):
var around := await SpawnWeaver.leaderboard_around("highscore", 2)
if around.ok:
print("You are #", around.value["player_rank"], " of ", around.value["total"])
for entry in around.value["entries"]:
print("#", entry.rank, " ", entry.display_name(), " ", entry.score,
" ← you" if entry.is_local else "")
leaderboard_top(board, limit) returns up to limit (1–100, default 10) entries.
leaderboard_around(board, entry_range) returns your entry ± entry_range (1–50,
default 5) neighbors, plus player_rank and the board's total entry count. If you
have no entry yet, player_rank is -1 and the top of the board is returned instead.
Each SWLeaderboardEntry carries rank, player_id,
player_name, score, updated_at, and an is_local flag that is true on your own
row — perfect for highlighting it.
Ranks and ties
- Ranks are 1-based. Equal scores share a rank — two players at 100 are both
#1, and the next score is#3. - Within a tie, the oldest entry lists first (defending a score beats matching it).
- On
"min"boards ranks read ascending: the lowest score is#1.
Managing boards from the dashboard
The Leaderboards page in the dashboard (Build → Leaderboards) shows every board of a project with its top 100. From there you can:
- Delete a single entry — e.g. an obvious cheater. The player can submit again immediately (their next submit re-creates the entry).
- Reset a whole board — removes every entry, e.g. at the start of a new season. The board re-appears on the next submit.
Limits
| Limit | Value | Error |
|---|---|---|
| Board name | ^[a-z0-9_.\-]{1,64}$ |
leaderboard-invalid-board |
| Score range | ±2^53-1 (JSON-safe integer) | leaderboard-invalid-score |
top page size |
1–100 entries (default 10) | clamped |
around range |
±1–50 entries (default 5) | clamped |
| Player name | 64 characters | trimmed to fit |
Leaderboard calls share the connection's message budget (20/s) — submit when a run ends, not every time the score ticks up.
Common mistakes
| Mistake | What happens | Fix |
|---|---|---|
Calling before start() |
not-connected |
Leaderboards ride the realtime connection |
Uppercase or spaced board names ("High Scores") |
leaderboard-invalid-board |
Use "high_scores" — lowercase, no spaces |
| Mixing modes on one board | Confusing best-score behavior | Pick one mode per board and stick to it |
Submitting lap times with "max" |
The worst time is kept | Use "min" for time-based boards |
| Storing scores in player storage | No ranks, not readable by other players | Storage is private per player; leaderboards are shared |
| Submitting every frame | Burns the message budget | Submit on run end / meaningful changes |
Next
- Protocol reference — the wire messages
- SDK reference — full method and model details
- Limits — every quota in one table