Make progress survive a browser refresh. A real game remembers you.

Without persistence, closing the browser erases everything. We use localStorage to save and load the game state. But not everything should persist — some things are intentionally reset. What you choose to save is a design decision, not just a technical one.

Ami — Combat Risk Engine

What persists: Banked XP.

What does NOT persist: Unbanked XP. It is "at risk" — closing the browser is like dying. This reinforces the banking mechanic.

Ida — Economic Growth Engine

What persists: Karma and debt.

What does NOT persist: Active jobs. You have to accept new jobs each session. This means every play session starts with a fresh decision.

Save game state to localStorage:

function saveGame() { // Only save what should persist const saveData = { bankedXP: gameState.bankedXP, karma: gameState.karma, debt: gameState.debt // Do NOT save: unbankedXP, activeEvent, riskLevel }; localStorage.setItem("gameState", JSON.stringify(saveData)); console.log("Game saved!", saveData); }

Load game state on page start:

function loadGame() { const saved = localStorage.getItem("gameState"); if (saved) { const saveData = JSON.parse(saved); // Restore only persistent values gameState.bankedXP = saveData.bankedXP || 0; gameState.karma = saveData.karma || 0; gameState.debt = saveData.debt || 0; console.log("Game loaded!", saveData); } else { console.log("No save found. Starting fresh."); } // These always start fresh gameState.unbankedXP = 0; gameState.activeEvent = null; gameState.riskLevel = 1; gameState.zone = "safe"; }

Call saveGame() whenever state changes (after banking, after resolution). Call loadGame() on page load:

// On page load loadGame(); // After banking XP function bankXP() { // ... banking logic ... saveGame(); // Persist the banked XP }

Add a "New Game" button that clears everything:

function newGame() { localStorage.removeItem("gameState"); // Reset all gameState to defaults gameState.bankedXP = 0; gameState.unbankedXP = 0; gameState.karma = 0; gameState.debt = 0; gameState.riskLevel = 1; gameState.activeEvent = null; gameState.zone = "safe"; console.log("New game started. All progress cleared."); }
  • Add save function that writes to localStorage
  • Add load function that reads on page load
  • Choose what persists and what doesn't
  • Test: refresh browser — progress remains
  • Test: verify unbanked XP / active jobs reset on refresh
  • Add a "New Game" button that clears localStorage
  • Checkpoint

    Refresh the browser. Banked progress remains. Unbanked progress is gone. This is intentional design.

    No cloud saves. Local only. No save slots. One save per game.

    Saving everything — including things that should reset. Be deliberate about what persists.

    Not parsing JSON on loadlocalStorage.getItem() returns a string. You must JSON.parse() it.

    Overwriting saved data with default state on load — make sure you load before initializing defaults, not after.

    Not handling the case where no save exists — the first time, getItem() returns null. Check for it.

    Ask: "Why should some things persist and others not?" This teaches that persistence is a design choice, not just a technical feature. The decision about what to save IS game design. Unbanked XP resetting on refresh reinforces the banking mechanic from Day 13 — it makes the browser itself part of the risk system.