instruction
Guide for Orvix Webflow Template
GSAP Guide
very GSAP code used on this template is here. How to edit them and find them is explain on this page. In every code block on this page, we added additional explanation to help you understand everything.
You can find the code in (Site settings) Footer Code.
Preload Section GSAP Animation
Scramble Text & Progress Counter Preload Animation
<script>
  addEventListener("DOMContentLoaded", () => {
  	if (!document.body.classList.contains("page-home")) return;

    /* ================= PRELOADER ================= */

    gsap.registerPlugin(ScrollTrigger);

    let scrollPos = 0;
	let move = 0

    if (w <= 480) {
      move = 60;
    } else {
      move = 300;
    }

    const scramble = document.querySelectorAll(".scramble");
    const countEl = document.querySelector(".counting");
    const bgAbs = document.querySelector(".bg-absolute");
    const wrapper = document.querySelector(".wrapper-pre-loading");

    gsap.set(scramble, {
      opacity: 1,
      y: 0,
    });

    requestAnimationFrame(() => {
      gsap.set("body", {
        position: "fixed",
        width: "100%",
        top: scrollPos,
        overflow: "hidden",
      });
    });

    const mainTL = gsap.timeline({
      defaults: { ease: "power2.out" },
    });

    mainTL
      .fromTo(
        countEl,
        { innerText: 1, y: -420, opacity: 0 },
        {
          innerText: 60,
          duration: 1.1,
          snap: { innerText: 1 },
          opacity: 1,
          y: -200,
          onUpdate: () => {
            countEl.innerText = Math.max(1, Math.round(countEl.innerText));
          },
        }
      )
      .to(countEl, {
        innerText: 100,
        duration: 1.2,
        ease: "expo.out",
        y: 0,
        snap: { innerText: 1 },
        onUpdate: () => {
          countEl.innerText = Math.round(countEl.innerText);
        },
      });

    mainTL.add("mid", 1.3);

    mainTL.from(
      scramble,
      {
        y: move,
        duration: 1,
        ease: "power3.out",
        stagger: 0.25,
      },
      "mid"
    );

    mainTL.to(
      scramble,
      {
        duration: 1.8,
        stagger: 0.22,
        scrambleText: {
          text: "{original}",
          chars: "+?84564XERS",
          speed: 0.7,
        },
      },
      "mid+=0.4"
    );

    mainTL
      .to(bgAbs, {
        y: "-100vh",
        duration: 1.1,
        ease: "power4.inOut",
      })
      .to(
        countEl,
        {
          opacity: 0,
          duration: 0.6,
        },
        "<"
      )
      .to(
        wrapper,
        {
          opacity: 0,
          duration: 0.6,
          onComplete: () => {
            wrapper.style.display = "none";

            gsap.set("body", {
              position: "static",
              overflow: "auto",
              top: 0,
            });

            window.scrollTo(0, scrollPos);
            ScrollTrigger.refresh();
          },
        },
        "-=0.2"
      );

  });
</script>
Story Section GSAP Animation
Interactive Circular Story Reveal on Scroll
<script>
  addEventListener("DOMContentLoaded", () => {

    /* ================= STORY CIRCLE ================= */

    const w = window.innerWidth;

    if (w > 480) {
      let radius;

      if (w <= 768) {
        radius = w * 0.28;
      } else {
        radius = w * 0.16;
      }

      const cardStory = gsap.utils.toArray(".card-story");
      const total = cardStory.length;
      const section = document.querySelector(".tracks");

      gsap.to(cardStory, {
        x: (i) => Math.cos((i / total) * Math.PI * 2) * radius,
        y: (i) => Math.sin((i / total) * Math.PI * 2) * radius,
        rotation: (i) => ((i / total) * Math.PI * 2 * 180) / Math.PI + 90,
        ease: "expo.inOut",
        scrollTrigger: {
          trigger: section,
          start: "top+=45% top",
          end: "top+=70% top",
          scrub: 2,
        },
      });

      gsap.to(".block-card-story", {
        rotate: 360,
        ease: "power1.inOut",
        transformOrigin: "center center",
        scrollTrigger: {
          trigger: section,
          start: "top+=70% top",
          end: "bottom top",
          scrub: 1.5,
          anticipatePin: 1,
        },
      });
    }

  });
