6 second breathing metronome Cycle 0
6

Ready

Inhale • pause • exhale • pause

Inhale
6 sec
Pause
6 sec
Exhale
6 sec
Pause
6 sec
Seconds per phase 6 sec Volume 65% Meditative female voice

Press Start to begin.

#breath-app { font-family: system-ui, -apple-system, BlinkMacSystemFont, “Segoe UI”, sans-serif; color: #f6f8fb; background: #111418; padding: 24px; } #breath-app .breath-card { max-width: 720px; margin: auto; background: #1b2026; border: 1px solid rgba(255,255,255,.1); border-radius: 10px; padding: 28px; text-align: center; } #breath-app .top { display: flex; justify-content: space-between; color: #aeb8c2; margin-bottom: 28px; } #breath-app .orb { width: min(320px, 72vw); aspect-ratio: 1; margin: 0 auto 24px; border-radius: 50%; display: grid; place-items: center; background: radial-gradient(circle, #35d19a, #3385d6); box-shadow: 0 0 0 16px rgba(53,209,154,.22), 0 0 60px rgba(53,209,154,.28); transform: scale(.72); transition: transform .2s linear; } #breath-app #timer { font-size: 72px; font-weight: 800; background: rgba(0,0,0,.28); width: 46%; aspect-ratio: 1; border-radius: 50%; display: grid; place-items: center; } #breath-app h1 { font-size: clamp(44px, 9vw, 76px); margin: 0; } #breath-app #hint { color: #aeb8c2; margin: 8px 0 22px; } #breath-app .steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-bottom: 22px; } #breath-app .steps div { background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.08); border-radius: 8px; padding: 12px; font-weight: 700; } #breath-app .steps div.active { border-color: #35d19a; background: rgba(53,209,154,.16); } #breath-app label { display: grid; gap: 8px; text-align: left; margin: 14px 0; color: #aeb8c2; } #breath-app input[type=”range”], #breath-app input[type=”checkbox”] { accent-color: #35d19a; } #breath-app .voice { display: flex; justify-content: space-between; align-items: center; } #breath-app button { min-height: 48px; border: 0; border-radius: 8px; padding: 0 22px; margin: 8px 4px; font-weight: 800; cursor: pointer; } #breath-app #start { background: #35d19a; color: #06110c; } #breath-app #reset { background: #2a3037; color: #f6f8fb; } #breath-app #status { color: #aeb8c2; } @media (max-width: 560px) { #breath-app .steps { grid-template-columns: repeat(2, 1fr); } } (() => { const phases = [ { key: “inhale”, title: “Inhale”, hint: “Breathe in smoothly”, word: “inhale”, tone: 660 }, { key: “pause-in”, title: “Pause”, hint: “Hold gently”, word: “pause”, tone: 520 }, { key: “exhale”, title: “Exhale”, hint: “Release slowly”, word: “exhale”, tone: 440 }, { key: “pause-out”, title: “Pause”, hint: “Rest before the next breath”, word: “pause”, tone: 360 } ]; const $ = (id) => document.getElementById(id); const timer = $(“timer”), phase = $(“phase”), hint = $(“hint”), orb = $(“orb”); const seconds = $(“seconds”), secondsText = $(“secondsText”); const volume = $(“volume”), volumeText = $(“volumeText”); const start = $(“start”), reset = $(“reset”), status = $(“status”); const voiceToggle = $(“voice”), cycle = $(“cycle”); const steps = […document.querySelectorAll(“#breath-app [data-step]”)]; let running = false, index = 0, startedAt = 0, raf = 0, cycles = 0, audio, chosenVoice; function pickVoice() { if (!speechSynthesis) return null; const voices = speechSynthesis.getVoices(); return voices.find(v => /female|woman|aria|jenny|samantha|victoria|karen|zira/i.test(v.name)) || voices.find(v => v.lang && v.lang.startsWith(“en”)) || voices[0]; } function speak(text) { if (!voiceToggle.checked || !(“speechSynthesis” in window)) return; chosenVoice = chosenVoice || pickVoice(); const u = new SpeechSynthesisUtterance(text); if (chosenVoice) u.voice = chosenVoice; u.rate = 0.72; u.pitch = 1.08; u.volume = Math.max(0.35, Number(volume.value) / 100); speechSynthesis.cancel(); speechSynthesis.speak(u); } function beep(freq) { const AudioEngine = window.AudioContext || window.webkitAudioContext; if (!AudioEngine || Number(volume.value) === 0) return; audio = audio || new AudioEngine(); const osc = audio.createOscillator(); const gain = audio.createGain(); const now = audio.currentTime; osc.frequency.value = freq; gain.gain.setValueAtTime(0, now); gain.gain.linearRampToValueAtTime(0.16 * Number(volume.value) / 100, now + 0.01); gain.gain.exponentialRampToValueAtTime(0.001, now + 0.18); osc.connect(gain); gain.connect(audio.destination); osc.start(now); osc.stop(now + 0.2); } function setPhase(i) { index = i % phases.length; const p = phases[index]; startedAt = performance.now(); phase.textContent = p.title; hint.textContent = p.hint; steps.forEach(s => s.classList.toggle(“active”, s.dataset.step === p.key)); speak(p.word); beep(p.tone); } function loop(now) { if (!running) return; const total = Number(seconds.value); const elapsed = (now – startedAt) / 1000; const left = Math.max(1, Math.ceil(total – elapsed)); const progress = Math.min(1, elapsed / total); timer.textContent = left; if (phases[index].key === “inhale”) orb.style.transform = `scale(${0.72 + progress * 0.28})`; if (phases[index].key === “exhale”) orb.style.transform = `scale(${1 – progress * 0.28})`; if (elapsed >= total) { const next = (index + 1) % phases.length; if (next === 0) cycles++; cycle.textContent = `Cycle ${cycles}`; setPhase(next); } raf = requestAnimationFrame(loop); } function updateLabels() { secondsText.textContent = `${seconds.value} sec`; volumeText.textContent = `${volume.value}%`; timer.textContent = seconds.value; steps.forEach(s => s.querySelector(“small”).textContent = `${seconds.value} sec`); } start.onclick = async () => { if (running) { running = false; cancelAnimationFrame(raf); start.textContent = “Start”; status.textContent = “Paused.”; return; } if (audio && audio.state === “suspended”) await audio.resume(); chosenVoice = pickVoice(); running = true; start.textContent = “Stop”; status.textContent = “Running with spoken cues.”; setPhase(0); raf = requestAnimationFrame(loop); }; reset.onclick = () => { running = false; cancelAnimationFrame(raf); cycles = 0; index = 0; cycle.textContent = “Cycle 0”; phase.textContent = “Ready”; hint.textContent = “Inhale • pause • exhale • pause”; orb.style.transform = “scale(.72)”; steps.forEach(s => s.classList.remove(“active”)); start.textContent = “Start”; status.textContent = “Press Start to begin.”; updateLabels(); }; seconds.oninput = updateLabels; volume.oninput = updateLabels; if (“speechSynthesis” in window) speechSynthesis.onvoiceschanged = () => chosenVoice = pickVoice(); updateLabels(); })();

Published by UDAY KUMAR

Welcome to my professional website! I am Uday Kumar Saama, a dedicated yoga instructor with an MSc in Yoga, UGC NET qualification, and a wealth of experience, including serving as the inaugural Teacher of Indian Culture at the ICC in Tel Aviv. My journey in yoga has taken me from teaching at Potti Sreeramulu Telugu University to instructing at SVPNPA, allowing me to understand and cater to the diverse needs of my students. Currently, I am pursuing a Ph.D. in Yoga Technology at IIT Hyderabad, where I am excited to explore and share cutting-edge research in the field. My expertise extends to traditional yoga practices, Astanga Vinyasa, and I am continually expanding my knowledge by learning Iyengar Yoga from senior teacher Zarna Mohan. My commitment to continuous learning and innovation in yoga drives my teaching philosophy and practice. I invite you to explore my website to learn more about my background, teaching methodology, and how I can contribute to your yoga journey. Thank you for visiting!

Leave a comment