Where ideas percolate and thoughts brew

The Research Performance

About This Sketch

Visualizing information overload vs. clarity Left: A single clear signal emerging from minimal noise Right: Increasing noise drowning out the signal as more "research" is added Shows how more information can make truth harder to find, not easier

This sketch accompanies the blog post "The Research Performance" and visualizes its core concepts through generative art.

Algorithm

Visualizing information overload vs. clarity Left: A single clear signal emerging from minimal noise Right: Increasing noise drowning out the signal as more "research" is added Shows how more information can make truth harder to find, not easier This sketch was originally created as a visual companion to the blog post "The Research Performance" and explores its themes through generative art.

Pseudocode

SETUP:
  Initialize canvas (400x300)
  Set up drawing parameters

DRAW (every frame):
  Get current theme colors
  Clear background
  Draw generative visualization
  Update animation state

Source Code

let sketch = function(p) {

    // Visualizing information overload vs. clarity
    // Left: A single clear signal emerging from minimal noise
    // Right: Increasing noise drowning out the signal as more "research" is added
    // Shows how more information can make truth harder to find, not easier

    let time = 0;
    let leftSignal = [];
    let leftNoise = [];
    let rightSignal = [];
    let rightNoise = [];

    class Signal {
        constructor(x, y, amplitude, frequency, color) {
            this.x = x;
            this.y = y;
            this.amplitude = amplitude;
            this.frequency = frequency;
            this.color = color;
            this.points = [];

            // Generate signal wave points
            for (let i = 0; i < 100; i++) {
                let angle = (i / 100) * p.TWO_PI * 2;
                let yOffset = p.sin(angle * this.frequency) * this.amplitude;
                this.points.push({x: i * 1.5, y: yOffset});
            }
        }

        display(colors, alpha) {
            p.noFill();
            p.stroke(...colors[this.color], alpha);
            p.strokeWeight(2);
            p.beginShape();
            for (let point of this.points) {
                let x = this.x + point.x;
                let y = this.y + point.y + p.sin(time * 0.02 + point.x * 0.05) * 3;
                p.vertex(x, y);
            }
            p.endShape();
        }
    }

    class Noise {
        constructor(x, y, width, height, density, intensity) {
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
            this.density = density;
            this.intensity = intensity;
            this.particles = [];

            // Generate noise particles
            for (let i = 0; i < density; i++) {
                this.particles.push({
                    x: p.random(width),
                    y: p.random(height),
                    vx: p.random(-0.5, 0.5),
                    vy: p.random(-0.5, 0.5),
                    size: p.random(1, 3),
                    alpha: p.random(50, 150)
                });
            }
        }

        update() {
            for (let particle of this.particles) {
                particle.x += particle.vx;
                particle.y += particle.vy;

                // Wrap around
                if (particle.x < 0) particle.x = this.width;
                if (particle.x > this.width) particle.x = 0;
                if (particle.y < 0) particle.y = this.height;
                if (particle.y > this.height) particle.y = 0;
            }
        }

        display(colors) {
            p.noStroke();
            for (let particle of this.particles) {
                p.fill(...colors.accent3, particle.alpha * this.intensity);
                p.circle(this.x + particle.x, this.y + particle.y, particle.size);
            }
        }
    }

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

        // Left side: Clear signal with minimal noise
        leftSignal.push(new Signal(20, 120, 25, 2, 'accent1'));
        leftNoise.push(new Noise(20, 70, 150, 100, 30, 0.3));

        // Right side: Same signal but with overwhelming noise
        rightSignal.push(new Signal(220, 120, 25, 2, 'accent1'));
        rightNoise.push(new Noise(220, 70, 150, 100, 150, 0.8));
    };

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

        // Dividing line
        p.stroke(...colors.accent3, 60);
        p.strokeWeight(1);
        p.line(200, 0, 200, 300);

        // Labels
        p.noStroke();
        p.fill(...colors.accent3, 200);
        p.textAlign(p.CENTER, p.TOP);
        p.textSize(11);
        p.text("Selective Reading", 95, 15);
        p.text("Extensive Research", 295, 15);

        // Descriptions
        p.textSize(8);
        p.fill(...colors.accent3, 150);
        p.text("2-3 good sources", 95, 32);
        p.text("Clear signal", 95, 43);
        p.text("20+ sources", 295, 32);
        p.text("Overwhelmed", 295, 43);

        // Left side: Clear signal with minimal noise
        leftNoise[0].update();
        leftNoise[0].display(colors);
        leftSignal[0].display(colors, 220);

        // Arrow pointing to signal
        if (time > 60 && time < 180) {
            let alpha = p.map(p.sin(time * 0.05), -1, 1, 100, 200);
            p.fill(...colors.accent1, alpha);
            p.noStroke();
            p.textSize(8);
            p.textAlign(p.CENTER);
            p.text("Signal", 95, 180);

            // Arrow
            p.stroke(...colors.accent1, alpha);
            p.strokeWeight(1);
            p.line(95, 175, 95, 145);
            p.noStroke();
            p.fill(...colors.accent1, alpha);
            p.triangle(95, 145, 92, 150, 98, 150);
        }

        // Right side: Same signal buried in noise
        rightNoise[0].update();
        rightNoise[0].display(colors);
        rightSignal[0].display(colors, 100); // Lower alpha - harder to see

        // Question mark over confused viewer
        if (time > 100) {
            let alpha = p.min((time - 100) * 3, 180);
            p.fill(...colors.accent2, alpha);
            p.noStroke();
            p.textSize(24);
            p.textAlign(p.CENTER);
            p.text("?", 295, 175);

            p.textSize(7);
            p.fill(...colors.accent3, alpha);
            p.text("Signal lost in noise", 295, 205);
        }

        // Information counters
        if (time > 30) {
            let leftAlpha = p.min((time - 30) * 5, 160);
            p.textAlign(p.CENTER, p.BOTTOM);
            p.textSize(9);
            p.noStroke();
            p.fill(...colors.accent1, leftAlpha);
            p.text("High clarity", 95, 240);
            p.fill(...colors.accent3, leftAlpha);
            p.textSize(7);
            p.text("Can see truth", 95, 252);
        }

        if (time > 120) {
            let rightAlpha = p.min((time - 120) * 5, 160);
            p.textAlign(p.CENTER, p.BOTTOM);
            p.textSize(9);
            p.noStroke();
            p.fill(...colors.accent2, rightAlpha);
            p.text("Low clarity", 295, 240);
            p.fill(...colors.accent3, rightAlpha);
            p.textSize(7);
            p.text("Confused by contradictions", 295, 252);
        }

        // Bottom message
        if (time > 180) {
            p.textAlign(p.CENTER, p.BOTTOM);
            p.textSize(9);
            let msgAlpha = p.min((time - 180) * 2, 140);
            p.fill(...colors.accent3, msgAlpha);
            p.text("More information ≠ Better understanding", 200, 280);

            p.textSize(8);
            p.fill(...colors.accent2, msgAlpha);
            p.text("Past a threshold, additional research creates confusion, not clarity", 200, 295);
        }

        // Animated "tabs" accumulating on right side
        if (time > 60 && time < 300) {
            let numTabs = Math.floor((time - 60) / 10);
            numTabs = Math.min(numTabs, 24);

            for (let i = 0; i < numTabs; i++) {
                let row = Math.floor(i / 8);
                let col = i % 8;
                let tabX = 230 + col * 18;
                let tabY = 15 + row * 6;

                p.noStroke();
                p.fill(...colors.accent2, 100);
                p.rect(tabX, tabY, 15, 4, 1);
            }

            // Tab counter
            if (numTabs > 0) {
                p.textAlign(p.LEFT, p.TOP);
                p.textSize(7);
                p.fill(...colors.accent2, 140);
                p.text(`${numTabs} tabs`, 230, 35);
            }
        }

        time++;

        // Loop
        if (time > 400) {
            time = 0;
        }
    };
};