The Curiosity Trap
About This Sketch
A visual comparison of scattered curiosity versus focused execution. Watch as unbounded curiosity spawns endless new interests while rarely completing anything, while focused execution steadily produces tangible results by maintaining attention on one goal at a time.
Algorithm
This sketch visualizes the contrast between unbounded curiosity and focused execution through two animated personas.
The left side shows "Unbounded Curiosity"—a person whose attention constantly splinters into new interests. New interest points spawn regularly, creating a cloud of scattered exploration. Each interest pulses and glows when new, then fades as attention shifts to the next shiny thing. Despite all this exploration, actual output (completed work) is rare because energy is constantly diverted to new explorations.
The right side shows "Focused Execution"—a person with a single target and steady progress toward completion. A focused beam of attention connects the person to their goal. A progress indicator shows steady advancement. When work completes, tangible output is created and floats upward, then new focused work begins. This person produces regular results because attention isn't fragmented.
The sketch accompanies the blog post "The Curiosity Trap" and visualizes its central argument: unlimited curiosity without execution constraints becomes sophisticated procrastination.
Pseudocode
SETUP:
Initialize canvas (400x300)
Create CuriousPerson (left side)
- Start with 3 random interests
- Track total interest count
Create FocusedPerson (right side)
- Single target above person
- Progress starts at 0
DRAW (every frame):
Get current theme colors
Clear background
CURIOUS PERSON:
Every 60 frames:
- Spawn new interest at random angle/distance
- Increment total interest count
For each interest:
- Age the interest
- After 180 frames, start fading (abandoned)
- Draw connection line
- Draw pulsing interest point
- Add glow to new interests
Rarely (0.5% chance) produce output
Draw person at center
Draw radiating attention waves (unfocused)
FOCUSED PERSON:
Increment progress by 0.5 each frame
When progress reaches 100:
- Create completed output object
- Reset progress to 0 (start new work)
For each completed output:
- Age and fade gradually
- Float upward slightly
Draw connection beam to target
Draw target with progress arc
Draw person at center
Display labels and statistics
Show contrast in shipped work count
Source Code
let sketch = function(p) {
let curiousPerson;
let focusedPerson;
let time = 0;
class CuriousPerson {
constructor() {
this.x = 100;
this.y = 150;
this.interests = [];
this.interestCount = 0;
this.output = 0;
// Start with a few interests
for (let i = 0; i < 3; i++) {
this.addInterest();
}
}
addInterest() {
let angle = p.random(p.TWO_PI);
let distance = p.random(30, 70);
this.interests.push({
x: this.x + p.cos(angle) * distance,
y: this.y + p.sin(angle) * distance,
age: 0,
explored: false,
alpha: 255
});
this.interestCount++;
}
update() {
// Add new interests frequently (curiosity spawning more curiosity)
if (p.frameCount % 60 === 0 && this.interests.length < 15) {
this.addInterest();
}
// Age interests
for (let i = this.interests.length - 1; i >= 0; i--) {
let interest = this.interests[i];
interest.age++;
// Fade out old interests (abandoned for new ones)
if (interest.age > 180) {
interest.alpha = p.max(0, interest.alpha - 3);
if (interest.alpha <= 0) {
this.interests.splice(i, 1);
}
}
}
// Very rarely produce output (too busy exploring)
if (p.random() < 0.005) {
this.output++;
}
}
display(colors) {
// Draw all interests as scattered points
for (let interest of this.interests) {
// Connection line
p.stroke(...colors.accent3, interest.alpha * 0.3);
p.strokeWeight(1);
p.line(this.x, this.y, interest.x, interest.y);
// Interest point (pulsing to show active exploration)
let pulse = p.sin(interest.age * 0.1) * 0.3 + 0.7;
p.noStroke();
p.fill(...colors.accent3, interest.alpha);
p.circle(interest.x, interest.y, 8 * pulse);
// Glow around new interests
if (interest.age < 60) {
p.fill(...colors.accent3, (60 - interest.age) * 2);
p.circle(interest.x, interest.y, 12);
}
}
// Draw the person (scattered attention)
p.noStroke();
p.fill(...colors.accent3, 180);
p.circle(this.x, this.y, 14);
// Attention radiating outward (unfocused)
for (let i = 0; i < 3; i++) {
let radius = (time * 2 + i * 20) % 60;
let alpha = p.map(radius, 0, 60, 100, 0);
p.stroke(...colors.accent3, alpha);
p.strokeWeight(1);
p.noFill();
p.circle(this.x, this.y, radius);
}
}
}
class FocusedPerson {
constructor() {
this.x = 300;
this.y = 150;
this.target = {
x: this.x,
y: this.y - 60,
progress: 0
};
this.output = 0;
this.completedOutputs = [];
}
update() {
// Steady progress on one thing
if (this.target.progress < 100) {
this.target.progress += 0.5;
} else {
// Complete the work, create output
this.completedOutputs.push({
x: this.target.x + p.random(-15, 15),
y: this.target.y - 30,
age: 0,
alpha: 255
});
this.output++;
// Start new focused work
this.target.progress = 0;
}
// Age and fade completed outputs
for (let i = this.completedOutputs.length - 1; i >= 0; i--) {
let output = this.completedOutputs[i];
output.age++;
// Move up slightly
output.y -= 0.3;
if (output.age > 200) {
output.alpha = p.max(0, output.alpha - 2);
if (output.alpha <= 0) {
this.completedOutputs.splice(i, 1);
}
}
}
}
display(colors) {
// Draw completed outputs
for (let output of this.completedOutputs) {
p.noStroke();
p.fill(...colors.accent2, output.alpha);
p.circle(output.x, output.y, 18);
// Glow
p.fill(...colors.accent2, output.alpha * 0.4);
p.circle(output.x, output.y, 28);
}
// Draw connection to current target
p.stroke(...colors.accent2, 200);
p.strokeWeight(2);
p.line(this.x, this.y, this.target.x, this.target.y);
// Draw target (single point of focus)
p.noStroke();
p.fill(...colors.accent2, 220);
p.circle(this.target.x, this.target.y, 16);
// Progress indicator around target
let progressAngle = p.map(this.target.progress, 0, 100, 0, p.TWO_PI);
p.noFill();
p.stroke(...colors.accent2, 200);
p.strokeWeight(3);
p.arc(this.target.x, this.target.y, 28, 28, -p.HALF_PI, -p.HALF_PI + progressAngle);
// Draw the person (focused)
p.noStroke();
p.fill(...colors.accent2, 200);
p.circle(this.x, this.y, 14);
// Focused beam toward target
p.stroke(...colors.accent2, 60);
p.strokeWeight(20);
p.line(this.x, this.y, this.target.x, this.target.y);
}
}
p.setup = function() {
p.createCanvas(400, 300);
p.colorMode(p.RGB);
curiousPerson = new CuriousPerson();
focusedPerson = new FocusedPerson();
};
p.draw = function() {
const colors = getThemeColors();
p.background(...colors.bg);
time++;
// Labels
p.noStroke();
p.fill(...colors.accent1, 180);
p.textAlign(p.CENTER);
p.textSize(11);
p.text('Unbounded Curiosity', 100, 30);
p.text('Focused Execution', 300, 30);
// Divider
p.stroke(...colors.accent1, 50);
p.strokeWeight(1);
p.line(200, 40, 200, 260);
// Update and display
curiousPerson.update();
focusedPerson.update();
curiousPerson.display(colors);
focusedPerson.display(colors);
// Stats
p.noStroke();
p.textSize(9);
p.textAlign(p.LEFT);
p.fill(...colors.accent3, 150);
p.text(`Topics explored: ${curiousPerson.interestCount}`, 20, 270);
p.text(`Shipped: ${curiousPerson.output}`, 20, 283);
p.textAlign(p.RIGHT);
p.fill(...colors.accent2, 150);
p.text(`Projects: ${focusedPerson.output}`, 380, 270);
p.text(`Shipped: ${focusedPerson.output}`, 380, 283);
// Bottom message
p.textAlign(p.CENTER);
p.fill(...colors.accent1, 140);
p.textSize(9);
p.text('Curiosity without execution is just procrastination', 200, 295);
};
};