Back to work
Quake Globe rendering the night side of Earth with city lights and glowing earthquake markers along the Pacific rim
Case Study — Creative Code

Quake Globe

Live USGS seismic data rendered as magnitude-scaled spikes on a Three.js globe — with a time scrubber, a true-depth view that exposes subduction zones, and a render pipeline tuned down to six draw calls.

Role
Concept · Design · Build
Live at
quakeglobe.com
Stack
Three.js · Vite · Vanilla JS
Data
USGS Hazards Program
01Overview

The data is public. The understanding isn't.

The USGS publishes earthquake activity continuously as GeoJSON — coordinates, magnitude, depth, timestamp. It's complete, it's free, and it's close to unreadable. Quake Globe turns that feed into a planet you can rotate, replay, and read at a glance.

Every event becomes a spike on a rendered Earth, coloured and scaled by magnitude. A day/night terminator computed from the live subsolar position means the globe matches the one outside your window — city lights on the dark half, sun glint on daylit ocean.

Day side of the globe showing specular sun glint on the ocean near the subsolar point, with quake markers clustered along plate margins
Fig 01 Day side — specular glint on water near the subsolar point, computed live from UTC.
02The problem

Four things a table of coordinates can't tell you.

01

Depth is invisible on a flat map

Quakes originate anywhere from the surface to roughly 700 km down. A pin map flattens a subduction slab into a smear of dots and discards the geometry that explains it.

02

A snapshot hides the sequence

Aftershock cascades and building swarms are stories told over hours and days. A single frame shows the aftermath and none of the plot.

03

History means writing API queries

Asking "what happened off Japan in March 2011?" normally means hand-building fdsnws archive requests — a hard stop for anyone who isn't already technical.

04

Ten thousand markers will stall a browser

The all_month feed carries about 10,600 events. Rendered naively — one mesh per quake, a raycast across every instance per hover — the page stutters before it's useful.

03The signature move

Drop below the crust and the slab appears.

Depth view turns the globe into a translucent wireframe and re-renders every quake at its true (exaggerated) depth, recoloured along a five-stop ramp. What reads as an unreadable cluster of dots on the surface resolves into the dipping plane of a subducting plate. Tonga–Fiji is the clearest example on Earth, and it renders in a single instanced draw.

Depth view showing the Tonga subduction zone as a dipping plane of coloured markers beneath a translucent wireframe globe
Fig 02 Tonga slab, depth view.
Depth view of the Fiji region showing deep violet markers hundreds of kilometres below the surface
Fig 03 Fiji — events past 500 km.
04The reading system

Two ramps. No legend-hunting.

Magnitude drives hue and spike height together, so severity reads before you've focused. Switch to depth view and the same markers re-map onto a separate ramp — warm at the surface, violet at the bottom of the slab.

Magnitude

Minor< 3.0
Light3.0 – 4.5
Moderate4.5 – 6.0
Strong +≥ 6.0

Depth

Shallow0 km
Upper~165 km
Mid~330 km
Deep~500 km
Deepest≥ 660 km
05What it does

Built as an instrument, not a map with pins.

Time scrubber

Replay the window

Play the loaded range chronologically. Quakes flash bright as they occur, then settle — turning a static cluster into a visible sequence.

Historical archive

Query back to 1900

Any date range via the USGS fdsnws archive, with a magnitude floor and region presets for Japan, Chile, Alaska and more.

Live mode

Refresh, diff, animate

Refetches every five minutes and diffs by event id. New arrivals get an expanding shockwave, a toast, and an optional audio ping.

Plate boundaries

Context on the sphere

Peter Bird's PB2002 dataset bundled at build time and drawn as a single LineSegments call — the reason the clusters sit where they do.

Deep links

Every view is a URL

Query, filters, camera and selected event all live in the URL hash, so whatever you're looking at is one paste away from someone else's screen.

Stats sidebar

Hand-rolled SVG charts

Magnitude histogram, quakes over time, and depth distribution — no charting library, no added bundle weight.

Historical query showing the March 2011 Tohoku M9.1 sequence off the coast of Japan, dense with aftershock markers
Fig 04 Historical query — Japan, March 2011. The M9.1 Tōhoku mainshock and its aftershock sequence, replayable on the timeline.
Globe with tectonic plate boundaries overlaid, quake markers clustering along the boundary lines
Fig 05 PB2002 plate boundaries.
An expanding shockwave ring animating outward from a newly arrived earthquake marker
Fig 06 Live arrival shockwave.
06The engineering

10,600 events. Six draw calls.

The visual design was half the work. A dedicated optimization pass rebuilt the hot paths: the feed moved to a worker producing transferable typed arrays, picking gained a bounding-sphere broad phase in front of a BVH, and rings, shockwaves and stars each collapsed into one instanced draw with the animation moved into the vertex shader.

MetricBeforeAfterChange
Draw calls (scene)476
CPU frame submit0.40 ms0.04 ms10×
Pick raycast, 10.6k instances0.78 ms0.09 ms~9×
Main-thread long tasks on load67 msnoneworker
Allocation rate, idle rotate9,950 KB/s1,449 KB/s~7×
Texture payload2,546 KB586 KB
Lighthouse performance7584TBT −54%

Two of those results came with a constraint attached. Bloom is applied without a second render pass — the scene renders into a half-float HDR target and only marker colours are pushed past the threshold, so the markers glow and the Earth never does. And the KTX2 compressed textures originally shipped in this pass were pulled back out: the Basis transcoder calls eval() internally, which the strict CSP blocks by design, and the KTX2 path was heavier over the wire regardless. Responsive JPEGs replaced it.

6
draw calls for the entire scene
~2,000
lines of vanilla JS, no framework
2
runtime dependencies: three, three-mesh-bvh
0 B
allocated per render and update call
07Outcome

A research-grade instrument that opens in a tab.

The same globe serves a seismology student tracing a slab, a journalist pulling a shareable link mid-story, and someone who just felt the ground move and wants to know what it was. No install, no account, no query syntax.

Legibility before interpretation. Magnitude and depth are encoded in colour and form, so the read happens before the reasoning.

Time as a first-class axis. The scrubber converts isolated points into the sequence that actually explains them.

Shareability as a feature. Full app state in the URL hash makes every view a link — the cheapest distribution a tool can have.

Performance is a design constraint. Depth view and live shockwaves are only usable because the render budget was engineered to afford them.

Built with
Three.js 0.185 three-mesh-bvh Vite Web Workers Custom GLSL shaders InstancedMesh USGS GeoJSON + fdsnws GitHub Actions → Pages
See it move

Watch the planet in real time.

Open Quake Globe
quakeglobe.com

Data: USGS Earthquake Hazards Program · Plate boundaries: Peter Bird PB2002 (ODC-By) · Textures: NASA Blue Marble.