007 - Physics System
The Physics System provides Verlet-based physics simulation.
Why Physics in Creative Coding?
Physics makes generative art come alive. A particle that follows gravity appears more natural than one that flies linearly. A swarm whose individuals react to each other creates emergent patterns that you couldn't have programmed.
Why Verlet?
There are many physics approaches. I use Verlet Integration because it is:
- Stable – Nothing explodes even with large time steps
- Simple – Position + previous position = velocity (implicit)
- Constraint-friendly – "These two points should have distance X" → simply correct positions
Classic Euler integration (position += velocity * dt) accumulates errors and requires small time steps. Verlet (position_new = 2*position - position_old + acceleration*dt²) is more stable and allows larger time steps.
Why Two Levels?
The system has two separate physics worlds:
- PhysicsWorld – For particles, swarms, chains. Each point is a Particle.
- SoftShape – For deformable shapes. The vertices have their own mini-physics.
Why separate? Because a soft circle retains its internal jelly physics even when it flies around as a whole in the PhysicsWorld. The ShapePhysicsAdapter connects both worlds.
Two-Level Architecture
┌─────────────────────────────────────────────────────────────────────────┐
│ Level 1: PhysicsWorld │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ PhysicsWorld │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ Particles │ │ Behaviors │ │Constraints │ │ Springs │ │
│ └────────────┘ └────────────┘ └────────────┘ └────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
▲
┌───────────────────────────────────┼─────────────────────────────────────┐
│ Adapter │ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ ShapePhysicsAdapter │ │
│ └───────────────────────────────────────────────────────────────────┘ │
└───────────────────────────────────┼─────────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ Level 2: SoftShape │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ SoftShape │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────┐ ┌────────────────────────┐ │
│ │ Vertices │ │ Internal Constraints │ │
│ └─────────────────┘ └────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘Level 1: PhysicsWorld
- Global point-based simulation
- Particles with Position, Velocity, Mass
- For: Particle systems, swarms, chains
Level 2: SoftShape
- Shape-internal simulation
- For: Deformable shapes (Blob, SoftCircle)
Components
| Class | File | Function |
|---|---|---|
PhysicsWorld |
PhysicsWorld.ts |
Container for Simulation |
Particle |
Particle.ts |
Verlet Particle |
Behavior |
Behavior.ts |
Force Interface |
Constraint |
Constraint.ts |
Rule Interface |
Spring |
Spring.ts |
Spring Connection |
ParticleString |
ParticleString.ts |
Particle Chain |
CollisionZone |
CollisionZone.ts |
Collision Zones |
ProximityConnection |
ProximityConnection.ts |
Proximity-based Lines |
PhysicsWorld
Container and update loop.
Update Order:
- Apply behaviors (forces)
- Update particles (Verlet)
- Update springs
- Apply constraints
API:
| Method | Description |
|---|---|
addParticle(p) |
Add Particle |
addBehavior(b) |
Add Behavior |
addConstraint(c) |
Add Constraint |
addSpring(s) |
Add Spring |
update(dt) |
Update Simulation |
clear() |
Remove Everything |
Particle
Verlet particle.
Properties:
| Property | Type | Description |
|---|---|---|
position |
Vector |
Current Position |
previousPosition |
Vector |
Previous Position |
mass |
number |
Mass |
locked |
boolean |
Fixed? |
damping |
number |
Damping (0-1) |
radius |
number |
For Collisions |
Methods:
| Method | Description |
|---|---|
addForce(f) |
Add Force |
update(dt) |
Verlet Integration |
velocity |
Getter/Setter for Velocity |
Behaviors
Forces that act on particles.
GravityBehavior
| Option | Type | Default | Description |
|---|---|---|---|
strength |
number |
9.81 | Strength |
direction |
Vector |
(0, 1) | Direction |
FrictionBehavior
| Option | Type | Default | Description |
|---|---|---|---|
coefficient |
number |
0.02 | Friction Coefficient |
AttractionBehavior
| Option | Type | Default | Description |
|---|---|---|---|
target |
Vector |
- | Attraction Point |
strength |
number |
0.1 | Strength |
radius |
number |
200 | Effective Radius |
ConstantForceBehavior
| Option | Type | Description |
|---|---|---|
force |
Vector |
Constant Force |
Presets: createWindBehavior(), createUpdraftBehavior()
Flocking Behaviors (Boids)
| Behavior | Description |
|---|---|
SeparationBehavior |
Keep Distance |
AlignmentBehavior |
Same Direction |
CohesionBehavior |
Stay Together |
FlockingBehavior |
Combines All Three |
Flocking Presets:
| Preset | Description |
|---|---|
birds |
Bird Flock |
fish |
Fish School |
insects |
Insect Swarm |
tight |
Tight Cohesion |
loose |
Loose Cohesion |
Constraints
Rules that particles must follow.
RectConstraint
Keeps particles in a rectangle.
| Option | Type | Description |
|---|---|---|
bounds |
{x,y,w,h} |
Rectangle |
mode |
RectConstraintMode |
'contain' or 'repel' |
bounce |
number |
Bounciness (0-1) |
CircularConstraint
Keeps particles in/outside a circle.
| Option | Type | Description |
|---|---|---|
center |
Vector |
Center Point |
radius |
number |
Radius |
mode |
CircularConstraintMode |
'contain' or 'exclude' |
DistanceConstraint
Fixed distance between two particles.
| Option | Type | Description |
|---|---|---|
particleA |
Particle |
First Particle |
particleB |
Particle |
Second Particle |
distance |
number |
Target Distance |
stiffness |
number |
Stiffness (0-1) |
AxisConstraint
Restricts to one axis.
| Option | Type | Description |
|---|---|---|
axis |
'x' | 'y' |
Axis |
value |
number |
Fixed Position |
Presets: createHorizontalRail(), createVerticalRail()
MinConstraint / MaxConstraint
Minimum/Maximum boundary.
Presets: createFloor(), createCeiling(), createLeftWall(), createRightWall()
Springs
Spring forces between particles.
| Class | Description |
|---|---|
Spring |
Standard Spring |
MinDistanceSpring |
Minimum Distance |
MaxDistanceSpring |
Maximum Distance |
Options:
| Option | Type | Default | Description |
|---|---|---|---|
particleA |
Particle |
- | First Particle |
particleB |
Particle |
- | Second Particle |
restLength |
number |
auto | Rest Length |
stiffness |
number |
0.5 | Stiffness |
damping |
number |
0.1 | Damping |
ParticleString
Chain of particles with constraints.
Factory Functions:
| Function | Description |
|---|---|
createRope(opts) |
Rope (many segments, soft) |
createTautLine(opts) |
Taut Line (stiff) |
createChain(opts) |
Chain (with Springs) |
CollisionZone
Zones with special behavior.
| Option | Type | Description |
|---|---|---|
shape |
'rect' | 'circle' |
Shape |
behavior |
ZoneBehavior |
Behavior on Entry |
Behaviors:
| Behavior | Description |
|---|---|
slow |
Slow Down |
accelerate |
Speed Up |
kill |
Remove Particle |
bounce |
Bounce |
attract |
Attract |
ProximityConnection
Draws lines between nearby particles.
| Option | Type | Default | Description |
|---|---|---|---|
maxDistance |
number |
100 | Max. Connection Distance |
minOpacity |
number |
0 | Opacity at maxDistance |
maxOpacity |
number |
1 | Opacity at Contact |
strokeWidth |
number |
1 | Line Width |
Presets:
| Preset | Description |
|---|---|
network |
Network Look |
constellation |
Constellation Look |
web |
Spider Web Look |
Presets & Factory Functions
| Function | Description |
|---|---|
createDefaultPhysicsWorld() |
Default World with Gravity |
createRandomParticle(bounds) |
Random Particle |
createParticleChain(n, opts) |
Chained Particles |
addFlockingToWorld(world, preset) |
Add Flocking |
Soft Body Collisions
The soft body system (see 004-Shapes) supports shape-to-shape collisions.
Collision Pipeline
┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐
│ Broad-Phase │ -> │ Narrow-Phase │ -> │ Response │
│ AABB │ │ SAT │ │ Impulse │
└─────────────────┘ └─────────────────┘ └─────────────┘Phases:
| Phase | Algorithm | Description |
|---|---|---|
| Broad-Phase | AABB | Fast bounding box test - filters non-colliding shapes |
| Narrow-Phase | SAT | Separating Axis Theorem - precise polygon overlap |
| Response | Impulse | Separate shapes + apply elastic bounce |
Enabling
import { ShapeStateManager } from '@carstennichte/cc-toolbox';
// Create and configure shapes...
const shapes: ShapeStateManager[] = [...];
// All shapes know all others
const decorators = shapes.map(s => s.getDecorator());
for (const shape of shapes) {
shape.setCollisionBodies(decorators);
}Parameter Influence
| Parameter | Influence on Collision |
|---|---|
elasticity |
Bounce strength (average of both shapes) |
stiffness |
How fast shape stabilizes after collision |
damping |
Dampens collision bounce |
Performance Notes
- All-against-All: With n shapes → n² checks
- Recommendation: ~20-30 shapes with collision, ~50 without
- Concave Shapes: SAT only works reliably for convex polygons