Dials

HTML

<script src="demo.js"></script>
<link href="demo.css" rel="stylesheet" />

<div>
  <button id="run" type="button">Run</button>
  <span style="margin-left: 10px;">Repeats 3 times then stops.</span>
</div>

<div id="container">
  <div class="reel">
    <div class="digit">
      <div>0</div>
      <div>1</div>
      <div>2</div>
      <div>3</div>
      <div>4</div>
      <div>5</div>
      <div>6</div>
      <div>7</div>
      <div>8</div>
      <div>9</div>
      <div>0</div>
    </div>
  </div>
</div>

CSS

body {
  font-family: Arial, sans-serif;
}

#container {
  font-size: 60px;
  display: flex;
  width: fit-content;
  padding: 10px;
}

.reel {
  height: 1.1em;
  /* change overflow from hidden to 
     visible to see how the reel works: */
  overflow: hidden;
  border: 1px solid grey;
}

JavaScript

//
// A basic PoC
//
function spin() {
  for (const [idx, digit] of digits.entries()) {
    // -------------------------------------------------------------------

    /* DEMO ONE: continuous smooth scroll:  */
    digit.animate(
      [
        { offset: 1, transform: 'translateY(' + height * -10 + 'px)' },
        { offset: 1, transform: 'translateY(0)' },
      ],
      {
        duration: 5000,
        iterations: 3,
      },
    );

    // -------------------------------------------------------------------

    /* DEMO TWO: scroll with steps/ticks (hard-coded numbers, to make the 
                 code easier to read - but slower to maintain): 
    digit.animate([
      { offset: 0.05, transform: 'translateY(' + (height * -1) + 'px)' },
      { offset: 0.10, transform: 'translateY(' + (height * -1) + 'px)' },
      { offset: 0.15, transform: 'translateY(' + (height * -2) + 'px)' },
      { offset: 0.20, transform: 'translateY(' + (height * -2) + 'px)' },
      { offset: 0.25, transform: 'translateY(' + (height * -3) + 'px)' },
      { offset: 0.30, transform: 'translateY(' + (height * -3) + 'px)' },
      { offset: 0.35, transform: 'translateY(' + (height * -4) + 'px)' },
      { offset: 0.40, transform: 'translateY(' + (height * -4) + 'px)' },
      { offset: 0.45, transform: 'translateY(' + (height * -5) + 'px)' },
      { offset: 0.50, transform: 'translateY(' + (height * -5) + 'px)' },
      { offset: 0.55, transform: 'translateY(' + (height * -6) + 'px)' },
      { offset: 0.60, transform: 'translateY(' + (height * -6) + 'px)' },
      { offset: 0.65, transform: 'translateY(' + (height * -7) + 'px)' },
      { offset: 0.70, transform: 'translateY(' + (height * -7) + 'px)' },
      { offset: 0.75, transform: 'translateY(' + (height * -8) + 'px)' },
      { offset: 0.80, transform: 'translateY(' + (height * -8) + 'px)' },
      { offset: 0.85, transform: 'translateY(' + (height * -9) + 'px)' },
      { offset:...