You Might Also Like
Canvas Boids Flocking Simulation — Free Emergent Behavior Snippet
Canvas Boids Flocking Simulation · Animations · Plain HTML, CSS & JS · Live preview
What's included
Features
About this UI Snippet
Canvas Boids Flocking Simulation — Craig Reynolds' Three Rules From Scratch

Boids, introduced by Craig Reynolds in 1986, remains one of the clearest demonstrations that complex, convincing group behavior doesn't require central coordination — just three simple local rules, applied identically and independently to every individual. This snippet implements all three from scratch on canvas, with a cursor predator layered on top.
Three rules, computed per-boid from local neighbors only
Every frame, flock() looks only at neighbors within a fixed PERCEPTION radius (55px) and computes three separate steering vectors: separation (steer away from nearby neighbors, weighted more strongly the closer they are, via a 1/d falloff), alignment (steer toward the average heading of nearby neighbors), and cohesion (steer toward the average position of nearby neighbors). No boid has any awareness of the flock as a whole — it only ever sees whoever happens to be within its own perception radius, exactly like Reynolds' original model.
Weighted force blending, not equal votes
The three steering vectors aren't averaged equally — separation is weighted roughly 1.6x, alignment 1.0x, and cohesion 0.9x before being summed into a single acceleration. This weighting is what keeps the flock cohesive (birds stay in a visible group) while still preventing them from colliding (separation dominates at close range) — tuning these weights is the single biggest lever over how "flocky" versus "swarmy" versus "scattered" the simulation looks.
Force and speed limiting keep motion boid-like
Both the individual steering vectors and the boid's final velocity are passed through limit(), which caps a vector's magnitude while preserving its direction. Without this, cohesion or alignment forces from a dense cluster could produce a huge instantaneous acceleration; capping keeps every boid's turning and speed changes gradual and readable rather than jittery.
A cursor predator layered on top of the three core rules
The pointer contributes a fourth, independent force: any boid within 120px of the pointer steers directly away from it. This isn't part of classical Reynolds boids, but composes naturally with the existing acceleration-summing structure — it's just one more vector added before the final speed clamp.
Naive O(n²) neighbor search, by design
Every boid scans every other boid to find its neighbors each frame. That's quadratic in boid count, but for the few hundred boids this demo supports it's comfortably fast at 60fps — a spatial grid or quadtree would only be worth the added complexity at boid counts in the thousands.
Compare with canvas particle text formation for a different flavor of large-particle-count canvas motion built around a target shape instead of emergent local rules.
Build with AI
Build, Understand, Optimize, and Extend It With AI
Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain why applying only three simple local rules — separation, alignment, cohesion — independently to every boid produces convincing group-level flocking with no central coordinator, and how the relative weighting of those three forces changes the character of the simulation. It's a great snippet to extend with an assistant — ask for a spatial-grid neighbor lookup to support thousands of boids, obstacle avoidance (steering around fixed shapes), or multiple predator/prey species with different rule weights interacting in the same scene.
Prompt to recreate it
Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:
Build a real-time "boids flocking simulation" in plain HTML, CSS, and JavaScript using only the Canvas 2D API and Craig Reynolds' classic three-rule boids algorithm — no simulation or physics library.
Requirements:
- A population of boid objects, each with position and velocity, rendered as small triangles rotated to face their current heading direction, moving continuously via a requestAnimationFrame loop, wrapping around canvas edges when they leave.
- Implement three independent local steering rules, computed every frame for every boid based ONLY on other boids within a fixed perception radius (e.g. 55px) — no boid should have any awareness of boids outside that radius or of the flock as a whole:
1. Separation: steer away from nearby boids, weighted more strongly for closer ones (inverse-distance falloff).
2. Alignment: steer toward the average velocity/heading of nearby boids.
3. Cohesion: steer toward the average position (center of mass) of nearby boids.
- Sum these three steering vectors with different relative weights (separation weighted highest, then alignment, then cohesion) into one acceleration vector per boid, clamping both the individual force vectors and the boid's final velocity to maximum magnitudes so motion stays smooth rather than jittery or explosive.
- Track the pointer (mouse and touch) and add a fourth steering force: any boid within a fixed radius of the pointer (e.g. 120px) steers directly away from it, acting as a predator the flock scatters from.
- Expose a live slider to add or remove boids from the simulation on the fly (supporting roughly 30 to 240 boids), and handle window resize by updating the simulation bounds. Use a straightforward O(n^2) neighbor search (every boid checks every other boid) since the supported boid count is small enough for that to stay real-time.Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.
Step by step
How to Use
- 1Paste HTML, CSS, and JS120 boids spawn and immediately begin flocking.
- 2Observe emergent groupingBoids align, cluster, and avoid collisions with no leader.
- 3Move the cursor into the flockNearby boids scatter away from the pointer as a predator.
- 4Move the cursor outThe flock re-coalesces into cohesive groups.
- 5Adjust the Boids sliderAdd or remove boids live; the flock rebalances instantly.
- 6Resize the windowThe simulation bounds adapt to the new canvas size.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
Boids is a 1986 artificial-life program by Craig Reynolds that simulates flocking behavior — birds, fish schools, herds — using three simple local steering rules applied to every individual: separation (avoid crowding neighbors), alignment (match neighbors' average heading), and cohesion (move toward neighbors' average position). No individual boid is aware of the group as a whole; the convincing group behavior emerges purely from many individuals following the same local rules.
The three steering forces are summed with different weights before being applied — separation is weighted more heavily than alignment or cohesion. That weighting means avoidance dominates at close range (preventing collisions) while cohesion and alignment still pull the group together at slightly longer range, producing a flock that stays visually grouped without individuals overlapping.
Only nearby boids. Every frame, flock() checks the distance from a boid to every other boid and only includes ones within the fixed PERCEPTION radius (55px) in its separation/alignment/cohesion calculations. This locality is the whole point of the algorithm — realistic group behavior emerges from purely local awareness, with no boid ever consulting global flock state.
It is an independent fourth steering force added on top of the three core boid rules: any boid within 120px of the pointer gets an acceleration pointing directly away from the pointer, scaled by a fixed strength. Because it is just one more vector summed into the boid's total acceleration before the final speed-limiting step, it composes naturally with the existing flocking behavior rather than overriding it.
Each frame currently does an O(n^2) neighbor scan — every boid checks the distance to every other boid — which is fast enough for the few hundred boids this demo supports but would start to degrade into the thousands. At that scale, you'd want to bucket boids into a spatial grid or quadtree first and only check distances against boids in nearby cells, which is the standard optimization for larger flocks.