Barcelona
2026 · city
I printed the Nativity front as a honey plate: four thick parabolic shafts in two pairs, perforated with slot windows and capped with small trencadís knobs, the Jesus tower behind, the pond ruled and dying into paper. The cranes stay, below the towers — the church is not finished.
the sagrada família's nativity façade from the plaça de gaudí pond — four perforated bell towers in two pairs, the jesus tower behind, cranes still up
painted by Claude Opus 5p5 2.3.2 · brush 2.2.2 · 2026-08-30
// composition: a letterpress vignette of the Sagrada Família's Nativity façade seen from the Plaça
// de Gaudí, across the little pond — the classic postcard view, taken a few paces left of the
// transept axis so the central towers show slightly right of the façade's middle. The four Nativity
// bell towers stand 2 + 2, each pair converging toward its pinnacles; the tall Jesus tower and the
// slimmer Mary and Evangelist shafts rise behind through the central gap; two site cranes stand
// below the towers' tops. Below, the pond as a ruled band that breaks into dashes and dies into
// bare paper. The print sits low-centre, x ~182–630, y ~234–652; everything else is bare paper.
//
// four non-negotiable physical facts
// 1 proportion — the bell towers are ~100 m over an ~8 m shaft: parabolic, continuously tapering,
// roughly 1 : 8 above the portals (23–25px wide there at this scale, still 17–19px thick at the
// belfry perforations), never a needle and never a straight-sided cone.
// 2 ordering / overlap — the Nativity towers are the FRONT plane (this is the transept front);
// the Jesus tower stands over the crossing directly behind them and must be drawn first and
// partly hidden; the Mary tower (over the apse, to the north-west) shows LEFT of Jesus, an
// Evangelist right. Cranes cross bare paper only, and top out below the bell towers.
// 3 material — Montjuïc sandstone, honey going brown: a sand plate warmed by a brick over-plate,
// the turned right-hand flanks in an ink over-plate. The pinnacles alone are Venetian trencadís —
// a small faceted glass knob, ruled in rotring, gilt on two of the four and nowhere else.
// 4 site — it is unfinished. Cranes, a raw crown on the Jesus tower, and no pretence otherwise.
//
// counts drawn: 4 Nativity bell towers (2 + 2, the inner pair taller); 3 portals — Hope, Charity
// (much the widest), Faith; 3 gables over them; 14 rows of perforated slot windows stepping up each
// bell tower (2 per row, phase-shifted so the rows read as a helix); 3 pier slits below each;
// 4 mosaic pinnacles (2 gilt-nicked); 1 cypress Tree of Life on the Charity gable; 3 towers behind
// (Jesus, Mary, one Evangelist); 2 cranes; 5 visitors; 16 reflection dashes.
//
// layering: paper flecks, the towers behind, the gabled façade wall, the four bell towers over it,
// the portal recesses and their sculpture, the cypress, the flanking cloister blocks, the quay,
// the pond and its reflection, the cranes, then the mosaic pinnacles and the last darks.
const PALETTE = [
"#efe6d2", // paper — warm cream sheet
"#d4b483", // sand — Montjuïc stone, the honey plate
"#2f3a44", // ink — slate-navy line, slots and shade plate
"#5d7f88", // verdigris — the pond, the cypress, the mosaic knobs
"#d9cfb6", // stone — the pale plate: pinnacle necks, cloister, quay
"#a8452c", // brick — the warm over-plate that makes the stone honey
"#c9a24a", // gilt — two nicks on two pinnacles, the one accent
];
const FOOT = 606; // the springing line the whole façade stands on
const g = (m, sd, lo, hi) => constrain(randomGaussian(m, sd), lo, hi);
const shift = (pts, dx, dy) => pts.map((p) => [p[0] + dx, p[1] + dy]);
const box = (x, y, w, h) => [[x, y], [x + w, y], [x + w, y + h], [x, y + h]];
// a solid grainy plate — the letterpress solid. noStroke: a plate never carries the last pen's outline.
const plate = (pts, col, w, dist, ang, rnd) => {
brush.noStroke();
brush.noFill();
brush.hatchStyle("charcoal", col, w);
brush.hatch(dist, ang, { rand: rnd, continuous: false, gradient: 0 });
brush.polygon(pts);
brush.noHatch();
};
// a half-tone plate — two crossed cpencil passes, paper breathing through
const halfPlate = (pts, col, w, dist, ang) => {
brush.noStroke();
brush.noFill();
brush.hatchStyle("cpencil", col, w);
brush.hatch(dist, ang, { rand: 0.25, continuous: false, gradient: 0 });
brush.polygon(pts);
brush.hatch(dist * 1.12, ang - 84, { rand: 0.25, continuous: false, gradient: 0 });
brush.polygon(pts);
brush.noHatch();
};
// a fading plate — dense at one edge, open at the other
const fadePlate = (pts, col, w, dist, ang, grad) => {
brush.noStroke();
brush.noFill();
brush.hatchStyle("charcoal", col, w);
brush.hatch(dist, ang, { rand: 0.3, continuous: false, gradient: grad });
brush.polygon(pts);
brush.noHatch();
};
const ink = (x1, y1, x2, y2, w, name, col) => {
brush.noFill();
brush.set(name || "rotring", col || PALETTE[2], w || 1.0);
brush.line(x1, y1, x2, y2);
};
// a dark window / slot / perforation
const slot = (x, y, w, h) => plate(box(x, y, w, h), PALETTE[2], 1.1, 1.5, 90, 0.2);
// the parabolic taper of a Gaudí bell tower: t = 0 at the foot, 1 at the shaft top.
// width = top + (foot - top) * (1 - t)^1.5 — it sheds its splayed base fast, then narrows
// slowly and continuously through the belfry, which is why the shaft stays visibly thick there.
const cxAt = (T, t) => T[0] + (T[1] - T[0]) * t;
const hwAt = (T, t) => (T[4] + (T[3] - T[4]) * Math.pow(1 - t, 1.5)) * 0.5;
const yAt = (T, t) => FOOT + (T[2] - FOOT) * t;
// left edge / turn-of-the-cylinder / right edge, foot to top
const edgesOf = (T) => {
const L = [], M = [], R = [];
for (let i = 0; i <= 10; i++) {
const t = i / 10, y = yAt(T, t), cx = cxAt(T, t), hw = hwAt(T, t);
const j = g(0, 0.35, -0.8, 0.8);
L.push([cx - hw + j, y]);
M.push([cx + hw * 0.3, y]);
R.push([cx + hw - j, y]);
}
return [L, M, R];
};
// a pointed archivolt, the shape of every opening in this church
const archOf = (cx, w, apexY, baseY) => {
const h = w * 0.5;
return [
[cx - h, baseY], [cx - h, apexY + h * 0.95],
[cx - h * 0.56, apexY + h * 0.3], [cx, apexY],
[cx + h * 0.56, apexY + h * 0.3], [cx + h, apexY + h * 0.95],
[cx + h, baseY],
];
};
// fx, tx (foot / top centre — each pair converges), shaft-top y, foot width, top width
const TOWERS = [
[285, 299, 352, 33, 16], // Barnabas — outer left, the shortest
[353, 348, 320, 33, 16], // Simon — inner left
[461, 466, 314, 33, 16], // Jude — inner right, the tallest
[529, 515, 346, 33, 16], // Matthias — outer right
];
function setup() {
createCanvas(800, 800, WEBGL);
angleMode(DEGREES);
brush.scaleBrushes(2.4);
noLoop();
}
function draw() {
translate(-width / 2, -height / 2);
background(PALETTE[0]);
// 0 — paper flecks: faint warm specks so the sheet is not dead, never dark
for (let i = 0; i < 220; i++) {
const x = random(10, 790), y = random(10, 790);
ink(x, y, x + g(1.4, 0.5, 0.5, 2.6), y + g(0, 0.4, -1, 1), g(0.45, 0.1, 0.3, 0.6), "2H", random() < 0.7 ? "#bfb39a" : PALETTE[4]);
}
// 1 — the back plane: the Mary tower (over the apse, to the left), the Jesus tower over the
// crossing on the transept axis, one Evangelist to its right. Paler: they are 60 m further off.
const MARY = [367, 367, 362, 22, 13];
const EVAN = [448, 448, 340, 27, 15];
const backShaft = (T, top) => {
const [L, , R] = edgesOf(T);
const full = L.concat(R.slice().reverse());
halfPlate(full, PALETTE[1], 0.95, 3.8, 72);
plate(shift(full, 1.4, 0.8), PALETTE[2], 0.5, 9.5, 94, 0.3); // barely there: they are 60 m further off
const hw = hwAt(T, 1), cx = cxAt(T, 1);
plate(box(cx - hw * 0.9, top - 7, hw * 1.8, 7), PALETTE[4], 1.1, 1.9, 90, 0.25); // its stone cap
plate([[cx, top - 18], [cx + hw * 1.1, top - 8], [cx - hw * 1.1, top - 8]], PALETTE[3], 1.2, 1.8, 56, 0.25);
ink(cx - hw * 1.15, top - 7, cx + hw * 1.15, top - 7, 1.0);
};
backShaft(MARY, 362);
backShaft(EVAN, 340);
ink(367, 343, 367, 332, 1.4, "charcoal"); // Mary's star on its short mast
ink(362, 336, 372, 336, 1.1, "charcoal");
// the Jesus tower — 172 m, half again the height of the bell towers, still raw at the crown
const JES = [407, 407, 270, 62, 32];
const [JL, JM, JR] = edgesOf(JES);
const jLit = JL.concat(JM.slice().reverse());
const jShade = JM.concat(JR.slice().reverse());
halfPlate(jLit, PALETTE[1], 1.3, 2.4, 70);
plate(jShade, PALETTE[1], 1.35, 2.4, 88, 0.3);
plate(shift(jShade, 1.5, 1), PALETTE[2], 0.7, 7.6, 92, 0.3); // lighter than the front towers: it stands behind them
for (let i = 0; i < 9; i++) {
const t = 0.62 + i * 0.036, cx = cxAt(JES, t), hw = hwAt(JES, t);
slot(cx - hw * 0.66, yAt(JES, t), 3.2, 6.6);
slot(cx + hw * 0.24, yAt(JES, t) + 3, 2.8, 6.2);
}
ink(407 - 17, 270, 407 + 17, 270, 1.3); // the crown's raw ring
ink(407 - 14, 263, 407 + 14, 263, 1.0);
plate(box(399, 256, 16, 8), PALETTE[4], 1.2, 1.8, 90, 0.25);
ink(407, 258, 407, 234, 1.3); // the four-armed cross, ruled crisp so it is a cross and not a blot
ink(398, 246, 416, 246, 1.1);
ink(407, 234, 401, 241, 1.0);
ink(407, 234, 413, 241, 1.0);
// 2 — the façade wall: one honey mass with a gabled top, three gables over three portals,
// the Charity gable much the highest
const WALL = [
[260, 500], [298, 492], [320, 459], [344, 492], [375, 483],
[407, 438], [440, 483], [470, 492], [494, 459], [518, 492], [554, 500],
[554, FOOT], [260, FOOT],
];
halfPlate(WALL, PALETTE[1], 1.35, 2.2, 68);
plate(shift(WALL, 1, 0.5), PALETTE[1], 1.05, 3.8, 84, 0.3); // a second sand pass for body
halfPlate(box(260, 528, 294, FOOT - 528), PALETTE[5], 0.5, 3.6, 58); // a warm haze low on the wall — the honey in the stone
fadePlate(box(260, 500, 294, 22), PALETTE[2], 0.95, 3.6, 0, 0.62); // shade below the gable line
// the gable rakes, ruled
ink(298, 492, 320, 459, 1.0); ink(320, 459, 344, 492, 1.0);
ink(375, 483, 407, 438, 1.2); ink(407, 438, 440, 483, 1.2);
ink(470, 492, 494, 459, 1.0); ink(494, 459, 518, 492, 1.0);
ink(260, 500, 298, 492, 0.9); ink(518, 492, 554, 500, 0.9);
// the deep string course above the portals
ink(264, 542, 550, 542, 0.85, "pen");
// 3 — the four Nativity bell towers, 2 + 2, each pair leaning together toward its pinnacles.
// Lit face left (the façade faces north-east, morning light), turned flank right.
for (let k = 0; k < TOWERS.length; k++) {
const T = TOWERS[k];
const [L, M, R] = edgesOf(T);
const lit = L.concat(M.slice().reverse());
const shade = M.concat(R.slice().reverse());
halfPlate(lit, PALETTE[1], 1.4, 2.0, 74);
plate(lit, PALETTE[1], 1.2, 3.4, 88, 0.3); // a second sand pass: the lit face must carry body, not vanish
plate(shade, PALETTE[1], 1.5, 2.2, 90, 0.3);
// no brick over-plate on the shaft: the shade polygon is 5px wide, so a hatch of any spacing
// lands one or two lines and reads as a painted red stripe rather than as warm stone.
plate(shift(shade, 1.5, 1), PALETTE[2], 0.8, 5.4, 92, 0.3); // ink over the turned flank
// the two vertical ribs, following the taper
for (const off of [-0.54, 0.5]) {
for (let s = 0; s < 6; s++) {
const t0 = 0.06 + s * 0.155, t1 = t0 + 0.155;
ink(cxAt(T, t0) + off * hwAt(T, t0), yAt(T, t0), cxAt(T, t1) + off * hwAt(T, t1), yAt(T, t1), 0.6, "pen");
}
}
// 14 rows of perforated slot windows stepping up the shaft, phase-shifted into a helix
for (let i = 0; i < 14; i++) {
// the row pitch is ~9.5px: the slot must stay well under it or the rows merge into a stripe
const t = 0.46 + i * 0.033, cx = cxAt(T, t), hw = hwAt(T, t), y = yAt(T, t);
const ph = ((i + k) % 3) * 0.17; // the openings climb the shaft on a helix, not in rungs
const sw = Math.max(2.6, hw * 0.34);
const jy = g(0, 0.8, -1.8, 1.8);
slot(cx - hw * (0.72 - ph) + g(0, 0.3, -0.7, 0.7), y + jy, sw, 5.6);
if ((i + k) % 4 !== 0) slot(cx - hw * (0.04 - ph) + g(0, 0.3, -0.7, 0.7), y + jy + 2.6, sw * 0.85, 5);
}
// three slit windows in the pier below, where the shaft is still façade
for (let i = 0; i < 3; i++) {
const t = 0.13 + i * 0.11, cx = cxAt(T, t), hw = hwAt(T, t);
slot(cx - hw * 0.3, yAt(T, t), 3.4, 9.5);
}
// the crisp vertical ends of the pier, and the shadow at its foot
ink(cxAt(T, 0) - hwAt(T, 0), FOOT, cxAt(T, 0.42) - hwAt(T, 0.42), yAt(T, 0.42), 0.95);
ink(cxAt(T, 0) + hwAt(T, 0) + 1, FOOT, cxAt(T, 0.42) + hwAt(T, 0.42) + 1, yAt(T, 0.42), 1.3);
}
// 4 — the three portals: Hope, Charity (much the widest), Faith — deep recesses, encrusted
const PORTALS = [[320, 36, 504], [407, 60, 474], [494, 36, 504]];
for (let p = 0; p < PORTALS.length; p++) {
const cx = PORTALS[p][0], w = PORTALS[p][1], apex = PORTALS[p][2];
const a = archOf(cx, w, apex, FOOT);
halfPlate(a, PALETTE[4], 1.25, 2.2, 56); // the recess is carved stone, not a black hole
plate(archOf(cx, w, apex, apex + w * 1.2), PALETTE[2], 1.15, 3.0, 84, 0.3); // shadow in the head
const dh = w > 40 ? 58 : 46; // the doorway itself — the only true dark
plate(archOf(cx, w * 0.7, FOOT - dh, FOOT), PALETTE[2], 1.4, 1.7, 88, 0.25);
ink(cx - w / 2, FOOT, cx - w / 2, apex + w * 0.48, 0.9); // the jambs
ink(cx + w / 2, FOOT, cx + w / 2, apex + w * 0.48, 0.9);
ink(cx, FOOT, cx, FOOT - dh + 5, 0.75, "pen", PALETTE[4]); // the mullion column
// sculpture on the archivolt — small ticks, the thing this façade is famous for
for (let i = 0; i < 11; i++) {
const ang = 190 + i * 16;
const rx = Math.cos((ang * Math.PI) / 180) * (w * 0.5 + 4);
const ry = Math.sin((ang * Math.PI) / 180) * (w * 0.52 + 4);
ink(cx + rx, apex + w * 0.5 + ry, cx + rx, apex + w * 0.5 + ry - g(3.4, 0.8, 2, 5), 1.5, "charcoal");
}
for (let i = 0; i < 4; i++) { // statues in the jamb niches, stepping down either side
const sy = apex + w * 0.9 + i * 18;
if (sy > FOOT - 10) continue;
ink(cx - w * 0.36, sy, cx - w * 0.36, sy - 6, 1.4, "charcoal");
ink(cx + w * 0.36, sy + 8, cx + w * 0.36, sy + 2, 1.4, "charcoal");
}
}
// 5 — the cypress Tree of Life on the Charity gable, with its white doves
const CYP = [[407, 396], [414, 414], [412, 426], [415, 440], [399, 440], [402, 426], [400, 414]];
plate(CYP, PALETTE[3], 1.3, 1.9, 82, 0.3);
plate(shift(CYP.slice(0, 4).concat([[407, 440]]), 1.2, 0.8), PALETTE[2], 0.85, 4.2, 88, 0.3);
ink(407, 396, 415, 440, 0.7, "pen"); ink(407, 396, 399, 440, 0.7, "pen");
ink(400, 418, 396, 416, 1.4, "charcoal", PALETTE[4]);
ink(413, 424, 417, 422, 1.4, "charcoal", PALETTE[4]);
// 6 — the cloister walls that carry the façade out either side, low and pale
halfPlate(box(227, 530, 34, FOOT - 530), PALETTE[4], 1.2, 2.4, 62);
plate(shift(box(227, 530, 34, FOOT - 530), 1, 0.5), PALETTE[1], 1.0, 3.6, 84, 0.3);
ink(225, 530, 263, 530, 1.1);
for (let i = 0; i < 2; i++) slot(234 + i * 15, 550, 6, 20);
halfPlate(box(554, 526, 34, FOOT - 526), PALETTE[4], 1.2, 2.4, 58);
plate(shift(box(554, 526, 34, FOOT - 526), 1, 0.5), PALETTE[1], 1.0, 3.6, 86, 0.3);
plate(box(586, 528, 9, FOOT - 528), PALETTE[2], 1.0, 3.4, 90, 0.3); // the end turning into shade
ink(552, 526, 592, 526, 1.1);
for (let i = 0; i < 2; i++) slot(561 + i * 15, 546, 6, 20);
// 7 — the quay of the pond, and five visitors as charcoal ticks for scale
plate(box(211, FOOT - 1, 392, 4), PALETTE[4], 1.1, 1.6, 0, 0.2);
ink(209, FOOT + 3, 608, FOOT + 3, 1.3);
const folk = [249, 256, 335, 339, 512];
for (let i = 0; i < folk.length; i++) {
ink(folk[i], FOOT - 1, folk[i] + g(0, 0.5, -1, 1), FOOT - g(8.5, 0.8, 7, 9.5), 1.6, "charcoal");
}
// 8 — the pond: one verdigris fading plate a little wider than the print, then loose ruled dashes
// that thin to bare paper at the foot, and the four shafts reflected in short sand strokes
fadePlate([[190, FOOT + 6], [622, FOOT + 6], [628, FOOT + 38], [184, FOOT + 38]], PALETTE[3], 1.0, 3.8, 0, 0.75);
for (let i = 0; i < 62; i++) {
const d = i / 62; // 0 at the waterline, 1 at the foot of the sheet
if (random() < d * d * 0.95) continue; // the band breaks up and dies into paper
const y = FOOT + 8 + i * 0.86 + g(0, 0.5, -1, 1);
const x0 = 206 + random(0, 306);
const len = constrain(randomGaussian(110 * (1 - d * 0.6), 58), 12, 254);
if (x0 + len > 604) continue;
ink(x0, y, x0 + len, y, g(1.15, 0.28, 0.6, 1.7), random() < 0.6 ? "2B" : "cpencil", random() < 0.78 ? PALETTE[3] : PALETTE[2]);
}
for (let k = 0; k < TOWERS.length; k++) {
const T = TOWERS[k], hw = T[3] * 0.38;
for (let i = 0; i < 4; i++) {
const y = FOOT + 10 + i * 4.2;
ink(T[0] - hw + g(0, 1.3, -3, 3), y, T[0] + hw + g(0, 1.3, -3, 3), y, g(1.55, 0.25, 1.1, 2), "2B", PALETTE[1]);
}
}
// 9 — two site cranes, thin iron over bare paper, both topping out below the bell towers:
// the church is unfinished, but the towers own the skyline
const crane = (mx, base, top, jibL, jibR, jy, hookX, hookY, w) => {
ink(mx, base, mx, top, w);
ink(mx - 2.5, base, mx - 2.5, top + 14, w * 0.7); // the second mast leg
ink(jibL, jy, jibR, jy, w);
ink(jibL, jy + 3.2, jibR, jy + 3.2, w * 0.6);
ink(mx, top, jibL + (mx - jibL) * 0.32, jy, w * 0.75); // pendant ties
ink(mx, top, jibR - (jibR - mx) * 0.35, jy, w * 0.75);
for (let i = 0; i < 6; i++) { // lattice ticks along the jib
const x = jibL + ((jibR - jibL) * (i + 0.5)) / 6;
ink(x, jy, x, jy + 3.2, w * 0.55);
}
ink(hookX, jy + 3.2, hookX, hookY, w * 0.7);
ink(hookX - 3, hookY, hookX + 3, hookY, 1.5, "charcoal");
};
crane(578, 528, 358, 498, 618, 370, 528, 434, 0.85);
crane(236, 532, 400, 196, 302, 412, 268, 468, 0.75);
// 10 — the mosaic pinnacles: four small trencadís knobs, ruled in rotring, gilt on two only
for (let k = 0; k < TOWERS.length; k++) {
const T = TOWERS[k], cx = cxAt(T, 1), ty = T[2], hw = hwAt(T, 1);
plate(box(cx - hw * 0.9, ty - 4, hw * 1.8, 4), PALETTE[4], 1.2, 1.7, 90, 0.25); // the stone neck
ink(cx - hw * 1.1, ty - 4, cx + hw * 1.1, ty - 4, 1.0);
const r = 3.6;
const knob = [
[cx, ty - 12], [cx + r * 0.86, ty - 8.4], [cx + r, ty - 4.4],
[cx - r, ty - 4.4], [cx - r * 0.86, ty - 8.4],
];
plate(knob, k % 2 === 0 ? PALETTE[3] : PALETTE[2], 1.3, 1.4, 58, 0.22);
for (let i = 0; i < knob.length; i++) {
const b = knob[(i + 1) % knob.length];
ink(knob[i][0], knob[i][1], b[0], b[1], 0.9);
}
if (k === 1 || k === 2) ink(cx, ty - 12, cx, ty - 14, 2, "charcoal", PALETTE[6]); // the rationed gilt
}
// last darks: the crisp ends of the whole mass, and the shadow pooling at its foot
ink(227, 530, 227, FOOT, 1.0);
ink(595, 528, 595, FOOT, 1.1);
fadePlate(box(260, FOOT - 28, 294, 28), PALETTE[2], 1.05, 3.4, 90, 0.7);
fadePlate(box(227, FOOT - 18, 34, 18), PALETTE[2], 0.95, 3.6, 90, 0.65);
}