Define what the score means
The downloadable games currently keep scores only for the active round. This tutorial adds a personal best to Neon Snake in the player's browser. It is a suggested extension, not a feature already included in the ZIP. The saved value belongs to one browser profile and site origin. It will not follow the player to a different phone or become an online leaderboard.
Use a dedicated key such as gf-neon-snake-best-v1. The site already uses a separate key for saved template IDs; game data should not overwrite it. The version suffix leaves room for a future scoring rule that is no longer comparable with this one.
Read defensively
Add a visible best-score label near the score display, then put the JavaScript below in the game's script after the DOM exists. Here the label uses a span with id="best-score". Treat storage as optional: it can be blocked, cleared, or contain unexpected values.
const BEST_KEY = 'gf-neon-snake-best-v1';
const bestEl = document.getElementById('best-score');
let best = 0;
try {
const value = Number(localStorage.getItem(BEST_KEY));
if (Number.isSafeInteger(value) && value >= 0) best = value;
} catch {
// A round can still be played without persistent storage.
}
bestEl.textContent = String(best);Number(null) becomes zero when the key has not been saved yet, which is a suitable opening value here. The integer and nonnegative checks reject malformed data. This validation protects the display from accidental corruption; players can still edit their own browser storage.
Update at the moment the score changes
Add the following function after that setup. In Snake's food branch, call rememberBest(score) immediately after setScore(score). This location records new personal bests as they happen and avoids putting game-specific storage behavior in a shared scoring helper.
function rememberBest(value) {
if (value <= best) return;
best = value;
bestEl.textContent = String(best);
try {
localStorage.setItem(BEST_KEY, String(best));
} catch {
// Keep the best for this open page even if saving fails.
}
}Do not reset best in the round's reset function. Resetting the snake and score should begin another attempt while preserving the record. If you add a separate clear-record button, label it clearly and remove only this key. Calling localStorage.clear() would also delete unrelated data stored by your site.
Test the boundaries of persistence
Play until you collect food, reload the page, and confirm the best returns while the current score starts at zero. Next, set the saved value to an invalid string in the browser's storage panel and reload. The display should fall back to zero. Also test with storage blocked: the game should run, and the visible best should still update for that open page.
Use a local HTTP server for a predictable test origin, and then repeat on the deployed HTTPS site. Browser handling of storage for files opened directly from disk can vary. Moving from a local origin to the public site does not copy the old record.
Explain the feature honestly
Label the result “Best on this device” or “Personal best in this browser.” Provide a way to clear it if your interface offers data controls, and update the privacy description when deploying a version that stores scores. This site's current privacy page describes its current behavior; it does not automatically cover a separate modified release you publish.
A public leaderboard needs a different design. A server would need to receive scores, validate what it can, prevent simple abuse, and explain which data is public. Local storage alone is suitable for a lightweight personal record because it stays under the player's control.