main#home-page(data-wrapper="", role="main")
  .container
    h2.font-sz-3xl.font-sans.font-400 Timing Options
    .animation-containers.jumbotron.jumbotron-fluid.my-2.p-4.rounded-lg.box-shadow.text-dark.bg-warning
      .animation-container.timing-options-demo
        h3.font-sz-xl.font-sans.font-400 Callback/Function Type
        p Click on the box to play the animation

        .row.mx-0.align-items-center
          - let options = ['duration', 'delay', 'endDelay', 'speed', 'loop'];
          each option in options
            .col-2
              label(for=option)= option
            .col-2
              | (
              span(id=`${option}-output`) 0
              | )
            .col-8.align-items-center
              if option == "speed"
                input.form-control-range(
                  id=option,
                  type="range",
                  value="1",
                  min="0.25",
                  max="3",
                  step="0.25"
                )
              else if option == "loop"
                input.form-control-range(
                  id=option,
                  type="range",
                  value="1",
                  min="0.25",
                  max="10",
                  step="0.25"
                )
              else if option == "duration"
                input.form-control-range(
                  id=option,
                  type="range",
                  value="250",
                  min="200",
                  max="3000",
                  step="50"
                )
              else
                input.form-control-range(
                  id=option,
                  type="range",
                  value="0",
                  min="0",
                  max="3000",
                  step="100"
                )

          - let easings = ['linear', 'ease', 'ease-in', 'ease-out', 'ease-in-out', 'in-sine', 'out-sine', 'in-out-sine', 'in-quad', 'out-quad', 'in-out-quad', 'in-cubic', 'out-cubic', 'in-out-cubic', 'in-quart', 'out-quart', 'in-out-quart', 'in-quint', 'out-quint', 'in-out-quint', 'in-expo', 'out-expo', 'in-out-expo', 'in-circ', 'out-circ', 'in-out-circ', 'in-back', 'out-back', 'in-out-back'];

          .col-2
            label(for="easing") easing

          .col-10.align-items-center
            select#easing.custom-select
              each ease in easings
                if ease == "in-out-quad"
                  option(value=ease, selected)= ease
                else
                  option(value=ease)= ease

          - let directions = ['normal', 'reverse', 'alternate', 'alternate-reverse'];

          .col-2
            label(for="direction") direction

          .col-10.align-items-center
            select#direction.custom-select
              each direction in directions
                if direction == "alternate"
                  option(value=direction, selected)= direction
                else
                  option(value=direction)= direction

        p.text-white.text-monospace.font-weight-bold Note: if you add endDelay, the animation won't complete until the endDelay period is over.
        p#finish.text-success Animation is complete.
        - for (let i = 0; i < 5; i ++) {
          .contain
            .el
            .el-initial
        - }
View Compiled
html,
body {
  font-family: Manrope, sans-serif;
}

.div {
  @apply bg-blue-400 w-10 h-10 rounded relative m-2;
  --size: 8vmin;
  width: var(--size);
  height: var(--size);
}

.el,
.el-initial {
  --size: 4vmin;
  width: var(--size);
  height: var(--size);
  /*     transform: scale(1); */
  // border-radius: 8%;
  margin: 5px;
  background: #616aff;
  position: relative;
}

.svg {
  margin: auto;
  display: block;
  width: 500px;
  height: 300px;
  max-height: 100vh;
  max-width: 100%;

  & path {
    stroke: #fff2b1;
    stroke-dasharray: 400 400;
    stroke-dashoffset: 0;
  }
}

.el-initial {
  opacity: 0.6;
  position: absolute;
  display: block;
  margin-top: 0;
  top: 0;
}

.animation-container {
  transition: background-color 0.5s ease;
  background-color: rgba(0, 0, 0, 0.085);
  border-radius: 5px;
  padding: 5px;
  cursor: pointer;

  &:hover {
    background-color: rgba(255, 255, 255, 0.25);
  }
}

.contain {
  position: relative;
}

.animation-container + .animation-container {
  margin-top: 2em;
}

input[type="range"] {
  height: 100%;
  width: 100%;
  padding: 0;
  margin: 0;
}
html:not(.unsupported) .support {
  display: none;
}

