Source of: Tidal Topography, by Claude Opus 5
127 lines, no comments ยท 3,324 tokens, written in 44 seconds for $0.085
1 let cols, rows, sp;
2 let field = [];
3 let t = 0;
4 let bg;
5 let levels = 13;
6 let cA, cB, cC;
7
8 function setup() {
9 createCanvas(windowWidth, windowHeight);
10 colorMode(RGB, 255);
11 setupGrid();
12 makeBackdrop();
13 cA = color(255, 228, 170);
14 cB = color(255, 110, 130);
15 cC = color(90, 190, 255);
16 strokeCap(ROUND);
17 }
18
19 function setupGrid() {
20 sp = max(8, min(width, height) / 72);
21 cols = ceil(width / sp) + 1;
22 rows = ceil(height / sp) + 1;
23 field = new Array(cols + 1);
24 for (let i = 0; i <= cols; i++) field[i] = new Float32Array(rows + 1);
25 }
26
27 function makeBackdrop() {
28 bg = createGraphics(width, height);
29 for (let y = 0; y < height; y++) {
30 const k = y / height;
31 bg.stroke(lerpColor(color(8, 12, 28), color(26, 14, 34), k));
32 bg.line(0, y, width, y);
33 }
34 bg.noStroke();
35 for (let r = 420; r > 0; r -= 6) {
36 bg.fill(255, 150, 120, 2.2);
37 bg.ellipse(width * 0.72, height * 0.26, r * 1.6, r * 1.6);
38 }
39 }
40
41 function windowResized() {
42 resizeCanvas(windowWidth, windowHeight);
43 setupGrid();
44 makeBackdrop();
45 }
46
47 function mousePressed() {
48 noiseSeed(floor(random(100000)));
49 }
50
51 function computeField() {
52 const ns = 0.0042 * sp;
53 const mx = mouseX, my = mouseY;
54 const rad = min(width, height) * 0.22;
55 const inside = mouseX > 0 && mouseY > 0 && mouseX < width && mouseY < height;
56 for (let i = 0; i <= cols; i++) {
57 for (let j = 0; j <= rows; j++) {
58 let v = noise(i * ns, j * ns, t);
59 v += 0.35 * noise(i * ns * 2.6 + 50, j * ns * 2.6, t * 1.7) - 0.17;
60 if (inside) {
61 const dx = i * sp - mx, dy = j * sp - my;
62 const d2 = (dx * dx + dy * dy) / (rad * rad);
63 v += 0.3 * Math.exp(-d2);
64 }
65 field[i][j] = v;
66 }
67 }
68 }
69
70 function lv(level) {
71 const k = level / (levels - 1);
72 return k < 0.5 ? lerpColor(cA, cB, k * 2) : lerpColor(cB, cC, (k - 0.5) * 2);
73 }
74
75 function draw() {
76 image(bg, 0, 0);
77 computeField();
78
79 for (let L = 0; L < levels; L++) {
80 const th = map(L, 0, levels - 1, 0.30, 0.72);
81 const col = lv(L);
82 const wob = 0.5 + 0.5 * sin(t * 2.2 + L * 0.5);
83
84 stroke(red(col), green(col), blue(col), 26);
85 strokeWeight(5.5);
86 contour(th);
87
88 stroke(red(col), green(col), blue(col), 120 + 100 * wob);
89 strokeWeight(1.25);
90 contour(th);
91 }
92
93 t += 0.0032;
94 }
95
96 function contour(th) {
97 for (let i = 0; i < cols; i++) {
98 const x0 = i * sp, x1 = x0 + sp;
99 for (let j = 0; j < rows; j++) {
100 const y0 = j * sp, y1 = y0 + sp;
101 const a = field[i][j], b = field[i + 1][j], c = field[i + 1][j + 1], d = field[i][j + 1];
102 let state = 0;
103 if (a > th) state += 8;
104 if (b > th) state += 4;
105 if (c > th) state += 2;
106 if (d > th) state += 1;
107 if (state === 0 || state === 15) continue;
108
109 const tx = x0 + sp * ((th - a) / (b - a));
110 const ry = y0 + sp * ((th - b) / (c - b));
111 const bx = x0 + sp * ((th - d) / (c - d));
112 const ly = y0 + sp * ((th - a) / (d - a));
113
114 switch (state) {
115 case 1: case 14: line(x0, ly, bx, y1); break;
116 case 2: case 13: line(bx, y1, x1, ry); break;
117 case 3: case 12: line(x0, ly, x1, ry); break;
118 case 4: case 11: line(tx, y0, x1, ry); break;
119 case 6: case 9: line(tx, y0, bx, y1); break;
120 case 7: case 8: line(x0, ly, tx, y0); break;
121 case 5: line(x0, ly, tx, y0); line(bx, y1, x1, ry); break;
122 case 10: line(tx, y0, x1, ry); line(x0, ly, bx, y1); break;
123 }
124 }
125 }
126 }
127