</script>
Service Section GSAP Animation
Orbital Service Cards Reveal on Scroll
<script>
  addEventListener("DOMContentLoaded", () => {

    /* ================= SERVICE ORBIT ================= */

    const w = window.innerWidth;
    
    let radiusService;

    if (w <= 480) {
      radiusService = w * 0.6;
    } else if (w <= 768) {
      radiusService = w * 0.3;
    } else {
      radiusService = w * 0.26;
    }

    const cardsService = gsap.utils.toArray(".card-service");
    const angles = [0, 90, 180, 270];
    const rotations = [0, 90, 180, -90];

    gsap.fromTo(
      cardsService,
      { x: 0, y: 0, rotation: 0 },
      {
        x: (i) => Math.cos((angles[i] * Math.PI) / 180) * radiusService,
        y: (i) => Math.sin((angles[i] * Math.PI) / 180) * radiusService,
        rotation: (i) => rotations[i],
        ease: "expo.out",
        duration: 1.4,
        scrollTrigger: {
          trigger: ".service",
          start: "top -20%",
          end: "top 90%",
          toggleActions: "restart none none reverse",
        },
      }
    );

  });
</script>
Review Section GSAP Animation
Draggable Review Stack Card Interaction
<script>
  addEventListener("DOMContentLoaded", () => {

   /* ================= DRAGGABLE CARD ================= */

    gsap.set(".card-review", {
      transformOrigin: "50% 50%",
      force3D: true,
    });

    const cardsReview = gsap.utils.toArray(".card-review");
    const isMobile = w <= 480;

    let positions;

    if (w <= 480) {
      positions = [
        { x: -50, y: 0, rotation: -6, zIndex: 3 },
        { x: 40, y: -10, rotation: 0, zIndex: 2 },
        { x: -30, y: -20, rotation: 6, zIndex: 1 },
      ];
    } else if (w <= 768) {
      positions = [
        { x: 30, y: 12, rotation: -10, zIndex: 2 },
        { x: 0, y: 27, rotation: 0, zIndex: 1 },
        { x: -30, y: 18, rotation: 8, zIndex: 2 },
      ];
    } else {
      positions = [
        { x: 60, y: 24, rotation: -14, zIndex: 2 },
        { x: 0, y: 54, rotation: 4, zIndex: 1 },
        { x: -60, y: 36, rotation: 8, zIndex: 2 },
      ];
    }

    cardsReview.forEach((card, i) => {
      const p = positions[i];

      gsap.set(card, p);

      card.dataset.x = p.x;
      card.dataset.y = p.y;
      card.dataset.rotation = p.rotation;
      card.dataset.z = p.zIndex;
    });

    cardsReview.forEach((card, index) => {
      Draggable.create(card, {
        inertia: !isMobile,
        throwResistance: 1200,

        onPress() {
          gsap.killTweensOf(card);

          gsap.to(card, {
            rotation: 0,
            zIndex: 10,
            duration: 0.2,
            ease: "power3.out",
          });

          cardsReview.forEach((other, i) => {
            if (other === card) return;
            const direction = i < index ? -1 : 1;

            if (isMobile) {
              gsap.to(other, {
                x: Number(other.dataset.x),
                y: Number(other.dataset.y) + direction * 20,
                rotation: Number(other.dataset.rotation),
                zIndex: 1,
                duration: 0.25,
                ease: "power3.out",
              });
            } else {
              gsap.to(other, {
                x: Number(other.dataset.x) + direction * 80,
                y: Number(other.dataset.y) + 30,
                rotation: Number(other.dataset.rotation) + direction * 4,
                zIndex: 1,
                duration: 0.3,
                ease: "power3.out",
              });
            }
          });
        },

        onRelease() {
          gsap.to(card, {
            rotation: 0,
            zIndex: 5,
            duration: 0.25,
            ease: "power3.out",
          });
        },
      });
    });

  });
</script>