/ proof-of-concept / soundbox
Sign in
proof-of-concept / soundbox
Put Save/Load scene in the transport bar and show the render command on save
Jeremy Magland <jeremy.magland@gmail.com> committed commit 61544919cf07 parent e18e57e Browse files
2 changed files+33−3
index.htmlmodified+10−3View file
@@ -73,6 +73,12 @@
7373 color: var(--ink-2); margin: 10px 0 0;
7474 }
7575 progress { width: 10em; height: 0.9em; }
76+ #scenehint code {
77+ font: 12px/1.5 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
78+ background: var(--panel-bg); border: 1px solid var(--line);
79+ border-radius: 4px; padding: 1px 6px; user-select: all;
80+ }
81+ #scenehint button { font-size: 11px; padding: 1px 8px; margin-left: 4px; }
7682
7783 /* tabs */
7884 .tabs { display: flex; gap: 2px; margin-top: 10px; border-bottom: 1px solid var(--line); }
@@ -248,8 +254,12 @@
248254 <progress id="renderprog" value="0" max="1" hidden></progress>
249255 <button id="listen" title="Play what the microphone has recorded since the last excite, in real time at its real pitch">Listen</button>
250256 <button id="download" title="Save the recording as a 48 kHz .wav">Save .wav</button>
257+ <button id="savescene" title="Download this scene — objects, body, every knob, the mic, and any hand-edited .m — as a .json that loads back here or renders on another machine with `npm run render`">Save scene</button>
258+ <button id="loadscene" title="Load a scene .json saved from this page">Load scene</button>
259+ <input type="file" id="loadfile" accept=".json,application/json" hidden />
251260 <span class="stats" id="recinfo"></span>
252261 </div>
262+ <p class="sub" id="scenehint" hidden></p>
253263
254264 <div class="tabs">
255265 <button id="tab-play" class="active">Play</button>
@@ -280,9 +290,6 @@
280290 <option value="256">256 (slow)</option>
281291 </select>
282292 </label>
283- <button id="savescene" title="Download this scene — objects, body, every knob, the mic, and any hand-edited .m — as a .json that loads back here or renders headless with `npm run render`">Save scene</button>
284- <button id="loadscene" title="Load a scene .json saved from this page">Load scene</button>
285- <input type="file" id="loadfile" accept=".json,application/json" hidden />
286293 </div>
287294 <div id="objects"></div>
288295 <div class="controls" style="margin-top:10px">
src/main.tsmodified+23−0View file
@@ -844,6 +844,29 @@ el('savescene').addEventListener('click', () => {
844844 a.download = 'soundbox-scene.json';
845845 a.click();
846846 setTimeout(() => URL.revokeObjectURL(url), 10_000);
847+
848+ // Show what to do with the file: the exact command that renders it
849+ // outside the browser, ready to copy.
850+ const cmd = 'npm run render -- soundbox-scene.json --seconds 10 --out clip.wav';
851+ const hint = el('scenehint');
852+ hint.hidden = false;
853+ hint.textContent =
854+ 'Saved soundbox-scene.json. To render it on another machine ' +
855+ '(a checkout of this repo, numbl beside it, any GPU): ';
856+ const code = document.createElement('code');
857+ code.textContent = cmd;
858+ const copy = document.createElement('button');
859+ copy.textContent = 'copy';
860+ copy.addEventListener('click', () => {
861+ void navigator.clipboard.writeText(cmd).then(() => {
862+ copy.textContent = 'copied';
863+ setTimeout(() => (copy.textContent = 'copy'), 1500);
864+ });
865+ });
866+ const tail = document.createElement('span');
867+ tail.textContent =
868+ ' — add --nx 192 or higher for more bandwidth than the browser grid; see the README.';
869+ hint.append(code, copy, tail);
847870 });
848871
849872 const loadFile = el<HTMLInputElement>('loadfile');
↑↓ move↵openescclose