Skip to content
animorio
IT
Back to the library

Ink blotted dry

Scroll, TextGSAP, CSS onlyAdvancedCompressed weight: Demo 7.1 KBGSAP + ScrollTrigger 45 KBFreeDownload the zip

Scroll inside the preview

A word just written in fresh ink, heavy and soft, with a shine sliding over it. As you scroll a rocker blotter rolls across it, the baseline gives under its weight and every letter comes out dry: light, sharp, with a tiny breath. At the end the blotter lifts, turns over and shows the letters it took, mirrored and blue. Minimal style.

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>Ink blotted dry</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/fraunces@5.3.0/full.css">
  <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>
  <!-- a word just written in fresh ink, heavy and soft; as you scroll a rocker blotter rolls across it and every letter
       comes out dry, light and sharp. At the end the blotter lifts, turns over and shows the ink it took, mirrored.
       The word and the numbers are in the values at the top of script.js -->
  <main>
    <section class="racconto" data-racconto>
      <div class="palco">
        <header class="testa">
          <p class="marchio">Quire</p>
          <p class="sezione">Writing room</p>
        </header>

        <div class="foglio">
          <div class="riga" data-riga>
            <!-- the word for screen readers; the script splits it into letters -->
            <p class="parola" data-parola aria-label="Sincerely"></p>
            <svg class="base" data-base aria-hidden="true" preserveAspectRatio="none">
              <path class="base__linea" data-base-linea d="" />
              <g data-tacche></g>
            </svg>
            <div class="tampone" data-tampone aria-hidden="true">
              <div class="tampone__giro" data-giro>
                <div class="tampone__faccia tampone__faccia--sopra">
                  <span class="tampone__piastra" data-piastra></span>
                  <span class="tampone__pomo" data-pomo></span>
                </div>
                <div class="tampone__faccia tampone__faccia--sotto" data-impronta></div>
              </div>
            </div>
          </div>
        </div>

        <footer class="piede">
          <p class="cenno" data-cenno>Scroll to blot the ink</p>
          <p class="stato"><span class="stato__nome">Ink</span> <span class="stato__valore" data-stato>wet</span></p>
        </footer>
      </div>
    </section>

    <section class="coda">
      <p class="coda__testo">Quire sells writing paper,<br>nibs and rocker blotters.</p>
      <p class="piccolo">Letters that dry before you fold them</p>
    </section>
  </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="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.

24 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 “Ink blotted dry” from Animorio and fit it into my site

What it does

The page belongs to Quire, an invented stationery shop. In the middle, on warm white paper, the word «Sincerely» appears, written letter by letter from the left as if by a pen: it is fresh ink, black, very heavy, with soft edges and a slightly bleeding halo, and a light shine slides over it now and then. Under it runs the thin baseline with a tick between one letter and the next; at the bottom right it says «Ink wet». As you scroll, the rocker blotter, seen from above (a rectangle with its plate and knob), leaves its place under the word, straightens up and settles on the first letter; then it rolls across the word, rocking: the plate slides sideways, the shadow follows the rocking and the baseline sinks a little under its weight. Every letter the blotter uncovers is dry: thin, sharp, without halo or shine, and it takes a tiny elastic breath; the letters do not move, because the space the glyph loses goes around it, and the tick under it grows longer. At the end the blotter lifts, moves to the centre above the word and turns over: underneath, on the blotting paper, are the letters it took, mirrored, blue and overlapping. «Ink» turns to «dry» in blue and the hint says «Dry, ready to fold». Scroll back and everything is fresh again.

How it works

The typeface axes make the ink

Fraunces has three axes: weight (wght), optical size (opsz) and softness (SOFT). Fresh ink is weight 820 and SOFT 100, which rounds the corners like a spreading drop; dry is weight 420 and SOFT 0. A text-shadow with its blur in em makes the halo, and a copy of the letter with a gradient in background-clip: text makes the sliding shine.

The letters stay in place

At the start and on every resize the script measures each letter wet and dry. As it dries, the letter takes a padding-inline equal to half the width it loses: the word stays the same length and every letter keeps its centre, so the blotter always knows where they are.

The blotter and the drying front

A single tween with ScrollTrigger and scrub carries a number from 0 to 1. Up to 0.1 the blotter settles, up to 0.7 it crosses the word, then it lifts and turns. The drying front sits under the blotter, a third of its width in: each letter dries with a 0.3 em wide smoothstep around its centre, and the weight follows a back.out curve, so it goes a little below the dry weight and comes back.

Rocking, shadow and the giving line

While it runs the blotter has a rotationY swinging a few degrees (the rocking, with perspective on the line), the plate slides the opposite way and the shadow is a CSS variable recomputed every frame. The baseline is an SVG path redrawn with a Gaussian under the centre of the blotter: it sinks where it presses.

The turn and the imprint

The blotter has two faces with backface-visibility: hidden, the bottom one already turned 180 degrees. GSAP turns the container with rotationX; underneath, every letter has its mirrored copy (scaleX(-1)) in a different spot, and its opacity grows with how dry the letter is.

Values to change

NameFileDefaultWhat it changes
WORDscript.js'Sincerely'The word written in fresh ink.
WETscript.js820The weight of the fresh ink.
DRYscript.js420The weight of the dry letters.
SOFTscript.js100How soft the wet edges are (the Fraunces SOFT axis, 0 to 100).
BLEEDscript.js0.03The halo of the wet ink, in em.
ROCKscript.js5How much the blotter rocks, in degrees.
DIPscript.js0.035How much the baseline gives under the blotter, in em.
SCRUBscript.js0.6How many seconds the word takes to catch up with the scroll.
WRITEscript.js1.2How long the word takes to be written when the page opens, in seconds.

Try them in the Playground

When to use it

For the page of a stationery shop, a calligraphy studio or a letters and invitations service, for the signature at the end of a letter or an about page, for the opening of an article about handwriting. It works with a single word, five to ten letters long.

On phones

The same: the word is sized on both the width and the height of the screen, and the blotter always stays inside the page.

With reduced motion

No blotter, no movement and no shine: as you scroll the letters dry one after the other in place, losing weight and halo, and «Ink» turns to «dry».

Pitfalls

  • The width of the letters changes with the weight: without the compensating padding the word gets shorter as it dries and the letters slide out from under the blotter.
  • The blotter starts resting under the word, not to its left: on a phone there is not enough margin to the left of the word and it would leave the page.
  • GSAP moves the blotter and turns the container of its faces, two different elements: the rocking (rotationY) and the turn (rotationX) do not cancel each other.

Libraries

GSAP 3.15.0, ScrollTrigger (GSAP) 3.15.0, Fraunces (font variabile) 5.3.0, Mona Sans (font variabile) 5.3.0.

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

Testing

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