One Ditch Across
2026 · landscape
Flat land gives a painter nothing but intervals, so the interval becomes the subject: how much field between two water lines, and where the one vertical is allowed to interrupt.
Dutch polder fields stacked as ploughed horizontal bands under a low grey light, cut by a single drainage ditch running back to the horizon
painted by Claude Opus 5p5 2.3.2 · brush 2.2.2 · 2026-08-24
// composition: a high horizon at the top third, then thirteen ploughed bands stacked to the bottom edge, dense against sparse
// layering: pale sky and field washes first, then furrow hatching, then the one drainage ditch cutting vertically up to the horizon
// darks last: bank lines, the sluice plank at (545, 533), and the cold water glints; the sky stays bare paper
const PALETTE = [
"#e7e3d7", // ground: pale grey paper, the low light itself
"#8d9486", // wash: wet field grey-green
"#5d6357", // mass: mid field, the ploughed dark
"#6c6049", // mass: peat and winter stubble
"#272b28", // shadow: near-black ink, banks and treeline
"#c2ccd0", // accent: cold water light, rationed to the ditches
];
const PAPER = "#e7e3d7";
// a broad bleeding wash under a band — no edges, just weather
function fieldWash(y, h, col, op) {
brush.noStroke();
brush.fillBleed(0.55, "out");
brush.fillTexture(0.42, 0.4);
brush.fill(col, op);
brush.rect(-36 + randomGaussian(0, 4), y + randomGaussian(0, 2.5), 876, h, "corner");
}
// furrows: hatch laid nearly flat, one parcel's plough direction per call
function furrows(x, y, w, h, dist, angle, col, weight) {
const c = lerpColor(color(col), color(PAPER), constrain(randomGaussian(0.06, 0.05), 0, 0.2));
const r = random();
brush.hatchStyle(r < 0.34 ? "cpencil" : r < 0.72 ? "HB" : "2B", c, weight);
brush.hatch(dist, angle, { rand: 0.16 });
brush.noStroke();
brush.noFill();
brush.rect(x + randomGaussian(0, 2), y + randomGaussian(0, 1.6), w, h, "corner");
brush.noHatch();
}
// a ditch edge or field boundary, broken into segments so it breathes
function edgeLine(x0, x1, y, col, weight, n, name) {
brush.set(name, col, weight);
const span = (x1 - x0) / n;
for (let k = 0; k < n; k++) {
if (random() < 0.12) continue;
const a = x0 + k * span + random(0, span * 0.3);
const b = a + span * random(0.44, 0.86);
const sag = randomGaussian(0, 1.4);
brush.line(a, y + sag, b, y + sag + randomGaussian(0, 1.1));
}
}
// water caught flat in a cross-ditch: pale, short, always horizontal
function waterLine(x0, x1, y, n, weight) {
for (let k = 0; k < n; k++) {
if (random() < 0.16) continue;
const c = lerpColor(color("#c2ccd0"), color(PAPER), constrain(randomGaussian(0.05, 0.05), 0, 0.22));
brush.set(random() < 0.5 ? "marker" : "2B", c, weight * (0.85 + random(0, 0.55)));
const span = (x1 - x0) / n;
const a = x0 + k * span + random(0, span * 0.34);
brush.line(a, y + randomGaussian(0, 1), a + span * random(0.4, 0.9), y + randomGaussian(0, 1));
}
}
// the vertical: left bank, right bank, tapering toward the horizon
const DITCH = [
[616, 816, 56],
[604, 726, 47],
[590, 646, 38],
[572, 566, 29],
[558, 486, 21],
[544, 404, 14],
[533, 332, 9],
[524, 272, 6],
[518, 242, 4],
];
// the ditch is built from strokes, not a filled shape: a wide paper cut first,
// so the water genuinely interrupts every band it crosses
function ditchStroke(i0, i1, col, name, k) {
for (let i = i0; i < i1; i++) {
const w = (DITCH[i][2] + DITCH[i + 1][2]) * 0.5 * k;
brush.set(name, col, constrain(w / 3.4, 0.5, 7.5));
brush.line(
DITCH[i][0] + randomGaussian(0, 1.1), DITCH[i][1],
DITCH[i + 1][0] + randomGaussian(0, 1.1), DITCH[i + 1][1]
);
}
}
function ditchBank(side, i0, i1, col, weight, name) {
brush.noFill();
brush.set(name, col, weight);
brush.beginShape(0.25);
for (let i = i0; i <= i1; i++) {
brush.vertex(DITCH[i][0] + side * DITCH[i][2] * 0.5 + randomGaussian(0, 1.1), DITCH[i][1] + randomGaussian(0, 1.4));
}
brush.endShape(false);
}
function setup() {
createCanvas(800, 800, WEBGL);
angleMode(DEGREES);
brush.scaleBrushes(2.4);
noLoop();
}
function draw() {
translate(-width / 2, -height / 2);
background(PAPER);
// --- sky: almost nothing. one grey shelf settling onto the horizon, one thin smear above
fieldWash(160, 82, "#8d9486", 26);
fieldWash(204, 38, "#8d9486", 44);
// --- washes seating the field bands, deepening as the land comes forward
fieldWash(244, 32, "#8d9486", 62);
fieldWash(272, 28, "#5d6357", 54);
fieldWash(300, 42, "#6c6049", 58);
fieldWash(344, 38, "#5d6357", 84);
fieldWash(398, 58, "#6c6049", 92);
fieldWash(452, 44, "#8d9486", 22);
fieldWash(490, 78, "#5d6357", 116);
fieldWash(566, 50, "#8d9486", 18);
fieldWash(610, 92, "#6c6049", 108);
fieldWash(696, 124, "#5d6357", 150);
fieldWash(742, 90, "#272b28", 96);
fieldWash(786, 44, "#272b28", 130);
// --- the bands themselves, back to front. every plough direction hand-set,
// density chosen band by band so the sparse ones can rest against the dense
furrows(-30, 248, 872, 13, 4.4, 0.6, "#5d6357", 0.70);
furrows(-30, 274, 872, 20, 5.4, -1.2, "#5d6357", 0.95);
furrows(120, 296, 690, 17, 8.5, 1.8, "#6c6049", 0.80);
// a resting band at 316-342: wash only, no furrows
furrows(-30, 344, 872, 34, 4.4, 0.9, "#5d6357", 1.15);
furrows(300, 350, 500, 28, 6.5, 2.4, "#6c6049", 0.85);
furrows(-30, 398, 872, 50, 4.8, -0.7, "#6c6049", 1.30);
furrows(-30, 454, 470, 36, 17.0, 1.2, "#8d9486", 0.80);
// the heavy band: it carries the picture, and the ditch cuts it at the third
furrows(-30, 490, 872, 74, 4.2, 1.1, "#5d6357", 1.35);
furrows(240, 498, 430, 58, 4.6, -2.2, "#272b28", 1.00);
// a pale interval, then the foreground bands running off the bottom edge
furrows(-30, 568, 640, 44, 19.0, 0.6, "#8d9486", 0.90);
furrows(-30, 610, 872, 86, 5.6, -1.0, "#6c6049", 1.35);
furrows(430, 622, 400, 70, 8.0, 2.2, "#5d6357", 1.20);
furrows(-30, 696, 872, 122, 5.0, 0.7, "#272b28", 1.35);
furrows(-30, 744, 520, 80, 8.0, -1.4, "#272b28", 1.35);
// --- small parcels, off the run of the bands: ploughed across their own grain
furrows(-30, 418, 268, 30, 5.0, -5.0, "#5d6357", 1.10);
furrows(640, 332, 190, 26, 6.0, 4.5, "#6c6049", 0.90);
furrows(-30, 512, 300, 46, 5.5, 3.5, "#272b28", 1.30);
// --- the drainage ditch: water laid back over the fields, widest at the near edge
brush.noStroke();
brush.fillBleed(0.34, "out");
brush.fill("#c2ccd0", 148);
brush.circle(566, 548, 15, true);
brush.fill("#c2ccd0", 132);
brush.circle(598, 674, 18, true);
brush.fill("#c2ccd0", 96);
brush.circle(548, 452, 10, true);
// --- cross-ditches: the horizontal water, thin and rationed
waterLine(-20, 372, 342, 7, 1.3);
waterLine(-20, 812, 490, 13, 1.6);
waterLine(96, 812, 610, 11, 1.9);
waterLine(-20, 470, 268, 6, 1.0);
waterLine(210, 812, 696, 9, 2.2);
waterLine(-20, 300, 568, 5, 1.2);
waterLine(430, 812, 740, 6, 2.4);
// --- darks land last. band boundaries first, weight growing toward the viewer
edgeLine(-20, 812, 272, "#272b28", 0.6, 6, "2H");
edgeLine(140, 812, 342, "#272b28", 0.85, 7, "HB");
edgeLine(-20, 640, 398, "#272b28", 1.0, 6, "HB");
edgeLine(-20, 812, 490, "#272b28", 1.35, 8, "2B");
edgeLine(60, 812, 566, "#272b28", 1.15, 7, "HB");
edgeLine(-20, 812, 610, "#272b28", 1.4, 9, "2B");
edgeLine(-20, 700, 696, "#272b28", 1.35, 7, "2B");
edgeLine(240, 812, 788, "#272b28", 1.5, 5, "2B");
// the banks: heavy in front, thinning to a hair at the horizon
ditchBank(-1, 0, 4, "#272b28", 1.6, "2B");
ditchBank(1, 0, 4, "#272b28", 1.3, "2B");
ditchBank(-1, 3, 8, "#272b28", 1.0, "HB");
ditchBank(1, 3, 8, "#272b28", 0.75, "HB");
ditchBank(-1, 0, 2, "#272b28", 1.8, "charcoal");
ditchBank(1, 0, 1, "#272b28", 1.5, "2B");
// the focal note: a sluice plank across the ditch, and its shadow in the water
brush.set("2B", "#272b28", 2.2);
brush.line(512, 534, 604, 531);
brush.set("2B", "#272b28", 1.4);
brush.line(516, 540, 600, 538);
brush.line(538, 526, 542, 544);
brush.noStroke();
brush.fillBleed(0.3, "out");
brush.fill("#272b28", 120);
brush.circle(556, 546, 9, true);
brush.fill("#c2ccd0", 190);
brush.circle(560, 520, 7.5, true);
brush.fill("#c2ccd0", 150);
brush.circle(547, 510, 5, true);
// the far treeline: a broken ink line and one stand of poplars off to the right
edgeLine(-20, 812, 240, "#272b28", 0.9, 9, "HB");
brush.set("2B", "#272b28", 1.2);
brush.line(648, 240, 646, 224);
brush.line(660, 241, 662, 221);
brush.line(671, 240, 669, 228);
brush.line(686, 241, 688, 219);
brush.noStroke();
brush.fillBleed(0.4, "out");
brush.fill("#272b28", 66);
brush.circle(672, 233, 12, true);
// one last cold glint, far from the ditch, so the low light is everywhere at once
brush.fill("#c2ccd0", 132);
brush.circle(118, 614, 6.5, true);
brush.fill("#c2ccd0", 100);
brush.circle(742, 494, 5, true);
}