Skip to content
animorio
IT
Back to the library

The tree of the seasons

Scroll, SVGGSAP, CSS onlyAdvancedCompressed weight: Demo 16 KBGSAP + ScrollTrigger 45 KBLenis 5.3 KBFreeDownload the zip

Scroll inside the preview

A big tree on a hill and, as you scroll, a whole year goes by: in spring buds and pink blossoms opening, in summer a full crown swaying with fruit, in autumn leaves that change colour and twirl down into a pile, in winter snow on the branches. On one branch there is a nest where the chicks hatch, grow and fly away.

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 tree of the seasons</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/mona-sans@5.3.0/standard.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="scena" data-scena>
    <div class="palco" data-palco>
      <!-- il cielo: lo script ne fonde i colori stagione per stagione -->
      <div class="cielo" data-cielo aria-hidden="true"></div>

      <!-- la collina, l'albero, il nido, la neve: lo script li disegna -->
      <svg class="mondo" data-mondo aria-hidden="true" focusable="false"></svg>

      <header class="testata">
        <p class="marchio">
          <svg class="marchio__segno" viewBox="0 0 32 32" aria-hidden="true" focusable="false"><path d="M16 29V14" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round"/><path d="M16 17c-7 0-11-4-11-12 7 0 11 4 11 12Z" fill="currentColor"/><path d="M16 21c6 0 10-3.4 10-10-6 0-10 3.4-10 10Z" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linejoin="round"/></svg>
          <span>Linden Hill Nursery</span>
        </p>
        <a class="pianta" href="#"><span class="pianta__fondo" aria-hidden="true"></span><span class="pianta__testo">Plan your planting</span></a>
      </header>

      <section class="racconto">
        <p class="occhiello">The year of the old linden</p>
        <h1 class="stagione" data-stagione aria-live="polite"></h1>
        <p class="mese"><span class="mese__nome" data-mese></span><span class="mese__consiglio" data-consiglio></span></p>
        <div class="riga" data-riga></div>
      </section>

      <p class="cenno" data-cenno>Scroll through the year</p>
    </div>
  </main>

  <!-- le quattro stagioni: il nome e la riga -->
  <ul class="stagioni" data-stagioni hidden>
    <li data-nome="Spring">Buds swell, blossoms open and a pair of robins move into the old linden.</li>
    <li data-nome="Summer">Full shade, ripe fruit and three hungry chicks that will not stop calling.</li>
    <li data-nome="Autumn">The leaves turn gold and copper, then come down to tuck the roots in.</li>
    <li data-nome="Winter">Bare branches, fresh snow and a quiet nest waiting for March.</li>
  </ul>

  <!-- i dodici mesi del calendario del vivaio: il nome e il lavoro del mese -->
  <ul class="mesi" data-mesi hidden>
    <li data-nome="March">Feed the roots</li>
    <li data-nome="April">Plant out seedlings</li>
    <li data-nome="May">Mulch the beds</li>
    <li data-nome="June">Water at dusk</li>
    <li data-nome="July">Thin the fruit</li>
    <li data-nome="August">Pick and share</li>
    <li data-nome="September">Sow wildflowers</li>
    <li data-nome="October">Rake for the compost</li>
    <li data-nome="November">Plant bare-root trees</li>
    <li data-nome="December">Wrap young trunks</li>
    <li data-nome="January">Prune on dry days</li>
    <li data-nome="February">Order spring seeds</li>
  </ul>

  <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/ScrollTrigger.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/lenis@1.3.26/dist/lenis.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.

45 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 tree of the seasons” from Animorio and fit it into my site

What it does

The page of a made-up tree nursery, Linden Hill Nursery, held on screen while you scroll: a big bare tree on a hill, distant hills, the sun and a few passing clouds. The whole way down is one year, from March to February. In spring dark pink buds appear on the branches and open one by one into five-petal blossoms with an elastic bounce; then light green leaves grow, and at the end of spring the petals come loose and twirl down. Meanwhile a robin flies in and lands on the rim of the nest, three blue eggs appear, tremble and hatch, and three grey chicks come out opening their beaks because they are hungry. In summer the crown is full and dark green and sways in the wind, the fruit appears green and turns red, the chicks grow, getting their feathers and orange breast. In autumn each leaf turns gold, copper or red on its own, the fruit drops bouncing on the grass, the chicks and their mother fly away one after another and the leaves come off and spin down until they pile up at the foot of the trunk, where they darken. In winter the sky turns grey blue, it starts to snow, the snow settles on the branches one by one and covers the hill, the pile of leaves and the empty nest. The sky and the hill change colour with the seasons and the sun is high in summer and low in winter. On the left the season's name changes with letters that arrive from below and bounce (from above when scrolling back), below it the month and the month's job in the nursery calendar roll away, and the season's line rises word by word.

