Leaderboard
A Leaderboard ranks players by the value of a Variable. You can use leaderboards to track high scores, fastest times, longest streaks, or any other numeric value you want to compare across players.
Saving to a leaderboard
Use the Save a variable to the leaderboard response in a Rule to write the current value of a variable to the leaderboard. Both the highest and lowest values are tracked automatically — you don't need to save separately for "high score" vs "fastest time" boards.
A common pattern is to save after a game-ending event:
When this collides with tag #finish-line:
Save variable $time to the leaderboard
Showing a leaderboard
Use the Show the leaderboard for a variable response to display the leaderboard UI to the player. You choose whether to sort high (highest first, for scores) or low (lowest first, for times), and provide a label that appears at the top of the leaderboard.
When this receives a message "game over":
Save variable $score to the leaderboard
Show the leaderboard for $score (sort: high, label: "High Scores")
Scopes
By default, a leaderboard is global — it tracks all players across all time. You can narrow the scope so that the leaderboard resets or is partitioned in different ways.
Global
The default. One leaderboard for all players, all time. A player's best score is preserved indefinitely.
Daily
The leaderboard resets each day. This is the most common scope for daily challenges — yesterday's scores are cleared and everyone starts fresh.
When using daily scope, you choose a timezone that determines when the day boundary falls:
| Timezone | Behavior |
|---|---|
| Player | The leaderboard resets at midnight in each player's local timezone. Two players in different timezones may be on different "days" at the same moment. |
| Castle | The leaderboard resets at midnight in Castle's server timezone. All players share the same day boundary, which is important if you want everyone competing on exactly the same daily challenge. |
For daily challenges where every player should face the same content, use Castle timezone — and pair it with setting the random seed to today's date so that the generated content is the same for everyone on a given day.
Card
The leaderboard is scoped to the current Card. Each card in your Deck gets its own independent leaderboard. This is useful if your deck has multiple levels or challenges that should be ranked separately.
Custom
You provide a custom scope identifier (an Expression that evaluates to a number). The leaderboard is partitioned by this value — entries with different scope values are on separate leaderboards.
This is the most flexible option. Some examples:
- Weekly leaderboards: Use the current date "days since Castle epoch" divided by 7 (floored) as the scope. Each week gets a new leaderboard.
- Per-level leaderboards: Use a variable that tracks the current level number as the scope.
- Tournament rounds: Use a round number as the scope.
Scripting
Leaderboards are also accessible from Lua scripts:
-- Save to a global leaderboard
castle.writeToLeaderboard("score")
-- Save to a daily leaderboard (Castle timezone)
castle.writeToLeaderboard("score", "daily", "Castle")
-- Save to a custom-scoped leaderboard
castle.writeToLeaderboard("score", "custom", "week-1")
-- Show a leaderboard
castle.showLeaderboard("score", "high", "High Scores")
castle.showLeaderboard("score", "high", "Today's Best", "daily", "Castle")