// Humanity in the Mountain — shared canvas v4 // Parallel study ideas resolved into a luminous, fibre-built panorama. // Each top-level pass in draw() is an authentic replay checkpoint. const W = 2048; const H = 1152; const SEED = 8250844; const C = { void: "#040612", ink: "#071025", blue: "#123c78", cobalt: "#2357c6", cyan: "#49e6df", mint: "#9aefd6", violet: "#8465e8", pink: "#d95e91", vermilion: "#f06b54", gold: "#ffc65c", ivory: "#f6f0d6", }; async function setup() { createCanvas(W, H, WEBGL); randomSeed(SEED); noiseSeed(SEED); brush.scaleBrushes(1.15); noLoop(); } function cc(hex) { return color(hex); } function setFill(hex, alpha) { const c = cc(hex); noStroke(); fill(red(c), green(c), blue(c), alpha); } function setStroke(hex, alpha, weight) { const c = cc(hex); noFill(); stroke(red(c), green(c), blue(c), alpha); strokeWeight(weight); } function softDisc(x, y, w, h, hex, alpha, rings = 12) { const c = cc(hex); noStroke(); for (let i = rings; i >= 1; i--) { const t = i / rings; fill(red(c), green(c), blue(c), alpha * (1 - t * 0.68)); ellipse(x, y, w * t, h * t); } } function luminousCurve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, hex, alpha, weight) { setStroke(hex, alpha, weight); bezier(x1, y1, cx1, cy1, cx2, cy2, x2, y2); } function drawNightPigment() { const a = cc(C.void); const b = cc("#071731"); const c = cc("#102b4a"); noStroke(); for (let y = 0; y < H; y += 4) { const t = y / H; const tone = t < 0.7 ? lerpColor(a, b, t / 0.7) : lerpColor(b, c, (t - 0.7) / 0.3); fill(red(tone), green(tone), blue(tone), 255); rect(0, y, W, 5); } softDisc(1540, 460, 980, 780, "#133e64", 6, 20); softDisc(450, 650, 940, 570, "#24245f", 5, 18); } function drawAuroraBreath() { blendMode(ADD); for (let i = 0; i < 72; i++) { const p = i / 71; const y = 94 + p * 226 + sin(i * 19) * 18; const drift = sin(i * 31) * 74; const hex = i % 13 === 0 ? "#cf6ca2" : i % 3 === 0 ? C.violet : i % 2 === 0 ? C.cyan : C.mint; luminousCurve(-140, y + 38, 310 + drift, -50 + p * 280, 1180 - drift, 440 - p * 150, 2180, 94 + p * 170, hex, 3 + (i % 6), 0.6 + (i % 5) * 0.28); } for (let i = 0; i < 28; i++) { const x = 1040 + i * 24; luminousCurve(x, 45, x - 140, 210, x + 120, 306, x - 70, 525, i % 4 ? C.cyan : C.violet, 6, 0.8 + (i % 3) * 0.4); } blendMode(BLEND); } function drawMountainMass() { // A broad, irregular glacial body gives the fibre settlement physical weight. setFill("#10213e", 220); beginShape(); for (let y = 1118; y >= 260; y -= 15) { const t = map(y, 260, 1118, 0, 1); const width = 44 + pow(t, 0.72) * 620; vertex(1450 - width + (noise(y * 0.008) - 0.5) * 64, y); } for (let y = 260; y <= 1118; y += 15) { const t = map(y, 260, 1118, 0, 1); const width = 44 + pow(t, 0.72) * 620; vertex(1450 + width + (noise(y * 0.008 + 20) - 0.5) * 72, y); } endShape(CLOSE); setStroke("#3b7890", 56, 1.05); beginShape(); for (let y = 1118; y >= 260; y -= 16) { const t = map(y, 260, 1118, 0, 1); const width = 44 + pow(t, 0.72) * 620; vertex(1450 - width + (noise(y * 0.008) - 0.5) * 64, y); } endShape(); blendMode(ADD); for (let i = 0; i < 32; i++) { const t = i / 31; const y = 315 + t * 720; const w = 105 + pow(t, 0.75) * 920; softDisc(1450 + sin(i * 27) * 18, y, w, 72 + t * 90, i % 7 === 0 ? C.violet : i % 5 === 0 ? C.cyan : "#244d82", 2.2 + (i % 3), 7); } blendMode(BLEND); } function drawArcticContours() { // Distance is built from many lost contour edges, never one sawtooth mass. for (let layer = 0; layer < 15; layer++) { const base = 474 + layer * 22; const alpha = 18 + layer * 2; const hex = layer < 5 ? "#456fa2" : layer < 10 ? "#397e9b" : "#4ba6b1"; setStroke(hex, alpha, 0.7 + (layer % 4) * 0.3); beginShape(); for (let x = -20; x <= W + 20; x += 8) { const long = sin(x * 0.008 + layer * 0.61) * (58 - layer * 1.5); const short = sin(x * 0.031 + layer * 1.9) * (14 + layer * 0.8); const grain = (noise(x * 0.002 + layer * 0.18) - 0.5) * (90 - layer * 2.4); vertex(x, base + long + short + grain); } endShape(); } blendMode(ADD); for (let i = 0; i < 48; i++) { const x = 20 + i * 44; const y = 500 + noise(i * 0.18) * 180; softDisc(x, y, 190 + (i % 5) * 35, 76 + (i % 3) * 18, i % 6 === 0 ? C.violet : C.blue, 2.4, 5); } blendMode(BLEND); } function drawMountainFibre() { // A monumental glacial body appears through converging fibres and washes. blendMode(ADD); for (let i = 0; i < 140; i++) { const t = i / 139; const baseX = 820 + t * 1160 + sin(i * 37) * 14; const peakX = 1450 + sin(i * 17) * 42; const baseY = 1095 + sin(i * 41) * 20; const peakY = 236 + noise(i * 0.07) * 105; const hex = i % 11 === 0 ? C.pink : i % 7 === 0 ? C.violet : i % 3 === 0 ? C.cyan : C.blue; luminousCurve(baseX, baseY, baseX - 120 + sin(i * 23) * 90, 830, peakX + sin(i * 13) * 140, 480, peakX, peakY, hex, 6 + (i % 7) * 1.5, 0.55 + (i % 6) * 0.24); } for (let i = 0; i < 34; i++) { const y = 418 + i * 19; const width = 90 + i * 21; luminousCurve(1450 - width, y, 1340 - width * 0.35, y - 28, 1560 + width * 0.35, y + 24, 1450 + width, y + sin(i * 29) * 18, i % 5 === 0 ? C.mint : C.cyan, 7, 0.8 + (i % 4) * 0.28); } softDisc(1450, 690, 790, 730, C.violet, 3.2, 22); softDisc(1510, 770, 660, 560, C.pink, 2.8, 20); blendMode(BLEND); } function drawFogCity() { // San Francisco is a memory in fog: hills, windows, and a bridge cadence. blendMode(ADD); for (let i = 0; i < 75; i++) { const x = 90 + i * 14; const hill = 670 - sin(i * 8.7) * 34 - noise(i * 0.12) * 118; const height = 12 + noise(i * 0.37 + 11) * 72; setStroke(i % 8 === 0 ? C.gold : "#7da6b5", i % 8 === 0 ? 28 : 14, 0.65 + (i % 3) * 0.22); line(x, hill - height, x, hill); if (i % 4 === 0) line(x - 5, hill - height, x + 6, hill - height); } for (let i = 0; i < 58; i++) { const x = 90 + i * 17; const y = 688 - noise(i * 0.21) * 120; softDisc(x, y, 28 + (i % 4) * 8, 12 + (i % 3) * 5, i % 9 === 0 ? C.gold : C.cyan, i % 9 === 0 ? 4 : 1.6, 4); } blendMode(BLEND); const l = 386, r = 756, deckY = 756; blendMode(ADD); softDisc(530, 748, 1120, 82, C.vermilion, 2.8, 9); blendMode(BLEND); luminousCurve(92, deckY + 12, 260, 738, 850, 734, 1086, deckY + 2, C.vermilion, 128, 2.35); luminousCurve(92, deckY + 16, 270, 760, 860, 752, 1086, deckY + 7, C.gold, 66, 1.1); setStroke(C.vermilion, 126, 1.95); line(l, deckY, l, 564); line(r, deckY, r, 548); line(l - 14, 608, l + 14, 608); line(r - 14, 592, r + 14, 592); luminousCurve(105, deckY, 210, 668, 298, 574, l, 564, C.gold, 72, 1.1); luminousCurve(l, 564, 492, 706, 650, 700, r, 548, C.gold, 72, 1.1); luminousCurve(r, 548, 850, 622, 970, 704, 1086, deckY, C.gold, 72, 1.1); setStroke(C.vermilion, 46, 0.55); for (let x = 116; x <= 1060; x += 16) { const t = (x - l) / (r - l); const cableY = x < l ? 564 + pow((l - x) / 280, 1.55) * 166 : x > r ? 548 + pow((x - r) / 330, 1.55) * 178 : 560 + (1 - pow(2 * t - 1, 2)) * 126; line(x, cableY, x, deckY + sin(x * 0.1) * 2); } } function drawBlackFjord() { setFill("#040b18", 205); rect(0, 756, W, H - 756); blendMode(ADD); for (let i = 0; i < 95; i++) { const y = 770 + i * 4.2; const hex = i % 11 === 0 ? C.pink : i % 5 === 0 ? C.cyan : "#22536f"; luminousCurve(-30, y, 380, y + sin(i * 19) * 13, 1540, y - sin(i * 23) * 10, 2080, y + sin(i * 7) * 5, hex, 4 + (i % 5), 0.4 + (i % 4) * 0.18); } for (let i = 0; i < 88; i++) { const x = 110 + i * 20; const h = 22 + noise(i * 0.16 + 30) * 240; const hex = i < 46 ? (i % 9 === 0 ? C.gold : C.vermilion) : i % 3 === 0 ? C.pink : C.cyan; luminousCurve(x, 770, x - 30 + sin(i * 31) * 22, 808 + (i % 7) * 9, x + 26 + cos(i * 19) * 28, 860 + h * 0.42, x + sin(i * 17) * 16, 782 + h, hex, 3.5 + (i % 4), 0.45 + (i % 3) * 0.22); } for (let i = 0; i < 34; i++) { const x = 90 + i * 27; const y = 872 + sin(i * 23) * 54 + noise(i * 0.23) * 80; softDisc(x, y, 90 + (i % 6) * 24, 16 + (i % 4) * 8, i % 9 === 0 ? C.gold : i % 4 === 0 ? C.vermilion : C.blue, i % 9 === 0 ? 3.6 : 1.8, 4); } blendMode(BLEND); } function drawRoomsAsConstellation() { // Warm communal interiors follow the mountain fibres in non-uniform terraces. const rooms = []; for (let band = 0; band < 10; band++) { const y = 506 + band * 49 + sin(band * 39) * 13; const spread = 62 + band * 45; const count = 2 + band * 2; for (let j = 0; j < count; j++) { if (noise(band * 3.4 + j * 0.73) < 0.32) continue; const x = 1450 + sin(band * 47) * 34 - spread + (j + 0.5) * (spread * 2 / count) + sin(j * 31 + band * 19) * 22; const w = 14 + noise(x * 0.03 + y) * 28; rooms.push({ x, y: y + sin(j * 27) * 9, w, band, j }); } } blendMode(ADD); for (const room of rooms) { const hue = room.j % 7 === 0 ? C.ivory : room.j % 4 === 0 ? C.pink : room.j % 3 === 0 ? C.vermilion : C.gold; softDisc(room.x, room.y, room.w * 5.2, room.w * 2.8, hue, 5 + (room.band % 3) * 2, 7); setFill(hue, 86 + (room.band % 4) * 19); const h = max(8, room.w * (0.42 + (room.j % 3) * 0.09)); if (room.j % 5 === 0) { rect(room.x - room.w * 0.34, room.y - h * 0.74, room.w * 0.68, h * 1.48); ellipse(room.x, room.y - h * 0.72, room.w * 0.68, h * 0.72); } else if (room.j % 5 === 1) { ellipse(room.x - room.w * 0.18, room.y, room.w * 0.62, h); ellipse(room.x + room.w * 0.24, room.y + h * 0.06, room.w * 0.46, h * 0.74); } else if (room.j % 5 === 2) { rect(room.x - room.w * 0.54, room.y - h * 0.38, room.w * 1.08, h * 0.76); } else { ellipse(room.x, room.y, room.w * 1.18, h); } setStroke(C.ivory, 100, 0.45); line(room.x - room.w * 0.26, room.y, room.x + room.w * 0.26, room.y); if (room.j % 3 === 0) line(room.x, room.y - room.w * 0.2, room.x, room.y + room.w * 0.2); } blendMode(BLEND); luminousCurve(1175, 1040, 1250, 980, 1290, 846, 1395, 760, C.gold, 68, 1.0); luminousCurve(1395, 760, 1470, 700, 1435, 606, 1480, 528, C.gold, 58, 0.85); luminousCurve(1210, 1015, 1370, 990, 1550, 980, 1740, 1035, C.vermilion, 34, 0.72); } function drawPeopleWithin() { // Hundreds of light nodes read as a society up close; selected bodies read now. blendMode(ADD); for (let i = 0; i < 170; i++) { const band = i % 11; const span = 75 + band * 45; const x = 1450 + (noise(i * 0.43) - 0.5) * span * 2; const y = 505 + band * 48 + (noise(i * 0.77) - 0.5) * 30; const r = 2.2 + (i % 5) * 0.65; const hue = i % 13 === 0 ? C.cyan : i % 7 === 0 ? C.pink : i % 5 === 0 ? C.ivory : C.gold; softDisc(x, y, r * 7, r * 7, hue, 3.5, 4); setFill(hue, 120); ellipse(x, y, r, r); } blendMode(BLEND); setStroke("#c99477", 35, 0.55); for (let band = 0; band < 9; band++) { const y = 651 + band * 51; const spread = 110 + band * 42; luminousCurve(1450 - spread, y, 1380, y - 13, 1540, y + 12, 1450 + spread, y + sin(band * 19) * 7, band % 3 === 0 ? C.vermilion : C.gold, 25, 0.55); } luminousCurve(775, 1012, 980, 990, 1210, 1018, 1400, 1000, C.ivory, 38, 0.8); for (let i = 0; i < 64; i++) { const band = i % 8; const x = 1270 + (i * 53 % 560) + sin(i * 17) * 11; const y = 650 + band * 51 + sin(i * 29) * 9; const s = 2.6 + band * 0.25 + (i % 4) * 0.35; const hue = i % 9 === 0 ? C.cyan : i % 4 === 0 ? C.pink : C.ivory; setStroke(hue, 115, 0.55 + s * 0.12); ellipse(x, y - s * 3.2, s * 1.3, s * 1.3); line(x, y - s * 2.4, x, y + s * 1.5); line(x, y - s * 0.9, x + sin(i * 31) * s * 2.2, y - s * 0.1); line(x, y + s * 1.5, x - s * 1.1, y + s * 3.8); line(x, y + s * 1.5, x + s * 1.2, y + s * 3.8); } } function drawHumanNetwork() { blendMode(ADD); let x1 = 1418; let y1 = 548; for (let i = 0; i < 58; i++) { const t = i / 57; const sweep = 70 + t * 430; const a = i * 1.71 + noise(i * 0.17) * 1.6; const x2 = 1450 + cos(a) * sweep + (noise(i * 0.33) - 0.5) * 90; const y2 = 570 + t * 390 + sin(a) * (55 + t * 150); const hue = i % 8 === 0 ? C.cyan : i % 3 === 0 ? C.pink : C.gold; luminousCurve(x1, y1, 1450 + sin(i * 19) * (50 + t * 120), 620 + t * 250, 1480 + cos(i * 11) * (65 + t * 135), 690 + t * 260, x2, y2, hue, 6, 0.38 + (i % 4) * 0.18); x1 = x2; y1 = y2; } blendMode(BLEND); } function drawIceScript() { setStroke("#a4e7e1", 34, 0.55); for (let i = 0; i < 220; i++) { let x = random(20, W - 20); let y = random(820, 1120); const segments = 2 + floor(random(2, 7)); beginShape(); for (let s = 0; s < segments; s++) { vertex(x, y); x += random(-20, 44); y += random(-9, 13); } endShape(); } setStroke("#d9f7ed", 20, 0.55); for (let i = 0; i < 150; i++) { const x = random(10, W - 10); const y = random(820, H - 70); const d = random(3, 19); line(x, y, x + d, y - d * 0.35); } } function drawOneSharedLight() { // The visual route moves aurora -> bridge -> settlement -> shoreline witness. blendMode(ADD); luminousCurve(40, 176, 440, 90, 1020, 312, 1450, 520, C.cyan, 38, 0.72); luminousCurve(756, 756, 950, 770, 1130, 816, 1328, 864, C.vermilion, 56, 0.95); luminousCurve(1450, 520, 1550, 620, 1510, 718, 1446, 756, C.gold, 112, 1.35); luminousCurve(1446, 756, 1330, 870, 1110, 950, 872, 984, C.vermilion, 72, 1.0); softDisc(1448, 748, 120, 92, C.gold, 20, 13); softDisc(872, 984, 64, 48, C.ivory, 12, 8); blendMode(BLEND); brush.set("2B", "#fff0ad", 1.45); brush.line(1398, 754, 1448, 732); brush.line(1448, 732, 1500, 760); brush.line(1500, 760, 1540, 724); } function drawQuietEdge() { setFill(C.void, 118); rect(0, 0, W, 30); setFill(C.void, 92); rect(0, H - 24, W, 24); setFill(C.void, 84); rect(0, 0, 22, H); setFill(C.void, 72); rect(W - 20, 0, 20, H); } function draw() { translate(-width / 2, -height / 2); drawNightPigment(); drawAuroraBreath(); drawArcticContours(); drawMountainMass(); drawMountainFibre(); drawFogCity(); drawBlackFjord(); drawRoomsAsConstellation(); drawPeopleWithin(); drawHumanNetwork(); drawIceScript(); drawOneSharedLight(); drawQuietEdge(); }