#finish {
  transition: opacity ease 0.25s;
  opacity: 0;
}
View Compiled
import { animate } from "https://cdn.skypack.dev/@okikio/animate";

/* Properties Section */
// Timing Options (Callback/Function Type) Demo
let containerSel = ".timing-options-demo";

let finishEl = document.querySelector("#finish");
let delayEl = document.querySelector("#delay");
let durationEl = document.querySelector("#duration");
let endDelayEl = document.querySelector("#endDelay");
let speedEl = document.querySelector("#speed");
let loopEl = document.querySelector("#loop");
let easingEl = document.querySelector("#easing");
let directionEl = document.querySelector("#direction");
// let fillModeEl = document.querySelector("#fillMode");

let delayOutputEl = document.querySelector("#delay-output");
let durationOutputEl = document.querySelector("#duration-output");
let endDelayOutputEl = document.querySelector("#endDelay-output");
let speedOutputEl = document.querySelector("#speed-output");
let loopOutputEl = document.querySelector("#loop-output");

let delayValue = delayEl.value;
let durationValue = durationEl.value;
let endDelayValue = endDelayEl.value;
let speedValue = speedEl.value;
let loopValue = loopEl.value;
let easingValue = easingEl.value;
let directionValue = directionEl.value;
// let fillModeValue = fillModeEl.value;

durationOutputEl.textContent = durationValue;
endDelayOutputEl.textContent = endDelayValue;
speedOutputEl.textContent = speedValue;
loopOutputEl.textContent = loopValue;
delayOutputEl.textContent = delayValue;

durationEl.addEventListener("input", (e) => {
  durationValue = durationEl.value;
  durationOutputEl.textContent = durationValue;
});

delayEl.addEventListener("input", (e) => {
  delayValue = delayEl.value;
  delayOutputEl.textContent = delayValue;
});

speedEl.addEventListener("input", (e) => {
  speedValue = speedEl.value;
  speedOutputEl.textContent = speedValue;
});

loopEl.addEventListener("input", (e) => {
  loopValue = loopEl.value;
  loopOutputEl.textContent = loopValue;
});

endDelayEl.addEventListener("input", (e) => {
  endDelayValue = endDelayEl.value;
  endDelayOutputEl.textContent = endDelayValue;
});

easingEl.addEventListener("input", (e) => {
  easingValue = easingEl.value;
});

directionEl.addEventListener("input", (e) => {
  directionValue = directionEl.value;
});

// fillModeEl.addEventListener("input", (e) => {
//   fillModeValue = fillModeEl.value;
// });

let container = document.querySelector(containerSel);
container.addEventListener("click", () => {
  finishEl.style.opacity = "0";
  delayValue = delayEl.value;
  durationValue = durationEl.value;
  endDelayValue = endDelayEl.value;
  speedValue = speedEl.value;
  loopValue = loopEl.value;
  easingValue = easingEl.value;
  directionValue = directionEl.value;
  // fillModeValue = fillModeEl.value;

  animate({
    target: `${containerSel} .el`,

    opacity(index, total, element) {
      console.log(element);
      return [0, Math.min((index + 1 + 0.2) / total, 1)];
    },
    transform: ["translateX(0px)", "translateX(250px)"],

    duration: (i) => (i + 1) * +durationValue,
    speed: +speedValue, // Speed can be a function; but in this situation its understand the animation if speed isn't a function
    endDelay: (i) => (i + 1) * +endDelayValue,
    delay: (i) => (i + 1) * +delayValue,
    loop: (i) => (+loopValue == 1 ? +loopValue : (i + 1) * +loopValue),
    fillMode: "both",

    // I feel these shouldn't be functions for your understanding
    direction: directionValue,
    easing: easingValue,
    autoplay: true
  }).on("finish", () => {
    finishEl.style.opacity = "1";
  });
});
View Compiled

External CSS

  1. https://fonts.googleapis.com/css2?family=Manrope:wght@500;600;700;800&amp;family=Material+Icons&amp;family=Material+Icons+Round&amp;display=swap

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.0/js/bootstrap.min.js