The Romance Hierarchy
About This Sketch
A split-screen comparison of two approaches to human connection. On the left, a single person relies on one dominant romantic relationship while other connections fade. On the right, a network of equally-valued relationships provides distributed support. The visualization challenges the cultural assumption that romantic love should be elevated above all other forms of connection.
Algorithm
This visualization contrasts two models of human connection: the hierarchy model (left) where one romantic relationship dominates and all others fade into insignificance, versus the portfolio model (right) where multiple connections of equal importance support each other in a distributed network.
The sketch uses visual weight (line thickness, node size, opacity) to represent the relative importance assigned to different relationships. In the hierarchy model, one connection pulses brightly while others remain faded and small. In the portfolio model, all connections maintain equal visual presence and interconnect to form a robust support network.
This accompanies the blog post "The Romance Hierarchy" which argues that our cultural elevation of romantic love above all other forms of connection weakens both romantic relationships (by overburdening them) and all other relationships (by systematically devaluing them).
Pseudocode
SETUP:
Create hierarchy person at left with:
- One large romantic connection (pulsing, bright)
- Six smaller secondary connections (faded, weak)
Create portfolio people arranged in circle at right
Initialize animation time
DRAW (every frame):
Get current theme colors
Clear background
LEFT SIDE (Hierarchy):
Draw label "Hierarchy"
For each connection from central person:
If romantic connection:
Draw thick, bright, pulsing line
Draw large endpoint
Else:
Draw thin, faded line
Draw small endpoint
Draw central person
Display status: "One connection bears all weight"
RIGHT SIDE (Portfolio):
Draw label "Portfolio"
For each person in network:
Check distance to all other people
If within connection threshold:
Draw connecting line (strength based on distance)
Draw all people as equal-sized nodes
Display status: "Many connections share the load"
Draw divider between models
Display message: "Distribute your emotional investment"
Increment time for animation
Source Code
let sketch = function(p) {
let hierarchyPerson;
let portfolioPeople;
let time = 0;
class HierarchyPerson {
constructor() {
this.x = 100;
this.y = 150;
this.connections = [];
// Create connections of different "importance"
// One large romantic connection
this.connections.push({
type: 'romantic',
angle: -p.HALF_PI,
distance: 60,
size: 20,
strength: 1.0,
pulseSpeed: 0.05
});
// Several smaller, faded connections
for (let i = 0; i < 6; i++) {
let angle = p.TWO_PI * i / 6;
this.connections.push({
type: 'other',
angle: angle,
distance: 45,
size: 8,
strength: 0.3,
pulseSpeed: 0.02
});
}
}
display(colors) {
// Draw connections
for (let conn of this.connections) {
let endX = this.x + p.cos(conn.angle) * conn.distance;
let endY = this.y + p.sin(conn.angle) * conn.distance;
// Pulsing effect
let pulse = p.sin(time * conn.pulseSpeed) * 0.2 + 0.8;
if (conn.type === 'romantic') {
// Thick, bright line for romantic connection
p.stroke(...colors.accent2, 200 * pulse);
p.strokeWeight(3);
p.line(this.x, this.y, endX, endY);
// Large endpoint
p.noStroke();
p.fill(...colors.accent2, 220 * pulse);
p.circle(endX, endY, conn.size * pulse);
} else {
// Thin, faded lines for other connections
p.stroke(...colors.accent3, 80 * conn.strength);
p.strokeWeight(1);
p.line(this.x, this.y, endX, endY);
// Small, faded endpoints
p.noStroke();
p.fill(...colors.accent3, 100 * conn.strength);
p.circle(endX, endY, conn.size);
}
}
// Draw central person (stressed from supporting everything through one connection)
p.noStroke();
p.fill(...colors.accent2, 180);
p.circle(this.x, this.y, 16);
}
}
class PortfolioPerson {
constructor(index, total) {
let angle = p.TWO_PI * index / total;
let radius = 45;
this.x = 300 + p.cos(angle) * radius;
this.y = 150 + p.sin(angle) * radius;
this.connections = [];
this.baseAngle = angle;
}
display(colors) {
p.noStroke();
p.fill(...colors.accent2, 200);
p.circle(this.x, this.y, 14);
}
}
p.setup = function() {
p.createCanvas(400, 300);
p.colorMode(p.RGB);
hierarchyPerson = new HierarchyPerson();
// Create network of portfolio people
portfolioPeople = [];
for (let i = 0; i < 7; i++) {
portfolioPeople.push(new PortfolioPerson(i, 7));
}
};
p.draw = function() {
const colors = getThemeColors();
p.background(...colors.bg);
time++;
// Left side - Hierarchy model
p.noStroke();
p.fill(...colors.accent1, 180);
p.textAlign(p.CENTER);
p.textSize(11);
p.text('Hierarchy', 100, 35);
hierarchyPerson.display(colors);
p.textSize(9);
p.fill(...colors.accent3, 150);
p.text('One connection', 100, 270);
p.text('bears all weight', 100, 282);
// Right side - Portfolio model
p.fill(...colors.accent1, 180);
p.textSize(11);
p.text('Portfolio', 300, 35);
// Draw interconnected network
// First pass: draw all connections
for (let i = 0; i < portfolioPeople.length; i++) {
let person = portfolioPeople[i];
// Connect to neighbors
for (let j = 0; j < portfolioPeople.length; j++) {
if (i !== j) {
let other = portfolioPeople[j];
let distance = p.dist(person.x, person.y, other.x, other.y);
// Connect if close enough
if (distance < 80) {
let alpha = p.map(distance, 0, 80, 180, 60);
p.stroke(...colors.accent2, alpha);
p.strokeWeight(1.5);
p.line(person.x, person.y, other.x, other.y);
}
}
}
}
// Second pass: draw people on top
for (let person of portfolioPeople) {
person.display(colors);
}
p.noStroke();
p.textSize(9);
p.fill(...colors.accent3, 150);
p.text('Many connections', 300, 270);
p.text('share the load', 300, 282);
// Divider
p.stroke(...colors.accent1, 50);
p.strokeWeight(1);
p.line(200, 50, 200, 260);
// Bottom message
p.noStroke();
p.fill(...colors.accent1, 140);
p.textSize(9);
p.textAlign(p.CENTER);
p.text('Distribute your emotional investment', 200, 295);
};
};