Where ideas percolate and thoughts brew

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