Instruction
Webflow Template User Guide
Webflow Template User Guide
<script src="https://unpkg.com/lenis@1.3.1/dist/lenis.min.js"></script>
<script>
// lenis smooth scroll
{
let lenis;
const initScroll = () => {
lenis = new Lenis({});
lenis.on("scroll", ScrollTrigger.update);
gsap.ticker.add((time) => lenis.raf(time * 1000));
gsap.ticker.lagSmoothing(0);
};
function initGsapGlobal() {
// Do everything that needs to happen
// before triggering all
// the gsap animations
initScroll();
// match reduced motion media
// const media = gsap.matchMedia();
// Send a custom
// event to all your
// gsap animations
// to start them
const sendGsapEvent = () => {
window.dispatchEvent(
new CustomEvent("GSAPReady", {
detail: {
lenis,
},
})
);
};
// Check if fonts are already loaded
if (document.fonts.status === "loaded") {
sendGsapEvent();
} else {
document.fonts.ready.then(() => {
sendGsapEvent();
});
}
// We need specific handling because the
// grid/list changes the scroll height of the whole container
//
let resizeTimeout;
const onResize = () => {
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(() => {
ScrollTrigger.refresh();
}, 50);
};
window.addEventListener("resize", () => onResize());
const resizeObserver = new ResizeObserver((entries) => onResize());
resizeObserver.observe(document.body);
queueMicrotask(() => {
gsap.to("[data-start='hidden']", {
autoAlpha: 1,
duration: 0.1,
delay: 0.2,
});
});
}
// this only for dev
const documentReady =
document.readyState === "complete" || document.readyState === "interactive";
if (documentReady) {
initGsapGlobal();
} else {
addEventListener("DOMContentLoaded", (event) => initGsapGlobal());
}
}
</script>
<script>
// Hero Section
// Hero Image Animation
gsap.registerPlugin(ScrollTrigger);
// Create one tween we can control
const tween = gsap.fromTo(".hero-moving-image-wrap",
{ perspective: "0vw" },
{ perspective: "100vw", duration: 3, ease: "power2.inOut", paused: true }
);
// Play forward when hero-moving-image-wrap enters
ScrollTrigger.create({
trigger: ".hero-moving-image-wrap",
start: "top 80%",
onEnter: () => {
tween.timeScale(1).play(); // forward at normal speed
}
});
// Reverse when reverse-trigger enters
ScrollTrigger.create({
trigger: ".reverse-trigger",
start: "top 80%",
onEnter: () => {
tween.timeScale(-1).play(); // reverse smoothly
gsap.to(tween, { timeScale: -1.5, duration: 0.01 }); // optional: make reverse 2s by adjusting speed
},
onLeaveBack: () => {
tween.timeScale(1).play(); // play forward again when scrolling up
}
});
// END Hero Image Animation
</script>
<script>
// About Section
// About Counter
gsap.registerPlugin(ScrollTrigger);
ScrollTrigger.create({
trigger: ".about-counter",
start: "top 100%", // starts when the top of .about-counter is 100% down the viewport
once: true, // run only once
onEnter: () => {
document.querySelectorAll(".number").forEach(counter => {
let finalValue = parseInt(counter.textContent, 10); // read existing number
gsap.fromTo(counter,
{ innerText: 0 },
{
innerText: finalValue,
duration: 2,
ease: "sine.inOut",
snap: { innerText: 1 }
}
);
});
}
});
// END About Counter
</script>