Making an image ripple is easy. Making one behave like cloth requires motion to travel across the surface: a pull at one point should move its neighbors, and a fold should change how the wind catches it.

flag-cloth builds that behavior from a small particle grid. The image and the grid are independent. A high-resolution texture stays sharp even when the simulation uses only a few hundred particles; WebGL fills the image between them.

Motion stored between frames

Each particle remembers two positions: where it is now and where it was on the previous step. Their difference acts like velocity. Wind and gravity add acceleration, and damping gradually removes energy.

next = current + (current - previous) × damping + acceleration × time²

This is Verlet integration. It needs little state and works naturally with position constraints. A pinned particle simply has no movable mass, so the solver leaves it in place.

Connections create the material

Particles alone would scatter. Three families of distance constraints give the grid its shape:

  • Structural connections hold neighboring rows and columns together.
  • Shear connections cross each cell diagonally and resist skewing.
  • Bend connections span two cells and keep the cloth from folding like paper at every edge.

The solver corrects those distances several times per step. Each correction is small, but together they carry motion from one particle into the rest of the flag.

Drag any white particle

Drag a white particle, change the pinned edge, or hide a constraint family. The diagram runs the same solver as the rendered flag, without the texture and lighting.

Wind follows the folds

Every grid cell is rendered as two triangles. A triangle gives the solver two useful facts: its area and the direction its surface faces. Comparing that direction with the local wind tells us how much air the triangle catches.

One cloth triangle83% relative pressure
WIND VELOCITYNORMALPRESSURE
Face-on surfaces catch the wind. Edge-on surfaces let most of it pass.

The resulting force is shared by the triangle's three particles. As those particles move, the triangle turns. A new orientation catches a different amount of wind, so the cloth responds to its own changing shape rather than following a predefined wave.

Turbulence only varies the local wind. It never places a particle directly.

A steady simulation, a responsive render

01ForcesWind and gravity
02IntegrateMove particles
03ConstrainRestore the cloth
04RenderUpdate the surface
The solver repeats this at a fixed timestep, independent of the display refresh rate.

The physics advances in fixed increments even when display frames arrive unevenly. The renderer then copies the latest particle positions into an existing WebGL buffer. It does not rebuild the grid, create a particle for each image pixel, or ask React to render every frame.

That separation is the useful core of the library: a small connected simulation controls the motion, while the GPU keeps the image and lighting smooth.