Where ideas percolate and thoughts brew

Passion Is Downstream

About This Sketch

A visual meditation on how passion emerges from the accumulation of skill and effort, rather than being a prerequisite for beginning. Small acts of commitment fall like raindrops, each landing and expanding into competence, which eventually generates the radiating ripples of genuine passion.

This sketch accompanies the essay "Passion Is Downstream," which argues against the common advice to "follow your passion" and instead suggests that passion develops as a natural consequence of building competence, gaining autonomy, and seeing impact from your work.

Algorithm

This sketch visualizes the core thesis of "Passion Is Downstream"β€”that passion emerges from competence rather than preceding it. The animation uses a water metaphor: small drops (representing initial commitment) fall from the top of the canvas and land at the bottom. Each drop that lands creates a pool that gradually expands (representing growing competence and skill development). Once a pool reaches its full size, it begins generating ripples that radiate outward (representing passion that emerges from mastery). The visual progression embodies the post's argument: you don't start with the ripples (passion)β€”you start with the commitment (drops), which builds competence (expanding pools), which then generates passion (radiating ripples). The causal flow moves from top to bottom, making "passion is downstream" literally visible.

Pseudocode

SETUP:
  Initialize empty arrays for drops and pools
  Create 400x300 canvas

DROP CLASS:
  Start at random x position at top of canvas
  Fall downward at random speed
  When reaching bottom:
    Mark as landed
    Create a new pool at landing position
    Remove self from active drops

POOL CLASS:
  Start with radius of 0
  Gradually expand toward maximum radius (competence building)
  When reaching full size:
    Begin spawning ripples periodically
  Each ripple expands outward and fades (passion radiating)

DRAW (every frame):
  Fade background slightly for trail effect
  Spawn new drops occasionally
  Update all drops (move downward, check for landing)
  Update all pools (expand, manage ripples)
  Display drops, pools, and ripples
  Show labels: "commitment ↓" and "β†’ passion"

Source Code

let sketch = function(p) {
    let drops = [];
    let pools = [];
    let time = 0;

    class Drop {
        constructor() {
            // Random starting position at top
            this.x = p.random(50, 350);
            this.y = -10;
            this.speed = p.random(2, 4);
            this.hasLanded = false;
            this.landedTime = 0;
        }

        update() {
            if (!this.hasLanded) {
                this.y += this.speed;

                // Check if reached bottom
                if (this.y >= 280) {
                    this.hasLanded = true;
                    this.landedTime = time;
                    // Create a pool where it landed
                    pools.push(new Pool(this.x, 280));
                }
            }
        }

        display(colors) {
            if (!this.hasLanded) {
                // Small falling drop (before commitment/competence)
                p.noStroke();
                p.fill(...colors.accent2, 180);
                p.ellipse(this.x, this.y, 4, 8);
            }
        }
    }

    class Pool {
        constructor(x, y) {
            this.x = x;
            this.y = y;
            this.radius = 0;
            this.maxRadius = p.random(25, 45);
            this.growth = p.random(0.3, 0.6);
            this.brightness = 255;
            this.ripples = [];
        }

        update() {
            // Pool grows over time (competence building)
            if (this.radius < this.maxRadius) {
                this.radius += this.growth;
            } else {
                // Once at max size, create ripples (passion emerging)
                if (p.frameCount % 30 === 0) {
                    this.ripples.push({ r: 0, alpha: 255 });
                }
            }

            // Update ripples
            for (let i = this.ripples.length - 1; i >= 0; i--) {
                this.ripples[i].r += 1.5;
                this.ripples[i].alpha -= 3;
                if (this.ripples[i].alpha <= 0) {
                    this.ripples.splice(i, 1);
                }
            }
        }

        display(colors) {
            // Draw ripples (passion radiating outward)
            p.noFill();
            for (let ripple of this.ripples) {
                p.stroke(...colors.accent1, ripple.alpha * 0.6);
                p.strokeWeight(2);
                p.circle(this.x, this.y, ripple.r * 2);
            }

            // Draw main pool (competence)
            p.noStroke();
            let poolAlpha = p.map(this.radius, 0, this.maxRadius, 50, 180);

            // Gradient effect - brighter at edges
            for (let r = this.radius; r > 0; r -= 3) {
                let alpha = p.map(r, 0, this.radius, poolAlpha, poolAlpha * 0.3);
                p.fill(...colors.accent2, alpha);
                p.circle(this.x, this.y, r * 2);
            }

            // Bright center when fully formed
            if (this.radius >= this.maxRadius) {
                p.fill(...colors.accent1, 200);
                p.circle(this.x, this.y, 8);
            }
        }
    }

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

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

        // Slow fade background
        p.fill(...colors.bg, 40);
        p.noStroke();
        p.rect(0, 0, p.width, p.height);

        time++;

        // Spawn new drops occasionally
        if (p.frameCount % 40 === 0 && drops.length < 5) {
            drops.push(new Drop());
        }

        // Update and display drops (commitment/effort)
        for (let i = drops.length - 1; i >= 0; i--) {
            drops[i].update();
            drops[i].display(colors);

            // Remove landed drops
            if (drops[i].hasLanded && time - drops[i].landedTime > 10) {
                drops.splice(i, 1);
            }
        }

        // Update and display pools (competence growing into passion)
        for (let pool of pools) {
            pool.update();
            pool.display(colors);
        }

        // Labels
        p.fill(...colors.accent3, 150);
        p.textSize(11);
        p.textAlign(p.LEFT);
        p.text('commitment ↓', 10, 20);
        p.textAlign(p.RIGHT);
        p.text('β†’ passion', 390, 285);

        // Visual metaphor: Small drops (initial commitment) fall and land,
        // creating expanding pools (growing competence) that eventually
        // generate ripples (passion radiating outward from mastery).
        // Passion is downstream - it emerges from the accumulated work.
    };
};