knowledge base/practices

A WebGL canvas reads back blank except straight after drawing

Fact

With preserveDrawingBuffer: false (the default), the drawing buffer is cleared once a frame is handed to the compositor. toDataURL, toBlob or drawImage(webglCanvas) return the picture only in the same task as the draw calls; at any other time they give a blank (transparent or black) image.

Why it matters

DOM-to-image screenshot libraries copy each <canvas> with toDataURL at some later moment, so a 3D view comes out empty while the HTML around it is fine. Turning preserveDrawingBuffer on to fix it costs performance on every frame, not just when a picture is taken.

How to apply

Take the 3D view yourself, in one task: render, then read back at once.

renderer.render(scene, camera);
const scene3d = canvas.toDataURL('image/png');

For a whole-page screenshot, leave the WebGL canvas out of the DOM snapshot (filter it, transparent background) and draw that snapshot over the image you read back.