instructions
How It Works
Learn how to customize this template and create a website that fits your brand.
window._cursorPause() and window._cursorResume() so other scripts can hide it on demand.<script>
window.Webflow = window.Webflow || [];
window.Webflow.push(function () {
// ==================================================
// MAIN CURSOR
// ==================================================
if (window._cursorCoreInit) return;
window._cursorCoreInit = true;
var cursor = document.querySelector(".cursor-core");
var pointer = document.querySelector(".cursor-pointer");
if (!cursor) return;
var mouseX = -100;
var mouseY = -100;
var x = -100;
var y = -100;
var paused = false;
// initial
gsap.set(cursor, {
xPercent: -50,
yPercent: -50,
x: x,
y: y
});
// smooth follow
gsap.ticker.add(function () {
x += (mouseX - x) * 0.15;
y += (mouseY - y) * 0.15;
gsap.set(cursor, {
x: x,
y: y
});
});
// track mouse
window.addEventListener("mousemove", function (e) {
mouseX = e.clientX;
mouseY = e.clientY;
});
// =========================================
// HIDE POINTER ONLY
// =========================================
window._cursorPause = function () {
paused = true;
if (!pointer) return;
gsap.to(pointer, {
opacity: 0,
duration: 0.2,
overwrite: true
});
};
// =========================================
// SHOW POINTER AGAIN
// =========================================
window._cursorResume = function () {
paused = false;
if (!pointer) return;
gsap.to(pointer, {
opacity: 1,
duration: 0.2,
overwrite: true
});
};
});
</script>0 to their final value when they enter the viewport. The animation automatically detects the first child element inside .counter-number, making it compatible with any typography class (such as .text-l, .text-xl, or .text-xxl). Numeric suffixes like %, +, or yrs are preserved throughout the animation..counter-number — the wrapper element that triggers the counter animation<script>
window.Webflow = window.Webflow || [];
window.Webflow.push(function () {
gsap.registerPlugin(ScrollTrigger);
document.querySelectorAll(".counter-number").forEach((counter) => {
// Get the first child element (.text-xl, .text-l, .text-xxl, etc.)
const number = counter.firstElementChild;
if (!number) return;
const text = number.textContent.trim();
const finalValue = parseInt(text.replace(/[^\d]/g, ""), 10);
if (isNaN(finalValue)) return;
// Preserve any non-numeric suffix (%, +, yrs, etc.)
const suffix = text.replace(/[\d\s]/g, "");
// Create an object to animate
const obj = { value: 0 };
gsap.to(obj, {
value: finalValue,
duration: 2,
ease: "expo.out",
snap: { value: 1 },
scrollTrigger: {
trigger: counter,
start: "top 85%",
once: true
},
onUpdate() {
number.textContent = Math.round(obj.value) + suffix;
}
});
});
});
</script>