INDEPENDENT STUDY / SEPTEMBER 2026
Persistent Scene
A graphics experiment built for this portfolio. Rust, wgpu and WGSL maintain positions and velocities on the GPU; selecting a project changes the target shape. The same canvas stays in place across page transitions while the HTML content updates separately.
The silver particles and sense of depth draw on a Pmndrs example; the organic shapes and open space reference stills from Phantom Garden. The surface functions, motion and page transitions were implemented specifically for this site.
DATA & COMPUTE
Surface Morphing
A stable ID and integer hash provide 2D samples and layer indices. The same sample IDs define positions across ten shapes, including ribbons, shells, knots, frames and orbits, preserving correspondence between pages.
The compute shader reads each particle’s position and velocity and applies a damped spring toward its target surface. Analytic curl fields drive both surface flow and the drifting particles around it.
Surface deformation and free drift have separate strengths. A stable subset of roughly 9% of particles drifts around every form at the same strength. In Repeated cells, cell centers stay fixed and the body particles rotate within each cell.
A short pointer history supplies direction and speed for local forces. The cell array responds through particle size and brightness, while drifting particles also move under the force. Scrolling changes the view and layer spacing. A cap on the simulation time step prevents large jumps when returning to the tab.
Position + velocityGPU storage buffer · 32 bytes per particleEach particle updates only its own state. Since no neighboring particle state is read, this path does not need ping-pong state buffers. Rendering reads the same buffer after the compute pass completes.
RENDERING & LIFETIME
Rendering & Lifetime
Depth and per-sample size variation mix fine points with larger bokeh. This is sprite-based depth styling, not a physical full-screen depth-of-field pass. Particle count and DPR are capped to limit the cost of overlapping translucent particles.
The canvas persists during navigation. A new target does not reset particle positions or velocities. The loop stops in hidden tabs, and reduced-motion preferences display the final shape without continuous animation.
When WebGPU is unavailable, the site tries a WebGL2 vertex-morph fallback. It approximates deformation from the same input history but does not retain compute simulation state or provide velocity visualization. If both paths fail, the content remains readable with a static background.
SOURCE & REPRODUCTION
Source Code
The WGSL shaders, Rust renderer, browser controller and build instructions are available below.
field.wgslShapes · simulation · renderingTarget functions, compute, point spriteslib.rsRust / wgpuDevice · buffers · pipelines · framescontroller.tsBrowser controllerNavigation · input · pausing · fallbacksource.zipDownload the independent implementationRust crate, WGSL, browser code and build instructions