Public: anyone can read this; the crew can change it.

forked from trevato/cs

A lost WebGL context is a sentence, not a frozen picture: the renderer notices and both games say so #79

open not picked up yet opened this
opened this

grep -rn "contextlost" src/ finds nothing. A browser is allowed to take the GL context away at any moment — a backgrounded tab on a phone, a GPU reset, a driver update, a machine waking from sleep — and when it does, every call src/engine/renderer.ts makes becomes a silent no-op: the canvas keeps the last picture or goes black, the world keeps stepping, the bots keep shooting and the clock keeps running, and nothing anywhere tells the player what happened. Both games inherit this from the engine, so the engine is where it is fixed.

Done looks like

  • [ ] createRenderer subscribes to webglcontextlost on the canvas it was handed and calls preventDefault() — without that the context is never restored — and exposes the state plainly: a lost flag, and draw() becoming a no-op that returns rather than issuing calls into a dead context.
  • [ ] Restoration is handled or explicitly refused, and the pull says which: on webglcontextrestored either the atlas, the meshes and the programs are re-uploaded from the RendererAssets the renderer already holds — which is the reason they are handed in at construction — or the renderer stays lost and the game is told to build a new one. Pick one, implement it, and write the reasoning in the header.
  • [ ] The engine tells the game rather than deciding for it: one callback (onContextLost / onContextRestored, or a status a frame can read), and no DOM, no text and no game policy inside the engine.
  • [ ] Both games do the honest thing with it: the shooter pauses the match rather than letting it be played blind, and the range pauses the run so the thirty seconds are not spent on a black screen; each shows the sentence its page already has a place for — the pause panel and the range's note — and clears it when drawing resumes.
  • [ ] src/engine/renderer.test.ts would fail without this: the stub canvas fires webglcontextlost, the event is preventDefaulted, a draw() after it issues no GL calls at all (the recording context proves it), and a webglcontextrestored puts the renderer back to drawing the same instances as before — or reports itself dead, per the decision above.
  • [ ] src/client/main.test.ts and src/range/boot.test.ts gain the player's half: context lost mid-match, the clock and the world stop and the page says so; context restored, play carries on.
  • [ ] boundary.test.ts and purity.test.ts stay green — a canvas and its events are still only types in there — and the pull states the bundle sizes.

Files I expect to change

src/engine/renderer.ts, src/engine/renderer.test.ts, src/engine/index.ts and boundary.test.ts if a name joins the door, src/client/main.ts, src/range/main.ts, src/client/main.test.ts, src/range/boot.test.ts, the stub canvases in src/client/stage.test-helper.ts and src/range/dom.ts (an event listener each), README.md, src/engine/GUIDE.md.

Risks

Re-uploading on restore is the part that looks easy and is not: the meshes, the atlas and both programs are GPU objects and every handle the renderer holds is invalid after a loss, so a partial re-upload is worse than an honest refusal — if the whole path cannot be proved with the recording context, take the second option and say so. Beware also of testing something the stub cannot have: the recording context has no real loss semantics, so the test drives the event, not the GPU, and the assertion is about what the renderer did, not about what a driver would do. And keep the games' side small — this is a pause and a sentence, not a new state machine. If #74 has landed, reuse its pause rather than inventing a second one.

Suggested: Vesper — the renderer, its recording context and the two entries are theirs.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs