Click examples on a map and similar spots light up, or define a few land cover classes and get a classification map, using satellite embeddings read directly from cloud storage. Everything is computed in your browser; there is no server.
Live site: https://shane98c.github.io/live-geoembeddings/
Clicks add a match (a circle) or, with the switch set to "Not a match" or Shift held, a spot that is not a match (an X). Cmd/Ctrl+Z undoes the last change. The year picker (2017-2025) switches both the embeddings and the Sentinel-2 imagery; aerial imagery is also available but is not matched to the year.
- Similar (default). Scores each pixel by its similarity to a search vector: the average of your matches, minus the average of the spots that are not a match times the not-a-match strength (default 0.25; a gentler form of geovibes' 2 x mean - mean). Scores are scaled so your matches average 1, and pixels above the match threshold are highlighted.
- Classify. Define a few classes (Forest, Water and Roads to start; rename them, recolor them, add your own) and click examples of each, plus spots that are not that class. Each class gets a search vector built as above, and every pixel takes the color of the class that scores it highest. Pixels that no class scores above the match threshold stay clear. The limit is six classes on most devices (see Rendering below).
- Colors. Three embedding dimensions as RGB.
Copy link encodes the clicks, their embeddings, the classes, the threshold and the view in the URL.
Both load at zoom 13 and closer; a laptop-sized view is roughly 125 MB of AlphaEarth or 400 MB of TESSERA.
- AlphaEarth Foundations (Google): 64 dimensions per 10 m pixel.
- TESSERA (University of Cambridge): 128 dimensions per 10 m pixel, stored per UTM zone. Similarity is the cosine of the raw int8 values, so the per-pixel scales are not needed.
- Loading. Embeddings are read from Zarr v3 stores on Source Cooperative with zarr-layer, a MapLibre custom layer.
- Rendering. A fragment shader scores every pixel on screen against the search vector, or against every class's vector. Clicks only change shader uniforms, so no data is refetched. The class vectors share one uniform array sized at compile time, and each slot costs fragment uniform vectors whether used or not, so the class limit is read from the device's budget at startup: six where WebGL2 reports the usual 1024 vectors, fewer where it reports less. A data texture would lift the limit, but zarr-layer's custom shaders cannot bind one yet.
| Data | Source | License |
|---|---|---|
| AlphaEarth embeddings, 2017-2025 | tge-labs/aef-mosaic | CC-BY 4.0, produced by Google and Google DeepMind |
| TESSERA embeddings, 2017-2025 | tessera/tessera | University of Cambridge |
| Sentinel-2 imagery, yearly | EOX Sentinel-2 cloudless (no 2017 mosaic; 2018 is shown) | CC BY-NC-SA 4.0, contains modified Copernicus Sentinel data |
| Aerial imagery | USGS The National Map | Public domain |
| Roads and place names | OpenFreeMap | © OpenMapTiles, OpenStreetMap (ODbL) |
npm install
npm run devPushes to main deploy to GitHub Pages.