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