cssAudio - Activefile-genericCSS - ActiveGeneric - ActiveHTML - ActiveImage - ActiveJS - ActiveSVG - ActiveText - Activefile-genericVideo - ActiveLovehtmlicon-new-collectionicon-personicon-teamlog-outoctocatpop-outspinnerstartv

Pen Settings

CSS Base

Vendor Prefixing

Add External CSS

These stylesheets will be added in this order and before the code you write in the CSS editor. You can also add another Pen here, and it will pull the CSS from it. Try typing "font" or "ribbon" below.

Quick-add: + add another resource

Add External JavaScript

These scripts will run in this order and before the code in the JavaScript editor. You can also link to another Pen here, and it will run the JavaScript from it. Also try typing the name of any popular library.

Quick-add: + add another resource

Code Indentation


Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

              // changing these parameters can strongly affect emergent behaviour
var max_speed = 0.004;
var max_force = 0.0006;
var centering_factor = 0.01;
var alignment_factor = 1;
var avoidance_factor = 1;
var agent_optimal_distance = 0.004;
var agent_range_of_view = 0.04;
var agent_field_of_view = 1.5;
var random_walk_variance = 1;
 // our agents:
var agents = [];

function make_agent() {
  var a = {
    pos: new vec2(random(), random()),
    vel: vec2.random(random() * max_speed),
    acceleration: new vec2(),
    size: (random() + 1)/160
  return a;
// make a few agents:
for (var i=0; i<100; i++) make_agent();

function move_agent(a) {
	// forward Euler integration + constraints

function update_agent(a) {
  // we will compute a desired velocity
  // intially, a simple random walker
  // (take current velocity and rotate it slightly)
  var desired_velocity = a.vel.clone()
    .setmag(max_speed * random());
  // useful to know our direction:
	var dir = a.vel.angle();
  // information to gather about visible neighbors:
	var neighbours = 0;
  // these are for the three steering forces:
  var neighbour_locations = new vec2();
  var neighbour_velocities = new vec2();
  var neighbour_avoidances = new vec2();
  // check for visible neighbours:
  // (might not be the most optimal, but it is simple):
	for (var n of agents) {
		if (n == a) continue;	// don't count yourself!
    // get the (relative) vector to the neighbor from the agent:
    // (clone() so that we don't modify n.pos)
    var rel = n.pos.clone().sub(a.pos);
    // because we are in toroidal space, spanning borders,
    // there can be more than one relative vector
    // this call makes sure we get the shortest one:
    rel.relativewrap(1);    // 1 is the size of our world    
    // to get the view distance, subtract sizes, 
    // (want distance between bodies, not between centers)
    var distance = Math.max(rel.len() - a.size - n.size, 0);
    // is the neighbour close enough to be seen?
    var in_visible_range = distance < agent_range_of_view;    
    // now rotate this into the view of the agent (global-to-local):
    // (i.e. directly in front of the agent is an angle of zero)
    var viewrel = rel.clone().rotate(-dir);
    // is the neighbor within the agent's field of view?
    // use absolute value to capture left & right sides:
    var in_visible_angle = Math.abs(viewrel.angle()) < agent_field_of_view;   
    // neighbour seen if within range & field of view:
    if (in_visible_range && in_visible_angle) {
      // yes -- add to count of neighbours
      // accumulate relative locations for centering force
      // rotate neighbour velocity into agent's perspective,
      // accumulate for aligning force
      var relative_velocity = n.vel.clone().rotate(-dir);
      // feel uncomfortable if the neighbour is too close:
      // e.g. closer than optimal distance
      var negative_feeling = Math.min(0, distance - agent_optimal_distance);
      if (negative_feeling < 0) {
        var normalized = negative_feeling  / agent_optimal_distance;
  // did we see anyone?
	a.sees_neighbours = neighbours > 0;
	if (a.sees_neighbours) {
    // convert accumulated information into averages:
    // change factors:
    // apply to desired velocity
    // (note avoidance is subtracted, as a repulsion):
  // to convert desired_velocity into a steering force,
  // need to subtract current velocity
  a.acceleration = desired_velocity.sub(a.vel);
  // apply constraints:

function update() {
  // to separate passes to prevent artefacts 
  // (similar to double-buffering)
  for (var a of agents) {
  for (var a of agents) {
function draw() {
  for (var a of agents) {
  	// push into agent's local coordinate system
      // draw agent body:
      draw2D.color(a.sees_neighbours ? "red" : "pink");
      // draw agent eyes:
      draw2D.circle([0.5, 0.5], 0.5);
      draw2D.circle([0.5,-0.5], 0.5);
    // done drawing agent:

// click to add more agents:
function mouse(e, pt) {
  if (e == "down") {
    var a = make_agent();

Asset uploading is a PRO feature.

As a PRO member, you can drag-and-drop upload files here to use as resources. Images, Libraries, JSON data... anything you want. You can even edit them anytime, like any other code on CodePen.


Loading ..................