Where ideas percolate and thoughts brew

The Advice Paradox

About This Sketch

An animated visualization exploring how we seek wisdom through consuming advice (represented by hollow, appealing but empty circles) when real understanding only comes through direct experience (solid, substantial circles). The seeker initially chases advice nodes in somewhat aimless patterns before the experience nodes gradually reveal themselves as the actual path to wisdom. This accompanies the essay on why actionable advice is often useless and unactionable advice is what we actually needβ€”once we've done the work to understand it.

Algorithm

This sketch visualizes the paradox that we seek wisdom through advice (hollow circles) but can only gain it through experience (solid circles). The animation shows a seeker initially chasing advice nodes scattered around the canvas, moving in somewhat aimless patterns. After a period of this fruitless seeking, the experience nodes gradually become visible, revealing the actual path to understanding. The hollow advice circles represent how advice looks appealing but is ultimately empty without context. The solid experience circles represent the substantial learning that comes from doing. The seeker's journey represents how we often waste time consuming advice before realizing we need to just start doing things.

Pseudocode

SETUP:
  Create canvas (400x300)
  Initialize advice nodes (hollow circles) at various positions - visible from start
  Initialize experience nodes (solid circles) hidden initially
  Create target point representing "wisdom"

DRAW (every frame):
  Get current theme colors
  Clear background
  Increment time counter

  IF time > 120 frames:
    Gradually reveal experience nodes
    Fade them in by increasing alpha

  IF time > 150 frames:
    Draw connections between experience nodes
    Show that experience forms the real path to wisdom

  FOR each node:
    IF advice node:
      Draw as hollow circle (stroke only)
    IF experience node AND visible:
      Draw as solid circle (filled)
    Apply pulsing animation to all visible nodes

  UPDATE seeker position:
    IF time <= 120:
      Seeker chases nearest advice node
      Moves in somewhat circular/aimless patterns
    ELSE:
      Seeker follows linear path
      Moving toward experience nodes

  Draw seeker as small dot
  Display contextual labels based on time

Source Code

let sketch = function(p) {
    let nodes = [];
    let target = null;
    let time = 0;

    class Node {
        constructor(x, y, label, type) {
            this.x = x;
            this.y = y;
            this.label = label;
            this.type = type; // 'advice' or 'experience'
            this.alpha = type === 'advice' ? 180 : 120;
            this.size = type === 'advice' ? 30 : 25;
            this.visible = type === 'advice'; // advice nodes start visible
            this.pulseOffset = p.random(p.TWO_PI);
        }

        display(colors) {
            if (!this.visible) return;

            let pulse = p.sin(time * 0.05 + this.pulseOffset) * 0.2 + 1;
            let currentSize = this.size * pulse;

            p.noStroke();
            if (this.type === 'advice') {
                // Hollow circles for advice (looks appealing but empty)
                p.noFill();
                p.stroke(...colors.accent1, this.alpha);
                p.strokeWeight(2);
                p.circle(this.x, this.y, currentSize);
            } else {
                // Solid circles for experience (substantial)
                p.fill(...colors.accent2, this.alpha);
                p.circle(this.x, this.y, currentSize);
            }
        }
    }

    p.setup = function() {
        p.createCanvas(400, 300);
        p.colorMode(p.RGB);

        // Create advice nodes (what you seek - visible)
        nodes.push(new Node(80, 70, 'Read more', 'advice'));
        nodes.push(new Node(180, 50, 'Network better', 'advice'));
        nodes.push(new Node(280, 80, 'Work harder', 'advice'));
        nodes.push(new Node(320, 150, 'Find passion', 'advice'));
        nodes.push(new Node(250, 220, 'Be authentic', 'advice'));
        nodes.push(new Node(150, 240, 'Ship fast', 'advice'));
        nodes.push(new Node(60, 180, 'Stay focused', 'advice'));

        // Create experience nodes (what you need - initially hidden)
        nodes.push(new Node(120, 110, 'failed project', 'experience'));
        nodes.push(new Node(200, 140, 'awkward conversation', 'experience'));
        nodes.push(new Node(180, 190, 'public mistake', 'experience'));
        nodes.push(new Node(260, 170, 'slow progress', 'experience'));

        // Target (the wisdom you're seeking)
        target = { x: 200, y: 150, reached: false };
    };

    p.draw = function() {
        const colors = getThemeColors();
        p.background(...colors.bg);

        time++;

        // Gradually reveal experience nodes
        if (time > 120) {
            for (let node of nodes) {
                if (node.type === 'experience') {
                    node.visible = true;
                    node.alpha = p.min(node.alpha + 2, 200);
                }
            }
        }

        // Draw connections between experience nodes (the real path)
        if (time > 150) {
            p.stroke(...colors.accent2, 60);
            p.strokeWeight(2);
            let experienceNodes = nodes.filter(n => n.type === 'experience' && n.visible);
            for (let i = 0; i < experienceNodes.length - 1; i++) {
                p.line(experienceNodes[i].x, experienceNodes[i].y,
                      experienceNodes[i+1].x, experienceNodes[i+1].y);
            }
        }

        // Draw target (wisdom/understanding)
        p.noStroke();
        p.fill(...colors.accent3, 150);
        p.circle(target.x, target.y, 15);

        // Display all nodes
        for (let node of nodes) {
            node.display(colors);
        }

        // Draw seeker (cursor moving through space)
        let seekerX = 50 + (time % 400);
        let seekerY = 150 + p.sin(time * 0.03) * 40;

        // Before 120 frames: chasing advice nodes (going in circles)
        if (time <= 120) {
            let closestAdvice = nodes.filter(n => n.type === 'advice')
                .reduce((closest, node) => {
                    let d = p.dist(seekerX, seekerY, node.x, node.y);
                    return d < closest.d ? {node, d} : closest;
                }, {node: null, d: Infinity});

            if (closestAdvice.node) {
                seekerX += (closestAdvice.node.x - seekerX) * 0.02;
                seekerY += (closestAdvice.node.y - seekerY) * 0.02;
            }
        }

        p.noStroke();
        p.fill(...colors.accent1, 220);
        p.circle(seekerX, seekerY, 8);

        // Labels
        p.fill(...colors.accent3, 180);
        p.textAlign(p.CENTER);
        p.textSize(10);

        if (time <= 120) {
            p.text('seeking advice...', 200, 290);
            p.textSize(8);
            p.text('(hollow circles)', 200, 20);
        } else if (time <= 180) {
            p.text('discovering the real path...', 200, 290);
            p.textSize(8);
            p.text('(solid circles = experience)', 200, 20);
        } else {
            p.text('wisdom comes from doing, not reading', 200, 290);
        }
    };
};