The Advice Trap
About This Sketch
A visualization accompanying the blog post "The Advice Trap" that explores how seeking advice has become a substitute for action. The falling particles represent the constant stream of advice, tips, and wisdom we consume. They accumulate at the bottom, fading as they pile up. The arrow in the center represents direct action—cutting through the noise of endless advice to just start doing.
Algorithm
This sketch visualizes the advice trap through falling particles that accumulate at the bottom, representing the endless stream of advice we consume. An arrow breaks through the middle, pulsing upward, symbolizing direct action cutting through the accumulation.
Particles fall at varying speeds with random drift, fading as they approach the accumulation line at the bottom. The ground line has subtle waves suggesting the weight of accumulated advice. The central arrow provides a visual contrast—bold, directional, active—representing the "just start" alternative to endless advice consumption.
The sketch uses theme-aware colors that adapt to light and dark modes, with particles cycling through three accent colors to create visual variety while maintaining cohesion.
Pseudocode
SETUP:
Initialize canvas (400x300)
Create 80 advice particles with random positions and properties
Set particle properties: position, size, speed, drift, fade point
DRAW (every frame):
Get current theme colors
Clear background
Draw accumulation ground line at 85% height
Add subtle wave animation to ground line
For each particle:
Move particle down at its speed
Add horizontal drift
Calculate fade based on distance from fade point
Reset particle if off screen
Wrap particle horizontally
Draw particle with appropriate color and opacity
Draw action arrow:
Position in center
Add pulsing animation
Draw shaft (vertical line)
Draw arrowhead (triangle pointing down)
Increment time for animations
Source Code
let sketch = function(p) {
let particles = [];
let time = 0;
class AdviceParticle {
constructor() {
this.reset();
this.y = p.random(p.height);
}
reset() {
this.x = p.random(p.width);
this.y = -10;
this.size = p.random(3, 8);
this.speed = p.random(0.5, 2);
this.drift = p.random(-0.5, 0.5);
this.fadeStart = p.random(p.height * 0.4, p.height * 0.7);
this.opacity = 255;
}
update() {
this.y += this.speed;
this.x += this.drift;
// Fade out as they accumulate
if (this.y > this.fadeStart) {
let fadeProgress = (this.y - this.fadeStart) / (p.height - this.fadeStart);
this.opacity = 255 * (1 - fadeProgress);
}
// Reset when off screen
if (this.y > p.height + 10) {
this.reset();
}
// Wrap horizontally
if (this.x < -10) this.x = p.width + 10;
if (this.x > p.width + 10) this.x = -10;
}
display(colors) {
// Alternate between accent colors
let colorIndex = Math.floor(this.x / 30) % 3;
let color = colorIndex === 0 ? colors.accent1 :
colorIndex === 1 ? colors.accent2 : colors.accent3;
p.fill(color[0], color[1], color[2], this.opacity);
p.noStroke();
p.circle(this.x, this.y, this.size);
}
}
p.setup = function() {
p.createCanvas(400, 300);
p.colorMode(p.RGB);
// Create falling advice particles
for (let i = 0; i < 80; i++) {
particles.push(new AdviceParticle());
}
};
p.draw = function() {
const colors = getThemeColors();
p.background(...colors.bg);
// Draw accumulation line (ground)
let accumulationY = p.height * 0.85;
p.stroke(colors.accent2[0], colors.accent2[1], colors.accent2[2], 100);
p.strokeWeight(2);
p.line(0, accumulationY, p.width, accumulationY);
// Small waves on the accumulation line
p.noFill();
p.stroke(colors.accent1[0], colors.accent1[1], colors.accent1[2], 150);
p.strokeWeight(1.5);
p.beginShape();
for (let x = 0; x < p.width; x += 5) {
let wave = p.sin(x * 0.05 + time * 0.02) * 3;
p.vertex(x, accumulationY + wave);
}
p.endShape();
// Update and draw particles
for (let particle of particles) {
particle.update();
particle.display(colors);
}
// Draw action arrow breaking through
let arrowY = p.height * 0.5;
let arrowX = p.width * 0.5;
let arrowPulse = p.sin(time * 0.1) * 3;
// Arrow shaft
p.stroke(colors.accent2[0], colors.accent2[1], colors.accent2[2], 200);
p.strokeWeight(4);
p.line(arrowX, arrowY - 40 + arrowPulse, arrowX, arrowY + 60);
// Arrow head
p.fill(colors.accent2[0], colors.accent2[1], colors.accent2[2], 200);
p.noStroke();
p.triangle(
arrowX, arrowY + 70,
arrowX - 10, arrowY + 50,
arrowX + 10, arrowY + 50
);
time++;
};
};