Skip to content
animorio
IT
Back to the library

Symbols under the cursor

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

A big headline whose letters, near a cursor, turn for a moment into the symbols of a comic-strip curse, each in a colour of its own, and turn back into letters once the cursor has gone. The symbol is picked among those almost as wide as the letter, and the letters next door slide instead of jumping. Two cursors with name tags share the page: yours, and a colleague’s that wanders by itself.

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>Symbols under the cursor</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/instrument-sans@5.3.0/wdth.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <header class="bar">
    <a class="brand" href="#"><span class="brand__mark" aria-hidden="true"></span>Redline</a>
    <nav class="bar__nav" aria-label="Sections">
      <a href="#">Product</a>
      <a href="#">Pricing</a>
      <a href="#">Changelog</a>
    </nav>
    <a class="bar__login" href="#">Log in</a>
  </header>

  <main class="hero">
    <!-- the headline: the script splits it into letters; near a cursor they turn into symbols for a moment -->
    <h1 class="title" data-scramble>Edit together,<br>swear less.</h1>
    <p class="lead">Comments, suggestions and tracked changes for teams who write. Your cursor and theirs, on the same page.</p>
    <div class="actions">
      <a class="btn" href="#">Start a draft</a>
      <a class="btn btn--ghost" href="#">See it live</a>
    </div>
  </main>

  <!-- the two cursors: yours follows the mouse, the colleague's wanders over the page -->
  <div class="cursor" data-cursor="you" aria-hidden="true">
    <div class="cursor__body" data-body>
      <svg class="cursor__arrow" viewBox="0 0 24 28"><path d="M3 2.5 21 15.6l-7.7 1.1 4.6 8.4-3.3 1.8-4.6-8.4L3.6 23.7z"/></svg>
      <span class="cursor__chip">You</span>
    </div>
  </div>
  <div class="cursor cursor--mate" data-cursor="mate" aria-hidden="true">
    <div class="cursor__body" data-body>
      <svg class="cursor__arrow" viewBox="0 0 24 28"><path d="M3 2.5 21 15.6l-7.7 1.1 4.6 8.4-3.3 1.8-4.6-8.4L3.6 23.7z"/></svg>
      <span class="cursor__chip" data-mate-name>Mara</span>
    </div>
  </div>

  <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.

36 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 “Symbols under the cursor” from Animorio and fit it into my site

What it does

The home page of an invented app for writing and editing text together, Redline: at the top the brand with a red stroke and three links, in the middle the huge headline “Edit together, swear less.”, below it a line and two buttons. The mouse cursor is drawn by the page: an arrow with a “You” tag, which leans when it runs sideways and rises a little when it goes fast. A second, orange cursor tagged “Mara” comes in from the right and runs over the headline in a figure of eight. When a cursor comes near the letters, those around it, in an oval wider than tall, turn into coloured !@#$%^&*>< symbols, purple, blue, yellow, orange, green, never the same colour twice in a row; each symbol hops into place from a little below. The letters do not all change at once: each waits a few random milliseconds. Every sixteen pixels the cursor travels, the symbols change again, and the letters left behind turn back. The symbol picked is almost always about as wide as the letter, so the line barely moves; when, about one time in five, a wider or narrower one comes along, the letters after it slide sideways instead of jumping.

How it works

Letters in boxes

The headline is split into words, which never break in the middle, and into letters: each letter is a box with the glyph inside. The box is there to slide, the glyph to hop. The headline keeps its whole text in aria-label, for whoever listens to it.

Symbols of the same width

Once the font has loaded, the script measures on a canvas, at 100 pixels, the width of every letter and every symbol, and lines up for each letter the symbols from the most similar to the most different. Usually it draws one among the six closest, weighted 1/(1 + difference); with probability WILD it takes one further away, up to 60 pixels of difference, and then the most different weigh most.

The oval around the cursor

Every frame the centre of every letter is measured. A cursor starts the game if it is inside the REACH oval of at least one letter, in letter heights; then every letter inside the bigger SPREAD oval changes. Each one books its change for between 0 and SWAP milliseconds later, and those that leave the oval turn back between 0 and RESTORE. Every REROLL pixels the cursor travels, the symbols are shuffled again. Two letters side by side never get the same colour or the same symbol.

No jumps

When a symbol is wider than its letter, everything after it moves. The script reads every letter’s offsetLeft every frame: if it has changed, the letter takes an equal and opposite offset and wins back a DRIFT share of it each frame. So on screen the letters slide to where they have to go.

The two cursors

Your cursor and the colleague’s are two fixed elements moved with a transform. Each leans with its sideways speed and rises with its overall speed, on a spring: stiffness 0.16 and damping 0.8 every sixtieth of a second, with speed counting up to 28 pixels a frame. The colleague runs a figure of eight over the headline in LAP seconds, and the cursor is like yours: it changes letters too.

Values to change

NameFileDefaultWhat it changes
SYMBOLSscript.js!@#$%^&*><The symbols the letters turn into.
COLORSscript.js#744cf6, #3fa9f5, #e0a91f, #ff5004, #6fa52fThe symbols’ colours; two letters side by side never share one.
REACHscript.js0.6, 0.55How close a cursor must come to a letter for the game to start, in letter heights: sideways, and up or down.
SPREADscript.js1.7, 1.3How far around the cursor the letters change, in letter heights: sideways, and up or down.
REROLLscript.js16The pixels a cursor travels before the symbols change again.
SWAPscript.js70The longest wait before a letter changes, in milliseconds.
RESTOREscript.js150And before it turns back into a letter.
HOPscript.js0.09How far below the line a new symbol starts before hopping into place, in letter heights.
WILDscript.js0.22The chance of a symbol much wider or narrower than the letter.
DRIFTscript.js0.24How much of their way the letters moved by a wide symbol win back every frame.
TILTscript.js7.2How far a cursor leans when it runs sideways, in degrees; a little more over the headline.
LIFTscript.js1.9How far a fast cursor rises, in pixels.
MATEscript.jsMaraThe name of the colleague who wanders over the headline; empty, nobody is there.
LAPscript.js13The seconds the colleague takes for one lap.

Try them in the Playground

When to use it

For the opening headline of a site that has to do with writing, play or working together: an app, a studio, a magazine. It wants a short, big headline, two lines at most, and a solid sans serif in which the symbols do not look like a mistake. On a long text meant to be read it would get in the way.

On phones

There is no cursor of yours, because there is no mouse: the game is played by the colleague’s cursor, which wanders over the headline on its own, and by a finger on the headline, while it stays down. The headline drops to 46-72 pixels.

With reduced motion

There is no colleague and the cursors do not lean. The letters near your cursor still change, but without hopping or sliding: glyph and colour change in place.

Pitfalls

  • The symbols’ widths must be measured with the font loaded: before document.fonts.ready the canvas measures a fallback font and the symbol lists come out wrong. Until the font is there, symbols are drawn at random.
  • The neighbours’ shift is worked out from offsetLeft, which ignores transforms, not from getBoundingClientRect, which would include the shift being worked off and double it.
  • A letter’s centre is read from its box minus the shift under way, or while it slides it goes in and out of the oval and flickers.
  • A canvas does not know font-stretch at 92%: the widths are measured at 100%. The differences between letter and symbol stay almost the same, and that is all that counts.

Libraries

GSAP 3.15.0, Instrument Sans (font variabile) 5.3.0.

Compressed with gzip, the three demo files weigh 6.8 KB; the libraries: GSAP 28 KB.

Testing

Tested on 2 October 2026

  • Desktop: Done
  • Phone: Done
  • Reduced motion: Done
  • Safari on iPhone: Done

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