How to Configure Three.js WebGLRenderer for Screenshots

This article explains how to configure the Three.js WebGLRenderer using the preserveDrawingBuffer property so users can successfully capture and download screenshots of a 3D canvas. By default, WebGL clears the drawing buffer after presenting the render, resulting in blank or black images when attempting to save the canvas. Setting this property to true resolves this issue, allowing for seamless image generation.

Why Three.js Screenshots Fail by Default

When you attempt to capture a screenshot of a standard Three.js canvas using canvas.toDataURL(), you will often get a completely blank or black image.

To optimize performance and save GPU memory, the WebGL context automatically clears its drawing buffer immediately after rendering the frame to the screen. By the time your JavaScript code attempts to read the canvas data, the buffer is already empty.

Enabling preserveDrawingBuffer

To prevent the browser from clearing the drawing buffer, you must explicitly set the preserveDrawingBuffer option to true when initializing your WebGLRenderer.

Here is how to configure the renderer:

import * as THREE from 'three';

// Create the renderer with preserveDrawingBuffer enabled
const renderer = new THREE.WebGLRenderer({
    canvas: document.querySelector('#myCanvas'),
    preserveDrawingBuffer: true
});

renderer.setSize(window.innerWidth, window.innerHeight);

By enabling this setting, the browser retains the rendered pixels in the buffer, making them accessible to standard browser APIs at any time.

How to Capture and Download the Screenshot

Once the renderer is configured, you can extract the image data from the canvas element using renderer.domElement.toDataURL() and trigger a download.

function takeScreenshot() {
    // 1. Force a render pass right before capturing to ensure the latest frame is captured
    renderer.render(scene, camera);

    // 2. Get the data URL from the canvas
    const dataURL = renderer.domElement.toDataURL('image/png');

    // 3. Create a temporary link element to trigger the download
    const link = document.createElement('a');
    link.download = 'threejs-screenshot.png';
    link.href = dataURL;
    
    // 4. Programmatically click the link to trigger the download dialog
    link.click();
}

// Example: Trigger screenshot on button click
document.getElementById('screenshotButton').addEventListener('click', takeScreenshot);

Performance Consideration

While setting preserveDrawingBuffer: true is the easiest way to enable screenshots, it does come with a minor performance cost. Because the browser cannot discard the drawing buffer after rendering, it requires more GPU memory and can slightly decrease frame rates on mobile or lower-end devices.

If absolute peak performance is critical for your application, keep preserveDrawingBuffer: false and instead call your screenshot capture logic inside the same execution frame as your renderer.render() call, immediately after the render function executes.