Find easy to follow instructions
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.
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>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"
});
});
});
}
});