Recipes
Leaderboards rankings and persistent high scores
Players want to see who is on top across sessions: highest score, fastest time, most wins. A leaderboard is durable per-player records plus a ranking sort you do in a script. There is no
StatsComponent (stripped) and no built-in ranked board.engine v1.0.234since script-semantic-patch-ops.v1, action-catalog.v1.0.232, persistence.v1, match.v1, ui.v1Copy for LLM
Use this for
a persistent leaderboard of top players; a high-score table that survives sessions; ranking players by best score or best time; a top-N standings board
Not for
the in-match phases and win check (see match-flow-and-scoreboards); a simple per-run score counter (see collectibles-and-scoring); durable saves that are not ranked (see saves-and-persistence)
Pairs with: Match flow phases scoreboards and win conditions, Saves persistence player progress and data stores, Collectibles pickups scoring and win condition, UI HUD panels widgets and world nameplates
The recipe
Author with project_apply_script_semantic_patch using the ai_safe op pack; the warehouse reads happen in a GessaScript body.
- Persist each player's best: on run end, compare the new score to the stored best and
writeTypedStateValuethe larger (orincrementNumericStatea running total) into a durable record keyed by the durable player id, in a leaderboard store (for examplestoreKey:"leaderboard", one record per player). - Track live scores in a match with
ctx.match.addScorefor a subject and read withctx.match.getScore; mirror the current value to the HUD withwireHudStateBinding. - Build the ranked list: in a GessaScript body,
ctx.warehouse.querythe leaderboard store to read the records, then SORT them by the score field yourself. Records come back ordered by recordKey in canonical collation, not by value, so the ranking order is your computation, not the query. - Page large boards: pass the query result
nextCursorback verbatim to walk pages; take the top N after sorting rather than assuming the first page is the top. - Show it: push the ranked names and scores into a UI panel (see ui-hud-panels-and-widgets) with
ctx.ui.setWidgetValue, or bind a single headline stat withwireHudStateBinding.
Pitfalls
- Warehouse query does NOT sort by value; do not expect an orderBy. Read the records and rank them in the script.
- Key each record by the DURABLE player id, not a per-session id, or the board resets every match (the same rule as a persistent scoreboard subject key).
- Warehouse writes are prefetch-then-drain and authority-gated; update the best on the server at run end, not per tick.
- A giant board is costly to read every frame; recompute the ranking on score change or on a timer, not each tick.
Verify
simulation_run(qa.run.start) to prove a new best updates the record and the ranked list reorders.project_get_graph_snapshotto confirm the score-write handlers and the HUD binding landed.