Where ideas percolate and thoughts brew

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);
    };
};