Where ideas percolate and thoughts brew

The Boredom Deficit

About This Sketch

Particles drift through a Perlin noise field, forming and dissolving connections as they pass close to one another. The motion is slow, aimless-lookingβ€”but constantly generative. This is what the mind does when left alone: wanders, finds unexpected connections, produces ideas that focused attention cannot.

The sketch visualizes the argument in "The Boredom Deficit": that an idle mind is not an empty one. The connections between particles appear without effort, without direction. They couldn't be planned. They can only happen when the particles are free to drift.

Algorithm

55 particles drift across the canvas guided by a 2D Perlin noise field, each following a smoothly evolving direction vector. When particles come within 48 pixels of each other, they are connected by faint lines whose opacity scales inversely with distance. A semi-transparent background rect drawn each frame creates trailing paths. The result resembles a mind wandering: particles move without apparent purpose but form and dissolve meaningful connections as they pass near each other β€” representing the associative, generative thinking that happens during boredom and mind-wandering. This sketch accompanies the blog post "The Boredom Deficit," which argues that eliminating boredom eliminates the mental state where original ideas and self-knowledge are formed.

Pseudocode

SETUP:
  Initialize 55 particles at random positions
  Each particle has: position, velocity, noise seed, size, speed

DRAW (every frame):
  Get current theme colors
  Draw semi-transparent background rect (creates trails)
  Increment time counter

  For each particle:
    Sample 2D Perlin noise at (nx + time, ny + time) β†’ angle
    Smoothly interpolate velocity toward noise direction
    Update position by velocity
    Wrap position at canvas edges

  For each pair of particles:
    Compute distance
    If distance < 48px:
      Draw line with alpha = map(distance, 0, 48, 65, 0)

  For each particle:
    Draw filled circle at position

  Draw caption text

Source Code

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

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

        for (let i = 0; i < 55; i++) {
            particles.push({
                x: p.random(400),
                y: p.random(300),
                vx: 0,
                vy: 0,
                nx: p.random(1000),
                ny: p.random(1000 + i * 47),
                size: p.random(2, 4.5),
                speed: p.random(0.4, 0.85)
            });
        }
    };

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

        p.noStroke();
        p.fill(...colors.bg, 38);
        p.rect(0, 0, 400, 300);

        time += 0.008;

        for (let particle of particles) {
            let angle = p.noise(particle.nx + time * 0.45, particle.ny + time * 0.3) * p.TWO_PI * 2;
            particle.vx = p.lerp(particle.vx, p.cos(angle) * particle.speed, 0.06);
            particle.vy = p.lerp(particle.vy, p.sin(angle) * particle.speed, 0.06);
            particle.x += particle.vx;
            particle.y += particle.vy;

            if (particle.x < -10) particle.x = 410;
            if (particle.x > 410) particle.x = -10;
            if (particle.y < -10) particle.y = 310;
            if (particle.y > 310) particle.y = -10;
        }

        for (let i = 0; i < particles.length; i++) {
            for (let j = i + 1; j < particles.length; j++) {
                let d = p.dist(particles[i].x, particles[i].y, particles[j].x, particles[j].y);
                if (d < 48) {
                    let alpha = p.map(d, 0, 48, 65, 0);
                    p.stroke(...colors.accent1, alpha);
                    p.strokeWeight(0.5);
                    p.line(particles[i].x, particles[i].y, particles[j].x, particles[j].y);
                }
            }
        }

        for (let particle of particles) {
            p.noStroke();
            p.fill(...colors.accent2, 195);
            p.circle(particle.x, particle.y, particle.size);
        }

        p.noStroke();
        p.fill(...colors.accent1, 105);
        p.textAlign(p.CENTER);
        p.textSize(9);
        p.text('an idle mind is not empty β€” it is working', 200, 293);
    };
};