A reference tour of where geo data comes from. Tutorials 1–10 mostly stream the keyless defaults; this one catalogs every source the geo module can pull from — OpenStreetMap, AWS, Cesium ion, the Google Map Tiles API, Gaussian-splat tiles, and Google Street View — what each gives you, what it costs, and the one-line call that wires it into a
GeoScene. Sources: src/geo/imagery.ts, src/geo/raster_dem.ts, src/geo/cesium_ion.ts, src/geo/google_tiles.ts, samples/geo_splat.ts, samples/geo_street_view.ts.
This is a reference tutorial — read it when you're choosing what to stream, not
as a step in the linear path. Everything here plugs into the same GeoScene
add* methods you met in tutorial 3; only the source object
changes.
The shape of it#
A GeoScene consumes four kinds of data, and each kind has several
interchangeable sources:
| Kind | GeoScene method | Keyless source | Keyed alternatives |
|---|---|---|---|
| Imagery (color drape) | imagery: option on terrain | ESRI_WORLD_IMAGERY, OSM_RASTER, CARTO_*, STADIA_* | MapTiler/Bing via xyzImagery, ion bingAerial |
| Terrain (elevation) | addRasterDemTerrain / addTerrain | AWS_TERRARIUM (raster DEM) | maptilerTerrainRgb, resolveMapTilerTerrain (quantized-mesh), ion worldTerrain |
| Vector tiles (buildings/roads) | addVectorTiles | OPENFREEMAP_VECTOR | maptilerVector |
| 3D Tiles (city models, photoreal) | add3DTiles | — | ion (osmBuildings, googlePhotorealistic, …), resolveGoogleTiles, UrlTilesetSource |
Plus two non-GeoScene integrations: Gaussian splats (composited over the
scene via GeoSplatFeature) and Street View (a DOM panel via
StreetViewPanel).
The split that matters: keyless sources (OSM-derived, AWS, Carto) need no account and stream straight from localhost; keyed sources (Cesium ion, Google, MapTiler, Stadia in some cases) want a token or API key. Tutorials 1–9 stay entirely keyless on purpose.
OpenStreetMap-derived (keyless)#
OSM is the data behind most of the keyless sources — re-served in several forms:
Vector-tile buildings — OPENFREEMAP_VECTOR#
OSM building footprints + roads in the OpenMapTiles schema, free and keyless from
openfreemap.org. addVectorTiles extrudes the
building layer into 3D:
import { OPENFREEMAP_VECTOR } from 'taos/geo/index.js';
geo.addVectorTiles(OPENFREEMAP_VECTOR); // decodes off the main thread automaticallyRaster map imagery — OSM_RASTER and the Carto styles#
OSM rendered to raster tiles, draped over terrain as color:
import { OSM_RASTER, CARTO_LIGHT, CARTO_DARK } from 'taos/geo/index.js';
geo.addRasterDemTerrain(AWS_TERRARIUM, { imagery: OSM_RASTER }); // standard OSM carto
geo.addRasterDemTerrain(AWS_TERRARIUM, { imagery: CARTO_LIGHT }); // clean light basemapBuilt-in imagery providers (no key for most): ESRI_WORLD_IMAGERY (aerial
photos, the default), OSM_RASTER, CARTO_LIGHT, CARTO_DARK,
CARTO_LIGHT_LABELS, CARTO_DARK_LABELS (transparent label-only overlays — see
the imageryStack recipe in tutorial 3),
CARTO_LIGHT_RETINA, STADIA_ALIDADE_SMOOTH, STADIA_ALIDADE_DARK.
Any XYZ tile server — xyzImagery#
The escape hatch for any {z}/{x}/{y} slippy-map server (your own, Mapbox,
Thunderforest, etc.). The key, if any, rides in the URL template:
import { xyzImagery } from 'taos/geo/index.js';
const myTiles = xyzImagery({
label: 'My Tiles',
attribution: '© Me',
template: 'https://tiles.example.com/{z}/{x}/{y}.png?key=ABC', // {s} subdomain optional
maxZoom: 18,
});
geo.addRasterDemTerrain(AWS_TERRARIUM, { imagery: myTiles });AWS — elevation (keyless)#
AWS_TERRARIUM is the keyless default terrain: AWS-hosted Terrain Tiles
(Mapzen Terrarium PNG encoding — height packed into RGB), sourced from SRTM /
GMTED2010 / ETOPO1. It's a raster DEM: addRasterDemTerrain decodes the PNG
heights and bakes terrain mesh on the GPU.
import { AWS_TERRARIUM, ESRI_WORLD_IMAGERY } from 'taos/geo/index.js';
// Geometry from AWS elevation, color from Esri imagery draped over it.
geo.addRasterDemTerrain(AWS_TERRARIUM, { imagery: ESRI_WORLD_IMAGERY });Global coverage to zoom 15 (~5 m near the equator). For finer terrain you reach for a keyed quantized-mesh source (ion or MapTiler — below).
Cesium ion — terrain, buildings, photoreal, other worlds (keyed)#
Cesium ion is the highest-fidelity catalog and the one keyed source the tutorials use (in tutorial 10). Get a free Bearer token at https://cesium.com/ion/tokens.
You stream an ion asset by first resolving its endpoint — ion hands back the
real tile URL, a per-asset access token, and the attribution HTML you're required
to display. resolveIonAsset does that round trip:
import { resolveIonAsset, ION_ASSETS } from 'taos/geo/index.js';
const ION_TOKEN = '…'; // your Bearer token
// Cesium World Terrain (quantized-mesh — note addTerrain, not addRasterDemTerrain):
geo.addTerrain(await resolveIonAsset(ION_ASSETS.worldTerrain, ION_TOKEN),
{ imagery: ESRI_WORLD_IMAGERY });
// Cesium OSM Buildings — a global 3D Tileset of extruded OSM footprints:
geo.add3DTiles(await resolveIonAsset(ION_ASSETS.osmBuildings, ION_TOKEN),
{ useWorker: () => true });
// Google Photorealistic 3D Tiles, proxied through ion (terrain + buildings baked in):
geo.add3DTiles(await resolveIonAsset(ION_ASSETS.googlePhotorealistic, ION_TOKEN));ION_ASSETS names the well-known IDs: worldTerrain (1), osmBuildings,
googlePhotorealistic, bingAerial (Bing aerial imagery), and cesiumMoon (a
3D Tileset of the Moon — see tutorial 10). Any other ion
asset ID works too; just pass the number.
Attribution is mandatory.
resolveIonAssetreturns the asset'sattributions(Cesium / Google ToS) — display them. For the visible-tile copyrights of photoreal tiles, see the Google section below.
Google Map Tiles API — photoreal, ion-free (keyed)#
You can stream Google Photorealistic 3D Tiles directly from Google's Map Tiles API, with no Cesium ion in the path (and so no ion quota). Needs a Google Maps Platform API key with the Map Tiles API enabled:
import { resolveGoogleTiles } from 'taos/geo/index.js';
geo.add3DTiles(resolveGoogleTiles(GOOGLE_MAPS_KEY), { useWorker: () => true });The key rides in the root URL and the session parameter is inherited down the
whole tile tree automatically — Tileset3D streams it like any other 3D Tiles
asset.
Attribution differs from ion. Google doesn't return one attribution string;
each glTF tile carries an asset.copyright listing its data providers, and you
must show the providers of the currently visible tiles, updated as they stream
in and out. That live set is collected for you:
const { tileset } = geo.add3DTiles(resolveGoogleTiles(GOOGLE_MAPS_KEY));
// each frame, after geo.update():
const credits = tileset.visibleCopyrights; // deduped, ref-stable until the set changes
attributionEl.textContent = credits.join(', ');The reference is tileset.visibleCopyrights's !==-stable contract — it only
changes identity when the on-screen providers change, so you can guard the DOM
write.
MapTiler — keyed terrain & vector (alternative to ion)#
MapTiler Cloud (free tier available) is the drop-in keyed alternative when you don't want an ion account. Three flavors:
import { resolveMapTilerTerrain, maptilerTerrainRgb, maptilerVector } from 'taos/geo/index.js';
// Quantized-mesh terrain (same format as Cesium World Terrain → addTerrain):
geo.addTerrain(resolveMapTilerTerrain(MAPTILER_KEY), { imagery: ESRI_WORLD_IMAGERY });
// …or raster terrain-RGB elevation (→ addRasterDemTerrain), like AWS but keyed:
geo.addRasterDemTerrain(maptilerTerrainRgb(MAPTILER_KEY), { imagery: ESRI_WORLD_IMAGERY });
// OpenMapTiles vector tiles (buildings/roads), keyed alternative to OpenFreeMap:
geo.addVectorTiles(maptilerVector(MAPTILER_KEY));Arbitrary 3D Tiles by URL — UrlTilesetSource#
Have a tileset.json somewhere (your own build, a public OGC 3D Tiles endpoint)?
Point add3DTiles straight at the URL — no resolution step:
import { UrlTilesetSource } from 'taos/geo/index.js';
geo.add3DTiles(new UrlTilesetSource('https://example.com/tileset.json', '© Example'),
{ useWorker: () => true });The second argument is the attribution HTML to display. This is how planet_explorer loads a user-pasted tileset URL.
Gaussian splats — GeoSplatFeature#
3D Gaussian-splat scenes (photoreal point-cloud captures) aren't a GeoScene
tileset — they render as a composite over the already-rendered geo scene. The
loader decodes a glTF carrying KHR_gaussian_splatting (incl. the spz_2
compression), and GeoSplatFeature draws it, depth-occluded against the terrain
in front of it:
import { loadGaussianSplatGlb, transformSplatData } from 'taos/splats/gltf_splat_loader.js';
import { GeoSplatFeature } from 'taos/splats/geo_splat_feature.js';
const { data, transform } = await loadGaussianSplatGlb(glbBuffer);
transformSplatData(data, placementMatrix); // bake the world placement into the cloud
// Register AFTER the tonemap feature — it composites over the final image.
engine.addFeature(new GeoSplatFeature(data));transformSplatData bakes a placement matrix into the cloud (the splat pass has
no per-cloud model matrix), so first build the matrix that puts your capture at
its lat/lon on the globe. samples/geo_splat.ts
walks the full placement on streamed AWS terrain.
For streaming splat tilesets with LOD (the Cesium "3D Tiles Gaussian Splats
with LOD" analog), GaussianSplatTileset drives a quadtree of splat tiles into
one merged GPU buffer with budget-aware SSE refinement — see
samples/splat_tileset.ts.
Google Street View — StreetViewPanel#
Street View isn't 3D geometry — it's Google's panorama widget rendered into a DOM element, two-way-synced with the globe. Needs a Google Maps JavaScript API key with the Street View service enabled. Tutorial 10 covers the full round trip; the gist:
import { StreetViewPanel } from 'taos/geo/index.js';
const panel = await StreetViewPanel.load({
apiKey: GOOGLE_MAPS_KEY,
container: document.getElementById('streetview')!,
lon: -122.4194, lat: 37.7749,
onPositionChanged: (lon, lat) => placeGlobeMarker(lon, lat), // panorama → globe
});
panel.setLocation(lon, lat); // drive it from a globe click (globe → panorama)Mixing sources#
Every source above plugs into the same GeoScene, so you mix freely — keyless
AWS terrain under keyed ion buildings, OSM imagery with MapTiler elevation,
whatever. Add terrain first (content clamps to its height), and remember the
stacking rules from tutorial 3:
geo.addRasterDemTerrain(AWS_TERRARIUM, { imagery: ESRI_WORLD_IMAGERY }); // keyless geometry + color
geo.add3DTiles(await resolveIonAsset(ION_ASSETS.osmBuildings, ION_TOKEN)); // keyed buildings on topThe dataSourceLog (src/geo/data_source.ts)
records every fetch per source — handy for confirming what's actually streaming
and spotting a 401/403 from a bad key.
Next#
- Tutorial 12 — Performance, Quality & Debugging: the
knobs (
maxSSE, memory budgets, preload, worker decode) that trade detail for framerate across any of these sources, plus the data-source/cache log for seeing exactly what each source is streaming. - The full reference is the Geo module guide.