/ proof-of-concept / instrawave
Sign in
proof-of-concept / instrawave
instrawave / index.html
86 lines · 4.0 KBCodeBlameHistory
2<html lang="en">
3 <head>
4 <meta charset="utf-8" />
5 <meta name="viewport" content="width=device-width, initial-scale=1" />
6 <title>instrawave</title>
7 <style>
8 :root {
9 color-scheme: light dark;
10 font-family: system-ui, sans-serif;
11 }
12 body {
13 margin: 0 auto;
14 max-width: 72rem;
15 padding: 1rem 1.5rem 4rem;
16 line-height: 1.45;
17 }
18 h1 { font-size: 1.3rem; margin: 0.3rem 0 0; }
19 h1 + p { margin-top: 0.2rem; opacity: 0.75; }
20 h2 { font-size: 0.95rem; margin: 1.2rem 0 0.4rem; }
21 .cost { font-weight: normal; opacity: 0.6; font-size: 0.8rem; }
22 .top { display: grid; grid-template-columns: minmax(0, 1fr) 26rem; gap: 0 1.5rem; align-items: start; }
23 @media (max-width: 56rem) { .top { grid-template-columns: 1fr; } }
24 .scene { position: relative; width: 26rem; max-width: 100%; aspect-ratio: 4 / 3; margin-top: 1.2rem; }
25 .scene canvas { position: absolute; inset: 0; width: 100%; height: 100%; border-radius: 6px; }
26 .scene .hint { position: absolute; right: 0.5rem; bottom: 0.3rem; font-size: 0.7rem; color: rgba(255,255,255,0.45); }
27 .params { display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); gap: 0.3rem 1.5rem; }
28 .param { display: grid; font-size: 0.85rem; }
29 .param label { display: flex; justify-content: space-between; }
30 .param label span:last-child { opacity: 0.7; font-variant-numeric: tabular-nums; }
31 .param input[type='range'] { width: 100%; }
32 .bar { display: flex; gap: 0.6rem; align-items: center; flex-wrap: wrap; margin: 1rem 0 0.4rem; }
33 button { font: inherit; padding: 0.35rem 0.9rem; }
34 progress { width: 10rem; }
35 #status { font-size: 0.85rem; opacity: 0.8; white-space: pre-wrap; }
36 textarea { width: 100%; font: 0.8rem/1.4 ui-monospace, monospace; min-height: 3.2rem; box-sizing: border-box; }
37 select, input[type='number'] { font: inherit; }
38 .stale { color: #b45309; }
39 .ready { color: #15803d; }
40 .plots canvas { width: 100%; border-radius: 6px; display: block; margin-top: 0.6rem; }
41 </style>
42 </head>
43 <body>
44 <h1>instrawave</h1>
45 <p>
46 Instruments as files: each carries its parameters (geometry and accuracy feed a
47 precomputed room; tuning is free) and the raw WebGPU programs for both steps.
48 </p>
49 <div class="bar">
50 <label>instrument <select id="instrument"></select></label>
51 <span id="gridinfo" style="font-size: 0.8rem; opacity: 0.7"></span>
52 </div>
53 <div class="top">
54 <div>
55 <h2>Tuning <span class="cost">free; renders straight from the bake</span></h2>
56 <div class="params" id="tuning"></div>
57 <h2>Geometry &amp; accuracy <span class="cost">changing one invalidates the bake</span></h2>
58 <div class="params" id="geometry"></div>
59 </div>
60 <div class="scene" id="scene">
61 <canvas id="volume"></canvas>
62 <canvas id="overlay"></canvas>
63 <span class="hint">drag to orbit · wheel to zoom</span>
64 </div>
65 </div>
66 <h2>Stimuli <span class="cost" id="evhint">JSON list; each event may override tuning parameters</span></h2>
67 <textarea id="events" spellcheck="false">[{"t": 0}]</textarea>
68 <div class="bar">
69 <button id="precompute">Precompute</button>
70 <span id="bakestate"></span>
71 <progress id="progress" max="1" value="0" hidden></progress>
72 <button id="cancel" hidden>Cancel</button>
73 <span style="flex: 1"></span>
74 <label>seconds <input id="seconds" type="number" value="4" min="0.2" max="60" step="0.2" style="width: 4.5rem" /></label>
75 <button id="render" disabled>Render</button>
76 <button id="play" disabled>Play</button>
77 <button id="save" disabled>Save .wav</button>
78 </div>
79 <p id="status"></p>
80 <div class="plots">
81 <canvas id="trace" height="140" hidden></canvas>
82 <canvas id="spectrum" height="220" hidden></canvas>
83 </div>
84 <script type="module" src="./src/main.ts"></script>
85 </body>
86</html>
↑↓ move↵openescclose