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;
}
};
};