Lub Dub Valves !new! đ Premium
.lub-btn background: #c2571a; border-bottom: 3px solid #ffaa70; .dub-btn background: #1a6c9e; border-bottom: 3px solid #70c8ff; .auto-btn background: #2b5e3b; border-bottom: 3px solid #8bc34a;
// ----- Auto Cycle (normal lub-dub rhythm) ----- let autoInterval = null; let isAuto = false; const bpmSlider = document.getElementById('bpmSlider'); const bpmValueSpan = document.getElementById('bpmValue');
<div class="bpm-control"> <span>â¤ī¸ BPM (auto)</span> <input type="range" id="bpmSlider" min="40" max="140" value="72" step="1"> <span id="bpmValue">72</span> </div> <footer>lub-dub rhythm | synthetic heart valves | real-time audio + animation</footer> </div> lub dub valves
<script> // ----- Web Audio Setup ----- const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
bpmSlider.addEventListener('input', (e) => const newBpm = e.target.value; bpmValueSpan.textContent = newBpm; if (isAuto) // restart auto cycle with new BPM const wasAuto = isAuto; stopAutoCycle(); startAutoCycle(); autoBtn.textContent = 'âšī¸ STOP CYCLE'; autoBtn.style.background = '#a13e2d'; statusSpan.innerHTML = `đ AUTO CYCLE ($newBpm BPM)`; ); .lub-btn background: #c2571a
.valve-desc font-size: 0.85rem; color: #bbd4f0;
function startAutoCycle() if (autoInterval) clearInterval(autoInterval); isAuto = true; function nextBeat() if (!isAuto) return; playLubDub(); // initial immediate beat nextBeat(); autoInterval = setInterval(nextBeat, getCycleIntervalMs()); statusSpan.innerHTML = `đ AUTO CYCLE ($bpmSlider.value BPM)`; border-bottom: 3px solid #ffaa70
function getCycleIntervalMs() const bpm = parseInt(bpmSlider.value, 10); // one cardiac cycle = 60/BPM seconds â milliseconds return (60 / bpm) * 1000;