Optimization Is Procrastination
About This Sketch
A pointed visualization of productivity theater. Three tools are endlessly sharpened, switched between, and "optimized" to ever-higher percentages, while actual finished products appear rarely at the bottom and slowly fade away. The sketch satirizes the modern tendency to perfect systems and workflows instead of using them to create.
This sketch accompanies "Optimization Is Procrastination," which argues that perfecting your tools and systems is structurally identical to procrastination—it looks like progress while preventing actual production.
Algorithm
This sketch visualizes the central irony of optimization culture: endless time spent perfecting tools while producing minimal actual output.
Three axes (representing productivity systems or tools) are displayed in the upper portion. The sketch randomly selects tools to "sharpen" (optimize), causing them to spin and display increasing "optimization" percentages. Meanwhile, at the bottom of the canvas, finished products (actual output) appear rarely and slowly fade away.
The visual starkly contrasts the constant activity of sharpening (which looks productive) with the minimal accumulation of finished products. A counter tracks "time sharpening" versus "things created," making the disparity explicit. The tools can reach "200% optimized!" while the product count remains in single digits.
This directly embodies the essay's argument: optimization is endless and feels productive, but it displaces the actual work of creation. You can sharpen forever, but eventually you need to cut down a tree.
Pseudocode
SETUP:
Create three Tool objects (axes) at different positions
Initialize empty product array
Set up 400x300 canvas
TOOL CLASS:
Properties: position, rotation, sharpness level, shine effect
sharpen(): Start rotating, increase sharpness metric, add shine
update(): Continue rotation if sharpening, fade shine effect
display(): Draw axe with rotation, show shine, display "optimized %" if high
PRODUCT CLASS:
Properties: position, size, opacity
update(): Slowly fade out over time
display(): Draw rectangular product with checkmark
DRAW (every frame):
Increment time counter
OPTIMIZATION BEHAVIOR (frequent):
Randomly select a tool to sharpen
Stop previous tool from sharpening
Start new tool sharpening
Increase its optimization metrics
PRODUCTION BEHAVIOR (rare):
Occasionally create a product at random position
Limit total products on screen
UPDATE ALL:
Update all tools (rotation, shine)
Update all products (fade out)
Remove fully faded products
DISPLAY:
Show all products at bottom (minimal, fading)
Show all tools at top (spinning, shining, optimizing)
Display counters showing time vs. output disparity
Add labels highlighting the irony
Source Code
let sketch = function(p) {
let tools = [];
let products = [];
let time = 0;
let switchCooldown = 0;
class Tool {
constructor(x, y) {
this.x = x;
this.y = y;
this.size = 25;
this.rotation = 0;
this.rotationSpeed = 0;
this.sharpness = 100; // How "optimized" the tool is
this.shine = 0;
}
sharpen() {
// Spending time sharpening (optimizing)
this.rotationSpeed = 0.15;
this.shine = 255;
this.sharpness = p.min(this.sharpness + 2, 200);
}
stopSharpening() {
this.rotationSpeed = 0;
}
update() {
this.rotation += this.rotationSpeed;
this.shine *= 0.95; // Shine fades
}
display(colors) {
p.push();
p.translate(this.x, this.y);
p.rotate(this.rotation);
// Tool body (axe head)
p.noStroke();
p.fill(...colors.accent2);
p.triangle(-this.size/2, 0, this.size/2, -this.size/3, this.size/2, this.size/3);
// Handle
p.fill(...colors.accent3);
p.rect(-this.size/2 - 15, -3, 15, 6);
// Shine effect when sharpening
if (this.shine > 10) {
p.fill(...colors.accent1, this.shine);
p.triangle(-this.size/2 + 2, 0, this.size/2 - 2, -this.size/4, this.size/2 - 2, this.size/4);
}
p.pop();
// "Sharpness" indicator (totally useless metric)
if (this.sharpness > 150) {
p.fill(...colors.accent1, 100);
p.noStroke();
p.textSize(8);
p.textAlign(p.CENTER);
p.text(`${p.floor(this.sharpness)}% optimized!`, this.x, this.y + 35);
}
}
}
class Product {
constructor(x) {
this.x = x;
this.y = 250;
this.width = p.random(15, 30);
this.height = p.random(40, 70);
this.alpha = 255;
this.created = time;
}
update() {
// Products slowly fade (getting old/irrelevant)
this.alpha *= 0.997;
}
display(colors) {
p.noStroke();
p.fill(...colors.accent2, this.alpha);
p.rect(this.x - this.width/2, this.y - this.height, this.width, this.height, 3);
// Checkmark on product
p.stroke(...colors.accent1, this.alpha);
p.strokeWeight(2);
p.noFill();
let cx = this.x;
let cy = this.y - this.height/2;
p.beginShape();
p.vertex(cx - 5, cy);
p.vertex(cx - 2, cy + 3);
p.vertex(cx + 5, cy - 4);
p.endShape();
}
}
p.setup = function() {
p.createCanvas(400, 300);
p.colorMode(p.RGB);
// Create three tools representing different "systems"
for (let i = 0; i < 3; i++) {
tools.push(new Tool(80 + i * 80, 80));
}
};
p.draw = function() {
const colors = getThemeColors();
p.background(...colors.bg);
time++;
switchCooldown = p.max(0, switchCooldown - 1);
// Simulate behavior: constantly switching between tools (systems)
// and sharpening them instead of using them
if (switchCooldown === 0 && p.random() < 0.02) {
// Stop sharpening all tools
tools.forEach(t => t.stopSharpening());
// Pick a "new" tool to optimize
let tool = p.random(tools);
tool.sharpen();
switchCooldown = 90; // Optimize for a while before switching again
}
// Occasionally actually USE a tool (ship something)
// But very rarely, because we're too busy optimizing
if (p.random() < 0.005 && products.length < 15) {
products.push(new Product(p.random(50, 350)));
}
// Update and display products (actual output)
for (let i = products.length - 1; i >= 0; i--) {
products[i].update();
products[i].display(colors);
if (products[i].alpha < 10) {
products.splice(i, 1);
}
}
// Update and display tools
for (let tool of tools) {
tool.update();
tool.display(colors);
}
// Labels
p.fill(...colors.accent3);
p.noStroke();
p.textSize(11);
p.textAlign(p.CENTER);
p.text('endless optimization', 200, 130);
p.text('(minimal output)', 200, 280);
// Visual counter showing the disparity
p.textAlign(p.LEFT);
p.textSize(10);
p.fill(...colors.accent3, 150);
p.text(`Time sharpening: ${p.floor(time/60)}s`, 10, 20);
p.text(`Things created: ${products.length}`, 10, 35);
};
};