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 320×320 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. We will also set the size of the canvas and adjust it based on the user’s device pixel ratio, or pixel density. This ensures that the final result is crisp on all monitors.

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

var size = window.innerWidth;
var dpr = window.devicePixelRatio;
canvas.width = size * dpr;
canvas.height = size * dpr;
context.scale(dpr, dpr);
context.lineWidth = 2;

var squareSize = 30;

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.

13
14
15
16
17
18
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.

19
20
21
22
23
24
25
26
27
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, one for how much they rotate, and one for how much to offset the entire drawing to get it centered on the canvas.

11
12
13
14
var randomDisplacement = 15;
var rotateMultiplier = 20;
var offset = 10;

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.

24
25
26
27
28
29
30
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 rotations. (Suddenly all that setup paid off!)

31
32
33
context.translate(i + translateAmt + offset, j + offset);
context.rotate(rotateAmt);

And there we have it: cubic disarray!

↪ You can edit the code above, and have it run by pressing the arrow between the code and demo, but if you like, you can also play around a little with this code