The Advice Paradox
About This Sketch
A visualization exploring how advice remains meaningless until we've accumulated the lived experiences to understand it. Watch as floating advice phrases only "connect" to the person after they've built up sufficient experience - representing the paradox that advice makes sense only after we've learned the lesson ourselves.
Algorithm
This sketch visualizes the core paradox of advice: it only becomes comprehensible after you've lived through the experiences it refers to.
The visualization shows a person (you) surrounded by floating advice phrases. As the person accumulates lived experiences (represented by glowing orbs that orbit them), occasionally a piece of advice "clicks" and connects to the person - but only after sufficient experience has been accumulated. The advice was always there, floating nearby, but meaningless until the person had the reference experiences to understand it.
This accompanies the blog post "The Advice Paradox" which explores why advice sounds obvious in hindsight, useless before you need it, and impossible to follow when you need it most.
Pseudocode
SETUP:
Create person entity at center bottom
Initialize 15 floating advice pieces with random positions and velocities
Initialize empty experience collection
EVERY FRAME:
- Occasionally add new experience orb to person (represents lived experience)
- Move advice pieces around the canvas (bounce off edges)
- Update all experience orbs (fade in, rotate around person)
- For each advice piece:
- If person has sufficient experience AND random chance triggers:
- Mark advice as "understood"
- Create connection flash between advice and person
- Advice begins settling near person instead of drifting
- Display state message showing how many pieces are understood
- Visual metaphor: advice is always present, but comprehension requires experience
Source Code
let sketch = function(p) {
// Visualization: Advice as floating words that only connect to a person
// when they've had the matching experience (represented by a colored aura)
// Words drift around, occasionally one connects when the person's experience matches
let person = {
x: 200,
y: 250,
experiences: []
};
let advicePieces = [];
let maxAdvice = 15;
let connectionFlashes = [];
class Experience {
constructor() {
this.angle = p.random(p.TWO_PI);
this.radius = p.random(30, 50);
this.opacity = 0;
this.targetOpacity = p.random(100, 180);
this.growth = p.random(0.5, 1.5);
}
update() {
this.opacity = p.lerp(this.opacity, this.targetOpacity, 0.05);
this.angle += 0.01;
}
display(colors) {
let x = person.x + p.cos(this.angle) * this.radius;
let y = person.y + p.sin(this.angle) * this.radius;
p.noStroke();
p.fill(...colors.accent1, this.opacity * 0.3);
p.circle(x, y, 15);
}
}
class AdvicePiece {
constructor() {
this.x = p.random(50, 350);
this.y = p.random(40, 150);
this.vx = p.random(-0.5, 0.5);
this.vy = p.random(-0.3, 0.3);
this.understood = false;
this.checkTimer = p.random(0, 100);
const adviceTexts = [
"Be yourself",
"Trust the process",
"Stay curious",
"Less is more",
"Start small",
"Done > Perfect",
"Know your worth",
"Pick battles",
"Trust takes time",
"Follow passion",
"Seek feedback",
"Stay humble",
"Keep learning",
"Be patient",
"Act bold"
];
this.text = p.random(adviceTexts);
}
update() {
this.x += this.vx;
this.y += this.vy;
// Bounce off edges
if (this.x < 30 || this.x > 370) this.vx *= -1;
if (this.y < 30 || this.y > 160) this.vy *= -1;
// Occasionally check if person is ready to understand this advice
this.checkTimer++;
if (this.checkTimer > 180 && !this.understood && person.experiences.length > 3) {
if (p.random() < 0.02) { // 2% chance per frame when conditions are met
this.understood = true;
connectionFlashes.push({
x: this.x,
y: this.y,
life: 60
});
}
}
}
display(colors) {
if (this.understood) {
// Connected advice - glows and settles near person
this.x = p.lerp(this.x, person.x + p.random(-40, 40), 0.05);
this.y = p.lerp(this.y, person.y - 60 + p.random(-20, 20), 0.05);
p.fill(...colors.accent2, 200);
p.textSize(8);
p.textAlign(p.CENTER);
p.text(this.text, this.x, this.y);
// Glow effect
p.fill(...colors.accent2, 40);
p.noStroke();
p.circle(this.x, this.y, 30);
} else {
// Floating advice - dim and drifting
p.fill(...colors.accent3, 100);
p.textSize(8);
p.textAlign(p.CENTER);
p.text(this.text, this.x, this.y);
}
}
}
class ConnectionFlash {
constructor(x, y, life) {
this.x = x;
this.y = y;
this.life = life;
this.maxLife = life;
}
update() {
this.life--;
return this.life > 0;
}
display(colors) {
let alpha = (this.life / this.maxLife) * 200;
p.stroke(...colors.accent2, alpha);
p.strokeWeight(2);
p.line(this.x, this.y, person.x, person.y);
}
}
p.setup = function() {
p.createCanvas(400, 300);
p.colorMode(p.RGB);
// Initialize advice pieces
for (let i = 0; i < maxAdvice; i++) {
advicePieces.push(new AdvicePiece());
}
};
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 Advice Paradox', 200, 20);
// Occasionally add experience to the person
if (p.frameCount % 90 === 0 && person.experiences.length < 12) {
person.experiences.push(new Experience());
}
// Update and display connection flashes
connectionFlashes = connectionFlashes.filter(flash => {
flash.update();
flash.display(colors);
return flash.life > 0;
});
// Update and display experiences (person's lived experience)
for (let exp of person.experiences) {
exp.update();
exp.display(colors);
}
// Draw the person
p.noStroke();
p.fill(...colors.accent1, 220);
p.circle(person.x, person.y, 12);
// Label
p.fill(...colors.accent3, 180);
p.textSize(7);
p.textAlign(p.CENTER);
p.text('You', person.x, person.y + 25);
// Update and display advice
for (let advice of advicePieces) {
advice.update();
advice.display(colors);
}
// Bottom text showing state
p.textAlign(p.CENTER);
p.textSize(7);
p.fill(...colors.accent3, 150);
let understoodCount = advicePieces.filter(a => a.understood).length;
if (person.experiences.length < 3) {
p.text('Advice floats around you, meaningless without experience', 200, 285);
} else if (understoodCount === 0) {
p.text('Living life generates experience. Advice starts to make sense.', 200, 285);
} else {
p.text(`${understoodCount} pieces understood - but only after the lesson was lived`, 200, 285);
}
};
};