The Action Bias
About This Sketch
When someone is "acting" on it, add random interference
This sketch accompanies the blog post "The Action Bias" and visualizes its core concepts through generative art.
Algorithm
When someone is "acting" on it, add random interference
This sketch was originally created as a visual companion to the blog post "The Action Bias" and explores its themes through generative art.
Pseudocode
SETUP:
Initialize canvas (400x300)
Set up drawing parameters
DRAW (every frame):
Get current theme colors
Clear background
Draw generative visualization
Update animation state
Source Code
let sketch = function(p) {
let pendulums = [];
class Pendulum {
constructor(x, angle, length, active) {
this.x = x;
this.angle = angle;
this.angleVel = 0;
this.angleAcc = 0;
this.length = length;
this.active = active; // whether someone is "acting" on it
this.damping = active ? 0.995 : 0.998; // active = more interference = more damping
this.gravity = 0.2;
}
update() {
if (this.active) {
// When someone is "acting" on it, add random interference
this.angleAcc = -this.gravity * p.sin(this.angle) / this.length;
this.angleAcc += p.random(-0.002, 0.002); // random interference from action
} else {
// When left alone, natural motion
this.angleAcc = -this.gravity * p.sin(this.angle) / this.length;
}
this.angleVel += this.angleAcc;
this.angleVel *= this.damping;
this.angle += this.angleVel;
}
display(colors) {
let posX = this.x + this.length * p.sin(this.angle);
let posY = 100 + this.length * p.cos(this.angle);
// Line
p.stroke(...(this.active ? colors.accent2 : colors.accent1), 150);
p.strokeWeight(2);
p.line(this.x, 100, posX, posY);
// Pivot point
p.noStroke();
p.fill(...colors.accent3, 200);
p.ellipse(this.x, 100, 6, 6);
// Bob
p.fill(...(this.active ? colors.accent2 : colors.accent1), 220);
p.ellipse(posX, posY, 12, 12);
}
// How close to equilibrium (rest state)
equilibrium() {
return p.abs(this.angle) + p.abs(this.angleVel);
}
}
p.setup = function() {
p.createCanvas(400, 300);
p.colorMode(p.RGB);
// Create pendulums - some "acted upon" (active), some left alone (inactive)
// The ones left alone will settle to equilibrium faster
pendulums.push(new Pendulum(100, 0.8, 80, true)); // acted upon
pendulums.push(new Pendulum(200, 0.8, 80, false)); // left alone
pendulums.push(new Pendulum(300, 0.8, 80, true)); // acted upon
};
p.draw = function() {
const colors = getThemeColors();
p.background(...colors.bg);
// Labels
p.textAlign(p.CENTER, p.TOP);
p.textSize(10);
p.fill(...colors.accent3, 200);
p.noStroke();
p.text("Action", 100, 15);
p.text("Waiting", 200, 15);
p.text("Action", 300, 15);
// Instructions
p.textAlign(p.CENTER, p.BOTTOM);
p.textSize(9);
p.fill(...colors.accent3, 150);
p.text("The middle pendulum (left alone) settles fastest", 200, 290);
// Update and display all pendulums
for (let pendulum of pendulums) {
pendulum.update();
pendulum.display(colors);
}
// Show equilibrium levels
p.textAlign(p.CENTER, p.TOP);
p.textSize(8);
for (let i = 0; i < pendulums.length; i++) {
let eq = pendulums[i].equilibrium();
let percentage = p.constrain(100 - eq * 100, 0, 100);
p.fill(...colors.accent3, 150);
p.text(p.floor(percentage) + "% settled", pendulums[i].x, 240);
}
};
};