Where ideas percolate and thoughts brew

The Legibility Game

About This Sketch

A competitive simulation showing two work styles: quality (complex, organic, hard to perceive) versus legibility (clean, geometric, easy to evaluate). Rewards fall and agents compete to capture them, but the legible agent has a larger "capture radius" because its work is more visible. Watch how legibility systematically wins despite quality doing equally valuable work. This sketch explores how institutions optimize for appearances over substance.

Algorithm

This sketch visualizes the disconnect between actual value (quality work) and perceived value (legible work) in professional environments. Two agents produce different types of work while competing for falling rewards. The Quality Agent (left, circular) produces complex, organic work represented by scattered particles. This work is valuable but harder to perceive—the agent has a smaller "capture radius" for rewards. The Legibility Agent (right, square) produces clean, geometric work represented by polished rectangles. This work is more visible—the agent has a larger capture radius, capturing more rewards despite not necessarily doing better work. Rewards fall from the top periodically. The visualization demonstrates how legibility (ease of evaluation) often matters more than quality (actual value) in determining success. The Legibility Agent consistently captures more rewards because its work is more visible, not because it's better. This accompanies the blog post "The Legibility Game" which explores how institutions systematically reward appearances over substance.

Pseudocode

SETUP:
  Initialize canvas (400x300)
  Create Quality Agent (left side, circular, organic work style)
  Create Legibility Agent (right side, square, geometric work style)
  Initialize reward tracking systems

DRAW (every frame):
  Get current theme colors
  Clear background

  // Spawn rewards periodically
  IF frame is multiple of 60:
    Create new reward at random X position, top of screen

  // Update all rewards
  FOR each reward:
    IF not captured:
      Move reward downward
      Check if Legibility Agent can capture (large radius)
      ELSE check if Quality Agent can capture (small radius)
      IF captured:
        Increment respective score
    Display reward if still visible
    Remove if off-screen

  // Agents produce work artifacts
  FOR each agent (every 30 frames):
    IF Quality Agent:
      Generate multiple small, scattered organic particles
    IF Legibility Agent:
      Generate single large, centered geometric shape

  // Display agents and their work
  Draw agents with appropriate styling
  Update and fade work particles over time
  Display current scores
  Show labels and explanatory text

Source Code

