Skip to content
animorio
IT
Back to the library

The submarine in the deep

Scroll, SVGGSAPAdvancedCompressed weight: Demo 18 KBGSAP + ScrollTrigger 45 KBLenis 5.3 KBFreeDownload the zip

Scroll inside the preview

A sea museum’s page: as you scroll, a little yellow sub dives off the waves and goes all the way down to the seabed. The light fades band by band, schools of fish open as it passes, jellyfish, a squid and a dumbo octopus drift by, and in the dark its lamp throws a cone of light that sweeps over a wreck at 4,800 metres. A mechanical counter reads the depth.

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 submarine in the deep</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/bricolage-grotesque@5.3.0/standard.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/martian-mono@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <!-- the header of the made-up museum -->
  <header class="testata">
    <p class="marchio">Bellwether <span>Sea Museum</span></p>
    <a class="testata__link" href="#fine"><span>Plan a visit</span></a>
  </header>

  <main>
    <!-- the dive: a tall section with a still stage; scrolling moves the camera down the water column -->
    <section class="discesa" data-discesa>
      <div class="palco" data-palco>
        <svg class="mondo" data-mondo aria-hidden="true"></svg>
        <svg class="buio" data-buio aria-hidden="true"></svg>
        <svg class="sotto" data-sotto aria-hidden="true"></svg>

        <!-- the opening, in the sky above the water -->
        <div class="apertura" data-apertura>
          <p class="apertura__etichetta" data-entra>New in the Deep Gallery</p>
          <h1 class="apertura__titolo">
            <span class="riga"><span data-riga>Down to</span></span>
            <span class="riga"><span data-riga>the <em>dark.</em></span></span>
          </h1>
          <p class="apertura__testo" data-entra>Ride the little yellow sub <em>Pip</em> from the waves to the seabed, 4,800 metres below.</p>
        </div>
        <p class="cenno" data-cenno>
          Scroll to dive
          <svg viewBox="0 0 24 32" aria-hidden="true"><path d="M12 3V27M4 19L12 28L20 19" /></svg>
        </p>

        <!-- one caption for every band of depth -->
        <div class="didascalie" data-didascalie>
          <article class="didascalia" data-zona="0">
            <p class="didascalia__quota"><span>0 to 200 m</span></p>
            <h2 class="didascalia__nome"><span>The sunlight zone</span></h2>
            <p class="didascalia__testo"><span>Where the light still reaches. Most of the life in the sea crowds into this thin top layer.</span></p>
          </article>
          <article class="didascalia" data-zona="1">
            <p class="didascalia__quota"><span>200 to 1,000 m</span></p>
            <h2 class="didascalia__nome"><span>The twilight zone</span></h2>
            <p class="didascalia__testo"><span>The blue fades to grey. Jellies drift past and whole schools rise every night to feed.</span></p>
          </article>
          <article class="didascalia" data-zona="2">
            <p class="didascalia__quota"><span>1,000 to 4,000 m</span></p>
            <h2 class="didascalia__nome"><span>The midnight zone</span></h2>
            <p class="didascalia__testo"><span>No sunlight at all. From here on, the only light is the one Pip carries.</span></p>
          </article>
          <article class="didascalia" data-zona="3">
            <p class="didascalia__quota"><span>4,000 to 6,000 m</span></p>
            <h2 class="didascalia__nome"><span>The abyss</span></h2>
            <p class="didascalia__testo"><span>Near-freezing water and hundreds of times the pressure of the air on your shoulders.</span></p>
          </article>
          <article class="didascalia" data-zona="4">
            <p class="didascalia__quota"><span>On the seabed</span></p>
            <h2 class="didascalia__nome"><span>The Argo Bell</span></h2>
            <p class="didascalia__testo"><span>A cargo steamer lost in a winter storm in 1923, resting upright where no storm can reach her.</span></p>
          </article>
        </div>

        <!-- the depth gauge: real numbers, counted as the sub goes down -->
        <aside class="strumento" data-strumento aria-label="Depth gauge">
          <p class="strumento__nome">Depth</p>
          <p class="strumento__metri"><span class="contatore" data-contatore></span><span class="strumento__unita">m</span></p>
          <dl class="strumento__dati">
            <div><dt>Pressure</dt><dd data-pressione>1 atm</dd></div>
            <div><dt>Sunlight</dt><dd data-luce>100%</dd></div>
          </dl>
        </aside>
        <div class="scala" data-scala aria-hidden="true">
          <div class="scala__binario"></div>
          <svg class="scala__segno" data-segno viewBox="0 0 40 20"><path d="M6 10C6 5 11 3 20 3C29 3 35 6 35 10C35 14 29 17 20 17C11 17 6 15 6 10Z" /><path d="M16 3L18 0H24L25 3Z" /><path d="M1 6L6 10L1 14Z" /></svg>
        </div>
      </div>
    </section>

    <footer class="fine" id="fine">
      <p class="fine__frase">Come down <em>with us.</em></p>
      <p class="fine__testo">The Deep Gallery, open every day from ten. Pip is waiting at the bottom of the stairs.</p>
      <a class="fine__bottone" href="#"><span>Plan your visit</span></a>
    </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/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.

64 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 submarine in the deep” from Animorio and fit it into my site

What it does

