V.2.3.0 is out

2026-11-02 · Kenji Yoshida

2.1 followed MapLibre, 2.2 followed Cesium, and 2.3 implements rendering features of our own: a hop, a step and a jump. On top of that, 2.3 still keeps following both properly.

Venn diagram of MapLibre, Cesium and ortho-earth featuresThree overlapping circles. Everything inside the green ortho-earth circle works in ortho-earth 2.3. (policy) marks something left out on purpose. Pink marks what arrived in v2.x. MapLibreCesiumortho-earth Home of the Style Spec Mapbox community power Maputnik style editor Martin tile server Home of 3D Tiles ion global 3D content iTwin · Bentley link Cesium Stories Conversion server (policy) Users & ecosystem Mercator plane (policy) Native SDKs (policy) Globe view 3D terrain (any DEM) Text labels · icons GeoJSON · extrusion Raster · WMS/WMTS Markers · popups Point clustering Feature queries Hypsometric tint MapLibre-compatible API style.json · expressions MVT · PMTiles · MLT Heatmap · hillshade feature-state Insert between layers Animated images Offline (PWA) Light on mobile + 6 plugin equivalents Cesium-compatible API 3D Tiles · I3S glTF · KTX2 · clearcoat CZML · clock quantized-mesh WGS84 ellipsoid Shadows · HDR · IBL Clipping planes · polygons Bloom · DOF · lens flare Particles · clouds Point clouds · voxels · splats Custom shaders SSR · contact shadow · fog · rain · toon Japan's public data at the core Ortho ⇄ perspective slider No server · 1 s revisit Main thread left free Edit → GeoPBF → GitHub Gint identify and match Out to the solar system Leaflet · Google Maps code Arcs · trips · H3 · contours Equal Earth ⇄ globe WebGPU by default
Everything inside the green circle works in ortho-earth 2.3. (policy) marks what is left out on purpose, and pink what arrived in v2.x.

New rendering

map.setPostChain gains six effects that neither Cesium nor MapLibre has (WebGPU only): screen-space reflections (SSR), contact shadows, height fog, light shafts, rain and an illustration style.

They all reuse the depth and normals the engine already had. SSR is about 380 lines and the other five about 720, and each went in within a day.

The Rainbow Bridge and the Tokyo skyline reflected in Tokyo Bay

map.setPostChain([{ type: "ssr" }]): the Rainbow Bridge and the city reflected in Tokyo Bay.

Keeping up with Cesium

The Sandcastle re-shoots did not stop after v2.2.0. From v221 to v244, all 309 examples were re-shot more than 20 times, and each time one family was fixed.

