Skip to content
animorio
IT
Back to the library

The seasons in lines

Images, TransitionsGSAP, Canvas, CSS onlyMediumCompressed weight: Demo 7.3 KBGSAP + CustomEase 31 KBFreeDownload the zip

A mountain landscape drawn in vertical lines, in the minimal style: every cell of the grid holds a line as wide as the cell is dark. The button changes the season: the summer’s levels wipe the lines column by column and the winter’s make them grow from below, until the mountain stands with its snow left empty between the lines.

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>Hollin, seasons in lines</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/anybody@5.3.0/wdth.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <!-- two landscapes drawn in grey on hidden canvases, shown as vertical lines: each cell of the grid holds one line
       as wide as the cell is dark. The button swaps the season: one landscape thins out to nothing, the other grows in -->
  <main class="pagina" data-pagina>
    <header class="testa">
      <p class="marchio">Hollin</p>
      <p class="nota">A mountain hotel, open all year</p>
    </header>

    <figure class="palco" data-palco>
      <canvas class="tela" data-tela aria-label="A mountain landscape drawn in vertical lines"></canvas>
      <span class="filo" data-filo aria-hidden="true"></span>
    </figure>

    <footer class="piede">
      <h1 class="stagione" aria-live="polite">
        <span class="stagione__parola is-on" data-parola="summer">Summer</span>
        <span class="stagione__parola" data-parola="winter" aria-hidden="true">Winter</span>
      </h1>
      <button class="pillola" type="button" data-cambia data-autoclic>
        <span class="pillola__scritta" data-scritta data-testo="See it in winter">See it in winter</span>
        <svg class="pillola__freccia" viewBox="0 0 16 16" aria-hidden="true"><path d="M2.5 8h10.5M9 3.8 13.2 8 9 12.2" /></svg>
      </button>
    </footer>
  </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.

21 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 seasons in lines” from Animorio and fit it into my site

What it does

Hollin, a made-up mountain hotel, shows its landscape as an engraving made of vertical lines on a warm white. In summer the sun is a white circle where the lines thin out until they vanish, the three ridges go from light grey to brown, the hotel has its windows lit and in front a river opens between the fir trees. On opening the landscape draws itself from left to right: in each column the lines grow from the bottom of their cell and widen to their weight, while underneath a sand thread follows the front and then pulls back, and the word Summer rises letter by letter, wide and light, settling narrow and full. The See it in winter button changes the season: column after column the summer’s lines thin out and drop until they vanish, and in their place the winter’s grow, with more contrast: the overcast sky in thin lines, the dark rocks and the snow left empty on the crests, the roofs and the tips of the fir trees, the frozen lake. The word Summer leaves upwards, narrowing, and Winter arrives. Another click goes back to summer.

How it works

Two landscapes in grey

Summer and winter are drawn in greyscale on two hidden canvases, with simple shapes: ridges made of sums of sines, always the same, triangle fir trees, the stepped hotel with its windows, a gradient sky. The hidden canvas is three times finer than the grid, and for each cell the grey of the pixel in the middle is read with getImageData. It is only redone when the stage changes size (ResizeObserver), even halfway through a change.

One line per cell

Levels first, as in a photo editor: the grey becomes (grey minus black) over (white minus black), kept between 0 and 1. Then the width of the line: (1 minus the light) times (MAX_W minus MIN_W) plus MIN_W, as a fraction of the cell. With MIN_W at -0.02 white draws nothing and with MAX_W at 1.02 the black lines touch. All the lines of both seasons go into a single path of rectangles and a single fill.

Changing season with the levels

A hidden season has the HIDDEN levels, 0 and 1: every grey above zero becomes white and the lines vanish. The change takes the incoming season’s levels to its own (SUMMER or WINTER) and the other’s to HIDDEN. Winter uses 25 and 150, that is more contrast: everything lighter than 150, the snow, stays empty.

The choreography

A single number, p, goes from 0 to 1 in DURATION seconds; each column has its own time, p times (1 plus STAGGER) minus STAGGER times its position, so the change runs from left to right. Each column interpolates the levels on the InOut curve (0.76, 0, 0.24, 1); incoming lines grow from the bottom of the cell with power3.out, outgoing ones drop with power2.in. The sand thread follows the front, then pulls back to the right, and the letters of the word change width and weight with Anybody’s axes.

Reduced motion

No wave and no flying letters: the landscape fades out, is redrawn in the new season and comes back; the word changes with a fade.

Values to change

NameFileDefaultWhat it changes
COLSscript.js100The columns of the grid, that is how many vertical lines (60% on a phone).
ROWSscript.js100The rows of the grid: the more there are, the finer the drawing from top to bottom.
MIN_Wscript.js-0.02The width of the line where the cell is white, as a fraction of the cell: below zero white stays empty.
MAX_Wscript.js1.02The width of the line where the cell is black: above 1 the lines touch.
SUMMERscript.js[0, 255]The summer’s levels: black point and white point.
WINTERscript.js[25, 150]The winter’s levels: more contrast, the snow stays empty.
HIDDENscript.js[0, 1]The levels of a hidden season: every grey turns white.
DURATIONscript.js1.2The seconds of a change of season.
STAGGERscript.js0.6How much the change runs from left to right: 0 all columns at once.

Try them in the Playground

When to use it

For the site of a hotel, a mountain hut or a holiday home that changes with the seasons, the page of a resort, a black and white home page that needs character without using photos.

On phones

The same animation, with a tall narrow stage: the columns are 60%, the landscape is redrawn for the new shape and the hotel and fir trees are sized on the shorter side. A tap changes the season.

With reduced motion

The landscape changes season with a fade, without the wave of columns, and the word appears and disappears without moving.

Pitfalls

  • With the winter’s levels, 25 and 150, every grey above 150 turns white: the first winter, drawn in the light greys of the summer, almost entirely vanished. The winter’s greys must be chosen within its range, below 150 what must show, above it the snow.
  • With the two landscapes on the same grid, one line per season overlaps: that is why halfway through a change the columns under the wave are darker, and it is on purpose. Drawing them in a single path with a single fill keeps the change light even with ten thousand cells.
  • A click during a change jumps the running one to its end (progress(1)) before reading the starting levels: otherwise the new season would start from halfway levels, different in every column.

Libraries

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

Compressed with gzip, the three demo files weigh 7.3 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