What's included
A dotted globe of the Earth, drawn on a 2-D
<canvas>, with pins anchored to real coordinates and address cards that follow the rotation then vanish behind the sphere. Three files: a stylesheet, a script, and the land map. No dependencies, no build step, no external requests.
The component doesn't replace your address list: it sits on top of it. Until the script has run — and if it never runs — the markup stays a grid list of offices, readable and navigable. The pin button isn't even rendered in that state: it would lead nowhere.
Features
- Pins that are real buttons — a click, the Enter key or focus alone turns the globe round to the place, and opens its card. Escape closes it.
- Rotation by mouse and by finger — with inertia, and a slow westward drift at rest, in the direction the Earth turns.
- A hidden pin is still reachable — once behind the sphere, it shrinks to a transparent pixel on the limb, but keeps its place in the tab order: reaching it from the keyboard is what brings it back to the front.
- Land map on board — a 1-bit mask of 1024 × 512 cells, 16 KiB, derived from the Natural Earth polygons, which are in the public domain. Nothing to download at runtime.
- Everything is set from the CSS — grid density, perspective, dot size, colours, durations: the script reads the variables back, you never touch it.
- Three variants — dark, glowing cyan, and light; plus a compact version for a side column.
Dropping it into a page
Three files to load, then a list of places:
<link rel="stylesheet" href="globe-pins.css">
<div class="globe-pins">
<div class="globe-pins__scene">
<canvas class="globe-pins__toile" aria-hidden="true"></canvas>
<ul class="globe-pins__liste">
<li class="globe-pins__lieu" data-gp-lat="48.8566" data-gp-lon="2.3522">
<button class="globe-pins__epingle" type="button" aria-controls="paris">
<span class="globe-pins__nom">Bring Paris round to the camera</span>
</button>
<div class="globe-pins__carte" id="paris">
<span class="globe-pins__pays">France</span>
<span class="globe-pins__ligne">Paris</span>
<span class="globe-pins__ligne">18 rue de Paradis</span>
</div>
</li>
</ul>
</div>
</div>
<script src="globe-pins.terres.js"></script>
<script src="globe-pins.js"></script>
Give .globe-pins a height: the globe centres itself in it and takes 68% of the shorter side. The component installs itself on load, including on instances added later.
What you should know
- A globe costs dots. At 181 rows, that's eleven thousand fill dots plus the coastline, half of which is drawn every frame. Measured at 61 frames per second with four globes on the same page; off screen or in a hidden tab, the loop stops.
-
The cards tread on each other if the places are close together. Two modifiers flip a card to the other side of its pin, and
data-gp-cartes="au-focus"only shows them on hover when the pins are many. -
A canvas can't be seen in forced colours.
Under
forced-colors: active, the component therefore goes back to being the address list it started as. Underprefers-reduced-motion, the drift stops and the delays fall to zero. -
No inline styles, no inline scripts. The component honours the site's strict security policy — checked by serving the folder with the header, not assumed — and never uses
innerHTML. The positions go through two CSS variables written via the CSSOM. - The design comes from elsewhere. The proportions follow those of a commercial Framer component, measured to the pixel from its screenshots: limb radius to within 0.71 px, perspective at 20.0°, grid at 181 rows. The code itself is original — nothing was taken from its implementation, and the satellite-texture variant isn't reproduced.
Take it, open it, break it.
This component is free. The full library — the templates and the other components — comes with the subscription, alongside the course.
Immediate access · No commitment · Cancel in one click