Skip to content
animorio
IT
All components

The hotel floors menu

Menus, SVG, Physics, HoverGSAP, CSS onlyAdvancedCompressed weight: Demo 9.5 KBGSAP 28 KBFreeDownload the zip

The menu of a small hotel as the hotel itself, in isometric, like an architect’s exploded view: the floors fall one on the other from the spa to the bar on the roof, and pointing at one the floors above lift on their springs and open it like a drawer, with the pool, the reception, the tables, the beds inside.

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 hotel floors menu</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>
  <main class="stage">
    <!-- the menu of a small hotel as its own building, drawn in isometric like an architect's exploded view: one
         slab for each floor, from the spa underground to the bar on the roof. Pointing at a floor, the floors above
         it lift on their springs and show what is inside; the floor you are on is the one left open -->
    <div class="hotel" data-frame>
      <button class="call" type="button" aria-expanded="false" aria-controls="hotel-menu" data-toggle data-autoclic>
        <svg class="call__icon" viewBox="0 0 24 24" aria-hidden="true">
          <path data-icon-floor d="M12 15.5 20 19.5 12 23.5 4 19.5Z"/>
          <path data-icon-floor d="M12 9.5 20 13.5 12 17.5 4 13.5Z"/>
          <path data-icon-floor d="M12 3.5 20 7.5 12 11.5 4 7.5Z"/>
        </svg>
        <span class="call__words" aria-hidden="true">
          <span class="call__word" data-word-open>Menu</span>
          <span class="call__word" data-word-close>Close</span>
        </span>
        <span class="sr" data-toggle-name>Open the menu</span>
      </button>

      <div class="card" id="hotel-menu" data-card inert>
        <svg class="building" viewBox="0 0 360 372" aria-hidden="true" data-building></svg>
        <nav class="floors" aria-label="Hotel">
          <ul class="floors__list">
            <li><a class="floor" href="#rooftop" data-floor="4"><span class="floor__name">Rooftop bar</span><span class="floor__note">Open until late</span></a></li>
            <li><a class="floor" href="#rooms" data-floor="3"><span class="floor__name">Rooms &amp; suites</span><span class="floor__note">Sea and garden views</span></a></li>
            <li><a class="floor" href="#restaurant" data-floor="2"><span class="floor__name">Restaurant</span><span class="floor__note">Breakfast to dinner</span></a></li>
            <li><a class="floor" href="#lobby" data-floor="1" aria-current="page"><span class="floor__name">Lobby</span><span class="floor__note">Check-in and lounge</span></a></li>
            <li><a class="floor" href="#spa" data-floor="0"><span class="floor__name">Spa</span><span class="floor__note">Pool and sauna</span></a></li>
          </ul>
        </nav>
      </div>
    </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.

31 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 hotel floors menu” from Animorio and fit it into my site

What it does

On a white page there is a petrol blue button with «Menu» and three little floors drawn in it, which part a little under the pointer. Pressed, the button goes up and a cream card opens below it: the floors of the hotel fall from above one after the other, the spa underground, the lobby, the restaurant, the rooms and the bar on the roof, each landing on the one below with a small bounce, and from each a hairline runs to its name, with a line under it. The floor you are on stays open: the ones above it are lifted, and inside you see its plan drawn in hairlines, with its lights on and its lines blue, and beside it «You are here». Pointing at another name, or at the floor itself, the floors above it lift on their springs and those that were lifted come down and settle, with their shadow darkening as they get closer. Choosing a floor, it sinks a hair as if stepped on and the menu closes: the floors fly away from the roof down and the button goes back to the middle. It also closes with Esc, with the button or by pressing outside.

How it works

A slab of three faces

Every floor is an svg group with three polygons: the floor, the side in the light and the side in the shade, worked out with the isometric projection (the plan’s x and y become (x − y)·cos 30° and (x + y)·sin 30°, the height goes straight up). Thickness SLAB, air between one floor and the next GAP. To move a floor, its group is just moved up or down.

The plan with one matrix

What is inside a floor (pool, reception, tables, beds, umbrellas) is drawn flat, in its own coordinates, and laid on the floor with one matrix, matrix(cos30, sin30, −cos30, sin30, …): the isometry itself. The stroke has vector-effect: non-scaling-stroke, so it stays a hairline even squashed by the matrix.

A spring for every floor

Every floor has its own spring (SPRING: stiffness and damping) taking it to its height: the resting one, plus PART if the open floor is below it. They are worked out from the ground up, three steps a frame, and a floor cannot go through the one below: it touches it and bounces back with LAND of its speed. When the menu opens the floors start high up, unseen, and are let go one every STAGGER seconds.

Shadows and lines

On the floor of every slab lies the shadow of the one above, a polygon blurred with an feGaussianBlur: the closer the floor above, the darker; the farther, the more it shifts and fades. Every frame the hairline starts at the corner of the floor, wherever it is, and reaches its name, which stays still in its column.

Real links

The names are links in a nav, placed over the drawing in percentages and with type in container units (cqw), so they grow and shrink with the drawing. The mouse on a name or on a floor opens that floor, leaving the card the floor you are on opens again; from the keyboard the arrows go from floor to floor, Enter chooses, Esc closes and the focus goes back to the button.

Values to change

NameFileDefaultWhat it changes
PARTscript.js66How far the floors above lift to show the one pointed at, in pixels of the drawing.
GAPscript.js9The air between one floor and the next while they rest.
SPRINGscript.js[240, 17]The floors’ springs: how stiff, and how much they are held back.
LANDscript.js0.32How much a floor bounces back when it lands on the one below (0 dead, 1 rubber).
STAGGERscript.js0.11The seconds between one floor landing and the next, opening.
SLABscript.js13The thickness of a floor, in pixels of the drawing.

Try them in the Playground

When to use it

For the site of a hotel, a hostel, a spa or a building with different things on each floor (a museum, a coworking space, a department store): the menu also tells how the place is made. It works with four, five or six links, one for each floor.

On phones

The card narrows to the width of the screen and the drawing shrinks together with the names. Without a pointer the floor you are on stays open; a tap on a name or on a floor chooses it.

With reduced motion

No falling floors and no springs: the card fades in with the hotel already standing, and pointing at a floor the ones above go at once to their height. Lights, colours and lines change as always.

Pitfalls

  • GSAP takes an array as a list of targets: a tween on an array of numbers does not animate them. So the values of each floor live in its own object, not in a separate array.
  • With a spring, a floor that lands goes past its place and into the one below: that is why they are worked out from the ground up and each one stops on the one before, bouncing, instead of going through it.
  • The plan’s stroke, inside the isometric matrix, got thicker one way than the other: vector-effect: non-scaling-stroke keeps it the same hairline everywhere.
  • The mouse left where the button was, when the button goes up, ends up over the roof and opens it at once: that is right, but for the preview the opening of the demo tour is done by the script.
  • The words «You are here» put in the grid over the line pushed the line onto a second row: now they are absolutely positioned over the line, which turns transparent.

Libraries

GSAP 3.15.0, Instrument Sans (font variabile) 5.3.0.

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