Shoot3210What went in
v2.2.019010700Last time's final count (297 scored)
v22119610100The re-shoot right after v2.2.0
v2332079100Imagery split view, 3D Tiles edge visibility, shapes clamped to terrain, time-dynamic WMTS (#845–#857)
v2382207701Serving Sandcastle's images, rectangle rotation, 3D lines that stop at buildings, imagery as fine as Cesium's (#863–#866)
v2442237500Front and back faces of closed shapes, 3D Tiles bounding spheres, Bing imagery, shadows from translucent 3D Tiles (#869–#900)

Note: the table is what the gate counted (298 scored). The Sandcastle gallery adds the examples checked by eye, 303 in all, at 3/2/1/0 = 226 / 77 / 0 / 0. At v243 an imagery change (#894) briefly pushed level 0 up to 7, but the gate caught it and #900 put it back.

Cesium on the left, ortho-earth on the right: imagery split view (splitDirection) and 3D Tiles edge visibility.

imagery-layers-split in Cesium and ortho-earth
3d-tiles-edge-visibility in Cesium and ortho-earth

Keeping up with MapLibre

While chasing Cesium, I also measured how things looked on the MapLibre side, where ortho-earth started: it began by drawing maps the MapLibre way. MapLibre's 139 official examples were lined up the same way. A picture shot on real MapLibre GL JS 6.11.2 (r7) is compared, at the same time and from the same camera, with the same code running on the MapLibre-compatible API of @ortho-earth/globe. The levels mean the same as for Cesium. Two examples that cannot be graded are left out, so 137 are counted.

Measured again this morning (the v2.2.x main), it came to 3/2/1/0 = 85 / 40 / 12 / 0. Twelve examples only partly ran. Having just brought that to 0 on Cesium, I could not let it pass.

When3210What went in
v2.1.07947110When /maplibre/ was first built
This morning8540120The v2.2.x main, measured as is
Midday864560MapLibre's default Mercator constraint, maxZoom 22, flyTo with MapLibre's choreography, querying clustered points, heatmap hits on a tilted map, the roof of zero-height extrusions
Afternoon874550The vertical field of view set to MapLibre's 36.87°
v2.3.0914330A sphere at the centre's height, unproject on terrain by walking the ray, terrain exaggeration applied to the centre too, and the real pictures re-shot for four examples where OSM had blocked the tiles

Note: the counts are on WebGPU (the Mac's real GPU). Everything was also run on WebGL2. The same 3 examples are at level 1 there, and the only difference is two examples that drop from 3 to 2 because of a single sample point on an icon.

MapLibre results

At v2.3.0 the 137 examples come to 3/2/1/0 = 91 / 43 / 3 / 0. Examples that only partly run went from 12 to 3. Every picture can be seen next to the real one in the MapLibre gallery. The gallery now has the same layout as Sandcastle, and its header and footer read in Japanese or English.

Real MapLibre on the left, ortho-earth (v2.3.0) on the right.

set-center-point-above-ground: a map without terrain with its centre held 541 m in the air. The picture already matched, but going between coordinates and screen points was 279 px off. MapLibre treats the plane at the centre's height as the ground. Only the MapLibre-compatible API now does the same (level 1 → 3)

set-center-point-above-ground: MapLibre and ortho-earth

display-a-hybrid-satellite-map-with-terrain-elevation: a satellite map of steep mountains. A click landed on the wrong slope, several kilometres away. It now walks the line of sight from near to far and closes in on the first point where it crosses the ground (queries 110/160 → 158/160, level 1 → 2)

display-a-hybrid-satellite-map-with-terrain-elevation: MapLibre and ortho-earth

add-a-3d-model-to-globe-using-threejs: a three.js model standing on the globe. The axes of custom layers on the globe had x and z swapped compared with MapLibre, so the antenna did not show

add-a-3d-model-to-globe-using-threejs: MapLibre and ortho-earth

What was built

What was given up

A stubborn bug

What took the longest this time was turning a click on terrain back into coordinates. Fixing steep slopes made the quantized-mesh example slow, and fixing the slowness made positions drift. Every fix brought a new problem in another example.

Even so, with the gate that shoots side by side with the real thing and the ratchet that fails when a level drops, it was clear on the spot where and what had broken. Along the way an older bug turned up: terrain exaggeration was never applied to the centre. In the end only terrain that can be read synchronously uses the new method, and everything else went back to the old way. Knowing when to stop digging is part of the method too.

Dropping Mercator

At the end of 2.2 I wrote a formula: Ortho Earth = MapLibre × Cesium − Mercator + α. Looking back, the term in that formula that mattered most may have been − Mercator. Because the map was drawn on a sphere from the start, not on a plane, MapLibre's 2D examples and Cesium's 3D examples could both be taken in by one and the same way of drawing. Not building 2D and 3D separately and joining them, but dropping Mercator: I think that was the essence of bringing 2D and 3D together this time.

Released: @ortho-earth/globe and @ortho-earth/core 2.3.0, @ortho-earth/cesium 0.2.0 (needs globe 2.3), @ortho-earth/voxel 0.6.1. Same API as 2.2 (npm i @ortho-earth/[email protected]).

Kenji Yoshida @ Yokohama