How it works

Scrolling is a year

A single tween takes one number from 0 (early March) to 1 (late February) while the scene goes from top to bottom (start top top, end bottom bottom, scrub 0.8). Every frame a single function draws everything from that number: sky, hill, leaves, fruit, snow, nest. Lenis smooths the scrolling and passes each step to ScrollTrigger.update.

A tree with a fixed seed

The trunk splits into two or three branches, and each of them again, five times, with angles and lengths taken from a seeded random number generator: the same tree every time, and changing TREE_SEED grows another one. Each branch is a filled shape that tapers along a curve, with a round knot where it splits. Leaves, blossoms and fruit sit on random points of the thin branches.

Thresholds that bounce

Every bud, blossom, leaf, fruit, egg and chick has its own moment in the year. When scrolling passes it, a tween with elastic.out starts on its growth value, and going back a short tween closes it: this way the scrub stays precise and every arrival keeps its bounce.

Computed falls

A falling leaf has no tween: its position is a function of the year, between its point on the branch and its place in the pile, with a sideways wave, a rotation and a flip (scaleX going from 1 to -1) for the twirl. That is why it also works scrolling back up, and the leaves go back on the branches. The fruit comes down with the bounce.out curve.

Bouncing text

The season's name is split into letters inside boxes with overflow: hidden: the old ones leave upwards, the new ones come in from below squashed and bounce with elastic.out, the other way when scrolling up. The month and the month's job roll with back.out, the line rises word by word.

Values to change

NameFileDefaultWhat it changes
LEAVESscript.js420How many leaves the crown has in summer. They are also the ones that later fall into the pile.
BLOSSOMSscript.js70How many blossoms open in spring; 0 skips the blossom.
FRUITSscript.js16How many fruits ripen in summer and drop in autumn.
SNOWFLAKESscript.js90How many flakes fall in winter; 0 leaves only the settled snow.
WINDscript.js1How much leaves and fruit sway in the wind; 0 keeps them still.
TREE_SEEDscript.js7The tree's seed: every number grows a different tree.
--cielo-primavera … --cielo-invernostyle.css#9fd0ea, #5aaee6, #e9b98a, #a9b6ccEach season's sky; it fades to light at the bottom on its own.
--foglia-oro, --foglia-rame, --foglia-rossastyle.css#e8b62f, #d9702a, #b8402eThe three autumn leaf colours, picked at random leaf by leaf.

Try them in the Playground

When to use it

To tell the passing of a year: a tree nursery or a garden, a farm, a sowing calendar, a winery, a park, an “our story” page told by seasons.

On phones

The same year with adapted sizes: the text sits at the top at full width and the tree below, framed so the whole crown always fits on screen, with the nest and the birds in proportion.

With reduced motion

Nothing moves continuously: the year goes in steps, one season at a time, and each change is a fade. Blossoms, leaves, fruit and chicks fade in without bounces, the leaves are already on the branches or already in the pile (never mid-air), they do not sway, the snow stands still and the text changes with a fade.

Pitfalls

  • Animating every falling leaf with a tween does not survive scrubbing backwards: the leaf's position is computed from the year, so scrolling up it goes back to its branch on its own. Tweens are only used for the arrival bounces, on the growth value.
  • Hundreds of leaves every frame: writing an attribute equal to the previous one still costs. It is only written when the value changes (remembered on the element), and all leaves are a <use> of the same drawing.
  • Snow on branches made with stroke-dasharray and a round linecap leaves a white dot even at zero: until it snows the stroke has opacity 0.
  • A fixed viewBox with slice crops the crown on a phone: the framing is computed from the crown's size, so it always fits, and the stage is 100lvh tall and is reframed only if the size really changes (not for Safari's bar).
  • Chicks in front of the nest look as if they were sitting on top of it: the nest is in two pieces, the back behind and the rim in front, with the chicks in between.

Libraries

GSAP 3.15.0, Lenis 1.3.26, Mona Sans (font variabile) 5.3.0.

Compressed with gzip, the three demo files weigh 16 KB; the libraries: GSAP + ScrollTrigger 45 KB, Lenis 5.3 KB.

Testing

Tested on 11 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