Skip to content
animorio
IT
All components

The shape rating

Ratings, SVG, Physics, HoverGSAPAdvancedCompressed weight: Demo 11 KBGSAP 28 KBFreeDownload the zip

Five shapes instead of stars, from a burst of spikes for the worst mark to a flower for the best: the coloured shape runs to the one pointed at and turns into it on the way, its outline a ring of springs that stretches and wobbles, printed in three layers like a risograph that slip out of register as it moves. Once picked, every shape answers in its own way: the flower shuts into a bud and blooms again, the burst bristles and shivers.

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 shape rating</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/recursive@5.3.0/casl.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the rating: five shapes from a spiky burst to a flower, over five real radio buttons. The coloured shape runs
         to the one pointed at and turns into it on the way, its three printed layers a little out of step; picked,
         it opens out for a good mark and flinches for a bad one. The shapes are drawn by the script -->
    <form class="mood" data-mood onsubmit="return false">
      <p class="mood__ask" id="mood-ask">How was today’s class?</p>
      <fieldset class="mood__row" aria-labelledby="mood-ask" data-row data-autoclic>
        <svg class="mood__art" aria-hidden="true" data-art>
          <g class="mood__marks" data-marks></g>
          <g class="mood__shape" data-shape>
            <path class="mood__print" data-print/>
            <path class="mood__print" data-print/>
            <path class="mood__print" data-print/>
          </g>
        </svg>
        <div class="mood__choices" data-choices></div>
      </fieldset>
      <p class="mood__word" aria-hidden="true"><span data-word>Pick one</span></p>
      <p class="mood__thanks" role="status" aria-live="polite" data-thanks></p>
    </form>
  </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.

25 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 shape rating” from Animorio and fit it into my site

What it does

On a white background the question How was today’s class?, under it a row of five small pale shapes, each a greyish wash of its own ink, and lower down, in grey, Pick one. The shapes go from bad to good: a burst of eleven crooked spikes, a lumpy drop sagging towards the bottom, a square with soft corners, a cloud of eight scallops and a flower of six petals. When the page opens they pop up one after the other with a bounce. Moving the pointer over them, a coloured shape twice as big grows out of the pale one and runs to the one pointed at on a spring, leaning a little towards the pointer; on the way it turns into the new shape, stretches along its run and, once there, wobbles before it stops. It is printed in three layers of the same ink, the lightest underneath and two darker ones over it, multiplied where they overlap: on the move the darker layers fall behind and slip out of register, each with the shape and colour of the spot where it is. The ink goes from the violet of the burst to blue, teal, green and the orange of the flower. The pale shapes shrink as it passes and spring back up. Below reads the word for that choice, Rough, Not great, Fine, Good or Loved it, in the shape’s colour: straight and heavy for the low marks, softer and brushy for the high ones. Leaving, the shape goes back to the choice made, or closes into a pale shape if there is none yet. On a pick, every shape answers in its own way: the flower shuts into a round bud and blooms again with its petals turning and hopping, the cloud puffs up, the square turns a quarter and clicks into place, the drop sags and drops a little, the burst bristles and shivers. Below appears Thanks, your teacher will see this., and at every change of mind Changed to followed by the new choice. A finger can slide along the shapes, and the choice falls where it lifts.

How it works

Shapes over real radio buttons

Under the shapes there are real radio buttons, see-through, one per column: the arrows change the choice, Tab goes in and out of the group, screen readers read the question (the fieldset’s aria-labelledby) and the word of each choice (aria-label), and the form sends the value. The drawing is an SVG the script redraws, and the line underneath, in a role="status", says the choice made.

Five shapes as radii

Every shape is a radius for every direction, from 0.6 to 1: the burst is an 11-turn cosine raised to 2.2 (narrow spikes, wide valleys) with a 3-turn unevenness, the drop a sum of cosines lower at the top, the square a superellipse of degree 4, the cloud |cos 4a| raised to 0.6, the flower |cos 3a| raised to 0.7. They are worked out once in 132 directions for each of the three prints (the middle one smaller and turned by half a lobe); between two shapes the radius is mixed with a smoothstep, so every point of the row has a shape of its own.

An outline of springs

Each of the 132 points of the outline is a spring along its radius towards the radius the shape asks for (JELLY), and pulls its two neighbours by the difference between their errors, so a wave runs along the edge. The springs run on GSAP’s ticker in steps of 1/240 of a second; the shape stretches along its run by STRETCH times its speed, and when it stops the springs make it wobble. Once nothing moves, the ticker is removed and nothing is redrawn.

