Where ideas percolate and thoughts brew

The Originality Trap

About This Sketch

A visualization of the originality paradox: agents actively fleeing convention and each other (trying to be original) end up clustering in a ring of sameness, while agents drifting naturally without concern for originality achieve genuine distinctiveness. The sketch demonstrates how the performance of uniqueness creates a new conformity, while authentic exploration naturally finds unoccupied space.

Bright agents represent authentic creators following genuine curiosity—they glow because their distinctiveness is real. Dim agents represent those performing originality—they're numerous, busy, and all "different" in identical ways. Watch how the performers form a predictable ring around convention, while authentic agents scatter unpredictably across the space.

Algorithm

This sketch visualizes the paradox of pursuing originality through particle simulation with two behavioral patterns. **Performing Originality (70% of agents):** These agents actively flee from the center (convention) and from each other, trying to be different. However, their identical strategy of "being different" causes them to cluster in a ring around the conventional center - all "original" in exactly the same way. They move faster, work harder, but end up creating a new conformity. **Authentic Exploration (30% of agents):** These agents drift slowly with no goal of being different. They follow gentle random walks and naturally avoid crowded areas. Without trying to be original, they end up scattered in truly distinctive positions. They're brighter and more visible because their distinctiveness is real, not performed. The irony: Those trying hardest to be original (performing agents) cluster together in predictable patterns. Those just following curiosity (authentic agents) achieve genuine distinctiveness as a side effect.

Pseudocode

SETUP:
  Create canvas 400x300
  Create 80 agents:
    70% performing type (flee convention/others)
    30% authentic type (drift naturally)
  Place randomly on canvas

DRAW (every frame):
  Clear background with theme colors
  Draw center marker (convention)
  Draw ring at radius 100 (where performers cluster)

  FOR EACH agent:
    IF performing type:
      Calculate flee force from center
      Calculate flee force from nearby performing agents
      Apply pull toward ring radius (unconscious conformity)
      Apply rotation around center (performing in a circle)
      Move faster, work harder

    ELSE IF authentic type:
      Apply gentle random drift
      If area is crowded, softly move toward space
      Move slowly, naturally

    Apply velocity with damping
    Enforce canvas boundaries

    Display agent:
      Authentic = bright with glow (distinctive)
      Performing = dim uniform appearance (sameness)

  Show labels and legend

Source Code

