
12) Boxes
It’s like draw a box. But somehow even more. And automatic.
let gui;
let params = {
cubes: 3, cubesMin: 1, cubesMax: 9,
drawSpeed: 5, drawSpeedMin: 1, drawSpeedMax: 100,
spin: true,
colorful: true,
persist: true,
};
let buffer;
let cubes = [];
function setup() {
createCanvas(400, 400);
colorMode(HSB, 360, 100, 100, 100);
background(0);
buffer = createGraphics(400, 400, WEBGL);
buffer.pixelDensity(1);
buffer.colorMode(HSB, 360, 100, 100, 100);
gui = createGuiPanel("params");
gui.addObject(params);
gui.setPosition(420, 0);
}
function draw() {
while (cubes.length > params.cubes) cubes.shift();
while (cubes.length < params.cubes) {
cubes.push(new CubeDrawer(
createVector(
(6 * random() - 3) * 50,
(6 * random() - 3) * 50,
(6 * random() - 3) * 50,
),
50,
))
}
if (!params.persist) {
background(0);
buffer.clear();
buffer.background(0);
buffer.push();
buffer.resetMatrix();
buffer.pop();
}
cubes.forEach(cube => cube.drawStep());
cubes = cubes.filter(cube => !cube.isDone());
image(buffer, 0, 0, width, height);
}
class CubeDrawer {
constructor(offset, size) {
this.size = size;
this.offset = offset;
this.progress = 0;
this.speedVariance = random(0.9, 1.1);
this.hue = random(360);
this.rx = random(TWO_PI);
this.ry = random(TWO_PI);
this.rz = random(TWO_PI);
this.spinX = random(-0.002, 0.002);
this.spinY = random(-0.002, 0.002);
this.spinZ = random(-0.002, 0.002);
let s = size / 2;
this.vertices = [
createVector(-s, -s, -s),
createVector( s, -s, -s),
createVector( s, s, -s),
createVector(-s, s, -s),
createVector(-s, -s, s),
createVector( s, -s, s),
createVector( s, s, s),
createVector(-s, s, s),
];
this.edges = [
[0,1], [1,2], [2,3], [3,0],
[4,5], [5,6], [6,7], [7,4],
[0,4], [1,5], [2,6], [3,7]
];
this.segments = [];
let stepsPerEdge = size * 2;
for (let e of this.edges) {
let a = this.vertices[e[0]];
let b = this.vertices[e[1]];
for (let i = 0; i < stepsPerEdge; i++) {
let t = i / stepsPerEdge;
this.segments.push({
from: a,
to: b,
t: t
});
}
}
}
drawStep() {
buffer.push();
buffer.translate(this.offset.x, this.offset.y, this.offset.z);
if (params.spin) {
this.rx += this.spinX * params.drawSpeed / 3;
this.ry += this.spinY * params.drawSpeed / 3;
this.rz += this.spinZ * params.drawSpeed / 3;
}
buffer.rotateX(this.rx);
buffer.rotateY(this.ry);
buffer.rotateZ(this.rz);
let steps = min(this.progress, this.segments.length);
if (params.colorful) {
buffer.stroke(this.hue, 100, 100, 100);
} else {
buffer.stroke(255);
}
buffer.strokeWeight(1);
for (let i = 0; i < steps; i++) {
let s = this.segments[i];
let p = p5.Vector.lerp(s.from, s.to, s.t);
buffer.point(p.x, p.y, p.z);
}
this.progress += params.drawSpeed * this.speedVariance;
buffer.pop();
}
isDone() {
return this.progress >= this.segments.length;
}
}
Posts in Genuary 2026:
- Genuary 2026.12: Boxes
- Genuary 2026.11: Quine
- Genuary 2026.10: Polar coordinates
- Genuary 2026.09: Cellular automata
- Genuary 2026.08: A city
- Genuary 2026.07: Boolean algebra
- Genuary 2026.06: Lights on/off
- Genuary 2026.05: Write 'genuary'
- Genuary 2026.04: lowres
- Genuary 2026.03: Fibonacci forever
- Genuary 2026.02: Twelve principles of animation
- Genuary 2026.01: One color, one shape