Skip to content
animorio
IT
All components

The reading dial

Navigation, SVG, Scroll, TextGSAP, CSS onlyAdvancedCompressed weight: Demo 11 KBGSAP 28 KBFreeDownload the zip

The chapter index of a long read, made as a dial. Under the text a thin bar says which chapter you are in and how many minutes are left; at its right a small dial with its rim cut into one arc per chapter, as long as the chapter, and a blue hand that turns as you read. Opened, the dial rises out of the bar over the page on a spring, with the chapters' names set along their arcs: the hand can be taken and turned, and the article runs under it, clicking onto the start of every chapter; a name glides you there.

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 reading dial</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/newsreader@5.3.0/opsz.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/newsreader@5.3.0/opsz-italic.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the chapter index of a long read, as a dial. Under the article a thin bar says which chapter you are in and how
         many minutes are left; at its right a small dial whose rim is cut into one arc per chapter, as long as the
         chapter, with a hand that turns as you read. Opened, the dial rises over the page with the chapters' names
         set along their arcs: the hand can be dragged round to run through the article, and a name takes you there.
         The article is only there to be read and scrolled -->
    <section class="reader" aria-label="Fire, slowly" data-reader>
      <article class="text" tabindex="0" data-text>
        <p class="kicker">A long read · Ceramics</p>
        <h1 class="title">Fire, slowly</h1>
        <p class="lede">A week inside a small pottery by the river, from a block of wet clay to the morning the kiln is opened.</p>

        <h2 id="ch-clay" data-chapter="Clay">Clay</h2>
        <p>The clay arrives on a Monday, in grey blocks wrapped in plastic, heavier than they look. Before anything else it has to be wedged: pressed, folded and turned on a slab of plaster until every pocket of air is gone and the block feels the same all the way through. It is slow, dull work, and nobody in the studio skips it.</p>
        <p>An air bubble left in the clay will not show for days. It waits through the shaping and the drying, and then, in the heat of the kiln, it swells and splits the pot open from the inside. So the wedging goes on until the cut face of the block is smooth and even, like the inside of a loaf.</p>
        <p>By noon there are twenty balls of clay on the shelf, each one weighed, each one the size of a large orange. They will be bowls by the evening.</p>

        <h2 id="ch-wheel" data-chapter="The wheel">The wheel</h2>
        <p>Throwing starts with centring. The ball is slapped onto the middle of the wheel, the wheel spins, and wet hands push the clay up into a cone and down again until it runs true, without the slightest wobble against the palm. A pot that starts off centre will stay off centre whatever happens next.</p>
        <p>Then the thumbs go in, the floor of the bowl is opened, and the walls are drawn up in three or four slow pulls, each one thinner and taller. The trick is to stop a pull early. A wall pulled one time too many goes soft, folds over on itself, and the whole thing goes back into the bucket.</p>
        <p>Every finished bowl is cut off the wheel with a wire and set on a board to rest. Twenty go up; seventeen are kept.</p>

        <h2 id="ch-drying" data-chapter="Drying">Drying</h2>
        <p>For two days the bowls dry under loose sheets of plastic, so that the rims, which are thin, do not dry faster than the feet, which are thick. When they are firm enough to hold but still soft enough to cut, they are turned upside down on the wheel and trimmed: a sharp loop of steel takes the extra clay off the base and carves the foot ring.</p>
        <p>Then the plastic comes off. The grey turns pale, almost white, and the bowls shrink as they lose their water, about a tenth of their size. They are as fragile now as they will ever be; a careless thumb on a rim is enough to crack it.</p>

        <h2 id="ch-kiln" data-chapter="The kiln">The kiln</h2>
        <p>The first firing is gentle and goes on overnight, up to the heat at which clay stops being clay and becomes something that will never soften in water again. After it the bowls are pink and ring when they are tapped. They are dipped in glaze, a grey slurry that looks nothing like the colour it will turn into, and wiped clean at the foot so they will not stick to the shelves.</p>
        <p>The second firing is the one everybody waits for. The kiln is packed with care, shelf by shelf, the bowls a finger apart, and the door is bricked up. For fourteen hours the temperature climbs, checked every half hour, until the cones of clay set on a shelf behind a spy hole bend over and tell the potters that the heat has done its work.</p>
        <p>Then the burners go off and nothing can be done but wait. A kiln cooled too fast will craze every glaze inside it.</p>

        <h2 id="ch-opening" data-chapter="Opening">Opening</h2>
        <p>Two days later the bricks come out of the door one by one. The air inside is still warm. The grey glaze has turned into a deep celadon green, pooling darker in the hollows and thinning to a pale edge at every rim, and there is the small, glassy sound of glazes still cooling, a tick here and there like a clock.</p>
        <p>Not every bowl makes it. One has a crack along its foot, one has stuck to its neighbour, one has a glaze that ran too far. The rest are lifted out, turned over in the light, and set in a line on the long table by the window, where they will wait for the market on Saturday.</p>
        <p>The studio sweeps the kiln, orders more clay, and on Monday it all begins again.</p>
      </article>

      <div class="veil" aria-hidden="true" data-veil></div>

      <!-- the dial: drawn by the script in one SVG over the reader, from the small one in the bar to the big one -->
      <svg class="dial" aria-hidden="true" data-dial>
        <defs>
          <filter id="dial-lift" x="-30%" y="-30%" width="160%" height="160%">
            <feDropShadow dx="0" dy="10" stdDeviation="14" flood-color="#141414" flood-opacity="0.16"/>
          </filter>
        </defs>
        <circle class="dial__face" filter="url(#dial-lift)" data-face/>
        <g data-tracks></g>
        <g data-reads></g>
        <g class="dial__names" data-names></g>
        <g class="dial__hand" data-hand>
          <line class="dial__needle" data-needle/>
          <circle class="dial__pin" data-pin/>
        </g>
        <text class="dial__now" text-anchor="middle" data-now-big></text>
        <text class="dial__left" text-anchor="middle" data-left-big></text>
      </svg>

      <div class="chapters" id="reader-chapters" role="group" aria-label="Chapters" data-chapters></div>
      <div class="grip" aria-hidden="true" data-grip></div>

      <button class="bar" type="button" aria-expanded="false" aria-controls="reader-chapters" data-bar data-autoclic>
        <span class="bar__words">
          <span class="bar__now-box"><span class="bar__now" data-now>Clay</span></span>
          <span class="bar__left" data-left>5 min left</span>
        </span>
        <span class="bar__dial" data-slot></span>
      </button>
    </section>
  </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.

