OffscreenCanvas: Multi-Threaded Canvas & WebGL Rendering in Web Workers
- Last updated
- Prerequisites:
- HTML5 Canvas 2D / WebGL basics
- Web Workers & Transferable objects
- browser
- canvas
- offscreen-canvas
- webgl
- web-workers
- gpu
Read at your depth
The practical view
`OffscreenCanvas` allows 2D and WebGL rendering to happen inside a Web Worker off the main thread. Call `canvas.transferControlToOffscreen()` on a regular DOM `<canvas>` and transfer it to a Worker via `worker.postMessage({ canvas: offscreen }, [offscreen])`. The Worker acquires a `2d` or `webgl` context and renders continuously without ever blocking UI clicks, animations, or DOM reflows.
The same idea in other frameworks
React Three Fiber (R3F) offloaded into a Web Worker via `@react-three/offscreen`.Three.js / Babylon.js canvas rendering managed in dedicated Angular Web Workers.Data visualization dashboards offloading Chart.js rendering to worker threads.Svelte canvas components delegating WebGL rendering to an OffscreenCanvas worker.Legacy vs modern
Main-Thread Blocking WebGL vs Worker-Based OffscreenCanvas
Main-thread canvas rendering stutters when JS tasks run; OffscreenCanvas guarantees 60/120 FPS rendering independent of main-thread load.
const ctx = canvas.getContext('2d'); renderLoop(); // ❌ Janks whenever main thread is busyconst offscreen = canvas.transferControlToOffscreen(); worker.postMessage({ canvas: offscreen }, [offscreen]); // ✅ NEWInterview gotchas
Context
Tests understanding of canvas context ownership and transfer constraints.
The mechanical answer
No. Once `transferControlToOffscreen()` has been called, control of the canvas context is permanently transferred. Calling `getContext()` on the original DOM `<canvas>` throws an `InvalidStateError` exception. All context acquisition must happen on the `OffscreenCanvas` instance inside the Worker.
Trap
Do not attempt to acquire a 2D context on the main thread and transfer the context object; you must transfer the *OffscreenCanvas* before getting any context.
Context
Checks knowledge of input event routing to Web Workers.
The mechanical answer
Because Web Workers do not have access to DOM event listeners, the main thread must attach DOM listeners (`pointerdown`, `mousemove`, `wheel`) to the `<canvas>` element and forward relevant serialized coordinates and input deltas (`event.clientX`, `event.clientY`, `event.deltaY`) to the Worker via `worker.postMessage()`.
Trap
Do not try to attach `addEventListener` to `OffscreenCanvas` inside the Worker; it is not an `EventTarget` for DOM input.