Instructions

Find easy to follow instructions

GSAP Guide

All GSAP animations used in this template are collected here. On this page, you’ll find guidance on how to locate and edit them. Each code block comes with extra notes to make it easier to understand.

Custom Code

Lenis Scroll

Smooth scrolling effect for the template using Lenis with GSAP integration for precise scroll updates and animations.

<link rel="stylesheet" href="https://unpkg.com/lenis@1.3.15/dist/lenis.css" />
<script src="https://unpkg.com/lenis@1.3.15/dist/lenis.min.js"></script>

<script>
  const lenis = new Lenis({ duration: 1.4 });

  lenis.on('scroll', ScrollTrigger.update);
  gsap.ticker.add((time) => {
    lenis.raf(time * 1000);
  });
  gsap.ticker.lagSmoothing(0);
</script>

Custom Code

Mouse Trail

Smooth scrolling effect for the template using Lenis with GSAP integration for precise scroll updates and animations.

/* ============================
   MOUSE TRAIL - GSAP (Optimized)
   ============================ */
   document.addEventListener("DOMContentLoaded", () => {
  if (window.matchMedia("(min-width: 768px)").matches) {
    const images = document.querySelectorAll(".trail-img");
    const buttons = document.querySelectorAll(".content-button"); 
    let mouse = { x: window.innerWidth / 2, y: window.innerHeight / 2 };
    let pos = { x: mouse.x, y: mouse.y };
    let isVisible = false;
    let hideTimeout;
    let isOverButton = false;

    // Start positions image
    gsap.set(images, { 
      x: mouse.x, 
      y: mouse.y, 
      opacity: 0, 
      scale: 0.7, 
      pointerEvents: "none", // important!
      rotate: () => gsap.utils.random(-10, 10)
    });

    // When mouse move
    window.addEventListener("mousemove", (e) => {
      if (isOverButton) return; // Stop animation when mouse on area 

      mouse.x = e.clientX;
      mouse.y = e.clientY;

      if (!isVisible) {
        gsap.to(images, { 
          opacity: 1, 
          scale: 1, 
          duration: 0.4, 
          stagger: 0.1, 
          ease: "power2.out" 
        });
        isVisible = true;
      }

      clearTimeout(hideTimeout);
      hideTimeout = setTimeout(() => {
        if (!isOverButton) {
          gsap.to(images, { opacity: 0, scale: 0.6, duration: 0.8 });
          isVisible = false;
        }
      }, 600);
    });

    // Loop animations
    function animateTrail() {
      pos.x += (mouse.x - pos.x) * 0.12;
      pos.y += (mouse.y - pos.y) * 0.12;

      if (isVisible && !isOverButton) {
        gsap.to(images, {
          x: pos.x,
          y: pos.y,
          duration: 0.5,
          ease: "power3.out",
          stagger: { each: 0.12, from: "end" }
        });
      }

      requestAnimationFrame(animateTrail);
    }
    animateTrail();

    // ===== BUTTON AREA =====
    buttons.forEach((btn) => {
      btn.addEventListener("mouseenter", () => {
        isOverButton = true;
        gsap.to(images, { 
          opacity: 0, 
          scale: 0, 
          duration: 0.3, 
          ease: "power1.inOut" 
        });
      });

      btn.addEventListener("mouseleave", () => {
        isOverButton = false;
        gsap.to(images, { 
          opacity: 1, 
          scale: 1, 
          duration: 0.4, 
          ease: "power1.out" 
        });
      });
    });
  }
});