Boids Flocking
Three rules, no leader, one mind
Ten thousand starlings carve a shape across the sky like spilled ink finding its level. There is no leader. There is no plan. No bird can see more than a handful of its neighbours.
So who is steering?
The answer, discovered in 1986, is one of the most beautiful results in all of robotics: nobody is. The flock is not following a mind; the flock is the mind, and it runs on three absurdly simple rules. Let's watch them switch on.
Build a flock with your hands
Every dot below follows the same three local rules. Nothing else. Slide the weights and watch a swarm boil out of nothing.
80 boids
hold a treat on the canvas; the flock steers toward it; release to disperse
Try this:
- Separation only. Drag cohesion and alignment to 0. The boids fan out, each one politely guarding its personal space, and that is all. A crowd at a party, no music.
- Cohesion only. Now separation and alignment to 0. They collapse into a single nervous clump, a magnet for moths.
- All three, balanced. Restore the defaults (1.5 / 1.0 / 1.0). Suddenly it flocks: rivers, splits, sudden turns. No dot planned any of it.
The point worth sitting with: not one of these rules mentions where the flock is going. There is no goal anywhere in the system. Global motion that looks purposeful falls out of purely local arithmetic. That is emergence, and once you see it you cannot unsee it.
The three rules, in full
Craig Reynolds called his agents boids (bird-oids) and gave each one exactly three things to want, all measured against only the neighbours inside a small radius:
- Separation: don't crowd. Steer away from anyone too close.
- Alignment: go with the flow. Match the average heading of your neighbours.
- Cohesion: don't get left behind. Drift toward the average position of your neighbours.
The magic is in the word local. No boid ever sees the whole flock, only the neighbours within its little radius. There is no central computer summing ten thousand positions. Each bird does a tiny weighted average of the half-dozen birds nearby, and the global pattern self-assembles. This is exactly why it scales: ten boids or ten million, every agent does the same constant-size sum.
Nature got there first
Reynolds was reverse-engineering something biology had already shipped. Fish do it too. A herring school dodging a predator splits and reforms with the same eerie unity, governed by the same three impulses: don't bump, go with the group, don't fall behind.
Why robots care
This is not just pretty animation. Drone swarms, warehouse fleets, and search-and-rescue robots all face the same nightmare: coordinating hundreds of agents with no central brain and a flaky radio. Boids is the escape hatch. Give each robot three local rules and a sense of its neighbours, and coherent group motion emerges for free: no master, no single point of failure, no bandwidth blowup. Knock out half the swarm and the rest keeps flocking, because nobody was in charge to lose.
The math: three forces, one weighted sum
Each boid looks only at its neighbour set , the agents inside its radius. Three steering accelerations fall out.
Separation pushes away from close neighbours, weighted by inverse-square distance so the nearest crowders shove hardest:
where keeps the denominator off zero when two boids nearly coincide.
Alignment steers toward the average velocity of the neighbourhood:
Cohesion steers toward the average position, the local centre of mass:
The boid's total acceleration is just the weighted sum:
Typical weights (the same defaults in the demo above) are , , . Crucially, every term depends only on . Nothing in these equations references a destination, a leader, or the flock as a whole.
fn compute_boids_forces(agent: &Agent, neighbors: &[&Agent],
k_sep: f32, k_ali: f32, k_coh: f32) -> Vec2 {
let n = neighbors.len() as f32;
if n == 0.0 { return Vec2::ZERO; }
let mut sep = Vec2::ZERO;
let mut ali = Vec2::ZERO;
let mut coh = Vec2::ZERO;
for neighbor in neighbors {
let diff = agent.pos - neighbor.pos;
let dist_sq = diff.length_squared() + 0.01; // epsilon
sep += diff / dist_sq; // separation
ali += neighbor.vel; // alignment
coh += neighbor.pos; // cohesion
}
sep = sep.normalize() * k_sep;
ali = (ali / n - agent.vel).normalize() * k_ali;
coh = ((coh / n) - agent.pos).normalize() * k_coh;
sep + ali + coh
}Key takeaways
- Separation, alignment, cohesion: three local rules are enough to produce convincing flocking.
- Purely local. Each boid averages only its neighbours; no agent sees the whole flock and no central controller exists.
- Emergence. Global, goal-directed-looking motion arises from rules that contain no goal.
- Robust by design. Because coordination is decentralised, the swarm survives losing agents and never bottlenecks on one brain.
There is no shepherd in the murmuration. There is no choreographer in the school, no general in the swarm. There is only every starling, every herring, every drone asking the same three small questions about the neighbours it can actually see.
Coordination, it turns out, was never about knowing the whole. It was about each of us paying close attention to the few who are near.