Verlet
Verlet integration for ropes and cloth
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:
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.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 lengthspacing * sqrt(2) - Bend constraints — Connect every-other-point:
(x,y)to(x+2,y)and(x,y)to(x,y+2), with rest lengthspacing * 2
Increase stiffness
Three approaches, in order of effectiveness:
- More iterations — Increase
constraintIterations. Each doubling roughly doubles stiffness. - Sub-stepping — Call
update()multiple times per frame with a subdivideddeltaTime. More accurate than extra constraint iterations alone. - 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
Macklin et al., "XPBD: Position-Based Simulation of Compliant Constrained Dynamics" (2016) Extends PBD with a compliance parameter that gives physically meaningful stiffness values independent of time step and iteration count. The natural next step if you need more control over material properties. https://matthias-research.github.io/pages/publications/XPBD.pdf
Muller et al., "Detailed Rigid Body Simulation with Extended Position Based Dynamics" (2020) Applies XPBD to rigid body simulation, demonstrating that the position-based approach scales from soft bodies to rigid constraints. https://matthias-research.github.io/pages/publications/PBDBodies.pdf
Macklin et al., "Small Steps in Physics Simulation" (SIGGRAPH 2019) Analyzes the relationship between sub-stepping, iteration count, and simulation quality in PBD. Shows that many small sub-steps can match the quality of complex implicit solvers. https://matthias-research.github.io/pages/publications/smallsteps.pdf
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.