AI ProjectWeb AppThree.js
Globeify
Build an interactive 3D globe, pin the places that matter, and take away an embed snippet for your own site. What started as a one-off component for a client page, rebuilt so anyone can make their own.
A client wanted testimonials on a rotating globe. Pins where the clients were, a quote when you clicked one. I built it, hand-tuned to that page, and it looked good.
Then a second client wanted roughly the same thing with different colours. Then someone asked whether they could have one for a site I had nothing to do with.
The third request is where the arithmetic changes. Twice is a coincidence; three times is a product, or at least a strong hint that you should stop copying files between repositories and hard-coding coordinates.
Globeify is that component turned into something anyone can drive. You sign in, build a globe in an editor, drop pins on it, choose a theme, and walk away with an embed snippet for your own site. Nobody has to open a code editor or ask me for a favour.
Six theme presets ship with it, paired as dark and light: graphite, paper, midnight, ice, sand and forest. Constrained palettes rather than a colour picker, because a colour picker on a 3D globe is a machine for producing ugly globes.
Three Ways Out
There are three ways to get a finished globe onto a site, which sounds like indecision and is actually the whole point.
A script tag — a tiny loader that injects an iframe pointed at your globe. Easiest, and it keeps updating when you edit the globe later.
A direct iframe — for anyone whose CMS lets them paste an iframe and nothing else, which is a surprising number of people.
A downloaded HTML file — a single self-contained page with Three.js from a CDN and no connection back to my database at all. It stops updating, and it also keeps working forever regardless of what happens to Globeify or to me. Anyone asked to put a third-party script on a client's production site should be offered a version that doesn't need one.
The embed page reads live from the database, so edits in the editor appear on the embedded globe without anyone touching the host site.
Drawing the Earth
The globe is Three.js, but the countries aren't 3D geometry. Triangulating every country polygon and filling it in 3D is expensive, and it goes wrong at exactly the places where the eye is most likely to notice.
Instead the world is drawn flat onto a 4096×2048 canvas in equirectangular projection and wrapped onto a sphere as a texture. TopoJSON world atlas data gets decoded, the polygons are split at the antimeridian — otherwise countries that cross the date line smear right across the map in a way that is briefly hilarious and then simply broken — and the whole thing is painted with the theme colours before being handed to the GPU as one image.
It renders faster, it re-themes instantly, and the coastlines are crisp because they're drawn at texture resolution rather than approximated in mesh.
The Fiddly Bits
Auto-save that doesn't fight you. The editor listens to the database for live updates and also saves your local edits on a short debounce. Left alone, those two mechanisms take turns overwriting each other, and you watch a colour you just changed flick back to its old value. Local edits now set a dirty flag, and while it's set the incoming updates are ignored. Obvious in hindsight. Not obvious at 1am.
Multiple globes on one page. The original component attached its event listeners to the window, which is fine until there are two globes and they both respond to a drag on either of them. Everything now binds to its own canvas, and the world topology is fetched once and shared across every instance rather than downloaded per globe.
Geocoding politely. Typing a place name and getting a pin means hitting a geocoding service. I proxy it through a server function with a 24-hour cache, per-user rate limiting, and requests serialised roughly one per second — which is what the service's terms ask for. Free public infrastructure stays free and public when people using it behave themselves.
Current State
Built and working. Next.js exported as a static site, with the database, sign-in and geocoding proxy on the backend, sitting on top of the same rendering core that ran on the original client page.
This one replaced the entry on this site that used to read "Globe Component". Same idea, several years of impatience later, now something I can hand over instead of rebuild.