The Fold Wins
2026 · geometric
A map only tells you where things are until you fold it; after that the creases are the strongest lines on the sheet, and one panel decides to be night.
a road map folded once too often, its panels climbing lower-left to upper-right, one of them nearly black
painted by Mistral Medium 3.1p5 2.3.2 · brush 2.2.2 · 2026-08-24
// composition: one dominant fold-diagonal climbs from the lower-left to the upper-right, its panels
// stepping in hard tonal jumps; a single near-black plane sits on the upper-right third and holds everything.
// layering: broad dry marker fibres build the paper planes, then charcoal creases and the printed road land last.
// the paper breathes in the upper-left and lower-right wedges; two faint crease echoes keep the void intentional.
const PALETTE = [
"#ece4d3", // ground — map paper, warm and slightly foxed
"#cbc4ae", // light — ridge faces turned toward the window
"#8f9490", // mass — the ordinary grey of a panel lying flat
"#5c6266", // shadow — valley faces
"#1e2226", // ink — the one dark plane, and every crease
"#b0512c", // accent — printed roads, rationed
];
// three rails running lower-left to upper-right: the ridge edge, the long spine crease, the valley edge.
// stations are hand-set, none of the three parallel to another — that is what makes it a fold and not a stripe.
const RAIL_A = [[-40, 400], [112, 344], [250, 292], [372, 216], [500, 168], [628, 96], [754, 44], [860, -20]];
const RAIL_M = [[-35, 596], [126, 540], [270, 470], [388, 418], [520, 336], [644, 274], [770, 206], [872, 142]];
const RAIL_B = [[-30, 800], [150, 758], [296, 692], [404, 630], [540, 570], [658, 488], [782, 436], [884, 364]];
// A paper plane is a family of broad, imperfect fibres. The open seams between them are the tooth
// of the map stock: materially richer, and more honest, than a perfect filled quadrilateral.
function weave(top, bottom, from, to, col, weight, strands, name) {
brush.noFill();
for (let k = 1; k <= strands; k++) {
const t = k / (strands + 1);
brush.set(name, col, constrain(randomGaussian(weight, 1.1), weight - 2.4, weight + 2.4));
if (to - from === 1) {
const ax = lerp(top[from][0], bottom[from][0], t) + randomGaussian(0, 1.4);
const ay = lerp(top[from][1], bottom[from][1], t) + randomGaussian(0, 1.4);
const bx = lerp(top[to][0], bottom[to][0], t) + randomGaussian(0, 1.4);
const by = lerp(top[to][1], bottom[to][1], t) + randomGaussian(0, 1.4);
brush.beginShape(0.18);
brush.vertex(ax, ay);
brush.vertex(lerp(ax, bx, 0.5) + randomGaussian(0, 1.1), lerp(ay, by, 0.5) + randomGaussian(0, 1.1));
brush.vertex(bx, by);
brush.endShape(false);
} else {
brush.beginShape(0.18);
for (let i = from; i <= to; i++) {
brush.vertex(
lerp(top[i][0], bottom[i][0], t) + randomGaussian(0, 1.4),
lerp(top[i][1], bottom[i][1], t) + randomGaussian(0, 1.4),
);
}
brush.endShape(false);
}
}
}
function creasePath(points, col, weight, name, wander) {
brush.noFill();
brush.set(name, col, weight);
brush.beginShape(0.16);
for (let i = 0; i < points.length; i++) {
brush.vertex(points[i][0] + randomGaussian(0, wander), points[i][1] + randomGaussian(0, wander));
}
brush.endShape(false);
}
// one whole-arm crease: the brush supplies the broken edge, while the endpoints refuse the ruler
function crease(x1, y1, x2, y2, col, w, name, wander) {
brush.noFill();
brush.set(name, col, w);
brush.line(
x1 + randomGaussian(0, wander * 0.55),
y1 + randomGaussian(0, wander * 0.55),
x2 + randomGaussian(0, wander),
y2 + randomGaussian(0, wander),
);
}
function setup() {
createCanvas(800, 800, WEBGL);
brush.scaleBrushes(2.4);
noLoop();
}
function draw() {
translate(-width / 2, -height / 2);
background("#ece4d3");
// --- the unpainted ground is the pale air; no atmospheric wash softens the Constructivist cut
// --- planes made from dry fibres: light ridge, cooler valley, then the night face laid over both.
weave(RAIL_A, RAIL_M, 0, 7, "#cbc4ae", 24, 5, "marker");
weave(RAIL_M, RAIL_B, 0, 4, "#8f9490", 27, 5, "marker");
weave(RAIL_M, RAIL_B, 4, 6, "#cbc4ae", 25, 5, "marker");
weave(RAIL_A, RAIL_M, 1, 2, "#8f9490", 5.5, 11, "2B");
weave(RAIL_M, RAIL_B, 2, 3, "#5c6266", 4.8, 11, "2B");
weave(RAIL_M, RAIL_B, 6, 7, "#5c6266", 5.5, 10, "2B");
weave(RAIL_A, RAIL_M, 4, 5, "#1e2226", 9, 12, "charcoal"); // one night plane; every other value answers it
// --- three long edges, then six cross-folds: geometry stated once, not outlined panel by panel.
creasePath(RAIL_M, "#1e2226", 1.55, "2B", 1.8);
creasePath(RAIL_A, "#5c6266", 1.7, "2B", 1.5);
creasePath(RAIL_B, "#5c6266", 1.3, "HB", 1.9);
crease(112, 344, 150, 758, "#5c6266", 1.1, "HB", 2.0);
crease(250, 292, 296, 692, "#5c6266", 1.3, "2B", 1.8);
crease(372, 216, 404, 630, "#5c6266", 1.1, "HB", 2.2);
crease(500, 168, 540, 570, "#1e2226", 1.35, "2B", 1.7);
crease(628, 96, 658, 488, "#1e2226", 1.25, "2B", 1.8);
crease(754, 44, 782, 436, "#5c6266", 1.0, "HB", 2.2);
// --- light on the ridge: a thread of bare paper laid back over the spine where it turns hardest
brush.noFill();
brush.set("2H", "#ece4d3", 1.6);
brush.line(392, 410, 512, 330);
brush.line(524, 330, 632, 272);
brush.set("2H", "#ece4d3", 1.2);
brush.line(258, 288, 366, 214);
brush.line(140, 534, 260, 468);
// --- printed road, crossing the folds and stepping sideways at every crease
brush.set("pen", "#b0512c", 1.1);
brush.beginShape(0.4);
brush.vertex(232, 646);
brush.vertex(266, 566);
brush.vertex(288, 500);
brush.endShape(false);
brush.beginShape(0.4);
brush.vertex(296, 466);
brush.vertex(322, 402);
brush.vertex(344, 340);
brush.endShape(false);
brush.set("pen", "#b0512c", 0.9);
brush.beginShape(0.5);
brush.vertex(352, 300);
brush.vertex(400, 258);
brush.vertex(462, 236);
brush.endShape(false);
brush.line(586, 448, 640, 404);
brush.line(648, 396, 690, 356);
// --- two rust ticks: a town on the dark plane and a quiet coordinate out on the paper
brush.noStroke();
brush.fillBleed(0.3, "out");
brush.fill("#b0512c", 232);
brush.circle(566, 214, 6.4, true);
brush.fill("#b0512c", 128);
brush.circle(742, 682, 4.1, true);
// --- two crease echoes far out in the empty quarter, so the paper is not merely blank
crease(624, 706, 800, 646, "#8f9490", 1.1, "HB", 2.8);
crease(694, 772, 830, 726, "#8f9490", 0.9, "HB", 2.6);
}