const runStateEl = document.getElementById("runState"); // Call this from script.js when state changes if you want /*window.setRunningState = function (state) { running = state; updateRunState(); };*/ function updateRunState() { runStateEl.textContent = running ? "running" : "stopped"; runStateEl.classList.toggle("running", running); startBtn.textContent = running ? "Stop" : "Start"; stepBtn.disabled = running; } // Fallback if script.js doesn’t call setRunningState startBtn.addEventListener("click", () => { updateRunState(); }); updateRunState(); // ---------- Live slider values ---------- function bindRange(id, suffix = "") { const input = document.getElementById(id); const output = document.getElementById(id.replace("Range", "Value")); const update = () => { output.textContent = input.value + suffix; }; input.addEventListener("input", update); update(); } bindRange("speedRange", " ms"); bindRange("cellSizeRange", " px"); bindRange("baseFrequencyRange", " Hz"); bindRange("volumeRange", "%"); // ---------- Music mode hint ---------- const modeHints = { additive: "Each active cell adds a tone to the mix.", frequencyGrid: "Grid rows map to pitch, density to amplitude.", granular: "Short sound grains triggered by cell activity.", polyrhythm: "Independent rhythmic layers from cell clusters." }; const modeSelect = document.getElementById("musicModeSelect"); const modeHint = document.getElementById("modeHint"); function updateModeHint() { modeHint.textContent = modeHints[modeSelect.value] || ""; } modeSelect.addEventListener("change", updateModeHint); updateModeHint(); // ---------- Keyboard shortcuts ---------- window.addEventListener("keydown", e => { if (e.target.tagName === "INPUT" || e.target.tagName === "SELECT") return; switch (e.code) { case "Space": e.preventDefault(); startBtn.click(); break; case "KeyR": document.getElementById("randomBtn").click(); break; case "KeyC": document.getElementById("clearBtn").click(); break; } }); // recording button handlers document.getElementById("recordBtn").addEventListener("click", () => { if (!lifeMusic) { console.warn("no synth"); return; } window.recording.start(lifeMusic); window.recording.visualize.start(lifeMusic.masterGain, lifeMusic.audioContext); }); document.getElementById("stopRecordBtn").addEventListener("click", async () => { running = false; startBtn.textContent = 'Start'; if (timer) clearInterval(timer); timer = null; lifeMusic.stop(); lifeMusic.generateFromGrid(grid, cols, rows); await window.recording.stopAndMerge("music-of-life.wav"); window.recording.visualize.stop(); });