Where ideas percolate and thoughts brew

The Need for Closure

About This Sketch

A generative visualization of cognitive closure: particles floating freely in uncertainty until they prematurely commit to fixed positions. Those that settle too quickly (high prematurity) land far from optimal positions—a metaphor for opinions formed on insufficient exploration. The translucent, wandering particles represent the discomfort of ambiguity, while the rigid, opaque settled ones show the false comfort of premature certainty.

Algorithm

This sketch visualizes the tension between uncertainty and premature closure through a particle system. Each particle represents a thought or opinion forming in the space of possibility. Particles float freely in the canvas, representing the state of uncertainty and open exploration. Scattered throughout are target zones—potential positions where particles can "settle" into fixed opinions. Each particle has a "prematurity factor" that determines how quickly it will commit to a position. Those with high prematurity factors settle into the nearest target zone even when they're not at the center, representing confidently-held but potentially inaccurate positions formed on insufficient exploration. Once settled, particles lose their translucency and become rigid, only capable of minor oscillation around their chosen position—a metaphor for how premature certainty makes us resistant to new information and limits our ability to update our views. The sketch accompanies the blog post "The Need for Closure" and explores how our discomfort with ambiguity leads us to rush toward certainty, often at the cost of accuracy.

Pseudocode

SETUP:
  Initialize canvas (400x300)
  Create 8 random target positions (potential settled states)
  Spawn 60 particles with random positions and velocities
  Assign each particle a random prematurity factor (0.3-1.0)

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

  FOR each target position:
    Draw faint circular zone (potential settling area)

  FOR each particle:
    IF particle has settled:
      Apply subtle oscillation (slight uncertainty remains)
      Draw as opaque, solid circle
    ELSE:
      Add random movement (exploring uncertainty space)
      Apply velocity damping
      Update position with wrapping at edges

      FOR each target position:
        Calculate distance to target
        IF distance < threshold * prematurity_factor AND target not taken:
          Mark particle as settled
          Lock particle to target position
          Mark target as occupied

      Draw as translucent, floating circle

  Add text labels indicating uncertainty and closure states

Source Code

let sketch = function(p) {
    let particles = [];
    let targetPositions = [];
    let settled = [];
    let time = 0;

    class Particle {
        constructor(x, y) {
            this.x = x;
            this.y = y;
            this.vx = p.random(-2, 2);
            this.vy = p.random(-2, 2);
            this.targetIndex = -1;
            this.hasSettled = false;
            this.prematurityFactor = p.random(0.3, 1.0); // How quickly it settles
            this.opacity = 255;
        }

        update() {
            if (this.hasSettled) {
                // Slight oscillation when settled (uncertainty)
                this.x += p.sin(time + this.y) * 0.3;
                return;
            }

            // Particles floating in ambiguity
            this.vx += p.random(-0.1, 0.1);
            this.vy += p.random(-0.1, 0.1);

            // Damping
            this.vx *= 0.98;
            this.vy *= 0.98;

            this.x += this.vx;
            this.y += this.vy;

            // Wrap around
            if (this.x < 0) this.x = 400;
            if (this.x > 400) this.x = 0;
            if (this.y < 0) this.y = 300;
            if (this.y > 300) this.y = 0;

            // Check if close to any target (representing premature closure)
            for (let i = 0; i < targetPositions.length; i++) {
                let target = targetPositions[i];
                let d = p.dist(this.x, this.y, target.x, target.y);

                // Particles with high prematurity settle too early
                if (d < 30 * this.prematurityFactor && !settled[i]) {
                    this.hasSettled = true;
                    this.targetIndex = i;
                    settled[i] = true;
                    this.x = target.x;
                    this.y = target.y;
                    break;
                }
            }
        }

        display(colors) {
            if (this.hasSettled) {
                // Settled particles are opaque and rigid
                p.fill(...colors.accent2, this.opacity);
                p.noStroke();
                p.circle(this.x, this.y, 8);
            } else {
                // Floating particles are translucent (uncertainty)
                p.fill(...colors.accent1, 100);
                p.noStroke();
                p.circle(this.x, this.y, 6);
            }
        }
    }

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

        // Create target positions (places where particles "settle")
        for (let i = 0; i < 8; i++) {
            targetPositions.push({
                x: p.random(50, 350),
                y: p.random(50, 250)
            });
            settled[i] = false;
        }

        // Create floating particles
        for (let i = 0; i < 60; i++) {
            particles.push(new Particle(p.random(400), p.random(300)));
        }
    };

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

        time += 0.05;

        // Draw target zones (faint)
        p.fill(...colors.accent3, 30);
        p.noStroke();
        for (let target of targetPositions) {
            p.circle(target.x, target.y, 60);
        }

        // Update and display particles
        for (let particle of particles) {
            particle.update();
            particle.display(colors);
        }

        // Visual metaphor: particles floating freely (uncertainty) until they
        // prematurely settle into fixed positions (closure). The ones that
        // settle too quickly (high prematurity factor) may be far from the
        // actual target center, representing confident but wrong positions.

        // Add subtle text labels
        p.fill(...colors.accent3, 120);
        p.noStroke();
        p.textSize(10);
        p.textAlign(p.LEFT);
        p.text('uncertainty', 10, 20);
        p.textAlign(p.RIGHT);
        p.text('premature closure', 390, 290);
    };
};