Cubic Disarray

Georg Nees’ fantastic generative art is a true inspiration. In this tutorial, we’re going to build one of his pieces: Cubic Disarray.

The only HTML we have on the page is a <canvas> element at 300x300 pixels.

As usual, here is our initial setup. You’re not going to see anything render here, because these are the primary lines to setting up the canvas and context which we use to draw.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
var canvas = document.querySelector('canvas');
var context = canvas.getContext('2d');
context.lineWidth = 2;

var size = window.innerWidth;

canvas.width = size;
canvas.height = size;

var squareSize = 40;
  

We’ve also got a variable in there to define the square size, understandably named squareSize.

Now, let’s create a function to draw the squares. This function is going to be fairly simple, taking only a width and a height. The position of the squares is going to be handled by another loop.

11
12
13
14
15
16
function draw(width, height) {
  context.beginPath();
  context.rect(-width/2, -height/2, width, height);
  context.stroke(); 
}

So how about we draw something. I’m going to loop through and fill the screen with squares. Here we’re using the context save, translate & restore functions to move the context around, and then our draw function above for drawing.

10
11
12
13
14
15
16
17
18
19
 
for( var i = squareSize; i <= size - squareSize; i += squareSize) {
  for( var j = squareSize; j <= size - squareSize; j+= squareSize ) {
    context.save();
    context.translate(i, j);
    draw(squareSize, squareSize);
    context.restore();
  }
}

And there we have it, squares! Now we have the “cubic” part down, we can get to the disarray.

Introducing random is fairly simple: first we’ll give ourselves some variables, one for how much the squares translate out of their position, and one for how much they rotate.

10
11
12
var randomDisplacement = 15;
var rotateMultiplier = 20;

We can use those variables, then, to create the random translations and rotations. They’re set up here to be larger numbers as they reach towards the end of the canvas.

22
23
24
25
26
27
28
    var plusOrMinus = Math.random() < 0.5 ? -1 : 1;
    var rotateAmt = j / size * Math.PI / 180 * plusOrMinus * Math.random() * rotateMultiplier;

    plusOrMinus = Math.random() < 0.5 ? -1 : 1;
    var translateAmt = j / size * plusOrMinus * Math.random() * randomDisplacement;
      

Now, we apply the translations and rotatations. (Suddenly all that setup paid off!)

22
23
24
    context.translate( i + translateAmt, j)
    context.rotate(rotateAmt);

And there we have it: cubic disarray!