main#home-page(data-wrapper="", role="main")
  .container-fluid
    h2.font-sz-4xl.font-sans.font-600 Playback Controls
    .jumbotron.jumbotron-fluid.my-2.p-4.rounded-lg.box-shadow.text-dark.bg-warning
      .playback-demo
        //- h3.font-sz-xl.font-sans.font-400 Keyframes
        //- p Click on the box to play the animation
        - for (let i = 0; i < 5; i ++) {
          .contain
            .el
            .el-initial
        - }

        .controls.row.mx-0.mt-5.align-items-center
          .col-2
            button#playstate-toggle.btn.btn-light(
              type="button",
              title="Play/Pause Toggle",
              data-playstate="paused"
            ) 
              i.fa.fa-play(aria-hidden="true")
              i.fa.fa-pause(aria-hidden="true")
              i.fa.fa-redo(aria-hidden="true")
            span.text-center(id=`progress-output`) 0
          input#progress.col-10.form-control-range(
            type="range",
            value="0",
            min="0",
            max="100",
            steps="0.0001"
          )
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"] {
  width: 100%;
  padding: 0;
  margin: 0;
}
html:not(.unsupported) .support {
  display: none;
}

.col-2 {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

#playstate-toggle[data-playstate="running"] {
  .fa-play,
  .fa-redo {
    display: none;
  }
}
#playstate-toggle[data-playstate="paused"] {
  .fa-pause,
  .fa-redo {
    display: none;
  }
}

#playstate-toggle[data-playstate="finished"] {
  .fa-play,
  .fa-pause {
    display: none;
  }
}
View Compiled
import { animate } from "https://cdn.skypack.dev/@okikio/animate";

/* Properties Section */
// Playback Controls Demo
(() => {
  let containerSel = ".playback-demo";

  let playstateEl = document.querySelector(
    "#playstate-toggle"
  ) as HTMLInputElement;
  let progressEl = document.querySelector("#progress") as HTMLInputElement;

  let progressOutputEl = document.querySelector("#progress-output");
  let progressValue = progressEl.value;
  let oldState: AnimationPlayState;

  let DOMNodes = document.querySelectorAll(`${containerSel} .el`);
  let anim = animate({
    target: DOMNodes,

    transform: ["translateX(0px)", "translateX(300px)"],
    opacity(index, total, element) {
      return [0, (index + 1) / total];
    },

    fillMode: "both",
    easing: "out-cubic",
    loop: 1,
    speed: 1,
    direction: "alternate",

    delay(index) {
      return ((index + 1) * 500) / 2;
    },
    duration(index: number) {
      return (index + 1) * 500;
    },

    padEndDelay: true,
    autoplay: true
  });

  let updatePlayState = () => {
    oldState = anim.getPlayState();
    playstateEl.setAttribute("data-playstate", oldState);
  };
  anim.on("finish begin", updatePlayState).on("update", (progress) => {
    progressEl.value = `` + progress.toFixed(4);
    progressOutputEl.textContent = `${Math.round(progress)}%`;
  });

  playstateEl.addEventListener("click", () => {
    if (anim.is("running")) anim.pause();
    else if (anim.is("finished")) anim.reset();
    else anim.play();

    updatePlayState();
  });

  progressEl.addEventListener("input", (e) => {
    let percent = Number(progressEl.value);
    anim.pause();
    anim.setProgress(percent);
  });

  progressEl.addEventListener("change", () => {
    oldState !== "paused" ? anim.play() : anim.pause();

    updatePlayState();
  });
})();
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
  2. https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css

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