The Feedback Paradox
About This Sketch
Watch as a center point gets pulled in contradictory directions by multiple voices, each representing a piece of feedback. Early feedback provides clear direction—just a few voices create coherent movement. But as more voices appear, each with their own agenda, the center becomes chaotic and confused. The clarity metric drops as voice count rises. This is the feedback paradox: the more input you collect, the less you know what to do. You're not synthesizing wisdom—you're drowning in contradictions.
Algorithm
The Feedback Paradox visualizes how collecting more feedback creates confusion rather than clarity. A central point (representing you) is pulled in multiple directions by "voices"—each representing a piece of feedback from a different person.
Initially, with just a few voices, the center point moves in relatively clear directions. But as more voices spawn over time, each pulling toward their own preferred position, the central point becomes increasingly chaotic. The pulls contradict each other: one voice wants you to move left while another wants you to move right. The result isn't averaged wisdom—it's paralysis and jittery confusion.
The "Clarity" metric decreases as more voices are added, demonstrating the core thesis: past the saturation point, more feedback makes you less certain about what to do, not more. The voices fade over time (representing how feedback becomes outdated), but new ones keep appearing faster than old ones disappear, maintaining the chaos.
This sketch accompanies the blog post "The Feedback Paradox" which argues that organizations' push for constant feedback creates confusion rather than improvement.
Pseudocode
SETUP:
Initialize canvas (400x300)
Create center point at canvas center
Initialize empty array for feedback voices
VOICE CLASS:
Properties: target position, pull strength, oscillation phase
Each voice wants you to move toward a specific location
Generate random "opinion" from contradictory set:
("Be more assertive", "Listen more", "Delegate", "Be hands-on", etc.)
DRAW (every frame):
Get current theme colors
Clear background
Spawn new voices periodically (rate increases over time)
Maximum 25 voices active at once
For each voice:
Calculate pull force toward its target position
Add oscillation (opinions shift over time)
Display as anchor point with connecting line
Age the voice, remove when expired
Sum all pull forces from all voices
Apply to center point velocity
Update center point position with dampening
Display center point with jitter (proportional to voice count)
Show statistics: active voice count, clarity level
Display state message:
Few voices: "Early feedback provides clear direction"
Many voices: "Paralyzed by conflicting advice"
RESULT:
As more voices accumulate, center point becomes more chaotic
Demonstrates: more feedback ≠ more clarity
Source Code
let sketch = function(p) {
// Visualization: The Feedback Paradox
// Multiple "voices" pull a center point in contradictory directions
// As more voices appear, the center becomes more chaotic, not more stable
// Represents how more feedback creates confusion rather than clarity
let voices = [];
let centerPoint = {x: 200, y: 150};
let actualPosition = {x: 200, y: 150};
let velocity = {x: 0, y: 0};
let time = 0;
let voiceSpawnTimer = 0;
class Voice {
constructor() {
// Each voice has a preferred position they want you to move toward
this.targetX = p.random(80, 320);
this.targetY = p.random(80, 220);
this.strength = p.random(0.3, 0.8);
this.phase = p.random(0, p.TWO_PI);
this.frequency = p.random(0.01, 0.03);
this.opinion = this.generateOpinion();
this.color = [p.random(100, 255), p.random(100, 200), p.random(50, 150)];
this.age = 0;
this.maxAge = p.random(200, 400);
}
generateOpinion() {
const opinions = [
"Be more assertive", "Listen more", "Delegate more",
"Be more hands-on", "Think strategically", "Focus on details",
"Speak up more", "Be more concise", "Show more empathy",
"Be more direct", "Build relationships", "Drive results"
];
return p.random(opinions);
}
update() {
this.age++;
this.phase += this.frequency;
}
getPull() {
// Each voice pulls you toward their preferred position
let pullX = (this.targetX - actualPosition.x) * this.strength * 0.01;
let pullY = (this.targetY - actualPosition.y) * this.strength * 0.01;
// Add oscillation to represent changing opinions
let oscillation = p.sin(this.phase) * 0.5;
pullX *= (1 + oscillation);
pullY *= (1 + oscillation);
return {x: pullX, y: pullY};
}
display(colors) {
// Draw the voice as a point with a line pulling toward it
let alpha = p.map(this.age, 0, this.maxAge, 255, 50);
// Connection line showing the pull
p.stroke(...colors.accent2, alpha * 0.3);
p.strokeWeight(1);
p.line(actualPosition.x, actualPosition.y, this.targetX, this.targetY);
// The voice's anchor point
p.noStroke();
p.fill(...colors.accent1, alpha * 0.6);
p.circle(this.targetX, this.targetY, 6);
// Pulsing to show active pulling
let pulse = p.sin(this.phase) * 2 + 4;
p.fill(...colors.accent2, alpha * 0.3);
p.circle(this.targetX, this.targetY, pulse);
}
isExpired() {
return this.age > this.maxAge;
}
}
p.setup = function() {
p.createCanvas(400, 300);
};
p.draw = function() {
const colors = getThemeColors();
p.background(...colors.bg);
time++;
voiceSpawnTimer++;
// Title
p.fill(...colors.accent3, 220);
p.noStroke();
p.textAlign(p.LEFT, p.TOP);
p.textSize(12);
p.textFont('Georgia');
p.text('The Feedback Paradox', 15, 15);
// Add new voices periodically - accelerating over time
let spawnRate = p.max(30 - Math.floor(time / 100), 10);
if (voiceSpawnTimer > spawnRate && voices.length < 25) {
voices.push(new Voice());
voiceSpawnTimer = 0;
}
// Calculate total pull from all voices
let totalPull = {x: 0, y: 0};
for (let voice of voices) {
let pull = voice.getPull();
totalPull.x += pull.x;
totalPull.y += pull.y;
}
// Apply pulls with dampening (more voices = more chaos)
velocity.x += totalPull.x;
velocity.y += totalPull.y;
// Dampening to prevent explosion
velocity.x *= 0.95;
velocity.y *= 0.95;
// Update position
actualPosition.x += velocity.x;
actualPosition.y += velocity.y;
// Keep in bounds with soft boundary
if (actualPosition.x < 50) {
actualPosition.x = 50;
velocity.x *= -0.5;
}
if (actualPosition.x > 350) {
actualPosition.x = 350;
velocity.x *= -0.5;
}
if (actualPosition.y < 50) {
actualPosition.y = 50;
velocity.y *= -0.5;
}
if (actualPosition.y > 250) {
actualPosition.y = 250;
velocity.y *= -0.5;
}
// Update and display voices
for (let i = voices.length - 1; i >= 0; i--) {
voices[i].update();
voices[i].display(colors);
if (voices[i].isExpired()) {
voices.splice(i, 1);
}
}
// Draw the center point (you) being pulled around
// Trail showing recent path (confusion)
p.noFill();
p.stroke(...colors.accent3, 100);
p.strokeWeight(2);
// Central point - gets more chaotic with more voices
let jitter = voices.length * 0.3;
let jitterX = p.random(-jitter, jitter);
let jitterY = p.random(-jitter, jitter);
p.fill(...colors.accent2, 200);
p.noStroke();
p.circle(actualPosition.x + jitterX, actualPosition.y + jitterY, 10);
// Inner core
p.fill(...colors.bg, 150);
p.circle(actualPosition.x, actualPosition.y, 5);
// Show chaos level
p.textAlign(p.LEFT);
p.textSize(10);
p.fill(...colors.accent3, 200);
p.text(`Active voices: ${voices.length}`, 15, 265);
// Calculate movement chaos (speed indicates confusion)
let chaos = p.sqrt(velocity.x * velocity.x + velocity.y * velocity.y);
let chaosLevel = p.constrain(p.floor(chaos * 3), 0, 10);
p.text(`Clarity: ${p.max(0, 10 - chaosLevel)}/10`, 15, 280);
// Message based on state
p.textAlign(p.CENTER);
p.textSize(9);
if (voices.length < 3) {
p.fill(...colors.accent1, 180);
p.text('Early feedback provides clear direction', 200, 40);
} else if (voices.length < 8) {
p.fill(...colors.accent2, 180);
p.text('More feedback, more contradictions', 200, 40);
} else {
p.fill(...colors.accent2, 220);
p.text('Paralyzed by conflicting advice', 200, 40);
}
// Easter egg: occasionally show specific contradictory feedback
if (time % 180 === 0 && voices.length > 5) {
// This creates a brief visible contradiction
}
};
};