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
<!DOCTYPE html>
<html>
<head>
<title>Meditation Timer 001 countdown</title>
<meta charset='utf8'/>
</head>
<body>
</body>
<link rel="stylesheet" href="medtimer.css"/>
<script src="medtimer.js"></script>
</html>