<div id="fps">0</div>

<div class="container">
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  <canvas width="320" height="240"></canvas>
  
</div>
#fps {
  position: fixed;
  background-color: #000;
  color: #fff;
  padding: 4px 8px;
}

canvas {
  width: 100px;
}
const framesLink = 'https://i.imgur.com/QvNKsCf.png';
const frameWidth = 320;
const frameHeight = 240;

class CanvasPlayer {
  constructor(el, image, frames) {
    this.fps = Math.round(24 + Math.random() * 24);
    this.frames = frames;
    this.image = image;
    this.ctx = el.getContext('2d');
    this.begin = 0;
    this.duration = frames / this.fps * 1000;
    this.timeOffset = Math.random() * 500;
  }

  update(now) {
    this.begin = this.begin || now;
    const elapsed = now - this.begin + this.timeOffset;
    const progress = elapsed / this.duration % 1;
    const nf = Math.round(progress * (this.frames - 1));
    const offset = frameWidth * nf;

    this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
    this.ctx.drawImage(this.image, offset, 0, frameWidth, frameHeight, 0, 0, frameWidth, frameHeight);
  }
}

function loadImg(src) {
  return new Promise(resolve => {
    const img = new Image();
    img.addEventListener('load', () => resolve(img));
    img.crossOrigin = 'Anonymous';
    img.src = src;
  });
}

loadImg(framesLink).then((image) => {
  const canvases = [...document.querySelectorAll('.container > canvas')]
    .map(c => new CanvasPlayer(c, image, 30));
  
  let prev = 0;
  function loop(now) {
    prev = prev || now;
    fps.textContent = Math.round(1e3 / (now - prev)) + ' fps';
    prev = now;
    
    canvases.forEach(c => c.update(now));
    requestAnimationFrame(loop);
  }
  requestAnimationFrame(loop);
});

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.