<!--
    Name: Cube Loader
    Created by: Eddy Koek
    Based on AE animation: https://www.instagram.com/p/BQyf0CqhPYZ
    Instagram: instagram.com/eddykoek
    More info: linktr.ee/eddykoek
    -->

<div class="CubeLoader" data-cubeloader>
  <div class="Cube" data-cube1></div>
  <div class="Cube" data-cube2></div>
  <div class="Cube" data-cube3></div>
  <div class="Cube" data-cube4></div>
  <div class="CubeHero" data-cubehero>
    <div class="CubeHero-child" data-cubehero-child></div>
  </div>
</div>
/*
    Name: Cube Loader
    Created by: Eddy Koek
    Based on AE animation: https://www.instagram.com/p/BQyf0CqhPYZ
    Instagram: instagram.com/eddykoek
    More info: linktr.ee/eddykoek
    */

body {
  margin: 0;
  padding: 0;
  background-color: #ccc;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}

.CubeLoader {
  position: relative;
  margin-left: -100px;
  margin-top: -100px;
  will-change: transform;
  transform-origin: 100% 100%;
}

.CubeHero {
  position: relative;
  width: 100px;
  height: 100px;
  background: #000;
  transform-origin: 100% 100%;
  will-change: transform;
}

.CubeHero-child {
  position: absolute;
  left: 50px;
  top: 50px;
  width: 50px;
  height: 50px;
  background: #fff;
  transform-origin: 100% 100%;
  will-change: transform;
}

.Cube {
  position: absolute;
  width: 100px;
  height: 100px;
  left: 0px;
  top: 0px;
  will-change: transform;
  transform-origin: 100% 100%;
  transform: scale(0);
  background: #999;
}

.Cube:nth-child(2) {
  left: 100px;
  top: 0px;
  transform-origin: 0 100%;
}

.Cube:nth-child(3) {
  left: 100px;
  top: 100px;
  transform-origin: 0 0;
}

.Cube:nth-child(4) {
  left: 0px;
  top: 100px;
  transform-origin: 100% 0;
}
/*
    Name: Cube Loader
    Created by: Eddy Koek
    Based on AE animation: https://www.instagram.com/p/BQyf0CqhPYZ
    Instagram: instagram.com/eddykoek
    More info: linktr.ee/eddykoek
    */

// refs
const cubeLoader = document.querySelector("[data-cubeloader]");
const cubeHero = document.querySelector("[data-cubehero]");
const cubeHeroChild = document.querySelector("[data-cubehero-child]");
const cube1 = document.querySelector("[data-cube1]");
const cube2 = document.querySelector("[data-cube2]");
const cube3 = document.querySelector("[data-cube3]");
const cube4 = document.querySelector("[data-cube4]");

// init
const cubeAnimation = ({
  target,
  delay = 0,
  duration1 = 0.5,
  duration2,
  duration3,
  ease = Linear.easeNone
}) => {
  let tl = gsap.timeline({ repeat: -1 });
  tl.to(target, {
    duration: duration1,
    delay,
    scale: 1,
    ease: Power4.easeInOut
  })
    .to(target, { duration: duration2, scale: 0, ease })
    .to(target, { duration: duration3 });
};

const tlCubeHero = gsap.timeline({ repeat: -1, paused: true });

tlCubeHero
  .to(cubeHero, { duration: 0.5, rotate: "+=90deg", ease: Power3.easeInOut })
  .to(cubeHeroChild, {
    duration: 0.5,
    rotate: "+=360deg",
    ease: Power3.easeInOut
  })
  .to(cubeHero, { duration: 0.5, rotate: "+=90deg", ease: Power3.easeInOut })
  .to(cubeHeroChild, {
    duration: 0.5,
    rotate: "+=360deg",
    ease: Power3.easeInOut
  })
  .to(cubeHero, { duration: 0.5, rotate: "+=90deg", ease: Power3.easeInOut })
  .to(cubeHeroChild, {
    duration: 0.5,
    rotate: "+=360deg",
    ease: Power3.easeInOut
  })
  .to(cubeHero, { duration: 0.5, rotate: "+=90deg", ease: Power3.easeInOut })
  .to(cubeHeroChild, {
    duration: 0.5,
    rotate: "+=360deg",
    ease: Power3.easeInOut
  });

const tlCubeLoader = gsap.timeline({ repeat: -1, paused: true });

tlCubeLoader
  .to(cubeLoader, {
    duration: 0.5,
    delay: 0.5,
    scale: 0.75,
    ease: Power3.easeInOut
  })
  .to(cubeLoader, {
    duration: 0.5,
    delay: 0.5,
    scale: 0.5,
    ease: Power3.easeInOut
  })
  .to(cubeLoader, {
    duration: 0.5,
    delay: 0.5,
    scale: 0.25,
    ease: Power3.easeInOut
  })
  .to(cubeLoader, {
    duration: 0.5,
    delay: 0.5,
    scale: 1,
    ease: Power3.easeInOut
  });

setTimeout(() => {
  // start animation loop
  tlCubeHero.play();
  tlCubeLoader.play();

  cubeAnimation({ target: cube1, duration2: 1, duration3: 2.5 });
  cubeAnimation({ target: cube2, delay: 1, duration2: 1, duration3: 1.5 });
  cubeAnimation({ target: cube3, delay: 2, duration2: 1, duration3: 0.5 });
  cubeAnimation({
    target: cube4,
    delay: 3,
    duration2: 0.4,
    duration3: 0.1,
    ease: Power3.easeInOut
  });
}, 500);

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://unpkg.co/gsap@3/dist/gsap.min.js