The assignment was to find an existing piece of visual art (painting, ad, etc) that uses randomization as a key design principle, and recreate it in code.

I chose the painting by Wassily Kandinsky Several Circles, 1926

1024px-Vassily_Kandinsky,_1926_-_Several_Circles,_Gugg_0910_25

Looking at the painting I identified a bunch of rule design elements that used randomness on the circles: size, color, stroke & placement.

I color picked the colors in photoshop and identified the size range. To determine the color and size distribution I used weighted randomness.

Here are some of the results:

empty-project (58)(ilike)

empty-project (56)(ilike)

empty-project (14) (ilike)

===========================================================

THE CODE:

var r = new Rune({
container: “#canvas”,
width: 600,
height: 600,
debug: true
});

// Draw background-color
r.rect(0, 0, r.width, r.height).fill(40).stroke(false)

//Draw background random shapes with opacities
var noise = new Rune.Noise().noiseDetail(0.03); //was 0.6
var numPoints = 240;
var pointDegree = 360 / numPoints;
var radius = Rune.random(350, 380);
var noiseStep = 0;

for (var j = 0; j < 5; j++){

var randomSize = Rune.random(100, 200);
var x = Rune.random(100 + randomSize, r.width);
var y = Rune.random(100 + randomSize, r.height);

var noiseCircle = r.polygon(x, y)

.stroke(false)
.fill(15, 0.3)
.strokeWidth(2);

for(var i = 0; i < numPoints; i++) {

var noiseRadius = (noise.get(noiseStep) * 30) + radius;
var x = Math.cos(Rune.radians(pointDegree * i)) * noiseRadius;
var y = Math.sin(Rune.radians(pointDegree * i)) * noiseRadius;

noiseCircle.lineTo(x, y);
noiseStep += 0.25;
}
}

/////////////////////////////////////////////////////////////////////////////////

// Define function used to find weights.
function chooseWeighted(opts) {

// get sum of all the weights. This is where underscore is really great.
var sum = _.reduce(opts, function(memo, opt) { return memo + opt.weight; }, 0);

// now pick a random number between 0 and the sum of the weights
var ran = Rune.random(sum);

// loop through all the options until you find a weight that is greater
// or equal to the random number. Subtract weight from random num every time.
for( var i = 0; i < opts.length; i++){

var opt = opts[i];

if(opt.weight >= ran) {
return opt.value;
}

ran -= opt.weight;
}
}

// call function to find random color based on weight.
var colors = [
{ value: new Rune.Color(250, 140, 127), weight: 2 },
{ value: new Rune.Color(241, 187, 81), weight: 5 },
{ value: new Rune.Color(167, 88, 117), weight: 1 },
{ value: new Rune.Color(222, 137, 57), weight: 5 },
{ value: new Rune.Color(65, 119, 82), weight: 3 },
{ value: new Rune.Color(41, 97, 75), weight: 1 },
{ value: new Rune.Color(207, 186, 201), weight: 2 },
{ value: new Rune.Color(31, 109, 177), weight: 5 },
{ value: new Rune.Color(251, 204, 124), weight: 3 },
{ value: new Rune.Color(198, 59, 56), weight: 6 }
]

///////////////////////////////////////////////////////////////////////////////
// draw perlin noise white under circle shapes
var noise = new Rune.Noise().noiseDetail(0.6);
var numPoints = 120;
var pointDegree = 360 / numPoints;
var radius = Rune.random(110,210);
var noiseStep = 0;

for (var j = 0; j < 5; j++){

var randomSize = Rune.random(110, 180);
var x = Rune.random(100 + randomSize, r.width – 100 – randomSize);
var y = Rune.random(100 + randomSize, r.height – 100 – randomSize);

var noiseCircle = r.polygon(x, y)

.stroke(false)
.fill(255, 255, 255, 0.3)
.strokeWidth(2);

for(var i = 0; i < numPoints; i++) {

var noiseRadius = (noise.get(noiseStep) * 30) + radius;
var x = Math.cos(Rune.radians(pointDegree * i)) * noiseRadius;
var y = Math.sin(Rune.radians(pointDegree * i)) * noiseRadius;

noiseCircle.lineTo(x, y);
noiseStep += 0.23;
}
}

// draw one big circle
var randomSize = Rune.random(100, 200);
var x = Rune.random(100 + randomSize, r.width – 100 – randomSize);
var y = Rune.random(100 + randomSize, r.height – 100 – randomSize);
r.circle(x, y, randomSize).fill(27, 35, 118).stroke(255).strokeWidth(5, 0.2);

// draw small balck circle
r.circle(x + Rune.random(10, 20), y + Rune.random(10,20), Rune.random(90,100)).fill(0).stroke(false)

// Draw the colors in circles
for(var i = 0; i < 40; i++){

var randomSize = chooseWeighted([
{ value: Rune.random(25, 30), weight: 5 },
{ value: Rune.random(10, 15), weight: 14 },
{ value: Rune.random(3, 7), weight: 10 },
{ value: 50, weight: 1 }
]);

var col = chooseWeighted(colors);

col.alpha(Rune.random(0.5, 1));

var x = Rune.random(50 + randomSize, r.width – 50 – randomSize);
var y = Rune.random(50 + randomSize, r.height – 50 – randomSize);

var theCircle = r.circle(x, y,randomSize).fill(col).stroke(false);

if(Rune.random(1) > 0.8) {
theCircle.stroke(255, 255, 255, 0.6).strokeWidth(Rune.random(1,5))
}
}

// Draw the black little circles
for(var i = 0; i < 9; i++){
var randomSize = chooseWeighted([
{ value: 3, weight: 3 },
{ value: 5, weight: 2 },
{ value: 7, weight: 1}
]);

var x = Rune.random(50 + randomSize, r.width – 50 – randomSize);
var y = Rune.random(50 + randomSize, r.height – 50 – randomSize);
r.circle(x, y,randomSize).fill(20).stroke(false);

if(Rune.random(1) > 0.7) {
theCircle.stroke(255, 255, 255, 0.8).strokeWidth(1)
}

}

r.draw();