On-the-fly Mosaics, titiler-cmr and Planetary Computer
How the NASA HLS pill composites granules through NASA VEDA's titiler-cmr, how the Planetary Computer catalogs tile a STAC search over Landsat and Sentinel-2 through the pcmosaic:// protocol, and how a Maxar, Vantor or NOAA capture is drawn from its COGs through capture://
Three medium-resolution series on the historical timeline are not tile pyramids anyone published. They are composited the moment a tile is asked for, by a dynamic tiler that searches a scene catalog for the window, reads the matching Cloud-Optimized GeoTIFFs by range request, and renders the tile:
| Series | Where on the timeline | Catalog searched | Tiler | Window |
|---|---|---|---|---|
| NASA HLS | the NASA HLS pill | NASA CMR, collection HLSS30 v2.0 | titiler-cmr, NASA VEDA's instance | 15 days either side of the date, from 2016 |
| Landsat 1982+ quarterly | Catalogs › World, with Google Earth Timelapse | Planetary Computer STAC, landsat-c2-l2 | Planetary Computer data API | a calendar quarter, from 1982 Q4 |
| Sentinel-2 2016+ monthly | same | Planetary Computer STAC, sentinel-2-l2a | Planetary Computer data API | a calendar month, from January 2016 |
Both tilers are public and keyless from the browser, and both are services someone else runs for their own catalog, not a contract: a slow tile or an outage is theirs to fix. Google Earth Timelapse is the opposite kind of source, one finished frame a year, and sits next to the Planetary Computer catalogs so a place can be read both ways.
titiler-cmr, behind the NASA HLS pill
titiler-cmr is Development Seed's titiler with NASA's Common Metadata Repository (CMR) as its backend: a tile request names a CMR collection by concept id and a time range, the server runs the granule search, and reads the granules' assets, GeoTIFFs with the rasterio backend or NetCDF and HDF5 with the xarray one. NASA VEDA runs a public instance at openveda.cloud/api/titiler-cmr, with a staging twin at staging.openveda.cloud; Development Seed's titiler-cmr browser is a front end on that same endpoint, configured for HLS and NISAR.
The data behind HLS lives at NASA's LP DAAC and needs an Earthdata login to read; the VEDA instance holds those credentials server-side, which is why the browser needs none. The instance is a demo of VEDA's, not an SLA.
The pill (lib/hls.ts) asks for one true-colour mosaic per date:
https://openveda.cloud/api/titiler-cmr/rasterio/tiles/WebMercatorQuad/{z}/{x}/{y}
?collection_concept_id=C2021957295-LPCLOUD HLSS30 v2.0, the Sentinel-2 half of HLS
&temporal=<date - 15 d>/<date + 15 d>
&assets=B04&assets=B03&assets=B02 red, green, blue
&rescale=0,3000 ×3 surface reflectance ×10000: the usual stretch
&color_formula=Gamma RGB 1.3 Saturation 1.5 Sigmoidal RGB 8 0.35- HLSS30, not HLSL30. The Sentinel-2 half revisits every 5 days against Landsat's 16, so a 30 day window nearly always has cloud-free pixels. Both halves are 30 m; the HLS algorithm resamples Sentinel-2 onto Landsat's grid, which is why "10 m Sentinel-2" is not what HLS gives.
- The window, not a date. A tile is whatever granules fall in the 30 days, in catalog order: no cloud filter and no cloud-first sort are sent today, titiler-cmr accepts
cloud_coverandsort_keyfor that. Scene seams show where two granules meet. - Ticks are synthetic. One a month from January 2016, the date at the middle of its own window; nothing checks that a granule exists at the view's centre. HLS exists from 2013 for the Landsat half; the ticks start where Sentinel-2 coverage is dense.
- Zoom. Served down to zoom 0, but a low-zoom tile means many granules read; the source is declared to zoom 16 and the tiles are 256 px.
Planetary Computer, behind the two World catalogs
Microsoft Planetary Computer keeps a STAC API over its catalog (Landsat Collection 2, Sentinel-2 L2A, NAIP, HLS 2.0, DEMs and more, the assets in Azure Blob Storage) and a data API that tiles it: titiler-pgstac behind planetarycomputer.microsoft.com/api/data/v1. Reading an asset normally needs a SAS token from the SAS API; the data API signs its own reads, so the browser sends none, and the register and tiles endpoints answer with an open CORS header.
A mosaic is a registered search:
POST /api/data/v1/mosaic/register
{ "collections": ["landsat-c2-l2"],
"datetime": "1990-04-01T00:00:00Z/1990-06-30T23:59:59Z",
"filter-lang": "cql2-json",
"filter": { "op": "<=", "args": [{ "property": "eo:cloud_cover" }, 10] },
"sortby": [{ "field": "eo:cloud_cover", "direction": "asc" }] }
→ { "searchid": "5dee14b3…" }
GET /api/data/v1/mosaic/5dee14b3…/tiles/WebMercatorQuad/{z}/{x}/{y}@1x.png
?assets=red&assets=green&assets=blue&nodata=0&collection=landsat-c2-l2
&color_formula=gamma RGB 2.7, saturation 1.5, sigmoidal RGB 15 0.55The search id is a hash of the search, so registering the same window again is free. For a tile the API lists the search's items that intersect it, in the sort order, and fills pixels from the first item that has data there (pixel_selection=first): the least cloudy scene wins where scenes overlap, and the scene edges, marked by nodata=0, let the next scene show through. That is a least-cloudy-scene mosaic, not the per-pixel median of a Timelapse year: seams follow Landsat paths and Sentinel-2 granules, and a scene that is 8 % cloudy brings its 8 % along. Below a zoom of 8 for Landsat and 9 for Sentinel-2 the API answers 204, empty, rather than read hundreds of scenes.
The protocol (lib/pc-mosaic.ts) exists because the registration is a POST, which a MapLibre tiles template cannot send:
pcmosaic://landsat-c2-l2/{z}/{x}/{y}?from=1990-04-01&to=1990-06-30
pcmosaic://sentinel-2-l2a/{z}/{x}/{y}?from=2024-08-01&to=2024-08-31- Two searches a window. Scenes with at most 10 % cloud first; when no such scene covers the tile (an overcast quarter, a rainy month: June 2024 over Paris has none) the handler registers the same window at 60 % and tries again, so the tile draws, cloudier, rather than stays blank. Both ids are cached for the session.
- Landsat is rendered from the
red,greenandbluesurface-reflectance assets with Planetary Computer's own "Natural color" formula, 30 m, declared to zoom 13. Landsat 4 TM's first scene is 22 August 1982; Landsat 1 to 5 MSS (1972 to 1992, 60 m, no blue band) sits inlandsat-c2-l1and is not offered. - Sentinel-2 uses the L2A product's own true-colour image, the
visualasset, 10 m, declared to zoom 15. Planetary Computer holds Level-2A from 2016 for most of the world, with 2015 scenes in places. - In the catalog (
lib/national-historical.ts) each window is a layer of acompletesource: every layer covers the globe, so the timeline lists them all without probing a tile at the view's centre. The Landsat catalog has a layer a quarter, the Sentinel-2 one a layer a month, and both sit under the Medium res pill. - Not in Export Multi. The export dialog lists the timeline's own pills; catalog layers, these included, are picked on the map.
Capture mosaics: one satellite pass from many COGs
The third kind has no tiler of its own and no search behind each tile. Maxar and Vantor Open Data publish one satellite pass (one catalog_id) as a grid of Cloud-Optimized GeoTIFFs about 5 km across, and NOAA a flight as frames, so the COG under the view centre alone stops at its own edge. Around Kahramanmaraş in 2023, single passes show as 30 COGs in a small search.
lib/capture-mosaic.ts draws them as one basemap, with one source for the tick:
capture://<catalog>|<date>|<catalog_id>/{z}/{x}/{y}- Grouping. The timeline's STAC search groups items by day and
catalog_id(then title or event) into one tick. A group of several gets a capture source; a single item stays a plain COG source. - Only what a tile touches. A map tile asks titiler for the COGs whose extent overlaps it, 1 to 4 once zoomed in, and composites the answers on a canvas in the browser, nearest COG on top. Only the map tiles in view cost anything, so no request goes out for the rest of the pass.
- A cap of 25 COGs. The nearest to the latest view, which keeps a low zoom over a long pass bounded.
- It grows with the view. Later searches add the COGs they find. A tile outside everything searched so far waits up to 3 s for the search of the new view; a tile inside it with no COG is simply empty.
- Seams. It is a mosaic of one pass, with no colour balancing: within a pass the seams are slight, since it is one sensor at one time.
The source is transient like every STAC tick: a shared link does not bring it back, since a catalog query would have to find it again.
What to expect of each
| NASA HLS | Planetary Computer Landsat | Planetary Computer Sentinel-2 | Google Earth Timelapse | |
|---|---|---|---|---|
| Pixel | 30 m | 30 m | 10 m | 30 m, 19 m from 2015 |
| From | 2016 (2013 for Landsat) | 1982 | 2016 | 1984 |
| Window | 30 days | a quarter | a month | a year |
| Cloud | none removed | least cloudy scene first | least cloudy scene first | per-pixel median, gap-filled |
| Seams | granule edges | scene edges | granule edges | none |
| First tile | a few seconds | 1 to 2 s, plus the registration | under a second | the video download |