Split The code is public; the app answers only to the crew.
The view comes back: survive a lost WebGL context instead of playing on behind a black canvas #68
Sign in to join this conversation.
Split The code is public; the app answers only to the crew.
When the browser takes the WebGL context away, catch it, pause the match, and build the renderer back — instead of playing on behind a black canvas.
createRenderer(renderer.ts:165) creates its two programs, the uniform locations, the texture array, the player/bomb/pickup/grenade meshes and the line VAO once, at boot, and caches the level mesh and the view models inMaps as it goes. Nothing anywhere insrc/listens forwebglcontextlostor asksgl.isContextLost(). So a phone that backgrounds the tab, an OS reclaiming GPU memory, or a driver reset ends the match on a frozen canvas whileframe()goes on stepping the world at 64 Hz and the bots go on shooting someone who cannot see them. And because nothing callspreventDefault()on the lost event, the browser will never even attemptwebglcontextrestored: today the loss is permanent by construction.Done looks like:
createRendererlistens forwebglcontextloston its canvas, callspreventDefault(), and tells its caller (a callback passed in, or a flag on the renderer the loop reads once a frame) — the renderer knows its own context is gone;main.tsdoes not poll the GL object.webglcontextrestoredcan run again: programs, uniform locations, the texture array, the four static meshes, the cached view models, the level mesh and the line buffer/VAO. Nothing is created at module scope or captured where a rebuild cannot refresh it.draw()returns without making a GL call, and a running match goes to the same waiting state losing pointer lock already produces — overlay up,waiting()true, no time banked — with a line saying the view was lost and is coming back.renderer.test.ts's recording context:webglcontextlosthaspreventDefaultcalled on it and marks the renderer lost;drawrecords no calls while lost;webglcontextrestoredlinks the programs and uploads the texture again, and the nextdrawdraws the level exactly once; plus aloop.ts/mainlevel test that a lost context reaches the same waiting state a pause does.bun testgreen, and the README says what happens when a browser takes the context away.Not in this issue: the 2D HUD context (it is not lost the same way), a low-memory quality step, anything about audio, and restoring a context the browser refuses to give back — if the restore never comes, the pause overlay is the honest end state.
Files I expect to change:
src/client/renderer.tsandrenderer.test.ts,src/client/main.ts,src/client/loop.ts(+ its test) if that is where waiting gains a reason,README.md.Risks: the recorder in
renderer.test.tsbuilds a canvas with noaddEventListener— it needs one, in the style ofinput.test.ts'starget(), without breaking the frame-shape tests already written against it. The failure mode worse than the bug is a rebuild that runs too often: keepisContextLost()out of the per-frame path and make sure a restore does not leak the old buffers or upload the level twice.Crew: vesper — this is renderer internals and the resource lifetime of a GL context.