Offline Progress & Saves
How offline catch-up replays your run, the offline cap, death handling, and cloud saves.
On this page
Leave with combat running and the game replays the time you were away the next time you load. This is not a statistical estimate — it is the real engine ticked forward, so the outcome is exactly what would have happened if you had left the tab open. That includes finding loot, gaining levels, clearing dungeons, using potions, taking durability damage — and dying.
When offline catch-up runs
The replay runs only if combat was active when you exited. If you stopped combat, sat in town, or were on a safe tile, offline time produces zero progress — you come back exactly as you left.
if (offlineSeconds <= 0 || !combatWasActive || heldAtBoss) → zero-progress summary, no replay
heldAtBoss is the one extra case: a dungeon run parked on a first-clear boss waiting for your
“Start Fight” can’t progress a single tick, so the replay is skipped outright instead of spinning
through hours of empty ticks.
How the replay works
Catch-up steps the simulation in fixed 1/20-second ticks (20 tps) — the same rate as live play:
steps = floor(offlineSeconds / (1 / 20)) // = offlineSeconds × 20
Each tick runs the full stepSimulation, so every mechanic behaves normally: attacks, respawns,
potions, DoTs, buff expiry, drops, auto-sell, crafting completion, and death. Because it is the real
engine, the result is exact and can be dangerous — a long absence in a fight you can’t sustain will
replay your death, not hand-wave it.
What does and doesn’t carry over
The hero never travels during a replay — except while auto-exploring, where it moves on to the next tile after each clear exactly as in live play (the recap shows an “Areas explored” row and lists the clear reward items). Otherwise it is the tile you left on, fought over and over. Everything the kill pipeline normally does happens with it, including camp-quest progress and slot cooldowns and Region Resonance kill quotas. An Endless Delve run you logged out of mid-descent keeps descending (its kills still grant no XP).
The one system held back is monster hunts: a mark never shows itself during the replay, so a hunt can only be finished in live play. The scout timer itself is wall-clock and does complete while you’re away, as do smith/witch commissions and bedroom construction (those three run whether or not combat was active).
Early-stop condition
The replay stops fighting early on this, so you can react instead of replaying past a decision:
| Trigger | What happens |
|---|---|
| Tile unlocked (not while auto-exploring) | Combat is suspended so the unlock modal can show; it is running again when you take over. |
A death ends combat as it does in live play. See Death for what it costs.
Winding down to full health
Neither ends the replay outright. Once combat is suspended, the remaining offline time keeps
ticking as out-of-combat regeneration (HERO_OUT_OF_COMBAT_REGEN_RATE = 1/60, so a full bar takes 60
seconds) until your health is back at 100%, and only then does the replay finish. You never come back
standing on a corpse or on the sliver of health a tile clear left you with — as long as enough offline
time was left to heal it. The same applies to a death: the replay idles through the respawn
regeneration before it stops.
The recap prompt
When you load, an offline-progress recap summarizes kills, levels, gold, XP, dungeon clears, deaths,
and found items. It is suppressed for absences of 5 minutes or less (OFFLINE_PROMPT_MIN_SECONDS = 5 × 60), and also skipped if nothing meaningful changed:
show recap ⇔ offlineSeconds > 300 AND combatWasActive AND (any of:
kills, levels, gold≠0, dungeon clears, xp, deaths, found items,
or Resonance quota progress)
A tab you leave open in the background counts as away too. Your hero fights on live, under the same offline cap as after closing the game: once the cap is used up it rests until you switch back. Then the fight on screen simply carries on from where it is now (nothing is replayed), and the same recap sums up the time the tab was away under the same rules.
Items you listed on the Trading Board sell while you are away. The recap then adds a Trading Board row (how many sold, gold received) and shows up for that alone, even after a short absence or with combat off.
The offline cap
Offline time is clamped so it can’t accrue indefinitely:
maxOffline = 8 hours × (1 + 0.10 × offlineCapLevel)
The base cap is 8 hours (MAX_OFFLINE_SECONDS). The Offline Cap Bedroom upgrade
adds +10% per level up to level 10, doubling the cap to 16 hours at max.
| Offline Cap level | Multiplier | Max offline |
|---|---|---|
| 0 | ×1.0 | 8 h |
| 5 | ×1.5 | 12 h |
| 10 (max) | ×2.0 | 16 h |
Worked example — level 10: 8 h × (1 + 0.10 × 10) = 8 × 2.0 = 16 hours. Anything beyond 16 hours
of real absence is discarded; the replay only ever simulates up to the cap.
Saves
| Property | Value |
|---|---|
| Storage | Cloud-only (Supabase backend) — no local save file |
| Slots | 5 per account (SAVE_SLOT_COUNT) |
| Save format version | 4 (SAVE_VERSION) — mismatched versions are rejected as incompatible on load |
| Autosave poll | Every 1 second, change-detecting |
| In-combat write throttle | At most once per 15 seconds |
| Out-of-combat writes | Debounced (only when the save signature actually changes) |
| On tab close | A final guarded save fires on beforeunload |
A change-detecting poll runs every second; idle regen never changes the save signature, so it never schedules a redundant write. In-combat changes are throttled to one write per 15 seconds, and out-of-combat changes are debounced.
What a slot shows in the main menu
Each filled slot carries one combined hero line plus the save time:
Level 34 Berserker - Fighting in Cursed Swamp (12)
Last Save on <timestamp in your language's format>
The location is the region (or dungeon, or the Endless Delve (Level N)) with the tile’s effective
rank in brackets. If combat was not running when the slot was last saved, the line reads
Level 34 Berserker - idling instead.
Game version
Every save records the game version it was last written with. The slot card only shows it when it differs from the game’s version.
- Older save: the slot shows an Update badge. Loading it opens a prompt with a one-line summary of each release since that version and what happens to your save data; Update & Load migrates it.
- Newer save (made with a newer game build): the slot shows Too new and loading is blocked. The save is not touched.
When a new version is released while the game is open, the tab notices (on focus, or every 10 minutes): in the main menu it reloads by itself, and before a slot starts it reloads instead of loading. In game a New Version Available prompt offers Reload now (saves first, then reloads) or Later.
Single active session per character
Each character can only be actively played in one session at a time. When a session loads a character it claims the slot, and there are two layers enforcing exclusivity:
- Instant broadcast — a realtime channel (
char:<user>:<slot>) tells any older session that a new one has claimed the character, bouncing it to the menu. - Guarded write — every autosave is a conditional update that only succeeds while this session
still owns the slot. If another session has claimed it, the write returns
supersededand the losing session returns to the menu instead of clobbering the newer save.
The last session to load a character always wins. The guarded write is the source of truth, so correctness holds even if the instant broadcast is never delivered (e.g. a suspended mobile tab).
Anonymous guest sessions are supported (a real backend user with no email), and can later be upgraded in place to a full account without migrating any save data.
Settings
The Settings modal opens from the in-game menu (the button in the bottom-right corner). It mixes two scopes: most toggles ride along in the character’s save, while audio and language belong to the account.
Per-character settings
These are stored in the save file, so they follow the character rather than the browser:
| Setting | What it does |
|---|---|
| Show the next item after selling | Keeps the sell flow moving through a haul |
| Show a sell confirmation in inventory | Confirm prompt on single inventory sales |
| Skip camp to world map | Switching to the Camp tab opens the world map straight away instead of the camp scene |
| Show detailed combat-log lines | Per-swing hits, misses, blocks, casts and status. Drops, XP/gold and system messages always show |
| Show first-time help | A Help window opens the first time you visit each tab or panel |
| Default town tab on load | Which town tab a freshly loaded character lands on |
| Default inventory sort | Sort mode applied on load |
| Default inventory filter | Filter applied on load |
Next to Show first-time help sits a Reset help overlays button: it clears the “seen” record for this character, so every Help window opens again on its next visit.
Audio & language (account-wide)
The Audio group carries a master switch and volume plus separate enable/volume pairs for music, sound effects (hits, blocks, misses, potions, buttons, level-ups) and ambience (a background bed per region, dungeon and delve, with a tension layer while you fight). Those four buses and the game language live in one cloud row per account, not on the character and not on the device, so they follow you across every character and every browser you sign in from. The cloud row wins over whatever the device had cached the moment you sign in.
Two settings are deliberately not in this modal: the auto-potion threshold and the loot filter both live on the Combat config card (the filter is also reachable from the inventory toolbar).
The leaderboard
Served by the get_leaderboard RPC and opened from the in-game menu (the hamburger button). It
lists the top 10 characters in four columns:
| Column | Value |
|---|---|
| Rank | Position in the sorted list |
| Name | Hero name |
| Level | Hero level |
| Delve | Deepest Endless Delve level ever reached (0 if never delved) |
Sorting is level descending, then delve highscore descending, then name. Only confirmed, registered accounts are eligible: guest characters and unconfirmed sign-ups are filtered out. Your own row is highlighted.
Installing the game
The game ships a web app manifest and a service worker, so browsers offer their normal Install app / Add to Home Screen option. Installed, it launches in its own standalone window with its own icon instead of a browser tab.
The installed game keeps its game files on your device (art, icons, maps, about 320 MB). Shortly after the first launch it downloads them once in the background; a small panel in the corner shows the progress and says when they are saved, and you can play meanwhile. From then on the game loads them from the device instead of the server. After an update it downloads only the files that changed (a small update does this without the panel). If a download is cut off, the next launch carries on where it stopped. A game opened in a normal browser tab downloads nothing extra.
It is still not an offline app: playing needs a connection to the game server, which runs the game; only the files are local. Every launch still checks for a new version, so you always play the current one. Your heroes are unaffected, they live on the server.
See also
- Bedroom Upgrades — the Offline Cap upgrade that raises the 8 h → 16 h ceiling.
- Death — what a death costs, including during an offline replay.