Where ideas percolate and thoughts brew

The Introspection Trap

About This Sketch

Seven wave strands emerge clear and coherent on the left — a clean first judgment — then progressively fragment into noise as "analysis" accumulates rightward. The more you examine, the more the original signal degrades into scattered rationalization. Visualizing the verbal overshadowing effect: introspection replaces signal with story.

Algorithm

Signal degradation through analysis — seven parallel wave strands travel left to right. On the far left, a glowing dot represents an unexamined first judgment: clean and coherent. As position moves rightward, each wave strand becomes progressively noisier and more fragmented, with stray scatter dots appearing to represent rationalization fragments. Color shifts from warm amber (clear judgment) to muted taupe (analyzed noise). This sketch accompanies the blog post "The Introspection Trap" and visualizes how carefully examining your reasons for a decision degrades rather than clarifies the underlying signal.

Pseudocode

SETUP:
  Initialize canvas (400x300)
  Generate random noise seeds for each of 7 wave strands

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

  FOR each column (0 to 79) across the canvas:
    Compute analysisFrac (0=left/pure, 1=right/degraded)

    FOR each of 7 wave strands:
      Compute clean sine wave position
      Blend in Perlin noise proportional to analysisFrac squared
      Shift color from accent2 (warm) to accent3 (muted)
      Reduce alpha and dot size rightward
      Scatter fragment dots stochastically for high analysisFrac columns

  Draw pulsing clarity dot at far left (original judgment)
  Draw labels: "first judgment" left, "after analysis" right
  Draw arrow and caption

Source Code

let sketch = function(p) {
    let time = 0;
    let noiseSeeds = [];
    const WAVE_COUNT = 7;
    const COLS = 80;

    p.setup = function() {
        p.createCanvas(400, 300);
        p.colorMode(p.RGB);
        for (let i = 0; i < WAVE_COUNT; i++) {
            noiseSeeds.push(p.random(1000));
        }
    };

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

        time += 0.012;

        for (let col = 0; col < COLS; col++) {
            let x = p.map(col, 0, COLS - 1, 30, 370);
            let analysisFrac = p.map(col, 0, COLS - 1, 0, 1);

            for (let w = 0; w < WAVE_COUNT; w++) {
                let baseY = p.map(w, 0, WAVE_COUNT - 1, 60, 240);
                let amplitude = p.map(analysisFrac, 0, 1, 22, 6);

                let cleanY = baseY + amplitude * Math.sin(time * (1 + w * 0.18) + w * 0.9);

                let noiseAmt = p.map(analysisFrac, 0, 1, 0, 1);
                let n = p.noise(noiseSeeds[w] + col * 0.12, time * 0.6 + w * 0.4);
                let noiseY = p.map(n, 0, 1, -28, 28);
                let y = p.lerp(cleanY, cleanY + noiseY, noiseAmt * noiseAmt);

                let waveAlpha = p.map(Math.abs(w - (WAVE_COUNT - 1) / 2), 0, (WAVE_COUNT - 1) / 2, 1, 0.25);

                let r = p.lerp(colors.accent2[0], colors.accent3[0], analysisFrac);
                let g = p.lerp(colors.accent2[1], colors.accent3[1], analysisFrac);
                let b = p.lerp(colors.accent2[2], colors.accent3[2], analysisFrac);
                let a = p.lerp(170, 60, analysisFrac * analysisFrac) * waveAlpha;

                p.noStroke();
                p.fill(r, g, b, a);
                let dotSize = p.lerp(3.2, 1.4, analysisFrac);
                p.circle(x, y, dotSize);

                if (analysisFrac > 0.55 && p.random() < analysisFrac * 0.18) {
                    let fragX = x + p.random(-9, 9);
                    let fragY = y + p.random(-18, 18);
                    p.fill(r, g, b, a * 0.4);
                    p.circle(fragX, fragY, dotSize * 0.7);
                }
            }
        }

        let dotPulse = 0.82 + 0.18 * Math.sin(time * 2.3);
        p.noStroke();
        p.fill(...colors.accent1, 30 * dotPulse);
        p.circle(30, 150, 28 * dotPulse);
        p.fill(...colors.accent2, 180 * dotPulse);
        p.circle(30, 150, 7 * dotPulse);

        p.noStroke();
        p.fill(...colors.accent3, 55);
        p.textSize(8.5);
        p.textAlign(p.CENTER);
        p.text('first judgment', 30, 288);
        p.text('after analysis', 370, 288);

        p.stroke(...colors.accent3, 38);
        p.strokeWeight(0.8);
        p.line(65, 282, 340, 282);
        p.noStroke();
        p.fill(...colors.accent3, 38);
        p.triangle(345, 282, 337, 278, 337, 286);

        p.noStroke();
        p.fill(...colors.accent3, 60);
        p.textAlign(p.CENTER);
        p.textSize(9);
        p.text('examining your reasons degrades the signal', 200, 18);
    };
};