Skip to content
animorio
IT
Back to the library

The cell transition

Transitions, TextGSAP, CSS onlyMediumCompressed weight: Demo 5.7 KBGSAP + CustomEase 31 KBFreeDownload the zip

A minimal-style page change for a mountain hotel’s site: on a click a curtain of 240 sand-coloured cells, twenty columns of twelve, closes over the page in a wave that starts from the bottom right corner while a veil darkens underneath; then it opens again with the same wave and the words of the new headline arrive in jumps, in scattered order, wide and light, and narrow down as they gain weight. Remade from scratch on the idea of the page change of sondaven.com.

The code

A folder that runs on its own: index.html, style.css, script.js and the libraries from a CDN. The React and Vue tabs hold the same demo as a ready component, which switches its animations off when it leaves the page.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>The cell transition</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/archivo@5.3.0/wdth.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage" data-stage>
    <!-- the first page: the rooms of a small mountain hotel, on warm paper -->
    <section class="page page--a is-on" data-page="a" aria-label="Rooms">
      <header class="bar">
        <span class="brand">Hollin</span>
        <nav class="nav" aria-label="Pages">
          <a class="nav__link" href="#rooms" aria-current="page">Rooms</a>
          <a class="nav__link" href="#seasons" data-go="b">Seasons</a>
        </nav>
      </header>
      <span class="rule" aria-hidden="true"></span>
      <h1 class="title" data-title><span class="title__line">Rooms above</span><span class="title__line">the treeline.</span></h1>
      <div class="under">
        <p class="lede" data-late>Twelve rooms of larch and stone, a stove in each, and windows that open on the valley.</p>
        <a class="go" href="#seasons" data-go="b" data-autoclic data-late>
          <span class="go__text">See the seasons</span>
          <svg class="go__arrow" viewBox="0 0 26 12" aria-hidden="true"><path d="M1 6h22"/><path d="M18.5 1.5 23.5 6l-5 4.5"/></svg>
        </a>
      </div>
      <footer class="foot" data-late>
        <span>A hotel in the high woods</span>
        <span>Open all year</span>
      </footer>
    </section>

    <!-- the second page: the seasons, on the dark brown of the woods at night -->
    <section class="page page--b" data-page="b" aria-label="Seasons" aria-hidden="true">
      <header class="bar">
        <span class="brand">Hollin</span>
        <nav class="nav" aria-label="Pages">
          <a class="nav__link" href="#rooms" data-go="a">Rooms</a>
          <a class="nav__link" href="#seasons" aria-current="page">Seasons</a>
        </nav>
      </header>
      <span class="rule" aria-hidden="true"></span>
      <h2 class="title" data-title><span class="title__line">Snow comes</span><span class="title__line">early here.</span></h2>
      <div class="under">
        <p class="lede" data-late>Trails and rivers in summer, quiet slopes from November. The stove is lit either way.</p>
        <a class="go" href="#rooms" data-go="a" data-autoclic data-late>
          <svg class="go__arrow go__arrow--back" viewBox="0 0 26 12" aria-hidden="true"><path d="M25 6H3"/><path d="M7.5 1.5 2.5 6l5 4.5"/></svg>
          <span class="go__text">Back to the rooms</span>
        </a>
      </div>
      <footer class="foot" data-late>
        <span>Summer and winter</span>
        <span>Open all year</span>
      </footer>
    </section>

    <!-- the curtain: a veil and a grid of cells, built by the script -->
    <div class="curtain" data-curtain aria-hidden="true">
      <div class="curtain__veil" data-veil></div>
      <div class="curtain__cells" data-cells></div>
    </div>
  </main>

  <script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/CustomEase.min.js"></script>
  <script src="script.js"></script>
</body>
</html>

Playground

Change values, colours and text with the controls and watch the animation respond live. Or write in the code yourself. Then download the folder with your changes.

41 values to change

Or ask Claude Code for it

With the Animorio connector, Claude Code takes it from here, guide included, and fits it into your project. Paste this request:

Take “The cell transition” from Animorio and fit it into my site

What it does

Hollin, a small made-up hotel high in the woods, has two pages: the rooms, on warm white paper, and the seasons, on the almost black brown of the woods at night. On opening the page is covered by a sand-coloured curtain that opens: it is made of twenty columns of twelve cells, and each cell pulls in sideways towards its middle, one after another, in a wave that begins at the bottom right corner and spreads up to the top left, in steps. Meanwhile the words of the headline, ‘Rooms above the treeline.’, arrive in scattered order: some jump down from above, others up from below, growing out of nothing, and each lands wide and thin and then narrows and gains weight until the headline is compact. On a click on ‘See the seasons’ the curtain closes again with the same wave: the cells stretch from their middle line until they touch, and the page still showing between one strip and the next darkens under a black veil. With the curtain closed the page changes; the curtain opens on the brown and ‘Snow comes early here.’ arrives the same way, then the small text and the link to go back. Another click brings back the rooms.

How it works

