Instruction
Guide for Fluke Webflow Template
Guide for Fluke Webflow Template
<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>
//About Section
// Image Card Loop
const items = document.querySelectorAll(".project-card");
const offset = 30;
gsap.set(items, {
zIndex: (index) => items.length - index,
opacity: 0,
scale: 0.8
});
// ------------------ Diagonal Loop (Desktop, unchanged) ------------------ //
function diagonalLoop(items) {
let totalItems = items.length;
let currentItem = 0;
function updatePositions() {
for (let i = 0; i < totalItems; i++) {
let itemIndex = (currentItem + i) % totalItems;
let item = items[itemIndex];
gsap.to(item, {
x: offset * i,
y: -offset * i * 1.5, // ⬆️ diagonal upward
zIndex: totalItems - i,
scale: 1,
opacity: 1,
duration: 0.6
});
}
}
function moveToNext() {
currentItem = (currentItem + 1) % totalItems;
updatePositions();
}
updatePositions();
setInterval(moveToNext, 2000);
}
// ------------------ Straight Loop (Mobile, fixed to stack upward) ------------------ //
function straightLoop(items) {
let totalItems = items.length;
let currentItem = 0;
function updatePositions() {
for (let i = 0; i < totalItems; i++) {
let itemIndex = (currentItem + i) % totalItems;
let item = items[itemIndex];
gsap.to(item, {
x: 0,
y: -offset * i * 1.5, // ⬆️ straight upward (TOP visible first)
zIndex: totalItems - i,
scale: 1,
opacity: 1,
duration: 0.6
});
}
}
function moveToNext() {
currentItem = (currentItem + 1) % totalItems;
updatePositions();
}
updatePositions();
setInterval(moveToNext, 2000);
}
// ------------------ Responsive Setup ------------------ //
document.addEventListener("DOMContentLoaded", function () {
gsap.registerPlugin(ScrollTrigger);
ScrollTrigger.create({
trigger: ".about-scroll-trigger",
start: "top 80%",
once: true,
onEnter: () => {
if (window.innerWidth <= 428) {
straightLoop(items); // 📱 Mobile → stacked upward (top peeks out)
} else {
diagonalLoop(items); // 💻 Desktop → original diagonal upward
}
}
});
});
// END Image Card Loop
</script>
<script>
//WHY US SECTION
// Counter
gsap.registerPlugin(ScrollTrigger);
document.querySelectorAll(".why-us-card").forEach(card => {
let counter = card.querySelector(".number");
if (counter) {
let finalValue = parseInt(counter.textContent, 10);
// Set initial value to 0
counter.textContent = "0";
ScrollTrigger.create({
trigger: card,
start: "top 80%", // when each card reaches 80% down the viewport
once: true,
onEnter: () => {
gsap.fromTo(counter,
{ innerText: 0 },
{
innerText: finalValue,
duration: 2,
ease: "power1.out",
snap: { innerText: 1 }
}
);
}
});
}
});
// END Counter
</script>