Where ideas percolate and thoughts brew

The Vulnerability Fetish

About This Sketch

Visualizing genuine vs performative vulnerability Left: Genuine vulnerability - small, mutual exchanges between two people, building gradually Right: Performative vulnerability - one person broadcasting intensely to many, creating obligation

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

Algorithm

Visualizing genuine vs performative vulnerability Left: Genuine vulnerability - small, mutual exchanges between two people, building gradually Right: Performative vulnerability - one person broadcasting intensely to many, creating obligation This sketch was originally created as a visual companion to the blog post "The Vulnerability Fetish" 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 genuine vs performative vulnerability
    // Left: Genuine vulnerability - small, mutual exchanges between two people, building gradually
    // Right: Performative vulnerability - one person broadcasting intensely to many, creating obligation

    let time = 0;
    let genuineParticles = [];
    let performativeWaves = [];

    class VulnerabilityParticle {
        constructor(x1, y1, x2, y2, delay) {
            this.x1 = x1;
            this.y1 = y1;
            this.x2 = x2;
            this.y2 = y2;
            this.x = x1;
            this.y = y1;
            this.delay = delay;
            this.progress = 0;
            this.alpha = 0;
            this.isReturn = false;
        }

        update() {
            if (time > this.delay) {
                this.alpha = p.min(this.alpha + 10, 200);

                if (!this.isReturn) {
                    this.progress = p.min(this.progress + 0.02, 1);
                    this.x = p.lerp(this.x1, this.x2, this.progress);
                    this.y = p.lerp(this.y1, this.y2, this.progress);

                    if (this.progress >= 1) {
                        this.isReturn = true;
                        this.progress = 0;
                    }
                } else {
                    this.progress = p.min(this.progress + 0.02, 1);
                    this.x = p.lerp(this.x2, this.x1, this.progress);
                    this.y = p.lerp(this.y2, this.y1, this.progress);

                    if (this.progress >= 1) {
                        this.isReturn = false;
                        this.progress = 0;
                    }
                }
            }
        }

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

            p.noStroke();
            p.fill(...colors.accent1, this.alpha);
            p.circle(this.x, this.y, 6);
        }
    }

    class BroadcastWave {
        constructor(x, y, maxRadius, delay, speed) {
            this.x = x;
            this.y = y;
            this.maxRadius = maxRadius;
            this.delay = delay;
            this.speed = speed;
            this.radius = 0;
            this.alpha = 0;
        }

        update() {
            if (time > this.delay) {
                if (this.radius < this.maxRadius) {
                    this.radius += this.speed;
                    this.alpha = p.map(this.radius, 0, this.maxRadius, 180, 0);
                } else {
                    this.radius = 0;
                }
            }
        }

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

            p.noFill();
            p.stroke(...colors.accent2, this.alpha);
            p.strokeWeight(2);
            p.circle(this.x, this.y, this.radius * 2);
        }
    }

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

        // Left side: Genuine vulnerability - mutual exchange between two people
        let person1X = 80;
        let person1Y = 150;
        let person2X = 120;
        let person2Y = 150;

        // Create bidirectional particles showing mutual, gradual exchange
        for (let i = 0; i < 6; i++) {
            genuineParticles.push(new VulnerabilityParticle(
                person1X, person1Y - 5,
                person2X, person2Y - 5,
                30 + i * 40
            ));
            genuineParticles.push(new VulnerabilityParticle(
                person2X, person2Y + 5,
                person1X, person1Y + 5,
                50 + i * 40
            ));
        }

        // Right side: Performative vulnerability - broadcasting waves from one person to many
        let broadcasterX = 300;
        let broadcasterY = 150;

        // Multiple waves emanating outward at different intervals
        for (let i = 0; i < 8; i++) {
            performativeWaves.push(new BroadcastWave(
                broadcasterX, broadcasterY,
                100,
                20 + i * 20,
                2
            ));
        }
    };

    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("Genuine Vulnerability", 100, 15);
        p.text("Performative Vulnerability", 300, 15);

        // Descriptions
        p.textSize(8);
        p.fill(...colors.accent3, 150);
        p.text("Mutual, gradual, bounded", 100, 32);
        p.text("Broadcasting, demanding", 300, 32);

        // Left side: Two people with mutual exchange
        if (time > 20) {
            p.noStroke();
            p.fill(...colors.accent3, 180);
            p.circle(80, 150, 20); // Person 1
            p.circle(120, 150, 20); // Person 2

            // Connection line showing relationship
            p.stroke(...colors.accent3, 60);
            p.strokeWeight(1);
            p.line(80, 150, 120, 150);

            // Label
            p.noStroke();
            p.fill(...colors.accent3, 140);
            p.textSize(7);
            p.textAlign(p.CENTER);
            p.text("Trust develops", 100, 185);
            p.text("through reciprocity", 100, 195);
        }

        // Right side: One person broadcasting to many
        if (time > 20) {
            p.noStroke();
            // Broadcaster - larger, more prominent
            p.fill(...colors.accent2, 200);
            p.circle(300, 150, 24);

            // Audience members - smaller, scattered
            p.fill(...colors.accent3, 120);
            let audiencePositions = [
                [260, 100], [290, 95], [320, 95], [350, 100],
                [250, 140], [355, 145],
                [250, 160], [355, 165],
                [260, 200], [290, 205], [320, 205], [350, 200]
            ];

            for (let pos of audiencePositions) {
                p.circle(pos[0], pos[1], 8);
            }

            // Label
            p.noStroke();
            p.fill(...colors.accent2, 140);
            p.textSize(7);
            p.textAlign(p.CENTER);
            p.text("Obligation created", 300, 240);
            p.text("through intensity", 300, 250);
        }

        // Update and display genuine vulnerability particles
        for (let particle of genuineParticles) {
            particle.update();
            particle.display(colors);
        }

        // Update and display performative waves
        for (let wave of performativeWaves) {
            wave.update();
            wave.display(colors);
        }

        // Bottom labels
        if (time > 100) {
            p.textAlign(p.CENTER, p.BOTTOM);
            p.textSize(9);
            p.fill(...colors.accent1, p.min((time - 100) * 2, 160));
            p.text("Contextual & Earned", 100, 275);

            p.fill(...colors.accent2, p.min((time - 100) * 2, 160));
            p.text("Universal & Coercive", 300, 275);
        }

        // Bottom message
        if (time > 200) {
            p.textAlign(p.CENTER, p.BOTTOM);
            p.textSize(8);
            p.fill(...colors.accent3, p.min((time - 200) * 2, 140));
            p.text("Real vulnerability is risky and reciprocal. Performance is safe and extractive.", 200, 295);
        }

        time++;

        // Loop animation
        if (time > 400) {
            time = 0;
        }
    };
};