<div class="timeline">
  <svg class="timeline__clip">
    <defs>
      <linearGradient id="gradient" gradientUnits="userSpaceOnUse">
        <stop offset="0%" stop-color="#f6bbdb" />
        <stop offset="100%" stop-color="#e50b80" />
      </linearGradient>
      
      <clipPath id="clip">
        <rect y="14" width="100%" height="28" rx="14" />
      </clipPath>
    </defs>

    <g class="timeline__back">
      <rect class="timeline__bar" y="14" width="100%" height="28" rx="14" />
      <circle class="timeline__dot" cx="10%" cy="50%" r="28" />
      <circle class="timeline__dot" cx="50%" cy="50%" r="28" />
      <circle class="timeline__dot" cx="100%" cy="50%" r="28" transform="translate(-28 0)" />
    </g>

    <g class="timeline__front" fill="url(#gradient)">
      <rect class="timeline__bar" x="-100%" y="14" width="100%" height="28" rx="14" clip-path="url(#clip)"/>
      <circle class="timeline__dot" cx="10%" cy="50%" r="28" transform="scale(0)"/>
      <circle class="timeline__dot" cx="50%" cy="50%" r="28" transform="scale(0)"/>
      <circle class="timeline__dot" cx="100%" cy="50%" r="28" transform="translate(-28 0) scale(0)" />
    </g>
  </svg>
</div>

<button class="play">play</button>
<input class="seek" type="range" min="0" max="100" value="60">
body {
  background: #f9e8ee;
}

.timeline {
  position: relative;
  height: 56px;
}

.timeline__clip {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

.timeline__back {
  fill: #fff;
}

.timeline__dot {
  transform-origin: 50% 50%;
  transform-box: fill-box;
}
import anime from "https://cdn.skypack.dev/animejs@3.2.1";

const barDuradion = 3000;
const dotDuradion = barDuradion * 0.05;
const bar = document.querySelector(".timeline__front .timeline__bar");
const dots = document.querySelectorAll(".timeline__front .timeline__dot");
const play = document.querySelector(".play");
const seek = document.querySelector(".seek");

const timeline = anime.timeline({
  easing: "linear",
  duration: dotDuradion,
  autoplay: false,
  update({ progress }) {
    seek.value = progress;
  }
});

timeline
  .add({
    targets: bar,
    x: "0%",
    easing: "linear",
    duration: barDuradion
  })
  .add({
    targets: dots[0],
    transform: "scale(1)",
  }, barDuradion * 0.10)
  .add({
    targets: dots[1],
    transform: "scale(1)",
  }, barDuradion * 0.50)
  .add({
    targets: dots[2],
    transform: "translate(-28 0) scale(1)",
  }, barDuradion * 1.00);


play.addEventListener("click", () => {
  timeline.play();
});

seek.addEventListener("input", ({ target: { value } }) => {
  timeline.seek(timeline.duration * (+value / 100));
});

timeline.seek(timeline.duration * 0.60)

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.