Where ideas percolate and thoughts brew

The Waiting Place

About This Sketch

A meditation on procrastination disguised as preparation. One figure endlessly prepares at the starting line, accumulating knowledge and plans but never moving. Another simply begins, making progress while the first is still waiting for the right moment.

This sketch accompanies the essay "The Waiting Place" about how waiting for optimal conditions is a sophisticated form of self-sabotage. Watch how preparation circles multiply around the static figure while the path ahead remains untouched.

Algorithm

This sketch visualizes the difference between perpetual preparation and actual action. A figure stands at the starting line, accumulating circles of "preparation" around them—representing endless learning, planning, and waiting for perfect conditions. These circles grow and fade over time, but the figure never moves forward. Periodically, a second figure appears who simply starts moving. No preparation circles, no waiting—just immediate action along the path ahead. The contrast illustrates the core thesis of the post: preparation accumulates but doesn't create progress. Only action does.

Pseudocode

SETUP:
  Initialize canvas (400x300)
  Create waiting figure at starting line
  Create path points representing the work ahead
  Initialize preparation circle array

DRAW (every frame):
  Get current theme colors
  Clear background

  Draw the path ahead (the actual work)
  Draw starting line

  Waiting Figure:
    Increment time waiting
    Every 30 frames, add new preparation circle
    Update all preparation circles (grow, rotate, fade)
    Display circles orbiting the waiting figure
    Draw waiting figure (never moves from start line)

  Starting Figure (appears periodically):
    Every 400 frames, show new starting figure
    Move figure forward along path
    Leave trail behind
    Display figure with "Doing" label
    When reaches end, hide until next cycle

  Display dynamic message based on state:
    If many preparation circles: "Preparation accumulates. Progress doesn't."
    Otherwise: "Waiting feels like progress. It isn't."

Source Code

let sketch = function(p) {
    // Visualization: A figure standing at a starting line
    // Circles of "preparation" accumulating around them
    // But the path ahead remains untouched
    // Over time, the preparation circles fade, but the figure never moves
    // Occasionally, a different figure appears who just starts walking

    let waitingFigure = {
        x: 80,
        y: 150,
        preparationCircles: [],
        timeWaiting: 0
    };

    let startingFigure = {
        x: 80,
        y: 150,
        active: false,
        progress: 0,
        visible: false
    };

    let pathPoints = [];
    let showMessage = false;
    let messageTimer = 0;

    class PreparationCircle {
        constructor(x, y, index) {
            this.x = x;
            this.y = y;
            this.radius = 0;
            this.targetRadius = 15 + (index * 2);
            this.opacity = 180;
            this.angle = p.random(p.TWO_PI);
            this.distance = 20 + (index * 8);
        }

        update() {
            this.radius = p.lerp(this.radius, this.targetRadius, 0.05);
            this.angle += 0.01;
            this.opacity -= 0.3; // Fade over time
            return this.opacity > 0;
        }

        display(colors) {
            let x = waitingFigure.x + p.cos(this.angle) * this.distance;
            let y = waitingFigure.y + p.sin(this.angle) * this.distance;

            p.noFill();
            p.stroke(...colors.accent3, this.opacity);
            p.strokeWeight(1);
            p.circle(x, y, this.radius);
        }
    }

    p.setup = function() {
        p.createCanvas(400, 300);

        // Create path points
        for (let x = 100; x < 380; x += 20) {
            pathPoints.push({x: x, y: 150 + p.random(-10, 10)});
        }
    };

    p.draw = function() {
        const colors = getThemeColors();
        p.background(...colors.bg);

        // Title
        p.fill(...colors.accent3);
        p.noStroke();
        p.textAlign(p.CENTER);
        p.textSize(12);
        p.text('The Waiting Place', 200, 20);

        // Draw the path (representing the work to be done)
        p.stroke(...colors.accent3, 60);
        p.strokeWeight(2);
        p.noFill();
        p.beginShape();
        for (let point of pathPoints) {
            p.vertex(point.x, point.y);
        }
        p.endShape();

        // Starting line
        p.stroke(...colors.accent2, 120);
        p.strokeWeight(2);
        p.line(70, 130, 70, 170);

        p.noStroke();
        p.fill(...colors.accent3, 150);
        p.textSize(8);
        p.textAlign(p.CENTER);
        p.text('START', 70, 185);

        // Waiting figure accumulates preparation
        waitingFigure.timeWaiting++;

        if (waitingFigure.timeWaiting % 30 === 0) {
            let index = waitingFigure.preparationCircles.length;
            waitingFigure.preparationCircles.push(
                new PreparationCircle(waitingFigure.x, waitingFigure.y, index)
            );
        }

        // Update and display preparation circles
        waitingFigure.preparationCircles = waitingFigure.preparationCircles.filter(circle => {
            circle.update();
            circle.display(colors);
            return circle.opacity > 0;
        });

        // Draw waiting figure (never moves)
        p.noStroke();
        p.fill(...colors.accent1, 200);
        p.circle(waitingFigure.x, waitingFigure.y, 10);

        // Label
        p.fill(...colors.accent3, 180);
        p.textSize(7);
        p.textAlign(p.CENTER);
        p.text('Preparing', waitingFigure.x, waitingFigure.y - 20);

        // Occasionally show a starting figure who just goes
        if (p.frameCount % 400 === 0) {
            startingFigure.visible = true;
            startingFigure.progress = 0;
            startingFigure.x = 80;
            showMessage = true;
            messageTimer = 0;
        }

        if (startingFigure.visible) {
            startingFigure.progress += 0.5;
            startingFigure.x += 0.8;

            // Draw starting figure (moves forward)
            p.noStroke();
            p.fill(...colors.accent2, 220);
            p.circle(startingFigure.x, startingFigure.y, 10);

            // Trail behind
            if (p.frameCount % 5 === 0) {
                p.fill(...colors.accent2, 60);
                p.circle(startingFigure.x - 10, startingFigure.y, 3);
            }

            // Label
            p.fill(...colors.accent3, 220);
            p.textSize(7);
            p.textAlign(p.CENTER);
            p.text('Doing', startingFigure.x, startingFigure.y - 20);

            if (startingFigure.x > 400) {
                startingFigure.visible = false;
                showMessage = false;
            }
        }

        // Message
        if (showMessage) {
            messageTimer++;
            let alpha = messageTimer < 60 ? messageTimer * 3 : 180;
            p.fill(...colors.accent2, alpha);
            p.textAlign(p.CENTER);
            p.textSize(8);
            p.text('This one just started', 200, 200);
        }

        // Bottom insight
        p.textAlign(p.CENTER);
        p.textSize(7);
        p.fill(...colors.accent3, 150);

        if (waitingFigure.preparationCircles.length > 10) {
            p.text('Preparation accumulates. Progress doesn\'t.', 200, 280);
        } else {
            p.text('Waiting feels like progress. It isn\'t.', 200, 280);
        }
    };
};