Developer
Scores & achievements
Any game on June 17 can post scores to a top-10 leaderboard and unlock achievements you define. Unlocks and new #1s flow into the community feed and every player’s public profile. It’s two small steps: turn it on for your game, then have the game report as people play. This works the same whether you hand-write HTML5 or build in the editor.
00How it works
Your game runs in a sandboxed frame. It reports events by posting a message up to the June 17 page, which validates it, records it against the signed-in player, and updates the boards. You never handle auth, storage, or ranking — you just report two things:
- a score — a single number (points, coins, seconds, moves…); and
- an achievement key — a stable id for a milestone you defined.
The rest — best-per-player, top-10 ordering, unlock counts, the community feed, profiles — is handled for you.
01Enable it on your game
Open your game in the creator dashboard (Creator → your game → Manage) and set it up once:
- Leaderboard — toggle it on, set a value label (e.g. “points”, “seconds”), and tick Lower is better if a smaller number wins (times, moves, strokes).
- Achievements — add each milestone: an icon, a name, a short description, points, and a key. The key is the stable id your game reports — lowercase, e.g.
first_win,score_100.
Keys are the contract
An achievement only unlocks if the key your game reports exactly matches a key you defined. Reporting an unknown key is silently ignored, so a typo fails quietly — double-check them. You can add or rename achievements any time.
02aReport from an HTML5 game
Post a message to the parent window. The message is a plain object with one of two keys. Nothing else is required — no SDK, no import, no origin to configure.
// Submit a score (the player's best is kept automatically)
parent.postMessage({ j17score: 1280 }, "*");
// Unlock an achievement by its key
parent.postMessage({ j17achievement: "first_win" }, "*");Call them at the natural moments — game over, a level cleared, a personal best. A tiny helper keeps it tidy:
function j17(msg) {
try { parent.postMessage(msg, "*"); } catch (e) {}
}
// on game over:
j17({ j17score: score });
if (score >= 100) j17({ j17achievement: "score_100" });
if (won) j17({ j17achievement: "cleared" });Safe outside June 17
When your game runs anywhere else (local testing, another site), parent is just the window and the message goes nowhere — so these calls are always safe to leave in. Wrap them in try/catch as above and they never throw.
02bReport from an editor game
Games built in the scene editor use the .j17 language — two verbs do the same thing, in any script effect (a hotspot, an item use, a dialogue line, a mini-game result):
score <expr> # report a number to the leaderboard
achievement "<key>" # unlock a milestone by keyFor example, reporting the player’s gold as their score and unlocking a milestone when they cross 100:
set gold = gold + coins
score gold
if gold >= 100 then
achievement "rich"
endscore takes any numeric expression; achievement takes the key (quote it if it has spaces — plain keys like first_win don’t need quotes). Both are no-ops in a standalone preview, so they never break a local run.
Show the score on screen. Add a text element on the HUD tab and use the {total} token — it renders the live leaderboard total (the same number score reports) and updates every frame. Drop it in a corner, e.g.:
SCORE: {total}{total} is the running leaderboard score. It’s separate from {score}, which interpolates a plain game variable you set yourself (set score = …); other tokens like {gold}, {active}, and {game.var} work too.
Rebuild to pick them up
score, achievement, and the {total} HUD token ship with the current editor engine. If you built your game before they existed, re-export it from the editor so the new engine is bundled.
03How scores are ranked
- Best per player. We keep each player’s best score for your game — reporting a worse one changes nothing. Report freely and often; only an improvement counts.
- Direction. Higher wins by default. Turn on Lower is better for times, moves, or strokes and the whole board flips.
- The board. Your game page shows the top 10 with avatars and names; the signed-in player is highlighted, even if they’re outside the top 10.
- A new #1 (overtaking someone, or the first score ever) posts to the community feed.
04How achievements unlock
- Idempotent. Reporting a key the player already has does nothing — safe to fire every time the condition is met, no need to track “already unlocked”.
- By key. Only keys you defined unlock; unknown keys are ignored.
- Feedback. A first-time unlock shows the player a toast in-game, and appears on your game page (with a global unlock count) and on their profile.
05Where it appears
Once your game reports, the data surfaces across June 17 automatically:
- Your game page — the top-10 leaderboard and the achievement grid.
- Community → Activity — a live feed of unlocks and new #1s.
- Community → Players — the all-time ranking (points, achievements, #1s, games).
- Player profiles — everything a player has earned across games.
Players can hide their profile and activity in their settings; a hidden player keeps their leaderboard spot but drops off the feed and the players chart.
06Fair-play validation
Because your game runs in the player’s browser, a determined cheat can post a fake score. You can’t make that impossible without running the game on a server — but you can reject the obviously-impossible cheaply, by declaring bounds on your game’s Manage page. June 17 checks each reported score against them (and against how long the player actually played) and silently drops anything out of range.
Max score
The highest a score can ever legitimately be. Reject anything above it.
Min score
A floor — useful for lower-is-better games (a puzzle can’t be solved in fewer than N moves).
Max per second
Higher-is-better only. The most points earnable per second of play; a score above played × rate is rejected.
The per-second cap is the strong one — it uses the play-time June 17 already tracks, so a “999,999 in 4 seconds” submission fails on its own. A small grace is added for heartbeat lag, so set the rate a little above your true best-case, not exactly on it. Leave any field blank to skip that check; with none set, scores are accepted as-is.
A deterrent, not a guarantee
Bounds stop casual forgery — the “opened the console” crowd — not a patient cheat who submits a plausiblefake. For a leaderboard that gates money or prizes, the only real fix is to compute the score on a server you control (or submit a verifiable replay) and report that. For casual and social boards, bounds are the right call.
07Limits
- Signed in. Only signed-in players are recorded — anonymous play reports nothing (and never errors).
- Rate limited. Score and achievement reports are throttled per player; fire them at real moments, not every frame.
- Bounds. Scores are whole numbers and capped at a sane maximum; achievement keys are trimmed to 80 characters. Add your own fair-play bounds for tighter, game-specific checks.
← Developer · Questions? Ask in the community.