Dina Bevers

Dina Bevers

Five places I have been, and one tiny plane to get there.

Press the arrow key down to take off from Brussels

  1. Photos from Seoul coming soon

    Stop 1 of 5

    Seoul

    South Korea

    Capital since 1394, when the Joseon dynasty moved its court here.

  2. Photos from Wellington coming soon

    Stop 2 of 5

    Wellington

    New Zealand

    The southernmost capital of any sovereign country.

  3. Photos from Tokyo coming soon

    Stop 3 of 5

    Tokyo

    Japan

    Around 37 million people live in its metro area, the largest on Earth.

  4. Photos from Ankara coming soon

    Stop 4 of 5

    Ankara

    Türkiye

    Chosen as capital of the new republic in 1923, over Istanbul.

  5. Photos from Brussels coming soon

    Stop 5 of 5

    Brussels

    Belgium

    Back where we started. Welkom in Brussel, bienvenue à Bruxelles.

Crossing the United States

Brussels → Seoul

One number drives everything

Scrolling moves one custom property, --scroll, from 0 to 1 with a scroll-driven animation. This leg owns a slice of it, and progress() turns that slice into its own 0 to 1.

<li data-depart="0.05"
    data-arrive="0.1872">

.stop {
  --leg: progress(
    var(--scroll),
    var(--depart),
    var(--arrive)
  );
}

Seoul → Wellington

Speed with some nuance

A straight line would fly at one speed and stop dead. The plane speeds up over the first 18% of the leg, cruises, then slows down. It is one calc() on top of --leg.

--ramp-in: max(0,
  0.18 - var(--leg));
--ramp-out: max(0,
  var(--leg) - 0.82);

--eased: calc(
  (var(--leg) - 0.09
  + pow(var(--ramp-in), 2) / 0.36
  - pow(var(--ramp-out), 2) / 0.36)
  / 0.82
);

Wellington → Tokyo

Climb, cruise, descend

Altitude reuses progress() on the eased position. One ramp for the climb, one for the descent. Outside their window they clamp to 0 or 1, so the plane flies level in between.

--climb: progress(
  var(--eased), 0, 0.22);
--descent: progress(
  var(--eased), 0.78, 1);

--arc: smooth(--climb)
  * (1 - smooth(--descent));

Tokyo → Ankara

Camera and sky

The camera pulls back as the plane climbs: --zoom is --arc times this leg's data-lift. The sky and the sunlight in the shader are color-mix() fed by progress() of the whole tour.

<li data-lift="1.6">

--zoom: calc(
  var(--arc) * var(--lift));
--dusk: progress(
  var(--scroll), 0.82, 1);
--sun-color: color-mix(in srgb,
  #fff3d6,
  #ff9e66 calc(var(--dusk) * 55%));

Ankara → Brussels

WebGL only reads it

Every frame, JavaScript reads the computed custom properties and hands them to the shader. It only adds a spring on top, so a jump across the page still flies. The cards, the route bar and the percentage up top are pure CSS.

const css = getComputedStyle(el);

const eased = parseFloat(
  css.getPropertyValue('--eased'));

gl.uniform3fv(u_sun,
  color(css, '--sun-color'));

Home again.

Back in Brussels, five places later.

Free flight

Speed
Altitude
  • ←→Turn
  • ↑↓Throttle
  • SpaceBoost
  • EClimb
  • FDescend
  • EscBack to the tour

This browser has no WebGL2, so the globe stays on the ground.