Methodology to determine the best amount of time to be spent on a card on average

I had some time and interest to tinker on this so I made it show an indicator instead. It should now properly reset the timers when advancing to the next card too.

This goes in the card Front again (edit the JS Api part to have your own email/github this time)

<script>
  var frontTimer;
  var backTimer;
  function initAutoAdvance(options = {}) {
    const {
      goToAnswerSeconds = 5,
      answerSeconds = 5,
      // Threshold when to add extra time for ease
      easeThreshold = 2.5,
      // Amount of ease per which to add/reduce by 1 second
      easeStep = 0.5
    } = options;

    const handlePromise = (val, func) => {
      if (typeof val === "object" && val !== null && !!val.then) {
        val.then((res) => func(res.value));
      } else {
        func(val);
      }
    };

    let goToAnswer;

  function answerFunc() {
    // Add indicator element into a fixed position
    const indicator = document.createElement("div");
    indicator.style.position = "fixed";
    // Positioned at bottom right corner
    indicator.style.bottom = "0";
    indicator.style.right = "0";
    // Size
    indicator.style.padding = "10px";
    // Black with 50% opacity
    indicator.style.background = "rgba(0,0,0,0.5)";
    // Large border to make the element circular
    indicator.style.borderRadius = "99px";

    document.body.appendChild(indicator);
  }
    function onGoToAnswer(answerWaitTime) {
      goToAnswer();
      // Start timer for answering
      backTimer = setTimeout(answerFunc, answerWaitTime);
    }
    const startAutoAdvance = (fctVal) => {
      clearTimeout(frontTimer);
      clearTimeout(backTimer);
      handlePromise(fctVal, (fctNum = 0) => {
        let goToAnswerWaitTime = goToAnswerSeconds * 1000;
        // fct is a number between 1300 and 5000
        // We want a multipler between 1 and 5
        const fctMult = fctNum / 1000 > 1;

        let answerWaitTime = answerSeconds * 1000;
        // If fct is missing, it'll be zero
        if (fctMult > 1 && easeThreshold > 1 && easeStep > 0) {
          // Add extra time if factor is lower than easeMiddle, reduce if higher
          const extraTime = (fctMult - easeThreshold) * easeStep * 1000;
          goToAnswerWaitTime = goToAnswerWaitTime + extraTime;
          answerWaitTime = answerWaitTime + extraTime;
        }
        // Start timer for showing answer
        frontTimer = setTimeout(
          () => onGoToAnswer(answerWaitTime),
          goToAnswerWaitTime
        );
      });
    };
    try {
      const jsApiContract = {
        version: "0.0.3",
        developer: "put_your_own_email_or_github_here"
      };

      const api = new AnkiDroidJS(jsApiContract);

      goToAnswer = showAnswer;
      startAutoAdvance(api.ankiGetCardFactor());
    } catch (e) {
      if (globalThis.ankiPlatform !== "desktop") {
        console.log("AnkiDroid API error", e);
      } else {
        goToAnswer = () => pycmd("ans");
        pycmd("AnkiJS.ankiGetCardFactor()", startAutoAdvance);
      }
    }
  }

    initAutoAdvance({
      // Customize options as you please
      goToAnswerSeconds: 4,
      answerSeconds: 3,
      easeThreshold: 2,
      easeStep: 0.7,
    });
</script>

In case you’re doing {{FrontSide}} in the card back, the javascript would get run again in the backside which is undesired. To fix that you can add a hidden div in the backside like this:

<div id="backside" style="display:none;"></div>

And then modify the front side code like this:

  var isBackside = document.getElementById("backside");
  if (!isBackside) {
    // Only init autoAdvance in the card front
    initAutoAdvance({
      // Customize options as you please
      goToAnswerSeconds: 4,
      answerSeconds: 3,
      easeThreshold: 2,
      easeStep: 0.7,
    });
  }

Edit: removed console.logs