Skip to content
animorio
IT
Back to the library

A year of daylight

SVG, HoverGSAP, CSS onlyMediumCompressed weight: Demo 10.0 KBGSAP 28 KBFreeDownload the zip

A year's hours of daylight in a ring of 365 hairlines, one a day, each as long as the day: a vermilion hand reads the day under the pointer, the number in the middle counts on the same spring and the year is inked up to the hand; choosing another city every day springs to its new length, in a wave that starts at the hand. Minimal style.

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>A year of daylight</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/archivo@5.3.0/wdth.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <!-- a year of daylight drawn as a ring: one hairline a day, as long as the hours of light of that day. A vermilion
       hand reads the day under the pointer, the big number counts on a spring, the year is inked up to the hand, and
       choosing another city every day springs to its new length in a wave that runs round from the hand -->
  <main class="stage" data-stage>
    <header class="top">
      <span class="top__name">Almanac</span>
      <span class="top__note">Hours of daylight, day by day</span>
    </header>

    <div class="dial" role="slider" tabindex="0" aria-label="Day of the year" aria-valuemin="1" aria-valuemax="365" data-dial>
      <svg class="dial__svg" viewBox="-500 -500 1000 1000" aria-hidden="true">
        <path class="guide guide--base" data-guide="0"></path>
        <path class="guide guide--half" data-guide="12"></path>
        <path class="guide guide--full" data-guide="24"></path>
        <path class="guide guide--months" data-month-ticks></path>
        <path class="days days--future" data-future></path>
        <path class="days days--past" data-past></path>
        <path class="hand" data-hand></path>
      </svg>
      <span class="scale scale--half" aria-hidden="true">12 h</span>
      <span class="scale scale--full" aria-hidden="true">24 h</span>
      <div class="months" aria-hidden="true" data-months></div>
      <div class="read" aria-hidden="true">
        <span class="read__date" data-date>June 21</span>
        <span class="read__value" data-value>
          <span class="read__num" data-hours>15</span><span class="read__unit">h</span>
          <span class="read__num" data-minutes>12</span><span class="read__unit">m</span>
        </span>
      </div>
    </div>

    <nav class="cities" aria-label="City" data-cities>
      <span class="cities__mark" aria-hidden="true" data-mark></span>
      <button type="button" class="city" data-city="oslo" data-autoclic>Oslo</button>
      <button type="button" class="city" data-city="rome" data-autoclic>Rome</button>
      <button type="button" class="city" data-city="quito" data-autoclic>Quito</button>
      <button type="button" class="city" data-city="ushuaia" data-autoclic>Ushuaia</button>
    </nav>

    <p class="hint">Move around the year</p>
  </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.

32 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 “A year of daylight” from Animorio and fit it into my site

What it does

