Skip to content
Sample of Particle-Spring Cloth (Verlet + Hooke)

reas_processing · particleSpring

Particle-Spring Cloth (Verlet + Hooke)

A rectangular grid of free particles is connected by Hooke's-law springs at rest length 'spacing'. Every step Verlet integrates positions (x_new = 2*x - x_prev + a*dt^2) with damping, then a small number of constraint-satisfaction iterations pulls every spring back to its rest length. Selected points are pinned as anchors (top row, bottom corners, optional center) so the mesh hangs and falls under gravity, like a Reas-era cloth net simulation.

Original: http://formandcode.com

▶ Try the live demo (JS port) ▶ Run reference.py via Pyodide 10 formulas have instant JS ports. The Pyodide path runs the actual Python in your browser — first load is ~6 MB, then instant.

Family
reas_processing
Source
reas · processing
Evolution
spring_mass
Render
linked_lines_and_nodes
Complexity
medium
Agents
768
Year
2002
Author
Casey Reas / Processing textbook (creative-coding canon)

Math essence

Velocity is implicit: v = (x - x_prev)*damping. Spring correction: d = ||p1-p0||; offset = (p1-p0)/d * (rest - d)*spring_k/2; distribute +/- offset between the two endpoints respecting anchor pinning. Fully vectorized over all edges via numpy.

Parameters

Name Type Default Range Description
dim int 500 200–1200 Square canvas side length.
grid_w int 32 4–80 Particles per row.
grid_h int 24 4–80 Particles per column.
spacing float 20 4–60 Initial spring rest length (pixels).
spring_k float 0.04 0.005–0.5 Hooke stiffness for one constraint pass.
damping float 0.985 0.7–0.999 Velocity damping factor.
gravity float 60 0–300 Downward acceleration magnitude.
constraint_iterations int 6 1–20 Position-relaxation passes per tick.
anchor_top bool true — Pin the top row of particles.
anchor_bottom_corners bool true — Pin the bottom-left and bottom-right corners.
center_anchor bool false — Also pin the geometric center node (creates a hammock).
bg_color tuple 245,240,230 —
link_color tuple 60,70,90 —
node_color tuple 220,80,70 —
line_alpha float 0.85 0.1–1
seed int null 0–999999

Reference

First 60 lines of reference.py. Full source: library_external/reas_processing/particleSpring/reference.py

from __future__ import annotations

from typing import ClassVar

import numpy as np


class ParticleSpring:
    """Particle-spring mass network with Verlet integration.

    A grid of free particles is connected to its 4-neighbors by linear
    Hooke's-law springs at rest length ``spacing``. A handful of points
    are marked as anchors (pinned to fixed positions). Per step:
    integrate with Verlet (x_new = 2*x - x_prev + a*dt^2), then
    relax each spring a fixed number of constraint iterations so the
    structure settles toward its rest-length network.
    """

    family: ClassVar[str] = "reas_processing"
    sketch: ClassVar[str] = "particleSpring"

    def __init__(
        self,
        dim: int = 500,
        grid_w: int = 32,
        grid_h: int = 24,
        spacing: float = 20.0,
        spring_k: float = 0.04,
        damping: float = 0.985,
        gravity: float = 60.0,
        constraint_iterations: int = 6,
        anchor_top: bool = True,
        anchor_bottom_corners: bool = True,
        center_anchor: bool = False,
        bg_color: tuple[int, int, int] = (245, 240, 230),
        link_color: tuple[int, int, int] = (60, 70, 90),
        node_color: tuple[int, int, int] = (220, 80, 70),
        line_alpha: float = 0.85,
        seed: int | None = None,
    ) -> None:
        self.dim = dim
        self.grid_w = grid_w
        self.grid_h = grid_h
        self.spacing = spacing
        self.spring_k = spring_k
        self.damping = damping
        self.gravity = gravity
        self.constraint_iterations = constraint_iterations
        self._anchor_top = anchor_top
        self._anchor_bottom_corners = anchor_bottom_corners
        self._center_anchor = center_anchor
        self.bg_color = np.array(bg_color, dtype=np.float32)
        self.link_color = np.array(link_color, dtype=np.float32)
        self.node_color = np.array(node_color, dtype=np.float32)
        self.line_alpha = line_alpha
        self._seed = seed
        self.reset()

    def reset(self, seed: int | None = None) -> None:
        if seed is not None:

Try running it locally

The reference implementation is self-contained Python with numpy. Install the package and run:

python library_external/reas_processing/particleSpring/reference.py

Need help? See Learn for the standard environment setup, or Playground for an in-browser sketchbook.

More from reas · processing

See all reas_processing artworks →