38 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 reading dial” from Animorio and fit it into my site

What it does

On a white background a white pane 600 pixels wide and 470 tall, with a grey hairline round it: above, a long read about a small pottery, Fire, slowly, with five chapters (Clay, The wheel, Drying, The kiln, Opening); below, a bar 64 tall with the chapter's name in italics, the minutes left and on the right a little dial. Its rim is cut into five grey arcs, each as long as its chapter: the part already read is black, that of the chapter you are in cobalt blue, and a blue hand from the middle to the rim marks the place. Scrolling the article the hand turns on a spring and when the chapter changes the name in the bar rolls out upwards and the new one rolls in from below with a little bounce; the minutes go down. Tapping the bar the text is veiled in white and the dial rises from the corner and grows on a spring to 264 pixels, going a touch too far, with a soft shadow: the chapters' names appear one after the other along their arcs, the bottom ones turned to read upright, the hand draws back to a short stroke across the rim and in the middle sit the chapter's name and the minutes left. The hand can be taken with a finger or the mouse and turned: the article scrolls under it and near the start of a chapter the hand clicks onto it. Tapping a name the article glides to its chapter and the dial goes back into the bar. From the keyboard Enter opens the dial and puts the focus on the chapter you are in, the arrows move from name to name with an outline turned along the rim, Esc closes.

How it works

The arcs from the headings