On warm white paper, at the top the name of a made-up almanac, Almanac, and on the right Hours of daylight, day by day. In the middle a ring: out of the inner circle come 365 hairlines, one per day, from the first of January at the top and then clockwise, each as long as that day's hours of light in the chosen city (worked out from the sun, not typed in). Outside, a dashed circle for twelve hours and a thin one for twenty-four, with the months' ticks and their names; in the seam at the top, between the last day and the first, the scale: 12 h and 24 h. In the middle the date and a big number, 15 h 14 m. Below, four cities: Oslo, Rome, Quito and Ushuaia, with a vermilion mark over the chosen one. When the page opens the circles draw themselves, the vermilion hand springs out of the inner circle and goes once round the year: the days are born behind it, each on a spring that goes a hair too far and comes back, the months appear as it passes them, the number counts, and the hand goes on to the 21st of June, the longest day. Then, moving over the ring, the hand follows the pointer on a spring and stops on the day; the days already gone are black and those to come are pale, so the year fills up to the hand, and the days next to it lean out a little while it runs. The number reads the hairline under the hand: it counts with it, turns narrow and thin while it runs (Archivo's width and weight axes) and wide and heavy again when it lands. Choosing another city the mark slides over the name on an elastic, the name takes on weight, and every day springs to its new length one after another, in a wave that starts at the hand and runs round both ways: Oslo swells into a very long summer, Quito closes into an almost perfect circle, Ushuaia turns the year upside down with summer in December. When nobody points, after a moment the hand walks round the year by itself. The arrow keys move a day, Page Up and Page Down a month, Home and End go to the first and the last day.

How it works

Hours of light from the sun

No tables typed by hand: for each day the sun's declination comes from Spencer's series, then the hour angle at which the sun's edge touches the horizon, cos ω = (sin(−0.833°) − sin φ sin δ) / (cos φ cos δ), with φ the city's latitude. The hours of light are 2ω/15. The −0.833 degrees account for the sun's radius and for the air bending the light; beyond the polar circle the cosine leaves −1…1 and the day is worth 0 or 24 hours.

A ring of hairlines in two paths

The SVG has a viewBox of 1000 with the centre in the middle: each day is a segment that starts at the inner circle (radius 200) and is its hours times 10.5 units long, so 24 hours reach the outer circle. The days do not close the ring: at the top a 10 degree seam is left for the scale. All the days gone sit in one black path and those to come in one pale path, rewritten every frame; vector-effect: non-scaling-stroke keeps the lines one pixel wide at any size.

A spring for each day

Each day has its length and its speed, integrated by hand on GSAP's ticker (DAY_SPRING, with the step capped at 1/30 of a second). Changing city the new length does not arrive at once: each day gets it after SPREAD seconds times its distance from the hand, divided by half a year, so the wave starts at the hand and the far side of the year changes last. The days near the hand also have a second spring, the lean, which grows with the hand's speed (LEAN).

The hand and the number on the same spring

From the pointer comes the angle round the centre with atan2, turned into the day, seam included; the hand goes there on HAND_SPRING the shortest way, never taking the long way round across New Year. The number has no spring of its own: between the two days the hand stands on, it reads their length at that moment, so it counts while the hand runs and goes a hair over when the line under it springs. Archivo's width and weight follow how fast it changes (WIDTH, WEIGHT).

The opening, the cities and the hands

A GSAP timeline draws the circles (arcs rewritten every frame), then takes the hand round a year and a half, to the 21st of June: a day is born when the hand passes it and the months appear with a small bounce. The cities are buttons with aria-pressed and data-autoclic; the vermilion mark slides on elastic.out and ducks while it runs. The mouse drives the hand on the ring and a little round it, a finger while it drags; the ring is a role=slider with the arrow keys. After 2.4 seconds with nobody there the hand walks by itself.

Values to change

NameFileDefaultWhat it changes
SPREADscript.js0.8How many seconds the change of city takes to run round the year from the hand.
DAY_SPRINGscript.js[230, 17]Each day's spring when its length changes: how stiff, and how much it is held back (less hold, more bounce).
HAND_SPRINGscript.js[160, 17]The hand's spring: how stiff, and how much it is held back.
LEANscript.js16How far the days next to the hand lean out while it runs (the ring is 1000 wide).
WIDTHscript.js[100, 66]The width of the number at rest and while it counts fast (62 to 125).
WEIGHTscript.js[580, 230]The weight of the number at rest and while it counts fast (100 to 900).
STARTscript.js'rome'The city the page opens on: oslo, rome, quito or ushuaia.
WANDERscript.jstrueThe hand walks round the year by itself when nobody points.

Try them in the Playground

When to use it

For a figure that changes through the year and is read day by day: the light for a hotel or a holiday home (how many hours of sun there are in March), a museum's or a restaurant's visitors, the rhythm of a crop, a festival's season. It works with one value a day and a few series to compare; for a single series with no seasons a line chart is enough.

On phones

The same animations with the sizes adapted: the ring is as wide as the screen minus the months' names, with a line every two days so they stay apart, and the number scales with the ring. The hand follows the finger while it drags on the ring (there the page does not scroll) and settles when it lifts; the cities are buttons big enough to tap.

With reduced motion

No springs, no wave and no hand walking by itself: the hand goes straight to the day, the number changes without counting and, changing city, the ring swaps with a short fade. When the page opens everything fades in already in place, on the 21st of June.

Pitfalls

  • At first the number read the length of the line under the hand, but in the opening the days are born exactly as the hand passes them: the number stayed near zero for the whole first turn. During the opening it reads the final value, afterwards the line as it is at that moment.
  • The months' names are placed with translate(-50%, -50%) in the CSS: animated by GSAP they lost their centring. The name sits in a second span, and GSAP only moves that one.
  • With the year closed in a circle, the 12 h and 24 h scale ended up over some cities' January lines. Leaving a 10 degree seam at the top between the last day and the first, the scale sits there on its own and the guide circles open there.
  • The hand must go the shortest way: from the 30th of December to the 2nd of January it must not go back round the whole year. Its position is a number of days that never wraps, and the new target is the nearest of its copies plus or minus 365 days.
  • With 365 one-pixel lines on a narrow phone the ring became a solid blot: on a phone a line is drawn every two days, while the hand and the number go on reading every day.
  • The mouse over the cities pulled the hand towards June (they sit under the ring): the hand follows the mouse only on the ring and a little round it, and lets go outside.

Libraries

GSAP 3.15.0, Archivo (font variabile) 5.3.0.

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

Testing

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