Bits are Pixels

Just messing around.

HTML

<script src="//cdnjs.cloudflare.com/ajax/libs/dat-gui/0.5/dat.gui.min.js"></script>
<canvas></canvas>
<div>
  <p>
    Bits are pixels with colour and direction. When they move, they colour the ground beneath.
    When a bit meets another path it will change direction depending on the colour of the crossed path:
  </p>
  <ul>
    <li>If the colour is the same as the bit, then it will continue in a random, orthogonal, direction</li>
    <li>If the colour is different, then the bit will follow the path</li>
  </ul>
</div>

<br>
<p>Below is documentation for the settings:</p>

<div>
  <table class="tg">
    <tr>
      <th class="tg-9hbo">Setting</th>
      <th class="tg-9hbo">Behaviour</th>
    </tr>
    <tr>
      <td class="tg-yw4l">SPEED</td>
      <td class="tg-yw4l">Number of steps each bit moves before the display updates</td>
    </tr>
    <tr>
      <td class="tg-yw4l">NUM_BITS</td>
      <td class="tg-yw4l">The number of bits </td>
    </tr>
    <tr>
      <td class="tg-yw4l">FOLLOW</td>
      <td class="tg-yw4l">If *checked*, then bits will follow the paths in the same direction they were made. Otherwise, bits follow in the opposite direction</td>
    </tr>
    <tr>
      <td class="tg-baqh" colspan="2">Offset Settings - Normally a bit looks at the path beneath it. If an offset is used, then it will look at a path offset from itself</td>
    </tr>
    <tr>
      <td class="tg-yw4l">OFFSET_X</td>
      <td class="tg-yw4l">Offset in the horizontal direction. A value of 1 means look at the path 1 pixel to the right</td>
    </tr>
    <tr>
      <td class="tg-yw4l">OFFSET_Y</td>
      <td class="tg-yw4l">Offset in the vertical direction. A value of 1 means look at the path 1 pixel down</td>
    </tr>
    <tr>
      <td class="tg-yw4l">RANDOM</td>
      <td class="tg-yw4l">If *checked*, then OFFSET_X and OFFSET_Y are used as the absolute maximum offsets, and the offset per bit is randomly chosen upon generation</td>
    </tr>
  </table>
</div>
<br><br><br>

CSS

*{margin:24;font: 14px/22px Arial, sans-serif;}
body{background:#222;text-align:center;color:#f3eee8;margin-right:200px} 
canvas{
  background: rgba(0,0,0,0.5);
  border:5px solid rgba(0,0,0,0.5);
  display: inline-block;
  padding: 0,200px,0,0;
}
div{text-align:left;}
.tg  {border-collapse:collapse;border-spacing:0;}
.tg td{font-family:Arial, sans-serif;font-size:14px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;}
.tg th{font-family:Arial, sans-serif;font-size:14px;font-weight:normal;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;}
.tg .tg-baqh{text-align:center;vertical-align:top}
.tg .tg-9hbo{font-weight:bold;vertical-align:top}
.tg .tg-yw4l{vertical-align:top}

JavaScript

var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
var world = null;
var bits = null;
var settings = {
	COLORS: ['#145C35', '#39A095', '#A2D4AE', '#EFDA94', '#EA7428'],
	SPEED: 1,
	NUM_BITS: 20,
	FOLLOW: true,
  OFFSET_X: 0,
  OFFSET_Y: 0,
  RAND_OFFSET: false,
  INIT: function() {
	  ctx.clearRect(0, 0, canvas.width, canvas.height);
  	bits = [];
    for(let i=0;i<settings.NUM_BITS;i++) {
      let x = Math.floor(Math.random() * canvas.width);
      let y = Math.floor(Math.random() * canvas.height);
      let col = Math.floor(Math.random() * settings.COLORS.length);
      let dir = Math.floor(Math.random() * 4);
      let xo = settings.OFFSET_X;
      let yo = settings.OFFSET_Y;
      if (settings.RAND_OFFSET) {
      	xo = Math.floor(Math.random() * 2 * settings.OFFSET_X) - settings.OFFSET_X;
      	yo = Math.floor(Math.random() * 2 * settings.OFFSET_Y) - settings.OFFSET_Y;
      }
      bits.push(new Bit(x,y,col,dir,xo,yo));
    }

    world = [];
    for (let x=0; x<canvas.width; x++) {
      let row = [];
      for (let y=0; y<canvas.height; y++) {
        row.push({col: null, dir: null});
      }
      world.push(row);
    }
  }
}
var gui = new dat.GUI();
gui.add(settings, 'SPEED', 1, 100).step(1);
gui.add(settings, 'NUM_BITS', 1, 100).step(1).onFinishChange(settings.INIT);
gui.add(settings, 'FOLLOW');

var offsetFolder = gui.addFolder('Offset Settings');
offsetFolder.add(settings, 'OFFSET_X', -250, 250).step(1).onFinishChange(settings.INIT);
offsetFolder.add(settings, 'OFFSET_Y', -250, 250).step(1).onFinishChange(settings.INIT);
offsetFolder.add(settings, 'RAND_OFFSET').name('RANDOM').onFinishChange(settings.INIT);

gui.add(settings, 'INIT').name('RESET');

canvas.width = 600;
canvas.height = 600;

Number.prototype.mod = function(n) {
    return ((this%n)+n)%n;
};

class Bit {
	constructor(x,y,col,dir,xOffset,yOffset) {
  	this.x = x;
    this.y = y;
    this.col = col;
    this.dir = dir;
    this.xOffset = xOffset;
   ...