All field notes

Engineering note

How we built a real 3D globe in React Native with a Skia shader

How the tripswipe globe works: a per-pixel orthographic projection in a React Native Skia fragment shader, a country-index texture, ripples that follow the rotation, and a WebGL port for the web.

David Rodrigues4 min read

The home screen of tripswipe is a globe with the countries you have visited lit up. It turns on its own, and touching it sends a ripple across the surface and flashes the country under your finger. This post explains how it works, from the projection maths to the textures, and why we used a shader instead of a 3D engine.

Why a fragment shader instead of a 3D engine

A sphere with a world map on it does not need meshes, cameras or a scene graph. For each pixel inside the disc we invert an orthographic projection to get a latitude and longitude, add the current rotation, and sample a flat world texture. It is the same arithmetic d3’s geoOrthographic does for polygons, run per pixel, sixty times a second. Foreshortening, the rim and the lighting all come from that geometry, so nothing has to be painted on top.

We draw it with React Native Skia as a runtime shader. We tried expo-gl first, but it presented the first couple of frames and then stopped compositing. Skia also runs the whole thing on the UI thread through Reanimated, so a touch is answered immediately even while JavaScript is busy loading the app.

Two textures: what the world looks like, and which country is where

  • world-base.png (2048×1024): the surface, with sea and grey land, sampled with linear filtering.
  • world-index.png (1024×512): which country each texel belongs to, stored as a number in the alpha channel and sampled with nearest filtering so numbers never blend.

The index texture is what lets countries light up one at a time without a texture per country. Your visited countries are uploaded as a 256×1 lookup table, one pixel per country number with red where that country is lit, so lighting an arbitrary set of countries costs one extra texture read per pixel and no loops over a list.

Ripples that travel with the globe

A touch stores where the finger landed and the rotation at that moment. Each frame, the shader turns that point back into a latitude and longitude and projects it forward at the current rotation, so the ripple stays attached to the piece of the world you touched instead of to a spot on the glass. There are six ripple slots filled in turn, so several fingers or quick taps each get their own ring.

The ripple is a refraction rather than a bump: it shifts where the map is sampled along the radius from the touch point, so the coastlines bend the way they would through moving water. A touch on land also reads the country index at the touch point and flashes that one country green for just over a second.

Lighting a ball properly

The shading is a Lambert term from a fixed light direction plus ambient light, a falloff towards the rim, and a thin cool edge on the lit side of the sphere for the atmosphere. Our first version had the atmosphere running from the middle of the ball outwards, which lit it inside out, so the dark centre and bright band read as a hollow shell. The fix was to keep the atmosphere to the edge and give the diffuse term room to model the shape.

The same globe on the web

The tripswipe landing page runs the same shader ported from SkSL to WebGL 1, on the same two textures and with the same constants. The page reads the index texture once into a canvas, so it can name the country under your cursor with the same projection maths the shader uses. Try it on the phone in the hero: tap a country and add it to the counter.

Takeaways

  • For a single textured sphere, a per-pixel projection in a fragment shader is simpler and faster than a 3D engine.
  • Encoding identity (which country) in a texture channel turns per-object state into a single lookup.
  • Store interaction points in world coordinates, not screen coordinates, when the surface underneath moves.
  • Keep the maths in one place and port it as-is between platforms, so mobile and web behave the same.

Building a product with a hard visual centrepiece like this? Book a strategy call with us.

From idea to production

Building something ambitious with AI?

We help teams turn promising concepts into dependable products, without the prototype debt.

Start a conversation