Procedural Animation with Canvas, random walks

HTML5 comes with Canvas, a beautiful blank canvas for us to paint on.
It can do a lot. I'll be going through how to create a simple procedural animation! It shouldn't take long to get a random walker moving around the screen. After we get our pixel friend moving, we'll play with it's color. Then we'll get a few walkers moving on the canvas at the same time. Finally, we'll connect the dots to get our walkers painting an abstract.

Our final walkers will draw something like this:
image

But first, we need a canvas!

<canvas id='mainCanvas'>Displayed if canvas isn't supported.</canvas>

I like the canvas to fill our whole view:

canvas.width = window.innerWidth
canvas.height = window.innerHeight

Once we have our canvas, we need it's context, the object we use to manipulate our canvas.

ctx = canvas.getRenderContext('2d')

That's all we need to start rendering shapes to our canvas.

let rectWidth = 5
let rectHeight = 5
ctx.fillStyle = 'black'
ctx.rect( canvas.width/2, canvas.height/2, rectWidth, rectHeight)
ctx.fill()

To animate the point, we need two things.

An animation loop and some rendering logic for the point that will be called each time the loop runs.

Our rendering logic will be ultra simple for now: at each step, we will move the x and y portions of our point by a random amount.
Then we will draw it to the screen.

function render(){
  point.x += (Math.random()-.5)*5
  point.y += (Math.random() -.5)*5
  ctx.rect( point.x, point.y, 5, 5)
  ctx.fill()
  window.requestAnimationFrame(render);
}

Then we get our animation loop from window.requestAnimationFrame(callback), which fires when the window is ready to draw a new frame.
We then give it our callback function that renders the new frame. (If animation speed is of concern, we should use the time passed to the callback to keep the animation steady across monitors with different refresh rates)


We have our animation running, just like that. Feel free to play with it on codepen!

Now we are going to play a little bit with color.


ctx.fillStyle = `rgba(${time%255}, ${time%50}, ${time%127}, 1)`

The context fillStyle can understand any valid CSS color value, including named strings, rgba() values, as well as many others.
We use the passed time along with the modulo operator to create a cycling color pallet. The red channel varies from 0-255, the green from 0 to 50, and the blue from 0 to 127.

Next, we'll add a few random walkers to our screen. Why? Because we can!

First we setup our walkers.

let points = []
for(let i = 0; i < numPoints; i++){
  let point = {x: canvas.width/numPoints*i, 
             y: canvas.height/2}
  points.push(point)
}

Then we update each of the walkers in our render function.

points.forEach( (point, i) =>{ 
    ctx.beginPath()
    point.x += (Math.random()-.5)*5
    point.y += (Math.random() -.5)*5
    ctx.rect( point.x, point.y, 5, 5)
    ctx.fill()
  })

What happens when we connect all the walkers with a colored line?
Let's find out!

with 'hue' compositing
image

Using the center point as the connected point, dodge compositing, smaller walkers, and a bigger y-direction jump.

Here is the codepen that generated it

46