Code:
Javascript/GSAP
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.3/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.3/Flip.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/CustomEase.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", () => {
gsap.registerPlugin(CustomEase);
CustomEase.create(
"hop",
"M0,0 C0.29,0 0.348,0.05 0.422,0.134 0.494,0.217 0.484,0.355 0.5,0.5 0.518,0.662 0.515,0.793 0.596,0.876 0.701,0.983 0.72,0.987 1,1 "
);
function splitTextIntoSpans(selector) {
let elements = document.querySelectorAll(selector);
elements.forEach((element) => {
let text = element.innerText;
let splitText = text
.split("")
.map(function (char) {
return `<span>${char === " " ? " " : char}</span>`;
})
.join("");
element.innerHTML = splitText;
});
}
splitTextIntoSpans(".header h1");
function animateCounter() {
const counterElement = document.querySelector(".counter p");
let currentValue = 0;
const updateInterval = 300;
const maxDuration = 2000;
const endValue = 100;
const startTime = Date.now();
const updateCounter = () => {
const elapsedTime = Date.now() - startTime;
if (elapsedTime < maxDuration) {
currentValue = Math.min(
currentValue + Math.floor(Math.random() * 30) + 5,
endValue
);
counterElement.textContent = currentValue;
setTimeout(updateCounter, updateInterval);
} else {
counterElement.textContent = endValue;
setTimeout(() => {
gsap.to(counterElement, {
y: -20,
duration: 1,
ease: "power3.inOut",
onStart: () => {
revealLandingPage();
},
});
}, -500);
}
};
updateCounter();
}
gsap.to(".counter p", {
y: 0,
duration: 1,
ease: "power3.out",
delay: 1,
onComplete: () => {
animateCounter();
},
});
const revealLandingPage = () => {
gsap.to(".hero", {
clipPath: "polygon(0% 100%, 100% 100%, 100% 0%, 0% 0%)",
duration: 2,
ease: "hop",
onStart: () => {
gsap.to(".hero", {
transform: "translate(-50%, -50%) scale(1)",
duration: 2.25,
ease: "power3.inOut",
delay: 0.25,
});
gsap.to(".overlay", {
clipPath: "polygon(0% 0%, 100% 0%, 100% 0%, 0% 0%)",
duration: 2,
delay: 0.5,
ease: "hop",
});
gsap.to(".hero-img img", {
transform: "scale(1)",
duration: 2.25,
ease: "power3.inOut",
delay: 0.25,
});
gsap.to(".header h1 span", {
y: 0,
stagger: 0.1,
duration: 2,
ease: "power4.inOut",
delay: 0.75,
});
},
});
};
});
</script>
CSS
<style>
.counter {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 40px;
height: 20px;
text-align: center;
clip-path: polygon(0 0, 100% 0, 100% 100%, 0% 100%);
z-index: 0;
}
.counter p {
position: relative;
display: block;
transform: translateY(20px);
}
.hero {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0.7);
width: 100vw;
height: 100vh;
clip-path: polygon(0% 100%, 100% 100%, 100% 100%, 0% 100%);
will-change: transform;
z-index: 1;
}
.overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #F6520C;
clip-path: polygon(0 100%, 100% 100%, 100% 0, 0 0);
z-index: 2;
}
.header {
position: absolute;
width: 100%;
height: 20vh;
left: 0;
clip-path: polygon(0 100%, 100% 100%, 100% 0, 0 0);
z-index: 1;
}
.header h1 {
font-weight: lighter;
text-align: center;
margin: 0;
padding: 0;
line-height: 100%;
}
.header h1 span {
position: relative;
display: inline-block;
transform: translateY(500px);
}
.hero-img {
position: absolute;
bottom: 0;
width: 100%;
height: 80vh;
overflow: hidden;
z-index: 0;
}
.hero-img img {
transform: scale(2);
}
</style>