The curtain

The curtain is a div over the pages holding a black veil and twenty flex columns, each with twelve cells stacked (flex: 1). Every cell has margin -1px, as on the site: the cells overlap by a pixel and with the curtain closed no gap is left. They start at scaleX(0), squeezed to nothing towards their middle line, because the transform origin is the centre.

The wave

The cells sit in column order: the first column top to bottom, then the second. For GSAP’s stagger the grid is [COLS, ROWS], so each of its ‘rows’ is one of our columns and the distance between two cells is the real one. With from: 'end' the wave starts from the last cell, bottom right, and with each 0.03 every cell waits three hundredths of a second for each step of distance: the farthest cell starts after about two thirds of a second. Each cell stretches in 0.4 seconds with the curve 0.76, 0, 0.24, 1, slow at the start and at the end.

The veil and the change

Under the cells a black veil goes from clear to full in 1.2 seconds with the same curve: it darkens the strips of page still showing. 1.2 seconds after the click the curtain is closed: the old page hides, the new one shows with its words already at their starting point, and the opening begins, with the cells going back to scaleX(0) in the same order and the veil fading away.

The words in jumps

The headline’s words are split by hand into spans (one for GSAP, with one inside for the font axes). They start from yPercent -150, 75, -75 and 150 in turn, scale 0 and opacity 0 and arrive at zero, one and one in 1.2 seconds with the curve 0.25, 1, 0.5, 1, 0.2 seconds after the curtain starts to open, one every 0.025 seconds in random order. The text inside starts at font-stretch 125% and weight 280 and ends at 88% and 640: the word lands wide and light and tightens.

Reduced motion

With prefers-reduced-motion there is no curtain: the new page fades in over the other in 0.6 seconds, already set.

Values to change

NameFileDefaultWhat it changes
COLSscript.js20The columns of the curtain (twenty on the site).
ROWSscript.js12The cells in each column (twelve on the site).
CELL_TIMEscript.js0.4How many seconds a cell takes to stretch or pull in.
EACHscript.js0.03The gap between a cell and the next, in seconds: higher makes the wave slower.
FROMscript.js'end'Where the wave starts: end (bottom right), start (top left), center, edges, random.
HOLDscript.js1.2How many seconds after the click, with the curtain closed, the page changes.
VEILscript.js1How dark the veil under the cells gets: 0 none, 1 black.
VEIL_TIMEscript.js1.2How many seconds the veil takes to come, and to go.
JUMPSscript.js[-150, 75, -75, 150]Where the words come from, as a percentage of their height, in turn: negative from above, positive from below.
WORD_TIMEscript.js1.2How many seconds a word takes to arrive.
WORD_EACHscript.js0.025The gap between one word and the next, in scattered order.
WORD_DELAYscript.js0.2How long the words wait after the curtain starts opening.
WIDEscript.js125The width of the typeface (wdth axis, in %) a word lands with, before it narrows.
LIGHTscript.js280The weight a word lands with, before taking the headline’s.
CELL_EASEscript.js'0.76, 0, 0.24, 1'The curve of the cells and the veil (the site’s).
WORD_EASEscript.js'0.25, 1, 0.5, 1'The curve of the words (the site’s).

Try them in the Playground

When to use it

For the page change of a hotel, a holiday home, an architecture studio or a brand with warm tones, where the new page arrives with a big headline.

On phones

The same curtain of twenty columns by twelve cells, narrower and taller; the headline smaller and the link under the text. A tap changes page.

With reduced motion

No curtain and no jumps: the new page fades in, already set.

Pitfalls

  • GSAP’s grid stagger reads elements row by row: with the cells laid out column by column, as on the site, the grid must be written [COLS, ROWS] and not [ROWS, COLS], otherwise the wave skews diagonally.
  • The opening has to be built when the timeline is built, with the right page already passed in: added to a timeline about to end, it started after its onComplete and the next click found the demo free halfway.
  • SplitText is a plugin: the words are split by hand into two spans, one for the jump and the scale and one inside for font-stretch and weight, so GSAP’s transform and the font axes sit on different elements.
  • The cells with margin -1px overlap: without it, with the curtain closed, a grid of thin cracks shows the page through.
  • A click during the opening was ignored (the demo was ‘busy’) and the test poster came out at random, sometimes with the curtain closed and sometimes with no curtain. Now the opening has its own timeline: a click jumps it to the end with progress(1) and the curtain starts at once.

Libraries

GSAP 3.15.0, CustomEase (GSAP) 3.15.0, Archivo (font variabile) 5.3.0.

Compressed with gzip, the three demo files weigh 5.7 KB; the libraries: GSAP + CustomEase 31 KB.

Testing

Tested on 21 October 2026

  • Desktop: Done
  • Phone: Done
  • Reduced motion: Done
  • Safari on iPhone: To do

License

Use it in your own projects and in your clients’ projects. Do not resell it or redistribute it as is. GSAP stays under its own Standard license. Full license.

All animations