← /research

Rust + WASM for Browser Graphics

Processing · Reading Notes Created Jan 4, 2025

Source

Rust + WebAssembly 2025 — Various (Article)
View source →
Project: web-graphics-research
rustwasmgraphicsperformance

The Rust + WASM + WebGPU stack is the current state of the art for building Figma-class applications.

The Modern Stack

Rust (application logic + rendering)
    ↓ wasm-pack / wasm-bindgen
WebAssembly (near-native performance)
    ↓ wgpu
WebGPU (GPU compute + graphics)

Why Rust

  1. Memory safety without GC: No pause jitter
  2. Zero-cost abstractions: Performance of C++
  3. Excellent WASM tooling: wasm-bindgen, wasm-pack
  4. Strong ecosystem: wgpu, vello, lyon for graphics

Performance Reality (2025)

Major browsers now achieve 95%+ of native performance for CPU-intensive WASM tasks.

V8 (Chrome) has integrated:

  • 16-bit float support for WebGPU
  • Packed integer dot products
  • Memory64 for larger AI models

Key Libraries

wgpu

Cross-platform WebGPU implementation in Rust. Runs on:

  • Native (Vulkan, Metal, DX12)
  • Browser (WebGPU, WebGL2 fallback)

Same code targets both native and web.

Vello

GPU compute-centric 2D renderer. The Skia/Cairo replacement.

  • 177 fps on paris-30k test scene (M1 Max, 1600px)
  • Uses prefix-sum algorithms for GPU parallelization
  • Eliminates CPU sorting/clipping bottlenecks
// Vello API (PostScript-inspired)
scene.fill(Fill::NonZero, transform, &brush, None, &path);

Lyon

Path tessellation library. Turns vector paths into GPU-friendly triangles.

Use when you need lower-level control than Vello.

Data Passing Patterns

Critical: Calling Rust from JS is cheap. Moving data isn’t.

The Cost Hierarchy

PatternCostUse Case
Primitive (u32, f64)~1nsCoordinates, indices
Small struct (via bindgen)~10nsConfig objects
Typed array view~100nsBuffer handoff
Vec copy~1μs/KBLast resort
Serialization (JSON/bincode)~10μs/KBAvoid if possible

Patterns

// Bad: Clone data
#[wasm_bindgen]
pub fn process(data: Vec<u8>) -> Vec<u8>

// Better: Pass typed views over buffers
#[wasm_bindgen]
pub fn process(data: &[u8], out: &mut [u8])

// Best: Zero-copy with SharedArrayBuffer
#[wasm_bindgen]
pub struct Renderer {
    buffer: Vec<u8>,  // Owned by WASM
}

#[wasm_bindgen]
impl Renderer {
    pub fn buffer_ptr(&self) -> *const u8 { self.buffer.as_ptr() }
    pub fn buffer_len(&self) -> usize { self.buffer.len() }
}

// JS side:
const ptr = renderer.buffer_ptr();
const len = renderer.buffer_len();
const view = new Uint8Array(memory.buffer, ptr, len);
// view is now a direct window into WASM memory

Memory Layout Gotcha

WASM linear memory can grow, invalidating all TypedArray views. Always re-create views after any call that might allocate:

// Danger: view may be stale after this call
renderer.add_object(...); // might grow memory
view[0] = 255; // UNDEFINED BEHAVIOR if memory grew

// Safe: recreate view after potential allocation
renderer.add_object(...);
const freshView = new Uint8Array(memory.buffer, ptr, len);
freshView[0] = 255;

New WASM Features (2025)

WasmGC: Garbage collection landed in all major browsers (Chrome 119+, Firefox 120+, Safari 18.2+). Enables languages like Go/Kotlin to target WASM efficiently.

SIMD: Parallel data processing. 2-4x speedup for math-heavy code.

Memory64: Large address spaces for AI models.

Build Pipeline

# Install toolchain
rustup target add wasm32-unknown-unknown
cargo install wasm-pack

# Build for web
wasm-pack build --target web

# Output: pkg/ with .wasm + JS bindings

Architecture Pattern

┌─────────────────────────────────────┐
│         JS/TS UI Layer              │
│    (React, Svelte, etc.)            │
└──────────────┬──────────────────────┘
               │ wasm-bindgen
┌──────────────▼──────────────────────┐
│         Rust Core                   │
│   • Document model                  │
│   • Business logic                  │
│   • Rendering commands              │
└──────────────┬──────────────────────┘
               │ wgpu
┌──────────────▼──────────────────────┐
│         WebGPU                      │
│   • GPU compute                     │
│   • Rasterization                   │
└─────────────────────────────────────┘

This is essentially Figma’s architecture, but with Rust instead of C++.

Sources:

Related: building figma today, vello gpu vector graphics, webgpu vs webgl