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