Where ideas percolate and thoughts brew

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