Skip to content
animorio
IT
Back to the library

The title written in chalk

Text, SVGCanvas, GSAPAdvancedCompressed weight: Demo 20 KBGSAP 28 KBFreeDownload the zip

A green chalkboard in a wooden frame: a stick of chalk writes the title in joined-up handwriting, with a grainy line and dust falling, wears down, snaps in two and one piece bounces on the tray; under it, it draws a sketch. Then the eraser passes, leaves a white haze and the next phrase is written. A click sends the eraser at once.

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 title written in chalk</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/familjen-grotesk@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="scena" data-scene>
    <!-- the phrase on the board, for screen readers: the script keeps it in step with what the chalk writes -->
    <h1 class="leggibile" data-reader>Fresh coffee all day</h1>
    <!-- the slate: its texture, the chalk, the dust and the white haze the eraser leaves are painted on this canvas -->
    <canvas class="lavagna" data-board aria-hidden="true"></canvas>
    <!-- the wooden frame, the tray, the stick of chalk, its broken pieces and the eraser: the script sizes them -->
    <svg class="cornice" data-stage aria-hidden="true">
      <defs>
        <filter id="grana-orizzontale" x="0" y="0" width="1" height="1" color-interpolation-filters="sRGB">
          <feTurbulence type="fractalNoise" baseFrequency="0.006 0.22" numOctaves="3" seed="4" result="rumore" />
          <feColorMatrix in="rumore" type="matrix" values="0 0 0 0 0.24  0 0 0 0 0.13  0 0 0 0 0.06  0 0 0 1.5 -0.55" result="venature" />
          <feComposite in="venature" in2="SourceGraphic" operator="atop" />
        </filter>
        <filter id="grana-verticale" x="0" y="0" width="1" height="1" color-interpolation-filters="sRGB">
          <feTurbulence type="fractalNoise" baseFrequency="0.22 0.006" numOctaves="3" seed="9" result="rumore" />
          <feColorMatrix in="rumore" type="matrix" values="0 0 0 0 0.24  0 0 0 0 0.13  0 0 0 0 0.06  0 0 0 1.5 -0.55" result="venature" />
          <feComposite in="venature" in2="SourceGraphic" operator="atop" />
        </filter>
        <filter id="polvere-sul-gesso" x="-0.1" y="-0.3" width="1.2" height="1.6" color-interpolation-filters="sRGB">
          <feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="1" seed="2" result="rumore" />
          <feColorMatrix in="rumore" type="matrix" values="0 0 0 0 0.55  0 0 0 0 0.53  0 0 0 0 0.48  0 0 0 2.2 -1.25" result="puntini" />
          <feComposite in="puntini" in2="SourceGraphic" operator="atop" />
        </filter>
        <filter id="ombra-morbida" x="-0.5" y="-0.5" width="2" height="2">
          <feGaussianBlur stdDeviation="2.6" />
        </filter>
        <linearGradient id="gesso" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0" style="stop-color: var(--chalk-light)" />
          <stop offset="0.45" style="stop-color: var(--chalk)" />
          <stop offset="1" style="stop-color: var(--chalk-shade)" />
        </linearGradient>
        <linearGradient id="legno-cornice" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0" style="stop-color: var(--wood-light)" />
          <stop offset="0.5" style="stop-color: var(--wood)" />
          <stop offset="1" style="stop-color: var(--wood-dark)" />
        </linearGradient>
        <linearGradient id="legno-lato" x1="0" y1="0" x2="1" y2="0">
          <stop offset="0" style="stop-color: var(--wood-light)" />
          <stop offset="0.55" style="stop-color: var(--wood)" />
          <stop offset="1" style="stop-color: var(--wood-dark)" />
        </linearGradient>
        <linearGradient id="legno-cancellino" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0" style="stop-color: var(--eraser-light)" />
          <stop offset="0.6" style="stop-color: var(--eraser)" />
          <stop offset="1" style="stop-color: var(--eraser-dark)" />
        </linearGradient>
      </defs>
      <g data-tray-back></g>
      <g data-objects></g>
      <g data-front></g>
    </svg>
    <p class="nota" data-hint>Click or tap to wipe the board</p>
  </main>

  <script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.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.

26 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 title written in chalk” from Animorio and fit it into my site

What it does

The whole window is a green slate blackboard, with lighter and darker blotches, a fine grain, corners in shadow and the ghosts of words wiped long ago, closed in a wooden frame with its grain. At the bottom is the tray: on the left the eraser, lying on its felt, on the right a new stick of chalk. The chalk rocks, lifts, turns to the board and starts writing the phrase of a made-up café, Fresh coffee all day, in joined-up handwriting, stroke after stroke: joined letters come out in one stroke, and the dots of the i and the bars of the t come at the end of the word, as a hand does them. The line is grainy, with holes where the chalk skips over the pores of the slate, thinner where it starts and ends; dust falls from the tip, and the stick leans with its movement and gets shorter as it writes. Halfway through the phrase it stops, presses, a crack appears, it trembles and snaps: the front half drops, spins, bounces two or three times on the tray in a little cloud of dust and stays there; the other half jolts and carries on writing with its broken end, which makes a wider line. Under the phrase it draws a little cup on its saucer with the steam, then lies back down in the tray with a small bounce. After a couple of seconds the eraser lifts, turns its felt to the board and wipes it in rows, back and forth, tilting at every turn and puffing dust: the chalk goes, but a white haze stays, smeared the way the eraser went. The chalk, shorter now, writes the second phrase over the haze, Lemon cake, baked today, with a lemon and its leaf. At the end the eraser wipes the board again, drops into the tray, slides along it pushing out the stub and the broken piece, goes back to its place, the haze fades and a new stick of chalk slides in: it starts again. A click, whenever you like, sends the chalk back to the tray and the eraser across at once.

