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>
// Service slider
gsap.registerPlugin(Draggable);
const gallery = document.querySelector(".about-service-gallery-slide");
Draggable.create(gallery, {
type: "x",
bounds: ".about-service-gallery", // container element
inertia: true
});
// END Service slider
</script><script>
document.addEventListener("DOMContentLoaded", () => {
gsap.registerPlugin(Draggable);
const slide = document.querySelector(".work-slide");
const cards = document.querySelectorAll(".work-card");
const images = document.querySelectorAll(".work-card-img");
const wrapper = document.querySelector(".work-slide-wrapper");
/* -------------------------------------------
SIZE SETTINGS β RESPONSIVE
------------------------------------------- */
let minW, maxW, minH, maxH;
function setResponsiveSizes() {
const w = window.innerWidth;
if (w <= 480) {
// π± MOBILE
minW = 40;
maxW = 70;
minH = 60;
maxH = 100;
} else if (w <= 991) {
// π² TABLET
minW = 22;
maxW = 32;
minH = 28;
maxH = 40;
} else {
// π» DESKTOP
minW = 14;
maxW = 20;
minH = 20;
maxH = 28;
}
}
setResponsiveSizes();
/* INITIAL STATE */
gsap.set(slide, {
display: "flex",
alignItems: "flex-end",
gap: "2vw"
});
gsap.set(cards, {
overflow: "hidden",
position: "relative"
});
gsap.set(images, {
width: "100%",
height: "100%",
objectFit: "cover"
});
/* DRAGGABLE */
const drag = Draggable.create(slide, {
type: "x",
bounds: getBounds(),
inertia: false,
onDrag: () => {
updateBounds();
updateSize();
}
})[0];
/* DYNAMIC BOUNDS */
function getBounds() {
return {
minX: -(slide.scrollWidth - window.innerWidth),
maxX: 0
};
}
function updateBounds() {
drag.applyBounds(getBounds());
}
/* SIZE LOGIC */
function updateSize() {
const viewportCenter = window.innerWidth / 2;
cards.forEach(card => {
const rect = card.getBoundingClientRect();
const cardCenter = rect.left + rect.width / 2;
const dist = Math.abs(viewportCenter - cardCenter);
const w = gsap.utils.mapRange(0, 400, maxW, minW, dist);
const h = gsap.utils.mapRange(0, 400, maxH, minH, dist);
gsap.to(card, {
width: w + "vw",
height: h + "vw",
duration: 0.25,
ease: "power3.out",
overwrite: true
});
});
}
/* INIT */
updateBounds();
updateSize(); // resize right away when loaded
window.addEventListener("resize", () => {
setResponsiveSizes(); // <-- update size variant
updateBounds();
updateSize();
});
/* -------------------------------------------
SCROLL NUDGE
------------------------------------------- */
window.addEventListener("wheel", (e) => {
const moveX = e.deltaY * 0.000001;
const currentX = gsap.getProperty(slide, "x");
const bounds = getBounds();
let newX = currentX - moveX;
newX = Math.min(bounds.maxX, Math.max(bounds.minX, newX));
gsap.to(slide, {
x: newX,
duration: 0.35,
ease: "power3.out"
});
updateSize();
});
});
</script><script>
document.addEventListener("DOMContentLoaded", () => {
const openBtn = document.querySelector(".navbar-menu-button-open");
const closeBtn = document.querySelector(".navbar-menu-button-close");
const target = document.querySelector(".section-header.var-1");
// OPEN β NORMAL (instant)
openBtn.addEventListener("click", () => {
gsap.to(target, {
duration: 0.2,
onStart: () => {
target.style.mixBlendMode = "normal";
}
});
});
// CLOSE β EXCLUSION (with 0.5s delay)
closeBtn.addEventListener("click", () => {
gsap.to(target, {
duration: 0.2,
delay: 0.5,
onStart: () => {
target.style.mixBlendMode = "exclusion";
}
});
});
});
</script>