ECP-Life: the short version

For someone who already knows particle life. Three changes, in the order they were made, and why each one forced the next.

In one paragraph. Take particle life. Replace the handful of species with a continuous colour, so the attraction matrix becomes a smooth landscape instead of a grid of numbers. Replace the piecewise-linear force with a bond that has a real rest distance, so pairs settle instead of orbiting. Then notice that half of every particle-life matrix is a "chase" that creates energy from nothing, and instead of throwing that energy away with friction, make each particle pay for it by shifting its colour. Colour becomes a battery. Nothing is created, nothing is lost, and the interesting behaviour is what the system does while the battery drains and recharges.

0. Where we start

Classic particle life: $N$ species, an $N \times N$ matrix of attraction strengths, and a force between two particles that is "repel hard when too close, then attract or repel by the matrix entry, fading to zero at a cutoff". Plus friction, always. You already know what it does: blobs, cells, chasers, things that look alive for a while.

the matrix: 5 species

the force vs distance: a tent

Left: a typical particle-life matrix, entry $(i,j)$ is how species $i$ responds to species $j$. Blue attracts, red repels. Note it is not symmetric: red-to-blue and blue-to-red differ, and that asymmetry is where all the chasing comes from. Right: the radial force, scaled by the matrix entry. A hard repulsive core, a linear peak, a linear fall to zero at the cutoff.

The one-line version of the force that this whole project starts from is

$$ \mathbf F_{ij} = f(\text{colour}_i, \text{colour}_j)\; g(r)\; \hat{\mathbf u} $$

a colour-dependent strength, times a distance fall-off, along the line between the two. Every change below is a change to one of those two factors, or to what happens to the energy they produce.

1. Continuous hue instead of species

The change. Each particle carries a hue, an angle on the colour wheel from $0$ to $2\pi$, instead of a species index. The attraction matrix becomes a smooth function of two angles, $f(h_i, h_j)$, drawn as tileable Perlin noise over the hue torus. Two particles with nearly the same hue feel nearly the same forces. A particle can be "a bit orange, leaning red".

5 × 5 lookup table

continuous: $f(h_i, h_j)$ from noise

Same idea, two resolutions. Both axes are hue, the colour strips along the edges show which hue is where. The left is what a species matrix looks like if you paint it on the hue wheel; the right is the noise field the built model actually uses. It wraps at every edge because hue is an angle.

What you get for free. The matrix is no longer a handful of numbers you have to design. Noise gives you a landscape of attractions and repulsions with all the structure of a hand-made matrix (cycles, cliques, predators) at every scale, and one seed changes all of it. The old matrix is the special case where the landscape is piecewise constant.

What it lets you do later. This is the change that makes everything after it possible. Once hue is a continuous number, it can move. A species index cannot drift; an angle can. Change 3 depends on that.

The split that matters. Any function of two colours can be split into a symmetric half and an antisymmetric half:

$$ f(h_i,h_j) = \underbrace{S(h_i,h_j)}_{\text{same both ways}} + \underbrace{\Lambda(h_i,h_j)}_{\text{flips sign when swapped}} $$

f, the matrix

= S, mirror across the diagonal

+ Λ, anti-mirror

The same noise field, split. $S$ is $\tfrac12[f(h_i,h_j)+f(h_j,h_i)]$ and is symmetric across the diagonal: flip it and nothing changes. $\Lambda$ is $\tfrac12[f(h_i,h_j)-f(h_j,h_i)]$ and is antisymmetric: flip it and every colour inverts. It is zero along the diagonal, because a hue cannot chase itself.

$S$ is "how much do these two like each other": both feel it equally, Newton's third law holds, it is an ordinary force. $\Lambda$ is "who chases whom": if orange pushes blue away and blue is pulled toward orange, that is the chase, and it is the same force vector on both particles. The chasers and predators you see in particle life all live in $\Lambda$.

Reciprocal half, S equal and opposite energy conserved Chase half, Λ same direction on both energy appears from nowhere
Both halves of one particle-life matrix, as forces on a pair. The left half is physics. The right half is the reason particle life needs friction.

2. A well instead of a ramp

The change. Particle life's radial force is a tent: a hard repulsive core, a linear rise to a peak, a linear fall back to zero at the cutoff. Nothing in it says "this is the right distance to sit at", so bonded particles never settle. They orbit, jitter, and lean on friction to calm down.

ECP-Life replaces the tent with a Gaussian well times a taper:

$$ V(r) = -\,e^{-(r-\rho)^2/2\sigma^2}\,\big(1-(r/R)^2\big)^2 $$

potential energy of a pair

force on the pair (slope of the left)

Grey: the particle-life tent, drawn as the potential it implies (left) and the force it is (right). Blue: the ECP-Life well with $\rho = 0.2$, $\sigma = 0.1$, $R = 1$. The tent's energy has no minimum except the hard core, so a bonded pair has nowhere to rest. The well has a floor at $\rho$: the force crosses zero there, pushing apart inside it and pulling together outside. Both include the soft core.

The bond force is $S$ times the slope of this. Inside the rest distance $\rho$ it pushes apart, outside it pulls together, and it dies smoothly (zero value and zero slope) at the cutoff $R$. Two particles that like each other have an actual place to be: $\rho$ apart. A small radial friction on the pair (not on the world) drains the "breathing" vibration so they click into place instead of ringing.

Why it matters. Now a bond is a thing. Two particles at rest distance with a mutual $S > 0$ is a stable object with a definable binding energy, which is what the next change needs: it is going to keep a ledger, and a ledger needs objects whose energy you can write down. It also gives you crystal-like clumps with a lattice constant instead of amorphous blobs, and that lattice constant can depend on colour.