let sketch = function(p) {
    // Visualization: Legibility vs. Quality
    // Two agents competing for rewards
    // Left: "Quality Agent" - does complex, deep work (messy, organic shapes)
    // Right: "Legibility Agent" - produces clean, impressive-looking output (geometric, polished)
    // Top: "Reward" tokens that fall down
    // The Legibility Agent captures most rewards despite Quality Agent doing better work
    // Shows the disconnect between actual value and perceived value

    let qualityAgent, legibilityAgent;
    let rewards = [];
    let qualityScore = 0;
    let legibilityScore = 0;
    let frame = 0;

    class Agent {
        constructor(x, type) {
            this.x = x;
            this.y = 220;
            this.type = type; // 'quality' or 'legibility'
            this.workParticles = [];
            this.capturedRewards = 0;
        }

        doWork() {
            // Generate work artifacts
            if (frame % 30 === 0) {
                if (this.type === 'quality') {
                    // Complex, organic work - harder to see value
                    for (let i = 0; i < 3; i++) {
                        this.workParticles.push({
                            x: this.x + p.random(-15, 15),
                            y: this.y + p.random(-15, 15),
                            size: p.random(3, 8),
                            alpha: 255,
                            age: 0
                        });
                    }
                } else {
                    // Clean, geometric work - easy to see
                    this.workParticles.push({
                        x: this.x,
                        y: this.y - 20,
                        size: 12,
                        alpha: 255,
                        age: 0,
                        shape: 'square'
                    });
                }
            }
        }

        display(colors) {
            // Display agent
            p.noStroke();

            if (this.type === 'quality') {
                // Quality agent - organic, complex representation
                p.fill(...colors.accent1, 180);
                p.circle(this.x, this.y, 20);

                // Show work particles (messy, organic)
                for (let i = this.workParticles.length - 1; i >= 0; i--) {
                    let particle = this.workParticles[i];
                    particle.alpha -= 3;
                    particle.age++;

                    if (particle.alpha <= 0 || particle.age > 100) {
                        this.workParticles.splice(i, 1);
                    } else {
                        p.fill(...colors.accent1, particle.alpha);
                        p.circle(particle.x, particle.y, particle.size);
                    }
                }
            } else {
                // Legibility agent - clean, geometric representation
                p.fill(...colors.accent2, 180);
                p.rectMode(p.CENTER);
                p.rect(this.x, this.y, 20, 20, 2);

                // Show work artifacts (clean, geometric)
                for (let i = this.workParticles.length - 1; i >= 0; i--) {
                    let particle = this.workParticles[i];
                    particle.alpha -= 3;
                    particle.age++;

                    if (particle.alpha <= 0 || particle.age > 100) {
                        this.workParticles.splice(i, 1);
                    } else {
                        p.fill(...colors.accent2, particle.alpha);
                        p.rectMode(p.CENTER);
                        p.rect(particle.x, particle.y, particle.size, particle.size, 2);
                    }
                }
            }
        }

        canCaptureReward(reward) {
            let distance = p.dist(this.x, this.y, reward.x, reward.y);

            if (this.type === 'legibility') {
                // Legibility agent has wider capture radius (more visible)
                return distance < 60;
            } else {
                // Quality agent has smaller capture radius (less visible)
                return distance < 30;
            }
        }

        captureReward() {
            this.capturedRewards++;
        }
    }

    class Reward {
        constructor() {
            this.x = p.random(60, 340);
            this.y = 20;
            this.speed = 1.5;
            this.captured = false;
            this.size = 8;
        }

        update() {
            if (!this.captured) {
                this.y += this.speed;
            }
        }

        display(colors) {
            if (!this.captured && this.y < 250) {
                p.noStroke();
                p.fill(...colors.accent3, 200);
                p.circle(this.x, this.y, this.size);
            }
        }

        isOffScreen() {
            return this.y > 260;
        }
    }

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

        // Create two agents
        qualityAgent = new Agent(120, 'quality');
        legibilityAgent = new Agent(280, 'legibility');
    };

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

        frame++;

        // Title
        p.fill(...colors.accent3, 200);
        p.noStroke();
        p.textAlign(p.CENTER);
        p.textSize(11);
        p.text('The Legibility Game', 200, 20);

        // Spawn rewards periodically
        if (frame % 60 === 0) {
            rewards.push(new Reward());
        }

        // Update and display rewards
        for (let i = rewards.length - 1; i >= 0; i--) {
            let reward = rewards[i];
            reward.update();

            // Check if either agent can capture this reward
            if (!reward.captured) {
                // Legibility agent checks first (gets priority - bias of the system)
                if (legibilityAgent.canCaptureReward(reward)) {
                    reward.captured = true;
                    legibilityAgent.captureReward();
                    legibilityScore++;
                } else if (qualityAgent.canCaptureReward(reward)) {
                    reward.captured = true;
                    qualityAgent.captureReward();
                    qualityScore++;
                }
            }

            reward.display(colors);

            // Remove off-screen rewards
            if (reward.isOffScreen()) {
                rewards.splice(i, 1);
            }
        }

        // Agents do work
        qualityAgent.doWork();
        legibilityAgent.doWork();

        // Display agents
        qualityAgent.display(colors);
        legibilityAgent.display(colors);

        // Labels
        p.fill(...colors.accent3, 180);
        p.textSize(9);
        p.textAlign(p.CENTER);
        p.text('Quality', qualityAgent.x, 255);
        p.text('(deep work)', qualityAgent.x, 265);

        p.text('Legibility', legibilityAgent.x, 255);
        p.text('(visible work)', legibilityAgent.x, 265);

        // Scores
        p.textSize(10);
        p.fill(...colors.accent1, 200);
        p.text(`Rewards: ${qualityScore}`, qualityAgent.x, 280);

        p.fill(...colors.accent2, 200);
        p.text(`Rewards: ${legibilityScore}`, legibilityAgent.x, 280);

        // Top label
        p.fill(...colors.accent3, 150);
        p.textSize(8);
        p.textAlign(p.CENTER);
        p.text('Rewards fall → Legible work captures more despite Quality doing better work', 200, 42);

        // Insight at bottom (rotating)
        p.textSize(7);
        p.fill(...colors.accent3, 180);
        if (frame % 300 < 150) {
            p.text('The person who looks competent beats the person who is competent.', 200, 295);
        } else {
            p.text('Visibility matters more than value. The legibility game is the real game.', 200, 295);
        }
    };
};