Dina Bevers
Five places I have been, and one tiny plane to get there.
Press the arrow key down to take off from Brussels
Stop 1 of 5
South Korea
Capital since 1394, when the Joseon dynasty moved its court here.
Stop 2 of 5
New Zealand
The southernmost capital of any sovereign country.
Stop 3 of 5
Japan
Around 37 million people live in its metro area, the largest on Earth.
Stop 4 of 5
Türkiye
Chosen as capital of the new republic in 1923, over Istanbul.
Stop 5 of 5
Belgium
Back where we started. Welkom in Brussel, bienvenue à Bruxelles.
Crossing the United States
Brussels → Seoul
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
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
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
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
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
This browser has no WebGL2, so the globe stays on the ground.