STUDY 01 / LIVE EXPERIMENT

Field / Form

The graphics experiment behind this site’s background.
Try different forms and rendering paths.

Back to Study
Backend
Preparing
Particles
—
Position + velocity buffer
—
rAF median / p95
Collecting samples
Drawing buffer
—

Frame intervals measured in this browser. These are not GPU execution times or results from other devices.

Read about the implementation

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 particle
TargetShape · sample ID
ComputeTarget force · damping
RenderState · pointer → point sprites

Each 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.

BACK TO INDEXStudy