Santorini
2026 · city
I left every sunlit wall as bare paper and drew only its arrises, so the town holds together as one white mass, and kept the rock under it small and broken so nothing competes with the domes.
oia along the caldera rim from the castle end — packed whitewashed cubes stepping down a steep wedge, three blue domes mid-slope, a broken rock ledge and a thin ruled sea below
painted by Claude Opus 5p5 2.3.2 · brush 2.2.2 · 2026-08-30
// composition: a letterpress vignette of Oia on the caldera rim, seen along the rim from the
// Byzantine castle at the west end — the classic view. The land is a steep wedge: high at the upper
// left, where three terraces of whitewashed cubes stack on top of one another, and falling away to
// the lower right until it is a single row of houses and then nothing. The town is the subject;
// under its footing the rock is only the ledge it stands on: three small overlapping masses at
// different values and hatch angles, under a third of the print's height, their feet a jagged line
// of short straight runs with spurs and notches, breaking into crumbs and then dashes before the
// print's midpoint. The sea is raised to just under that foot — a narrow band of ruled dashes
// thinning to bare paper at the lower left. There is no sky: the paper is the sky.
//
// four facts I may not fudge:
// 1 proportion — a dome is a true hemisphere, its diameter equal to the drum it stands on, and the
// drum is short (about half the dome's radius). The cubes are wider than tall; the windows are
// tiny squares, never large, because these are 2.6 m rooms cut for shade.
// 2 ordering — the churches sit INSIDE the cascade, houses above and behind them, houses below and
// in front; nothing rises above a dome except its cross. The cliff is the lowest built thing, its
// top edge is the town's own footing, and the water is at its foot — never behind the town.
// 3 material — whitewashed lime over volcanic tuff: a sunlit wall is BARE PAPER, drawn only by its
// arrises. Only a return turned from the sun and the strip under the parapet take a stone
// half-plate, so the town reads as one solid white mass against the dark cliff. The cliff is warm
// tuff banded oxblood, gullied vertically, ink over its plunge. The domes are flat blue plaster.
// 4 site — Oia stands on the rim about 120 m above the water. The cliff below it is a face, not a
// slope: it falls straight into deep water. The houses are flat-roofed, packed with shared walls,
// every roof the terrace of the house above; skafta are barrel-vaulted. No pitched roof, no tree.
//
// counts drawn: 3 blue domes on 3 drums, 3 crosses, 3 drum lights per drum (9), 1 bell-cote wall
// with 2 arched bell openings and its cross, 5 upper-terrace cubes, 8 middle-terrace cubes,
// 12 front-terrace cubes (4 of them barrel-vaulted skafta), 2 skafta cut into the rock face,
// 3 short gullies, 3 rock masses, 6 stair flights, 9 terrace walls, 1 bougainvillea, 4 figures.
//
// layering: paper flecks; the ledge (three rock masses, oxblood band, shaded lower halves, short
// gullies, spurs, its skafta, terrace walls and stairs spilling over it); the sea at its foot;
// the upper terrace; the middle terrace; the three churches and the bell-cote; the front terrace over them; then stairs, parapets, the accent and the
// figures; then the last darks — the shadow the town throws over the cliff's lip and the crisp ends.
const PALETTE = [
"#efe6d2", // paper — warm cream sheet, and every sunlit whitewashed wall
"#2f3a44", // ink — slate-navy line, window slots, every over-plate
"#4e7a8c", // dome — the painted blue of Anastasis and its neighbours
"#d9cfb6", // stone — the half-plate on a shaded whitewashed return
"#d4b483", // tuff — the caldera cliff's warm body
"#8b3a2f", // oxblood — the red band in the cliff's strata
"#5d7f88", // caldera — the ruled water at the cliff's foot
"#a8452c", // bougainvillea — the one warm accent
];
// the town's footing: the line every front-terrace house stands on, and the cliff's top edge.
const FOOT = (x) => 422 + (x - 168) * 0.352;
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 / door / bell opening
const slot = (x, y, w, h) => plate(box(x, y, w, h), PALETTE[1], 1.1, 1.5, 90, 0.2);
// the upper half of an ellipse, ruled as n chords — a vault crown, a bell opening's head
const arcLine = (cx, cy, rx, ry, n, w, name) => {
for (let i = 0; i < n; i++) {
const a0 = Math.PI + (i / n) * Math.PI, a1 = Math.PI + ((i + 1) / n) * Math.PI;
ink(cx + Math.cos(a0) * rx, cy + Math.sin(a0) * ry, cx + Math.cos(a1) * rx, cy + Math.sin(a1) * ry, w, name);
}
};
// a narrow gully scoured straight down the cliff face — the mark that says the face is vertical
const gully = (xt, yt, xb, yb, wt, wb) =>
fadePlate([[xt, yt], [xt + wt, yt], [xb + wb, yb], [xb, yb]], PALETTE[1], 1.15, 3.0, 88, 0.6);
// one whitewashed cube. The sunlit front is BARE PAPER: no left edge (its neighbour owns that wall),
// no outline box — only the parapet cap, the right arris, the base, and the shaded return beyond it.
const cubeAt = (x, base, w, h, sw, nWin, tone, vault) => {
const dy = sw * 0.6, top = base - h;
const ret = [[x + w, base], [x + w + sw, base - dy], [x + w + sw, top - dy], [x + w, top]];
if (tone) halfPlate(box(x, top, w, h), PALETTE[3], 1.05, 3.2, 54); // a front only half turned to the sun
halfPlate(box(x, top, w, 9), PALETTE[3], 1.2, 2.3, 62); // the shadow under the parapet
halfPlate(ret, PALETTE[3], 1.3, 2.2, 70); // the return, turned from the sun
plate(shift(ret, 1.3, 0.7), PALETTE[1], 1.05, 3.2, 84, 0.3); // ink over the shade face
// the shadow the cube throws forward onto the terrace roof below it
fadePlate([[x - 1, base], [x + w + sw, base - dy], [x + w + sw, base - dy + 9], [x - 1, base + 9]], PALETTE[1], 1.0, 3.4, 0, 0.7);
if (vault) {
arcLine(x + w / 2, top + 4, w / 2, w * 0.3, 9, 0.9, "pen"); // the barrel's crown
slot(x + w * 0.36, base - h * 0.55, w * 0.28, h * 0.5); // its dark mouth
arcLine(x + w * 0.5, base - h * 0.55, w * 0.14, w * 0.13, 6, 0.8, "pen");
} else {
ink(x - 0.5, top, x + w, top, 0.8, "pen"); // the parapet cap — a fine edge, not a box outline
}
ink(x + w, top, x + w + sw, top - dy, 0.75, "pen"); // the parapet running back
ink(x + w, top, x + w, base, 1.05); // the arris — the seam between this house and the next
ink(x + w + sw, top - dy, x + w + sw, base - dy, 0.75, "pen");
ink(x - 1, base, x + w, base, 0.9); // the footing
const ww = constrain(w * 0.11, 3.4, 5.4), wh = ww * 1.1;
for (let k = 0; k < nWin; k++) {
const wx = x + 6 + k * ((w - 11) / max(nWin, 1)) + g(0, 0.5, -1.2, 1.2);
slot(wx, base - h * 0.62 + g(0, 1.8, -4, 4), ww, wh);
if (k === 0 && !vault && h > 46) slot(wx + 1, base - h * 0.3, ww * 0.85, wh * 1.8); // a door under it
}
};
// a skafto cut into the tuff itself: a whitewashed arched front pressed into the cliff face
const skaftoAt = (x, base, w, h) => {
const r = w / 2, sp = base - h;
halfPlate(box(x, sp - r * 0.9, w, h + r * 0.9), PALETTE[3], 1.2, 2.6, 48);
arcLine(x + r, sp, r, r * 0.9, 9, 0.85, "pen");
ink(x, sp, x, base, 0.75, "pen");
ink(x + w, sp, x + w, base, 0.85);
ink(x - 1, base, x + w + 1, base, 1.0);
slot(x + w * 0.34, base - h * 0.86, w * 0.3, h * 0.86);
};
// a hemisphere on a short drum, the cross above — the one blue in the print, the one-second read
const churchAt = (cx, base, r, drumH, bodyW, bodyH) => {
const bx = cx - bodyW / 2, spring = base - bodyH - drumH, rw = 9;
// the white body: bare paper, a stone return on the right, cornice and footing ruled
const bret = [[bx + bodyW, base], [bx + bodyW + rw, base - 6], [bx + bodyW + rw, base - 6 - bodyH], [bx + bodyW, base - bodyH]];
halfPlate(bret, PALETTE[3], 1.3, 2.2, 66);
plate(shift(bret, 1.3, 0.7), PALETTE[1], 1.05, 3.2, 80, 0.3);
halfPlate(box(bx, base - bodyH, bodyW, 6), PALETTE[3], 1.15, 2.4, 60);
ink(bx - 1, base - bodyH, bx + bodyW + rw + 1, base - bodyH - 6, 1.1); // cornice
ink(bx, base - bodyH, bx, base, 0.8, "pen");
ink(bx + bodyW, base - bodyH, bx + bodyW, base, 1.1);
ink(bx - 1, base, bx + bodyW + rw, base - 6, 1.1);
// the drum: paper again, ruled, three small round-headed lights, its right side in shade
ink(cx - r, spring, cx - r, spring + drumH, 0.8, "pen");
ink(cx + r, spring, cx + r, spring + drumH, 1.0);
ink(cx - r - 1, spring + drumH, cx + r + 1, spring + drumH, 1.0);
for (let i = 0; i < 3; i++) {
const lx = cx - r * 0.62 + i * r * 0.62;
slot(lx - 1.5, spring + 3.5, 3.0, drumH - 5.5);
arcLine(lx, spring + 3.5, 1.6, 1.6, 5, 0.7, "pen");
}
plate([[cx + r * 0.5, spring], [cx + r + 1, spring], [cx + r + 1, spring + drumH], [cx + r * 0.5, spring + drumH]], PALETTE[1], 1.0, 3.6, 88, 0.3);
// the dome — a true hemisphere, blue, laid twice so the plate holds solid
const dome = [];
for (let i = 0; i <= 20; i++) {
const a = Math.PI + (i / 20) * Math.PI;
dome.push([cx + Math.cos(a) * r, spring + Math.sin(a) * r]);
}
plate(dome, PALETTE[2], 1.5, 1.9, 60, 0.28);
plate(dome, PALETTE[2], 1.25, 3.4, 106, 0.3);
const shade = dome.filter((p) => p[0] >= cx - r * 0.1).concat([[cx - r * 0.1, spring]]);
plate(shift(shade, 1.5, 1), PALETTE[1], 1.1, 3.1, 116, 0.3); // ink over the shade half
ink(cx - r - 1, spring, cx + r + 1, spring, 1.0); // the springing course
// the cross
ink(cx, spring - r, cx, spring - r - 11, 1.6, "charcoal");
ink(cx - 4, spring - r - 7.5, cx + 4, spring - r - 7.5, 1.3, "charcoal");
};
const stairRun = (sx, sy, n, dx, dy, tread) => {
for (let i = 0; i < n; i++) {
const px = sx + dx * i + g(0, 0.6, -1.3, 1.3), py = sy + dy * i + g(0, 0.5, -1.1, 1.1);
ink(px, py, px + tread, py, 0.8, "pen");
ink(px + tread, py, px + tread, py + dy, 0.7, "pen");
}
};
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[3]);
}
// 1 — the ledge the town stands on: not one wedge but three small rock masses that overlap,
// each at its own value and hatch angle, their feet a jagged line of short straight runs with
// spurs and notches. Nowhere is it deeper than about a quarter of the print — the town is the
// subject, this is only its footing. Its right end stops at x 474 and dissolves into dashes.
const ROCK_A = [ // the near mass under the crest, deepest and darkest
[160, 421], [178, 425], [179, 431], [205, 434], [206, 428], [232, 446],
[258, 450], [259, 459], [286, 463], [302, 470],
[305, 492], [287, 501], [272, 487], [254, 498], [236, 492], [214, 504],
[197, 494], [178, 500], [164, 487],
];
const ROCK_B = [ // the middle mass, paler and set back, overlapping A's right flank
[268, 454], [292, 464], [293, 457], [318, 471], [344, 478], [345, 487],
[372, 491], [398, 503],
[401, 514], [386, 505], [372, 517], [356, 504], [338, 514], [320, 501],
[302, 510], [282, 498],
];
const B_SHADE = [[278, 466], [304, 476], [330, 485], [358, 493], [386, 501], [401, 514],
[386, 505], [372, 517], [356, 504], [338, 514], [320, 501], [302, 510], [282, 498]];
const A_SHADE = [[166, 460], [200, 468], [232, 476], [262, 481], [292, 487], [305, 492],
[287, 501], [272, 487], [254, 498], [236, 492], [214, 504], [197, 494], [178, 500], [164, 487]];
plate(ROCK_A, PALETTE[4], 1.4, 2.4, 84, 0.3); // tuff body
halfPlate(ROCK_A, PALETTE[5], 1.0, 3.6, 62); // the red in the strata
halfPlate(A_SHADE, PALETTE[1], 1.25, 2.5, 74); // its lower band in shade
halfPlate(ROCK_B, PALETTE[4], 1.1, 3.2, 56); // the middle mass — open, so paper gaps it from A
halfPlate(B_SHADE, PALETTE[1], 1.2, 2.4, 64); // its shaded lower half, crossed so it cannot stripe
// two small rocky spurs jutting below the foot, so the underside is never one line
plate([[214, 503], [223, 515], [231, 506], [227, 499]], PALETTE[1], 1.2, 2.6, 78, 0.3);
plate([[330, 515], [340, 528], [350, 517], [345, 510]], PALETTE[1], 1.25, 2.7, 60, 0.3);
// the one true dark: the corner where the near face turns into the water
plate([[166, 458], [188, 478], [200, 492], [178, 500], [164, 487]], PALETTE[1], 1.2, 2.6, 82, 0.3);
// three short gullies, all on the near mass and none running the whole face
gully(196, 438, 202, 484, 6, 8);
gully(228, 452, 233, 479, 5, 7);
gully(264, 462, 268, 490, 4, 6);
// the lip, ruled run by run and deliberately broken — the town's footing meets rock in steps
for (let i = 0; i < 9; i++) {
if (i === 3 || i === 6) continue; // two breaks where paper shows through the seam
ink(ROCK_A[i][0], ROCK_A[i][1] + 1, ROCK_A[i + 1][0], ROCK_A[i + 1][1] + 1, g(1.15, 0.2, 0.8, 1.5));
}
for (let i = 0; i < 7; i++) {
if (i === 2) continue;
ink(ROCK_B[i][0], ROCK_B[i][1] + 1, ROCK_B[i + 1][0], ROCK_B[i + 1][1] + 1, g(1.0, 0.2, 0.7, 1.3));
}
ink(160, 421, 164, 487, 1.3); // the short near-vertical left end
ink(164, 487, 178, 500, 1.0);
ink(302, 470, 305, 492, 0.9, "pen"); // the seam where the middle mass laps the near one
ink(398, 503, 401, 517, 0.85, "pen");
// two skafta cut into the tuff just under the lip
skaftoAt(236, 460, 21, 11);
skaftoAt(326, 484, 19, 10);
// terrace walls and stairs spilling down over the rock, so town and rock interlock
stairRun(208, 434, 5, 5.4, 8.4, 5);
stairRun(302, 474, 4, 5.2, 8.0, 4.5);
for (let i = 0; i < 9; i++) {
const wx = 190 + i * 26, wy = FOOT(wx) + g(9, 2.5, 5, 14);
ink(wx, wy, wx + g(15, 3, 9, 21), wy + g(2.4, 1, 0.6, 4.2), 0.75, "pen");
if (i % 2 === 0) ink(wx, wy, wx, wy - g(6, 1.5, 3.5, 8.5), 0.7, "pen");
}
// past the middle mass the ledge stops being rock at all: two crumbs, then broken dashes
// thinning into bare paper, so the right end never tapers to a smooth point
plate([[416, 508], [426, 520], [435, 511], [429, 505]], PALETTE[1], 1.2, 2.8, 66, 0.3);
plate([[470, 528], [477, 537], [484, 529], [479, 524]], PALETTE[1], 1.15, 3.0, 74, 0.3);
for (let i = 0; i < 26; i++) {
const dx = 406 + i * 8, dy = FOOT(dx) + g(4, 1.8, 0.5, 8);
ink(dx, dy, dx + g(5.5, 1.6, 2, 9), dy + g(1.3, 0.7, 0, 2.8),
constrain(1.25 - i * 0.03, 0.5, 1.25), i % 3 === 0 ? "rotring" : "2B", PALETTE[1]);
}
// 2 — the caldera, raised to just under the ledge's foot: ruled dashes that thin to bare paper
const SEAF = (x) => 494 + (x - 164) * 0.15;
fadePlate([[168, 498], [240, 509], [312, 521], [386, 533], [428, 540],
[422, 552], [352, 546], [278, 534], [200, 524], [170, 514]], PALETTE[6], 1.15, 3.8, 0, 0.78);
brush.noStroke(); brush.noFill();
brush.hatchStyle("cpencil", PALETTE[6], 1.2);
brush.hatch(4.4, 0, { rand: 0.12, continuous: false, gradient: 0.6 });
brush.polygon([[176, 501], [252, 513], [326, 525], [396, 536], [424, 541],
[416, 549], [330, 538], [244, 526], [178, 513]]);
brush.noHatch();
for (let i = 0; i < 34; i++) {
const x0 = 172 + random(0, 226);
const len = constrain(randomGaussian(85, 55), 16, 190);
if (x0 + len > 424) continue;
const y = SEAF(x0 + len) + 3 + random(0, 22);
if (y > 558) continue;
ink(x0, y, x0 + len, y, g(1.1, 0.3, 0.6, 1.6), random() < 0.7 ? "2B" : "cpencil",
random() < 0.8 ? PALETTE[6] : PALETTE[1]);
}
// 3 — the crest of the wedge: two cubes on the highest ledge at the far left, wider than tall
let ax = 168;
for (let i = 0; i < 2; i++) {
const w = g(46, 3, 38, 54), h = g(44, 4, 36, 52);
cubeAt(ax, FOOT(ax) - 70 + g(0, 2, -4.5, 4.5), w, h, 12, 2, i === 1, false);
ax += w - g(2, 1.2, 0, 4);
}
// 4 — the middle terrace: nine cubes, stepping down and away, one of them a vaulted skafto.
// It runs on past the churches so the far tail of the town is never a single file of boxes.
let bx = 168;
for (let i = 0; i < 9; i++) {
const s = 1 - (bx - 168) * 0.00046;
const w = g(46, 3.4, 37, 56) * s, h = g(45, 4, 37, 54) * s;
cubeAt(bx, FOOT(bx) - 38 + g(0, 2, -4.5, 4.5), w, h, 11.5 * s, i % 3 === 0 ? 2 : 1, i % 2 === 1, i === 5);
bx += w - g(2, 1.2, 0, 4);
}
// 5 — the three churches, crowning the cascade on the crest line: the big dome on the left third
churchAt(262, FOOT(262) - 70, 24, 13, 40, 20);
churchAt(326, FOOT(326) - 70, 30, 15, 50, 22);
churchAt(392, FOOT(392) - 70, 25, 13, 42, 20);
// the bell-cote: a white wall pierced by two arched bell openings, a cross on its crown
const BX = 424, BY = FOOT(424) - 70, BW = 30, BH = 56;
halfPlate(box(BX + BW, BY - BH + 7, 7, BH - 7), PALETTE[3], 1.2, 2.4, 64);
plate(shift(box(BX + BW, BY - BH + 7, 7, BH - 7), 1.2, 0.6), PALETTE[1], 1.0, 3.4, 82, 0.3);
halfPlate(box(BX, BY - BH, BW, 6), PALETTE[3], 1.15, 2.4, 58);
ink(BX - 1, BY - BH, BX + BW + 1, BY - BH, 1.1);
ink(BX, BY - BH, BX, BY, 0.8, "pen");
ink(BX + BW, BY - BH, BX + BW, BY, 1.1);
ink(BX - 1, BY, BX + BW + 7, BY, 1.1);
for (let i = 0; i < 2; i++) {
const ox = BX + 5.5 + i * 11;
slot(ox, BY - BH + 12, 5.6, 14);
arcLine(ox + 2.8, BY - BH + 12, 3.4, 3.4, 7, 0.8, "pen");
}
ink(BX + BW / 2, BY - BH, BX + BW / 2, BY - BH - 9, 1.6, "charcoal");
ink(BX + BW / 2 - 3.4, BY - BH - 6, BX + BW / 2 + 3.4, BY - BH - 6, 1.3, "charcoal");
// 6 — the front terrace: twelve cubes on the lip itself, nearest and boldest, four of them skafta.
// Through the church span they are kept low so the domes stand clear above them.
let cx = 172;
for (let i = 0; i < 9; i++) {
const s = 1 - (cx - 172) * 0.00052;
const w = g(52, 3.6, 42, 62) * s, h = g(52, 5, 42, 62) * s;
cubeAt(cx, FOOT(cx) + g(0, 2, -4.5, 4.5), w, h, 13 * s, i % 3 === 2 ? 3 : 2, i % 2 === 0, i % 3 === 1);
cx += w - g(2.2, 1.2, 0, 4.2);
}
// 7 — the fabric that says people live here: outside stairs, parapet ticks, one bloom, four figures
stairRun(216, 358, 6, 6.2, 4.9, 6);
stairRun(310, 392, 6, 6.0, 5.2, 6);
stairRun(452, 478, 6, 5.8, 7.0, 5.5);
stairRun(556, 518, 5, 5.4, 8.0, 5);
for (let i = 0; i < 20; i++) ink(192 + i * 5.2, 342 + i * 1.8, 192 + i * 5.2, 347 + i * 1.8, 0.7, "pen");
for (let i = 0; i < 18; i++) ink(470 + i * 5.4, 480 + i * 1.9, 470 + i * 5.4, 485 + i * 1.9, 0.7, "pen");
// the far right of the town dissolves into low terrace walls on the rim, then into the bare nose
for (let i = 0; i < 7; i++) {
const x0 = 580 + i * 9;
ink(x0, FOOT(x0) - 9, x0 + g(6.5, 1.4, 3.5, 9), FOOT(x0) - 9 + 3.2, 0.8, "pen");
if (i % 2 === 0) ink(x0, FOOT(x0) - 9, x0, FOOT(x0) - 2, 0.7, "pen");
}
const bloom = [];
for (let i = 0; i < 12; i++) {
const a = (i / 12) * Math.PI * 2, rr = 10.5 * (0.62 + noise(i * 0.85 + 5) * 0.7);
bloom.push([466 + Math.cos(a) * rr, 500 + Math.sin(a) * rr * 0.82]);
}
plate(bloom, PALETTE[7], 1.4, 2.0, 44, 0.3);
ink(466, 508, 464, 521, 1.5, "charcoal");
const folk = [[200, 385], [206, 384], [396, 456], [520, 504]];
for (let i = 0; i < folk.length; i++) {
ink(folk[i][0], folk[i][1], folk[i][0] + g(0, 0.6, -1.2, 1.2), folk[i][1] - g(8, 0.8, 6.5, 9.5), 1.6, "charcoal");
}
// 8 — the last darks: the shadow the town throws over the cliff's lip, and the crisp ends
// laid in three short broken runs over the rock only — never one ruled diagonal
fadePlate([[166, 424], [292, 468], [290, 480], [164, 438]], PALETTE[1], 1.1, 3.2, 0, 0.72);
fadePlate([[300, 470], [396, 504], [394, 514], [298, 482]], PALETTE[1], 1.05, 3.4, 0, 0.72);
ink(168, 424, 168, 308, 0.9, "pen"); // the left end of the whole mass
ink(398, 503, 404, 508, 1.1);
}