Setup: Phaser 3.90 + Spine 4.1 WebGL game, mobile web. A portal page opens the game in a NEW tab via window.open(). Common iOS flow: player taps Back / switches to the opener tab → game tab goes hidden → iOS evicts it under memory pressure → returning to the tab = cold reload (or a white tab that reloads on focus). No pagehide/popstate ever fires in the game tab for this flow — only visibilitychange to hidden, so we can’t show a “quit?” prompt or save state at the normal lifecycle points.
What we log (localStorage boot-trail, classified on next boot): over a 2-week test soak on iOS we see both “killed while hidden” (tab eviction/OOM) and “died mid-load” cases — the mid-load ones cluster at our asset-load peak (~20 Spine skeletons loading), which matches the per-tab memory cap behavior others have reported (e.g. webkit.org bugs 261331 / 262628).
Mitigations we already run:
- Release the GL context after N seconds hidden when window.opener is set, restore on visibility (cuts VRAM while hidden)
- Idle-suspend: after 10s hidden, destroy the game + show a resume modal instead of letting iOS pick a kill moment
- ASTC (.ktx) compressed textures to lower VRAM baseline
- Freeing splash/loader assets after first render
Questions:
1. Anyone found a reliable signal to distinguish “returned after eviction” from a fresh boot, beyond a localStorage heartbeat?
2. Do you proactively lose the WebGL context on hidden, and has it measurably reduced eviction/reload rates for you?
3. Rough VRAM/heap budget you target to stay under Safari’s per-tab kill threshold on 3–4GB iPhones?
4. Has anyone just abandoned window.open and forced same-tab navigation from the portal? That’s our current “real fix” candidate — regrets?