Skip to content
animorio
IT
Back to the library

Places on the tilted map

Hover, SVG, 3DGSAP, CSS onlyMediumCompressed weight: Demo 6.0 KBGSAP 28 KBFreeDownload the zip

What is around a residence, in the minimal style: on the left the places, large; on the right a street map in thin lines, laid down in perspective. Pointing at a place its name rolls into italics, on the map a soft light glides there and its marker stands up.

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>Places on the tilted map</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/fraunces@5.3.0/full.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/fraunces@5.3.0/full-italic.css">
  <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>
  <!-- what is around a made-up residence, Linden Court. On the left the places, large; on the right a street map in
       thin lines, laid down in perspective. Pointing at a place, its name rolls into italics, a hairline slides under
       it, and on the map a soft light moves to it and its marker stands up -->
  <main class="intorno" data-intorno>
    <section class="elenco">
      <p class="occhiello">What’s around</p>
      <ul class="luoghi" data-luoghi>
        <li><button type="button" data-luogo="0"><span class="nome"><span>Central Station</span><span class="corsivo" aria-hidden="true">Central Station</span></span><span class="tempo">6 min by bike</span></button></li>
        <li><button type="button" data-luogo="1"><span class="nome"><span>Riverside School</span><span class="corsivo" aria-hidden="true">Riverside School</span></span><span class="tempo">4 min on foot</span></button></li>
        <li><button type="button" data-luogo="2"><span class="nome"><span>West Market</span><span class="corsivo" aria-hidden="true">West Market</span></span><span class="tempo">9 min on foot</span></button></li>
        <li><button type="button" data-luogo="3"><span class="nome"><span>Harbour Park</span><span class="corsivo" aria-hidden="true">Harbour Park</span></span><span class="tempo">3 min on foot</span></button></li>
        <li><button type="button" data-luogo="4"><span class="nome"><span>Old Mill Hall</span><span class="corsivo" aria-hidden="true">Old Mill Hall</span></span><span class="tempo">12 min by tram</span></button></li>
        <li><button type="button" data-luogo="5"><span class="nome"><span>City Airport</span><span class="corsivo" aria-hidden="true">City Airport</span></span><span class="tempo">20 min by car</span></button></li>
      </ul>
      <span class="filo" data-filo aria-hidden="true"></span>
    </section>

    <div class="mappa" aria-hidden="true">
      <div class="piano" data-piano>
        <svg class="strade" viewBox="0 0 100 100" data-strade>
          <defs>
            <radialGradient id="luce">
              <stop offset="0" stop-color="#fff" />
              <stop offset="0.55" stop-color="#fff" stop-opacity="0.6" />
              <stop offset="1" stop-color="#fff" stop-opacity="0" />
            </radialGradient>
            <mask id="faro" maskUnits="userSpaceOnUse" x="-10" y="-10" width="120" height="120">
              <circle data-faro cx="50" cy="50" r="0" fill="url(#luce)" />
            </mask>
          </defs>
          <g class="strade__tenui" data-tenui></g>
          <g class="strade__accese" mask="url(#faro)" data-accese></g>
        </svg>
        <div class="casa" data-casa style="--x: 47%; --y: 52%"><span class="casa__blocco"></span><span class="segno">Linden Court</span></div>
      </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.

33 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 “Places on the tilted map” from Animorio and fit it into my site

What it does

The surroundings page of Linden Court, a made-up residence. On the left six places, the station, the school, the market, the park, a hall, the airport, written large in a light serif; on the right a map of thin streets, a river and the home, a small gold block, laid back and turned, as if seen from a roof. Pointing at a place (or reaching it with the Tab key) its name rises and the same word in italics, darker, comes up from below in its place; a thin line slides to it and the time to get there appears. On the map a soft light glides to the place: under the light the streets turn dark, and the place’s marker, a gold stem with its name, stands up with a small spring. The whole map leans a little towards the pointer. If nobody points at anything, the places light up by themselves one after the other.

How it works

The map in perspective

The map is an SVG inside a CSS plane: the container has the perspective, the plane has transform-style: preserve-3d and turns with rotateX(TILT) and rotateZ(TURN). The streets are a single path made of avenues, short random streets and a river, faded at the edges with a radial mask.

The light

The streets are drawn twice: pale underneath, dark on top. The dark group has an SVG mask with a radial gradient circle: GSAP moves the circle’s centre to the place and widens its radius to LIGHT, so the streets darken only there, as under a torch.

Markers that stand up

Each marker sits in the plane, at its position, but its content has the inverse turn of the plane, rotateZ(-TURN) and then rotateX(-TILT): so it stands upright again in front of the viewer. The stem of the active place grows with back.out a little after the light; the others stay low.

The rolling name

Each name has its italic copy in the same grid cell, with hidden overflow. Pointing at it, the upright one rises by a hundred per cent and the italic comes up from below, in 0.6 seconds with power3.out; the thin line moves to the item in BAR_TIME seconds, 80 per cent of the row tall, as on the site. The lean towards the pointer chases the mouse by FOLLOW every frame.

Values to change

NameFileDefaultWhat it changes
TILTscript.js58How far the map lies back, in degrees.
TURNscript.js38How far it is turned, in degrees.
LEANscript.js[2, 3]How many degrees it leans towards the pointer, up-down and sideways.
FOLLOWscript.js0.08How quickly it follows the pointer, every frame.
LIGHTscript.js24How big the light on the map is.
BAR_TIMEscript.js0.3How long the line takes to slide to a place, in seconds.
AUTOscript.js2.4The seconds between one place and the next when nobody points; 0 to stay still.

Try them in the Playground

When to use it

For the surroundings page of a residence, a hotel, a holiday home, a restaurant or an event in town: the places nearby, how long it takes, where they are. The map can be the real one, drawn in lines.

On phones

The same, with the map on top and the places below, smaller; you tap a place with a finger.

With reduced motion

The map does not lean towards the pointer, the name turns to italics with a fade instead of rolling, the light and the line jump straight to the place.

Pitfalls

  • The mask that fades the edges goes on the streets’ SVG, not on the plane: a mask (like overflow or filter) on the plane flattens it, and the markers would stay lying down.
  • To stand a marker back up the order of the inverse turns matters: first rotateZ(-TURN), then rotateX(-TILT). The other way round it stays crooked.
  • The light must be a mask over a second copy of the streets: changing the colour of each street near the place would be jumpy and cost much more.
  • Each item is a button, so it can be reached with the Tab key and focus does the same as the pointer.

Libraries

GSAP 3.15.0, Fraunces (font variabile) 5.3.0, Instrument Sans (font variabile) 5.3.0.

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

Testing

Tested on 17 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 animations