The Ritual Trap
About This Sketch
Visualizing the ritual trap Top: Perfect, geometric ritual forms - rigid, repetitive, empty Bottom: Organic, irregular moments of genuine presence - messy but alive Shows contrast between performed ritual and actual engagement
This sketch accompanies the blog post "The Ritual Trap" and visualizes its core concepts through generative art.
Algorithm
Visualizing the ritual trap Top: Perfect, geometric ritual forms - rigid, repetitive, empty Bottom: Organic, irregular moments of genuine presence - messy but alive Shows contrast between performed ritual and actual engagement
This sketch was originally created as a visual companion to the blog post "The Ritual Trap" 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 ritual trap
// Top: Perfect, geometric ritual forms - rigid, repetitive, empty
// Bottom: Organic, irregular moments of genuine presence - messy but alive
// Shows contrast between performed ritual and actual engagement
let time = 0;
let ritualForms = [];
let genuineMoments = [];
class RitualForm {
constructor(x, y, type) {
this.x = x;
this.y = y;
this.type = type; // 0: circle, 1: square, 2: triangle
this.size = 25;
this.rotation = 0;
this.rotationSpeed = 0.02;
this.alpha = 180;
this.empty = true; // Hollow, just form
}
update() {
// Mechanical, predictable rotation
this.rotation += this.rotationSpeed;
}
display(colors) {
p.push();
p.translate(this.x, this.y);
p.rotate(this.rotation);
// Hollow forms - all structure, no substance
p.noFill();
p.stroke(...colors.accent3, this.alpha);
p.strokeWeight(2);
if (this.type === 0) {
p.circle(0, 0, this.size);
} else if (this.type === 1) {
p.square(-this.size/2, -this.size/2, this.size);
} else {
p.triangle(0, -this.size/2, -this.size/2, this.size/2, this.size/2, this.size/2);
}
// Checkmark inside - ritual completed
if (time % 120 > 60) {
let checkAlpha = p.map(time % 60, 0, 60, 0, 150);
p.stroke(...colors.accent3, checkAlpha);
p.strokeWeight(1.5);
p.noFill();
p.beginShape();
p.vertex(-5, 0);
p.vertex(-2, 5);
p.vertex(6, -6);
p.endShape();
}
p.pop();
}
}
class GenuineMoment {
constructor(x, y) {
this.x = x;
this.y = y;
this.life = 255;
this.decay = p.random(1, 3);
this.size = p.random(8, 20);
this.vx = p.random(-0.5, 0.5);
this.vy = p.random(-1, -2);
this.color = p.random([0, 1]); // accent1 or accent2
this.rotation = p.random(p.TWO_PI);
this.rotationSpeed = p.random(-0.05, 0.05);
this.shape = p.floor(p.random(4)); // More variety in shapes
}
update() {
// Organic, unpredictable movement
this.x += this.vx;
this.y += this.vy;
this.life -= this.decay;
this.rotation += this.rotationSpeed;
// Slow down
this.vy += 0.03;
this.vx *= 0.98;
}
display(colors) {
if (this.life <= 0) return;
p.push();
p.translate(this.x, this.y);
p.rotate(this.rotation);
// Filled, alive, varied shapes - substance not just form
let col = this.color === 0 ? colors.accent1 : colors.accent2;
p.fill(...col, this.life);
p.noStroke();
// Irregular, organic shapes
if (this.shape === 0) {
// Irregular blob
p.beginShape();
for (let a = 0; a < p.TWO_PI; a += p.PI/4) {
let r = this.size/2 + p.sin(a * 3 + time * 0.05) * 3;
p.vertex(p.cos(a) * r, p.sin(a) * r);
}
p.endShape(p.CLOSE);
} else if (this.shape === 1) {
// Splatter
for (let i = 0; i < 5; i++) {
let angle = (p.TWO_PI / 5) * i;
let r = this.size/2;
p.circle(p.cos(angle) * r, p.sin(angle) * r, this.size/3);
}
} else if (this.shape === 2) {
// Streak
p.ellipse(0, 0, this.size, this.size/2);
} else {
// Cluster
p.circle(0, 0, this.size);
p.circle(this.size/3, this.size/3, this.size/2);
}
p.pop();
}
isDead() {
return this.life <= 0;
}
}
p.setup = function() {
p.createCanvas(400, 300);
p.colorMode(p.RGB);
// Initialize ritual forms (top) - perfectly spaced, mechanical
for (let i = 0; i < 5; i++) {
ritualForms.push(
new RitualForm(
60 + i * 70,
60,
i % 3
)
);
}
};
p.draw = function() {
const colors = getThemeColors();
p.background(...colors.bg);
// Title
p.noStroke();
p.fill(...colors.accent3, 180);
p.textAlign(p.CENTER, p.TOP);
p.textSize(11);
p.text("The Ritual Trap", 200, 15);
// Section labels
p.textAlign(p.CENTER, p.TOP);
p.textSize(8);
p.fill(...colors.accent3, 160);
p.text("Performed ritual (empty form)", 200, 35);
p.text("Genuine engagement (messy substance)", 200, 145);
// Dividing line
p.stroke(...colors.accent3, 60);
p.strokeWeight(1);
p.line(30, 130, 370, 130);
// Top: Ritual forms - mechanical, perfect, empty
for (let form of ritualForms) {
form.update();
form.display(colors);
}
// Show repetition of ritual
if (time > 60) {
let repeatAlpha = Math.min((time - 60) * 2, 140);
p.noStroke();
p.fill(...colors.accent3, repeatAlpha);
p.textAlign(p.CENTER, p.CENTER);
p.textSize(7);
p.text("Perfect. Consistent. Empty.", 200, 95);
}
// Add annotations about optimization
if (time > 180 && time < 300) {
let annAlpha = Math.min((time - 180) * 2, 130);
p.textSize(6);
p.fill(...colors.accent3, annAlpha);
p.textAlign(p.LEFT, p.CENTER);
p.text("□ Morning meditation", 40, 110);
p.text("□ Gratitude journal", 150, 110);
p.text("□ Intention setting", 260, 110);
}
// Bottom: Genuine moments - irregular, unpredictable, alive
for (let moment of genuineMoments) {
moment.update();
moment.display(colors);
}
// Clean up dead moments
genuineMoments = genuineMoments.filter(m => !m.isDead());
// Randomly spawn genuine moments - irregular timing
if (p.random() < 0.05) {
genuineMoments.push(
new GenuineMoment(
p.random(60, 340),
240
)
);
}
// Comparison messages
if (time > 300) {
let msgAlpha = Math.min((time - 300) * 1.5, 160);
p.textAlign(p.LEFT, p.CENTER);
p.textSize(7);
p.noStroke();
p.fill(...colors.accent3, msgAlpha);
p.text("Top: Checking boxes", 30, 80);
p.text("Bottom: Actually feeling", 30, 200);
}
// Show the problem
if (time > 420) {
let problemAlpha = Math.min((time - 420) * 1.5, 170);
p.textAlign(p.CENTER, p.BOTTOM);
p.textSize(8);
p.fill(...colors.accent2, problemAlpha);
p.text("The protocol replaced the presence", 200, 275);
}
// Final insight
if (time > 540) {
let insightAlpha = Math.min((time - 540) * 2, 160);
p.textAlign(p.CENTER, p.BOTTOM);
p.textSize(8);
p.fill(...colors.accent1, insightAlpha);
p.text("Real moments are irregular, imperfect, and can't be scheduled", 200, 293);
}
// Occasionally show ritual becoming obligation
if (time > 200 && time % 180 < 60) {
let obligAlpha = p.map(time % 60, 0, 60, 0, 140);
// "SHOULD" appearing over ritual forms
p.push();
p.textAlign(p.CENTER, p.CENTER);
p.textSize(10);
p.fill(...colors.accent3, obligAlpha);
p.text("SHOULD", 200, 60);
p.pop();
}
time++;
// Loop
if (time > 700) {
time = 0;
}
};
};