<div class="grid"></div>
:root {
  --cols: 0;
  --rows: 0;
}

* {
  box-sizing: border-box;
  position: relative;
}

body {
  background: #000;
  overflow-x: hidden;
}

.grid {
  pointer-events: none;
}

.row {  
  display: flex;
}

.cell {
  flex: 1;
  padding-bottom: calc(100% / var(--cols));  
  perspective: 1000px;
}

.item {
  position: absolute;
  top: 1px;
  left: 1px;
  right: 1px;
  bottom: 1px;
  z-index: 1;
}

.grid .item {
  will-change: transform;
}
View Compiled

var frag = document.createDocumentFragment();
var grid = document.querySelector(".grid");

var rows = 100;
var cols = 7;

var observer = new IntersectionObserver(handleIntersect, {
  rootMargin: (1 / cols * 100) + "% 0px"
});

TweenLite.set("html", {
  "--cols": cols,
  "--rows": rows
});

for (var r = 0; r < rows; r++) {
  
  var hue = r / rows * 360;
  var row = createElement("row", frag);
  var tl = row._timeline = new TimelineLite({ paused: true })
  
  for (var c = 0; c < cols; c++) {
     
    var cell = createElement("cell", row);
    var item = createElement("item", cell);
        
    TweenLite.set(item, {   
      autoAlpha: 0,
      force3D: true,
      backgroundColor: "hsl(" + hue + ",80%," + random(50, 70) + "%)",
      scale: Math.random() < 0.8 ? 0 : random(1.1, 1.3),
      rotationX: random(-180, 180),
      rotationY: random(-180, 180),
      rotationZ: random(-180, 180),
      xPercent: random(-300, 300),
      yPercent: random(-300, 300)
    });
    
    tl.to(item, random(0.4, 1), {
      autoAlpha: 1,
      scale: 1,
      rotationX: 0,
      rotationY: 0,
      rotationZ: 0,
      xPercent: 0,
      yPercent: 0
    }, random(0.15));    
  }  
  
  tl.progress(1);
}

grid.appendChild(frag);

for (var i = 0; i < grid.children.length; i++) {
  observer.observe(grid.children[i]);
}

function handleIntersect(entries, observer) {
  
  for (var i = 0; i < entries.length; i++) {
    
    var entry = entries[i];
    
    if (entry.isIntersecting) {
      entry.target._timeline.play();
    } else {
      entry.target._timeline.pause(0);
    } 
  }
}

function createElement(className, parent) {
  var element = document.createElement("div");
  element.className = className;
  parent.appendChild(element);
  return element;
}

function random(min, max) {
  if (max == null) { max = min; min = 0; }
  if (min > max) { var tmp = min; min = max; max = tmp; }
  return min + (max - min) * Math.random();
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/gsap/2.0.2/TweenMax.min.js