Passion as Privilege
About This Sketch
Visualizing two paths to career success: Left side: "Follow your passion" - starts with heart, but needs safety net (platform) to explore Right side: "Build competence first" - starts with foundation, builds up, passion develops at top
This sketch accompanies the blog post "Passion as Privilege" and visualizes its core concepts through generative art.
Algorithm
Visualizing two paths to career success: Left side: "Follow your passion" - starts with heart, but needs safety net (platform) to explore Right side: "Build competence first" - starts with foundation, builds up, passion develops at top
This sketch was originally created as a visual companion to the blog post "Passion as Privilege" 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 two paths to career success:
// Left side: "Follow your passion" - starts with heart, but needs safety net (platform) to explore
// Right side: "Build competence first" - starts with foundation, builds up, passion develops at top
let time = 0;
let passionPath = [];
let competencePath = [];
class PathElement {
constructor(x, y, size, delay, type) {
this.x = x;
this.y = y;
this.size = size;
this.delay = delay;
this.type = type; // 'foundation', 'building', 'passion'
this.alpha = 0;
}
update() {
if (time > this.delay) {
this.alpha = p.min(this.alpha + 5, 200);
}
}
display(colors) {
if (this.alpha === 0) return;
p.noStroke();
if (this.type === 'foundation') {
// Solid base - represents stability/resources
p.fill(...colors.accent3, this.alpha);
p.rect(this.x - this.size/2, this.y - this.size/2, this.size, this.size, 2);
} else if (this.type === 'building') {
// Building blocks - represents competence
p.fill(...colors.accent1, this.alpha);
p.rect(this.x - this.size/2, this.y - this.size/2, this.size, this.size, 2);
} else if (this.type === 'passion') {
// Heart shape - represents passion
p.fill(...colors.accent2, this.alpha);
this.drawHeart(this.x, this.y, this.size);
} else if (this.type === 'falling') {
// Falling/unstable - represents pursuing passion without foundation
p.fill(...colors.accent2, this.alpha * 0.6);
this.drawHeart(this.x, this.y, this.size);
// Draw motion lines
p.stroke(...colors.accent2, this.alpha * 0.3);
p.strokeWeight(1);
p.line(this.x - 5, this.y - 15, this.x - 8, this.y - 20);
p.line(this.x + 5, this.y - 15, this.x + 8, this.y - 20);
} else if (this.type === 'gap') {
// Gap/missing foundation - dotted line
p.stroke(...colors.accent3, this.alpha * 0.4);
p.strokeWeight(2);
p.drawingContext.setLineDash([5, 5]);
p.line(this.x - this.size/2, this.y, this.x + this.size/2, this.y);
p.drawingContext.setLineDash([]);
}
}
drawHeart(x, y, size) {
p.push();
p.translate(x, y);
p.scale(size / 20);
p.beginShape();
for (let a = 0; a < p.TWO_PI; a += 0.1) {
let r = p.sin(a) * p.sqrt(p.abs(p.cos(a))) / (p.sin(a) + 7/5) - 2 * p.sin(a) + 2;
let px = r * p.cos(a);
let py = -r * p.sin(a);
p.vertex(px * 3, py * 3);
}
p.endShape(p.CLOSE);
p.pop();
}
}
p.setup = function() {
p.createCanvas(400, 300);
p.colorMode(p.RGB);
// Left side: "Follow your passion" path - starts with passion, needs foundation
// Heart at top (passion)
passionPath.push(new PathElement(100, 60, 20, 20, 'passion'));
// Falling indicator - passion without foundation
for (let i = 0; i < 3; i++) {
passionPath.push(new PathElement(100, 100 + i * 30, 16 - i * 2, 50 + i * 20, 'falling'));
}
// Gap - missing foundation
passionPath.push(new PathElement(100, 200, 40, 110, 'gap'));
// Foundation that passion needs (appears late, bottom)
for (let i = 0; i < 3; i++) {
passionPath.push(new PathElement(70 + i * 30, 235, 25, 150 + i * 10, 'foundation'));
}
// Text indicator
passionPath.push({
display: function(colors) {
if (time > 180) {
p.noStroke();
p.fill(...colors.accent2, p.min((time - 180) * 3, 180));
p.textSize(8);
p.textAlign(p.CENTER);
p.text("Needs safety net", 100, 260);
}
},
update: function() {}
});
// Right side: "Build competence first" path - foundation first, passion develops
// Foundation at bottom
for (let i = 0; i < 3; i++) {
competencePath.push(new PathElement(270 + i * 30, 235, 25, 20 + i * 10, 'foundation'));
}
// Building competence - stacking blocks
let buildingLayers = [
[300, 200], // bottom layer
[285, 175], [315, 175], // second layer
[300, 150], // third layer
[285, 125], [315, 125], // fourth layer
[300, 100] // fifth layer
];
for (let i = 0; i < buildingLayers.length; i++) {
let [x, y] = buildingLayers[i];
competencePath.push(new PathElement(x, y, 22, 70 + i * 15, 'building'));
}
// Passion at top (develops last)
competencePath.push(new PathElement(300, 60, 20, 200, 'passion'));
// Text indicator
competencePath.push({
display: function(colors) {
if (time > 220) {
p.noStroke();
p.fill(...colors.accent1, p.min((time - 220) * 3, 180));
p.textSize(8);
p.textAlign(p.CENTER);
p.text("Passion from mastery", 300, 260);
}
},
update: function() {}
});
};
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 at top
p.noStroke();
p.fill(...colors.accent3, 200);
p.textAlign(p.CENTER, p.TOP);
p.textSize(11);
p.text("Follow Passion", 100, 15);
p.text("Build Competence", 300, 15);
// Descriptions
p.textSize(8);
p.fill(...colors.accent3, 140);
p.text("(requires privilege)", 100, 32);
p.text("(works for most)", 300, 32);
// Update and display both paths
for (let element of passionPath) {
element.update();
element.display(colors);
}
for (let element of competencePath) {
element.update();
element.display(colors);
}
// Bottom message
if (time > 250) {
p.textAlign(p.CENTER, p.BOTTOM);
p.textSize(9);
p.fill(...colors.accent3, p.min((time - 250) * 2, 160));
p.text("Passion is often the result of success, not its prerequisite", 200, 290);
}
time++;
// Loop animation
if (time > 350) {
time = 0;
for (let element of passionPath) {
if (element.alpha !== undefined) element.alpha = 0;
}
for (let element of competencePath) {
if (element.alpha !== undefined) element.alpha = 0;
}
}
};
};