A standalone Tauri 2 + wgpu example that treats mesh geometry as a persistent GPU feedback system.
Instead of uploading new vertex positions from Rust every frame, a WGSL compute pass reads the previous mesh state from one storage buffer and writes the next state into another. The render pass consumes the newly written state directly. On the next frame, the buffers reverse roles.
frame N
state A ──compute──► state B ──render──► native surface
frame N + 1
state B ──compute──► state A ──render──► native surface
This is the geometry equivalent of ping-pong texture feedback.
controls: HTML/CSS/JavaScript WebViewrenderer: separate native OS window owned by wgpunpm install
npm run dev
Backend-specific development commands:
npm run dev:metal
npm run dev:vulkan
npm run dev:dx12
The backend must be available on the current operating system.
Only the controls WebView is declared in tauri.conf.json. During Tauri setup, Rust creates a second native window labeled renderer and passes that window directly to wgpu::Instance::create_surface.
┌─────────────────────────────┐ Tauri commands ┌───────────────────────────┐
│ controls WebView │ ─────────────────────────► │ Rust renderer thread │
│ sliders / presets / status │ │ compute + render encoder │
└─────────────────────────────┘ └─────────────┬─────────────┘
│
▼
┌───────────────────────────┐
│ native renderer window │
│ Metal / Vulkan / DX12 │
└───────────────────────────┘
The graphics window is not a WebView canvas. wgpu owns its native surface.
Every vertex occupies 64 bytes in both Rust and WGSL:
position_u vec4 xyz current position, w U coordinate
velocity_v vec4 xyz persistent velocity, w V coordinate
normal_displacement vec4 xyz normal, w displacement from rest
rest_seed vec4 xyz immutable rest position, w stable seed
The default sphere uses 128 latitude segments and 192 longitude segments. The seam is duplicated so the mesh can retain standard UV coordinates.
Each active simulation frame performs these steps:
@builtin(vertex_index).No per-frame mesh readback or CPU vertex upload occurs.
The compute shader combines:
The controls deliberately separate feedback from damping:
1.0 can amplify history and produce unstable or explosive behavior.Applying a preset resets both storage buffers to the original sphere so the preset starts from a known state.
src-tauri/src/main.rs Tauri commands and two-window lifecycle
src-tauri/src/renderer.rs wgpu device, ping-pong buffers, compute/render loop
src-tauri/src/mesh.rs initial sphere topology and persistent vertex state
src-tauri/src/feedback_compute.wgsl compute simulation stage
src-tauri/src/feedback_render.wgsl vertex and fragment rendering stages
src/index.html controls window
src/app.js IPC and telemetry synchronization
Restore sphere state writes the original vertex array into both GPU state buffers. This is an explicit user action, not part of the normal frame path.
Reset all restores the default controls and resets the mesh state.
The example allocates two geometry state buffers because simultaneous read/write feedback on a single buffer would introduce data hazards. wgpu inserts the required compute-to-vertex synchronization when both passes are encoded in order.
The renderer uses PresentMode::Fifo, so visible frame rate normally follows display refresh. Compute work still scales with vertex count, shader complexity, and backend.
wgpu and Naga handle backend translation. WGSL remains the canonical source shader.