Here is some text...
... and scroll trigger follows content ...
... till ...
... and scroll trigger follows content ...
... till ...
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/Draggable.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/DrawSVGPlugin.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/EaselPlugin.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/Flip.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/GSDevTools.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/InertiaPlugin.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/MotionPathHelper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/MotionPathPlugin.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/MorphSVGPlugin.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/Observer.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/Physics2DPlugin.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/PhysicsPropsPlugin.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/PixiPlugin.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/ScrambleTextPlugin.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/ScrollTrigger.min.js"></script>
<!-- ScrollSmoother requires ScrollTrigger -->
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/ScrollSmoother.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/ScrollToPlugin.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/SplitText.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/TextPlugin.min.js"></script>
<!-- RoughEase, ExpoScaleEase and SlowMo are all included in the EasePack file -->
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/EasePack.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/CustomEase.min.js"></script>
<!-- CustomBounce requires CustomEase -->
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/CustomBounce.min.js"></script>
<!-- CustomWiggle requires CustomEase -->
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/CustomWiggle.min.js"></script>
<script>
// use a script tag or an external JS file
document.addEventListener("DOMContentLoaded", (event) => {
gsap.registerPlugin(Draggable,DrawSVGPlugin,EaselPlugin,Flip,GSDevTools,InertiaPlugin,MotionPathHelper,MotionPathPlugin,MorphSVGPlugin,Observer,Physics2DPlugin,PhysicsPropsPlugin,PixiPlugin,ScrambleTextPlugin,ScrollTrigger,ScrollSmoother,ScrollToPlugin,SplitText,TextPlugin,RoughEase,ExpoScaleEase,SlowMo,CustomEase,CustomBounce,CustomWiggle)
// gsap code here!
});
</script>
<title>GSAP timeline examples - </title>
</head>
<body>
<div class="main">
<div class="pinned">
<div class="horse">
<img src="https://www.dziedziczak-artur.com//microblog/2024-01-28-02-04/images/index.jpeg" />
<div class="grid">
<div class="tile t1"></div>
<div class="tile t2"></div>
<div class="tile t3"></div>
<div class="tile t4"></div>
<div class="tile t5"></div>
</div>
</div>
<div class="text-part">
<h1 class="heading-1">Here is some text...</h1>
<p class="heading-2">... and scroll trigger follows content ...</p>
<p class="heading-3">... till ...</p>
</div>
</div>
</div>
<div class="end">
<div class="heading-4">
<img src="https://www.dziedziczak-artur.com/microblog/2025-06-08-15/images/index.jpeg" />
<h1>THE END</h1>
</div>
</div>
<script>
const tl1 = gsap.timeline({
scrollTrigger: {
trigger: ".main",
start: "top top",
markers: true,
end: "bottom bottom",
scrub: 1
}
});
tl1.fromTo(".tile", {width: "0vw"}, { width: "50vw", stagger: {
each: 0.1,
from: "random"
}})
const tl2 = gsap.timeline({
scrollTrigger: {
trigger: ".main",
start: "top top",
markers: true,
end: "bottom bottom",
scrub: 1
}
});
tl2.to(".heading-1", {opacity: 1});
tl2.to(".heading-2", {opacity: 1});
tl2.to(".heading-3", {opacity: 1});
const tl3 = gsap.timeline({
scrollTrigger: {
trigger: ".end",
markers: { startColor: 'pink', endColor: 'purple'},
start: "top center",
end: "center center",
scrub: 1
}
});
tl3.to(".heading-4", {opacity: 1});
</script>
<style>
body {
margin: 0;
padding: 0;
}
.main {
height: 600vh;
width: 100%;
position: relative;
}
.pinned {
position: sticky;
top: 0;
width: 100%;
height: 100vh;
display: flex;
}
.horse img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100vh;
object-contain: cover;
}
.text-part {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 50%;
height: 100vh;
}
.heading-1 {
opacity: 0;
}
.heading-2 {
opacity: 0;
}
.heading-3 {
opacity: 0;
}
.heading-4 {
opacity: 0;
}
.heading-4 h1 {
position: relative;
color: white;
}
.end img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100vh;
}
.end {
position: relative;
height: 100vh;
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.horse {
position: relative;
top: 0;
width: 50vw;
overflow: hidden;
display: flex;
flex-direction: row;
}
.grid {
position: relative;
top: 0;
left: 0;
display: flex;
flex-gap: 0px;
flex-direction: column;
flex-wrap: wrap;
width: 100%;
height: 100vh;
}
.tile {
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
position: relative;
width: 0vw;
height: 20vh;
backdrop-filter: invert(100%);
}
</style>
</body>
</html>