/ concept-collection / turing-surface
Sign in
concept-collection / turing-surface
301 lines · 12.6 KBCodeBlameHistory
0af3386Reaction-diffusion on spherical-harmonic surfacesJeremy Magland 1<!doctype html>
2<html lang="en">
3 <head>
4 <meta charset="utf-8" />
5 <meta name="viewport" content="width=device-width, initial-scale=1" />
6 <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><circle cx=%2250%22 cy=%2250%22 r=%2245%22 fill=%22%232a7f62%22/><circle cx=%2235%22 cy=%2238%22 r=%2211%22 fill=%22%23f5d547%22/><circle cx=%2265%22 cy=%2258%22 r=%229%22 fill=%22%23f5d547%22/><circle cx=%2248%22 cy=%2274%22 r=%227%22 fill=%22%23f5d547%22/><circle cx=%2268%22 cy=%2230%22 r=%226%22 fill=%22%23f5d547%22/></svg>" />
7 <title>turing-surface — reaction-diffusion on closed surfaces, live in the browser</title>
8 <style>
9 :root {
10 --bg: #ffffff;
11 --ink: #1f2328;
12 --ink-2: #57606a;
13 --line: #d0d7de;
14 --accent: #0969da;
15 --sphere-bg: #f4f6f8;
16 --tok-com: #6e7781;
17 --tok-str: #0a3069;
18 --tok-num: #0550ae;
19 --tok-kw: #cf222e;
20 --tok-ext: #8250df;
21 color-scheme: light dark;
22 }
23 @media (prefers-color-scheme: dark) {
24 :root {
25 --bg: #14171a;
26 --ink: #e6e9ec;
27 --ink-2: #9aa4af;
28 --line: #333b44;
29 --accent: #58a6ff;
30 --sphere-bg: #14161c;
31 --tok-com: #8b949e;
32 --tok-str: #a5d6ff;
33 --tok-num: #79c0ff;
34 --tok-kw: #ff7b72;
35 --tok-ext: #d2a8ff;
36 }
37 }
38 body {
39 margin: 0;
40 background: var(--bg);
41 color: var(--ink);
42 font: 15px/1.5 system-ui, -apple-system, sans-serif;
43 }
44 main { max-width: 1100px; margin: 0 auto; padding: 20px 16px 48px; }
45 h1 { font-size: 20px; margin: 0 0 2px; }
46 .sub { color: var(--ink-2); margin: 0 0 12px; font-size: 13px; }
47 .sub a { color: var(--accent); }
48 .controls {
49 display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center;
50 padding: 6px 0;
51 }
52 /* display:flex above would otherwise override the UA's [hidden] rule */
53 .controls[hidden] { display: none; }
54 .controls label { color: var(--ink-2); font-size: 13px; white-space: nowrap; }
55 select, input[type="number"], button {
56 font: inherit; font-size: 13px;
57 color: var(--ink); background: var(--bg);
58 border: 1px solid var(--line); border-radius: 6px;
59 padding: 4px 8px;
60 }
61 input[type="number"] { width: 6em; }
62 input[type="range"] { width: 8em; vertical-align: middle; accent-color: var(--accent); }
63 button { cursor: pointer; }
64 #geomnote { margin-top: 4px; }
65 button:hover { border-color: var(--accent); }
66 button.primary { border-color: var(--accent); color: var(--accent); font-weight: 600; min-width: 5.5em; }
67 #panels {
68 display: flex; flex-wrap: wrap; gap: 14px; margin-top: 12px;
69 }
70 .panel {
71 flex: 1 1 320px; min-width: 280px;
72 border: 1px solid var(--line); border-radius: 8px; overflow: hidden;
73 display: flex;
74 }
75 .sphere-box { flex: 1; aspect-ratio: 1 / 1; max-height: 70vh; position: relative; }
76 .species-tag {
77 position: absolute; top: 8px; left: 10px; z-index: 2;
78 font-size: 15px; font-weight: 600; color: #fff;
79 background: rgba(0, 0, 0, 0.45);
80 padding: 1px 10px; border-radius: 12px;
81 pointer-events: none;
82 }
83 .colorbar {
84 display: flex; flex-direction: column; align-items: center; justify-content: center;
85 gap: 4px; padding: 8px 4px; background: var(--sphere-bg);
86 width: 52px; flex: none; box-sizing: border-box;
87 }
88 .colorbar canvas { border: 1px solid var(--line); border-radius: 2px; }
89 .colorbar-label { font-size: 11px; color: var(--ink-2); font-variant-numeric: tabular-nums; }
90 .stats { margin-top: 10px; font-size: 13px; color: var(--ink-2); font-variant-numeric: tabular-nums; }
91 .stats b { color: var(--ink); font-weight: 600; }
92 .cli {
93 margin-top: 10px; border: 1px solid var(--line); border-radius: 8px;
94 overflow: hidden;
95 }
96 .cli-head {
97 display: flex; gap: 10px; align-items: center; justify-content: space-between;
98 padding: 6px 10px; font-size: 12px; color: var(--ink-2);
99 background: var(--sphere-bg); border-bottom: 1px solid var(--line);
100 }
101 .cli-head button { padding: 2px 10px; font-size: 12px; }
102 #cmd {
103 display: block; padding: 8px 10px; white-space: pre-wrap;
104 font: 12px/1.6 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
105 color: var(--ink); user-select: all;
106 }
107 #blurb { margin-top: 4px; font-size: 13px; color: var(--ink-2); }
108 #err { color: #b35900; white-space: pre-wrap; font-size: 13px; }
109 .editor {
110 margin-top: 12px; border: 1px solid var(--line); border-radius: 8px;
111 overflow: hidden;
112 }
113 .editor-head {
114 display: flex; gap: 10px; align-items: center; justify-content: space-between;
115 padding: 6px 10px; font-size: 12px; color: var(--ink-2);
116 background: var(--sphere-bg); border-bottom: 1px solid var(--line);
117 }
118 .editor-head button { padding: 2px 10px; font-size: 12px; }
119 /* Source and compiled-op list side by side, so the editor gets the
120 height rather than sharing it with the list below. */
121 .editor-body { display: flex; align-items: stretch; }
122 .editor-code { position: relative; flex: 1 1 62%; min-width: 0; height: 34em; }
123 /* The overlay and the textarea must agree on every metric that affects
124 where a character lands. Keep these two rules together. */
125 .editor-code > pre,
126 .editor-code > textarea {
127 margin: 0; padding: 10px 12px; border: 0;
128 box-sizing: border-box; width: 100%; height: 100%;
129 font: 12.5px/1.6 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
130 tab-size: 2;
131 white-space: pre; overflow-wrap: normal;
132 }
133 #highlight {
134 position: absolute; inset: 0; overflow: hidden;
135 pointer-events: none; background: var(--bg); color: var(--ink);
136 }
137 #source {
138 position: relative; z-index: 1; display: block;
139 resize: none; overflow: auto;
140 background: transparent; color: transparent; caret-color: var(--ink);
141 }
142 #source:focus { outline: none; }
143 /* Transparent text means the selection must be see-through, or selected
144 code would be invisible. */
145 #source::selection { background: color-mix(in srgb, var(--accent) 28%, transparent); }
146 #compiled {
147 flex: 1 1 38%; min-width: 0; margin: 0; padding: 10px 12px; overflow: auto;
148 border-left: 1px solid var(--line); background: var(--sphere-bg);
149 font: 12px/1.6 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
150 color: var(--ink-2); white-space: pre;
151 }
152 @media (max-width: 860px) {
153 .editor-body { flex-direction: column; }
154 .editor-code { flex: none; height: 26em; }
155 #compiled { border-left: 0; border-top: 1px solid var(--line); max-height: 12em; }
156 }
157 .tok-com { color: var(--tok-com); }
158 .tok-str { color: var(--tok-str); }
159 .tok-num { color: var(--tok-num); }
160 .tok-kw { color: var(--tok-kw); font-weight: 600; }
161 .tok-ext { color: var(--tok-ext); }
162 </style>
163 </head>
164 <body>
165 <main>
166 <h1>turing-surface</h1>
167 <p class="sub">
62e6cc4Simplify UI text and built-in .m script commentsJeremy Magland 168 Reaction-diffusion on closed surfaces, solved live with spherical
169 harmonics on WebGPU via
0af3386Reaction-diffusion on spherical-harmonic surfacesJeremy Magland 170 <a href="https://github.com/concept-collection/shtns-webgpu">shtns-webgpu</a>.
1015122Editable operator/solver files in the page, and a solver selectorJeremy Magland 171 The model, the shape, the diffusion operator and the solvers are all
172 the MATLAB below, compiled in your browser by
173 <a href="https://numbl.org">numbl</a>. Edit any of them and watch it
174 change. Drag to rotate.
176 <div class="controls">
177 <label>preset
178 <select id="model"></select>
179 </label>
59f3e22Factor the solver out of the models; add BiCGSTAB and GMRESJeremy Magland 180 <label title="The surface being solved on.">geometry
0af3386Reaction-diffusion on spherical-harmonic surfacesJeremy Magland 181 <select id="geometry"></select>
182 </label>
62e6cc4Simplify UI text and built-in .m script commentsJeremy Magland 183 <label title="Blend between the sphere (0) and the surface (1). Display only.">morph
0af3386Reaction-diffusion on spherical-harmonic surfacesJeremy Magland 184 <input type="range" id="morph" min="0" max="1" step="0.01" value="1" />
185 </label>
1015122Editable operator/solver files in the page, and a solver selectorJeremy Magland 186 <label title="Which solver answers the models' solve(...) call — see solvers/. Changing it recompiles.">solver
187 <select id="solver">
188 <option value="richardson" selected>richardson</option>
189 <option value="bicgstab">bicgstab</option>
190 <option value="gmres">gmres</option>
191 </select>
192 </label>
62e6cc4Simplify UI text and built-in .m script commentsJeremy Magland 193 <label title="Iterations of the implicit diffusion solve. Changing it recompiles.">solve iters
0af3386Reaction-diffusion on spherical-harmonic surfacesJeremy Magland 194 <select id="niter">
195 <option value="0">0</option>
196 <option value="1" selected>1</option>
197 <option value="2">2</option>
198 <option value="4">4</option>
199 <option value="8">8</option>
067895eadditional options for niterJeremy Magland 200 <option value="16">16</option>
201 <option value="32">32</option>
202 <option value="64">64</option>
203 <option value="128">128</option>
205 </label>
206 <label>lmax
207 <select id="lmax">
208 <option value="31">31</option>
209 <option value="63" selected>63</option>
210 <option value="127">127</option>
211 <option value="255">255</option>
212 </select>
213 </label>
62e6cc4Simplify UI text and built-in .m script commentsJeremy Magland 214 <label title="Render on a finer grid. Display only.">display oversampling
0af3386Reaction-diffusion on spherical-harmonic surfacesJeremy Magland 215 <select id="oversample">
216 <option value="auto" selected>auto</option>
217 <option value="1">off</option>
218 <option value="2"></option>
219 <option value="4"></option>
220 <option value="8"></option>
221 </select>
222 </label>
223 <label>colormap
224 <select id="colormap"></select>
225 </label>
226 <button id="runpause" class="primary">Run</button>
227 <button id="benchmark">Benchmark</button>
228 <button id="reseed">Re-seed</button>
229 <button id="resetview">Reset view</button>
230 <button id="movietoggle" title="Export the run as an MP4 movie">Export movie</button>
231 </div>
232 <div class="controls" id="moviebar" hidden>
62e6cc4Simplify UI text and built-in .m script commentsJeremy Magland 233 <label title="Simulation-time units per second of video">movie speed
0af3386Reaction-diffusion on spherical-harmonic surfacesJeremy Magland 234 <select id="moviespeed">
235 <option value="0.1">0.1×</option>
236 <option value="0.5">0.5×</option>
237 <option value="1"></option>
238 <option value="3"></option>
239 <option value="5"></option>
240 <option value="10" selected>10×</option>
241 <option value="20">20×</option>
242 </select>
243 </label>
62e6cc4Simplify UI text and built-in .m script commentsJeremy Magland 244 <label title="Size of each sphere panel in the video, in pixels">resolution
0af3386Reaction-diffusion on spherical-harmonic surfacesJeremy Magland 245 <select id="movieres">
246 <option value="480">480</option>
247 <option value="640">640</option>
248 <option value="768" selected>768</option>
249 <option value="1080">1080</option>
250 <option value="1440">1440</option>
251 </select>
252 </label>
62e6cc4Simplify UI text and built-in .m script commentsJeremy Magland 253 <label title="Slowly orbit the camera during the movie">
0af3386Reaction-diffusion on spherical-harmonic surfacesJeremy Magland 254 <input type="checkbox" id="movierotate" checked /> auto-rotate
255 </label>
62e6cc4Simplify UI text and built-in .m script commentsJeremy Magland 256 <button id="movie" title="Replay the run from t = 0 and download an MP4">Export</button>
258 <div class="controls" id="params"></div>
259 <div class="controls" id="geomparams"></div>
260 <p id="geomnote" class="stats"></p>
261 <div id="panels"></div>
262 <p class="stats" id="stats"></p>
263 <p class="stats" id="benchresult"></p>
264 <div class="editor">
265 <div class="editor-head">
266 <span>
267 <select id="editor-file" aria-label="file to edit"></select>
268 <span id="editor-title"></span>
269 </span>
270 <span>
271 <button id="recompile" type="button">Recompile</button>
272 <button id="revert" type="button">Revert</button>
273 </span>
274 </div>
275 <div class="editor-body">
276 <div class="editor-code">
277 <pre id="highlight" aria-hidden="true"></pre>
278 <textarea
279 id="source"
280 spellcheck="false"
281 autocomplete="off"
282 autocapitalize="off"
283 aria-label="model source (MATLAB)"
284 ></textarea>
285 </div>
286 <pre id="compiled"></pre>
287 </div>
288 </div>
289 <div class="cli">
290 <div class="cli-head">
62e6cc4Simplify UI text and built-in .m script commentsJeremy Magland 291 <span>The same run on the desktop</span>
0af3386Reaction-diffusion on spherical-harmonic surfacesJeremy Magland 292 <button id="copycmd" type="button">Copy</button>
293 </div>
294 <code id="cmd"></code>
295 </div>
296 <p id="blurb"></p>
297 <p id="err"></p>
298 </main>
299 <script type="module" src="/src/main.ts"></script>
300 </body>
301</html>
moveopenescclose