Code:
JavaScript
<!-- GSAP Core -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<!-- GSAP ScrollTrigger Plugin -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/ScrollTrigger.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function () {
let sections = gsap.utils.toArray(".project-section");
const gap = 200;
const sectionHeight = window.innerHeight * 0.5;
sections.forEach((section, index) => {
let mask = section.querySelector(".image-mask");
let isLast = index === sections.length - 1;
// Define the start trigger.
let startVal = index === 0 ? "top top" : `top top+=${index * gap}`;
let pinDuration;
if (index === 0) {
// Extend the pin duration for the first section with an extra multiplier.
pinDuration = "+=" + (sectionHeight + (sections.length * gap * 1.2));
} else if (isLast) {
pinDuration = "+=20%";
} else {
pinDuration = "+=" + (sectionHeight + ((sections.length - index - 1) * gap));
}
// Create the timeline for pinning the section.
gsap.timeline({
scrollTrigger: {
trigger: section,
start: startVal,
end: pinDuration,
pin: true,
pinSpacing: false,
scrub: 1,
anticipatePin: 1,
// markers: true, // Uncomment for debugging.
}
});
// Animate the image mask over the scroll duration.
gsap.to(mask, {
height: "20%",
duration: 1,
ease: "power2.out",
scrollTrigger: {
trigger: section,
start: startVal,
end: pinDuration,
scrub: 1,
// markers: true, // Uncomment for debugging.
}
});
});
});
</script>
CSS
.image-mask {
width: 100%;
height: 100%; /* the starting height; this will be animated */
overflow: hidden;
transform-origin: center top;
transition: transform 0.9s ease-out;
}
.project-section{
height: 70vh;
}