Quick answer: Listen for webglcontextlost and preventDefault() it (this allows restoration). On webglcontextrestored, recreate every GPU resource — textures, buffers, shaders.
A browser game running for a while goes blank. The GPU process crashed or the OS reclaimed the context. Without handling, WebGL never comes back.
Listen and Prevent Default
canvas.addEventListener("webglcontextlost", (e) => {
e.preventDefault(); // REQUIRED for restoration to be possible
cancelAnimationFrame(rafId);
gpuResourcesValid = false;
}, false);
Without preventDefault, the browser won’t fire the restored event — the context is gone permanently.
Recreate on Restore
canvas.addEventListener("webglcontextrestored", () => {
initGLState(); // blend modes, etc.
recreateShaders();
reuploadTextures(); // from CPU-side copies
recreateBuffers();
gpuResourcesValid = true;
rafId = requestAnimationFrame(loop);
}, false);
All GPU objects are invalid after loss. Recreate from CPU-side source data — which means you must keep that source data around.
Keep CPU-Side Copies
Texture pixels, vertex data, shader source — retain them (or be able to re-fetch). If you discarded them after upload, you can’t restore.
Engine Note
Unity WebGL, Godot Web, and Construct 3 handle context loss internally to varying degrees. For hand-rolled WebGL or three.js, you own this.
Verifying
Simulate loss via the WEBGL_lose_context extension in dev. The game pauses, then restores and resumes rendering. No permanent blank canvas.
“Context loss is normal on the web. preventDefault, keep CPU copies, recreate on restore.”
Test context loss explicitly — it’s rare in dev but common on real devices under memory pressure, especially mobile browsers.