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);
};
};