The chase follows the well. The chase force also needs a radial envelope, and the choice turns out to matter: it uses the same shape as the well, so a chase can never act at a distance where the bond cannot hold. With a longer-reaching chase, an incoming particle spends all its colour (see below) before it is close enough to be caught, and just flies off faster. With the chase confined to the well, the spending happens where the bond is, and capture works.

The three radial envelopes in the built model. The bond (blue) and the chase (red) share one shape, so the chase acts exactly where the bond can catch. The battery envelope (yellow) can either follow the well too, or reach all the way to the cutoff as shown here, which makes mismatch repel at long range: an activation barrier that unlike hues have to climb before they can bond.

3. Conserving mechanics: colour as a battery

This is the big one, and it only works because of the first two.

The problem. The symmetric half $S$ is a potential force and conserves energy by itself. The chase half $\Lambda$ does not and cannot: a force that points the same way on both particles has no potential that produces it. A chase pair accelerates as a unit, forever, gaining kinetic energy from nowhere. Classic particle life hides this with global friction, which throws the energy away as fast as it arrives. That works, but it means the whole system is a pump into a drain, and everything you see is the steady state of that pump.

The idea. Keep the books instead. Give every pair a third energy term that is charged by colour mismatch: zero when the two hues agree, largest exactly where the chase is strongest. The simplest is $\Lambda^2$ times a distance envelope:

$$ U_{ij} = \underbrace{k(r_0-r)^2}_{\text{soft core}} \;+\; \underbrace{S(h_i,h_j)\,V(r)}_{\text{the bond}} \;+\; \underbrace{\lambda\,\Lambda(h_i,h_j)^2\,w(r)}_{\text{the hue battery}} $$
The three hue-dependent quantities for one pair, as a function of how far apart their hues are (using the readable cosine version of the matrix, $S = 1.3 + 0.5\cos d$, $\Lambda = 0.7 \sin d$). The chase is strongest at a quarter turn apart; that is exactly where the battery is fullest. Hue on its own costs nothing. Only a disagreement between neighbours costs anything, and if each hue had its own energy level, everything would slide to the cheapest hue and stop.

The rule. Every step, each particle measures the power the chase is putting into it, $P_i = \mathbf F^{\text{chase}}_i \cdot \mathbf v_i$, and the amount its own hue could change the total energy, $W_i = \partial E / \partial h_i$. Then it moves its hue at exactly the rate that pays the bill:

$$ \dot h_i = -\frac{P_i}{W_i} $$

That is the whole mechanic. It is not a tunable "colour drift speed"; it is computed from forces and velocities each frame, and any other value breaks conservation. The only real knobs are how strong the chase is ($\kappa$) and how big the battery is ($\lambda$).

What it does. Three regimes, and a particle cycles through them as it orbits:

Burn v chase F · v > 0 battery → motion hues converge Hold v chase F · v = 0 nothing flows hues frozen Recharge v chase F · v < 0 motion → battery hues diverge
The same particle at three moments in an orbit. The bond curves the path, the chase axis rotates relative to the velocity, and the sign of $P = \mathbf F^{\text{chase}}\cdot\mathbf v$ cycles. No memory is needed: the sign is read fresh each step.
Chase vs. velocityEnergy flowHue
Chase pushes along the motion ($P > 0$)battery drains into motionhues converge, the pair becomes more alike
Chase is sideways ($P = 0$)nothing flowshue frozen
Chase pushes against the motion ($P < 0$)motion is stored back in the batteryhues diverge, the pair becomes more different

Watch it. Two particles start at rest, bonded at the rest distance of the well from section 2, a quarter turn apart in hue: the point where the chase is strongest. Orange chases teal, the pair accelerates as a unit, and every bit of speed it gains is paid for by the two hues sliding toward each other. When they meet the chase is gone, the battery is empty, and the pair coasts at whatever speed it bought. Blue arrows are the reciprocal force, red arrows the chase, particle colour is hue. The camera follows the pair; the grid shows how far it has travelled.

The strip is energy over time: total (thick) stays flat while the battery (red) drains into kinetic energy (blue). A little bond friction on the radial relative velocity keeps the pair from ringing; it is equal and opposite so it cannot slow the pair as a whole, and what it removes is booked as heat. The yellow line is energy plus heat: flat. Tick "stop paying" and the hues freeze, the chase never weakens, and total energy climbs forever: that is particle life without friction. Tick "turn off the chase" and nothing moves at all. This demo uses the $|\Lambda|$ battery, which lets a burned-out pair settle and coast; the $\Lambda^2$ version sloshes around the same colour instead of stopping on it.

So a predator that catches prey burns colour doing it, and drifts toward its prey's colour as it goes. A pair braked by the crowd around it charges up and grows more different. A cyclic chase (red chases green chases blue chases red) unwinds as its battery drains, unless collisions with unlike hues feed mismatch back in. Clumps grow by burning the mismatch of what they capture. A hot clump that gets braked charges and loosens.

The ledger. The sim keeps total energy, plus heat (from the bond friction, when routed there), plus a small "unpaid" column for the rare step where a particle's hue gradient is so close to zero that it cannot pay. Their sum is constant to a couple of percent over long runs, and the residual shrinks with the time step, which is the test that the mechanics are really conserving and not just approximately damped.

Why the order matters

The payoff over ordinary particle life is that nothing is being pumped and drained. Every chase you see is spending something, every capture costs something, and colour is the visible record of the transaction. Structure that persists is structure that has found a way to recharge.

Further reading: the full derivation, the open questions, and a review of the derivation against the code.