let sketch = function(p) {
    let agents = [];
    let centerX = 200;
    let centerY = 150;
    let numAgents = 80;

    class Agent {
        constructor(x, y, type) {
            this.x = x;
            this.y = y;
            this.type = type; // 'authentic' or 'performing'
            this.vx = 0;
            this.vy = 0;
            this.targetAngle = p.random(p.TWO_PI);
            this.speed = type === 'authentic' ? p.random(0.3, 0.8) : p.random(1, 2);
            this.size = type === 'authentic' ? p.random(4, 8) : p.random(3, 5);
            this.originalityAngle = p.random(p.TWO_PI);
            this.rotationSpeed = p.random(0.01, 0.03);
        }

        update() {
            if (this.type === 'performing') {
                // Performing agents actively flee from center and each other
                // They're "trying to be original" = avoiding similarity

                // Flee from center
                let dx = this.x - centerX;
                let dy = this.y - centerY;
                let distFromCenter = p.sqrt(dx * dx + dy * dy);

                if (distFromCenter > 0) {
                    this.vx += (dx / distFromCenter) * 0.5;
                    this.vy += (dy / distFromCenter) * 0.5;
                }

                // Flee from nearby performing agents (everyone trying to be different)
                for (let other of agents) {
                    if (other !== this && other.type === 'performing') {
                        let odx = this.x - other.x;
                        let ody = this.y - other.y;
                        let dist = p.sqrt(odx * odx + ody * ody);

                        if (dist < 30 && dist > 0) {
                            this.vx += (odx / dist) * 0.3;
                            this.vy += (ody / dist) * 0.3;
                        }
                    }
                }

                // But they end up in a ring - all "different" in the same way
                let distFromIdealRing = Math.abs(distFromCenter - 100);
                if (distFromCenter > 0) {
                    let pullX = (centerX - this.x) / distFromCenter;
                    let pullY = (centerY - this.y) / distFromCenter;
                    this.vx += pullX * distFromIdealRing * 0.01;
                    this.vy += pullY * distFromIdealRing * 0.01;
                }

                // Rotate around center (they're all performing in a circle)
                this.originalityAngle += this.rotationSpeed;
                let tangentX = -Math.sin(this.originalityAngle) * 0.2;
                let tangentY = Math.cos(this.originalityAngle) * 0.2;
                this.vx += tangentX;
                this.vy += tangentY;

            } else {
                // Authentic agents just drift slowly, following genuine interest
                // They're not trying to be original, just exploring
                this.vx += p.random(-0.1, 0.1);
                this.vy += p.random(-0.1, 0.1);

                // Very gentle pull toward areas with fewer agents (naturally finding gaps)
                let nearbyCount = 0;
                let avgX = 0;
                let avgY = 0;

                for (let other of agents) {
                    let dx = other.x - this.x;
                    let dy = other.y - this.y;
                    let dist = p.sqrt(dx * dx + dy * dy);
                    if (dist < 50 && dist > 0) {
                        nearbyCount++;
                        avgX += other.x;
                        avgY += other.y;
                    }
                }

                if (nearbyCount > 5) {
                    avgX /= nearbyCount;
                    avgY /= nearbyCount;
                    let fleeX = this.x - avgX;
                    let fleeY = this.y - avgY;
                    this.vx += fleeX * 0.01;
                    this.vy += fleeY * 0.01;
                }
            }

            // Apply velocity
            this.vx *= 0.92; // Damping
            this.vy *= 0.92;
            this.x += this.vx;
            this.y += this.vy;

            // Boundary constraints
            let margin = 20;
            if (this.x < margin) this.vx += 0.5;
            if (this.x > 400 - margin) this.vx -= 0.5;
            if (this.y < margin) this.vy += 0.5;
            if (this.y > 300 - margin) this.vy -= 0.5;
        }

        display(colors) {
            p.noStroke();
            if (this.type === 'authentic') {
                // Authentic agents are brighter, more distinctive
                p.fill(...colors.accent1, 220);
                p.circle(this.x, this.y, this.size);
                // Subtle glow
                p.fill(...colors.accent1, 60);
                p.circle(this.x, this.y, this.size * 1.8);
            } else {
                // Performing agents are dimmer, all looking the same
                p.fill(...colors.accent3, 140);
                p.circle(this.x, this.y, this.size);
            }
        }
    }

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

        // Create agents - more performing than authentic (reflects reality)
        for (let i = 0; i < numAgents; i++) {
            let x = p.random(50, 350);
            let y = p.random(50, 250);
            // 70% performing originality, 30% authentic
            let type = p.random() < 0.7 ? 'performing' : 'authentic';
            agents.push(new Agent(x, y, type));
        }
    };

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

        // Draw center point (representing "conventional")
        p.noFill();
        p.stroke(...colors.accent2, 80);
        p.strokeWeight(1);
        p.circle(centerX, centerY, 20);
        p.circle(centerX, centerY, 200); // The ring where performers cluster

        // Update and display agents
        for (let agent of agents) {
            agent.update();
            agent.display(colors);
        }

        // Labels
        p.noStroke();
        p.fill(...colors.accent3);
        p.textAlign(p.CENTER);
        p.textSize(11);
        p.text('The Originality Trap', 200, 15);

        p.textSize(7);
        p.textAlign(p.CENTER);
        p.fill(...colors.accent2, 150);
        p.text('CONVENTIONAL', centerX, centerY + 3);

        // Legend
        p.textAlign(p.LEFT);
        p.textSize(8);

        p.fill(...colors.accent1);
        p.circle(15, 280, 6);
        p.fill(...colors.accent3);
        p.text('Authentic - drift naturally, end up distinctive', 25, 283);

        p.fill(...colors.accent3, 140);
        p.circle(15, 292, 4);
        p.fill(...colors.accent3);
        p.text('Performing - flee convention, cluster in sameness', 25, 295);

        // Count stats
        let authentic = agents.filter(a => a.type === 'authentic').length;
        let performing = agents.filter(a => a.type === 'performing').length;
    };
};