Timer alert (beep / vibration) when Maximum Answer Time is reached

Hello,

I often get distracted by my own thoughts while reviewing cards in AnkiDroid.
I like the built-in on-screen timer that shows the time spent on each card, but I tend to lose track of time.

Is there any way to make the timer vibrate or play a short beep when the maximum answer time is reached?

Thank you!

Add an audio file prefixed with an underscore to your collection.media folder or make a note with an audio file and use the name AnkiDroid assigns to it.

Add this code to your templates. You should change the name and time (in milliseconds):

<script>
var audio = new Audio('_alertAudio.mp3');

setTimeout(() => {
audio.play();
}, 3000);
</script>

Vibration is also not difficult to do, here is vibration and a pause of 100 ms between them

navigator.vibrate([200, 100, 200]);

Thank you @ZornHadNoChoice and @kaiu !

Combining your approaches and AI I finished with this version (tap on the text tests the vibration):

<div id="t" style="font-size:0.5em;text-align:right;margin:15px 0;color:grey;cursor:pointer">Time: 60s</div>
<script>
const S=60; let t=S; const d = document.getElementById('t');
function u(){d.textContent=`Time: ${t}s`;}
function vibrate() {if ("vibrate" in navigator) navigator.vibrate([800]);}
setInterval(()=>{t--; u(); if(t<=0){vibrate(); t=S; u();}},1000);
d.addEventListener('click', vibrate); u();
</script>

It’s compacted, because it’s copied to all card types.

thank you!

i have better code, just change the number in the div or span. this will countdown to 0 and auto changes to red

<span class="amx-timer-widget" style="font-size:0.5em;text-align:right;margin:15px 0;color:inherite;opacity:75%;cursor:pointer">Time: 45s</span>
<span class="amx-timer-widget">Timer 1: 30s</span>
<span class="amx-timer-widget">Timer 1: 20s</span>

<!--- 13:02 revision --->
<script>
(function(){
  // bersihkan semua timer dari render/kartu sebelumnya dulu
  if(window.__amxTimerRegistry){
    window.__amxTimerRegistry.forEach(id=>clearInterval(id));
  }
  window.__amxTimerRegistry = [];

  document.querySelectorAll('.amx-timer-widget:not([data-amx-init])').forEach(function(el){
    el.setAttribute('data-amx-init','1');
    const match=el.textContent.match(/^(.*?)(\d+)\s*s?\s*$/);
    const label=match?match[1].trim():'Time';
    const duration=match?parseInt(match[2]):60;
    let remaining=duration;
    let tickInterval=null;

    function render(){
      el.textContent=`${label} ${remaining}s`;
      el.style.color=remaining<=0?'red':'';
    }
    function buzz(){ if("vibrate" in navigator) navigator.vibrate([800]); }

    function startTicking(){
      if(tickInterval) clearInterval(tickInterval);
      tickInterval=setInterval(()=>{
        remaining--;
        if(remaining<=0){
          remaining=0; render(); buzz();
          clearInterval(tickInterval);
        } else {
          render();
        }
      },1000);
      window.__amxTimerRegistry.push(tickInterval);
    }

    el.addEventListener('click',()=>{
      buzz();
      if(remaining<=0){
        remaining=duration; render(); startTicking();
      }
    });

    render();
    startTicking();
  });
})();
</script>

Shine Bocchi GIF

I’ve fixed the front-back vibration. no more mistakes for this new revision!