A WebGL globe of your music taste

Globe-FM renders every artist in your Last.fm history as a node on a 3D globe — genre clusters gather in one hemisphere, outliers in another. Click any artist and the globe traces great-circle arcs to its nearest neighbours, resolved live from a similarity graph and streamed in node by node.

Launch the globe →source ↗runs on any public Last.fm username — or tick mock data
Globe-FM — artists clustered by genre with great-circle arcs
WebGL render — artist nodes coloured by genre, arcs following the globe surface.
Three.jsReact Three FiberSSEDACTALLast.fm APINext.jsTypeScript
What it does

There is no pre-computed layout: every artist position is derived at runtime from genre taxonomy and haversine distance, so the globe is unique to each listener. Same-genre artists settle into the same region of the sphere; the shape of your taste becomes geography.

The whole thing runs in WebGL with no canvas abstraction — just Three.js, spherical math and React. Data arrives over Server-Sent Events, so you watch the universe assemble incrementally rather than waiting on a bulk load.

How it works
Rendering
React Three Fiber + Three.js. Bloom post-processing (luminance threshold 0.08, intensity 1.4). Artist nodes use BufferGeometry with vertex colours and additive blending to avoid z-fighting.
Globe layout
Artists placed via spherical coordinates derived from genre taxonomy. Haversine distance clusters same-genre artists into coherent hemispheres. Labels pushed 0.45u off the surface to avoid clipping.
Edge routing
Great-circle arcs via spherical linear interpolation (slerp). Each arc is tessellated into 8–16 line segments that follow the globe surface — no chords cutting through the sphere.
Data pipeline
Server-Sent Events stream artist data from a Next.js route handler. Concurrent Last.fm fetches run through a concurrency limiter to dodge 429s. Genre resolved via tag taxonomy with a tag-API fallback.
Similarity graph
On artist click, similar artists load into a DACTAL in-memory graph engine and are queried relationally to surface second-order connections across the globe.
Animation
A four-phase state machine — idle → loading → animating → settled. Ripple rings, tracing edges and billboard circles each have staggered, eased delays.
Camera
OrbitControls with full polar range for true 360° access including the poles. Zoom bounds 12–55u. No inertia on click-to-focus — the snap is intentional.
Labels
HTML overlays via drei's Html, shown only on click (the selected artist + its similar network). Distance-factored scaling keeps them readable at any zoom.
What I’d do next

Honest limitations — none hypothetical, all traceable to real constraints in the current build.

WebWorker offload
DACTAL graph queries run on the main thread; at 200+ nodes the similarity resolution hitches. Moving it to a Worker would unblock the render loop.
Persistent sessions
The globe re-fetches the full history on every load. Caching the resolved artist graph (localStorage or Vercel KV) would make revisits instant.
Canvas-based labels
drei's Html overlays work up to ~50 nodes but add DOM overhead at scale. Canvas-rendered billboards are the right call for dense graphs.
back to all projects

  /\
 ( o.o)
  > ^ <
 /|   |\
(_|   |_)