<div id="container" class="container"></div>
$canvas-count: 10;
$canvas-width: 400px;
$animation-dur: 2s;

html, body {
  height: 100%;
}

body {
  display: flex;
  justify-content: center;
  align-items: center;
  perspective: 5000px;
}

.container {
  position: relative;
  width: $canvas-width;
  height: $canvas-width;
  background: rgba(black, .05);
  transition: all $animation-dur;
  transform-style: preserve-3d;
  animation: container 6s 1s 1;

  canvas {
    position: absolute;
    top: 50%;
    left: 50%;
    transition: all $animation-dur;
    transform: translate(-50%, -50%);

    @for $i from 0 through $canvas-count {
      &:nth-child(#{$i}) {
        animation: canvas-#{$i} 6s 1s 1;
      }
    }
  }

  &:hover {
    transform:
      translateX(-50%)
      rotateX(-27.5deg)
      rotateY(-45deg);

    @for $i from 0 through $canvas-count {
      canvas:nth-child(#{$i}) {
        transform:
          translate3d(-50%, -50%, #{($i - 1) * -50px})
      }
    }
  }
}

@keyframes container {
  33.3%, 66.6% {
    transform:
      translateX(-50%)
      rotateX(-27.5deg)
      rotateY(-45deg);
  }
}

@for $i from 0 through $canvas-count {
  @keyframes canvas-#{$i} {
    33.3%, 66.6% {
      transform:
        translate3d(-50%, -50%, #{($i - 1) * -50px})
    }
  }
}
View Compiled
var canvasCount = 10
var canvasWidth = 400

function drawSin(ctx, waveLength, x = 1, y) {
  var i = 0
  while (i++ < x) {
    ctx.fillRect(
      i,
      y + Math.sin((i / waveLength)) * waveLength,
      1, 1
    )
  }
}

var canvases = new Array(canvasCount)
  .join(' ')
  .split(' ')
  .map((c, i) => {
    var canvas = document.createElement('canvas')
    canvas.width = canvasWidth
    canvas.height = canvasWidth
    container.appendChild(canvas)
    return canvas
  })

var contexts = canvases.map(c => c.getContext('2d'))
contexts.forEach(ctx => ctx.fillStyle = 'red')

function draw() {
  contexts.forEach((ctx, index) => {
    ctx.clearRect(0, 0, canvasWidth, canvasWidth)
    i += 0.0002
    
    drawSin(
      ctx,
      60 / (Math.pow(index + 1, 1 + Math.sin(i))),
      canvasWidth,
      canvasWidth / 2
    )
  })
  requestAnimationFrame(draw)
}

var i = 0
draw()
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.