A backgrounded replay of the G=530 field crashed: the map-tile LRU held up to 768 offscreen canvases (~1 MB each at dpr 2), the kind of memory that gets a hidden tab discarded. The cache is capped at 160 (about 40 are visible), and a hidden tab pauses playback and drops the cache.
- commit
- 0e9b86b40c04d8b711bd45fc5cb03cc4cc5bf5b4
- parent
- e7afacc6ee0086f3ba16d8008a21e1e3fa902dd8
- author
- dami <gazey55@gmail.com>
| M | site/ | 21 | ++++++++++++++++++++- |
@@ -692,7 +692,11 @@ export default function Viewer(
692692 const canvasRef = useRef<HTMLCanvasElement>(null);693693 const paneRef = useRef<HTMLDivElement>(null);694694 const scene = useRef(new Scene());695- const cache = useRef(new TileCache<Raster>(768));695+ // ~40 map tiles are visible at once; 160 keeps one level plus its696+ // neighbours warm without holding hundreds of megabytes of canvases697+ // (at dpr 2 a raster is ~1 MB), which is what gets a background tab698+ // discarded by the browser699+ const cache = useRef(new TileCache<Raster>(160));696700 const log = useRef(new ChangeLog());697701 const perf = useRef<Perf>({ frames: [], redraws: [], visible: [] });698702 const [events, setEvents] = useState<GameEvent[]>([]);@@ -848,6 +852,21 @@ export default function Viewer(
848852 if (p && live) p.scrollTop = p.scrollHeight;849853 }, [state.revision, live]);850854 855+ // a hidden tab keeps nothing expensive: playback pauses, the raster856+ // cache is released (rebuilt in a few frames on return)857+ useEffect(() => {858+ const onVis = () => {859+ if (document.hidden) {860+ setPlaying(false);861+ cache.current.clear();862+ } else {863+ requestAnimationFrame(() => setRev((r) => r));864+ }865+ };866+ document.addEventListener("visibilitychange", onVis);867+ return () => document.removeEventListener("visibilitychange", onVis);868+ }, []);869+851870 // playback852871 useEffect(() => {853872 if (!playing) return;