title: Simple Meditation Timer tags: js timer I used to use Insight Timer, but it's just so bloated beyond what it was, and the one thing I want: a simple meditation timer, is annoying to even get to, together with adverts for their 'plus subscription' crap. Back in the day I paid for it, and it was good. Anyway, I decided I'd write a minimal timer. The sounds come from the Insight Timer apk, so I can't redistribute them, but you can use any sound you like that a web browser can load. It wouldn't be hard to add a little code to the `tick()` function for interval bells. That's something I'll do for my version when I find the need for it. Probably when starting, create a list of times, and when a time is hit, pop it off the list and play a sound. # Code ## medtimer.js ``` let input = document.createElement("input") input.value = "5:0" document.body.append(input) let startButton = document.createElement("button") startButton.textContent = "start" startButton.classList.add("start") document.body.append(startButton) let stopButton = document.createElement("button") stopButton.textContent = "stop" stopButton.classList.add("stop") document.body.append(stopButton) let div = document.createElement("div") div.textContent = "" div.classList.add("timer") document.body.append(div) let t0 = 0 const ms = 1000 const period = 100 let interval function tick() { let t1 = Date.now() let dt = t0 - t1 if( dt >= 0 ) { let ds = (dt/1000)|0 let s = ds % 60 let dm = (ds/60)|0 let m = dm % 60 let h = (dm/60)|0 s = (""+s).padStart(2,"0") m = (""+m).padStart(2,"0") h = (""+h).padStart(2,"0") let text = `${m}:${s}` if( h !== "00" ) { text = h+":"+text } div.textContent = text interval = setTimeout(tick,period) } else { finished() } } let bell = "bell_sakya.ogg" let audio = new Audio(bell) function playSound() { let audio = new Audio(bell) audio.play(); } function finished() { playSound() stop() } function stop() { clearTimeout(interval) t0 = 0 document.body.classList.remove("running") } function start() { if( t0 !== 0 ) { stop() } let v = input.value v = v.replace(/\./g,":") let vs = v.split(":") let tx = 0 vs.forEach((x,i) => { let j = vs.length-i-1 let f = 60**j let y = parseInt(x) tx += y*f }) t0 = Date.now() + tx*ms tick() document.body.classList.add("running") } startButton.addEventListener("click",start) stopButton.addEventListener("click",stop) window.addEventListener("keydown",e => { if( e.ctrlKey ) { let k = e.key.toLowerCase() switch(k) { case "a": e.preventDefault() start() break case "s": e.preventDefault() stop() input.focus() break } } }) ``` ## medtimer.css ``` body { background-color: black; } div.timer { font-size: 30vh; text-align: center; margin: 3rem; color: #700; } body.running { } body.running div.timer { color: #070; } input { font-size: 3rem; border: 2px solid black; border-radius: 0.3rem; padding: 0.3rem; margin: 1rem; } body.running input { display: none; } body.running button { background-color: black; border: 2px solid black; color: #777; font-size: 1.5rem; } button { margin: 1rem; font-size: 3rem; border: 2px solid black; border-radius: 0.3rem; padding: 0.3rem; color: white; background-color: #444; } body:not(.running) button.start { background-color: #070; } body:not(.running) button.stop { background-color: #700; } ``` ## index.html ```