Minimal demo: winit runs on the main thread, wgpu renders in a worker.
main thread worker
───────────── ──────────────────────
winit EventLoop wgpu Surface
↓ transferControlToOffscreen on OffscreenCanvas
↓ postMessage("init", canvas) ─→ surface / device / queue
↓ postMessage("render") ─────→ render frame
↓ postMessage("resize") ─────→ reconfigure surface
winit's web event loop must live on the main thread (DOM + rAF). So the canvas
is transferred to a worker via transferControlToOffscreen(), and all GPU work
happens there.
| File | Role |
|---|---|
src/bin/app.rs |
Main thread: canvas + winit event loop + worker spawn + render ticks |
src/bin/worker.rs |
Worker: wgpu surface/device/queue + frame rendering |
src/lib.rs |
Shared postMessage helpers |
Two separate wasm modules, built via Trunk's data-type="main" / data-type="worker".
rustup target add wasm32-unknown-unknown
cargo install --locked trunk
trunk serve --openOpens at http://127.0.0.1:8080. Resize the window; the surface reconfigures.
Requires a browser with WebGPU.