How it works

A one-stroke script

The letters are the Hershey Script 1-stroke alphabet (from the early sixties, free to use with its note of origin), written in the script as numbers: for every letter its width and its strokes, points joined by lines, with the baseline at zero and small letters 9 units tall. Joined-up letters end where the next one begins, so strokes that touch are merged into one: a word comes out without lifting the chalk. The dot of the i and the bar of the t move to the end of the word. Every stroke goes through Chaikin's algorithm three times, which rounds off the corners, and keeps its running lengths, so the tip's position is known at every moment. The phrase wraps onto one, two, three or four lines: whichever makes it biggest wins.

The chalk line

The chalk is laid down in dabs on a canvas: every few pixels of path, three small semi-transparent circles moved at random, smaller where the stroke starts and ends, with a pressure that sways slowly. Every frame this canvas is copied onto another and passed through destination-in over a noise pattern (a 160 pixel tile with fuller and emptier patches and 16% holes): those are the pores of the slate, fixed to the board, where the chalk skips. The dust is little specks with gravity born from the tip as it writes.

The chalk that snaps

The stick is an SVG path built from its length, with a round or a broken tip (a random zigzag) and a gradient from one side to the other; its sway is the writing angle plus a damped lean that follows its speed. It gets shorter by a little for every pixel written. At the breaking point a timeline brings up the crack and makes it tremble, then snaps it: the front half becomes a piece of its own, which falls through a small simulation (gravity, bounces that lose 64%, a turn until it lies flat) worked out once and played back by a tween, so GSAP keeps the time; the half that stays moves by half its length and looks exactly as before, so there is no jump.

The eraser and the haze

When the eraser starts, a copy of the writing is shrunk to a sixth: scaled up again it is a blurred writing. The eraser goes in rows with sine.inOut tweens and every frame, in short steps along its path, takes the chalk away with destination-out and, clipped to its outline, lays on the haze canvas a veil of that blurred copy, shifted a little backwards, plus the fine lines of the felt. Each pass takes away half of the chalk: after two or three only a trace is left, as it really happens. In the tray the eraser is seen side on; to turn to the board it squashes in height and comes back showing its back.

Direction

Every round is a single timeline: the chalk lifts, writes stroke by stroke (one tween per stroke, its length giving its duration, and a hop for every lift), goes back to the tray, waits, the eraser passes; the same for every phrase. At the end the eraser pushes the pieces out of the tray, the haze and the leftover chalk fade, and at the end of the timeline the round starts again, identical, with the same random numbers. A click stops the timeline and builds a new one starting with the eraser. The frame and the tray are SVG rectangles with a stretched feTurbulence for the wood grain; the tray's front lip sits above the objects, so whatever falls lands inside it.

Values to change

NameFileDefaultWhat it changes
PHRASESscript.js['Fresh coffee all day', 'Lemon cake, baked today']The phrases written on the board, one after another: the eraser wipes each one and the chalk writes the next. Letters, numbers and the signs . , ' ! ? : - & / ( ).
SKETCHscript.jstrueThe sketch under every phrase: a cup of coffee, then a lemon (with false only the phrase stays, bigger).
WRITE_SPEEDscript.js1How fast the chalk writes: 2 is twice as fast, 0.5 half as fast.
BREAKscript.jstrueWhether the chalk snaps halfway through the first phrase.
DUSTscript.js1How much chalk dust falls from the tip and puffs from the eraser (0 = none).
HAZEscript.js1How much white haze the eraser leaves (0 = a clean board, 2 = the writing stays easy to read under the new one).
RESTscript.js1.8How many seconds the finished phrase stays on the board before the eraser comes.

Try them in the Playground

When to use it

To open the page of a bar, a café, a bakery or a restaurant with its daily menu, a school, a course or a bookshop; for a message that changes, like the dish of the day or the opening hours; for a post or a story with a handmade touch.

On phones

The same animation with the sizes adapted: the phrase wraps onto two or three lines to stay big, the sketch gets smaller, and the chalk, the eraser and the tray are sized on the short side of the screen. A tap sends the eraser.

With reduced motion

Nothing moves: the chalk and the eraser stay in the tray, the phrase and the sketch fade in already written, then fade out leaving the haze and the next phrase fades in; at the end the haze fades too.

Pitfalls

  • With the Hershey letters as they are, the dot of the i came before the letter, because in the original drawing it is the first stroke: dots and bars move to the end of the word.
  • The letters are polylines on a grid of whole units: scaled up, their corners showed. Three passes of Chaikin round them off without moving the start and the end, so the letters stay joined.
  • An eraser moving in jumps (the video is recorded at 30 frames a second) left stripes of chalk between one position and the next: it wipes in short steps along the whole path covered in the frame.
  • The broken piece could land on top of the lying chalk or on the eraser: the simulation is run once and then the whole path is shifted little by little, along a soft curve, so it stops in the free spot of the tray.
  • The canvas blur filter is missing in Safari: the blurred haze is made by shrinking the writing to a sixth and scaling it up again.
  • An SVG gradient colour written as an attribute (stop-color="var(--chalk)") does not read CSS variables: it goes in style.

Libraries

GSAP 3.15.0, Familjen Grotesk (font variabile) 5.3.0.

Compressed with gzip, the three demo files weigh 20 KB; the libraries: GSAP 28 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