Skip to main content

Performance

The loop idles

The single most important thing to know: frames are skipped entirely when nothing is moving.

globe.render(); // draws now
globe._animating(); // internal: true while something needs to move

A static chart: no auto-rotation, no live markers, no animated arcs, no orbits, no pings, no video media: costs nothing after the first paint. It is not burning a requestAnimationFrame loop redrawing an identical image.

Anything that changes state marks the next frame dirty. If you mutate something the library cannot see, ask for a repaint:

globe.invalidate();

Measured costs

On a laptop, 560 × 216 map, full bundled geometry:

ScenarioPer frame
Country geometry only~14 ms
5,000 markers, clustered~25 ms
Textured globe, half-res~10 ms
Dot matrix, 2° spacing (~2,900 dots)~4 ms

The frame budget at the default 30 fps is 33 ms.

Where the time goes

Geometry tracing dominates. 177 countries with ~10,800 points is most of the per-frame work. Globe mode is cheaper than it looks because geometry behind the horizon is clipped rather than drawn: a typical frame skips 20-60% of the world.

Choropleth costs more than plain land. A single fill for all countries becomes one path per country, because each needs its own colour. Only enable it when you are using it.

Levers

LeverEffect
fps: 24Cheaper, still smooth for a background element
cluster: trueTurns thousands of markers into dozens of bubbles
graticule: falseRemoves ~30 sampled polylines
stars: falseRemoves 140 circles per frame
landStyle: "dots"Cheaper than fill once cached: a single batched fill
dotSpacing upFewer dots, quadratically
textureQuality: 3Coarser texture pass, upscaled
Simpler world GeoJSONFewer points to trace

Caches worth knowing about

Several things are computed once and reused. Keeping references stable keeps the caches warm:

CacheKeyed onInvalidated by
Arc great-circle pointsthe arc objectpassing a new object
Dot matrixdotSpacingchanging spacing or geometry
Land raster maskworld + India geometrychanging either
Country bounding boxesthe shape objectreplacing world
Auto country coloursworld + palettereplacing either
Projection boundsprojection + latRangechanging either
// Good: the arc objects persist, so their sample points stay cached
const arcs = useMemo(() => routes.map(toArc), [routes]);
globe.setArcs(arcs);

// Bad: new objects every render, cache misses every time
globe.setArcs(routes.map(toArc));

Many globes on one page

Each instance runs its own loop, but idle instances cost nothing. The preset gallery on this site runs ten globes simultaneously with autoRotate: false and stays completely idle.

For a grid of small static globes, turn off interaction too:

createGlobe(canvas, {
preset: "atlas",
autoRotate: false,
interactive: false,
keyboard: false,
});

Memory

destroy() releases everything: the animation frame, all listeners, the ResizeObserver, the tooltip and live-region nodes, the reduced-motion listener, any video or GIF elements, and all timers from tours, stories, timelines and ping feeds.

Failing to call it in a single-page app leaks a requestAnimationFrame loop per mount. The React component and custom element handle it.

Bundle size

~120 KB gzipped, of which about 71 KB is map data:

PieceGzipped
Country geometry~64 KB
Time-zone table~7 KB
All code~43 KB

The build enforces a size budget and fails if it is exceeded, so this does not drift silently.