At start and whenever the sizes change the script reads where the chapters' headings are in the article. Each chapter's arc is its share of the text's height, in degrees; the scroll at which it starts is the heading's position less 24 pixels, rounded down to a whole pixel (the browser rounds the scroll and, half a pixel too far, the end of a glide landed in the chapter before). Inside a chapter the angle goes with the scroll in a straight line, and the same function the other way round turns an angle into a scroll.

One dial, from small to big

The small dial in the bar and the big one over the page are the same drawing in one SVG over the pane. A spring (OPEN_SPRING) takes a value from 0 to 1, a touch past and back, and every frame the middle, the rim's radius (16 to 92), the arcs' thickness, the white face with its shadow and the hand all come from it. The space between the arcs is in pixels (GAP), so in degrees it changes with the radius.

The names along the rim

Every name is a textPath centred on a 150 degree arc round the middle of its chapter. For the chapters in the bottom half the path runs the other way and a little further out, so the letters are never upside down. Over every name lies a real button, turned along the rim like it, that takes you to the chapter and shows the keyboard focus.

The hand, on a spring and by hand

The article's scroll says where the hand should be; it gets there on a spring (HAND_SPRING), in steps of 1/120 of a second. Taken on the open dial, the pointer's angle from the middle becomes the article's scroll, with no spring; the hand does not jump from the end to the start across the top, and within SNAP degrees of a chapter's start it clicks onto it.

The minutes and the name in the bar

Every chapter's words are counted once; the minutes left are the words of the rest of the chapter, in proportion to the angle, plus those of the chapters after, divided by WORDS_A_MINUTE. When the chapter changes the name in the bar rolls out of its little window and the new one rolls in with a back.out, in a timeline that, if cut short, the next one replaces without leaving the old name behind.

Values to change

NameFileDefaultWhat it changes
OPEN_SPRINGscript.js[200, 19]The spring the dial opens and closes on: how stiff, and how much it is held back (less, further it overshoots).
HAND_SPRINGscript.js[260, 26]The spring the hand follows the reading on.
DIAL_SIZEscript.js264How wide the open dial is, in pixels.
GAPscript.js6The gap between two chapters on the rim, in pixels.
SNAPscript.js5How close to a chapter's start, in degrees, the hand turned by hand clicks onto it.
WORDS_A_MINUTEscript.js230How many words the reader reads in a minute: the minutes left come from it.

Try them in the Playground

When to use it

For a long read split into chapters: a blog, a magazine, a story, a guide, a product's documentation. It works with three to seven chapters with short names; the chapters are read from the headings with data-chapter, so it is enough to put that attribute on the headings of your own text. Colours and type are in the variables.

On phones

On a phone the pane is as wide as the screen less 32 pixels (358 at 390) and stays 470 tall; the text takes the whole width. The open dial is 264 wide and sits inside the pane, over the veiled text. The hand turns with a finger (the dial has touch-action: none, so the page does not scroll while it is held) and a name is tapped.

With reduced motion

The dial does not grow and the hand has no spring: opening, the big dial appears already in place in a short fade, and the hand follows the scroll without delay. A name takes you to its chapter at once, with the article fading back in; the name in the bar changes in a fade, without rolling.

Pitfalls

  • After the glide to The kiln the bar still said Drying: the chapter started at 1393.4 pixels, the browser rounded the scroll to 1393 and the hand stayed a hair short. Now the chapters' starts are whole pixels and the comparison has three tenths of a degree to spare.
  • With the hand running from the middle to the rim in the big dial too, it passed over the chapter's name written in the middle. Opening, it now draws back to a short stroke across the rim.
  • Changing chapter quickly the name in the bar stayed the old one: the second animation killed the first before it wrote the new name. Now the way out, the change and the way in are one timeline, and the change always writes the latest chapter.
  • A straight focus outline over a name written along the rim cut across the arc. Now the buttons are turned like the name and as wide as it.
  • Opening from the keyboard with reduced motion the focus did not reach the chapters, which were still hidden: now they become visible before they take the focus.

Libraries

GSAP 3.15.0, Newsreader (font variabile) 5.3.0.

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

Testing

Tested on 19 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 components