Three prints out of register

The three prints run on three springs, each softer than the one before (LAG): each takes the shape and the ink of the point of the row where it is itself, so on the move the dark prints fall behind with the shape they had. The first is solid, the other two are in mix-blend-mode multiply inside an isolated group: where they overlap the ink deepens, as in a risograph. The inks are mixed in OKLCh, lightness, colourfulness and hue on their own, the hue the shorter way round.

The answer to every mark

On a pick, a GSAP timeline for each print, 45 milliseconds apart, moves four settings of the outline: how far the lobes stand out from the middle radius (amp), the size, a squash and a turn. The flower goes to amp 0 (a round bud) and comes back with elastic.out while the springs jump; the cloud puffs up; the square starts a quarter turned and comes back with back.out, looking the same; the drop squashes and sinks; the burst draws out its spikes and gets a random speed on every point, and shivers.

The word, fingers and the preview

The word is set in Recursive: the CASL axis goes from 0 to 1 and the weight from 760 to 640 with the mark, read from the middle print at every frame, and its colour is the shape’s ink with the lightness kept under 0.58 so it reads. A finger slides sideways along the shapes and the choice falls where it lifts; the click that may follow is cancelled, so the radio the finger started on does not win. A click from a script (detail 0, the library’s preview) is a pretend hand and picks in turn a flower, a drop, a cloud, a burst and the square.

Values to change

NameFileDefaultWhat it changes
LABELSscript.js['Rough', 'Not great', 'Fine', 'Good', 'Loved it']The word for each choice, from the worst to the best (and how many choices there are: the shapes share out the way from the burst to the flower).
STARTscript.js0The choice when the page opens (0 = none).
MOVEscript.js[230, 0.62]The spring that carries the shape: how stiff it is and how much it is held back.
LAGscript.js0.3How far behind the two dark prints follow the light one (0 = all together).
JELLYscript.js[700, 0.2]The outline’s springs: how stiff they are and how much they are held back (held back less, they wobble longer).
STRETCHscript.js0.0008How much the shape stretches with its speed.
PULLscript.js0.3How far the shape leans from its place towards the pointer (0 = not at all, 1 = it follows it).
BLOOMscript.js1How strong the answer to a pick is: the flower that shuts and blooms again, the burst that bristles, the drop that sags.

Try them in the Playground

When to use it

To ask how a lesson, a course, a workshop, an appointment or a delivery went, for the mood diary of a wellbeing app, for the question at the end of a session: wherever you ask for a mark from one to five but stars would be too cold, or too much like a review.

On phones

The row is 310 pixels wide, 62 per choice, and narrows with the screen if there are more choices. A finger slides sideways along the shapes and the choice falls where it lifts; up and down the page still scrolls (touch-action: pan-y). A tap picks straight away.

With reduced motion

No run and no springs: the shape is in its place at once, with its shape and colour, and the prints stay in register. On a pick it fades in; the word changes in a fade without rising or blurring, and the pale shapes do not move.

Pitfalls

  • Mixing green and orange in a straight line, even in OKLab, gave a dull olive halfway: mixing lightness, colourfulness and hue on their own (OKLCh, the hue the shorter way round) goes through a clean yellow.
  • The prints in multiply also multiplied the pale shape underneath, which showed as a dark stain inside the coloured shape: the prints sit in a group with isolation: isolate and the first one is solid and normal, so it covers the pale shapes.
  • The dark prints, grown together with the light one, made a small coloured dot in the middle of the pale shape at the first instant: now they come in only once the light one has grown by a quarter.
  • The pale shapes making room for the shape passing by, shrunk until they vanished, turned into little dots beside it: now they stop at half their size, which does not show under the shape.
  • Sliding a finger, the finger always starts on a radio button: if a click came after the slide, that radio won over the choice made by sliding. The click after a slide is cancelled (preventDefault on a radio puts back the state before), and a mouse button pressed on the shapes and let go outside picks nothing.
  • With BLOOM above 1 the bud took the flower’s lobes past the middle radius and the petals turned inside out: amp does not go below 0.
  • The word in the shape’s ink as it is could not be read on white for green and orange: the ink’s lightness is kept under 0.58 in OKLab, without touching the hue.

Libraries

GSAP 3.15.0, Recursive (font variabile) 5.3.0.

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

Testing

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