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-sphere — reaction-diffusion on the sphere, 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 color-scheme: light dark;
17 }
18 @media (prefers-color-scheme: dark) {
19 :root {
20 --bg: #14171a;
21 --ink: #e6e9ec;
22 --ink-2: #9aa4af;
23 --line: #333b44;
24 --accent: #58a6ff;
25 --sphere-bg: #14161c;
26 }
27 }
28 body {
29 margin: 0;
30 background: var(--bg);
31 color: var(--ink);
32 font: 15px/1.5 system-ui, -apple-system, sans-serif;
33 }
34 main { max-width: 1100px; margin: 0 auto; padding: 20px 16px 48px; }
35 h1 { font-size: 20px; margin: 0 0 2px; }
36 .sub { color: var(--ink-2); margin: 0 0 12px; font-size: 13px; }
37 .sub a { color: var(--accent); }
38 .controls {
39 display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center;
40 padding: 6px 0;
41 }
42 .controls label { color: var(--ink-2); font-size: 13px; white-space: nowrap; }
43 select, input[type="number"], button {
44 font: inherit; font-size: 13px;
45 color: var(--ink); background: var(--bg);
46 border: 1px solid var(--line); border-radius: 6px;
47 padding: 4px 8px;
48 }
49 input[type="number"] { width: 6em; }
50 button { cursor: pointer; }
51 button:hover { border-color: var(--accent); }
52 button.primary { border-color: var(--accent); color: var(--accent); font-weight: 600; min-width: 5.5em; }
53 #panels {
54 display: flex; flex-wrap: wrap; gap: 14px; margin-top: 12px;
55 }
56 .panel {
57 flex: 1 1 320px; min-width: 280px;
58 border: 1px solid var(--line); border-radius: 8px; overflow: hidden;
59 display: flex;
60 }
61 .sphere-box { flex: 1; aspect-ratio: 1 / 1; max-height: 70vh; position: relative; }
62 .species-tag {
63 position: absolute; top: 8px; left: 10px; z-index: 2;
64 font-size: 15px; font-weight: 600; color: #fff;
65 background: rgba(0, 0, 0, 0.45);
66 padding: 1px 10px; border-radius: 12px;
67 pointer-events: none;
68 }
69 .colorbar {
70 display: flex; flex-direction: column; align-items: center; justify-content: center;
71 gap: 4px; padding: 8px 4px; background: var(--sphere-bg);
72 width: 52px; flex: none; box-sizing: border-box;
73 }
74 .colorbar canvas { border: 1px solid var(--line); border-radius: 2px; }
75 .colorbar-label { font-size: 11px; color: var(--ink-2); font-variant-numeric: tabular-nums; }
76 .stats { margin-top: 10px; font-size: 13px; color: var(--ink-2); font-variant-numeric: tabular-nums; }
77 .stats b { color: var(--ink); font-weight: 600; }
78 .cli {
79 margin-top: 10px; border: 1px solid var(--line); border-radius: 8px;
80 overflow: hidden;
81 }
82 .cli-head {
83 display: flex; gap: 10px; align-items: center; justify-content: space-between;
84 padding: 6px 10px; font-size: 12px; color: var(--ink-2);
85 background: var(--sphere-bg); border-bottom: 1px solid var(--line);
86 }
87 .cli-head button { padding: 2px 10px; font-size: 12px; }
88 #cmd {
89 display: block; padding: 8px 10px; white-space: pre-wrap;
90 font: 12px/1.6 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
91 color: var(--ink); user-select: all;
92 }
93 #blurb { margin-top: 4px; font-size: 13px; color: var(--ink-2); }
94 #err { color: #b35900; white-space: pre-wrap; font-size: 13px; }
95 </style>
96 </head>
97 <body>
98 <main>
99 <h1>turing-sphere</h1>
100 <p class="sub">
101 Reaction-diffusion on the sphere, solved live with spherical harmonics:
102 implicit spectral diffusion + explicit reaction (IMEX Euler), transforms on WebGPU via
103 <a href="https://github.com/concept-collection/shtns-webgpu">shtns-webgpu</a>.
104 Drag to rotate.
105 </p>
106 <div class="controls">
107 <label>preset
108 <select id="model"></select>
109 </label>
110 <label>lmax
111 <select id="lmax">
112 <option value="31">31</option>
113 <option value="63" selected>63</option>
114 <option value="127">127</option>
115 <option value="255">255</option>
116 </select>
117 </label>
118 <label>colormap
119 <select id="colormap"></select>
120 </label>
121 <label>backend
122 <select id="backend">
123 <option value="webgpu" selected>WebGPU (fp32)</option>
124 <option value="cpu">CPU (f64)</option>
125 </select>
126 </label>
127 <button id="runpause" class="primary">Run</button>
128 <button id="reseed">Re-seed</button>
129 <button id="resetview">Reset view</button>
130 </div>
131 <div class="controls" id="params"></div>
132 <div id="panels"></div>
133 <p class="stats" id="stats"></p>
134 <div class="cli">
135 <div class="cli-head">
136 <span>Same run on the desktop, solver only — compare its ms/step with the one above</span>
137 <button id="copycmd" type="button">Copy</button>
138 </div>
139 <code id="cmd"></code>
140 </div>
141 <p id="blurb"></p>
142 <p id="err"></p>
143 </main>
144 <script type="module" src="/src/main.ts"></script>
145 </body>
146</html>