Where ideas percolate and thoughts brew

The Humility Trap

About This Sketch

Twenty-two views orbit a point of truth. The calibrated ones stay close — they've committed to a radius and hold it. The hedged ones start nearby but drift outward as time passes, each at its own rate, each pulled by the same invisible force: the comfort of not being pinned down. Watch the signal clarity bar fall as the cloud expands. The truth hasn't moved. The views have just become too diffuse to locate it.

Algorithm

Twenty-two particles orbit a central "truth" point. Twelve are calibrated: they maintain tight, stable orbits close to the center. Ten are hedged: over 480 frames, hedge pressure builds and each hedged particle drifts outward toward a looser orbit at radius 85, with individual drift rates varying by a random hedge factor. A signal clarity bar tracks the fraction of particles still orbiting tightly. As hedging spreads, the cloud expands and clarity falls. The calibrated particles stay anchored; the hedged ones disperse.

Pseudocode

SETUP:
  Create 12 calibrated particles at radius ~28 (tight orbit)
  Create 10 hedged particles starting near radius 28-48

DRAW each frame:
  Increment frame counter
  Compute hedgePressure = min(1.0, frame / 480)

  Draw reference rings at calibrated radius and hedged radius
  Draw and label central truth point

  For each particle:
    Increment angle by speed (orbital motion)
    If calibrated: targetR = baseR (stays put)
    If hedged: targetR = baseR + hedgePressure * hedgeFactor * (LOOSE_R - baseR)
    Lerp r toward targetR
    Draw particle: calibrated = warm dot, hedged = muted dot fading outward

  Count particles in tight orbit (r < TIGHT_R + 16)
  Draw signal clarity bar = tightCount / total
  Draw legend and caption

Source Code

let sketch = function(p) {
    // The Hedge Field: particles orbit a central "truth" point.
    // Calibrated particles maintain tight orbits (small radius).
    // Hedged particles drift outward over time (large, loose orbits).
    // As hedging pressure builds, more particles spread further from truth.
    // A signal clarity bar tracks how much useful information remains
    // concentrated near the center.

    const W = 400, H = 300;
    const CX = W / 2, CY = H / 2 - 10;
    const TRUTH_R = 8;
    const TIGHT_R = 28;
    const LOOSE_R = 85;

    let particles = [];
    let frame = 0;

    function makeParticle(isCalibrated) {
        let angle = p.random(p.TWO_PI);
        let baseR = isCalibrated ? TIGHT_R + p.random(-8, 8) : TIGHT_R + p.random(5, 20);
        return {
            angle: angle,
            r: baseR,
            baseR: baseR,
            speed: p.random(0.009, 0.022) * (p.random() > 0.5 ? 1 : -1),
            calibrated: isCalibrated,
            hedgeFactor: isCalibrated ? 0 : p.random(0.4, 1.0)
        };
    }

    p.setup = function() {
        p.createCanvas(W, H);
        p.randomSeed(7);
        for (let i = 0; i < 12; i++) particles.push(makeParticle(true));
        for (let i = 0; i < 10; i++) particles.push(makeParticle(false));
    };

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

        let hedgePressure = p.min(1.0, frame / 480);

        p.noFill();
        p.stroke(...colors.accent2, 40);
        p.strokeWeight(1);
        p.circle(CX, CY, TIGHT_R * 2 + 16);

        p.stroke(...colors.accent3, 25);
        p.strokeWeight(1);
        p.circle(CX, CY, LOOSE_R * 2);

        p.noStroke();
        p.textSize(8);
        p.textAlign(p.LEFT);
        p.fill(...colors.accent2, 80);
        p.text('calibrated', CX + TIGHT_R + 10, CY - 2);
        p.fill(...colors.accent3, 55);
        p.text('hedged', CX + LOOSE_R + 4, CY - 2);

        p.fill(...colors.accent1);
        p.noStroke();
        p.circle(CX, CY, TRUTH_R * 2);
        p.fill(...colors.bg);
        p.circle(CX, CY, TRUTH_R);
        p.fill(...colors.accent1, 130);
        p.textSize(8);
        p.textAlign(p.CENTER);
        p.text('truth', CX, CY + TRUTH_R + 10);

        let tightCount = 0;
        for (let pt of particles) {
            pt.angle += pt.speed;

            let targetR = pt.calibrated
                ? pt.baseR
                : pt.baseR + hedgePressure * pt.hedgeFactor * (LOOSE_R - pt.baseR);

            pt.r += (targetR - pt.r) * 0.018;

            let x = CX + pt.r * p.cos(pt.angle);
            let y = CY + pt.r * p.sin(pt.angle);

            if (pt.r < TIGHT_R + 16) tightCount++;

            if (pt.calibrated) {
                p.fill(...colors.accent2, 210);
                p.noStroke();
                p.circle(x, y, 6);
            } else {
                let t = p.constrain((pt.r - TIGHT_R) / (LOOSE_R - TIGHT_R), 0, 1);
                let alpha = p.lerp(180, 90, t);
                p.fill(...colors.accent3, alpha);
                p.noStroke();
                p.circle(x, y, 5);
            }
        }

        let clarity = tightCount / particles.length;

        let barX = 10, barY = H - 28, barW = 120, barH = 9;
        p.noStroke();
        p.fill(...colors.accent3, 35);
        p.rect(barX, barY, barW, barH, 3);
        p.fill(...colors.accent2, 180);
        p.rect(barX, barY, barW * clarity, barH, 3);

        p.fill(...colors.accent3, 140);
        p.textSize(8);
        p.textAlign(p.LEFT);
        p.text('signal clarity', barX, barY - 3);

        p.fill(...colors.accent2, 200);
        p.circle(W - 110, H - 35, 6);
        p.fill(...colors.accent2, 160);
        p.textSize(8);
        p.textAlign(p.LEFT);
        p.text('calibrated', W - 102, H - 31);

        p.fill(...colors.accent3, 130);
        p.circle(W - 110, H - 20, 5);
        p.fill(...colors.accent3, 110);
        p.text('hedged', W - 102, H - 16);

        p.fill(...colors.accent3, 50);
        p.textAlign(p.CENTER);
        p.textSize(8);
        p.text('precision lost \u00b7 hedges expand the cloud', W / 2, H - 4);
    };
};