Skip to content
animorio
IT
All components

The cube calendar

Calendars, 3D, Physics, TransitionsGSAP, CSS onlyAdvancedCompressed weight: Demo 18 KBGSAP 28 KBFreeDownload the zip

A picker for a furniture delivery day: the chosen date stands on a little desk at the top, with two oak cubes for the day and a drum for the month, like a perpetual calendar. Choosing a day the cubes are lifted, turned over in the air and, when needed, swap places (the 6 is also the 9); changing month the weeks roll under a wooden tile that keeps the same day.

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 cube calendar</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/gantari@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- a delivery day picker. The chosen date stands on a little desk at the top, set with two oak day cubes and a
         month drum on its stand, like a perpetual desk calendar; below, the weeks are one long strip that rolls under
         a wooden tile. The cubes, the drum and the weeks are drawn by the script -->
    <div class="picker" data-picker>
      <div class="picker__top">
        <div class="desk" aria-hidden="true" data-desk></div>
        <div class="picker__arrows">
          <button class="arrow" type="button" aria-label="Previous month" data-prev><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 14.5l6-6 6 6"/></svg></button>
          <button class="arrow" type="button" aria-label="Next month" data-next><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 9.5l6 6 6-6"/></svg></button>
        </div>
      </div>

      <p class="sr" id="cube-calendar-month" data-month-name></p>
      <div class="cal" role="grid" aria-labelledby="cube-calendar-month" data-grid>
        <div class="cal__week" role="row" data-week></div>
        <div class="cal__window" data-window>
          <div class="cal__strip" role="rowgroup" data-strip></div>
          <div class="tile" aria-hidden="true" data-tile>
            <span class="tile__shadow" data-tile-shadow></span>
            <span class="tile__face"><span class="tile__copy" data-copy></span></span>
          </div>
        </div>
      </div>

      <div class="picker__foot">
        <p class="picker__done" data-done><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5" data-check/></svg><span data-done-text></span></p>
        <button class="book" type="button" data-book>
          <span class="book__label" data-book-label>Book delivery</span>
          <span class="book__date" data-book-date></span>
          <svg class="book__spin" viewBox="0 0 24 24" aria-hidden="true" data-spin><path d="M12 4a8 8 0 0 1 8 8"/></svg>
        </button>
      </div>
      <p class="sr" role="status" aria-live="polite" data-said></p>
    </div>
  </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.

27 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 calendar” from Animorio and fit it into my site

What it does

On a white background a card 360 pixels wide to choose the day a piece of furniture arrives. At the top, as on a desk seen a little from above, the chosen date is made of objects: two oak cubes with the figures burnt into the wood for the day and, next to them, an oak drum on a walnut stand for the month and the year; on the right two arrows, up and down. Below are the initials of the days, from Monday, and six weeks: the days of the month are in full ink, those of the months either side only hinted at. Today has a thin frame; past days, the two days needed to get a delivery ready, Sundays (no deliveries) and days more than four months ahead are grey, and the ones already fully booked are hatched as well. The chosen day sits under an oak tile with its number burnt into the wood. Pressing a day the tile glides there, and the days it passes over show burnt into the wood for a moment; meanwhile the cubes that have to change are lifted, turned over in the air to the right figure and put down, landing on an edge and rocking before they stop. Two cubes are enough for every day from 01 to 31 only because the 6 is also the 9, upside down: so sometimes the cubes swap places, the one going left hopping in front of the other. The arrows, or dragging the weeks or the drum up and down, change month: the weeks roll like a strip of paper, the drum turns with them as if the two were geared together, and the tile keeps the same day of the month, or the nearest free one, gliding to its new weekday while the weeks pass under it. At the bottom Book delivery, with the date; pressed it says Booking with a spinner, then it becomes a Change button while on the left a tick is drawn with Booked for and the date, the weeks fade and the cubes hop. When the page opens the cubes fall onto the desk turning and the drum rolls round to the month.

How it works

The cubes and the drum

Each cube is a CSS 3D box with six faces, drawn twice as big and shrunk with scale(0.5), so that in Chrome the figures stay sharp. The first cube has 0 1 2 3 4 5, the second 0 1 2 6 7 8, and the 6 turned upside down makes the 9. For each day the left cube shows the tens if it has them, otherwise the two cubes swap places: 13 needs the second cube on the left, 31 the first one. The month drum has four long faces round an axle, between two walnut posts, and turns 90 degrees a month: the writing on a face is changed while the face is at the back, and only the face coming to the front shows it.

Turned over in the air

A cube's orientation is a quaternion. The turn that brings the right face to the front, with its normal towards you and its up pointing up (down for the 9), is written as a matrix and becomes the quaternion to reach. GSAP lifts the cube by LIFT pixels in 0.2 seconds, turns it with a slerp from the quaternion it has now to the new one in TURN seconds (power2.inOut), drops it with bounce.out and rocks it on an edge with elastic.out. Lifted, a cube moves a little away from its neighbour, because turned on an edge it is wider than its place. Swapping, the cube going left hops and passes in front, the other slides behind, and as long as the two overlap one is kept in front and the other behind anyway. Stopped halfway, a cube starts again from the orientation and the place it is in.

