Skip to content
animorio
IT
Back to the library

The word made of smoke

Text, HoverGSAP, CanvasMediumCompressed weight: Demo 10.0 KBGSAP 28 KBFreeDownload the zip

A minimal-style animation: a large word made of threads of incense smoke, bone white on a warm black. The smoke rises from below and gathers into the word, the threads breathe and now and then one peels away and curls upwards; the pointer is a draught that carries the smoke off, and the word slowly gathers itself back.

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>Linger</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/fraunces@5.3.0/full.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <!-- a word made of incense smoke on a warm black: thin wisps hold the letters, some peel off and rise, the pointer
       is a draught that blows the smoke into curls, and the word slowly gathers itself back -->
  <main class="pagina" data-pagina>
    <canvas class="tela" aria-hidden="true" data-tela></canvas>

    <header class="testa">
      <p class="marchio" data-entra>Linger</p>
      <p class="testa__nota" data-entra>Incense &amp; slow fragrance</p>
    </header>

    <h1 class="parola" data-parola>Linger</h1>

    <footer class="piede">
      <p class="nota" data-entra data-nota>Move to stir the smoke, click to blow</p>
      <p class="aria" data-entra><span class="aria__nome">Air</span> <span class="aria__valore" data-aria>still</span><span class="aria__riga" data-riga></span></p>
    </footer>
  </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.

20 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 word made of smoke” from Animorio and fit it into my site

What it does

A warm black page with a few small words in Fraunces: top left the name of an invented incense house, Linger, on the right ‘Incense & slow fragrance’, bottom left an invitation to stir the smoke and on the right a reading of the air. At the start the smoke rises from the bottom of the page in thin bone-white threads, curling as it goes, and gathers into the word ‘Linger’ from left to right: light at first, in the thinnest weight of the typeface, then thickening to the full weight. Once the word is complete the smoke never stands still: every thread breathes a little around its place in a slow field of swirls, and now and then one peels away from its letter, rises bending and fades out, then goes back to its place and slowly lights up again. The pointer is a draught: wherever it passes it carries the smoke in its direction and curls it at the sides, stronger and wider the faster it runs; the threads carried off slow down, spin and go back to the letter, soft at first and then firm. If the pointer rests over a letter, the warmth of the hand makes more smoke rise from there. A click or a tap is a breath: the whole word scatters into wisps and gathers itself back. Bottom right, the air reads ‘still’ when it is calm and the metres per second, in vermilion, when it moves, with a thin line that stretches.

How it works

The word twice, in the hidden canvas

The word is written in a canvas as big as the page, never shown, twice: in the full weight (WEIGHT) and in the thin one (THIN), at the same size, which fits it into 74% of the width (86% on a phone) and 36% of the height. getImageData gives the filled pixels, and a grid with the right step, nudged a little at random, gives about COUNT points per word. The points are sorted from left to right, so the i-th thread of the thin word and of the full one sit close together and the smoke moves only a little as it thickens.

Curl noise

A smooth value noise on a grid, with a fixed permutation, and its curl: the noise’s derivatives swapped round with one sign flipped. It is a velocity field with no sources, which turns the smoke in swirls instead of pushing it all one way; it drifts slowly upwards over time, so it looks like rising smoke.

Three modes for every thread

On the letter, a spring pulls the thread towards its home, shifted a couple of pixels by the curl: the word breathes. Peeled away, it rises with the heat (a steady push upwards), curls in the field and fades out over 1.8 to 3.4 seconds, then reappears unlit at its place and lights up again. Carried off by the air, it is free and damped; when its time runs out the spring takes it back with a grip that grows from zero, soft at first and then firm. About 2% of the threads peel away every second (RISE), many more near a resting hand.

The draught and the breath

The pointer’s damped speed gives the strength and the radius of the draught (REACH, wider when it runs): inside the radius every thread gets the pointer’s velocity and a sideways push that curls it around the pass; if the hit is strong the thread leaves its letter. The click gives every thread a push away from the point, slightly turned, and a different return time. When nobody moves the pointer for 2.4 seconds, a fake draught passes over the word in a figure of eight that lasts nine seconds.

Drawing with trails

On every frame a veil of black covers the canvas, lighter the higher TRAIL is, and every thread is drawn as a thin stroke from its previous position to the current one, adding up the light (lighter): where there are many threads the smoke is denser. The threads are split into five groups by brightness, so five draws per frame are enough. GSAP directs the show (the arrival, the thickening) and its clock also drives the physics.

Values to change

NameFileDefaultWhat it changes
WORDscript.js'Linger'The word made of smoke: short, it fits on one line.
COUNTscript.js2800How many threads of smoke (a little over half on a phone).
WEIGHTscript.js560The weight of the word once the smoke has thickened (Fraunces goes from 100 to 900).
THINscript.js240The weight of the word when the smoke arrives.
DRAUGHTscript.js1How hard the pointer’s draught blows (0 it does not).
REACHscript.js120How far the draught reaches, in px: wider when the pointer runs.
RISEscript.js1How many threads peel away and rise (0 none).
SWIRLscript.js1How much the loose threads curl.
TRAILscript.js0.8How long the trails last: higher means longer trails.
ARRIVALscript.js3How many seconds the smoke takes to gather into the word.

Try them in the Playground

When to use it

As the opening of a perfumery, an incense and candle house, a cocktail bar or a tea room, a theatre or a film; anywhere a single word should feel suspended in the air and react to the hand.

On phones

The same with a finger: dragging moves the air, tapping blows. The word fits 86% of the width, there are a little over half the threads, slightly thinner, and the draught is a little narrower. Over the demo the finger moves the smoke instead of scrolling the page.

With reduced motion

The word of smoke is already built and still, in the full weight, and fades in; the pointer and the click move nothing and the air stays ‘still’.

Pitfalls

  • The thin word and the full one must be measured at the same weight, or they come out at different sizes and the smoke slides sideways as it thickens.
  • Without sorting the points from left to right, every thread would cross from one letter to another as the word thickens: a tangle of threads instead of smoke getting denser.
  • A peeled thread that comes back must be put back unlit and lit slowly: put back lit, the word flickers in specks.
  • The trails come from the veil of black, not from the strokes’ transparency: the veil has to be worked out from the frame time, or at 120 Hz the trails are half as long.

Libraries

GSAP 3.15.0, Fraunces (font variabile) 5.3.0.

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