<div class="flex flex-wrap justify-center items-center vh-100"> 
  <div>
    <svg
      viewBox="0 0 400 400"
      class="db w5 h5 center"
      fill="none"
      stroke-linejoin="round"
      stroke-linecap="round"
      stroke-width="4">
      <g transform="translate(200 200)">
        <path 
          id="square"
          stroke="#0f0" 
          d="M -155.885 -155.885 h 311.77 v 311.77 h -311.77 z" 
        />
      </g>
      <circle cx="200" cy="200" r="4" stroke="#ccc" stroke-width="4" />
      <g id="container">
        <circle cx="0" cy="0" r="4" stroke="#f0f" stroke-width="4" />
        <path
          id="reuleaux-triangle"
          stroke="#333"
          d="M 90 155.88457268119896 
             A 311.77 311.77 0 0 1 -180 0
             A 311.77 311.77 0 0 1 90 -155.885
             A 311.77 311.77 0 0 1 90 155.885
             Z"
        />
      </g>
    </svg>
    <div class="mt4 flex items-center">
      <button 
        class="bg-animate hover-bg-light-gray lh-solid f7 ttu tracked bg-none bw1 bg-white ba br-0 b--dark-gray tc pv2 ph2"               
        id="play">
        play
      </button>
      <button 
        class="bg-animate hover-bg-light-gray lh-solid f7 ttu tracked bg-none bw1 bg-white ba b--dark-gray tc pv2 ph2 mr3"              
        id="pause">
        pause
      </button>
      <input class="input-range-rv"
        id="progress"
        type="range" step=".001" type="range" min="0" max="100" value="0" />
    </div>
  </div>
</div>
.input-range-rv {
  vertical-align: middle;
  background-color: transparent;
  padding-top: 8px;
  padding-top: 0.5rem;
  padding-bottom: 8px;
  padding-bottom: 0.5rem;
  color: inherit;
  background-color: transparent;
  -webkit-appearance: none;
}

.input-range-rv::-webkit-slider-thumb {
  position: relative;
  width: 8px;
  width: 0.5rem;
  height: 20px;
  height: 1.25rem;
  cursor: pointer;
  margin-top: -8px;
  margin-top: -0.5rem;
  border-radius: 3px;
  background-color: #333;
  -webkit-appearance: none;
}

/* Touch screen friendly pseudo element */
.input-range-rv::-webkit-slider-thumb:before {
  content: '';
  display: block;
  position: absolute;
  top: -8px;
  top: -0.5rem;
  left: -14px;
  left: -0.875rem;
  width: 36px;
  width: 2.25rem;
  height: 36px;
  height: 2.25rem;
  opacity: 0;
}

.input-range-rv::-moz-range-thumb {
  width: 8px;
  width: 0.5rem;
  height: 20px;
  height: 1.25rem;
  cursor: pointer;
  border-radius: 3px;
  border-color: transparent;
  border-width: 0;
  background-color: #333;
}

.input-range-rv::-webkit-slider-runnable-track {
  height: 4px;
  height: 0.25rem;
  cursor: pointer;
  border-radius: 3px;
  background-color: #ccc;
}

.input-range-rv::-moz-range-track {
  height: 4px;
  height: 0.25rem;
  cursor: pointer;
  border-radius: 3px;
  background-color: #ccc;
}

.input-range-rv:focus {
  outline: none;
}

const triangle = document.querySelector('#reuleaux-triangle');
const container = document.querySelector('#container');

triangle.setAttribute('transform', `rotate(0)`);
container.setAttribute('transform', `translate(${200 + 24.115} 200)`);

const tl = anime({
  targets: { beta: 0, theta: 0 },
  theta: [0, 6 * Math.PI],
  beta: [0, -360],
  easing: 'linear',
  duration: 8000,
  loop: true,
  // autoplay: false,
  update: (anim) => {
    const t = anim.animations[0].animatable.target.theta;
    const b = anim.animations[0].animatable.target.beta;
    const a = 24.115;
    const n = 2.36185;
    const x = Math.pow( Math.abs( Math.cos( t ) ), 2 / n ) * a * Math.sign( Math.cos( t ) );
    const y = Math.pow( Math.abs( Math.sin( t ) ), 2 / n ) * a * Math.sign( Math.sin( t ) );
    triangle.setAttribute('transform', `rotate(${b})`);
    container.setAttribute('transform', `translate(${200 + x} ${200 + y})`);
    progressEl.value = anim.progress;
  }
});

var progressEl = document.querySelector('#progress');

document.querySelector('#play').onclick = tl.play;
document.querySelector('#pause').onclick = tl.pause;

progressEl.addEventListener('input', function() {
  tl.seek(tl.duration * (progressEl.value / 100));
});

['input','change'].forEach(function(evt) {
  progressEl.addEventListener(evt, function() {
    tl.seek(tl.duration * (progressEl.value / 100));
  });
});
View Compiled

External CSS

  1. https://cdnjs.cloudflare.com/ajax/libs/tachyons/4.9.1/tachyons.css

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/animejs/2.2.0/anime.js