A standalone Tauri 2 + wgpu example for rendering resolution-independent GPU artwork and exporting it as tiled 4K, 6K, 8K, or square PNG files.
The renderer window is only a live preview. Export does not capture or upscale that window. Instead, the same WGSL shader is rendered again into an offscreen Rgba8UnormSrgb texture using global output coordinates.
native preview
WGSL shader ──render──► swapchain surface
high-resolution export
WGSL shader ──render tile──► RGBA8 texture
│
├──copy──► padded MAP_READ buffer
│
└──repeat for every tile
│
▼
dense CPU RGBA image ──► PNG
controls: HTML/CSS/JavaScript WebViewrenderer: separate native OS window owned directly by wgpuRgba8UnormSrgb export texturesMAP_READ staging-buffer mappingnpm install
npm run dev
Explicit backend selection:
npm run dev:metal
npm run dev:vulkan
npm run dev:dx12
The selected backend must be available on the operating system.
2048, and samples at 1×.Exports are written to:
Pictures/Junkpile Exports/
If the platform does not expose a Pictures directory, the app falls back to the home directory and then the current working directory.
A direct 8K render target is possible on many desktop GPUs, but it couples export to maximum texture dimensions and creates a large temporary GPU allocation. This example instead uses a reusable tile texture.
For a 7680 × 4320 export with 2048 px tiles:
columns = ceil(7680 / 2048) = 4
rows = ceil(4320 / 2048) = 3
tiles = 12
Only one tile texture and one staging buffer are allocated. The final dense image exists in CPU memory because PNG encoding requires all output rows.
Each export tile receives:
The fragment shader reconstructs the global pixel position:
global pixel = tile origin + local fragment position
All procedural noise, grain, aspect correction, and vignette calculations use that global coordinate. Neighboring tiles therefore evaluate the same continuous image instead of restarting the shader at each tile.
Texture-to-buffer copies require bytes_per_row to respect the WebGPU copy alignment. The dense row size is:
width × 4 bytes
The staging row size is rounded up to a multiple of 256 bytes:
padded = ceil(dense / 256) × 256
After the GPU buffer is mapped, Rust copies only the dense pixel bytes from each padded row into the final image.
1920 × 10803840 × 21605760 × 32407680 × 43204096 × 4096Custom width and height values are accepted from 256 through 8192, with a safety limit of 67.1 megapixels.
512 — smallest allocation; highest tile count1024 — conservative cross-platform setting2048 — balanced default4096 — fewer submissions and larger temporary resourcesThe requested tile size must not exceed the adapter’s reported max_texture_dimension_2d.
1× — one shader evaluation per output pixel2× — two subpixel evaluations4× — four subpixel evaluationsHigher sampling improves fine edges and small procedural details but multiplies fragment-shader cost.
The live preview can keep animating before export. When export begins, Rust stores the current scene time once and uses that same value for every tile. This prevents time from advancing between tiles.
The preview pauses while GPU tiles are rendered, read back, assembled, and encoded. The controls WebView remains responsive and reads progress from the shared renderer telemetry.
The built-in shader combines:
The visual is intentionally procedural so export quality can be tested without loading external assets.
src-tauri/src/main.rs Tauri commands and two-window lifecycle
src-tauri/src/renderer.rs preview, tiled export, readback, image assembly, PNG write
src-tauri/src/export_scene.wgsl fullscreen procedural shader with global tile coordinates
src/index.html controls and export telemetry
src/app.js smooth IPC controls and progress polling
src/styles.css responsive controls-window presentation
The final CPU image uses four bytes per pixel before PNG compression:
3840 × 2160 × 4 ≈ 31.6 MiB
7680 × 4320 × 4 ≈ 126.6 MiB
8192 × 8192 × 4 = 256 MiB
PNG output size is usually much smaller, but compression time and memory depend on scene complexity and output dimensions.
wgpu and Naga handle backend translation. WGSL remains the canonical shader source.
MIT.