Marrakech
2026 · city
I counted the Koutoubia's four storeys and set the shaft at a true six to one, then let its garden — palms, a low wall, a calèche — hold the foot of the sheet.
the koutoubia minaret over its garden, seen from the jemaa el-fnaa side
painted by Claude Sonnet 5p5 2.3.2 · brush 2.2.2 · 2026-08-30
// composition: the Koutoubia Mosque seen from the Jemaa el-Fnaa side, across its gardens — a
// square rose-sandstone minaret stands left of the print's centre, its prayer hall running low
// and long beside and below it (green-tiled ridge roof, rose walls); the garden's palms, a low
// wall, a calèche and a few figures sit in front. No sky, no ground band beyond the print.
// facts: (1) proportion — the shaft is a true 6:1 tower, 12.8m wide against 77m tall, drawn as a
// 42×252 plate; (2) ordering — hall is built against the minaret's base and reads behind it,
// garden foliage and figures are drawn last, in front of both; (3) material — rose-pink
// sandstone shaft/walls (lit halfPlate, shade plate + ink over-plate), one verdigris faience
// band, a verdigris-tiled hall roof, gilt only on the topmost orb; (4) site — the mosque rises
// over its own garden wall, not a street, with palms and a horse-drawn calèche for scale.
// counts: 4 storeys of blind arches, each a different motif — bottom to top: 2 tall narrow
// arches / 3 interlocking lobed arches / 2 pairs of small arches under a roundel / 1 wide arch
// flanked by 2 slits; every storey carried in simplified form onto the shaded face, and the
// three storey cornices ruled straight across both faces; 1 verdigris tile band; 5 merlons
// on the crenellated parapet; 2 lantern arches; 3 orbs on the spar, decreasing upward, the
// topmost gilt; 4 palms; 1 calèche; 2 figures; 5 hall windows.
const PALETTE = [
"#efe6d2", // paper — warm cream sheet
"#2f3a44", // ink — slate-navy line and shadow plate
"#c9a58e", // rose — the minaret and hall's sandstone
"#5d7f88", // verdigris — the faience band and the hall's tiled roof
"#d9cfb6", // stone — the garden wall
"#7a8c6a", // moss — the palms
"#c9a24a", // gilt — the topmost orb, and nothing else
];
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 — gradient hatch, 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[1], w || 1.0);
brush.line(x1, y1, x2, y2);
};
// a dark window / arch slot
const slot = (x, y, w, h) => plate(box(x, y, w, h), PALETTE[1], 1.1, 1.5, 90, 0.2);
// a small grainy disc — the roundel, the orbs
const dot = (x, y, d, 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.circle(x, y, d);
brush.noHatch();
};
// the outline of a blind arch — jambs rising to a springline, then a head;
// lobes > 0 scallops the head into a lobed (multifoil) arch. inset shrinks it for the ink slot.
const archPath = (x, y, w, h, lobes, inset) => {
const cx = x + w / 2, sy = y + (w / 2) * 1.3;
const r = w / 2 - inset, rise = (w / 2) * 1.3 - inset;
const pts = [[cx - r, y + h], [cx - r, sy]];
for (let i = 1; i < 10; i++) {
const rad = ((180 - (i / 10) * 180) * Math.PI) / 180;
const lob = lobes ? 1 - 0.2 * Math.abs(Math.sin(lobes * rad)) : 1;
pts.push([cx + Math.cos(rad) * r * lob, sy - Math.sin(rad) * rise * lob]);
}
pts.push([cx + r, sy], [cx + r, y + h]);
return pts;
};
// a blind arch: an ink slot recessed inside a pen-ruled arch outline
const blindArch = (x, y, w, h, wt, lobes) => {
plate(archPath(x, y, w, h, lobes, Math.min(1.1, w * 0.19)), PALETTE[1], 0.8, 2.0, 90, 0.18);
brush.noFill();
brush.set("pen", PALETTE[1], wt);
brush.polygon(archPath(x, y, w, h, lobes, 0));
};
// a slender ink slit — the narrow openings flanking storey four's wide arch
const slit = (x, y, w, h) => plate(box(x, y, w, h), PALETTE[1], 0.8, 2.0, 90, 0.18);
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 prayer hall: long, low, beside and below the minaret, reading behind it
const HX0 = 371, HX1 = 600, EAVE = 555, HBASE = 612;
const roof = [[HX0 - 4, EAVE], [(HX0 + HX1) / 2, EAVE - 16], [HX1 + 4, EAVE], [HX1 + 4, EAVE + 6], [HX0 - 4, EAVE + 6]];
halfPlate(roof, PALETTE[3], 1.2, 2.2, 20);
plate(shift(roof, 1, 1), PALETTE[1], 1.0, 3.4, 15, 0.3);
ink(HX0 - 4, EAVE, (HX0 + HX1) / 2, EAVE - 16, 1.0);
ink(HX1 + 4, EAVE, (HX0 + HX1) / 2, EAVE - 16, 1.0);
halfPlate(box(HX0, EAVE + 6, HX1 - HX0, HBASE - EAVE - 6), PALETTE[2], 1.15, 2.6, 68);
fadePlate(box(HX0, EAVE + 6, HX1 - HX0, 9), PALETTE[1], 0.9, 3.4, 0, 0.6); // eave shadow
ink(HX0, EAVE + 6, HX1, EAVE + 6, 1.1); // eave line
ink(HX0, HBASE - 20, HX1, HBASE - 20, 0.9); // impost line
for (let i = 0; i < 5; i++) {
const x = HX0 + 22 + i * 40;
slot(x + g(0, 0.4, -1, 1), EAVE + 20, 6, 20);
}
plate(box(HX1, EAVE + 8, 9, HBASE - EAVE - 8), PALETTE[1], 1.0, 3.2, 90, 0.3); // far end into shade
ink(HX0, EAVE + 6, HX0, HBASE, 0.9);
ink(HX1 + 9, EAVE + 8, HX1 + 9, HBASE, 1.0);
// 2 — the minaret shaft: four storeys, each a different blind-arch arrangement
const CX = 340, SHAFT_TOP = 356, BASE = 608;
const litFace = box(319, SHAFT_TOP, 24, BASE - SHAFT_TOP);
const shadeFace = box(343, SHAFT_TOP, 18, BASE - SHAFT_TOP);
halfPlate(litFace, PALETTE[2], 1.35, 2.2, 78);
plate(litFace, PALETTE[2], 1.2, 3.6, 90, 0.3);
// shade face: a MID-TONE rose plate under a LIGHT, open ink over-plate — darker than the lit
// face, never near-black; the darks in this tower live only in the slots and under the parapet.
plate(shadeFace, PALETTE[2], 1.25, 2.6, 92, 0.3);
plate(shift(shadeFace, 0.8, 0.6), PALETTE[1], 0.8, 5.0, 96, 0.3);
ink(319, SHAFT_TOP, 319, BASE, 1.0);
ink(361, SHAFT_TOP, 361, BASE, 1.0);
// storey cornices — ruled straight across BOTH faces so the tower reads as stacked storeys,
// each with a fine ledge line under it that continues into the shade
for (const cy of [524, 467, 410]) {
ink(317, cy, 363, cy, 1.1);
ink(343, cy + 2.4, 363, cy + 2.4, 0.6, "pen");
ink(319, cy + 2.2, 343, cy + 2.2, 0.5, "pen");
}
// storey 1 (bottom, 524-608): a pair of tall narrow blind arches
blindArch(322.8, 540, 5, 56, 0.8);
blindArch(333.7, 540, 5, 56, 0.8);
blindArch(345.4, 542, 2.2, 52, 0.6); // simplified onto the shade face
blindArch(355, 542, 2.2, 52, 0.6);
// storey 2 (467-524): a row of three interlocking lobed arches
for (let i = 0; i < 3; i++) blindArch(321.4 + i * 6.2, 480, 5.9, 34, 0.75, 3);
blindArch(345.4, 482, 2.6, 30, 0.6, 3);
blindArch(354.8, 482, 2.6, 30, 0.6, 3);
// storey 3 (410-467): a band of small paired arches under a roundel
dot(331, 420.5, 5.5, PALETTE[1], 0.95, 1.6, 62, 0.2);
brush.noFill();
brush.set("pen", PALETTE[1], 0.6);
brush.circle(331, 420.5, 9.5);
for (let i = 0; i < 4; i++) blindArch(321 + (i >> 1) * 12.2 + (i & 1) * 5.4, 433, 3.2, 25, 0.6);
dot(350.5, 421, 4.5, PALETTE[1], 0.9, 1.6, 62, 0.2); // simplified on the shade face
blindArch(345.8, 434, 2, 23, 0.55);
blindArch(355.2, 434, 2, 23, 0.55);
// storey 4 (356-410): one wide arch flanked by two slits
blindArch(326.8, 370, 8.4, 31, 0.85);
slit(320.8, 378, 2.4, 21);
slit(338.8, 378, 2.4, 21);
blindArch(346.2, 372, 3.4, 28, 0.7);
slit(356.4, 379, 1.6, 20);
// the faience band — thin verdigris plate, the one tile course
plate(box(318, 348, 44, 8), PALETTE[3], 1.1, 1.6, 0, 0.2);
ink(318, 348, 362, 348, 0.9);
ink(318, 356, 362, 356, 0.9);
fadePlate(box(319, 356, 42, 8), PALETTE[1], 1.0, 3.0, 0, 0.75); // the deep dark under the parapet
// the crenellated parapet — five merlons
const parapetPts = [[319, 348]];
for (let i = 0; i < 5; i++) {
const x0 = 321 + i * 8;
parapetPts.push([x0, 348], [x0, 334], [x0 + 6, 334], [x0 + 6, 348]);
}
parapetPts.push([361, 348]);
plate(parapetPts, PALETTE[2], 1.2, 1.6, 90, 0.2);
for (let i = 0; i < 5; i++) {
const x0 = 321 + i * 8;
ink(x0, 334, x0, 348, 0.7, "pen");
ink(x0 + 6, 334, x0 + 6, 348, 0.7, "pen");
}
// the lantern turret — smaller square, two small arches
const TB = 334, TT = 306;
const litT = box(329, TT, 13, TB - TT);
const shadeT = box(342, TT, 9, TB - TT);
halfPlate(litT, PALETTE[2], 1.2, 2.0, 70);
plate(shadeT, PALETTE[2], 1.2, 2.4, 90, 0.3);
plate(shift(shadeT, 1, 1), PALETTE[1], 0.9, 3.9, 94, 0.3);
ink(329, TT, 351, TT, 1.0);
slot(332, TT + 6, 5, 12);
slot(343, TT + 6, 5, 12);
// the small tiled cap and the spar with three orbs, decreasing upward
const APEX = [340, 286];
halfPlate([[329, TB - 28], [APEX[0], TB - 28], APEX], PALETTE[3], 1.15, 1.9, 74);
plate([[APEX[0], TB - 28], [351, TB - 28], APEX], PALETTE[3], 1.3, 1.9, 98, 0.3);
plate([[APEX[0] + 1, TB - 27], [352, TB - 27], [APEX[0] + 1, 287]], PALETTE[1], 1.0, 3.2, 102, 0.3);
ink(329, TB - 28, APEX[0], APEX[1], 0.8);
ink(351, TB - 28, APEX[0], APEX[1], 0.8);
ink(340, APEX[1], 340, 258, 1.0);
ink(340, 286, 340, 277, 3.2, "charcoal", PALETTE[1]); // bottom orb, decreasing upward
ink(340, 275, 340, 269, 2.4, "charcoal", PALETTE[1]); // middle orb
ink(340, 267, 340, 262, 1.7, "charcoal", PALETTE[6]); // topmost orb — the gilt accent
// deep shadow at the shaft's foot, where it meets the courtyard
fadePlate(box(318, BASE - 26, 44, 26), PALETTE[1], 1.1, 3.0, 90, 0.7);
// 3 — the garden: a low wall, four palms, a calèche, two figures — all in front
plate(box(150, 616, 500, 5), PALETTE[4], 1.1, 1.6, 0, 0.2);
ink(160, 620, 640, 620, 1.2);
ink(140, 619, 152, 618, 0.8, "2B"); // the wall dissolving into paper at each end
ink(648, 618, 660, 617, 0.8, "2B");
const palmAt = (px, py, s) => {
const trunkLean = g(0, 0.7, -1.6, 1.6);
ink(px, py, px + trunkLean, py - 34 * s, 1.6, "charcoal", PALETTE[1]);
const crown = [];
for (let i = 0; i < 12; i++) {
const a = (i / 12) * Math.PI * 2;
const rr = 20 * s * (0.6 + noise(i * 0.8 + px * 0.02) * 0.7);
crown.push([px + trunkLean + Math.cos(a) * rr, py - 34 * s + Math.sin(a) * rr * 0.55]);
}
halfPlate(crown, PALETTE[5], 1.3, 2.0, 35);
plate(shift(crown.slice(3, 8).concat([[px + trunkLean, py - 34 * s]]), 1.5, 1.5), PALETTE[1], 1.2, 3.0, 45, 0.3);
};
palmAt(196, 614, 0.9);
palmAt(256, 610, 1.05);
palmAt(432, 612, 0.85);
palmAt(602, 608, 1.0);
// the calèche — a horse-drawn carriage, charcoal ticks and two small wheels
dot(474, 616, 9, PALETTE[1], 1.4, 1.4, 90, 0.2);
dot(500, 616, 9, PALETTE[1], 1.4, 1.4, 90, 0.2);
ink(468, 604, 508, 604, 2.4, "charcoal");
ink(508, 604, 520, 596, 1.4, "charcoal"); // the shaft to the horse
ink(520, 596, 528, 611, 1.6, "charcoal"); // the horse, a single dark tick
ink(528, 596, 528, 609, 1.3, "charcoal");
// two figures on the garden path
ink(300, 613, 300, 604, 1.6, "charcoal");
ink(560, 611, 559, 602, 1.5, "charcoal");
}