gsapmotionweb-animation

Loading Animation

Creating a Cinematic GSAP Page Loader with Expanding Image Reveal

Playground

Breakdown

First impressions matter on the web. Before a visitor scrolls, clicks, or explores, the loading experience sets the tone for the entire site.

Instead of a simple spinner, we can create a cinematic loading animation where typography, images, and layout elements animate together. This tutorial demonstrates a GSAP-powered loader that reveals a hero section through expanding imagery and staggered typography.

The result feels more like a motion sequence than a loading screen.

What This Animation Does

When the page loads:

  1. The letters of the word “Willem” slide upward into view.
  2. A small vertical box expands in the center.
  3. Inside that box, an image begins growing horizontally.
  4. Multiple cover images fade away to reveal the main image.
  5. The image expands to fill the entire viewport.
  6. Navigation links and header text animate upward.

Instead of abruptly loading content, the page reveals itself through motion.


HTML Structure

The loader consists of three primary parts:

• Loader container
• Expanding image box
• Main header content

1<section class="willem-header is--loading is--hidden">
2
3  <!-- Loader -->
4  <div class="willem-loader">
5    <div class="willem__h1">
6
7      <div class="willem__h1-start">
8        <span class="willem__letter">W</span>
9        <span class="willem__letter">i</span>
10        <span class="willem__letter">l</span>
11      </div>
12
13      <div class="willem-loader__box">
14        <div class="willem-loader__box-inner">
15
16          <div class="willem__growing-image">
17            <div class="willem__growing-image-wrap">
18
19              <img class="willem__cover-image-extra is--1" src="image1.avif">
20              <img class="willem__cover-image-extra is--2" src="image2.avif">
21              <img class="willem__cover-image-extra is--3" src="image3.avif">
22
23              <img class="willem__cover-image" src="image-main.avif">
24
25            </div>
26          </div>
27
28        </div>
29      </div>
30
31      <div class="willem__h1-end">
32        <span class="willem__letter">l</span>
33        <span class="willem__letter">e</span>
34        <span class="willem__letter">m</span>
35      </div>
36
37    </div>
38  </div>
39
40</section>

The text Willem is split into two groups:

Start → Wil

End → lem

The image box sits between them and grows during the animation.


Styling the Loader Layout

The header container hides everything initially and prevents scrolling.

1.willem-header {
2  color: #f4f4f4;
3  position: relative;
4  overflow: hidden;
5}

During loading, scrolling is disabled.

1main:has(.willem-header.is--loading) {
2  height: 100dvh;
3}

The loader is centered using Flexbox.

1.willem-loader {
2  justify-content: center;
3  align-items: center;
4  display: flex;
5  position: absolute;
6  width: 100%;
7  height: 100%;
8}


Typography Animation

Each letter is placed inside its own <span>.

1.willem__letter {
2  display: block;
3  position: relative;
4}

This allows GSAP to animate the letters individually.

Image Reveal Container

The image starts with zero width.

1.willem__growing-image {
2  width: 0%;
3  height: 100%;
4  position: absolute;
5  overflow: hidden;
6}

This allows the image to grow outward like a curtain opening.


GSAP Timeline Animation

The animation is controlled through a GSAP timeline.

1const tl = gsap.timeline({
2  defaults: {
3    ease: "expo.inOut"
4  },
5  onStart: () => {
6    container.classList.remove("is--hidden");
7  }
8});

This timeline coordinates multiple animations into a single smooth sequence.


Step 1: Animate Loader Letters

The letters slide upward into view.

1tl.from(loadingLetter, {
2  yPercent: 100,
3  stagger: 0.025,
4  duration: 1.25
5});

Step 2: Expand the Loader Box

Next, the center box grows horizontally.

1tl.fromTo(
2  box,
3  { width: "0em" },
4  { width: "1em", duration: 1.25 },
5  "< 1.25"
6);

The < tells GSAP to start this animation at the same time as the previous one.

Step 3: Reveal the Image

The image inside the box expands across the container.

1tl.fromTo(
2  growingImage,
3  { width: "0%" },
4  { width: "100%", duration: 1.25 },
5  "<"
6);

Now the loader starts transitioning from typography to imagery.

Step 4: Fade Image Layers

Extra images are stacked above the main image.

1tl.fromTo(
2  coverImageExtra,
3  { opacity: 1 },
4  {
5    opacity: 0,
6    duration: 0.05,
7    stagger: 0.5
8  }
9);

This creates a layered reveal effect.

Step 5: Expand to Full Screen

Once the image is revealed, it expands to fill the viewport.

1tl.to(
2  growingImage,
3  {
4    width: "100vw",
5    height: "100dvh",
6    duration: 2
7  }
8);

Now the loader smoothly transitions into the hero section.

Step 6: Animate Navigation and Header

Finally, the main header and navigation appear.

1tl.from(headerLetter, {
2  yPercent: 100,
3  duration: 1.25,
4  stagger: 0.025
5});

Navigation links animate similarly.

1tl.from(navLinks, {
2  yPercent: 100,
3  duration: 1.25,
4  stagger: 0.1
5});

This completes the transition from loader to fully interactive page.

Why This Loader Feels Premium

Most loaders simply delay the user. This one introduces the design language of the site.

It works well because it:

• Combines typography and imagery
• Uses staggered motion for rhythm
• Transitions naturally into the hero section
• Feels like a designed experience rather than a loading delay

This type of animation is common in award-winning websites, creative studios, and high-end portfolios.

Final Thoughts

Motion design on the web is about storytelling. Even a loading screen can be an opportunity to communicate style, mood, and personality.

With GSAP timelines, staggered animations, and expanding layouts, you can create a loader that feels cinematic instead of functional.

Sometimes the best way to start a website…
is with a little bit of theatre.