Where ideas percolate and thoughts brew

The Permission Fallacy

About This Sketch

Visualizing the permission barrier A figure stands before imaginary gates that fade away when approached Represents how the gatekeepers are internalized, not external

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

Algorithm

Visualizing the permission barrier A figure stands before imaginary gates that fade away when approached Represents how the gatekeepers are internalized, not external This sketch was originally created as a visual companion to the blog post "The Permission Fallacy" 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 the permission barrier
    // A figure stands before imaginary gates that fade away when approached
    // Represents how the gatekeepers are internalized, not external

    let time = 0;
    let figure = {
        x: 80,
        y: 220,
        targetX: 80
    };

    let gates = [];
    let numGates = 5;

    class Gate {
        constructor(x, label) {
            this.x = x;
            this.baseX = x;
            this.label = label;
            this.opacity = 255;
            this.height = 120;
            this.fadeStart = false;
        }

        update(figureX) {
            // Gate starts fading when figure gets close
            let distance = Math.abs(this.x - figureX);
            if (distance < 60) {
                this.fadeStart = true;
            }

            if (this.fadeStart) {
                this.opacity -= 3;
                if (this.opacity < 0) this.opacity = 0;
            }
        }

        display(colors) {
            if (this.opacity <= 0) return;

            // Draw gate posts
            p.stroke(...colors.accent2, this.opacity);
            p.strokeWeight(3);
            p.line(this.x - 15, 220, this.x - 15, 220 - this.height);
            p.line(this.x + 15, 220, this.x + 15, 220 - this.height);

            // Draw gate top
            p.strokeWeight(2);
            p.line(this.x - 15, 220 - this.height, this.x + 15, 220 - this.height);

            // Draw lock symbol
            p.noStroke();
            p.fill(...colors.accent2, this.opacity);
            p.rect(this.x - 8, 160, 16, 18, 2);
            p.arc(this.x, 160, 12, 12, p.PI, p.TWO_PI);

            // Label
            p.textAlign(p.CENTER, p.BOTTOM);
            p.textSize(7);
            p.fill(...colors.accent3, this.opacity);
            p.text(this.label, this.x, 140);
        }
    }

    class Figure {
        constructor(x, y) {
            this.x = x;
            this.y = y;
            this.targetX = x;
        }

        update() {
            // Move towards target
            let diff = this.targetX - this.x;
            this.x += diff * 0.02;
        }

        display(colors) {
            // Simple stick figure
            p.noFill();
            p.stroke(...colors.accent1);
            p.strokeWeight(2);

            // Head
            p.circle(this.x, this.y - 35, 12);

            // Body
            p.line(this.x, this.y - 29, this.x, this.y - 10);

            // Arms
            let armAngle = p.sin(time * 0.05) * 0.2;
            p.line(this.x, this.y - 22, this.x - 10, this.y - 12 + armAngle * 10);
            p.line(this.x, this.y - 22, this.x + 10, this.y - 12 - armAngle * 10);

            // Legs
            let legAngle = p.sin(time * 0.05 + p.PI) * 0.3;
            p.line(this.x, this.y - 10, this.x - 6, this.y + legAngle * 5);
            p.line(this.x, this.y - 10, this.x + 6, this.y - legAngle * 5);
        }
    }

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

        // Initialize gates at regular intervals
        gates.push(new Gate(140, "Credentials"));
        gates.push(new Gate(200, "Approval"));
        gates.push(new Gate(260, "Readiness"));
        gates.push(new Gate(320, "Permission"));
    };

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

        // Ground line
        p.stroke(...colors.accent3, 100);
        p.strokeWeight(1);
        p.line(0, 220, 400, 220);

        // Title area
        p.noStroke();
        p.fill(...colors.accent3, 180);
        p.textAlign(p.CENTER, p.TOP);
        p.textSize(11);
        p.text("The Internalized Gates", 200, 15);

        // Instruction text that changes over time
        if (time < 180) {
            p.textSize(8);
            p.fill(...colors.accent3, 150);
            p.text("Waiting for permission to move forward...", 200, 32);
        } else if (time < 360) {
            p.textSize(8);
            let alpha = p.map(p.sin((time - 180) * 0.05), -1, 1, 100, 200);
            p.fill(...colors.accent1, alpha);
            p.text("But the gates were never real", 200, 32);
        } else {
            p.textSize(8);
            p.fill(...colors.accent1, 180);
            p.text("You just needed to start", 200, 32);
        }

        // Start movement after pause
        if (time === 120) {
            figure.targetX = 360;
        }

        // Update figure position
        figure.update();

        // Update and display gates
        for (let gate of gates) {
            gate.update(figure.x);
            gate.display(colors);
        }

        // Display figure
        figure.display(colors);

        // Path line showing progress
        if (figure.x > 85) {
            p.stroke(...colors.accent1, 100);
            p.strokeWeight(1);
            p.line(80, 223, figure.x, 223);

            // Footprints
            for (let i = 80; i < figure.x; i += 20) {
                p.noStroke();
                p.fill(...colors.accent1, 60);
                p.ellipse(i, 223, 4, 6);
            }
        }

        // Message at bottom showing insight
        if (time > 240 && time < 480) {
            let msgAlpha = Math.min((time - 240) * 2, 150);
            p.textAlign(p.CENTER, p.BOTTOM);
            p.textSize(9);
            p.fill(...colors.accent3, msgAlpha);
            p.text("The gates dissolve when approached", 200, 265);

            p.textSize(8);
            p.fill(...colors.accent2, msgAlpha);
            p.text("They were internalized barriers, not external ones", 200, 280);
        }

        // Final message
        if (time > 480) {
            let finalAlpha = Math.min((time - 480) * 2, 160);
            p.textAlign(p.CENTER, p.BOTTOM);
            p.textSize(10);
            p.fill(...colors.accent1, finalAlpha);
            p.text("You had permission all along", 200, 265);

            p.textSize(7);
            p.fill(...colors.accent3, finalAlpha);
            p.text("The only permission that mattered was your own", 200, 280);
        }

        time++;

        // Loop the animation
        if (time > 600) {
            time = 0;
            figure.x = 80;
            figure.targetX = 80;
            gates = [];
            gates.push(new Gate(140, "Credentials"));
            gates.push(new Gate(200, "Approval"));
            gates.push(new Gate(260, "Readiness"));
            gates.push(new Gate(320, "Permission"));
        }
    };
};