The page of a made-up sea museum, the Bellwether Sea Museum. At the top a sand-coloured sky, the big title «Down to the dark.» and the sea below it: the yellow sub Pip drops from above, hits the water with a splash of drops and two widening rings, then floats rocking on the waves. As you scroll the stage holds still and the camera follows Pip down: the title flies off, the depth gauge appears at the top right and, along the edge, a scale with a tiny sub going down it. The metres are a mechanical counter: every figure is a column that rolls on to the next, carrying like an odometer; below sit the pressure in atmospheres and the sunlight left. Pip tips its nose down when the dive is fast, trails bubbles from its propeller and drifts a little from side to side. The sea goes from turquoise to blue, to midnight blue, to black, and at every band (sunlight, twilight, midnight, the abyss) a caption rises line by line at the bottom left, while a dashed line marks in the water where the band begins. A school of silver fish and then one of dark fish part around the sub like a curtain and close behind it; jellyfish drift past, squeezing their bells and trailing their tentacles. When the dark comes, Pip switches on its lamp: the cone of light comes on with a small elastic flicker and from then on you only see what falls in the beam, the marine snow, a squid swimming in jets, a dumbo octopus flapping its ears. At the bottom Pip moves aside, the beam turns to the wreck of the steamer Argo Bell lying on the seabed and runs along it from stern to bow. The pointer scares the fish and jellyfish away; touching Pip makes the sub shake and puff out a burst of bubbles.

How it works

The stage and the water column

The section is DIVE_LENGTH+1 screens tall and holds a sticky stage 100lvh tall with three SVGs on top of each other: the world, the dark and the sub, each with a viewBox as big as the stage in pixels. The world is a group more than six screens tall (sky, water with a four-stop gradient, fish, jellyfish, wreck, seabed) that slides up every frame: the camera is just a translate that keeps Pip still at 42% of the height.

Metres that are not linear

Real depths do not fit on a screen evenly: 200 metres of light against 3,000 of midnight. A small table of knots says where each depth sits in screens below the waves (0, 1.5, 3, 4.6, 5.8) and two functions, profondita(u) and quota(d), go from one to the other in straight pieces. So every band gets its own stretch of scroll, and the counter always reads the right metres for Pip’s position.

A timeline of numbers

A single timeline tied to the scroll with scrub moves an object of numbers: p (how far down, with power1.inOut), luce (the lamp, with elastic.out, so it flickers on), fine, mira and spazza (the final move aside and the beam running over the wreck). The captions come in when Pip passes 200, 1,000 and 4,000 metres: that moment is found by inverting the dive’s ease with thirty halvings.

The dark with a hole

Over the world lies a rectangle the colour of the dark, its opacity growing with depth, and a mask: a white rectangle with the lamp’s cone in black, softened with feGaussianBlur. Where the cone is, the dark disappears and the world shows through; on top, the same cone filled with a warm gradient in mix-blend-mode screen makes the light. The cone follows the sub’s nose and turns with it.

Fish on springs

Every fish has a place in a school that slowly swims sideways, and a damped spring: if the sub or the pointer is within a radius, the spring’s goal becomes a push outwards, stronger the closer it is, and the fish gets there with a small bounce, turned along its speed. Once Pip has passed the spring brings it back and the school closes. The jellyfish use the same spring, softer.

Values to change

NameFileDefaultWhat it changes
DIVE_LENGTHscript.js9How many screens of scrolling the dive lasts.
MAX_DEPTHscript.js4800The depth of the seabed in metres, where the wreck lies.
FISHscript.js36How many fish in each school; a phone gets about three quarters.
PARTscript.js1How wide the schools open around the sub and the pointer.
JELLIESscript.js6How many jellyfish in the twilight zone.
BEAMscript.js1How long and wide the lamp’s beam is.
WEAVEscript.js1How far the sub drifts from side to side on the way down.
SNOWscript.js70How many specks of marine snow drift through the beam.
--sottomarinostyle.css#ffc629The sub’s yellow; next to it are the colours of the water at each depth, of the dark and of the beam.

Try them in the Playground

When to use it

To tell a descent or a scale of sizes: a sea or science museum, an aquarium, an expedition, a diving centre, the page of an ocean research project, but also a story that goes from light to deep, or the tiers of a product.

On phones

The same dive with the sizes adapted: smaller sub, fish and creatures, about three quarters of the fish, the school wider for the screen, a longer beam, the wreck smaller and closer to the middle. The scale on the edge is shorter and has no labels. A tap on Pip makes it shake and puff bubbles.

With reduced motion

No travelling camera, no swimming, no bubbles and no smooth scrolling: the stage shows one still picture per band (the surface, sunlight, twilight, midnight, the abyss, the wreck) and scrolling fades in the next, with the lamp already on where it is dark, the counter on that band’s number and its caption.

Pitfalls

  • Before the first frame the fish, jellyfish and octopus were drawn at 0,0, that is in the sky at the top left: a pink octopus showed up over the title. Every creature is born with translate(-999 -999) and is placed only when its band is near the screen.
  • A see-through band of water in front of the hull, to make it look afloat, was solid all the way down: it tinted the yellow green and left a hard step in the light rays. Now it is a gradient that fades out in a few pixels.
  • With the counter’s units rolling non-stop, every picture caught two half figures and the number could not be read. Every figure holds still and rolls to the next only in the last fifth of a metre, and the ones above carry at the same moment.
  • The squid that rises in jets and starts again from below with a modulo jumped suddenly. Each cycle has a jet up and a slow sink of the same size, so the position comes back to where it started without a jump.
  • A mask with a cone blurred by feGaussianBlur is not free: the cone is drawn only when the lamp is on, and fish, jellyfish and creatures update only when their band is on screen.

Libraries

GSAP 3.15.0, Lenis 1.3.26, Bricolage Grotesque (font variabile) 5.3.0, Martian Mono (font variabile) 5.3.0.

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

Testing

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