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;