The light

On every frame the normal of each face goes through the same matrix as the cube and through its rocking; its product with the direction of the light, from the top left and a little in front, says how dark the face gets: LIGHT times what it lacks of the full light. The drum does the same with its four faces. The shadows on the desk are soft ellipses lying on the plane, which widen and fade as the cube is lifted. Everything is tilted by TILT degrees, so the tops of the cubes show.

The weeks

The weeks are a single strip, from before the first bookable month to after the last one. Everything hangs on one number, the month with its fraction, pulled by a spring (ROLL): the strip sits between the first week of a month and that of the next one in proportion to the fraction, the drum turns 90 degrees a month, and every day is in full ink in its own month and fades towards the others. Dragging the weeks, or the drum, the number follows the finger, with some give past the first and the last month; let go, the push carries it on by a month or two.

The tile

The oak tile on the chosen day has its own spring (GLIDE). Changing month, the chosen day becomes the same day of the new month, or the nearest free one, and the tile glides there while the weeks pass under it; while dragging it stays still. Inside it is a copy of the strip with dark numbers, moved by the opposite of the tile: the days passing under it look burnt into the wood.

Keyboard and booking

The grid has role grid, the rows outside the window are inert and a single day takes the Tab key: the arrows move between the days, Home and End go to the start and the end of the week, Page Up and Page Down change month, and the chosen day follows the focus when it can be chosen. The days that can't be chosen have aria-disabled and the reason in their name, and the new month is announced. Book delivery says Booking, then shrinks into Change while a tick is drawn on its left.

Values to change

NameFileDefaultWhat it changes
WEEK_STARTscript.js1The first day of the week: 1 Monday, 0 Sunday.
LEADscript.js2The days it takes to get a delivery ready: the first day that can be chosen is today plus these.
HORIZONscript.js120How many days ahead a delivery can be booked.
CLOSEDscript.js[0]The days of the week with no deliveries: 0 Sunday, 1 Monday, up to 6 Saturday.
FULLscript.js6About one day in this many is already fully booked (made up from the date).
TURNscript.js0.62The seconds a cube takes to be turned over in the air.
LIFTscript.js18How many pixels a cube is lifted to be turned.
ROLLscript.js[120, 18]The spring of the weeks and of the month drum: stiffness and damping.
GLIDEscript.js[300, 30]The spring of the wooden tile on the chosen day: stiffness and damping.
TILTscript.js16How much from above the desk is seen, in degrees.
LIGHTscript.js0.42How much darker the wood gets on a face turned away from the light.

Try them in the Playground

When to use it

To choose the day of a delivery, a pickup or an appointment when the brand has something handmade about it: a furniture shop, a joinery, a stationer's, a coffee roaster. The fully booked days should come from your own system instead of the made-up ones. For a stay, with arrival and departure, there is the booking calendar.

On phones

The card is 360 pixels wide, or the screen minus the margins: at 390 pixels it is 358 wide and everything fits, cubes, drum and arrows included; on a narrower screen the desk shrinks by itself to leave room for the arrows. Taps choose the days; dragging the weeks or the drum up and down changes month, with a fling. touch-action none is only there: outside them the page scrolls. The tint under the pointer is not there on a phone.

With reduced motion

The cubes are not lifted and not turned: they fade and come back already on the right figure. The weeks and the drum change month with a fade, the tile appears on the new day with a fade, the days that can't be chosen don't shake and when the page opens everything is already in place. Dragging, the weeks follow the finger, but let go they go straight to the month.

Pitfalls

  • In Chrome the text on the 3D faces came out grainy: the content of a 3D face is drawn at a low density. The faces are drawn twice as big (K) and shrunk with scale(1/K), and every measure of the wood grows with --k: the figures stay sharp even on a screen of density 3.
  • The tile's shadow, made with a box-shadow, left a white strip under it when it moved: a box-shadow is not drawn under its own box, and the shadow's box moved down stayed empty. Now the shadow is a dark box blurred with filter: blur.
  • The button shrinking into Change, with a fixed width inside a flex, widened the line and with it the page, which spilled sideways. The stage is now a flex that doesn't grow with its content, and while shrinking the button can only give way (flex 0 1 auto), never push.
  • The drum, seen a little from above, showed the month before on its top face: SEP over OCT, hard to read. The writing on each face now fades as the face turns away from the front, and is changed only while the face is at the back.
  • Two cubes turning together, side by side, went through each other: turned on an edge a cube is up to 1.4 times as wide as its side. Lifted, they now move a little apart (and the left cube has some room before the edge of the card); and if a new choice stops a swap halfway, as long as they overlap one is kept in front and the other behind.
  • On a 375 pixel phone the top row didn't fit and the arrows stuck out of the card: the desk is measured and shrunk with a transform scale, with its vanishing point fixed in pixels at the middle of the cubes and the drum.

Libraries

GSAP 3.15.0, Gantari (font variabile) 5.3.0.

Compressed with gzip, the three demo files weigh 18 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