Verlet

Verlet integration for ropes and cloth

Initializing WebGPU...

Move your cursor over the rope to push it around.

Quick Start

Loading...

Source

Loading...

Documentation

Verlet

GPU-accelerated Verlet integration for ropes, cloth, and soft bodies. Two compute shaders handle position integration and distance constraint solving — you handle rendering.

Usage

import { createVerlet } from './verlet';

// Default: a rope (chain of connected points, first point pinned)
const rope = createVerlet(device, {
  points: 32,
  gravity: [0, 9.8],
  damping: 0.99
});

// Per frame
rope.update(deltaTime);

// Read positions for rendering
const positionBuffer = rope.positions; // GPUBuffer of vec2<f32>

// Clean up when done
rope.destroy();

Custom constraints (cloth grid)

const cols = 16;
const rows = 16;
const spacing = 1.0;
const constraints = [];

for (let y = 0; y < rows; y++) {
  for (let x = 0; x < cols; x++) {
    const i = y * cols + x;
    // Horizontal constraint
    if (x < cols - 1) constraints.push({ a: i, b: i + 1, restLength: spacing });
    // Vertical constraint
    if (y < rows - 1) constraints.push({ a: i, b: i + cols, restLength: spacing });
  }
}

const cloth = createVerlet(device, {
  points: cols * rows,
  constraints,
  pins: [0, cols - 1], // Pin top corners
  gravity: [0, 9.8],
  damping: 0.99,
  constraintIterations: 12
});

API

createVerlet(device, options)

Returns a Verlet instance.

Option Type Default Description
points number (required) Number of points
constraints VerletConstraint[] (rope chain) Pairs of point indices + rest lengths
gravity [number, number] [0, 9.8] Acceleration applied each frame
damping number 0.99 Velocity damping (0 = frozen, 1 = no damping)
bounds { width, height } (none) Boundary box centered at origin
pins number[] [0] Indices of fixed (immovable) points
constraintIterations number 8 Constraint relaxation passes per frame

Each VerletConstraint has:

Field Type Description
a number Index of the first point
b number Index of the second point
restLength number Target distance between the points

sim.update(deltaTime)

Advances the simulation by deltaTime seconds. Runs one integration pass, then constraintIterations constraint relaxation passes. Delta time is clamped to 1/30s to prevent instability.

sim.positions

GPUBuffer containing count vec2<f32> values (current positions). Usages: STORAGE | COPY_DST | VERTEX | COPY_SRC.

sim.count

Number of points in the simulation.

sim.destroy()

Releases all GPU buffers.

Algorithm

Verlet integration is a position-based physics method where velocity is implicit — stored as the difference between the current and previous position. This makes it naturally stable and trivial to add constraints.

Each frame:

  1. Integration — For each free point: new_pos = pos + (pos - old_pos) * damping + gravity * dt^2. Pinned points don't move. Boundary constraints are applied by clamping positions.

  2. Constraint relaxation — For each distance constraint connecting points A and B: compute the current distance, find the error vs. the rest length, and move both points along the connecting axis to correct the error. Pinned points absorb the full correction. This is run multiple times per frame (default 8) because each constraint correction can disturb previously solved constraints. More iterations produce stiffer, more accurate results.

The combination of Verlet integration and iterative constraint projection is the core of Position Based Dynamics (PBD), used in many physics engines for real-time soft body simulation.

WGSL loading

The default imports use Vite's ?raw suffix:

import integrateSource from './integrate.wgsl?raw';
import constraintsSource from './constraints.wgsl?raw';

If you're not using a bundler, load via fetch:

const integrateSource = await fetch(new URL('./integrate.wgsl', import.meta.url)).then((r) =>
  r.text()
);
const constraintsSource = await fetch(new URL('./constraints.wgsl', import.meta.url)).then((r) =>
  r.text()
);

Modifying

Extend to 3D

Change vec2f to vec3f in both WGSL shaders and update gravity to [0, -9.8, 0]. Update buffer sizes from count * 2 * 4 to count * 4 * 4 (vec3f is 16-byte aligned in storage buffers). Add bounds checking for the Z axis.

Add mouse interaction

Write a pinned point's position from JavaScript each frame to let the user drag points:

device.queue.writeBuffer(sim.positions, pointIndex * 8, new Float32Array([mouseX, mouseY]));

