Where ideas percolate and thoughts brew

The Plateau

About This Sketch

Most particles stop in the plateau zone. A few keep going and reach the destination — then loop back to begin again.

A visualization of the learning curve: early progress is fast, then a long flat stretch where nothing seems to be working, then acceleration once the threshold is crossed. The ones who quit in the middle never find out how close they were.

Algorithm

Eight particles travel horizontal tracks from left to right. The middle zone (plateau) dramatically slows all particles and introduces vertical drift. Five particles (quitters) stop and gray out in the plateau zone; three persisters continue through, accelerating after the plateau and looping back to the start when they reach the glowing destination on the right.

Pseudocode

SETUP:
  Create 8 particles with staggered start positions
  Mark bottom 3 as persisters, top 5 as quitters
  Assign each quitter a random stop position within the plateau

DRAW:
  Render plateau zone (subtle fill, label)
  Render pulsing destination glow on right
  For each particle:
    If stopped: draw as faded gray dot, skip
    Calculate speed multiplier based on zone:
      Before plateau: normal speed
      In plateau: 7% of normal speed + y jitter
      After plateau: 170% of normal speed
    If quitter and past quitX: mark stopped
    Advance x position
    If x > right edge and persister: reset to start
    Draw with accent2 (persister) or accent1 (quitter)

Source Code

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

    p.setup = function() {
        p.createCanvas(400, 300);
        for (let i = 0; i < 8; i++) {
            particles.push(makeParticle(i));
        }
    };

    function makeParticle(i) {
        let persists = i >= 5;
        return {
            idx: i,
            x: p.random(10, 35),
            y: 28 + i * 32,
            baseY: 28 + i * 32,
            speed: p.random(0.5, 0.9),
            persists: persists,
            quitX: persists ? 9999 : p.random(175, 235),
            stopped: false
        };
    }

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

        p.noStroke();
        p.fill(...colors.accent3, 18);
        p.rect(155, 8, 95, 282);
        p.fill(...colors.accent3, 55);
        p.textAlign(p.CENTER);
        p.textSize(8);
        p.text("plateau", 202, 298);

        let pulse = 0.5 + 0.5 * Math.sin(p.frameCount * 0.05);
        p.noStroke();
        p.fill(...colors.accent2, 18 + 12 * pulse);
        p.ellipse(368, 150, 80, 80);
        p.fill(...colors.accent2, 40 + 20 * pulse);
        p.ellipse(368, 150, 40, 40);
        p.fill(...colors.accent2, 130);
        p.ellipse(368, 150, 14, 14);

        for (let pt of particles) {
            if (pt.stopped) {
                p.fill(...colors.accent3, 65);
                p.noStroke();
                p.ellipse(pt.x, pt.y, 7, 7);
                continue;
            }

            let inPlateau = pt.x >= 155 && pt.x < 250;
            let afterPlateau = pt.x >= 250;

            let spd = pt.speed;
            if (inPlateau) spd *= 0.07;
            else if (afterPlateau) spd *= 1.7;

            if (!pt.persists && pt.x >= pt.quitX) {
                pt.stopped = true;
                continue;
            }

            pt.x += spd;

            if (inPlateau) {
                pt.y += p.random(-0.5, 0.5);
                pt.y = Math.max(pt.baseY - 8, Math.min(pt.baseY + 8, pt.y));
            }

            if (pt.x > 382) {
                pt.x = p.random(10, 35);
                pt.y = pt.baseY;
            }

            let col = pt.persists ? colors.accent2 : colors.accent1;
            p.fill(...col, 200);
            p.noStroke();
            p.ellipse(pt.x, pt.y, 8, 8);
        }
    };
};