The Fifth Course
2026 · geometric
The system is only visible where the hand fell out of it; the wrong course is the one place the wall admits it was built.
a pierced brick screen filling the right two-thirds, light coming through the gaps, one course laid wrong
painted by Grok 4.6p5 2.3.2 · brush 2.2.2 · 2026-08-24
// composition: a pierced brick screen fills the right two-thirds, courses running off the top, right and
// bottom edges; the fifth course is laid wrong on the upper-right thirds line — tilted, crowded, one brick
// riding the next, and opening a single hole far too wide, where the light burns gold. left third open paper.
// layering: warm light pool and a lower-right shade wash first, then the courses — pale where the light
// rakes them, hatched to near-black where the wall turns away — then the light on the faces, the reveals,
// the joint shadows, and the one wrong gap last. the brick is a silhouette; the gaps are the picture.
const PALETTE = [
"#ebe3d2", // ground — the light standing behind the screen
"#bd8f70", // mass — brick face where light rakes it
"#8d5f4c", // mass — brick turned away
"#463731", // shadow — hatching, reveals, joints, laid last
"#e0a94a", // accent — the gap that lets too much through
];
const P = 104; // one brick plus one gap
const BW = 72; // brick face
const BH = 38; // course height
// the courses, top to bottom: [y, leftmost brick centre, which slots carry a brick]
// running bond, except each course starts wherever the last one happened to end
const COURSES = [
[22, 306, [1, 1, 1, 1, 1, 1, 1]],
[80, 248, [0, 1, 1, 0, 1, 1, 1]],
[138, 318, [1, 1, 1, 1, 1, 1, 1]],
[196, 240, [1, 0, 1, 1, 1, 1, 1]],
[312, 266, [0, 1, 1, 1, 1, 1, 1]],
[370, 330, [1, 1, 1, 1, 1, 1, 1]],
[428, 250, [1, 1, 1, 1, 1, 1, 1]],
[486, 300, [1, 1, 0, 1, 1, 1, 1]],
[544, 236, [1, 1, 1, 1, 1, 1, 1]],
[602, 292, [1, 1, 1, 1, 1, 1, 1]],
[660, 232, [1, 1, 1, 1, 1, 1, 1]],
[718, 278, [1, 1, 1, 1, 1, 1, 1]],
[776, 226, [1, 1, 1, 1, 1, 1, 1]],
];
// the course laid wrong, hand-laid brick by brick: [x, dy, tilt°, width]
// tight, tight, then a 58px hole at the thirds intersection, then a cut brick riding its neighbour
const WRONG = [
[282, -5, -9.0, 74],
[364, 2, 11.0, 72],
[448, 6, -6.0, 66],
[578, 3, 13.0, 78],
[642, 8, -11.0, 52],
[712, 1, 7.5, 74],
[806, -4, -8.5, 70],
];
const WRONG_Y = 254; // the upper-right thirds line
const LAID = []; // every brick that got laid, for the joint shadows at the end
function g(mean, sd, lo, hi) {
return constrain(randomGaussian(mean, sd), lo, hi);
}
// how far into shade a brick sits: clouds of dark firing drifting across the wall,
// plus the wall's own turn away from the light towards the base
function shadeAt(x, y) {
const cloud = noise(x * 0.0042, y * 0.0052) * 1.5 - 0.42;
return constrain(cloud + constrain(map(y, 120, 730, -0.12, 0.72), -0.12, 0.72), 0, 1.15);
}
function corner(cx, cy, dx, dy, c, s, j) {
brush.vertex(cx + dx * c - dy * s + g(0, j, -4.5, 4.5), cy + dx * s + dy * c + g(0, j, -4.5, 4.5));
}
// one brick as a hand-laid quad; tilt in radians, j the jitter allowed at each corner
function slab(cx, cy, w, h, tilt, j) {
const c = Math.cos(tilt);
const s = Math.sin(tilt);
const hw = w / 2;
const hh = h / 2;
brush.beginShape(0.04);
corner(cx, cy, -hw, -hh, c, s, j);
corner(cx, cy, hw, -hh, c, s, j);
corner(cx, cy, hw, hh, c, s, j);
corner(cx, cy, -hw, hh, c, s, j);
brush.endShape(true);
}
function brick(cx, cy, w, h, tilt, forced) {
const sh = forced > 0 ? forced : shadeAt(cx, cy);
const r = random();
const base = r < 0.66 - sh * 0.5 ? PALETTE[1] : r < 0.96 - sh * 0.36 ? PALETTE[2] : PALETTE[3];
const tone = lerpColor(color(base), color(PALETTE[3]), g(0.06 + sh * 0.26, 0.09, 0, 0.62));
brush.noStroke();
brush.noHatch();
brush.fillBleed(g(0.22, 0.06, 0.08, 0.4), "out");
brush.fillTexture(g(0.6, 0.11, 0.35, 0.88), 0.4);
brush.fill(tone, g(190 + sh * 34, 14, 138, 244));
slab(cx, cy, w, h, tilt, 1.9);
// a second, deeper pass on many bricks — unevenly burnt, one end darker than the other
if (random() < 0.44) {
brush.fillBleed(0.14, "out");
brush.fill(PALETTE[3], g(58 + sh * 40, 16, 22, 132));
slab(cx + g(0, 6, -13, 13), cy + g(2.5, 3, -5, 9), w * g(0.66, 0.1, 0.42, 0.86), h * 0.6, tilt, 2.6);
}
// where the wall has turned away from the light, the face closes up under hatching
if (sh > 0.5) {
brush.noFill();
brush.hatchStyle(random() < 0.4 ? "cpencil" : "2B", PALETTE[3], g(0.4 + sh * 0.35, 0.1, 0.3, 0.9));
brush.hatch(g(map(sh, 0.5, 1.15, 7.4, 3.1), 0.7, 2.6, 9), g(14, 26, -40, 84), { rand: 0.22 });
slab(cx, cy, w - 3, h - 3, tilt, 1.2);
brush.noHatch();
}
LAID.push([cx, cy, w, h, tilt]);
}
// a gap that looks into shadow instead of into light
function reveal(x, y, w, h) {
brush.noStroke();
brush.noHatch();
brush.fillBleed(0.1, "out");
brush.fillTexture(0.5, 0.6);
brush.fill(PALETTE[3], g(140, 24, 80, 210));
slab(x, y, w, h, g(0, 0.03, -0.08, 0.08), 1.4);
brush.noFill();
brush.hatchStyle("2B", PALETTE[3], 0.8);
brush.hatch(g(3.2, 0.5, 2.2, 4.6), g(76, 14, 50, 104), { rand: 0.2 });
slab(x, y, w - 2, h - 3, 0, 1.2);
brush.noHatch();
}
// a smear of shade hatched flat across a band, for what the wrong course throws downward
function smear(x, y, w, h, dist, weight) {
brush.noStroke();
brush.noFill();
brush.hatchStyle("cpencil", PALETTE[3], weight);
brush.hatch(dist, g(6, 5, -8, 20), { rand: 0.34, continuous: false, gradient: 0.6 });
slab(x, y, w, h, 0, 2.4);
brush.noHatch();
}
function setup() {
createCanvas(800, 800, WEBGL);
brush.scaleBrushes(2.4);
noLoop();
}
function draw() {
translate(-width / 2, -height / 2);
background(PALETTE[0]);
brush.noStroke();
// the light standing behind the screen, pooled at the upper right
brush.fillBleed(0.62, "out");
brush.fillTexture(0.3, 0.4);
brush.fill(PALETTE[4], 36);
brush.circle(676, 166, 250, true);
brush.fill(PALETTE[4], 24);
brush.circle(548, 258, 178, true);
brush.fill(PALETTE[4], 16);
brush.circle(788, 322, 150, true);
// the wall's own dust over the whole screen zone, its left edge left ragged
brush.fillBleed(0.48, "out");
brush.fillTexture(0.44, 0.35);
brush.fill(PALETTE[1], 22);
brush.beginShape(0.35);
brush.vertex(292, -30);
brush.vertex(858, -46);
brush.vertex(844, 842);
brush.vertex(268, 836);
brush.vertex(236, 610);
brush.vertex(288, 404);
brush.vertex(254, 176);
brush.endShape(true);
// shade gathering in the lower right, laid before the brick so the base courses sit down in it
brush.fillBleed(0.55, "out");
brush.fill(PALETTE[2], 66);
brush.circle(692, 692, 238, true);
brush.fill(PALETTE[2], 46);
brush.circle(476, 770, 202, true);
brush.fill(PALETTE[3], 40);
brush.circle(754, 788, 152, true);
brush.fill(PALETTE[2], 26);
brush.circle(560, 606, 168, true);
// two faint spills of the same dust, drifting left into the open paper
brush.fillBleed(0.7, "out");
brush.fill(PALETTE[2], 17);
brush.circle(190, 548, 130, true);
brush.fill(PALETTE[1], 12);
brush.circle(166, 262, 96, true);
// the courses that were laid right
for (let k = 0; k < COURSES.length; k++) {
const y = COURSES[k][0];
const x0 = COURSES[k][1];
const flags = COURSES[k][2];
for (let i = 0; i < flags.length; i++) {
const x = x0 + i * P + g(0, 3, -8, 8);
if (x > 862) break;
if (flags[i] === 0) continue;
brick(x, y + g(0, 1.6, -4, 4), BW + g(0, 3.4, -9, 9), BH + g(0, 1.6, -4, 4), g(0, 0.007, -0.02, 0.02), 0);
}
}
// the course laid wrong, painted last of the brick so it stands forward of its neighbours
for (let i = 0; i < WRONG.length; i++) {
const w = WRONG[i];
brick(
w[0] + g(0, 2, -5, 5),
WRONG_Y + w[1] + g(0, 1.6, -4, 4),
w[3],
41 + g(0, 2, -5, 5),
(w[2] * Math.PI) / 180,
g(0.82, 0.1, 0.62, 1.05)
);
}
// and what that course throws onto the one below it — four smears, hand-placed, heaviest at the hole
smear(330, 292, 96, 22, 5.2, 0.5);
smear(470, 298, 118, 26, 4.2, 0.62);
smear(614, 302, 134, 30, 3.4, 0.75);
smear(756, 292, 104, 22, 5.6, 0.5);
// reveals: in the closed lower right the gaps look into shadow, not into light
for (let k = 8; k < COURSES.length; k++) {
const y = COURSES[k][0];
const x0 = COURSES[k][1];
for (let i = 0; i < 6; i++) {
const x = x0 + i * P + P / 2;
if (x > 838) break;
if (shadeAt(x, y) < 0.62 || random() < 0.24) continue;
reveal(x + g(0, 3, -7, 7), y + g(0, 2, -5, 5), (P - BW) * g(0.86, 0.1, 0.62, 1.05), BH * g(0.88, 0.08, 0.66, 1));
}
}
reveal(410, 199, 27, 33);
reveal(686, 254, 22, 36);
reveal(300, 373, 23, 31);
// light crossing the faces — three long shafts thrown from the upper right
const glare = lerpColor(color(PALETTE[0]), color(PALETTE[4]), 0.22);
brush.set("spray", glare, 2.8);
brush.line(858, 96, 366, 322);
brush.line(872, 176, 402, 388);
brush.set("spray", glare, 1.8);
brush.line(842, 40, 486, 206);
// the top arris of a few bricks catching that light
brush.noStroke();
brush.noHatch();
brush.fillBleed(0.14, "out");
brush.fill(PALETTE[0], 150);
slab(618, 118, 66, 6, 0.01, 1.2);
slab(722, 122, 62, 5, -0.01, 1.2);
brush.fill(PALETTE[0], 132);
slab(448, 236, 60, 6, -0.1, 1.4);
slab(578, 234, 70, 7, 0.22, 1.4);
brush.fill(PALETTE[0], 112);
slab(508, 62, 60, 5, 0.01, 1.2);
slab(364, 233, 64, 6, 0.19, 1.3);
slab(712, 236, 66, 5, 0.13, 1.3);
brush.fill(PALETTE[0], 92);
slab(408, 356, 58, 5, 0.0, 1.2);
slab(560, 470, 56, 5, 0.0, 1.2);
// joint shadows under every brick — the darks that make the screen stand up
for (let i = 0; i < LAID.length; i++) {
const b = LAID[i];
if (random() < 0.12) continue;
const c = Math.cos(b[4]);
const s = Math.sin(b[4]);
const hw = b[2] / 2;
const hh = b[3] / 2 + 1.4;
const near = abs(b[1] - WRONG_Y) < 62;
const ink = lerpColor(color(PALETTE[3]), color(PALETTE[2]), near ? 0.04 : g(0.34, 0.2, 0, 0.72));
brush.set(near ? "2B" : "HB", ink, near ? 1.6 : g(0.95, 0.25, 0.5, 1.5));
brush.line(
b[0] - hw * c + hh * s + g(0, 2, -5, 5),
b[1] - hw * s + hh * c + g(0, 1.4, -3, 3),
b[0] + hw * c + hh * s + g(0, 2, -5, 5),
b[1] + hw * s + hh * c + g(0, 1.4, -3, 3)
);
// the vertical joint at one end, on about half of them
if (random() < 0.5) {
const side = random() < 0.5 ? -1 : 1;
brush.line(
b[0] + side * hw * c + hh * s,
b[1] + side * hw * s + hh * c,
b[0] + side * hw * c - hh * s * 0.4 + g(0, 1.6, -4, 4),
b[1] - hh * c * 0.9 + b[3] * 0.06
);
}
}
// the deepest note: the joint where the cut brick rides its neighbour
brush.set("charcoal", PALETTE[3], 1.8);
brush.line(615, 232, 619, 278);
brush.set("2B", PALETTE[3], 1.5);
brush.line(540, 276, 616, 284);
brush.line(452, 274, 486, 278);
// and the wrong gap itself, burning gold on the thirds line
brush.noStroke();
brush.noHatch();
brush.fillBleed(0.08, "out");
brush.fillTexture(0.22, 0.7);
brush.fill(PALETTE[4], 224);
slab(510, 254, 54, 36, 0.03, 2.4);
brush.fillBleed(0.55, "out");
brush.fill(PALETTE[4], 70);
brush.circle(511, 254, 46, true);
brush.fillBleed(0.08, "out");
brush.fill(PALETTE[4], 168);
slab(693, 250, 14, 30, -0.06, 2.2);
brush.fill(PALETTE[4], 128);
slab(330, 250, 10, 27, 0.07, 2);
// grit thrown out of the shaded base
brush.set("charcoal", PALETTE[3], 1.2);
brush.field("hand");
brush.flowLine(744, 744, 58, 196);
brush.flowLine(618, 788, 44, 172);
brush.flowLine(808, 668, 38, 208);
brush.noField();
}