The Momentum Illusion
About This Sketch
A visualization contrasting momentum (busy activity) with progress (directed movement). Multiple particles on the left move quickly but randomly, while a single particle on the right moves deliberately toward a goal. Despite being slower, the progress particle actually reaches its destination—demonstrating that speed without direction is less valuable than intentional movement. Accompanies the essay "The Momentum Illusion" about confusing activity with achievement.
Algorithm
This sketch visualizes the difference between momentum (activity without direction) and progress (deliberate movement toward a goal).
LEFT SIDE: Eight particles moving at high speed with frequently changing random directions, leaving short trails. They bounce off walls and constantly change course—lots of visible motion but no destination. Represents busy-work, constant activity, momentum culture.
RIGHT SIDE: A single particle moving more slowly but directly toward a goal (represented by a rotating star). It leaves a longer, straighter trail showing its intentional path. Despite moving slower, it makes continuous progress toward its destination.
The visual contrast demonstrates the core insight: High velocity without direction is less valuable than slower, intentional movement. The sketch tracks the progress particle's distance to the goal, showing measurable progress versus the directionless motion on the left.
This accompanies the blog post "The Momentum Illusion" which explores how we confuse activity with progress and why stopping to check direction is often the most productive action.
Pseudocode
SETUP:
Create canvas (400x300)
Place goal star in right section
Initialize 8 momentum particles (left side, random positions)
Initialize 1 progress particle (center-right, aimed at goal)
DRAW (every frame):
Get current theme colors
Clear background
LEFT SECTION:
For each momentum particle:
- Add current position to trail
- Move at high speed in current direction
- Randomly change direction 3% of frames
- Bounce off section boundaries
- Draw fading trail (shows lots of motion)
- Draw particle
RIGHT SECTION:
Draw rotating goal star
For progress particle:
- Add current position to trail
- Calculate direction vector to goal
- Move slowly but directly toward goal
- Draw longer, straighter trail
- Draw particle
- Display distance remaining to goal
If progress particle reaches goal:
- Reset particle to starting position
- Continue cycle
Display alternating insight text
Show labels for both sections
Source Code
let sketch = function(p) {
// Visualization: The Momentum Illusion
// Shows particles moving with high velocity but in random/circular directions
// vs a single particle moving slowly but directly toward a goal
// Demonstrates: Speed without direction vs. intentional progress
let momentumParticles = [];
let progressParticle;
let goal;
let frame = 0;
class MomentumParticle {
constructor(x, y) {
this.x = x;
this.y = y;
this.vx = p.random(-2, 2);
this.vy = p.random(-2, 2);
this.size = 6;
this.trail = [];
this.maxTrail = 30;
}
update() {
// High speed, random direction changes
this.trail.push({ x: this.x, y: this.y });
if (this.trail.length > this.maxTrail) {
this.trail.shift();
}
this.x += this.vx;
this.y += this.vy;
// Random direction changes (momentum without purpose)
if (p.random() < 0.03) {
this.vx = p.random(-2, 2);
this.vy = p.random(-2, 2);
}
// Bounce off walls
if (this.x < 20 || this.x > 180) this.vx *= -1;
if (this.y < 60 || this.y > 240) this.vy *= -1;
// Keep in bounds
this.x = p.constrain(this.x, 20, 180);
this.y = p.constrain(this.y, 60, 240);
}
display(colors) {
// Trail (showing lots of motion)
p.noFill();
p.beginShape();
for (let i = 0; i < this.trail.length; i++) {
let alpha = p.map(i, 0, this.trail.length, 0, 120);
p.stroke(...colors.accent2, alpha);
p.strokeWeight(1);
p.vertex(this.trail[i].x, this.trail[i].y);
}
p.endShape();
// Particle
p.noStroke();
p.fill(...colors.accent2, 180);
p.circle(this.x, this.y, this.size);
}
}
class ProgressParticle {
constructor(x, y, goal) {
this.x = x;
this.y = y;
this.goal = goal;
this.size = 8;
this.trail = [];
this.maxTrail = 50;
this.speed = 0.8; // Slower than momentum particles
}
update() {
// Slow, deliberate movement toward goal
this.trail.push({ x: this.x, y: this.y });
if (this.trail.length > this.maxTrail) {
this.trail.shift();
}
let dx = this.goal.x - this.x;
let dy = this.goal.y - this.y;
let distance = p.sqrt(dx * dx + dy * dy);
if (distance > 5) {
let angle = p.atan2(dy, dx);
this.x += p.cos(angle) * this.speed;
this.y += p.sin(angle) * this.speed;
}
}
display(colors) {
// Trail (showing direct path)
p.noFill();
p.beginShape();
for (let i = 0; i < this.trail.length; i++) {
let alpha = p.map(i, 0, this.trail.length, 0, 150);
p.stroke(...colors.accent1, alpha);
p.strokeWeight(2);
p.vertex(this.trail[i].x, this.trail[i].y);
}
p.endShape();
// Particle
p.noStroke();
p.fill(...colors.accent1, 200);
p.circle(this.x, this.y, this.size);
}
distanceToGoal() {
let dx = this.goal.x - this.x;
let dy = this.goal.y - this.y;
return p.sqrt(dx * dx + dy * dy);
}
}
p.setup = function() {
p.createCanvas(400, 300);
// Goal star in right section
goal = { x: 340, y: 150 };
// Create momentum particles (left side) - lots of them, moving fast
for (let i = 0; i < 8; i++) {
momentumParticles.push(
new MomentumParticle(
p.random(40, 160),
p.random(80, 220)
)
);
}
// Create progress particle (right side) - single, slow, directed
progressParticle = new ProgressParticle(220, 150, goal);
};
p.draw = function() {
const colors = getThemeColors();
p.background(...colors.bg);
frame++;
// Title
p.fill(...colors.accent3, 200);
p.noStroke();
p.textAlign(p.CENTER);
p.textSize(11);
p.text('The Momentum Illusion', 200, 20);
// Divider line
p.stroke(...colors.accent3, 80);
p.strokeWeight(1);
p.line(200, 50, 200, 270);
// LEFT SECTION: Momentum without direction
p.fill(...colors.accent3, 180);
p.noStroke();
p.textSize(9);
p.textAlign(p.CENTER);
p.text('High Momentum', 100, 45);
p.textSize(7);
p.fill(...colors.accent3, 140);
p.text('(Lots of motion, no direction)', 100, 55);
// Update and display momentum particles
for (let particle of momentumParticles) {
particle.update();
particle.display(colors);
}
// RIGHT SECTION: Progress toward goal
p.fill(...colors.accent3, 180);
p.noStroke();
p.textSize(9);
p.textAlign(p.CENTER);
p.text('Intentional Progress', 300, 45);
p.textSize(7);
p.fill(...colors.accent3, 140);
p.text('(Slower, but toward a goal)', 300, 55);
// Draw goal
p.noStroke();
p.fill(...colors.accent3, 200);
// Draw star for goal
p.push();
p.translate(goal.x, goal.y);
p.rotate(frame * 0.02);
p.beginShape();
for (let i = 0; i < 5; i++) {
let angle = (i * p.TWO_PI) / 5 - p.HALF_PI;
let x = p.cos(angle) * 10;
let y = p.sin(angle) * 10;
p.vertex(x, y);
angle += p.PI / 5;
x = p.cos(angle) * 5;
y = p.sin(angle) * 5;
p.vertex(x, y);
}
p.endShape(p.CLOSE);
p.pop();
p.textSize(7);
p.fill(...colors.accent3, 140);
p.text('GOAL', goal.x, goal.y + 20);
// Update and display progress particle
progressParticle.update();
progressParticle.display(colors);
// Show distance to goal
let distance = progressParticle.distanceToGoal();
p.textSize(8);
p.fill(...colors.accent1, 180);
p.text(`Distance: ${Math.round(distance)}`, 300, 270);
// Bottom insight text
p.fill(...colors.accent3, 180);
p.noStroke();
p.textSize(7);
p.textAlign(p.CENTER);
if (frame < 200) {
p.text('Activity without direction is just exhaustion with no destination.', 200, 290);
} else if (frame < 400) {
p.text('The fastest path to your goal: Stop moving. Check direction. Then move deliberately.', 200, 290);
} else {
p.text('Progress beats momentum. Slow and aimed beats fast and random.', 200, 290);
}
// Reset if progress particle reaches goal
if (distance < 10) {
progressParticle = new ProgressParticle(220, 150, goal);
}
// Labels for motion vs progress
if (frame % 120 < 60) {
p.textSize(6);
p.fill(...colors.accent2, 140);
p.textAlign(p.CENTER);
p.text('Busy, but going nowhere', 100, 265);
p.fill(...colors.accent1, 140);
p.text('Slower, but getting there', 300, 260);
}
};
};