Rudi Foodi stores completion times in two places — aDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/mbeckham4-hub/Rudi-Foodi/llms.txt
Use this file to discover all available pages before exploring further.
localStorage leaderboard for local high scores, and an optional Firebase Firestore global leaderboard that activates automatically when a real Firebase config is present. The same UI and score-entry flow handles both backends; the only difference is whether scores are written to a local JSON string or to a Firestore collection.
Local Leaderboard
Local scores are persisted under a versionedlocalStorage key so that future format changes can be detected without conflicting with stale data:
time— completion time in milliseconds, the primary sort keyusernameLower— lowercase copy used for duplicate-username checksdate— Unix timestamp of when the score was recorded
saveLeaderboard(entries)
getLeaderboard()
getLeaderboard() is async because it may need to await a Firestore get() call. When the global leaderboard is enabled it fetches from Firestore directly; otherwise it reads from localStorage:
formatTime(ms)
Completion times are displayed in M:SS format:
154500 ms renders as "2:34". The function discards sub-second precision when rendering, though the raw millisecond value is stored for accurate sorting.
openLeaderboard()
renderLeaderboard() awaits getLeaderboard(), sorts the results ascending by time, and populates #leaderboardList with <li> elements formatted as "username — M:SS".
Global Leaderboard (Firebase)
The global leaderboard uses the Firebase Firestore compat SDK (v10.12.5), loaded via<script> tags from the Google CDN.
Configuration
ThefirebaseConfig object sits near the top of the script. Replace every placeholder value with your project’s credentials from the Firebase Console:
The Enable Flag
The global leaderboard switches itself on or off based on whether theapiKey field still contains the placeholder string:
GLOBAL_LEADERBOARD_ENABLED is true and the firebase global is available (i.e., the CDN scripts loaded), the app is initialized and globalDb is set:
globalDb remains null and every leaderboard read/write falls back to localStorage silently.
Writing a Score
saveScoreOnlineOrLocal(username, time) writes to Firestore when enabled:
"leaderboard" collection with addDoc() (compat API: .add()). Documents are never updated — every submission creates a new document, so the same player can appear multiple times on the global board if they complete the game more than once.
Recommended Firestore Security Rules
Score Entry Flow
Game completes
The player reaches Level 20 and collects 30 treats, triggering the fly-away ending.
showEnding("🐶 Good job, you won!", true) is called.Capture completion time
Inside
showEnding, when completedGame is true, the elapsed time is computed: const completedTime = performance.now() - gameStartTime. This is stored in finalCompletionTime and passed to askForLeaderboardName(completedTime).Name entry panel appears
askForLeaderboardName(timeMs) sets finalTimeText to display the formatted time, clears any previous input, and shows #nameEntryPanel. The username input receives focus after a 50 ms delay to ensure the panel is visible.Player enters a username
The
#usernameInput accepts up to 18 characters (maxlength="18"). The #saveScoreButton click handler calls saveFinalScore().Validation
saveFinalScore() trims the input and rejects it if empty or if the lowercase username already exists in the current leaderboard. An error message appears in #nameEntryError on failure.Skipping Score Entry
The#closeNameEntryButton (“Skip”) hides #nameEntryPanel without saving anything. finalCompletionTime is still set, so if the player opens the leaderboard manually later from the title screen, their un-submitted time is not re-offered.