Three.js Globe: Building an Interactive 3D Earth

A Three.js globe starts as a textured sphere (a SphereGeometry with an equirectangular Earth texture map), with data points and connection arcs plotted onto its surface by converting latitude/longitude coordinates to 3D positions with spherical-to-Cartesian math. This is the technique behind every "interactive data globe" visualization on the web.

Last updated . Verified against three.js r181.

Read the FAQJump to code

The base sphere

A globe is a SphereGeometry with a texture mapped onto it: a day-map Earth texture at minimum, often layered with a normal map (for terrain bump) and a specular/roughness map (oceans reflect differently than land). A separate, slightly larger transparent sphere with a Fresnel-based glow shader is the common technique for the soft atmospheric rim visible around most globe visualizations. It's a cheap effect that adds significant perceived polish.

Rotation is usually just mesh.rotation.y += delta * speed for a slow idle spin, paused on user drag via OrbitControls or custom pointer handling.

Converting latitude/longitude to 3D positions

Every data point or city marker needs converting from latitude/longitude to a 3D position on the sphere's surface, using the standard spherical-to-Cartesian formula:

function latLngToVector3(lat, lng, radius) {
  const phi = (90 - lat) * (Math.PI / 180)
  const theta = (lng + 180) * (Math.PI / 180)
  return new THREE.Vector3(
    -radius * Math.sin(phi) * Math.cos(theta),
    radius * Math.cos(phi),
    radius * Math.sin(phi) * Math.sin(theta)
  )
}

The sign and offset conventions (the - and +180) depend on how your texture is UV-mapped. If points appear mirrored or rotated relative to the texture, this is almost always where to look first, not the data itself.

Animated connection arcs between points

The "flight path" arcs common in globe visualizations are QuadraticBezierCurve3 or CubicBezierCurve3 paths between two surface points, with a control point lifted above the surface (along the midpoint's normal) so the arc curves outward rather than cutting straight through the sphere. Animate them by progressively revealing the curve (drawing more of its length over time) or by animating a small sprite/point moving along the curve's getPoint(t). Both read as "data flowing" far more effectively than a static line.

See it in production

Browse the full showcase →

Code

Globe with a data point and arc (r181)
1const globe = new THREE.Mesh(
2 new THREE.SphereGeometry(2, 64, 64),
3 new THREE.MeshStandardMaterial({ map: earthTexture })
4)
5scene.add(globe)
6
7function latLngToVector3(lat, lng, radius) {
8 const phi = (90 - lat) * (Math.PI / 180)
9 const theta = (lng + 180) * (Math.PI / 180)
10 return new THREE.Vector3(
11 -radius * Math.sin(phi) * Math.cos(theta),
12 radius * Math.cos(phi),
13 radius * Math.sin(phi) * Math.sin(theta)
14 )
15}
16
17const start = latLngToVector3(40.7, -74.0, 2) // New York
18const end = latLngToVector3(51.5, -0.1, 2) // London
19const mid = start.clone().add(end).multiplyScalar(0.5).normalize().multiplyScalar(2.6) // lifted above the surface
20const curve = new THREE.QuadraticBezierCurve3(start, mid, end)
21const arc = new THREE.Line(new THREE.BufferGeometry().setFromPoints(curve.getPoints(50)), new THREE.LineBasicMaterial({ color: 0x38bdf8 }))
22scene.add(arc)
Atmospheric glow with TSL Fresnel
1import { positionLocal, normalLocal, cameraPosition, dot, pow, color } from 'three/tsl'
2
3const viewDir = cameraPosition.sub(positionLocal).normalize()
4const fresnel = pow(dot(normalLocal, viewDir).oneMinus(), 3)
5
6const atmosphere = new THREE.MeshBasicNodeMaterial({ transparent: true, side: THREE.BackSide })
7atmosphere.colorNode = color(0x4a9eff)
8atmosphere.opacityNode = fresnel.mul(0.6)
9
10const glowMesh = new THREE.Mesh(new THREE.SphereGeometry(2.15, 64, 64), atmosphere)
11scene.add(glowMesh)

Learn this properly

Learn Practical TSL

Your First Node Material

The Fresnel glow technique used for the globe's atmosphere is built with node materials.

Start the lesson (6 minutes)

Frequently asked questions

How do I plot data points on a Three.js globe?

Convert each point's latitude/longitude to a 3D position using the standard spherical-to-Cartesian formula, then place a marker mesh (or point in a THREE.Points system for many markers) at that position on the sphere's surface.

How do I add the glowing atmosphere effect to a Three.js globe?

A separate, slightly larger sphere with a Fresnel-based shader (a custom ShaderMaterial or TSL node material) rendered with backface culling reversed (THREE.BackSide) and additive or alpha blending: brighter at the silhouette edge, transparent facing the camera directly.

Why are my globe data points in the wrong place?

Almost always a sign/offset mismatch in the latitude/longitude-to-3D conversion relative to how your Earth texture is UV-mapped. Check the formula's sign conventions against your specific texture rather than assuming the data is wrong.

Keep reading