Skip to content
animorio
IT
Back to the library

The metro network

SVG, HoverGSAPAdvancedCompressed weight: Demo 14 KBGSAP 28 KBFreeDownload the zip

The metro map of a made-up city that draws itself: each line is laid by its first train, the stations open as circles with a bounce, then the trains run their service. Over a station, the quickest way to the venue draws itself over the faded map while the panel counts the minutes and the changes.

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 metro network</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/instrument-sans@5.3.0/standard.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage" data-stage>
    <!-- the side: the title, the journey planner and the names of the lines -->
    <aside class="side">
      <header class="head">
        <p class="head__city" data-rise>Port Ardena Metro</p>
        <h1 class="head__title" data-rise>Getting to <span data-dest>Harbour Hall</span></h1>
        <p class="head__hint" data-rise>
          <span class="hint--mouse">Point at any station to see the quickest way there.</span>
          <span class="hint--touch">Tap any station to see the quickest way there.</span>
        </p>
      </header>

      <!-- the planner: written by the script for the station chosen -->
      <section class="trip" aria-live="polite" data-trip>
        <p class="trip__idle" data-idle>Every line, every change, the fewest minutes.</p>
      </section>

      <!-- the lines: their names on their colours, as on the station walls -->
      <ul class="legend" data-legend aria-label="Lines"></ul>
    </aside>

    <!-- the map: river, parks, lines, stations and trains, all drawn by the script from the data at the top of it -->
    <div class="map" data-map>
      <svg class="map__art" data-art role="img" aria-label="Map of the Port Ardena metro"></svg>
    </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.

26 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 metro network” from Animorio and fit it into my site

What it does

A paper-coloured page for getting to an event, Harbour Hall, in the made-up city of Port Ardena: on the left the title, the journey panel and the names of the four lines on pills in their colours (red Crown, blue Tide, green Orchard, yellow Quay); on the right the map, with straight and 45 degree lines as on real ones. On opening the river Arden runs in from the left and the two parks grow with a small bounce. Then, one after the other, the lines draw themselves: each is laid by its first train, a carriage in the line's colour with its windows, which runs at the head of the track and pulls it along behind. When the line reaches a station, the station opens as a white circle with an elastic bounce and its name slides out on its side; an interchange the track reaches a second time gives a jolt. Last comes Harbour Hall, an ink circle with a white heart and its name on a black tag, with a bigger bounce. From then on the trains run their service: two to a line, end to end, slowing before each station, stopping and setting off again. With the pointer near a station, the map fades, the starting station swells and the quickest way to Harbour Hall draws itself on top, stretch by stretch in the colours of the lines, the stations jolting as the drawing reaches them and the destination bouncing when it arrives. In the panel the name of the start rises, the minutes count up to the total and the rides appear, with the name of the line, the stops and the changes. The route stays until you move onto another station; a click away from the stations (or Esc) clears it. Over the names of the lines, only that line stays in colour.

How it works

The network as data

At the top of the script sit the stations (name, place on a 1000 by 640 grid, side of the name) and the lines, each with its stations in order and the bends as pairs of numbers in between. Everything else is built from there: the tracks, the interchanges (the stations on more than one line), the graph for the planner. On a tall screen the map is turned over its diagonal (x and y swap): it is still a true 45 degree map, the sides of the names turn with it and a few stations have a side of their own for the phone.

The rounded bends

Each line is a single path: a straight stretch up to a little before each bend and a quadratic curve with its control point on the corner. The stations are never on a bend, so the distance of each station along the line is measured with getTotalLength on a piece of path that ends there. The same method draws the pieces of the route, which therefore match the lines underneath exactly.

The train that lays the line

The line draws itself with stroke-dasharray and stroke-dashoffset, driven by a number that goes from zero to the length with power1.inOut; the same number puts the first train in the right place with getPointAtLength and turns it along the line by looking at a point just before and one just after. The moment the drawing reaches a station is found by inverting the easing (a halving search on its value), so the circle opens just as the line touches it.

The train service

Each train has a timeline that repeats forever: from one station to the next with power2.inOut (it slows before it stops), a pause, the next one, to the end of the line and back. The train that laid the line starts again from the point of its timeline where it reaches the end of the line, so it does not jump; the others start a fraction of the round apart and pop out with back.out.

The quickest way

The graph has a node for every pair of station and line: a ride costs its minutes (the length divided by the speed, plus half a minute at the stop), a change costs CHANGE_MINUTES. Dijkstra finds the shortest way and splits it into rides on the same line. Each ride becomes two paths, a paper-coloured edge and the coloured line, drawn one after the other in a paused timeline whose progress is driven by a tween with power2.inOut. The pointer picks the nearest station within SNAP map units, converting its coordinates with getScreenCTM.

Values to change

NameFileDefaultWhat it changes
DESTINATIONscript.js'Harbour Hall'The station every route leads to: write the name of any station on the map. It gets the black tag and goes into the title too.
DRAW_TIMEscript.js2.4The seconds the whole map takes to draw itself when the page opens.
TRAINSscript.js2How many trains run on each line (0 = none, the lines draw themselves).
TRAIN_SPEEDscript.js1How fast the trains run between the stations: 2 is twice as fast.
DWELLscript.js0.7The seconds a train waits at each station.
CHANGE_MINUTESscript.js4How many minutes a change of line costs: the higher it is, the more the route prefers to stay on one line even when it is longer.
BOUNCEscript.js1How much the stations bounce when they open and when the route reaches them (0 = no bounce).
SNAPscript.js60How close to a station the pointer has to come to pick it, in map units.

Try them in the Playground

When to use it

To explain how to get somewhere with a drawing that explains itself: the getting-there page of a festival, a concert, a fair or a city hotel, the map of a campus or a park, the network of a delivery service. It also works for any diagram made of nodes and links, such as a study path or the steps of a product.

On phones

The same animation with the sizes adapted: on the tall screen the map turns over its diagonal and stands upright, the names are larger in proportion, the title and the lines sit above and the journey panel below, on one line. Tap a station to see the route, tap away from the stations to clear it.

With reduced motion

Nothing travels: the river, the parks, the lines and the stations fade in, the trains stand still halfway between two stations. The chosen route fades in whole, without bounces, and the minutes are already written.

Pitfalls

  • The route drawn over the line did not match it in the bends: the pieces of the route must be built with the same rounded-corner function and from the same points as the whole line, and the stations must never sit on a bend.
  • The stations opened before or after the line passed, because the drawing has an easing: the right moment is found by inverting the easing with a halving search, not with the share of the distance.
  • The train that laid the line jumped at the end of the line when the service began: its timeline starts from the end label, the point where it reaches the last station, and the other trains are offset from there.
  • Jumping into the middle of a timeline made of to() tweens, the trains started from the wrong place (the starting value is read only on the first pass): every stretch is a fromTo.
  • The route vanished when the pointer went off to read the panel, because it crossed the map far from the stations: the route stays until the next station and is cleared with a click or Esc.
  • On the phone the wide map became tiny: turned over its diagonal it fills the tall screen, the size of the names is worked out from the real scale, and the viewBox is taken from the box of lines, stations and names, so no name gets cut off.
  • With reduced motion the trains standing on the stations covered the circles: they stand halfway between two stations.

Libraries

GSAP 3.15.0, Instrument Sans (font variabile) 5.3.0.

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

Testing

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