Integrations

<link rel="stylesheet" href="https://unpkg.com/lenis@1.3.20/dist/lenis.css" />
<script src="https://unpkg.com/lenis@1.3.20/dist/lenis.min.js"></script>
<script>
  gsap.registerPlugin(ScrollTrigger);

  const lenis = new Lenis({
    duration: 1.5,
    easing: (t) => 1 - Math.pow(1 - t, 3),
    smooth: true,
    smoothTouch: false, // ✅ important
  });

  // sync
  lenis.on('scroll', ScrollTrigger.update);

  // raf loop
  function raf(time) {
    lenis.raf(time);
    requestAnimationFrame(raf);
  }
  requestAnimationFrame(raf);

  // ✅ correct scroller
  ScrollTrigger.scrollerProxy(document.documentElement, {
    scrollTop(value) {
      return arguments.length ? lenis.scrollTo(value, { immediate: true }) : lenis.scroll;
    },
    getBoundingClientRect() {
      return {
        top: 0,
        left: 0,
        width: window.innerWidth,
        height: window.innerHeight,
      };
    },
  });

  // ✅ important
  ScrollTrigger.defaults({
    scroller: document.documentElement,
  });

  // refresh fix
  ScrollTrigger.addEventListener('refresh', () => lenis.resize());

  ScrollTrigger.refresh();
</script>
<script>
gsap.registerPlugin(ScrollTrigger);

gsap.utils.toArray(".counter").forEach(counter => {

  const finalText = counter.textContent.trim();

  const endValue = parseFloat(finalText.replace(/[^0-9.-]/g, ""));
  const suffix = finalText.replace(/[0-9.-]/g, "");
  const decimals = finalText.includes(".") ? 1 : 0;

  // Reset to zero
  counter.textContent = "0" + suffix;

  const obj = { value: 0 };

  gsap.to(obj, {
    value: endValue,
    duration: 5,
    ease: "power2.out",
    scrollTrigger: {
      trigger: counter,
      start: "top 80%",
      once: true
    },
    onUpdate() {
      counter.textContent =
        obj.value.toFixed(decimals) + suffix;
    }
  });

});
</script>
<script>

gsap.registerPlugin(ScrollTrigger);

const mm = gsap.matchMedia();

mm.add({
  desktop: "(min-width: 992px)",
  tablet: "(min-width: 768px) and (max-width: 991px)",
  mobile: "(max-width: 767px)"
}, (context) => {

  let { desktop, tablet, mobile } = context.conditions;

  let pos;

  if (desktop) {
    pos = {
      first:  { x: -240, y: 0,   rot: -25, ry: 35, rx: -15, z: 0 },
      second: { x: -110, y: -35, rot: -12, ry: 25, rx: -8,  z: 20 },
      third:  { x: 20,   y: -35, rot: -2,  ry: 15, rx: -2,  z: 60 },
      fourth: { x: 150,  y: -10, rot: 12,  ry: 8,  rx: 2,   z: 120 }
    };
  }

  if (tablet) {
    pos = {
      first:  { x: -170, y: 0,   rot: -20, ry: 25, rx: -10, z: 0 },
      second: { x: -80,  y: -25, rot: -10, ry: 18, rx: -6,  z: 20 },
      third:  { x: 15,   y: -25, rot: -2,  ry: 10, rx: -2,  z: 40 },
      fourth: { x: 100,  y: -8,  rot: 10,  ry: 6,  rx: 2,   z: 70 }
    };
  }

  if (mobile) {
    pos = {
      first:  { x: -95, y: 0,   rot: -12, ry: 12, rx: -5, z: 0 },
      second: { x: -35, y: -12, rot: -6,  ry: 8,  rx: -2, z: 10 },
      third:  { x: 25,  y: -12, rot: 2,   ry: 5,  rx: 0,  z: 20 },
      fourth: { x: 80,  y: 0,   rot: 8,   ry: 2,  rx: 2,  z: 30 }
    };
  }

  gsap.set(".studio-image-wrap", {
    x: 0,
    y: 0,
    rotation: 0,
    rotationX: 0,
    rotationY: 0,
    z: 0,
    transformOrigin: "center center",
    transformStyle: "preserve-3d"
  });

  const master = gsap.timeline({
    repeat: -1,
    repeatDelay: 2
  });

  master.to({}, { duration: 0.4 });

  master.to(".studio-image-wrap.ist", {
    x: pos.first.x,
    y: pos.first.y,
    rotation: pos.first.rot,
    rotationY: pos.first.ry,
    rotationX: pos.first.rx,
    z: pos.first.z,
    duration: 1.1,
    ease: "power3.inOut"
  }, 0)

  .to(".studio-image-wrap._2nd", {
    x: pos.second.x,
    y: pos.second.y,
    rotation: pos.second.rot,
    rotationY: pos.second.ry,
    rotationX: pos.second.rx,
    z: pos.second.z,
    duration: 1.1,
    ease: "power3.inOut"
  }, 0.08)

  .to(".studio-image-wrap._3rd", {
    x: pos.third.x,
    y: pos.third.y,
    rotation: pos.third.rot,
    rotationY: pos.third.ry,
    rotationX: pos.third.rx,
    z: pos.third.z,
    duration: 1.1,
    ease: "power3.inOut"
  }, 0.16)

  .to(".studio-image-wrap._4th", {
    x: pos.fourth.x,
    y: pos.fourth.y,
    rotation: pos.fourth.rot,
    rotationY: pos.fourth.ry,
    rotationX: pos.fourth.rx,
    z: pos.fourth.z,
    duration: 1.1,
    ease: "power3.inOut"
  }, 0.24)

  .to(".studio-image-wrap", {
    y: "+=10",
    rotation: "+=2",
    duration: 2,
    ease: "sine.inOut",
    stagger: {
      each: 0.12,
      yoyo: true,
      repeat: 1
    }
  })

  .to(".studio-image-wrap", {
    x: 0,
    y: 0,
    z: 0,
    rotation: 0,
    rotationX: 0,
    rotationY: 0,
    duration: 1.2,
    ease: "power3.inOut"
  });

});

</script>