Instructions
A comprehensive guide to customizing and managing the advanced GSAP animations and interactive components within the template.
Developer & Customization Guide: GSAP Animations
This template leverages GSAP (GreenSock Animation Platform) to create premium, interactive user experiences. If your template consumers rename classes inside Webflow, they must match those updates inside the respective page code fields.
1. Home Page: Section Recap Scroll Animation
This section utilizes GSAP's
ScrollTrigger to create a sticky parallax reveal effect. As users scroll down, the items smoothly slide up while their inner content counters the movement, creating a dynamic masking effect.How to Use & Customize
- Classes to Maintain: The script targets specific classes to function correctly. Ensure
.recap_sticky,.recap_item,.recap_trigger, and.recap_innerremain unchanged in your Webflow structure. If you rename them in Webflow, you must update the corresponding variables in the code. - Animation Behavior: The animation is tied directly to the user's scroll position (
scrub: 1). The distance the elements move is calculated based on the viewport height (vh). - Adding/Removing Items: The logic automatically calculates the sequence based on the number of items. Just make sure that for every
.recap_itemyou add, there is a corresponding.recap_triggerelement to activate it.
Code Configuration
< script >
window.Webflow ||= [];
window.Webflow.push(() => {
gsap.registerPlugin(ScrollTrigger);
const ctx = gsap.context(() => {
const items = gsap.utils.toArray(".recap_sticky .recap_item");
const triggers = gsap.utils.toArray(".recap_trigger");
if (items.length < 2) return;
const vh = window.innerHeight;
triggers.forEach((trigger, i) => {
const item = items[items.length - 1 - i];
const inner = item?.querySelector(".recap_inner");
if (!item || !inner) return;
gsap.timeline({
scrollTrigger: {
trigger,
start: "top top",
end: "bottom top",
scrub: true
}
})
.to(item, {
y: -vh,
ease: "none"
}, 0)
.to(inner, {
y: vh,
ease: "none"
}, 0);
});
});
return () => ctx.revert();
}); <
/script>2. Home Page: Hero Section, Popup Reveal & Swiper Activation
A GSAP timeline sequence that dynamically reveals a popup modal on page load. Once the user dismisses the popup, it seamlessly triggers the appearance of the main hero swiper.
How to Use & Customize
- Classes to Maintain: The script explicitly targets
.section_popup,.popup_content,.primary-btn(used as the close button), and.hero_swiper. If you rename any of these in Webflow, update the corresponding variables at the top of the code. - Initial Delay: The popup opens automatically after a
1.3sdelay to accommodate page loading. You can adjust this timing by changingdelay: 1.3inside the script. - Sequential Reveal Logic: When the close button is clicked, an
onCompletecallback runs at the end of the timeline. This function completely hides the popup and automatically fades the.hero_swiperinto full visibility.
Code Configuration
<script>
window.Webflow ||= [];
window.Webflow.push(() => {
// ── Popup Animation
const popup = document.querySelector(".section_popup");
const content = document.querySelector(".popup_content");
const closeBtn = document.querySelector(".primary-btn");
const heroSwiper = document.querySelector(".hero_swiper");
if (popup && content && closeBtn) {
// Initial state
gsap.set(popup, { display: "none", opacity: 0 });
gsap.set(content, { scale: 0.85, opacity: 0, y: 30 });
gsap.set(heroSwiper, { opacity: 0, visibility: "hidden" });
// 1.3s delay and popup open
gsap.timeline({ delay: 1.3 })
.to(popup, {
display: "flex",
opacity: 1,
duration: 0.35,
ease: "power2.out",
})
.to(content, {
scale: 1,
opacity: 1,
y: 0,
duration: 0.3,
ease: "back.out(1.4)",
}, "-=0.1");
// Close button click
closeBtn.addEventListener("click", function() {
gsap.timeline()
.to(content, {
scale: 0.85,
opacity: 0,
y: 30,
duration: 0.35,
ease: "power2.in",
})
.to(popup, {
opacity: 0,
duration: 0.3,
ease: "power2.in",
onComplete: () => {
gsap.set(popup, { display: "none" });
// Activates hero_swiper after popup closes
gsap.to(heroSwiper, {
opacity: 1,
visibility: "visible",
duration: 0.4,
ease: "power2.out",
});
},
}, "-=0.1");
});
}
});
</script>3. Home Page: Interactive Buttons, SVG Running Dashed Border
An advanced interactive hover effect applied to the primary button. The script dynamically injects an SVG shape to create a continuous, animated dashed border whenever the user hovers over the element.
How to Use & Customize
- Target Element: The animation currently targets the
.primary-btnclass. If your button class changes, update thecloseBtnvariable selector in the code. - Dynamic Injection: You do not need to build the SVG lines manually inside Webflow. The script dynamically creates the
<svg>and<rect>tags and appends them to the button on the live site. - Color Customization: On hover, the button's background changes to
#000000, and resets to#1b1b1bwhen the mouse leaves. Update these HEX codes in thebackgroundColortweens to match your global brand colors. - Dash Appearance: The dashed visual is generated by
stroke-dasharray: 6 4. You can tweak these specific numbers in therect.style.cssTextblock to adjust the dash length and spacing.
Code Configuration
<script>
window.Webflow ||= [];
window.Webflow.push(() => {
//── Running Dashed Border on primary-btn ──
const closeBtn = document.querySelector(".primary-btn");
if (closeBtn) {
// SVG inject
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
svg.style.cssText = `
position: absolute;
inset: 0;
width: 100%;
height: 100%;
pointer-events: none;
opacity: 0;
overflow: visible;
`;
rect.setAttribute("x", "1");
rect.setAttribute("y", "1");
rect.setAttribute("width", "calc(100% - 2px)");
rect.setAttribute("height", "calc(100% - 2px)");
rect.setAttribute("rx", "10");
rect.setAttribute("ry", "10");
rect.style.cssText = `
fill: none;
stroke: rgba(255, 255, 255, 0.20);
stroke-width: 1;
stroke-dasharray: 6 4;
stroke-dashoffset: 0;
`;
svg.appendChild(rect);
gsap.set(closeBtn, {position: "relative", overflow: "hidden"});
closeBtn.appendChild(svg);
let runAnim = null;
closeBtn.addEventListener("mouseenter", () => {
gsap.killTweensOf(closeBtn);
gsap.to(closeBtn, {
backgroundColor: "#000000",
duration: 0.45,
ease: "power2.out"
});
// SVG fade in
gsap.to(svg, {
opacity: 1,
duration: 0.5,
ease: "power2.out"
});
// Running dash
runAnim = gsap.to(rect, {
strokeDashoffset: -20,
duration: 1.5,
ease: "none",
repeat: -1,
});
});
closeBtn.addEventListener("mouseleave", () => {
gsap.killTweensOf(closeBtn);
gsap.killTweensOf(rect);
if (runAnim) runAnim.kill();
gsap.set(rect, { strokeDashoffset: 0 });
gsap.to(closeBtn, {
backgroundColor: "#1b1b1b",
duration: 0.45,
ease: "power2.out"
});
gsap.to(svg, {
opacity: 0,
duration: 0.5,
ease: "power2.out"
});
});
}
});
</script>4. Home Page: Hero Section, Background Video Switcher
A dynamic background cross-fade system that smoothly transitions between multiple background videos whenever a designated
trigger button is clicked.
trigger button is clicked.
How to Use & Customize
- Classes to Maintain: Ensure all your background video elements share the class
.hero_bg-video. The element meant to trigger the slide change must have the class.hero_swipe. - Automatic Looping: The script automatically counts all elements with the
.hero_bg-videoclass and cycles through them infinitely based on the total number. - Transition Effect: The transition uses a
0.6sGSAP fade. As the user clicks, the current video smoothly fades out (opacity: 0) while the next video simultaneously fades in (opacity: 1). Adjust the duration values if you prefer a slower or faster cross-fade.
Code Configuration
<script>
window.Webflow ||= [];
window.Webflow.push(() => {
// Video switcher
const videos = document.querySelectorAll(".hero_bg-video");
const btn = document.querySelector(".hero_swipe");
if (btn && videos.length > 0) {
let current = 0;
gsap.set(videos, {
opacity: 0,
display: "block"
});
gsap.set(videos[0], { opacity: 1 });
btn.addEventListener("click", function() {
const prev = current;
current = (current + 1) % videos.length;
gsap.to(videos[prev], {
opacity: 0,
duration: 0.6,
ease: "power2.inOut"
});
gsap.to(videos[current], {
opacity: 1,
duration: 0.6,
ease: "power2.inOut"
});
});
}
});
</script>5. Footer Section of all pages: Real-Time Digital Watch
A real-time digital clock located in the footer. It uses the
gsap.ticker for smooth rendering and is synchronized to a specific timezone.How to Use & Customize
- Target Element ID: The clock script specifically looks for an element with the ID
realtime-clock. Make sure your text block in Webflow has this exact ID applied in the element settings. - Target Element ID: The clock script specifically looks for an element with the ID
realtime-clock. Make sure your text block in Webflow has this exact ID applied in the element settings. - Timezone Customization: By default, the clock is set to Singapore time (
'Asia/Singapore'). To change this to your local timezone (e.g., New York or London), replace'Asia/Singapore'in thetoLocaleStringfunction with your preferred IANA time zone string (e.g.,'America/New_York'). - Time Format: The current output format is
HH : MM : SS : 00. If you wish to remove the trailing : 00 or change the separators, you can modify the template literal in theclockEl.textContentline.
Code Configuration
(Note: I wrapped your snippet in a DOMContentLoaded event listener to ensure it loads properly without errors.)
< script >
window.Webflow ||= [];
window.Webflow.push(() => {
const clock = document.querySelector("#realtime-clock");
if (clock) {
const pad = n => String(n).padStart(2, "0");
gsap.ticker.add(() => {
const now = new Date();
const sg = new Date(
now.toLocaleString("en-US", {
timeZone: "Asia/Singapore"
})
);
clock.textContent =
`${pad(sg.getHours())} : ${pad(sg.getMinutes())} : ${pad(sg.getSeconds())} : 00`;
});
}
});
return () => ctx.revert();
}); <
/script>.webp)