The constraint solver will pull connected points along naturally.

Add shear and bend constraints for cloth

For a cloth grid, structural constraints (horizontal + vertical) keep the grid shape, but it will shear and fold easily. Add:

  • Shear constraints — Connect diagonal neighbors: (x,y) to (x+1,y+1) and (x+1,y) to (x,y+1), with rest length spacing * sqrt(2)
  • Bend constraints — Connect every-other-point: (x,y) to (x+2,y) and (x,y) to (x,y+2), with rest length spacing * 2

Increase stiffness

Three approaches, in order of effectiveness:

  1. More iterations — Increase constraintIterations. Each doubling roughly doubles stiffness.
  2. Sub-stepping — Call update() multiple times per frame with a subdivided deltaTime. More accurate than extra constraint iterations alone.
  3. XPBD — Replace the simple position correction with Extended Position Based Dynamics, which uses a compliance parameter for physically-based stiffness control.

Self-collision

Add a collision detection pass after constraint solving. For each pair of nearby points, if they're closer than a minimum distance, push them apart. For small point counts, brute-force O(n^2) works. For larger simulations, use spatial hashing (see the boids module's further reading for references).

Further Reading

Resources on Verlet integration, position-based dynamics, and constraint-based physics simulation.

Original Research

  • Loup Verlet, "Computer 'Experiments' on Classical Fluids" (Physical Review, 1967) The original paper introducing the Verlet integration method for molecular dynamics simulation. The position-based formulation (Stormer-Verlet) is what this module implements. https://doi.org/10.1103/PhysRev.159.98

  • Jakobsen, "Advanced Character Physics" (GDC 2001) The landmark talk that popularized Verlet integration for real-time game physics. Introduces the pattern of Verlet integration + iterative constraint relaxation for ropes, cloth, and ragdolls. This is the direct basis for this module's approach. https://www.cs.cmu.edu/afs/cs/academic/class/15462-s13/www/lec_slides/Jakobsen.pdf

  • Muller et al., "Position Based Dynamics" (2007) Formalizes the Verlet + constraint projection approach into the PBD framework. Covers distance constraints, volume preservation, collision handling, and the relationship between iteration count and stiffness. https://matthias-research.github.io/pages/publications/posBasedDyn.pdf

Extended Methods

Cloth Simulation

  • Provot, "Deformation Constraints in a Mass-Spring Model to Describe Rigid Cloth Behavior" (1995) Early work on using distance constraints for cloth simulation. Introduces the structural, shear, and bend constraint pattern for grid-based cloth that this module's README describes. https://doi.org/10.1007/978-3-7091-9418-2_18

  • Muller, Chentanez, "Wrinkle Meshes" (2010) Technique for adding fine wrinkle detail to coarse PBD cloth simulation, useful if you extend this module to cloth rendering. https://matthias-research.github.io/pages/publications/wrinkles.pdf

GPU Implementation

  • Tassone, Cozzi, "A Parallel Constraint Solver for a Deformable Body Simulation" (2006) Discusses GPU parallelization strategies for constraint solving, including the graph coloring approach to avoid write conflicts between constraints that share points.

  • NVIDIA Flex A unified GPU particle physics engine built on PBD, handling cloth, fluids, rigid bodies, and soft bodies. Good reference for how Verlet-based simulation scales to complex scenes. https://developer.nvidia.com/flex

Practical Guides

  • Daniel Shiffman, "The Nature of Code" — Chapter on Springs Accessible introduction to spring-based particle systems, covering the basics of Verlet integration and constraint solving with step-by-step code examples. https://natureofcode.com/springs/

  • Matthias Muller, "Ten Minute Physics" (YouTube) Video series by the PBD author covering practical implementation of position-based simulation, including cloth, soft bodies, and fluids. https://www.youtube.com/c/TenMinutePhysics

General References

  • Hairer, Lubich, Wanner, "Geometric Numerical Integration" (2006) Rigorous mathematical treatment of symplectic integrators including Verlet/Stormer-Verlet. Explains why Verlet integration conserves energy better than Euler methods over long simulations.

  • Bridson, "Fluid Simulation for Computer Graphics" (2015) While focused on fluids, includes excellent coverage of particle-based simulation, time integration, and constraint methods that apply broadly to Verlet-based systems.