Skip to content
animorio
IT
All components

The cube stories

Stories, 3D, TransitionsGSAPAdvancedCompressed weight: Demo 7.4 KBGSAP 28 KBFreeDownload the zip

A bakery’s stories, one after another: the bars at the top fill, a tap on the right goes on and one on the left goes back, turning the stories like the faces of a cube, holding pauses and hides everything but the story, and closing, the story shrinks into its avatar’s circle.

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 stories</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/league-spartan@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the stories: the bars fill one after another, a tap goes on or back turning the stories like the faces of a
         cube, holding pauses and hides everything but the story, and closing shrinks it into its circle -->
    <section class="stories" aria-label="Stories from Forno Lupo" data-stories data-autoclic>
      <div class="viewer" tabindex="0" aria-roledescription="stories" aria-describedby="stories-help" data-viewer>
        <div class="viewer__stage" data-stage></div>
        <div class="viewer__chrome" data-chrome>
          <div class="viewer__bars" aria-hidden="true" data-bars></div>
          <div class="viewer__head">
            <span class="viewer__avatar" aria-hidden="true">FL</span>
            <span class="viewer__name">Forno Lupo</span>
            <span class="viewer__time">2 h</span>
            <button class="viewer__close" type="button" aria-label="Close the stories" data-close>
              <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6.5 6.5l11 11M17.5 6.5l-11 11"/></svg>
            </button>
          </div>
        </div>
        <p class="sr" id="stories-help">Arrows to go on or back, space to pause, Escape to close.</p>
      </div>
      <button class="ring" type="button" aria-label="Watch the stories from Forno Lupo again" hidden data-ring>
        <span class="ring__avatar" aria-hidden="true">FL</span>
        <span class="ring__name">Forno Lupo</span>
      </button>
      <p class="sr" aria-live="polite" data-live></p>
    </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.

34 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 cube stories” from Animorio and fit it into my site

What it does

On a white background a story in a phone’s proportions: at the top four thin bars, the FL circle, Forno Lupo, 2 h and a cross; under them, the first story, yellow, with a loaf rising from below, three threads of steam and the words Out of the oven at 7 rising one after another. The story’s bar fills in five seconds, then it moves on to the next: Today: rye and fennel (green, with ears of wheat that grow and sway), Sold out by 11 (red, with the hands going round), Sunday we rest (blue, with the moon rising and a cloud passing). A tap on the left third goes back, anywhere else on: the stories turn like the faces of a cube, and the one going away darkens. Holding, the story stops and the bars and the head disappear; dragging it down the story comes down and shrinks, and let go low enough it closes. Closing (with the cross too, or when the stories are over) the story becomes a square, then a circle, and flies shrinking into the avatar’s circle with Forno Lupo under it; the circle opens it again, growing it back.

How it works

The bars

Every story has a bar, filled by a scaleX tween from 0 to 1 in DURATION seconds with no ease (time runs evenly); at the end the tween moves on to the next story, and after the last the stories close. Going on or back, the bars before are full and those after empty.

The cube

The two stories turn round the cube’s axis, half a width behind them (transformOrigin with a negative third coordinate): the one leaving from 0 to −90 degrees and the one arriving from 90 to 0, in TURN seconds with power2.inOut, with the DEPTH perspective on the container and backface-visibility hidden; a black veil on the one leaving darkens it.

Every story moves

Every story has its own timeline that starts again when it shows: the words rise one after another and the drawing plays its part (the loaf rises with back.out and the steam goes up and down, the ears grow and sway, the hands turn for the whole story, the moon rises and floats). Pausing stops it too.

Holding, dragging, closing

A press lasting more than HOLD seconds pauses, and letting go it goes on; a drag down moves and shrinks the story, which closes past 70 pixels. Closing, a clip-path (numbers on a separate object) cuts it to a square and rounds it into the circle, while x, y and scale take it onto the avatar’s circle, measured as it stands in the page, without the drag going on.

Keys and the preview

The stories are reached with Tab: the arrows go on and back, space pauses, Escape closes and takes the focus to the circle, which opens them again with Enter; an aria-live region says which story it is at. A click from a script (the library’s preview) is a pretend thumb: it goes on, holds a story, goes back, closes the stories into the circle and opens them again.

Values to change

NameFileDefaultWhat it changes
DURATIONscript.js5The seconds each story stays.
TURNscript.js0.65The seconds the cube takes to turn to another story.
HOLDscript.js0.22The seconds a press must last to pause instead of going on.
DEPTHscript.js900The perspective, in pixels: the smaller, the deeper the cube.
STORIESscript.js[['Out of the oven at 7', 'Every morning, every loaf', 'loaf', '#f4b450', '#3a1e05'], …]The stories: words, smaller words, drawing (loaf, wheat, clock, moon), background and the words’ colour.

Try them in the Playground

When to use it

For the news of a shop or a restaurant, the moments of an event, the day’s offers, the steps of a recipe, a product’s introduction, told in a few screens.

On phones

The stories take the screen’s height less a margin; they are tapped, held and dragged down with a finger without the page scrolling (touch-action none), and the long press does not open the system’s menu.

With reduced motion

The stories change at once, without the cube, and the drawings and words stay still; the bars still fill, because they tell how long is left, and closing or opening happens without the circle shrinking or growing.

Pitfalls

  • A constant called chrome at the top level of a classic script clashes, in Chrome, with window.chrome (elsewhere it does not): the script fails only there. Here it is called overlay.
  • Words put in inline-block spans lose the space at the start of each span: the spaces go outside, between one span and the next.
  • A real cube turns round its middle, not round an edge: transformOrigin with depth (50% 50% and minus half the width) turns the two faces together, without gaps.
  • Closing during a drag, the story is already moved and shrunk: its place must be measured taking the drag off, or it would land far from the circle.
  • A from() in a timeline takes as its end the values of the moment it is made: the name under the circle, just hidden, would have stayed hidden. It needs a fromTo with immediateRender false.

Libraries

GSAP 3.15.0, League Spartan (font variabile) 5.3.0.

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

Testing

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