diff --git a/CHANGELOG.md b/CHANGELOG.md index 8023905..f9ada3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,11 +11,13 @@ The format is based on Keep a Changelog, and the project follows Semantic Versio ## [0.1.1] - 2026-04-01 ### Added + - Automated pull request changelog enforcement with a `skip-changelog` escape hatch for docs, tests, CI, and other internal-only changes. - Tag-driven GitHub Release publishing that uses the matching `CHANGELOG.md` section as the release notes. - Trusted Publishing release automation for PyPI and TestPyPI, including a manual TestPyPI dry run and install smoke test. ### Changed + - The contribution and release workflow now treats `CHANGELOG.md` as the canonical source for user-visible release notes. - The tag-triggered release flow now validates `src/rs_embed/_version.py`, publishes to PyPI, and only then creates the GitHub Release. - The tag-triggered release flow now validates the matching `CHANGELOG.md` entry before publishing to PyPI, so a missing release-notes section fails early instead of after package upload. @@ -27,11 +29,13 @@ The format is based on Keep a Changelog, and the project follows Semantic Versio ### Removed ### Fixed + - The TestPyPI smoke test now verifies package importability and the `rs-embed` CLI entry point, not just installability and version metadata. ## [0.1.0] - 2026-03-31 ### Added + - Initial public alpha release of `rs-embed`. - Unified ROI to embedding API centered on `get_embedding(...)`, `get_embeddings_batch(...)`, `export_batch(...)`, and `inspect_provider_patch(...)`. - Support for precomputed embedding products including `tessera`, `gse`, and `copernicus`. diff --git a/README.md b/README.md index 269d550..890709e 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@
-# icon rs-embed -**One line code to get Any Remote Sensing Foundation Model (RSFM) embeddings for Any Place and Any Time** +# icon rs-embed +**One line code to get Any Remote Sensing Foundation Model (RSFM) embeddings for Any Place and Any Time** [![arXiv](https://img.shields.io/badge/arXiv-2602.23678-b31b1b.svg)](https://arxiv.org/abs/2602.23678) [![Docs](https://img.shields.io/badge/docs-online-brightgreen)](https://cybergis.github.io/rs-embed/) @@ -13,18 +13,13 @@ ![Last Commit](https://img.shields.io/github/last-commit/cybergis/rs-embed) ![License](https://img.shields.io/github/license/cybergis/rs-embed) - - [Docs](https://cybergis.github.io/rs-embed/) · [Releases](https://github.com/cybergis/rs-embed/releases) · [Changelog](https://github.com/cybergis/rs-embed/blob/main/CHANGELOG.md) · [StartNow](https://github.com/cybergis/rs-embed/blob/main/examples/playground.ipynb) · [UseCase](https://github.com/cybergis/rs-embed/blob/main/examples/demo.ipynb) · [Paper](https://arxiv.org/abs/2602.23678)
> Get Start on [I-GUIDE](https://platform.i-guide.io/notebooks/a013ce97-d963-4262-9f21-edd09976181a) Today! - - - - + ## TL;DR @@ -32,7 +27,6 @@ emb = get_embedding("prithvi", spatial=..., temporal=..., output=...) ``` - ## Install ```bash @@ -51,15 +45,14 @@ cd rs-embed pip install -e . # use -e ".[terratorch]" if you need terramind ``` - If this is your first time using Google Earth Engine, authenticate once: ```bash earthengine authenticate ``` - ## Quick Example + ```python from rs_embed import PointBuffer, TemporalSpec, OutputSpec, get_embedding @@ -83,7 +76,7 @@ See the visualization helper and end-to-end notebook in the repository: - [`examples/plot_utils.py`](https://github.com/cybergis/rs-embed/blob/main/examples/plot_utils.py) - [`examples/playground.ipynb`](https://github.com/cybergis/rs-embed/blob/main/examples/playground.ipynb) - + ## Main API @@ -94,45 +87,41 @@ For new users, start with these primary APIs: - `export_batch(...)`: export datasets / experiments (single or multiple ROIs) - `inspect_provider_patch(...)`: inspect raw provider patches before inference - ## Supported Models This is a convenience index with basic model info only (for quick scanning / links). For detailed I/O behavior and preprocessing notes, see [Supported Models](https://cybergis.github.io/rs-embed/models/). ### Precomputed Embeddings -| Model ID | Resolution | Time Coverage | Publication | -|---|---|---|---| -|`tessera` | 10m | 2017-2025 |[CVPR 2026](https://arxiv.org/abs/2506.20380v4)| -|`gse` (Alpha Earth) | 10 m | 2017-2024 |[arXiv 2025](https://arxiv.org/abs/2507.22291)| -| `copernicus` | 0.25° | 2021 |[ICCV 2025](https://arxiv.org/abs/2503.11849)| +| Model ID | Resolution | Time Coverage | Publication | +| ------------------- | ---------- | ------------- | ----------------------------------------------- | +| `tessera` | 10m | 2017-2025 | [CVPR 2026](https://arxiv.org/abs/2506.20380v4) | +| `gse` (Alpha Earth) | 10 m | 2017-2024 | [arXiv 2025](https://arxiv.org/abs/2507.22291) | +| `copernicus` | 0.25° | 2021 | [ICCV 2025](https://arxiv.org/abs/2503.11849) | ### On-the-fly Foundation Models -| Model ID | Primary Input | Resolution(Default) | Publication | Link | -|---|---|---|---|---| -| `satmae` | S2 RGB | 10m | [NeurIPS 2022](https://arxiv.org/abs/2207.08051) |[link](https://github.com/sustainlab-group/SatMAE)| -| `satmaepp` | S2 RGB | 10m | [CVPR 2024](https://arxiv.org/abs/2403.05419) | [link](https://github.com/techmn/satmae_pp) | -| `satmaepp_s2_10b` | S2 SR 10-band | 10m | [CVPR 2024](https://arxiv.org/abs/2403.05419) | [link](https://github.com/techmn/satmae_pp) | -| `prithvi` | S2 6-band | 30m | [arXiv 2023](https://arxiv.org/abs/2310.18660) | [link](https://huggingface.co/ibm-nasa-geospatial) | -| `scalemae` | S2 RGB (+ scale) | 10m | [ICCV 2023](https://arxiv.org/abs/2212.14532) | [link](https://github.com/bair-climate-initiative/scale-mae) | -| `remoteclip` | S2 RGB | 10m | [TGRS 2024](https://arxiv.org/abs/2306.11029) |[link](https://github.com/ChenDelong1999/RemoteCLIP) | -| `dofa` | Multi-band + wavelengths | 10m | [arXiv 2024](https://arxiv.org/abs/2403.15356) | [link](https://github.com/zhu-xlab/DOFA) | -| `satvision` | TOA 14-channel | 1000m | [arXiv 2024](https://arxiv.org/abs/2411.17000) | [link](https://github.com/nasa-nccs-hpda/pytorch-caney)| -| `anysat` | S2 time series (10-band) | 10m | [CVPR 2025](https://arxiv.org/abs/2412.14123) | [link](https://github.com/gastruc/AnySat) | -| `galileo` | S2 time series (10-band) | 10m | [ICML 2025](https://arxiv.org/abs/2502.09356) | [link](https://github.com/nasaharvest/galileo) | -| `wildsat` | S2 RGB | 10m | [ICCV 2025](https://arxiv.org/abs/2412.14428) | [link](https://github.com/mdchuc/HRSFM) | -| `fomo` | S2 12-band | 10m | [AAAI 2025](https://arxiv.org/abs/2312.10114) |[link](https://github.com/RolnickLab/FoMo-Bench)| -| `terramind` | S2 12-band | 10m | [ICCV 2025](https://arxiv.org/abs/2504.11171) | [link](https://github.com/IBM/terramind) | -| `terrafm` | S2 12-band / S1 VV-VH | 10m | [ICLR 2026](https://arxiv.org/abs/2506.06281) | [link](https://github.com/mbzuai-oryx/TerraFM) | -| `thor` | S2 10-band | 10m | [arXiv 2026](https://arxiv.org/abs/2601.16011) | [link](https://github.com/FM4CS/THOR) | -| `agrifm` | S2 time series (10-band) | 10m | [RSE 2026](https://www.sciencedirect.com/science/article/pii/S0034425726000040) | [link](https://github.com/flyakon/AgriFM) | +| Model ID | Primary Input | Resolution(Default) | Publication | Link | +| ----------------- | ------------------------ | ------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------ | +| `satmae` | S2 RGB | 10m | [NeurIPS 2022](https://arxiv.org/abs/2207.08051) | [link](https://github.com/sustainlab-group/SatMAE) | +| `satmaepp` | S2 RGB | 10m | [CVPR 2024](https://arxiv.org/abs/2403.05419) | [link](https://github.com/techmn/satmae_pp) | +| `satmaepp_s2_10b` | S2 SR 10-band | 10m | [CVPR 2024](https://arxiv.org/abs/2403.05419) | [link](https://github.com/techmn/satmae_pp) | +| `prithvi` | S2 6-band | 30m | [arXiv 2023](https://arxiv.org/abs/2310.18660) | [link](https://huggingface.co/ibm-nasa-geospatial) | +| `scalemae` | S2 RGB (+ scale) | 10m | [ICCV 2023](https://arxiv.org/abs/2212.14532) | [link](https://github.com/bair-climate-initiative/scale-mae) | +| `remoteclip` | S2 RGB | 10m | [TGRS 2024](https://arxiv.org/abs/2306.11029) | [link](https://github.com/ChenDelong1999/RemoteCLIP) | +| `dofa` | Multi-band + wavelengths | 10m | [arXiv 2024](https://arxiv.org/abs/2403.15356) | [link](https://github.com/zhu-xlab/DOFA) | +| `satvision` | TOA 14-channel | 1000m | [arXiv 2024](https://arxiv.org/abs/2411.17000) | [link](https://github.com/nasa-nccs-hpda/pytorch-caney) | +| `anysat` | S2 time series (10-band) | 10m | [CVPR 2025](https://arxiv.org/abs/2412.14123) | [link](https://github.com/gastruc/AnySat) | +| `galileo` | S2 time series (10-band) | 10m | [ICML 2025](https://arxiv.org/abs/2502.09356) | [link](https://github.com/nasaharvest/galileo) | +| `wildsat` | S2 RGB | 10m | [ICCV 2025](https://arxiv.org/abs/2412.14428) | [link](https://github.com/mdchuc/HRSFM) | +| `fomo` | S2 12-band | 10m | [AAAI 2025](https://arxiv.org/abs/2312.10114) | [link](https://github.com/RolnickLab/FoMo-Bench) | +| `terramind` | S2 12-band | 10m | [ICCV 2025](https://arxiv.org/abs/2504.11171) | [link](https://github.com/IBM/terramind) | +| `terrafm` | S2 12-band / S1 VV-VH | 10m | [ICLR 2026](https://arxiv.org/abs/2506.06281) | [link](https://github.com/mbzuai-oryx/TerraFM) | +| `thor` | S2 10-band | 10m | [arXiv 2026](https://arxiv.org/abs/2601.16011) | [link](https://github.com/FM4CS/THOR) | +| `agrifm` | S2 time series (10-band) | 10m | [RSE 2026](https://www.sciencedirect.com/science/article/pii/S0034425726000040) | [link](https://github.com/flyakon/AgriFM) | Resolution here means the default provider/source fetch resolution used by the adapter, not the final resized tensor shape seen by the model. - - - ## Learn More 📚 [Full documentation](https://cybergis.github.io/rs-embed/) @@ -145,37 +134,35 @@ Resolution here means the default provider/source fetch resolution used by the a 🪀 [Use case: Maize yield mapping Illinois](https://github.com/cybergis/rs-embed/blob/main/examples/demo.ipynb) - ## Extending & Contributing We welcome issues for new model integrations, extension ideas, bugs, and documentation gaps. If you have your own work, or a model or paper that you think would be valuable to include in `rs-embed`, please open an [Issue](https://github.com/cybergis/rs-embed/issues) and share the relevant links, context, and examples. -We also warmly welcome community contributions, including new model support, bug fixes, documentation improvements, and example notebooks. If you would like to contribute directly, please start with the [`extending`](https://cybergis.github.io/rs-embed/extending/) guide and the [contributing guide](https://cybergis.github.io/rs-embed/contributing/). - - +We also warmly welcome community contributions, including new model support, bug fixes, documentation improvements, and example notebooks. If you would like to contribute directly, please start with the [`extending`](https://cybergis.github.io/rs-embed/extending/) guide and the [contributing guide](https://cybergis.github.io/rs-embed/contributing/). ## 🎖 Acknowledgements + We would like to thank the following organizations and projects that make rs-embed possible: [Google Earth Engine](https://earthengine.google.com), [TorchGeo](https://github.com/torchgeo/torchgeo), [GeoTessera](https://github.com/ucam-eo/geotessera), [TerraTorch](https://github.com/terrastackai/terratorch), [rshf](https://github.com/mvrl/rshf), and the [Copernicus-Embed](https://huggingface.co/datasets/torchgeo/copernicus_embed). This library also builds upon the incredible work of the Remote Sensing community!(Full list and citations available in our Documentation) ## Citation + ``` @article{ye2026modelplacetimeremote, - title={Any Model, Any Place, Any Time: Get Remote Sensing Foundation Model Embeddings On Demand}, + title={Any Model, Any Place, Any Time: Get Remote Sensing Foundation Model Embeddings On Demand}, author={Dingqi Ye and Daniel Kiv and Wei Hu and Jimeng Shi and Shaowen Wang}, year={2026}, eprint={2602.23678}, archivePrefix={arXiv}, primaryClass={cs.CV}, - url={https://arxiv.org/abs/2602.23678}, + url={https://arxiv.org/abs/2602.23678}, } ``` - ## License -This project is released under the [Apache-2.0](https://github.com/cybergis/rs-embed/blob/main/LICENSE) +This project is released under the [Apache-2.0](https://github.com/cybergis/rs-embed/blob/main/LICENSE) ## Contributors diff --git a/docs/api.md b/docs/api.md index 6d832dc..0a5c47b 100644 --- a/docs/api.md +++ b/docs/api.md @@ -13,14 +13,15 @@ Most users only need four public entry points: `get_embedding(...)`, `get_embedd ## Choose by Task -| I want to... | Read this page | -|---|---| -| understand spatial/temporal/output specs | [API: Specs and Data Structures](api_specs.md) | -| get one embedding or batch embeddings | [API: Embedding](api_embedding.md) | -| build export pipelines and datasets | [API: Export](api_export.md) | -| inspect raw provider patches before inference | [API: Inspect](api_inspect.md) | +| I want to... | Read this page | +| --------------------------------------------- | ---------------------------------------------- | +| understand spatial/temporal/output specs | [API: Specs and Data Structures](api_specs.md) | +| get one embedding or batch embeddings | [API: Embedding](api_embedding.md) | +| build export pipelines and datasets | [API: Export](api_export.md) | +| inspect raw provider patches before inference | [API: Inspect](api_inspect.md) | --- + ## Useful Extras `export_npz(...)` is a compatibility wrapper around `export_batch(...)` for single-ROI `.npz`, `inspect_gee_patch(...)` is the older GEE-focused name for `inspect_provider_patch(...)`, and `list_models()` is the stable public helper for inspecting the model catalog. diff --git a/docs/api_embedding.md b/docs/api_embedding.md index e1c28c2..939db63 100644 --- a/docs/api_embedding.md +++ b/docs/api_embedding.md @@ -2,7 +2,6 @@ This page covers single-ROI and batch embedding APIs. - Related pages: [API: Specs and Data Structures](api_specs.md), [API: Export](api_export.md), and [API: Inspect](api_inspect.md). --- @@ -55,30 +54,30 @@ Computes the embedding for a single ROI. Core inputs: -| Parameter | Meaning | -|---|---| -| `model` | Model ID. See [Supported Models](models.md) or call `rs_embed.list_models()`. | -| `spatial` | `BBox` or `PointBuffer`. | -| `temporal` | `TemporalSpec` or `None`. The parameter is optional at the API level, but some models or data sources still require it. | -| `sensor` | Full input descriptor for on-the-fly models. Most precomputed models can leave this as `None`. When provided, it overrides source-level details such as collection, bands, scale, and compositing. | -| `fetch` | Lightweight sampling override for common cases such as `scale_m`, `cloudy_pct`, `composite`, and `fill_value`. It is applied on top of the model's resolved default sensor and cannot be combined with `sensor`. | -| `output` | Usually `OutputSpec.pooled()` or `OutputSpec.grid(...)`. | +| Parameter | Meaning | +| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `model` | Model ID. See [Supported Models](models.md) or call `rs_embed.list_models()`. | +| `spatial` | `BBox` or `PointBuffer`. | +| `temporal` | `TemporalSpec` or `None`. The parameter is optional at the API level, but some models or data sources still require it. | +| `sensor` | Full input descriptor for on-the-fly models. Most precomputed models can leave this as `None`. When provided, it overrides source-level details such as collection, bands, scale, and compositing. | +| `fetch` | Lightweight sampling override for common cases such as `scale_m`, `cloudy_pct`, `composite`, and `fill_value`. It is applied on top of the model's resolved default sensor and cannot be combined with `sensor`. | +| `output` | Usually `OutputSpec.pooled()` or `OutputSpec.grid(...)`. | Runtime and branch selection: -| Parameter | Meaning | -|---|---| -| `modality` | Optional model-facing modality selector such as `s1`, `s2`, or `s2_l2a` for models that expose multiple branches. The API normalizes common aliases such as `sentinel-1 -> s1` and `sentinel-2 -> s2`. | -| `backend` | Access backend. `backend="auto"` is the public default and the recommended choice. Precomputed models typically expect `auto`, while provider-backed on-the-fly paths commonly use `gee` through the auto resolver. | -| `device` | `"auto"`, `"cpu"`, or `"cuda"` for torch-backed models. | -| `input_prep` | `"resize"` (default), `"tile"`, `"auto"`, `InputPrepSpec(...)`, or `None`. `None` is treated like the default resize path. | +| Parameter | Meaning | +| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `modality` | Optional model-facing modality selector such as `s1`, `s2`, or `s2_l2a` for models that expose multiple branches. The API normalizes common aliases such as `sentinel-1 -> s1` and `sentinel-2 -> s2`. | +| `backend` | Access backend. `backend="auto"` is the public default and the recommended choice. Precomputed models typically expect `auto`, while provider-backed on-the-fly paths commonly use `gee` through the auto resolver. | +| `device` | `"auto"`, `"cpu"`, or `"cuda"` for torch-backed models. | +| `input_prep` | `"resize"` (default), `"tile"`, `"auto"`, `InputPrepSpec(...)`, or `None`. `None` is treated like the default resize path. | Model-specific settings: -| Parameter | Meaning | -|---|---| -| `variant` | Common model-specific selector passed through `**model_kwargs`, for example `variant="large"` or `variant="base"`. Only models that declare variant support accept it. | -| `**model_kwargs` | Model-specific settings passed directly as keyword arguments, such as `variant="large"`. Accepted keys depend on the model. | +| Parameter | Meaning | +| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `variant` | Common model-specific selector passed through `**model_kwargs`, for example `variant="large"` or `variant="base"`. Only models that declare variant support accept it. | +| `**model_kwargs` | Model-specific settings passed directly as keyword arguments, such as `variant="large"`. Accepted keys depend on the model. | #### Rules And Contracts @@ -153,30 +152,30 @@ Batch-computes embeddings for multiple ROIs using the same embedder instance (of Core inputs: -| Parameter | Meaning | -|---|---| -| `model` | Model ID. See [Supported Models](models.md) or call `rs_embed.list_models()`. | -| `spatials` | Non-empty `List[SpatialSpec]`. Each item is a `BBox` or `PointBuffer`. Output order matches input order. | -| `temporal` | `TemporalSpec` or `None`. The parameter is optional at the API level, but some models or data sources still require it. | -| `sensor` | Full input descriptor for on-the-fly models. Most precomputed models can leave this as `None`. When provided, it overrides source-level details such as collection, bands, scale, and compositing. | -| `fetch` | Lightweight sampling override for common cases such as `scale_m`, `cloudy_pct`, `composite`, and `fill_value`. It is applied on top of the model's resolved default sensor and cannot be combined with `sensor`. | -| `output` | Usually `OutputSpec.pooled()` or `OutputSpec.grid(...)`. | +| Parameter | Meaning | +| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `model` | Model ID. See [Supported Models](models.md) or call `rs_embed.list_models()`. | +| `spatials` | Non-empty `List[SpatialSpec]`. Each item is a `BBox` or `PointBuffer`. Output order matches input order. | +| `temporal` | `TemporalSpec` or `None`. The parameter is optional at the API level, but some models or data sources still require it. | +| `sensor` | Full input descriptor for on-the-fly models. Most precomputed models can leave this as `None`. When provided, it overrides source-level details such as collection, bands, scale, and compositing. | +| `fetch` | Lightweight sampling override for common cases such as `scale_m`, `cloudy_pct`, `composite`, and `fill_value`. It is applied on top of the model's resolved default sensor and cannot be combined with `sensor`. | +| `output` | Usually `OutputSpec.pooled()` or `OutputSpec.grid(...)`. | Runtime and branch selection: -| Parameter | Meaning | -|---|---| -| `modality` | Optional model-facing modality selector such as `s1`, `s2`, or `s2_l2a` for models that expose multiple branches. The API normalizes common aliases such as `sentinel-1 -> s1` and `sentinel-2 -> s2`. | -| `backend` | Access backend. `backend="auto"` is the public default and the recommended choice. Precomputed models typically expect `auto`, while provider-backed on-the-fly paths commonly use `gee` through the auto resolver. | -| `device` | `"auto"`, `"cpu"`, or `"cuda"` for torch-backed models. | -| `input_prep` | `"resize"` (default), `"tile"`, `"auto"`, `InputPrepSpec(...)`, or `None`. `None` is treated like the default resize path. | +| Parameter | Meaning | +| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `modality` | Optional model-facing modality selector such as `s1`, `s2`, or `s2_l2a` for models that expose multiple branches. The API normalizes common aliases such as `sentinel-1 -> s1` and `sentinel-2 -> s2`. | +| `backend` | Access backend. `backend="auto"` is the public default and the recommended choice. Precomputed models typically expect `auto`, while provider-backed on-the-fly paths commonly use `gee` through the auto resolver. | +| `device` | `"auto"`, `"cpu"`, or `"cuda"` for torch-backed models. | +| `input_prep` | `"resize"` (default), `"tile"`, `"auto"`, `InputPrepSpec(...)`, or `None`. `None` is treated like the default resize path. | Model-specific settings: -| Parameter | Meaning | -|---|---| -| `variant` | Common model-specific selector passed through `**model_kwargs`, for example `variant="large"` or `variant="base"`. Only models that declare variant support accept it. | -| `**model_kwargs` | Model-specific settings passed directly as keyword arguments, such as `variant="large"`. Accepted keys depend on the model. | +| Parameter | Meaning | +| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `variant` | Common model-specific selector passed through `**model_kwargs`, for example `variant="large"` or `variant="base"`. Only models that declare variant support accept it. | +| `**model_kwargs` | Model-specific settings passed directly as keyword arguments, such as `variant="large"`. Accepted keys depend on the model. | #### Rules And Contracts diff --git a/docs/api_export.md b/docs/api_export.md index 26d5205..6c7de2d 100644 --- a/docs/api_export.md +++ b/docs/api_export.md @@ -71,11 +71,11 @@ That gives you one combined export artifact in the default `.npz` format, includ ### 1. Required dataset definition -| Parameter | Meaning | -|---|---| -| `spatials` | Non-empty list of `BBox` or `PointBuffer`. | +| Parameter | Meaning | +| ---------- | ----------------------------------------------------------------------------------------------------------------------- | +| `spatials` | Non-empty list of `BBox` or `PointBuffer`. | | `temporal` | `TemporalSpec` or `None`. The parameter is optional at the API level, but some models or data sources still require it. | -| `models` | Non-empty list of model IDs or `ExportModelRequest(...)`. | +| `models` | Non-empty list of model IDs or `ExportModelRequest(...)`. | ### 2. Output location and layout @@ -96,14 +96,14 @@ For `combined`, the output extension is normalized from `config.format` if missi These usually apply to all models in the call: -| Setting | Typical use | -|---|---| -| `backend` | Keep `backend="auto"` unless you need a specific provider such as `"gee"`. | -| `device` | `"auto"` is the normal choice. | -| `output` | Usually `OutputSpec.pooled()`. | -| `fetch` | Shared `FetchSpec` for resolution or compositing overrides. | -| `sensor` | Shared `SensorSpec` for advanced on-the-fly source overrides. | -| `modality` | Shared modality override for models that expose multiple public branches. | +| Setting | Typical use | +| ---------- | -------------------------------------------------------------------------- | +| `backend` | Keep `backend="auto"` unless you need a specific provider such as `"gee"`. | +| `device` | `"auto"` is the normal choice. | +| `output` | Usually `OutputSpec.pooled()`. | +| `fetch` | Shared `FetchSpec` for resolution or compositing overrides. | +| `sensor` | Shared `SensorSpec` for advanced on-the-fly source overrides. | +| `modality` | Shared modality override for models that expose multiple public branches. | Use per-model overrides only when one model needs different settings. @@ -125,14 +125,14 @@ If both are provided, inline values on `ExportModelRequest(...)` take precedence The most important ones are: -| Option | Meaning | -|---|---| -| `format` | `"npz"` or `"netcdf"`. | -| `save_inputs` | Save model-ready input patches. | -| `save_embeddings` | Save embedding arrays. | -| `save_manifest` | Save JSON manifest metadata. | -| `resume` | Skip items already exported. | -| `input_prep` | Large-ROI policy, usually `"resize"` or `"tile"`. | +| Option | Meaning | +| ----------------- | ------------------------------------------------- | +| `format` | `"npz"` or `"netcdf"`. | +| `save_inputs` | Save model-ready input patches. | +| `save_embeddings` | Save embedding arrays. | +| `save_manifest` | Save JSON manifest metadata. | +| `resume` | Skip items already exported. | +| `input_prep` | Large-ROI policy, usually `"resize"` or `"tile"`. | You can usually ignore the rest until you need performance tuning or failure recovery. @@ -329,7 +329,7 @@ Model scheduling is serial, so one model runs at a time. Batch inference is used If provider-backed export is used and both `save_inputs=True` and `save_embeddings=True`, rs-embed reuses the fetched input patch for both writing and embedding inference instead of downloading it twice. !!! tip "Simple rule" - Start with `ExportTarget.combined(...)` + `ExportConfig()`. - Add `ExportModelRequest.configure(...)` only for the few models that need per-model sensor, fetch, modality, or variant overrides. +Start with `ExportTarget.combined(...)` + `ExportConfig()`. +Add `ExportModelRequest.configure(...)` only for the few models that need per-model sensor, fetch, modality, or variant overrides. --- diff --git a/docs/api_specs.md b/docs/api_specs.md index 68125ac..b498cfa 100644 --- a/docs/api_specs.md +++ b/docs/api_specs.md @@ -58,7 +58,7 @@ TemporalSpec.range("2022-06-01", "2022-09-01") ``` !!! warning "Temporal range is a window" - `TemporalSpec.range(start, end)` is treated as a half-open interval `[start, end)`, so `end` is excluded. +`TemporalSpec.range(start, end)` is treated as a half-open interval `[start, end)`, so `end` is excluded. Temporal semantics in provider and on-the-fly paths: `TemporalSpec.range(start, end)` is interpreted as a half-open window `[start, end)`, so `end` is excluded. In GEE-backed fetch paths, that window is used to filter an image collection and then apply a compositing reducer such as `median` or `mosaic`. The fetched input is therefore usually a composite over the whole window rather than an automatically selected single-day scene. If you want to approximate a single-day query, use a one-day window such as `TemporalSpec.range("2022-06-01", "2022-06-02")`. @@ -87,27 +87,27 @@ SensorSpec( ) ``` -| Field | Meaning | -|---|---| -| `collection` | GEE collection or image ID. | -| `bands` | Band names as a tuple. | -| `scale_m` | Sampling resolution in meters. | -| `cloudy_pct` | Best-effort cloud filter, subject to collection properties. | -| `fill_value` | No-data fill value. | -| `composite` | Temporal compositing method, usually `median` or `mosaic`. | -| `modality` | Optional model-facing modality selector for models with multiple branches. | -| `orbit` | Optional orbit or pass filter for sensor families that support it. | -| `use_float_linear` | Selects linear-scale floating-point products when a sensor family offers both linear and dB variants. | -| `s1_require_iw` | Prefer Sentinel-1 `IW` scenes only on provider-backed S1 fetch paths. | -| `s1_relax_iw_on_empty` | Retry without the `IW` filter when strict S1 `IW` fetch returns no imagery. | -| `check_*` | Optional input checks and quicklook saving; see [API: Inspect](api_inspect.md#inspect_gee_patch). | +| Field | Meaning | +| ---------------------- | ----------------------------------------------------------------------------------------------------- | +| `collection` | GEE collection or image ID. | +| `bands` | Band names as a tuple. | +| `scale_m` | Sampling resolution in meters. | +| `cloudy_pct` | Best-effort cloud filter, subject to collection properties. | +| `fill_value` | No-data fill value. | +| `composite` | Temporal compositing method, usually `median` or `mosaic`. | +| `modality` | Optional model-facing modality selector for models with multiple branches. | +| `orbit` | Optional orbit or pass filter for sensor families that support it. | +| `use_float_linear` | Selects linear-scale floating-point products when a sensor family offers both linear and dB variants. | +| `s1_require_iw` | Prefer Sentinel-1 `IW` scenes only on provider-backed S1 fetch paths. | +| `s1_relax_iw_on_empty` | Retry without the `IW` filter when strict S1 `IW` fetch returns no imagery. | +| `check_*` | Optional input checks and quicklook saving; see [API: Inspect](api_inspect.md#inspect_gee_patch). | !!! note - For **precomputed** models (e.g., directly reading offline embedding products), `sensor` is usually ignored or set to `None`. +For **precomputed** models (e.g., directly reading offline embedding products), `sensor` is usually ignored or set to `None`. !!! note - Public embedding/export APIs also accept a top-level `modality=...` convenience argument. - When provided, rs-embed resolves it into the model's sensor/input contract and validates that the model explicitly supports that modality. +Public embedding/export APIs also accept a top-level `modality=...` convenience argument. +When provided, rs-embed resolves it into the model's sensor/input contract and validates that the model explicitly supports that modality. ### FetchSpec @@ -123,12 +123,12 @@ FetchSpec( ) ``` -| Field | Meaning | -|---|---| -| `scale_m` | Sampling resolution override. | -| `cloudy_pct` | Cloud filter override. | -| `fill_value` | No-data fill override. | -| `composite` | Temporal compositing override. | +| Field | Meaning | +| ------------ | ------------------------------ | +| `scale_m` | Sampling resolution override. | +| `cloudy_pct` | Cloud filter override. | +| `fill_value` | No-data fill override. | +| `composite` | Temporal compositing override. | Recommended rule: use `fetch=FetchSpec(...)` for normal public API usage. Use `sensor=SensorSpec(...)` only when you need advanced control over `collection`, `bands`, `modality`, or similar source-level details. @@ -153,7 +153,6 @@ emb = get_embedding( `OutputSpec` controls the embedding output shape: a **pooled vector** or a **dense grid**. - ```python OutputSpec( mode: Literal["grid", "pooled"], @@ -180,12 +179,10 @@ OutputSpec( Sampling resolution is no longer configured on `OutputSpec`. Use `fetch=FetchSpec(scale_m=...)` for resolution overrides. - #### `pooled` > ROI-level Vector Embedding - `pooled` represents one whole ROI (Region of Interest) using a single vector `(D,)`. Best suited for classification, retrieval, clustering, and most cross-model comparison work. The out put shape is: @@ -212,10 +209,9 @@ $$ v_d = \frac{1}{HW} \sum_{y,x} g_{d,y,x} $$ - #### `grid` -> ROI-level Spatial Embedding Field +> ROI-level Spatial Embedding Field `grid` returns a spatial embedding field `(D, H, W)`, where each spatial location maps to a vector. @@ -226,7 +222,7 @@ Embedding.data.shape == (D, H, W) ``` !!! note - `data` can be returned as `xarray.DataArray`, with metadata in `meta` or `attrs`. For precomputed geospatial products, that metadata may include CRS and crop context. For ViT token grids, it usually describes patch-grid structure rather than georeferenced pixel coordinates. +`data` can be returned as `xarray.DataArray`, with metadata in `meta` or `attrs`. For precomputed geospatial products, that metadata may include CRS and crop context. For ViT token grids, it usually describes patch-grid structure rather than georeferenced pixel coordinates. How `grid` is produced: @@ -238,7 +234,8 @@ How `grid` is produced: --- -### InputPrepSpec +### InputPrepSpec + > Optional Large-ROI Input Policy `InputPrepSpec` controls API-level handling of large on-the-fly inputs before model inference. @@ -279,7 +276,6 @@ Tile size defaults to `embedder.describe()["defaults"]["image_size"]` when avail - --- ### ExportTarget / ExportConfig / ExportModelRequest @@ -342,19 +338,19 @@ This is the main metadata users should inspect across the public embedding APIs. All built-in embedders now share the same minimum `Embedding.meta` contract. These fields should always be present, even when a specific model has little to say for one of them: -| Field | Meaning | -|---|---| -| `model` | Model identifier that produced the embedding. | -| `type` | Execution family such as `precomputed` or `on_the_fly`. | -| `backend` | Backend used at runtime, such as `auto` or `gee`. | -| `source` | Source dataset, collection, or checkpoint family used by the embedder. | -| `sensor` | Effective sensor metadata attached to the returned embedding. | -| `temporal` | Serialized temporal request as interpreted by the embedder. | -| `image_size` | Model input image size when the embedder records it. | -| `pooling` | Pooling semantics for pooled outputs, such as `token_mean`, `patch_mean`, or `mean_hw`. | -| `grid_hw` | Grid height and width for grid outputs in model feature space. | -| `cls_removed` | Whether a CLS token was removed before pooling or grid reshaping. | -| `input_prep` | API-side input preprocessing metadata, for example whether the request resolved to `resize`, `tile`, or `auto -> tile`. | +| Field | Meaning | +| ------------- | ----------------------------------------------------------------------------------------------------------------------- | +| `model` | Model identifier that produced the embedding. | +| `type` | Execution family such as `precomputed` or `on_the_fly`. | +| `backend` | Backend used at runtime, such as `auto` or `gee`. | +| `source` | Source dataset, collection, or checkpoint family used by the embedder. | +| `sensor` | Effective sensor metadata attached to the returned embedding. | +| `temporal` | Serialized temporal request as interpreted by the embedder. | +| `image_size` | Model input image size when the embedder records it. | +| `pooling` | Pooling semantics for pooled outputs, such as `token_mean`, `patch_mean`, or `mean_hw`. | +| `grid_hw` | Grid height and width for grid outputs in model feature space. | +| `cls_removed` | Whether a CLS token was removed before pooling or grid reshaping. | +| `input_prep` | API-side input preprocessing metadata, for example whether the request resolved to `resize`, `tile`, or `auto -> tile`. | Model-specific adapters can still attach additional keys beyond this stable base, such as checkpoint IDs, normalization details, token counts, frame counts, CRS hints, crop provenance, or modality-specific runtime flags. @@ -379,11 +375,11 @@ print(emb.meta.get("sensor")) These two metadata surfaces are related, but they serve different purposes: -| Surface | When you read it | What it means | -|---|---|---| -| `Embedding.meta` | After inference | Runtime result metadata for one concrete output | -| `describe_model(model)` | Before inference | Static capability metadata for a model class | -| `Model.describe()` | After constructing `Model(...)`, before or after inference | The same capability metadata, accessed from the model instance | +| Surface | When you read it | What it means | +| ----------------------- | ---------------------------------------------------------- | -------------------------------------------------------------- | +| `Embedding.meta` | After inference | Runtime result metadata for one concrete output | +| `describe_model(model)` | Before inference | Static capability metadata for a model class | +| `Model.describe()` | After constructing `Model(...)`, before or after inference | The same capability metadata, accessed from the model instance | Use `Embedding.meta` when you want to interpret a returned embedding. @@ -395,16 +391,16 @@ Use `describe_model()` or `Model.describe()` when you want to inspect what a mod A typical `describe()` result contains fields such as: -| Field | Meaning | -|---|---| -| `type` | Whether the model is `precomputed` or `on_the_fly`. | -| `backend` | Supported backends or backend family. | -| `inputs` | Default provider-facing input contract, often collection and bands. | -| `temporal` | Supported temporal mode such as `year` or `range`. | -| `output` | Supported output modes such as `pooled` and `grid`. | -| `defaults` | Default runtime knobs such as `scale_m`, `cloudy_pct`, `composite`, or `image_size`. | -| `modalities` | Optional modality-specific branches for multi-branch models. | -| `model_config` | Machine-readable schema for supported model-specific kwargs such as `variant`. | +| Field | Meaning | +| -------------- | ------------------------------------------------------------------------------------ | +| `type` | Whether the model is `precomputed` or `on_the_fly`. | +| `backend` | Supported backends or backend family. | +| `inputs` | Default provider-facing input contract, often collection and bands. | +| `temporal` | Supported temporal mode such as `year` or `range`. | +| `output` | Supported output modes such as `pooled` and `grid`. | +| `defaults` | Default runtime knobs such as `scale_m`, `cloudy_pct`, `composite`, or `image_size`. | +| `modalities` | Optional modality-specific branches for multi-branch models. | +| `model_config` | Machine-readable schema for supported model-specific kwargs such as `variant`. | Example: diff --git a/docs/concepts.md b/docs/concepts.md index 73bf122..702e1f9 100644 --- a/docs/concepts.md +++ b/docs/concepts.md @@ -46,8 +46,8 @@ For most on-the-fly GEE-backed models, this means: It usually does **not** mean "pick a single image acquired exactly on this date." !!! tip - If you want a near single-day query, use a one-day window such as - `TemporalSpec.range("2022-06-01", "2022-06-02")`. +If you want a near single-day query, use a one-day window such as +`TemporalSpec.range("2022-06-01", "2022-06-02")`. See detailed model-specific temporal behavior in [Supported Models](models.md). @@ -70,7 +70,7 @@ Returns a spatial feature grid `(D, H, W)`. Use `grid` for visualization, patch-wise analysis, and spatial structure inspection. !!! note - For ViT-like models, `grid` is often a token/patch grid, not guaranteed georeferenced raster pixels. +For ViT-like models, `grid` is often a token/patch grid, not guaranteed georeferenced raster pixels. Conceptually, this is one ROI in and one spatial embedding field out. It is useful when spatial layout matters more than a single pooled descriptor. diff --git a/docs/contributing.md b/docs/contributing.md index 242c6ca..4178bc9 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -4,8 +4,6 @@ The `rs-embed` project welcomes bug reports, documentation fixes, model integrat If you want to add a new model adapter or change the embedder contract, start with [Extending](extending.md). - - ## GitHub Workflow All development happens on GitHub. If you already know what needs to change, the fastest path is usually to open a pull request. If the scope is still unclear, or if the change affects public API shape, model semantics, or repository direction, opening an issue first helps everyone start from the same written context. diff --git a/docs/extending.md b/docs/extending.md index 8ae19be..8ec005b 100644 --- a/docs/extending.md +++ b/docs/extending.md @@ -42,8 +42,8 @@ Model loading is lazy: - The class is inserted into the runtime registry. !!! tip - Put your embedder in `rs_embed/embedders/` and add it to `src/rs_embed/embedders/catalog.py`. - If it's not in `MODEL_SPECS`, string-based lookup (`get_embedding("...")`) will not find it. +Put your embedder in `rs_embed/embedders/` and add it to `src/rs_embed/embedders/catalog.py`. +If it's not in `MODEL_SPECS`, string-based lookup (`get_embedding("...")`) will not find it. --- @@ -116,7 +116,7 @@ The stable extension points are: ``` !!! note - `describe()` must stay fast. It should not trigger checkpoint downloads, provider setup, or heavy model loading. +`describe()` must stay fast. It should not trigger checkpoint downloads, provider setup, or heavy model loading. Important fields currently consumed by rs-embed: @@ -219,10 +219,11 @@ Recommended extension pattern: and `modality=...` resolution can reuse your model cleanly. You can follow existing implementations in: + - `rs_embed/embedders/onthefly_*.py` !!! tip - Keep provider IO separate from model inference whenever possible. That makes batching, caching, and export reuse simpler. +Keep provider IO separate from model inference whenever possible. That makes batching, caching, and export reuse simpler. --- @@ -272,7 +273,7 @@ if input_chw is None: ``` !!! important - This is the key to avoiding “download twice” when `save_inputs=True` and `save_embeddings=True`. +This is the key to avoiding “download twice” when `save_inputs=True` and `save_embeddings=True`. --- @@ -352,7 +353,7 @@ if output.mode == "grid" and not supported: ## Optional Dependencies -Many embedders rely on optional packages (e.g., `torch`, `ee`). +Many embedders rely on optional packages (e.g., `torch`, `ee`). Recommended pattern: @@ -413,6 +414,7 @@ def test_toy_model_get_embedding(): If your model supports input reuse and batch export, add a small `export_batch` test using `monkeypatch` to avoid real network calls. See existing patterns in: + - `tests/test_export_batch.py` - `tests/test_gee_provider.py` @@ -434,7 +436,6 @@ Update docs in these places as needed: Use [Model Detail Template](model_detail_template.md) for the detailed page structure. - --- ## Checklist diff --git a/docs/index.md b/docs/index.md index 33ddfff..eb4174a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -14,7 +14,7 @@ Yet, using them in practice remains surprisingly painful. Model interfaces vary RS-Embed aims to fix this. !!! success "Goal" - Provide a **minimal**, **unified**, and **stable API** that turns diverse RS foundation models into a simple `ROI → embedding service` — so researchers can focus on **downstream tasks**, **benchmarking**, and **analysis**, not glue code. +Provide a **minimal**, **unified**, and **stable API** that turns diverse RS foundation models into a simple `ROI → embedding service` — so researchers can focus on **downstream tasks**, **benchmarking**, and **analysis**, not glue code. --- @@ -22,12 +22,12 @@ RS-Embed aims to fix this. Use the documentation the same way you would approach a mature library: start with one successful run, choose a model only after you understand the core API shape, and drop into the reference when you need exact contracts. -| Start here if you want to... | Page | -|---|---| +| Start here if you want to... | Page | +| ----------------------------- | ---------------------------------------------------------------------------------------------------- | | get something running quickly | [Quickstart](quickstart.md): install the package, run a first example, and learn the three core APIs | -| choose a model | [Models](models.md): shortlist model IDs by task, input type, and temporal behavior | -| check exact signatures | [API](api.md): exact signatures for specs, embedding, export, and inspection | -| add support for a new model | [Extending](extending.md): add a new model adapter or integrate with the registry/export flow | +| choose a model | [Models](models.md): shortlist model IDs by task, input type, and temporal behavior | +| check exact signatures | [API](api.md): exact signatures for specs, embedding, export, and inspection | +| add support for a new model | [Extending](extending.md): add a new model adapter or integrate with the registry/export flow | --- @@ -41,13 +41,13 @@ Most workflows revolve around three functions: `get_embedding(...)` for one ROI, ## Common Tasks -| Goal | Page | Main API | -|---|---|---| -| Get one embedding for one ROI | [Quickstart](quickstart.md) | `get_embedding(...)` | -| Compute embeddings for many ROIs | [Quickstart](quickstart.md) | `get_embeddings_batch(...)` | -| Build an export dataset | [Quickstart](quickstart.md) | `export_batch(...)` | -| Compare model assumptions | [Models](models.md) | model tables + detail pages | -| Inspect a raw provider patch | [Inspect API](api_inspect.md) | `inspect_provider_patch(...)` | +| Goal | Page | Main API | +| -------------------------------- | ----------------------------- | ----------------------------- | +| Get one embedding for one ROI | [Quickstart](quickstart.md) | `get_embedding(...)` | +| Compute embeddings for many ROIs | [Quickstart](quickstart.md) | `get_embeddings_batch(...)` | +| Build an export dataset | [Quickstart](quickstart.md) | `export_batch(...)` | +| Compare model assumptions | [Models](models.md) | model tables + detail pages | +| Inspect a raw provider patch | [Inspect API](api_inspect.md) | `inspect_provider_patch(...)` | --- @@ -55,19 +55,20 @@ Most workflows revolve around three functions: `get_embedding(...)` for one ROI, Once the basic flow is familiar, read [Concepts](concepts.md) for the semantics behind `TemporalSpec`, `OutputSpec`, and backends, then use [Workflows](workflows.md) for task-oriented recipes. [Advanced Model Reference](models_reference.md) goes deeper on preprocessing and temporal assumptions, while [Limitations](limitations.md) collects current constraints and edge cases. - ## Citation + ``` @article{ye2026modelplacetimeremote, - title={Any Model, Any Place, Any Time: Get Remote Sensing Foundation Model Embeddings On Demand}, + title={Any Model, Any Place, Any Time: Get Remote Sensing Foundation Model Embeddings On Demand}, author={Dingqi Ye and Daniel Kiv and Wei Hu and Jimeng Shi and Shaowen Wang}, year={2026}, eprint={2602.23678}, archivePrefix={arXiv}, primaryClass={cs.CV}, - url={https://arxiv.org/abs/2602.23678}, + url={https://arxiv.org/abs/2602.23678}, } ``` ## License -This project is released under the [Apache-2.0](https://github.com/cybergis/rs-embed/blob/main/LICENSE) \ No newline at end of file + +This project is released under the [Apache-2.0](https://github.com/cybergis/rs-embed/blob/main/LICENSE) diff --git a/docs/model_detail_template.md b/docs/model_detail_template.md index 9f1cdcc..9d34d80 100644 --- a/docs/model_detail_template.md +++ b/docs/model_detail_template.md @@ -24,18 +24,18 @@ Goal: make every model page answer the same questions quickly, so users can comp ## Quick Facts -| Field | Value | -|---|---| -| Model ID | `` | -| Family / Backbone | `TODO` | -| Adapter type | `precomputed` / `on-the-fly` | -| Typical backend | `auto` / `gee` / provider-specific | -| Primary input | `TODO` | -| Temporal mode | `year` / `range` / model-specific | -| Output modes | `pooled`, `grid` | -| Model config keys | none / `variant` / `TODO` | -| Extra side inputs | none / `TODO` | -| Training alignment (adapter path) | Low / Medium / High + short note | +| Field | Value | +| --------------------------------- | ---------------------------------- | +| Model ID | `` | +| Family / Backbone | `TODO` | +| Adapter type | `precomputed` / `on-the-fly` | +| Typical backend | `auto` / `gee` / provider-specific | +| Primary input | `TODO` | +| Temporal mode | `year` / `range` / model-specific | +| Output modes | `pooled`, `grid` | +| Model config keys | none / `variant` / `TODO` | +| Extra side inputs | none / `TODO` | +| Training alignment (adapter path) | Low / Medium / High + short note | --- @@ -89,7 +89,9 @@ Recommended display pattern in MkDocs Material: Example: ```html -
INPUT  provider fetch / input_chw
+
INPUT  provider fetch / input_chw
   -> normalize
   -> model-specific prep
      resize: ...
@@ -111,8 +113,8 @@ Suggested content checklist:
 ### Environment variables that change behavior
 
 | Env var | Default | Effect |
-|---|---|---|
-| `TODO` | `TODO` | `TODO` |
+| ------- | ------- | ------ |
+| `TODO`  | `TODO`  | `TODO` |
 
 ---
 
diff --git a/docs/models.md b/docs/models.md
index 258281d..8ae30e5 100644
--- a/docs/models.md
+++ b/docs/models.md
@@ -18,44 +18,44 @@ Some detail-page filenames still use older names for compatibility, but the cano
 
 ## Quick Chooser by Goal
 
-| Goal | Good starting models | Why |
-|---|---|---|
-| Fast baseline / simple pipeline | `tessera`, `gse`, `copernicus` | Precomputed embeddings, fewer runtime dependencies |
-| Simple S2 RGB on-the-fly experiments | `remoteclip`, `satmae`, `satmaepp`, `scalemae` | Straightforward RGB input paths |
-| Time-series temporal modeling | `agrifm`, `anysat`, `galileo` | Native multi-frame temporal packaging |
-| Multispectral / strict spectral semantics | `satmaepp_s2_10b`, `dofa`, `terramind`, `thor`, `satvision` | Strong channel/schema assumptions |
-| Mixed-modality experiments (S1/S2) | `terrafm` | Supports S2 or S1 path (per call) |
+| Goal                                      | Good starting models                                        | Why                                                |
+| ----------------------------------------- | ----------------------------------------------------------- | -------------------------------------------------- |
+| Fast baseline / simple pipeline           | `tessera`, `gse`, `copernicus`                              | Precomputed embeddings, fewer runtime dependencies |
+| Simple S2 RGB on-the-fly experiments      | `remoteclip`, `satmae`, `satmaepp`, `scalemae`              | Straightforward RGB input paths                    |
+| Time-series temporal modeling             | `agrifm`, `anysat`, `galileo`                               | Native multi-frame temporal packaging              |
+| Multispectral / strict spectral semantics | `satmaepp_s2_10b`, `dofa`, `terramind`, `thor`, `satvision` | Strong channel/schema assumptions                  |
+| Mixed-modality experiments (S1/S2)        | `terrafm`                                                   | Supports S2 or S1 path (per call)                  |
 
 ## Model Catalog Snapshot
 
 ### Precomputed Embeddings
 
-| Model ID | Type | Primary Input / Source | Default Resolution | Outputs | Temporal mode | Notes | Detail |
-|---|---|---|---|---|---|---|---|
-| `tessera` | Precomputed | GeoTessera embedding tiles | 10m | `pooled`, `grid` | yearly coverage product | Fast baseline, source-fixed precomputed workflow; product-native fixed CRS | [detail](models/tessera.md) |
-| `gse` | Precomputed | Google Satellite Embedding (annual) | 10m | `pooled`, `grid` | `TemporalSpec.year(...)` | Annual product via provider path | [detail](models/gse.md) |
-| `copernicus` | Precomputed | Copernicus embeddings | 0.25° | `pooled`, `grid` | limited (2021) | Coarse resolution product on fixed EPSG:4326 grid | [detail](models/copernicus.md) |
+| Model ID     | Type        | Primary Input / Source              | Default Resolution | Outputs          | Temporal mode            | Notes                                                                      | Detail                         |
+| ------------ | ----------- | ----------------------------------- | ------------------ | ---------------- | ------------------------ | -------------------------------------------------------------------------- | ------------------------------ |
+| `tessera`    | Precomputed | GeoTessera embedding tiles          | 10m                | `pooled`, `grid` | yearly coverage product  | Fast baseline, source-fixed precomputed workflow; product-native fixed CRS | [detail](models/tessera.md)    |
+| `gse`        | Precomputed | Google Satellite Embedding (annual) | 10m                | `pooled`, `grid` | `TemporalSpec.year(...)` | Annual product via provider path                                           | [detail](models/gse.md)        |
+| `copernicus` | Precomputed | Copernicus embeddings               | 0.25°              | `pooled`, `grid` | limited (2021)           | Coarse resolution product on fixed EPSG:4326 grid                          | [detail](models/copernicus.md) |
 
 ### On-the-fly Foundation Models
 
-| Model ID | Primary Input | Default Resolution | Temporal style | Outputs | Notable requirements | Detail |
-|---|---|---|---|---|---|---|
-| `remoteclip` | S2 RGB (`B4,B3,B2`) | 10m | single composite window | `pooled`, `grid` | provider backend; RGB preprocessing | [detail](models/remoteclip.md) |
-| `satmae` | S2 RGB (`B4,B3,B2`) | 10m | single composite window | `pooled`, `grid` | RGB path; ViT token/grid behavior | [detail](models/satmae.md) |
-| `satmaepp` | S2 RGB (`B4,B3,B2`) | 10m | single composite window | `pooled`, `grid` | SatMAE++ fMoW-style eval preprocessing; channel order control | [detail](models/satmaepp.md) |
-| `satmaepp_s2_10b` | S2 SR 10-band (`B2,B3,B4,B5,B6,B7,B8,B8A,B11,B12`) | 10m | single composite window | `pooled`, `grid` | strict 10-band order; grouped-channel token handling | [detail](models/satmaepp.md) |
-| `scalemae` | S2 RGB + scale | 10m | single composite window | `pooled`, `grid` | requires `sensor.scale_m` / `input_res_m` | [detail](models/scalemae.md) |
-| `wildsat` | S2 RGB | 10m | single composite window | `pooled`, `grid` | normalization options | [detail](models/wildsat.md) |
-| `prithvi` | S2 6-band | 30m | single composite window | `pooled`, `grid` | required temporal + location side inputs | [detail](models/prithvi.md) |
-| `terrafm` | S2 12-band or S1 VV/VH | 10m | single composite window | `pooled`, `grid` | choose modality per call | [detail](models/terrafm.md) |
-| `terramind` | S2 SR 12-band | 10m | single composite window | `pooled`, `grid` | strict normalization/channel semantics | [detail](models/terramind.md) |
-| `dofa` | Multispectral + wavelengths | 10m | single composite window | `pooled`, `grid` | wavelength vector required/inferred | [detail](models/dofa.md) |
-| `fomo` | S2 12-band | 10m | single composite window | `pooled`, `grid` | normalization mode choices | [detail](models/fomo.md) |
-| `thor` | S2 SR 10-band | 10m | single composite window | `pooled`, `grid` | strict stats-based normalization | [detail](models/thor.md) |
-| `satvision` | TOA 14-channel | 1000m | single composite window | `pooled`, `grid` | strict channel order + calibration | [detail](models/satvision.md) |
-| `anysat` | S2 10-band time series | 10m | multi-frame | `pooled`, `grid` | frame dates (`s2_dates`) side input | [detail](models/anysat.md) |
-| `galileo` | S2 10-band time series | 10m | multi-frame | `pooled`, `grid` | month tokens + grouped tensors | [detail](models/galileo.md) |
-| `agrifm` | S2 10-band time series | 10m | multi-frame | `pooled`, `grid` | fixed `T` frame stack behavior | [detail](models/agrifm.md) |
+| Model ID          | Primary Input                                      | Default Resolution | Temporal style          | Outputs          | Notable requirements                                          | Detail                         |
+| ----------------- | -------------------------------------------------- | ------------------ | ----------------------- | ---------------- | ------------------------------------------------------------- | ------------------------------ |
+| `remoteclip`      | S2 RGB (`B4,B3,B2`)                                | 10m                | single composite window | `pooled`, `grid` | provider backend; RGB preprocessing                           | [detail](models/remoteclip.md) |
+| `satmae`          | S2 RGB (`B4,B3,B2`)                                | 10m                | single composite window | `pooled`, `grid` | RGB path; ViT token/grid behavior                             | [detail](models/satmae.md)     |
+| `satmaepp`        | S2 RGB (`B4,B3,B2`)                                | 10m                | single composite window | `pooled`, `grid` | SatMAE++ fMoW-style eval preprocessing; channel order control | [detail](models/satmaepp.md)   |
+| `satmaepp_s2_10b` | S2 SR 10-band (`B2,B3,B4,B5,B6,B7,B8,B8A,B11,B12`) | 10m                | single composite window | `pooled`, `grid` | strict 10-band order; grouped-channel token handling          | [detail](models/satmaepp.md)   |
+| `scalemae`        | S2 RGB + scale                                     | 10m                | single composite window | `pooled`, `grid` | requires `sensor.scale_m` / `input_res_m`                     | [detail](models/scalemae.md)   |
+| `wildsat`         | S2 RGB                                             | 10m                | single composite window | `pooled`, `grid` | normalization options                                         | [detail](models/wildsat.md)    |
+| `prithvi`         | S2 6-band                                          | 30m                | single composite window | `pooled`, `grid` | required temporal + location side inputs                      | [detail](models/prithvi.md)    |
+| `terrafm`         | S2 12-band or S1 VV/VH                             | 10m                | single composite window | `pooled`, `grid` | choose modality per call                                      | [detail](models/terrafm.md)    |
+| `terramind`       | S2 SR 12-band                                      | 10m                | single composite window | `pooled`, `grid` | strict normalization/channel semantics                        | [detail](models/terramind.md)  |
+| `dofa`            | Multispectral + wavelengths                        | 10m                | single composite window | `pooled`, `grid` | wavelength vector required/inferred                           | [detail](models/dofa.md)       |
+| `fomo`            | S2 12-band                                         | 10m                | single composite window | `pooled`, `grid` | normalization mode choices                                    | [detail](models/fomo.md)       |
+| `thor`            | S2 SR 10-band                                      | 10m                | single composite window | `pooled`, `grid` | strict stats-based normalization                              | [detail](models/thor.md)       |
+| `satvision`       | TOA 14-channel                                     | 1000m              | single composite window | `pooled`, `grid` | strict channel order + calibration                            | [detail](models/satvision.md)  |
+| `anysat`          | S2 10-band time series                             | 10m                | multi-frame             | `pooled`, `grid` | frame dates (`s2_dates`) side input                           | [detail](models/anysat.md)     |
+| `galileo`         | S2 10-band time series                             | 10m                | multi-frame             | `pooled`, `grid` | month tokens + grouped tensors                                | [detail](models/galileo.md)    |
+| `agrifm`          | S2 10-band time series                             | 10m                | multi-frame             | `pooled`, `grid` | fixed `T` frame stack behavior                                | [detail](models/agrifm.md)     |
 
 ---
 
diff --git a/docs/models/agrifm.md b/docs/models/agrifm.md
index f26d7ab..95b99eb 100644
--- a/docs/models/agrifm.md
+++ b/docs/models/agrifm.md
@@ -4,17 +4,17 @@
 
 ## Quick Facts
 
-| Field | Value |
-|---|---|
-| Model ID | `agrifm` |
-| Family / Backbone | AgriFM (vendored Video Swin runtime + checkpoint loader) |
-| Adapter type | `on-the-fly` |
-| Typical backend | provider backend (`gee`) |
-| Primary input | S2 SR 10-band time series (`T,10,H,W`) |
-| Default resolution | 10m default provider fetch (`sensor.scale_m`) |
-| Temporal mode | `range` in practice (window split into `T` frames) |
-| Output modes | `pooled`, `grid` |
-| Extra side inputs | none required (adapter builds fixed frame stack) |
+| Field                             | Value                                                                 |
+| --------------------------------- | --------------------------------------------------------------------- |
+| Model ID                          | `agrifm`                                                              |
+| Family / Backbone                 | AgriFM (vendored Video Swin runtime + checkpoint loader)              |
+| Adapter type                      | `on-the-fly`                                                          |
+| Typical backend                   | provider backend (`gee`)                                              |
+| Primary input                     | S2 SR 10-band time series (`T,10,H,W`)                                |
+| Default resolution                | 10m default provider fetch (`sensor.scale_m`)                         |
+| Temporal mode                     | `range` in practice (window split into `T` frames)                    |
+| Output modes                      | `pooled`, `grid`                                                      |
+| Extra side inputs                 | none required (adapter builds fixed frame stack)                      |
 | Training alignment (adapter path) | High when `n_frames`, normalization, and checkpoint version are fixed |
 
 ---
@@ -65,23 +65,23 @@ For `input_chw`, the adapter accepts `CHW` with `C=10` and repeats that frame to
 
 ### Temporal / preprocessing
 
-| Env var | Default | Effect |
-|---|---|---|
-| `RS_EMBED_AGRIFM_FRAMES` | `8` | Fixed frame count `T` |
-| `RS_EMBED_AGRIFM_IMG` | `224` | Resize target image size |
-| `RS_EMBED_AGRIFM_NORM` | `agrifm_stats` | `agrifm_stats`, `unit_scale`, or `none` |
-| `RS_EMBED_AGRIFM_FETCH_WORKERS` | `8` | Provider prefetch workers for batch APIs |
+| Env var                         | Default        | Effect                                   |
+| ------------------------------- | -------------- | ---------------------------------------- |
+| `RS_EMBED_AGRIFM_FRAMES`        | `8`            | Fixed frame count `T`                    |
+| `RS_EMBED_AGRIFM_IMG`           | `224`          | Resize target image size                 |
+| `RS_EMBED_AGRIFM_NORM`          | `agrifm_stats` | `agrifm_stats`, `unit_scale`, or `none`  |
+| `RS_EMBED_AGRIFM_FETCH_WORKERS` | `8`            | Provider prefetch workers for batch APIs |
 
 ### Checkpoint loading
 
-| Env var | Default | Effect |
-|---|---|---|
-| `RS_EMBED_AGRIFM_CKPT` | unset | Local checkpoint path |
-| `RS_EMBED_AGRIFM_AUTO_DOWNLOAD` | `1` | Allow checkpoint auto-download |
-| `RS_EMBED_AGRIFM_CACHE_DIR` | `~/.cache/rs_embed/agrifm` | Checkpoint cache dir |
-| `RS_EMBED_AGRIFM_CKPT_FILE` | `AgriFM.pth` | Cached checkpoint filename |
-| `RS_EMBED_AGRIFM_CKPT_URL` | project default URL | Checkpoint download URL |
-| `RS_EMBED_AGRIFM_CKPT_MIN_BYTES` | large-size threshold | Download validation threshold |
+| Env var                          | Default                    | Effect                         |
+| -------------------------------- | -------------------------- | ------------------------------ |
+| `RS_EMBED_AGRIFM_CKPT`           | unset                      | Local checkpoint path          |
+| `RS_EMBED_AGRIFM_AUTO_DOWNLOAD`  | `1`                        | Allow checkpoint auto-download |
+| `RS_EMBED_AGRIFM_CACHE_DIR`      | `~/.cache/rs_embed/agrifm` | Checkpoint cache dir           |
+| `RS_EMBED_AGRIFM_CKPT_FILE`      | `AgriFM.pth`               | Cached checkpoint filename     |
+| `RS_EMBED_AGRIFM_CKPT_URL`       | project default URL        | Checkpoint download URL        |
+| `RS_EMBED_AGRIFM_CKPT_MIN_BYTES` | large-size threshold       | Download validation threshold  |
 
 ## Output Semantics
 
diff --git a/docs/models/anysat.md b/docs/models/anysat.md
index 114a6f3..91f5929 100644
--- a/docs/models/anysat.md
+++ b/docs/models/anysat.md
@@ -4,18 +4,18 @@
 
 ## Quick Facts
 
-| Field | Value |
-|---|---|
-| Model ID | `anysat` |
-| Family / Backbone | AnySat (vendored local runtime) |
-| Adapter type | `on-the-fly` |
-| Typical backend | provider-backed; prefer `backend="auto"` in public API |
-| Primary input | S2 10-band time series (`T,C,H,W`) |
-| Default resolution | 10m default provider fetch (`sensor.scale_m`) |
-| Temporal mode | `range` in practice (adapter normalizes `year`/`None` to range) |
-| Output modes | `pooled`, `grid` |
-| Model config keys | `variant` (default: `base`; choices: `base`) |
-| Extra side inputs | **required** `s2_dates` (per-frame DOY values) |
+| Field                             | Value                                                               |
+| --------------------------------- | ------------------------------------------------------------------- |
+| Model ID                          | `anysat`                                                            |
+| Family / Backbone                 | AnySat (vendored local runtime)                                     |
+| Adapter type                      | `on-the-fly`                                                        |
+| Typical backend                   | provider-backed; prefer `backend="auto"` in public API              |
+| Primary input                     | S2 10-band time series (`T,C,H,W`)                                  |
+| Default resolution                | 10m default provider fetch (`sensor.scale_m`)                       |
+| Temporal mode                     | `range` in practice (adapter normalizes `year`/`None` to range)     |
+| Output modes                      | `pooled`, `grid`                                                    |
+| Model config keys                 | `variant` (default: `base`; choices: `base`)                        |
+| Extra side inputs                 | **required** `s2_dates` (per-frame DOY values)                      |
 | Training alignment (adapter path) | Medium (depends on frame count, normalization mode, and image size) |
 
 ---
@@ -69,23 +69,22 @@ Important constraint:
 
 ## Environment Variables / Tuning Knobs
 
-| Env var | Default | Effect |
-|---|---|---|
-| `RS_EMBED_ANYSAT_FRAMES` | `8` | Number of temporal frames `T` |
-| `RS_EMBED_ANYSAT_IMG` | `24` | Per-frame resize target (square) |
-| `RS_EMBED_ANYSAT_NORM` | `per_tile_zscore` | Series normalization mode |
-| `RS_EMBED_ANYSAT_MODEL_SIZE` | `base` | AnySat model size |
-| `RS_EMBED_ANYSAT_GRID_MODE` | `dense` | Grid path native AnySat spatial output (`dense` or `patch`) |
-| `RS_EMBED_ANYSAT_POOLED_SOURCE` | `patch` | Pooled path source (`patch` compatibility pooling or native `tile`) |
-| `RS_EMBED_ANYSAT_FLASH_ATTN` | `0` | Enable flash attention path if supported |
-| `RS_EMBED_ANYSAT_PRETRAINED` | `1` | Load pretrained checkpoint weights |
-| `RS_EMBED_ANYSAT_CKPT` | unset | Local checkpoint override |
-| `RS_EMBED_ANYSAT_HF_REPO` | `g-astruc/AnySat` | Hugging Face repo used for checkpoint download |
-| `RS_EMBED_ANYSAT_HF_FILE` | `models/AnySat.pth` | Checkpoint file inside the Hugging Face repo |
-| `RS_EMBED_ANYSAT_CACHE_DIR` | `~/.cache/rs_embed/anysat` | Checkpoint cache dir |
-| `RS_EMBED_ANYSAT_CKPT_MIN_BYTES` | adapter threshold | Download size sanity check |
-| `RS_EMBED_ANYSAT_FETCH_WORKERS` | `8` | Provider prefetch workers for batch APIs |
-
+| Env var                          | Default                    | Effect                                                              |
+| -------------------------------- | -------------------------- | ------------------------------------------------------------------- |
+| `RS_EMBED_ANYSAT_FRAMES`         | `8`                        | Number of temporal frames `T`                                       |
+| `RS_EMBED_ANYSAT_IMG`            | `24`                       | Per-frame resize target (square)                                    |
+| `RS_EMBED_ANYSAT_NORM`           | `per_tile_zscore`          | Series normalization mode                                           |
+| `RS_EMBED_ANYSAT_MODEL_SIZE`     | `base`                     | AnySat model size                                                   |
+| `RS_EMBED_ANYSAT_GRID_MODE`      | `dense`                    | Grid path native AnySat spatial output (`dense` or `patch`)         |
+| `RS_EMBED_ANYSAT_POOLED_SOURCE`  | `patch`                    | Pooled path source (`patch` compatibility pooling or native `tile`) |
+| `RS_EMBED_ANYSAT_FLASH_ATTN`     | `0`                        | Enable flash attention path if supported                            |
+| `RS_EMBED_ANYSAT_PRETRAINED`     | `1`                        | Load pretrained checkpoint weights                                  |
+| `RS_EMBED_ANYSAT_CKPT`           | unset                      | Local checkpoint override                                           |
+| `RS_EMBED_ANYSAT_HF_REPO`        | `g-astruc/AnySat`          | Hugging Face repo used for checkpoint download                      |
+| `RS_EMBED_ANYSAT_HF_FILE`        | `models/AnySat.pth`        | Checkpoint file inside the Hugging Face repo                        |
+| `RS_EMBED_ANYSAT_CACHE_DIR`      | `~/.cache/rs_embed/anysat` | Checkpoint cache dir                                                |
+| `RS_EMBED_ANYSAT_CKPT_MIN_BYTES` | adapter threshold          | Download size sanity check                                          |
+| `RS_EMBED_ANYSAT_FETCH_WORKERS`  | `8`                        | Provider prefetch workers for batch APIs                            |
 
 ## Output Semantics
 
@@ -118,7 +117,6 @@ emb = get_embedding(
 # export RS_EMBED_ANYSAT_IMG=24
 ```
 
-
 ---
 
 ## Common Failure Modes / Debugging
diff --git a/docs/models/copernicus.md b/docs/models/copernicus.md
index 87dd64b..87b428c 100644
--- a/docs/models/copernicus.md
+++ b/docs/models/copernicus.md
@@ -4,21 +4,20 @@
 
 ## Quick Facts
 
-| Field | Value |
-|---|---|
-| Model ID | `copernicus` |
-| Aliases | `copernicus_embed` |
-| Family / Source | `torchgeo/copernicus_embed` GeoTIFF redistribution on Hugging Face |
-| Adapter type | `precomputed` |
-| Typical backend | `auto` |
-| Primary input | `BBox` / `PointBuffer` in EPSG:4326, sliced via vendored GeoTIFF bbox indexing |
-| Product grid CRS | fixed `EPSG:4326` grid (not the common provider-backed EPSG:3857 default) |
-| Default resolution | 0.25° source product resolution |
-| Temporal mode | **strict** `TemporalSpec.year(2021)` in v0.1 |
-| Output modes | `pooled`, `grid` |
-| Extra side inputs | none |
-| Training alignment (adapter path) | N/A (precomputed product) |
-
+| Field                             | Value                                                                          |
+| --------------------------------- | ------------------------------------------------------------------------------ |
+| Model ID                          | `copernicus`                                                                   |
+| Aliases                           | `copernicus_embed`                                                             |
+| Family / Source                   | `torchgeo/copernicus_embed` GeoTIFF redistribution on Hugging Face             |
+| Adapter type                      | `precomputed`                                                                  |
+| Typical backend                   | `auto`                                                                         |
+| Primary input                     | `BBox` / `PointBuffer` in EPSG:4326, sliced via vendored GeoTIFF bbox indexing |
+| Product grid CRS                  | fixed `EPSG:4326` grid (not the common provider-backed EPSG:3857 default)      |
+| Default resolution                | 0.25° source product resolution                                                |
+| Temporal mode                     | **strict** `TemporalSpec.year(2021)` in v0.1                                   |
+| Output modes                      | `pooled`, `grid`                                                               |
+| Extra side inputs                 | none                                                                           |
+| Training alignment (adapter path) | N/A (precomputed product)                                                      |
 
 ---
 
@@ -35,7 +34,7 @@ Copernicus Embed is a good fit for precomputed embedding workflows via local Geo
 The adapter accepts `BBox` directly and `PointBuffer`, which it converts to an EPSG:4326 bbox. Internally it slices the local GeoTIFF with bbox indexing via `ds[minlon:maxlon, minlat:maxlat]`.
 
 !!! warning
-    Copernicus keeps the product's fixed `EPSG:4326` grid with 0.25 degree pixels. That differs from the more common provider-backed EPSG:3857 sampling default used elsewhere in `rs-embed`, even though the public spatial input is still `EPSG:4326`.
+Copernicus keeps the product's fixed `EPSG:4326` grid with 0.25 degree pixels. That differs from the more common provider-backed EPSG:3857 sampling default used elsewhere in `rs-embed`, even though the public spatial input is still `EPSG:4326`.
 
 ### Temporal
 
@@ -72,10 +71,10 @@ Notes:
 
 ## Environment Variables / Tuning Knobs
 
-| Env var | Default | Effect |
-|---|---|---|
-| `RS_EMBED_COP_DIR` | `data/copernicus_embed` | Local Copernicus embed GeoTIFF directory |
-| `RS_EMBED_COPERNICUS_BATCH_WORKERS` | `4` | Batch worker count for `get_embeddings_batch(...)` |
+| Env var                             | Default                 | Effect                                             |
+| ----------------------------------- | ----------------------- | -------------------------------------------------- |
+| `RS_EMBED_COP_DIR`                  | `data/copernicus_embed` | Local Copernicus embed GeoTIFF directory           |
+| `RS_EMBED_COPERNICUS_BATCH_WORKERS` | `4`                     | Batch worker count for `get_embeddings_batch(...)` |
 
 Non-env override:
 
diff --git a/docs/models/dofa.md b/docs/models/dofa.md
index f869207..ba40ada 100644
--- a/docs/models/dofa.md
+++ b/docs/models/dofa.md
@@ -4,18 +4,18 @@
 
 ## Quick Facts
 
-| Field | Value |
-|---|---|
-| Model ID | `dofa` |
-| Family / Backbone | DOFA ViT (`base` / `large`, official checkpoints) |
-| Adapter type | `on-the-fly` |
-| Typical backend | provider backend (`gee`), also supports `backend="tensor"` |
-| Primary input | Raw Sentinel-2 SR CHW + wavelengths (µm) |
-| Default resolution | 10m default provider fetch (`sensor.scale_m`) |
-| Temporal mode | provider path requires `TemporalSpec.range(...)` |
-| Output modes | `pooled`, `grid` |
-| Model config keys | `variant` (default: `base`; choices: `base`, `large`) |
-| Extra side inputs | **required** wavelength vector (`wavelengths_um`) |
+| Field                             | Value                                                         |
+| --------------------------------- | ------------------------------------------------------------- |
+| Model ID                          | `dofa`                                                        |
+| Family / Backbone                 | DOFA ViT (`base` / `large`, official checkpoints)             |
+| Adapter type                      | `on-the-fly`                                                  |
+| Typical backend                   | provider backend (`gee`), also supports `backend="tensor"`    |
+| Primary input                     | Raw Sentinel-2 SR CHW + wavelengths (µm)                      |
+| Default resolution                | 10m default provider fetch (`sensor.scale_m`)                 |
+| Temporal mode                     | provider path requires `TemporalSpec.range(...)`              |
+| Output modes                      | `pooled`, `grid`                                              |
+| Model config keys                 | `variant` (default: `base`; choices: `base`, `large`)         |
+| Extra side inputs                 | **required** wavelength vector (`wavelengths_um`)             |
 | Training alignment (adapter path) | Medium-High (when wavelengths and band semantics are correct) |
 
 ---
@@ -93,15 +93,15 @@ The current implementation fixes image size at `224`, and the official preproces
 
 ## Environment Variables / Tuning Knobs
 
-| Env var | Default | Effect |
-|---|---|---|
-| `RS_EMBED_DOFA_FETCH_WORKERS` | `8` | Provider prefetch workers for batch APIs |
-| `RS_EMBED_DOFA_BATCH_SIZE` | CPU:`8`, CUDA:`64` | Inference batch size for batch APIs |
-| `RS_EMBED_DOFA_BASE_WEIGHTS` | unset | Local override for the base checkpoint file |
-| `RS_EMBED_DOFA_LARGE_WEIGHTS` | unset | Local override for the large checkpoint file |
-| `RS_EMBED_DOFA_WEIGHTS_DIR` | unset | Directory override containing DOFA checkpoint files |
-| `RS_EMBED_DOFA_HF_REPO_ID` | `earthflow/DOFA` | Hugging Face repo used for checkpoint download |
-| `RS_EMBED_DOFA_HF_REVISION` | `main` | Hugging Face revision used for checkpoint download |
+| Env var                       | Default            | Effect                                              |
+| ----------------------------- | ------------------ | --------------------------------------------------- |
+| `RS_EMBED_DOFA_FETCH_WORKERS` | `8`                | Provider prefetch workers for batch APIs            |
+| `RS_EMBED_DOFA_BATCH_SIZE`    | CPU:`8`, CUDA:`64` | Inference batch size for batch APIs                 |
+| `RS_EMBED_DOFA_BASE_WEIGHTS`  | unset              | Local override for the base checkpoint file         |
+| `RS_EMBED_DOFA_LARGE_WEIGHTS` | unset              | Local override for the large checkpoint file        |
+| `RS_EMBED_DOFA_WEIGHTS_DIR`   | unset              | Directory override containing DOFA checkpoint files |
+| `RS_EMBED_DOFA_HF_REPO_ID`    | `earthflow/DOFA`   | Hugging Face repo used for checkpoint download      |
+| `RS_EMBED_DOFA_HF_REVISION`   | `main`             | Hugging Face revision used for checkpoint download  |
 
 Non-env model selection knobs:
 
diff --git a/docs/models/fomo.md b/docs/models/fomo.md
index f77b7dd..697509b 100644
--- a/docs/models/fomo.md
+++ b/docs/models/fomo.md
@@ -4,17 +4,17 @@
 
 ## Quick Facts
 
-| Field | Value |
-|---|---|
-| Model ID | `fomo` |
-| Family / Backbone | FoMo-Bench `MultiSpectralViT` (vendored local code + checkpoint loader) |
-| Adapter type | `on-the-fly` |
-| Typical backend | provider backend (`gee`) |
-| Primary input | S2 SR 12-band (`B1,B2,B3,B4,B5,B6,B7,B8,B8A,B9,B11,B12`) |
-| Default resolution | 10m default provider fetch (`sensor.scale_m`) |
-| Temporal mode | `range` in practice (normalized via shared helper) |
-| Output modes | `pooled`, `grid` |
-| Extra side inputs | **required modality keys** (adapter provides S2 defaults, configurable via env) |
+| Field                             | Value                                                                                    |
+| --------------------------------- | ---------------------------------------------------------------------------------------- |
+| Model ID                          | `fomo`                                                                                   |
+| Family / Backbone                 | FoMo-Bench `MultiSpectralViT` (vendored local code + checkpoint loader)                  |
+| Adapter type                      | `on-the-fly`                                                                             |
+| Typical backend                   | provider backend (`gee`)                                                                 |
+| Primary input                     | S2 SR 12-band (`B1,B2,B3,B4,B5,B6,B7,B8,B8A,B9,B11,B12`)                                 |
+| Default resolution                | 10m default provider fetch (`sensor.scale_m`)                                            |
+| Temporal mode                     | `range` in practice (normalized via shared helper)                                       |
+| Output modes                      | `pooled`, `grid`                                                                         |
+| Extra side inputs                 | **required modality keys** (adapter provides S2 defaults, configurable via env)          |
 | Training alignment (adapter path) | Medium-High when `S2_KEYS`, normalization, and model config match checkpoint assumptions |
 
 ---
@@ -65,34 +65,35 @@ The FoMo forward path requires one modality key per channel. The default S2 mapp
 
 ### Core model / preprocessing
 
-| Env var | Default | Effect |
-|---|---|---|
-| `RS_EMBED_FOMO_IMG` | `64` | Resize target image size |
-| `RS_EMBED_FOMO_PATCH` | `16` | Patch size (used for model config + grid expectations) |
-| `RS_EMBED_FOMO_NORM` | `unit_scale` | `unit_scale`, `per_tile_minmax`, or `none` |
-| `RS_EMBED_FOMO_S2_KEYS` | adapter S2 default mapping | 12 comma-separated modality keys |
-| `RS_EMBED_FOMO_FETCH_WORKERS` | `8` | Provider prefetch workers for batch APIs |
+| Env var                       | Default                    | Effect                                                 |
+| ----------------------------- | -------------------------- | ------------------------------------------------------ |
+| `RS_EMBED_FOMO_IMG`           | `64`                       | Resize target image size                               |
+| `RS_EMBED_FOMO_PATCH`         | `16`                       | Patch size (used for model config + grid expectations) |
+| `RS_EMBED_FOMO_NORM`          | `unit_scale`               | `unit_scale`, `per_tile_minmax`, or `none`             |
+| `RS_EMBED_FOMO_S2_KEYS`       | adapter S2 default mapping | 12 comma-separated modality keys                       |
+| `RS_EMBED_FOMO_FETCH_WORKERS` | `8`                        | Provider prefetch workers for batch APIs               |
 
 ### FoMo model config (advanced; keep aligned with checkpoint)
 
-| Env var | Default | Effect |
-|---|---|---|
-| `RS_EMBED_FOMO_DIM` | `768` | Model dim |
-| `RS_EMBED_FOMO_DEPTH` | `12` | Transformer depth |
-| `RS_EMBED_FOMO_HEADS` | `12` | Attention heads |
-| `RS_EMBED_FOMO_MLP_DIM` | `2048` | MLP dim |
-| `RS_EMBED_FOMO_NUM_CLASSES` | `1000` | Class head size (config compatibility) |
+| Env var                     | Default | Effect                                 |
+| --------------------------- | ------- | -------------------------------------- |
+| `RS_EMBED_FOMO_DIM`         | `768`   | Model dim                              |
+| `RS_EMBED_FOMO_DEPTH`       | `12`    | Transformer depth                      |
+| `RS_EMBED_FOMO_HEADS`       | `12`    | Attention heads                        |
+| `RS_EMBED_FOMO_MLP_DIM`     | `2048`  | MLP dim                                |
+| `RS_EMBED_FOMO_NUM_CLASSES` | `1000`  | Class head size (config compatibility) |
 
 ### Checkpoint loading
 
-| Env var | Default | Effect |
-|---|---|---|
-| `RS_EMBED_FOMO_CKPT` | unset | Local checkpoint path |
-| `RS_EMBED_FOMO_AUTO_DOWNLOAD` | `1` | Allow checkpoint auto-download |
-| `RS_EMBED_FOMO_CACHE_DIR` | `~/.cache/rs_embed/fomo` | Checkpoint cache dir |
-| `RS_EMBED_FOMO_CKPT_FILE` | default FoMo checkpoint filename | Cached ckpt filename |
-| `RS_EMBED_FOMO_CKPT_URL` | default Dropbox URL | Checkpoint download URL |
-| `RS_EMBED_FOMO_CKPT_MIN_BYTES` | adapter threshold | Download size sanity check |
+| Env var                        | Default                          | Effect                         |
+| ------------------------------ | -------------------------------- | ------------------------------ |
+| `RS_EMBED_FOMO_CKPT`           | unset                            | Local checkpoint path          |
+| `RS_EMBED_FOMO_AUTO_DOWNLOAD`  | `1`                              | Allow checkpoint auto-download |
+| `RS_EMBED_FOMO_CACHE_DIR`      | `~/.cache/rs_embed/fomo`         | Checkpoint cache dir           |
+| `RS_EMBED_FOMO_CKPT_FILE`      | default FoMo checkpoint filename | Cached ckpt filename           |
+| `RS_EMBED_FOMO_CKPT_URL`       | default Dropbox URL              | Checkpoint download URL        |
+| `RS_EMBED_FOMO_CKPT_MIN_BYTES` | adapter threshold                | Download size sanity check     |
+
 ---
 
 ## Output Semantics
diff --git a/docs/models/galileo.md b/docs/models/galileo.md
index 86f5ee4..1c5fcb6 100644
--- a/docs/models/galileo.md
+++ b/docs/models/galileo.md
@@ -4,18 +4,18 @@
 
 ## Quick Facts
 
-| Field | Value |
-|---|---|
-| Model ID | `galileo` |
-| Family / Backbone | Galileo `Encoder` from vendored local runtime |
-| Adapter type | `on-the-fly` |
-| Typical backend | provider-backed; prefer `backend="auto"` in public API |
-| Primary input | S2 10-band time series (`T,C,H,W`) |
-| Default resolution | 10m default provider fetch (`sensor.scale_m`) |
-| Temporal mode | `range` in practice (adapter normalizes via shared helper) |
-| Output modes | `pooled`, `grid` |
-| Extra side inputs | **required** `months` (per-frame month tokens), plus Galileo masks/tensors built by adapter |
-| Training alignment (adapter path) | Medium (depends on `FRAMES`, `IMG`, `PATCH`, normalization) |
+| Field                             | Value                                                                                       |
+| --------------------------------- | ------------------------------------------------------------------------------------------- |
+| Model ID                          | `galileo`                                                                                   |
+| Family / Backbone                 | Galileo `Encoder` from vendored local runtime                                               |
+| Adapter type                      | `on-the-fly`                                                                                |
+| Typical backend                   | provider-backed; prefer `backend="auto"` in public API                                      |
+| Primary input                     | S2 10-band time series (`T,C,H,W`)                                                          |
+| Default resolution                | 10m default provider fetch (`sensor.scale_m`)                                               |
+| Temporal mode                     | `range` in practice (adapter normalizes via shared helper)                                  |
+| Output modes                      | `pooled`, `grid`                                                                            |
+| Extra side inputs                 | **required** `months` (per-frame month tokens), plus Galileo masks/tensors built by adapter |
+| Training alignment (adapter path) | Medium (depends on `FRAMES`, `IMG`, `PATCH`, normalization)                                 |
 
 ---
 
@@ -68,20 +68,20 @@ Constraint:
 
 ## Environment Variables / Tuning Knobs
 
-| Env var | Default | Effect |
-|---|---|---|
-| `RS_EMBED_GALILEO_MODEL_SIZE` | `nano` | Galileo model size selector (`models//`) |
-| `RS_EMBED_GALILEO_MODEL_PATH` | unset | Local model folder override containing `config.json` + `encoder.pt` |
-| `RS_EMBED_GALILEO_HF_REPO` | `nasaharvest/galileo` | Hugging Face repo used for snapshot download |
-| `RS_EMBED_GALILEO_CACHE_DIR` | `~/.cache/rs_embed/galileo` | Download cache dir for model snapshots |
-| `RS_EMBED_GALILEO_AUTO_DOWNLOAD` | `1` | Auto-download model folder from Hugging Face when `MODEL_PATH` is unset |
-| `RS_EMBED_GALILEO_IMG` | `64` | Frame resize target |
-| `RS_EMBED_GALILEO_PATCH` | `8` | Encoder patch size |
-| `RS_EMBED_GALILEO_FRAMES` | `8` | Number of temporal frames `T` |
-| `RS_EMBED_GALILEO_NORM` | `none` | S2 normalization mode (`none`, `unit_scale`, `per_tile_minmax`, `official_stats`) |
-| `RS_EMBED_GALILEO_ADD_LN` | `1` | Add layer norm on encoder exit |
-| `RS_EMBED_GALILEO_MONTH` | unset | Force a constant month (1..12) for all frames |
-| `RS_EMBED_GALILEO_FETCH_WORKERS` | `8` | Prefetch workers for batch APIs |
+| Env var                          | Default                     | Effect                                                                            |
+| -------------------------------- | --------------------------- | --------------------------------------------------------------------------------- |
+| `RS_EMBED_GALILEO_MODEL_SIZE`    | `nano`                      | Galileo model size selector (`models//`)                                    |
+| `RS_EMBED_GALILEO_MODEL_PATH`    | unset                       | Local model folder override containing `config.json` + `encoder.pt`               |
+| `RS_EMBED_GALILEO_HF_REPO`       | `nasaharvest/galileo`       | Hugging Face repo used for snapshot download                                      |
+| `RS_EMBED_GALILEO_CACHE_DIR`     | `~/.cache/rs_embed/galileo` | Download cache dir for model snapshots                                            |
+| `RS_EMBED_GALILEO_AUTO_DOWNLOAD` | `1`                         | Auto-download model folder from Hugging Face when `MODEL_PATH` is unset           |
+| `RS_EMBED_GALILEO_IMG`           | `64`                        | Frame resize target                                                               |
+| `RS_EMBED_GALILEO_PATCH`         | `8`                         | Encoder patch size                                                                |
+| `RS_EMBED_GALILEO_FRAMES`        | `8`                         | Number of temporal frames `T`                                                     |
+| `RS_EMBED_GALILEO_NORM`          | `none`                      | S2 normalization mode (`none`, `unit_scale`, `per_tile_minmax`, `official_stats`) |
+| `RS_EMBED_GALILEO_ADD_LN`        | `1`                         | Add layer norm on encoder exit                                                    |
+| `RS_EMBED_GALILEO_MONTH`         | unset                       | Force a constant month (1..12) for all frames                                     |
+| `RS_EMBED_GALILEO_FETCH_WORKERS` | `8`                         | Prefetch workers for batch APIs                                                   |
 
 ---
 
diff --git a/docs/models/gse.md b/docs/models/gse.md
index 844d289..5f023d8 100644
--- a/docs/models/gse.md
+++ b/docs/models/gse.md
@@ -4,19 +4,19 @@
 
 ## Quick Facts
 
-| Field | Value |
-|---|---|
-| Model ID | `gse` |
-| Aliases | `gse_annual` |
-| Family / Source | Google Satellite Embedding annual product (`GOOGLE/SATELLITE_EMBEDDING/V1/ANNUAL`) |
-| Adapter type | `precomputed` |
-| Typical backend | provider-backed; prefer `backend="auto"` in public API |
-| Primary input | Provider-sampled annual embedding image collection |
-| Default resolution | 10m default provider sampling (`fetch.scale_m` / `sensor.scale_m`) |
-| Temporal mode | **strict** `TemporalSpec.year(...)` |
-| Output modes | `pooled`, `grid` |
-| Extra side inputs | none |
-| Training alignment (adapter path) | N/A (precomputed product) |
+| Field                             | Value                                                                              |
+| --------------------------------- | ---------------------------------------------------------------------------------- |
+| Model ID                          | `gse`                                                                              |
+| Aliases                           | `gse_annual`                                                                       |
+| Family / Source                   | Google Satellite Embedding annual product (`GOOGLE/SATELLITE_EMBEDDING/V1/ANNUAL`) |
+| Adapter type                      | `precomputed`                                                                      |
+| Typical backend                   | provider-backed; prefer `backend="auto"` in public API                             |
+| Primary input                     | Provider-sampled annual embedding image collection                                 |
+| Default resolution                | 10m default provider sampling (`fetch.scale_m` / `sensor.scale_m`)                 |
+| Temporal mode                     | **strict** `TemporalSpec.year(...)`                                                |
+| Output modes                      | `pooled`, `grid`                                                                   |
+| Extra side inputs                 | none                                                                               |
+| Training alignment (adapter path) | N/A (precomputed product)                                                          |
 
 ---
 
@@ -57,9 +57,9 @@ The provider fetch settings are fixed to collection `GOOGLE/SATELLITE_EMBEDDING/
 
 ## Environment Variables / Tuning Knobs
 
-| Env var | Default | Effect |
-|---|---|---|
-| `RS_EMBED_GSE_BATCH_WORKERS` | `4` | Batch worker count for `get_embeddings_batch(...)` |
+| Env var                      | Default | Effect                                             |
+| ---------------------------- | ------- | -------------------------------------------------- |
+| `RS_EMBED_GSE_BATCH_WORKERS` | `4`     | Batch worker count for `get_embeddings_batch(...)` |
 
 Primary non-env sampling knob:
 
diff --git a/docs/models/prithvi.md b/docs/models/prithvi.md
index 59dce95..92a76be 100644
--- a/docs/models/prithvi.md
+++ b/docs/models/prithvi.md
@@ -4,20 +4,20 @@
 
 ## Quick Facts
 
-| Field | Value |
-|---|---|
-| Model ID | `prithvi` |
-| Aliases | `prithvi_eo_v2_s2_6b` |
-| Family / Backbone | Prithvi-EO v2 via vendored `PrithviMAE` runtime |
-| Adapter type | `on-the-fly` |
-| Typical backend | provider backend (`gee` via public API) |
-| Primary input | S2 6-band (`BLUE,GREEN,RED,NIR_NARROW,SWIR_1,SWIR_2`) |
-| Default resolution | 30m default provider fetch (`sensor.scale_m`) |
-| Temporal mode | `range` preferred; adapter normalizes `year`/`None` to a range |
-| Output modes | `pooled`, `grid` |
-| Model config keys | `variant` (default: `prithvi_eo_v2_100_tl`) |
-| Extra side inputs | **required** temporal coords + location coords (derived by adapter) |
-| Training alignment (adapter path) | Medium (depends on preprocessing mode and resize/pad choices) |
+| Field                             | Value                                                               |
+| --------------------------------- | ------------------------------------------------------------------- |
+| Model ID                          | `prithvi`                                                           |
+| Aliases                           | `prithvi_eo_v2_s2_6b`                                               |
+| Family / Backbone                 | Prithvi-EO v2 via vendored `PrithviMAE` runtime                     |
+| Adapter type                      | `on-the-fly`                                                        |
+| Typical backend                   | provider backend (`gee` via public API)                             |
+| Primary input                     | S2 6-band (`BLUE,GREEN,RED,NIR_NARROW,SWIR_1,SWIR_2`)               |
+| Default resolution                | 30m default provider fetch (`sensor.scale_m`)                       |
+| Temporal mode                     | `range` preferred; adapter normalizes `year`/`None` to a range      |
+| Output modes                      | `pooled`, `grid`                                                    |
+| Model config keys                 | `variant` (default: `prithvi_eo_v2_100_tl`)                         |
+| Extra side inputs                 | **required** temporal coords + location coords (derived by adapter) |
+| Training alignment (adapter path) | Medium (depends on preprocessing mode and resize/pad choices)       |
 
 ---
 
@@ -27,7 +27,6 @@ Prithvi is a good fit for multispectral Sentinel-2 experiments that need more th
 
 Use carefully when comparing Prithvi against models without side inputs, because the derived time and location signals can affect behavior. It is also worth treating preprocessing mode (`resize` vs `pad`) as part of the experiment definition.
 
-
 ---
 
 ## Input Contract (Current Adapter Path)
@@ -72,24 +71,24 @@ The default sensor is `COPERNICUS/S2_SR_HARMONIZED` with bands `("BLUE", "GREEN"
 
 ## Environment Variables / Tuning Knobs
 
-| Env var | Default | Effect |
-|---|---|---|
-| `RS_EMBED_PRITHVI_KEY` | `prithvi_eo_v2_100_tl` | Prithvi variant selector |
-| `RS_EMBED_PRITHVI_PRETRAINED` | `1` | Use pretrained weights vs random init |
-| `RS_EMBED_PRITHVI_CACHE_DIR` | unset | Optional Hugging Face cache dir for config/checkpoint downloads |
-| `RS_EMBED_PRITHVI_WEIGHTS_ONLY` | `1` | `torch.load(..., weights_only=...)` compatibility toggle |
-| `RS_EMBED_PRITHVI_PREP` | `resize` | Input prep mode: `resize` or `pad` |
-| `RS_EMBED_PRITHVI_IMG` | `224` | Target square size for `resize` mode |
-| `RS_EMBED_PRITHVI_PATCH_MULT` | `16` | Pad multiple for `pad` mode |
-| `RS_EMBED_PRITHVI_FETCH_WORKERS` | `8` | Provider prefetch workers for batch APIs |
-| `RS_EMBED_PRITHVI_BATCH_SIZE` | CPU:`4`, CUDA:`16` | Inference batch size for batch APIs |
+| Env var                          | Default                | Effect                                                          |
+| -------------------------------- | ---------------------- | --------------------------------------------------------------- |
+| `RS_EMBED_PRITHVI_KEY`           | `prithvi_eo_v2_100_tl` | Prithvi variant selector                                        |
+| `RS_EMBED_PRITHVI_PRETRAINED`    | `1`                    | Use pretrained weights vs random init                           |
+| `RS_EMBED_PRITHVI_CACHE_DIR`     | unset                  | Optional Hugging Face cache dir for config/checkpoint downloads |
+| `RS_EMBED_PRITHVI_WEIGHTS_ONLY`  | `1`                    | `torch.load(..., weights_only=...)` compatibility toggle        |
+| `RS_EMBED_PRITHVI_PREP`          | `resize`               | Input prep mode: `resize` or `pad`                              |
+| `RS_EMBED_PRITHVI_IMG`           | `224`                  | Target square size for `resize` mode                            |
+| `RS_EMBED_PRITHVI_PATCH_MULT`    | `16`                   | Pad multiple for `pad` mode                                     |
+| `RS_EMBED_PRITHVI_FETCH_WORKERS` | `8`                    | Provider prefetch workers for batch APIs                        |
+| `RS_EMBED_PRITHVI_BATCH_SIZE`    | CPU:`4`, CUDA:`16`     | Inference batch size for batch APIs                             |
 
 ---
 
 ## Model-specific Settings
 
-| Key | Type | Default | Choices |
-|---|---|---|---|
+| Key       | Type     | Default                | Choices                                                                |
+| --------- | -------- | ---------------------- | ---------------------------------------------------------------------- |
 | `variant` | `string` | `prithvi_eo_v2_100_tl` | `prithvi_eo_v2_100_tl`, `prithvi_eo_v2_300_tl`, `prithvi_eo_v2_600_tl` |
 
 Notes:
diff --git a/docs/models/remoteclip.md b/docs/models/remoteclip.md
index 8b35eb1..adb0075 100644
--- a/docs/models/remoteclip.md
+++ b/docs/models/remoteclip.md
@@ -4,18 +4,18 @@
 
 ## Quick Facts
 
-| Field | Value |
-|---|---|
-| Model ID | `remoteclip` |
-| Aliases | `remoteclip_s2rgb` |
-| Family / Backbone | RemoteCLIP (CLIP-style ViT via `rshf.remoteclip.RemoteCLIP`) |
-| Adapter type | `on-the-fly` |
-| Typical backend | provider-backed; prefer `backend="auto"` in public API |
-| Primary input | S2 RGB (`B4,B3,B2`) |
-| Default resolution | 10m default provider fetch (`sensor.scale_m`) |
-| Temporal mode | `TemporalSpec.range(...)` required |
-| Output modes | `pooled`, `grid` |
-| Extra side inputs | none |
+| Field                             | Value                                                                                                            |
+| --------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
+| Model ID                          | `remoteclip`                                                                                                     |
+| Aliases                           | `remoteclip_s2rgb`                                                                                               |
+| Family / Backbone                 | RemoteCLIP (CLIP-style ViT via `rshf.remoteclip.RemoteCLIP`)                                                     |
+| Adapter type                      | `on-the-fly`                                                                                                     |
+| Typical backend                   | provider-backed; prefer `backend="auto"` in public API                                                           |
+| Primary input                     | S2 RGB (`B4,B3,B2`)                                                                                              |
+| Default resolution                | 10m default provider fetch (`sensor.scale_m`)                                                                    |
+| Temporal mode                     | `TemporalSpec.range(...)` required                                                                               |
+| Output modes                      | `pooled`, `grid`                                                                                                 |
+| Extra side inputs                 | none                                                                                                             |
 | Training alignment (adapter path) | Medium (higher if wrapper `model.transform(...)` matches training pipeline; fallback is generic CLIP preprocess) |
 
 ---
@@ -61,11 +61,11 @@ The image size is fixed at `224` in this adapter path.
 
 ## Environment Variables / Tuning Knobs
 
-| Env var | Default | Effect |
-|---|---|---|
-| `RS_EMBED_REMOTECLIP_FETCH_WORKERS` | `8` | Provider prefetch worker count for batch APIs |
-| `RS_EMBED_REMOTECLIP_BATCH_SIZE` | CPU:`8`, CUDA:`64` | Inference batch size for batch APIs |
-| `HUGGINGFACE_HUB_CACHE` / `HF_HOME` / `HUGGINGFACE_HOME` | unset | Controls HF cache path used for model snapshot downloads |
+| Env var                                                  | Default            | Effect                                                   |
+| -------------------------------------------------------- | ------------------ | -------------------------------------------------------- |
+| `RS_EMBED_REMOTECLIP_FETCH_WORKERS`                      | `8`                | Provider prefetch worker count for batch APIs            |
+| `RS_EMBED_REMOTECLIP_BATCH_SIZE`                         | CPU:`8`, CUDA:`64` | Inference batch size for batch APIs                      |
+| `HUGGINGFACE_HUB_CACHE` / `HF_HOME` / `HUGGINGFACE_HOME` | unset              | Controls HF cache path used for model snapshot downloads |
 
 Checkpoint override (not env-based in this adapter):
 
diff --git a/docs/models/satmae.md b/docs/models/satmae.md
index a3bab85..ffd918a 100644
--- a/docs/models/satmae.md
+++ b/docs/models/satmae.md
@@ -4,18 +4,18 @@
 
 ## Quick Facts
 
-| Field | Value |
-|---|---|
-| Model ID | `satmae` |
-| Aliases | `satmae_rgb` |
-| Family / Backbone | SatMAE via `rshf.satmae.SatMAE` |
-| Adapter type | `on-the-fly` |
-| Typical backend | provider backend (`gee`) |
-| Primary input | S2 RGB (`B4,B3,B2`) |
-| Default resolution | 10m default provider fetch (`sensor.scale_m`) |
-| Temporal mode | range window in practice (normalized via shared helper) |
-| Output modes | `pooled`, `grid` |
-| Extra side inputs | none |
+| Field                             | Value                                                                          |
+| --------------------------------- | ------------------------------------------------------------------------------ |
+| Model ID                          | `satmae`                                                                       |
+| Aliases                           | `satmae_rgb`                                                                   |
+| Family / Backbone                 | SatMAE via `rshf.satmae.SatMAE`                                                |
+| Adapter type                      | `on-the-fly`                                                                   |
+| Typical backend                   | provider backend (`gee`)                                                       |
+| Primary input                     | S2 RGB (`B4,B3,B2`)                                                            |
+| Default resolution                | 10m default provider fetch (`sensor.scale_m`)                                  |
+| Temporal mode                     | range window in practice (normalized via shared helper)                        |
+| Output modes                      | `pooled`, `grid`                                                               |
+| Extra side inputs                 | none                                                                           |
 | Training alignment (adapter path) | Medium-High (higher when wrapper `model.transform(...)` is available and used) |
 
 ---
@@ -68,12 +68,12 @@ The current adapter path always targets token output rather than pre-pooled wrap
 
 ## Environment Variables / Tuning Knobs
 
-| Env var | Default | Effect |
-|---|---|---|
-| `RS_EMBED_SATMAE_ID` | `MVRL/satmae-vitlarge-fmow-pretrain-800` | HF model ID used by `SatMAE.from_pretrained(...)` |
-| `RS_EMBED_SATMAE_IMG` | `224` | Resize / preprocess image size |
-| `RS_EMBED_SATMAE_FETCH_WORKERS` | `8` | Provider prefetch workers for batch APIs |
-| `RS_EMBED_SATMAE_BATCH_SIZE` | CPU:`8`, CUDA:`32` | Inference batch size for batch APIs |
+| Env var                         | Default                                  | Effect                                            |
+| ------------------------------- | ---------------------------------------- | ------------------------------------------------- |
+| `RS_EMBED_SATMAE_ID`            | `MVRL/satmae-vitlarge-fmow-pretrain-800` | HF model ID used by `SatMAE.from_pretrained(...)` |
+| `RS_EMBED_SATMAE_IMG`           | `224`                                    | Resize / preprocess image size                    |
+| `RS_EMBED_SATMAE_FETCH_WORKERS` | `8`                                      | Provider prefetch workers for batch APIs          |
+| `RS_EMBED_SATMAE_BATCH_SIZE`    | CPU:`8`, CUDA:`32`                       | Inference batch size for batch APIs               |
 
 ---
 
diff --git a/docs/models/satmaepp.md b/docs/models/satmaepp.md
index 6e99873..55023ea 100644
--- a/docs/models/satmaepp.md
+++ b/docs/models/satmaepp.md
@@ -4,18 +4,18 @@
 
 ## Quick Facts
 
-| Field | `satmaepp` (RGB) | `satmaepp_s2_10b` (S2-10B) |
-|---|---|---|
-| Canonical ID | `satmaepp` | `satmaepp_s2_10b` |
-| Aliases | `satmaepp_rgb`, `satmae++` | `satmaepp_sentinel10`, `satmaepp_s2` |
-| Adapter type | `on-the-fly` | `on-the-fly` |
-| Typical backend | provider backend (`gee`) | provider backend (`gee`) |
-| Primary input | S2 RGB (`B4,B3,B2`) | S2 SR 10-band (`B2,B3,B4,B5,B6,B7,B8,B8A,B11,B12`) |
-| Default resolution | 10m default provider fetch (`sensor.scale_m`) | 10m default provider fetch (`sensor.scale_m`) |
-| Temporal mode | range window + single composite | range window + single composite |
-| Output modes | `pooled`, `grid` | `pooled`, `grid` |
-| Model config keys | none | `variant` (default: `large`; choices: `large`) |
-| Core extraction | `forward_encoder(mask_ratio=0.0)` | `forward_encoder(mask_ratio=0.0)` |
+| Field              | `satmaepp` (RGB)                              | `satmaepp_s2_10b` (S2-10B)                         |
+| ------------------ | --------------------------------------------- | -------------------------------------------------- |
+| Canonical ID       | `satmaepp`                                    | `satmaepp_s2_10b`                                  |
+| Aliases            | `satmaepp_rgb`, `satmae++`                    | `satmaepp_sentinel10`, `satmaepp_s2`               |
+| Adapter type       | `on-the-fly`                                  | `on-the-fly`                                       |
+| Typical backend    | provider backend (`gee`)                      | provider backend (`gee`)                           |
+| Primary input      | S2 RGB (`B4,B3,B2`)                           | S2 SR 10-band (`B2,B3,B4,B5,B6,B7,B8,B8A,B11,B12`) |
+| Default resolution | 10m default provider fetch (`sensor.scale_m`) | 10m default provider fetch (`sensor.scale_m`)      |
+| Temporal mode      | range window + single composite               | range window + single composite                    |
+| Output modes       | `pooled`, `grid`                              | `pooled`, `grid`                                   |
+| Model config keys  | none                                          | `variant` (default: `large`; choices: `large`)     |
+| Core extraction    | `forward_encoder(mask_ratio=0.0)`             | `forward_encoder(mask_ratio=0.0)`                  |
 
 ---
 
@@ -66,14 +66,14 @@ The RGB variant defaults to `collection="COPERNICUS/S2_SR_HARMONIZED"`, `bands=(
 
 ### Key Environment Variables
 
-| Env var | Effect |
-|---|---|
-| `RS_EMBED_SATMAEPP_ID` | HF model ID / checkpoint selector |
-| `RS_EMBED_SATMAEPP_IMG` | Eval image size |
-| `RS_EMBED_SATMAEPP_CHANNEL_ORDER` | `rgb` or `bgr` preprocessing order |
-| `RS_EMBED_SATMAEPP_BGR` | Legacy BGR toggle |
+| Env var                           | Effect                                   |
+| --------------------------------- | ---------------------------------------- |
+| `RS_EMBED_SATMAEPP_ID`            | HF model ID / checkpoint selector        |
+| `RS_EMBED_SATMAEPP_IMG`           | Eval image size                          |
+| `RS_EMBED_SATMAEPP_CHANNEL_ORDER` | `rgb` or `bgr` preprocessing order       |
+| `RS_EMBED_SATMAEPP_BGR`           | Legacy BGR toggle                        |
 | `RS_EMBED_SATMAEPP_FETCH_WORKERS` | Provider prefetch workers for batch APIs |
-| `RS_EMBED_SATMAEPP_BATCH_SIZE` | Inference batch size for batch APIs |
+| `RS_EMBED_SATMAEPP_BATCH_SIZE`    | Inference batch size for batch APIs      |
 
 ### Common Failure Modes
 
@@ -114,17 +114,17 @@ This path is stricter than the RGB path: `sensor.bands` must exactly match the 1
 
 ### Key Environment Variables
 
-| Env var | Effect |
-|---|---|
-| `RS_EMBED_SATMAEPP_S2_CKPT_REPO` | Checkpoint repo/source |
-| `RS_EMBED_SATMAEPP_S2_CKPT_FILE` | Checkpoint filename |
-| `RS_EMBED_SATMAEPP_S2_MODEL_FN` | Model constructor name |
-| `RS_EMBED_SATMAEPP_S2_IMG` | Eval image size |
-| `RS_EMBED_SATMAEPP_S2_PATCH` | Patch size |
-| `RS_EMBED_SATMAEPP_S2_GRID_REDUCE` | Group reduction mode for grid output |
-| `RS_EMBED_SATMAEPP_S2_WEIGHTS_ONLY` | Weights-only checkpoint loading toggle |
+| Env var                              | Effect                                   |
+| ------------------------------------ | ---------------------------------------- |
+| `RS_EMBED_SATMAEPP_S2_CKPT_REPO`     | Checkpoint repo/source                   |
+| `RS_EMBED_SATMAEPP_S2_CKPT_FILE`     | Checkpoint filename                      |
+| `RS_EMBED_SATMAEPP_S2_MODEL_FN`      | Model constructor name                   |
+| `RS_EMBED_SATMAEPP_S2_IMG`           | Eval image size                          |
+| `RS_EMBED_SATMAEPP_S2_PATCH`         | Patch size                               |
+| `RS_EMBED_SATMAEPP_S2_GRID_REDUCE`   | Group reduction mode for grid output     |
+| `RS_EMBED_SATMAEPP_S2_WEIGHTS_ONLY`  | Weights-only checkpoint loading toggle   |
 | `RS_EMBED_SATMAEPP_S2_FETCH_WORKERS` | Provider prefetch workers for batch APIs |
-| `RS_EMBED_SATMAEPP_S2_BATCH_SIZE` | Inference batch size for batch APIs |
+| `RS_EMBED_SATMAEPP_S2_BATCH_SIZE`    | Inference batch size for batch APIs      |
 
 ### Common Failure Modes
 
diff --git a/docs/models/satvision.md b/docs/models/satvision.md
index 7fead0c..75c3c2f 100644
--- a/docs/models/satvision.md
+++ b/docs/models/satvision.md
@@ -4,18 +4,18 @@
 
 ## Quick Facts
 
-| Field | Value |
-|---|---|
-| Model ID | `satvision` |
-| Aliases | `satvision_toa` |
-| Family / Backbone | SatVision-TOA checkpoint (HF/local checkpoint loader) |
-| Adapter type | `on-the-fly` |
-| Typical backend | provider backend (`gee`) |
-| Primary input | 14-channel TOA `CHW` (default MODIS/061/MOD021KM band order) |
-| Default resolution | 1000m default provider fetch (`sensor.scale_m`) |
-| Temporal mode | `range` in practice (normalized via shared helper) |
-| Output modes | `pooled`, `grid` |
-| Extra side inputs | none (but channel calibration settings matter) |
+| Field                             | Value                                                                    |
+| --------------------------------- | ------------------------------------------------------------------------ |
+| Model ID                          | `satvision`                                                              |
+| Aliases                           | `satvision_toa`                                                          |
+| Family / Backbone                 | SatVision-TOA checkpoint (HF/local checkpoint loader)                    |
+| Adapter type                      | `on-the-fly`                                                             |
+| Typical backend                   | provider backend (`gee`)                                                 |
+| Primary input                     | 14-channel TOA `CHW` (default MODIS/061/MOD021KM band order)             |
+| Default resolution                | 1000m default provider fetch (`sensor.scale_m`)                          |
+| Temporal mode                     | `range` in practice (normalized via shared helper)                       |
+| Output modes                      | `pooled`, `grid`                                                         |
+| Extra side inputs                 | none (but channel calibration settings matter)                           |
 | Training alignment (adapter path) | High only when channel order + calibration match checkpoint expectations |
 
 ---
@@ -77,37 +77,37 @@ The adapter does not infer semantic channel order from the values themselves, so
 
 ### Model / weights
 
-| Env var | Default | Effect |
-|---|---|---|
-| `RS_EMBED_SATVISION_TOA_ID` | SatVision TOA HF model ID | HF model identifier |
-| `RS_EMBED_SATVISION_TOA_CKPT` | unset | Local checkpoint path override |
-| `RS_EMBED_SATVISION_TOA_AUTO_DOWNLOAD` | `1` | Allow HF download when local checkpoint not set |
-| `RS_EMBED_SATVISION_TOA_IMG` | `128` | Resize target image size |
-| `RS_EMBED_SATVISION_TOA_IN_CHANS` | `14` | Expected channel count |
-| `RS_EMBED_SATVISION_TOA_BATCH_SIZE` | CPU:`2`, CUDA:`8` | Inference batch size (batch APIs) |
-| `RS_EMBED_SATVISION_TOA_FETCH_WORKERS` | `8` | Provider prefetch workers (batch APIs) |
+| Env var                                | Default                   | Effect                                          |
+| -------------------------------------- | ------------------------- | ----------------------------------------------- |
+| `RS_EMBED_SATVISION_TOA_ID`            | SatVision TOA HF model ID | HF model identifier                             |
+| `RS_EMBED_SATVISION_TOA_CKPT`          | unset                     | Local checkpoint path override                  |
+| `RS_EMBED_SATVISION_TOA_AUTO_DOWNLOAD` | `1`                       | Allow HF download when local checkpoint not set |
+| `RS_EMBED_SATVISION_TOA_IMG`           | `128`                     | Resize target image size                        |
+| `RS_EMBED_SATVISION_TOA_IN_CHANS`      | `14`                      | Expected channel count                          |
+| `RS_EMBED_SATVISION_TOA_BATCH_SIZE`    | CPU:`2`, CUDA:`8`         | Inference batch size (batch APIs)               |
+| `RS_EMBED_SATVISION_TOA_FETCH_WORKERS` | `8`                       | Provider prefetch workers (batch APIs)          |
 
 ### Normalization / calibration
 
-| Env var | Default | Effect |
-|---|---|---|
-| `RS_EMBED_SATVISION_TOA_NORM` | `auto` | `auto`, `raw`, or `unit` |
-| `RS_EMBED_SATVISION_TOA_REFLECTANCE_IDXS` | adapter defaults | Reflectance channel indices |
-| `RS_EMBED_SATVISION_TOA_EMISSIVE_IDXS` | adapter defaults | Emissive channel indices |
-| `RS_EMBED_SATVISION_TOA_REF_DIV` | `100` | Reflectance divisor |
-| `RS_EMBED_SATVISION_TOA_EMISSIVE_MINS` | adapter defaults | Emissive min calibration values |
-| `RS_EMBED_SATVISION_TOA_EMISSIVE_MAXS` | adapter defaults | Emissive max calibration values |
+| Env var                                   | Default          | Effect                          |
+| ----------------------------------------- | ---------------- | ------------------------------- |
+| `RS_EMBED_SATVISION_TOA_NORM`             | `auto`           | `auto`, `raw`, or `unit`        |
+| `RS_EMBED_SATVISION_TOA_REFLECTANCE_IDXS` | adapter defaults | Reflectance channel indices     |
+| `RS_EMBED_SATVISION_TOA_EMISSIVE_IDXS`    | adapter defaults | Emissive channel indices        |
+| `RS_EMBED_SATVISION_TOA_REF_DIV`          | `100`            | Reflectance divisor             |
+| `RS_EMBED_SATVISION_TOA_EMISSIVE_MINS`    | adapter defaults | Emissive min calibration values |
+| `RS_EMBED_SATVISION_TOA_EMISSIVE_MAXS`    | adapter defaults | Emissive max calibration values |
 
 ### Default sensor overrides (if `sensor` omitted)
 
-| Env var | Default | Effect |
-|---|---|---|
-| `RS_EMBED_SATVISION_TOA_COLLECTION` | `MODIS/061/MOD021KM` | Default provider collection |
-| `RS_EMBED_SATVISION_TOA_BANDS` | default 14-band MODIS order | Override default band list |
-| `RS_EMBED_SATVISION_TOA_SCALE_M` | `1000` | Default fetch scale |
-| `RS_EMBED_SATVISION_TOA_CLOUDY_PCT` | `100` | Default cloud filter |
-| `RS_EMBED_SATVISION_TOA_FILL` | `0` | Default fill value |
-| `RS_EMBED_SATVISION_TOA_COMPOSITE` | `mosaic` | Default composite method |
+| Env var                             | Default                     | Effect                      |
+| ----------------------------------- | --------------------------- | --------------------------- |
+| `RS_EMBED_SATVISION_TOA_COLLECTION` | `MODIS/061/MOD021KM`        | Default provider collection |
+| `RS_EMBED_SATVISION_TOA_BANDS`      | default 14-band MODIS order | Override default band list  |
+| `RS_EMBED_SATVISION_TOA_SCALE_M`    | `1000`                      | Default fetch scale         |
+| `RS_EMBED_SATVISION_TOA_CLOUDY_PCT` | `100`                       | Default cloud filter        |
+| `RS_EMBED_SATVISION_TOA_FILL`       | `0`                         | Default fill value          |
+| `RS_EMBED_SATVISION_TOA_COMPOSITE`  | `mosaic`                    | Default composite method    |
 
 ---
 
diff --git a/docs/models/scalemae.md b/docs/models/scalemae.md
index fd5468f..3b80291 100644
--- a/docs/models/scalemae.md
+++ b/docs/models/scalemae.md
@@ -4,18 +4,18 @@
 
 ## Quick Facts
 
-| Field | Value |
-|---|---|
-| Model ID | `scalemae` |
-| Aliases | `scalemae_rgb` |
-| Family / Backbone | ScaleMAE via `rshf.scalemae.ScaleMAE` |
-| Adapter type | `on-the-fly` |
-| Typical backend | provider backend (`gee`) |
-| Primary input | S2 RGB (`B4,B3,B2`) + `input_res_m` |
-| Default resolution | 10m default provider fetch / semantic scale (`sensor.scale_m`) |
-| Temporal mode | range window in practice (normalized via shared helper) |
-| Output modes | `pooled`, `grid` |
-| Extra side inputs | **required semantic scale** (`sensor.scale_m` passed as `input_res_m`) |
+| Field                             | Value                                                                           |
+| --------------------------------- | ------------------------------------------------------------------------------- |
+| Model ID                          | `scalemae`                                                                      |
+| Aliases                           | `scalemae_rgb`                                                                  |
+| Family / Backbone                 | ScaleMAE via `rshf.scalemae.ScaleMAE`                                           |
+| Adapter type                      | `on-the-fly`                                                                    |
+| Typical backend                   | provider backend (`gee`)                                                        |
+| Primary input                     | S2 RGB (`B4,B3,B2`) + `input_res_m`                                             |
+| Default resolution                | 10m default provider fetch / semantic scale (`sensor.scale_m`)                  |
+| Temporal mode                     | range window in practice (normalized via shared helper)                         |
+| Output modes                      | `pooled`, `grid`                                                                |
+| Extra side inputs                 | **required semantic scale** (`sensor.scale_m` passed as `input_res_m`)          |
 | Training alignment (adapter path) | Medium-High when `sensor.scale_m` matches the actual input resolution semantics |
 
 ---
@@ -79,12 +79,12 @@ Important:
 
 ## Environment Variables / Tuning Knobs
 
-| Env var | Default | Effect |
-|---|---|---|
-| `RS_EMBED_SCALEMAE_ID` | `MVRL/scalemae-vitlarge-800` | HF model ID for `ScaleMAE.from_pretrained(...)` |
-| `RS_EMBED_SCALEMAE_IMG` | `224` | Resize / preprocess image size |
-| `RS_EMBED_SCALEMAE_FETCH_WORKERS` | `8` | Provider prefetch workers for batch APIs |
-| `RS_EMBED_SCALEMAE_BATCH_SIZE` | CPU:`8`, CUDA:`32` | Inference batch size for batch APIs |
+| Env var                           | Default                      | Effect                                          |
+| --------------------------------- | ---------------------------- | ----------------------------------------------- |
+| `RS_EMBED_SCALEMAE_ID`            | `MVRL/scalemae-vitlarge-800` | HF model ID for `ScaleMAE.from_pretrained(...)` |
+| `RS_EMBED_SCALEMAE_IMG`           | `224`                        | Resize / preprocess image size                  |
+| `RS_EMBED_SCALEMAE_FETCH_WORKERS` | `8`                          | Provider prefetch workers for batch APIs        |
+| `RS_EMBED_SCALEMAE_BATCH_SIZE`    | CPU:`8`, CUDA:`32`           | Inference batch size for batch APIs             |
 
 Non-env but critical:
 
diff --git a/docs/models/terrafm.md b/docs/models/terrafm.md
index b6f7774..e9789d0 100644
--- a/docs/models/terrafm.md
+++ b/docs/models/terrafm.md
@@ -4,19 +4,19 @@
 
 ## Quick Facts
 
-| Field | Value |
-|---|---|
-| Model ID | `terrafm` |
-| Aliases | `terrafm_b` |
-| Family / Backbone | TerraFM-B from Hugging Face (`MBZUAI/TerraFM`) |
-| Adapter type | `on-the-fly` |
-| Typical backend | provider backend (`gee`), also supports `backend="tensor"` |
-| Primary input | S2 SR 12-band or S1 VV/VH (selected by `sensor.modality`) |
-| Default resolution | 10m default provider fetch (`sensor.scale_m`) |
-| Temporal mode | provider path requires `TemporalSpec.range(...)` (v0.1 behavior) |
-| Output modes | `pooled`, `grid` |
-| Extra side inputs | modality settings on `sensor` (`modality`, `use_float_linear`, `s1_require_iw`, `s1_relax_iw_on_empty`) |
-| Training alignment (adapter path) | Medium-High when modality-specific preprocessing matches the intended TerraFM path |
+| Field                             | Value                                                                                                   |
+| --------------------------------- | ------------------------------------------------------------------------------------------------------- |
+| Model ID                          | `terrafm`                                                                                               |
+| Aliases                           | `terrafm_b`                                                                                             |
+| Family / Backbone                 | TerraFM-B from Hugging Face (`MBZUAI/TerraFM`)                                                          |
+| Adapter type                      | `on-the-fly`                                                                                            |
+| Typical backend                   | provider backend (`gee`), also supports `backend="tensor"`                                              |
+| Primary input                     | S2 SR 12-band or S1 VV/VH (selected by `sensor.modality`)                                               |
+| Default resolution                | 10m default provider fetch (`sensor.scale_m`)                                                           |
+| Temporal mode                     | provider path requires `TemporalSpec.range(...)` (v0.1 behavior)                                        |
+| Output modes                      | `pooled`, `grid`                                                                                        |
+| Extra side inputs                 | modality settings on `sensor` (`modality`, `use_float_linear`, `s1_require_iw`, `s1_relax_iw_on_empty`) |
+| Training alignment (adapter path) | Medium-High when modality-specific preprocessing matches the intended TerraFM path                      |
 
 ---
 
@@ -106,10 +106,10 @@ The tensor backend does apply the adapter's modality-specific normalization. In
 
 ## Environment Variables / Tuning Knobs
 
-| Env var | Default | Effect |
-|---|---|---|
-| `RS_EMBED_TERRAFM_FETCH_WORKERS` | `8` | Provider prefetch workers for batch APIs |
-| `RS_EMBED_TERRAFM_BATCH_SIZE` | CPU:`8`, CUDA:`64` | Inference batch size for batch APIs |
+| Env var                          | Default            | Effect                                   |
+| -------------------------------- | ------------------ | ---------------------------------------- |
+| `RS_EMBED_TERRAFM_FETCH_WORKERS` | `8`                | Provider prefetch workers for batch APIs |
+| `RS_EMBED_TERRAFM_BATCH_SIZE`    | CPU:`8`, CUDA:`64` | Inference batch size for batch APIs      |
 
 Related cache envs (used by HF asset download path):
 
diff --git a/docs/models/terramind.md b/docs/models/terramind.md
index 0b99f85..1955aaf 100644
--- a/docs/models/terramind.md
+++ b/docs/models/terramind.md
@@ -4,17 +4,17 @@
 
 ## Quick Facts
 
-| Field | Value |
-|---|---|
-| Model ID | `terramind` |
-| Family / Backbone | TerraMind via TerraTorch `BACKBONE_REGISTRY` |
-| Adapter type | `on-the-fly` |
-| Typical backend | provider backend (`gee`), also supports `backend="tensor"` |
-| Primary input | S2 SR 12-band (`B1..B12` subset used by adapter order) |
-| Default resolution | 10m default provider fetch (`sensor.scale_m`) |
-| Temporal mode | `range` (provider path normalized via shared helper) |
-| Output modes | `pooled`, `grid` |
-| Extra side inputs | none required in current adapter |
+| Field                             | Value                                                          |
+| --------------------------------- | -------------------------------------------------------------- |
+| Model ID                          | `terramind`                                                    |
+| Family / Backbone                 | TerraMind via TerraTorch `BACKBONE_REGISTRY`                   |
+| Adapter type                      | `on-the-fly`                                                   |
+| Typical backend                   | provider backend (`gee`), also supports `backend="tensor"`     |
+| Primary input                     | S2 SR 12-band (`B1..B12` subset used by adapter order)         |
+| Default resolution                | 10m default provider fetch (`sensor.scale_m`)                  |
+| Temporal mode                     | `range` (provider path normalized via shared helper)           |
+| Output modes                      | `pooled`, `grid`                                               |
+| Extra side inputs                 | none required in current adapter                               |
 | Training alignment (adapter path) | High when default TerraMind z-score normalization is preserved |
 
 ---
@@ -85,14 +85,14 @@ For provider overrides, `input_chw` must be `CHW` with 12 bands in the adapter f
 
 ## Environment Variables / Tuning Knobs
 
-| Env var | Default | Effect |
-|---|---|---|
-| `RS_EMBED_TERRAMIND_MODEL_KEY` | `terramind_v1_small` | TerraMind backbone key |
-| `RS_EMBED_TERRAMIND_MODALITY` | `S2L2A` | Modality passed to TerraMind/TerraTorch |
-| `RS_EMBED_TERRAMIND_NORMALIZE` | `zscore` | Input normalization mode (`zscore` vs raw/none) |
-| `RS_EMBED_TERRAMIND_LAYER_INDEX` | `-1` | Which layer output to select when sequence-like outputs are returned |
-| `RS_EMBED_TERRAMIND_PRETRAINED` | `1` | Use pretrained weights |
-| `RS_EMBED_TERRAMIND_FETCH_WORKERS` | `8` | Provider prefetch workers for batch APIs |
+| Env var                            | Default              | Effect                                                               |
+| ---------------------------------- | -------------------- | -------------------------------------------------------------------- |
+| `RS_EMBED_TERRAMIND_MODEL_KEY`     | `terramind_v1_small` | TerraMind backbone key                                               |
+| `RS_EMBED_TERRAMIND_MODALITY`      | `S2L2A`              | Modality passed to TerraMind/TerraTorch                              |
+| `RS_EMBED_TERRAMIND_NORMALIZE`     | `zscore`             | Input normalization mode (`zscore` vs raw/none)                      |
+| `RS_EMBED_TERRAMIND_LAYER_INDEX`   | `-1`                 | Which layer output to select when sequence-like outputs are returned |
+| `RS_EMBED_TERRAMIND_PRETRAINED`    | `1`                  | Use pretrained weights                                               |
+| `RS_EMBED_TERRAMIND_FETCH_WORKERS` | `8`                  | Provider prefetch workers for batch APIs                             |
 
 Fixed adapter behavior:
 
diff --git a/docs/models/tessera.md b/docs/models/tessera.md
index 5320b4b..f4450d1 100644
--- a/docs/models/tessera.md
+++ b/docs/models/tessera.md
@@ -4,19 +4,19 @@
 
 ## Quick Facts
 
-| Field | Value |
-|---|---|
-| Model ID | `tessera` |
-| Family / Source | GeoTessera precomputed embeddings |
-| Adapter type | `precomputed` |
-| Typical backend | `auto` |
-| Primary input | `BBox` / `PointBuffer` in EPSG:4326 (converted to bbox) |
-| Product grid CRS | fixed tile-native CRS (not the common provider-backed EPSG:3857 default) |
-| Default resolution | 10m source product resolution |
-| Temporal mode | year-like selection (`year`; `range` uses start year fallback) |
-| Output modes | `pooled`, `grid` |
-| Extra side inputs | none |
-| Training alignment (adapter path) | N/A (precomputed product) |
+| Field                             | Value                                                                    |
+| --------------------------------- | ------------------------------------------------------------------------ |
+| Model ID                          | `tessera`                                                                |
+| Family / Source                   | GeoTessera precomputed embeddings                                        |
+| Adapter type                      | `precomputed`                                                            |
+| Typical backend                   | `auto`                                                                   |
+| Primary input                     | `BBox` / `PointBuffer` in EPSG:4326 (converted to bbox)                  |
+| Product grid CRS                  | fixed tile-native CRS (not the common provider-backed EPSG:3857 default) |
+| Default resolution                | 10m source product resolution                                            |
+| Temporal mode                     | year-like selection (`year`; `range` uses start year fallback)           |
+| Output modes                      | `pooled`, `grid`                                                         |
+| Extra side inputs                 | none                                                                     |
+| Training alignment (adapter path) | N/A (precomputed product)                                                |
 
 ---
 
@@ -33,7 +33,7 @@ Tessera is a strong choice for fast precomputed baselines, large-area ROI extrac
 The adapter accepts `BBox` directly and `PointBuffer`, which it converts to `BBox` in EPSG:4326 using an approximate meter-to-degree conversion. Unsupported spatial types raise `ModelError`.
 
 !!! warning
-    Tessera still reads and returns embeddings in the product-native tile CRS after crop. That CRS may differ from the more common provider-backed EPSG:3857 sampling default used elsewhere in `rs-embed`, even though the public spatial input is still `EPSG:4326`.
+Tessera still reads and returns embeddings in the product-native tile CRS after crop. That CRS may differ from the more common provider-backed EPSG:3857 sampling default used elsewhere in `rs-embed`, even though the public spatial input is still `EPSG:4326`.
 
 ### Temporal
 
@@ -67,10 +67,10 @@ The backend should be `auto`, although legacy `local` is still accepted for comp
 
 ## Environment Variables / Tuning Knobs
 
-| Env var | Default | Effect |
-|---|---|---|
-| `RS_EMBED_TESSERA_CACHE` | unset (GeoTessera default) | Local GeoTessera cache directory |
-| `RS_EMBED_TESSERA_BATCH_WORKERS` | `4` | Batch worker count for `get_embeddings_batch(...)` |
+| Env var                          | Default                    | Effect                                             |
+| -------------------------------- | -------------------------- | -------------------------------------------------- |
+| `RS_EMBED_TESSERA_CACHE`         | unset (GeoTessera default) | Local GeoTessera cache directory                   |
+| `RS_EMBED_TESSERA_BATCH_WORKERS` | `4`                        | Batch worker count for `get_embeddings_batch(...)` |
 
 Non-env override:
 
diff --git a/docs/models/thor.md b/docs/models/thor.md
index 5562a13..8743aba 100644
--- a/docs/models/thor.md
+++ b/docs/models/thor.md
@@ -4,20 +4,20 @@
 
 ## Quick Facts
 
-| Field | Value |
-|---|---|
-| Model ID | `thor` |
-| Aliases | `thor_1_0_base` |
-| Family / Backbone | Fully vendored THOR runtime (`thor_v1_tiny` / `thor_v1_small` / `thor_v1_base` / `thor_v1_large`) |
-| Adapter type | `on-the-fly` |
-| Typical backend | provider backend (`gee`) |
-| Primary input | S2 SR 10-band `CHW` |
-| Default resolution | 10m default provider fetch (`sensor.scale_m`) |
-| Temporal mode | `range` in practice (composite window) |
-| Output modes | `pooled`, `grid` |
-| Model config keys | `variant` (default: `base`; choices: `tiny`, `small`, `base`, `large`) |
-| Extra side inputs | none required in current adapter |
-| Training alignment (adapter path) | High when `thor_stats` normalization and default S2 SR setup are preserved |
+| Field                             | Value                                                                                             |
+| --------------------------------- | ------------------------------------------------------------------------------------------------- |
+| Model ID                          | `thor`                                                                                            |
+| Aliases                           | `thor_1_0_base`                                                                                   |
+| Family / Backbone                 | Fully vendored THOR runtime (`thor_v1_tiny` / `thor_v1_small` / `thor_v1_base` / `thor_v1_large`) |
+| Adapter type                      | `on-the-fly`                                                                                      |
+| Typical backend                   | provider backend (`gee`)                                                                          |
+| Primary input                     | S2 SR 10-band `CHW`                                                                               |
+| Default resolution                | 10m default provider fetch (`sensor.scale_m`)                                                     |
+| Temporal mode                     | `range` in practice (composite window)                                                            |
+| Output modes                      | `pooled`, `grid`                                                                                  |
+| Model config keys                 | `variant` (default: `base`; choices: `tiny`, `small`, `base`, `large`)                            |
+| Extra side inputs                 | none required in current adapter                                                                  |
+| Training alignment (adapter path) | High when `thor_stats` normalization and default S2 SR setup are preserved                        |
 
 ---
 
@@ -71,16 +71,16 @@ The default sensor is `COPERNICUS/S2_SR_HARMONIZED` with adapter band order `B2,
 
 ## Environment Variables / Tuning Knobs
 
-| Env var | Default | Effect |
-|---|---|---|
-| `RS_EMBED_THOR_MODEL_KEY` | `thor_v1_base` | THOR backbone key for the vendored runtime |
-| `RS_EMBED_THOR_CKPT` | unset | Local checkpoint path override |
-| `RS_EMBED_THOR_PRETRAINED` | `1` | Use pretrained weights (HF default path) |
-| `RS_EMBED_THOR_IMG` | `288` | Resize target image size |
-| `RS_EMBED_THOR_NORMALIZE` | `thor_stats` | `thor_stats`, `unit_scale`, or `none` |
-| `RS_EMBED_THOR_GROUP_MERGE` | `mean` | THOR group-grid aggregation: `mean`, `sum`, `concat` |
-| `RS_EMBED_THOR_PATCH_SIZE` | `16` | THOR flexi patch size parameter |
-| `RS_EMBED_THOR_FETCH_WORKERS` | `8` | Provider prefetch workers for batch APIs |
+| Env var                       | Default        | Effect                                               |
+| ----------------------------- | -------------- | ---------------------------------------------------- |
+| `RS_EMBED_THOR_MODEL_KEY`     | `thor_v1_base` | THOR backbone key for the vendored runtime           |
+| `RS_EMBED_THOR_CKPT`          | unset          | Local checkpoint path override                       |
+| `RS_EMBED_THOR_PRETRAINED`    | `1`            | Use pretrained weights (HF default path)             |
+| `RS_EMBED_THOR_IMG`           | `288`          | Resize target image size                             |
+| `RS_EMBED_THOR_NORMALIZE`     | `thor_stats`   | `thor_stats`, `unit_scale`, or `none`                |
+| `RS_EMBED_THOR_GROUP_MERGE`   | `mean`         | THOR group-grid aggregation: `mean`, `sum`, `concat` |
+| `RS_EMBED_THOR_PATCH_SIZE`    | `16`           | THOR flexi patch size parameter                      |
+| `RS_EMBED_THOR_FETCH_WORKERS` | `8`            | Provider prefetch workers for batch APIs             |
 
 Notes:
 
@@ -88,9 +88,9 @@ Notes:
 
 ## Model-specific Settings
 
-| Key | Type | Default | Choices | Notes |
-|---|---|---|---|---|
-| `variant` | `string` | `base` | `tiny`, `small`, `base`, `large` | Backbone size selector. For export jobs, pass it through `ExportModelRequest.configure("thor", variant=...)`. |
+| Key       | Type     | Default | Choices                          | Notes                                                                                                         |
+| --------- | -------- | ------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------- |
+| `variant` | `string` | `base`  | `tiny`, `small`, `base`, `large` | Backbone size selector. For export jobs, pass it through `ExportModelRequest.configure("thor", variant=...)`. |
 
 Example:
 
diff --git a/docs/models/wildsat.md b/docs/models/wildsat.md
index a963cc4..8c9ceb3 100644
--- a/docs/models/wildsat.md
+++ b/docs/models/wildsat.md
@@ -4,17 +4,17 @@
 
 ## Quick Facts
 
-| Field | Value |
-|---|---|
-| Model ID | `wildsat` |
-| Family / Backbone | WildSAT checkpoint loader + torchvision backbones (`vitb16`, `vitl16`, `resnet50`, `swint`) |
-| Adapter type | `on-the-fly` |
-| Typical backend | provider backend (`gee`) |
-| Primary input | S2 RGB (`B4,B3,B2`) |
-| Default resolution | 10m default provider fetch (`sensor.scale_m`) |
-| Temporal mode | `range` in practice (normalized via shared helper) |
-| Output modes | `pooled`, `grid` |
-| Extra side inputs | none (but checkpoint/arch/image-head settings matter) |
+| Field                             | Value                                                                                         |
+| --------------------------------- | --------------------------------------------------------------------------------------------- |
+| Model ID                          | `wildsat`                                                                                     |
+| Family / Backbone                 | WildSAT checkpoint loader + torchvision backbones (`vitb16`, `vitl16`, `resnet50`, `swint`)   |
+| Adapter type                      | `on-the-fly`                                                                                  |
+| Typical backend                   | provider backend (`gee`)                                                                      |
+| Primary input                     | S2 RGB (`B4,B3,B2`)                                                                           |
+| Default resolution                | 10m default provider fetch (`sensor.scale_m`)                                                 |
+| Temporal mode                     | `range` in practice (normalized via shared helper)                                            |
+| Output modes                      | `pooled`, `grid`                                                                              |
+| Extra side inputs                 | none (but checkpoint/arch/image-head settings matter)                                         |
 | Training alignment (adapter path) | Medium (depends on checkpoint source, arch inference, normalization mode, and feature source) |
 
 ---
@@ -73,29 +73,29 @@ If `grid` is requested but ViT tokens are unavailable, for example with a non-Vi
 
 ### Runtime / feature extraction
 
-| Env var | Default | Effect |
-|---|---|---|
-| `RS_EMBED_WILDSAT_ARCH` | `auto` | Backbone arch hint (`vitb16`, `vitl16`, `resnet50`, `swint`, or `auto`) |
-| `RS_EMBED_WILDSAT_IMG` | `224` | Resize target image size |
-| `RS_EMBED_WILDSAT_NORM` | `minmax` | `minmax`, `unit_scale`, or `none` |
-| `RS_EMBED_WILDSAT_FEATURE` | `image_head` | Feature source: `auto`, `image_head`, `backbone` |
-| `RS_EMBED_WILDSAT_IMAGE_BRANCH` | `3` | Preferred decoder branch for image head extraction |
-| `RS_EMBED_WILDSAT_POOLED_FROM_TOKENS` | `0` | If true and ViT tokens available, pooled output uses token pooling |
-| `RS_EMBED_WILDSAT_GRID_FROM_TOKENS` | `1` | Enable ViT token extraction for grid/token-based pooling |
-| `RS_EMBED_WILDSAT_FETCH_WORKERS` | `8` | Provider prefetch workers for batch APIs |
+| Env var                               | Default      | Effect                                                                  |
+| ------------------------------------- | ------------ | ----------------------------------------------------------------------- |
+| `RS_EMBED_WILDSAT_ARCH`               | `auto`       | Backbone arch hint (`vitb16`, `vitl16`, `resnet50`, `swint`, or `auto`) |
+| `RS_EMBED_WILDSAT_IMG`                | `224`        | Resize target image size                                                |
+| `RS_EMBED_WILDSAT_NORM`               | `minmax`     | `minmax`, `unit_scale`, or `none`                                       |
+| `RS_EMBED_WILDSAT_FEATURE`            | `image_head` | Feature source: `auto`, `image_head`, `backbone`                        |
+| `RS_EMBED_WILDSAT_IMAGE_BRANCH`       | `3`          | Preferred decoder branch for image head extraction                      |
+| `RS_EMBED_WILDSAT_POOLED_FROM_TOKENS` | `0`          | If true and ViT tokens available, pooled output uses token pooling      |
+| `RS_EMBED_WILDSAT_GRID_FROM_TOKENS`   | `1`          | Enable ViT token extraction for grid/token-based pooling                |
+| `RS_EMBED_WILDSAT_FETCH_WORKERS`      | `8`          | Provider prefetch workers for batch APIs                                |
 
 ### Checkpoint path / download
 
-| Env var | Default | Effect |
-|---|---|---|
-| `RS_EMBED_WILDSAT_CKPT` | unset | Local checkpoint path |
-| `RS_EMBED_WILDSAT_AUTO_DOWNLOAD` | `1` | Allow auto-download if `CKPT` not set |
-| `RS_EMBED_WILDSAT_CACHE_DIR` | `~/.cache/rs_embed/wildsat` | Checkpoint cache dir |
-| `RS_EMBED_WILDSAT_CKPT_MIN_BYTES` | adapter threshold | Download size sanity check |
-| `RS_EMBED_WILDSAT_GDRIVE_ID` | official sample file id | Google Drive source (default auto-download path) |
-| `RS_EMBED_WILDSAT_CKPT_FILE` | `vitb16-imagenet-bnfc.pth` | Local cached filename for GDrive path |
-| `RS_EMBED_WILDSAT_HF_REPO` | unset | Optional HF repo override (must pair with `HF_FILE`) |
-| `RS_EMBED_WILDSAT_HF_FILE` | unset | Optional HF file override (must pair with `HF_REPO`) |
+| Env var                           | Default                     | Effect                                               |
+| --------------------------------- | --------------------------- | ---------------------------------------------------- |
+| `RS_EMBED_WILDSAT_CKPT`           | unset                       | Local checkpoint path                                |
+| `RS_EMBED_WILDSAT_AUTO_DOWNLOAD`  | `1`                         | Allow auto-download if `CKPT` not set                |
+| `RS_EMBED_WILDSAT_CACHE_DIR`      | `~/.cache/rs_embed/wildsat` | Checkpoint cache dir                                 |
+| `RS_EMBED_WILDSAT_CKPT_MIN_BYTES` | adapter threshold           | Download size sanity check                           |
+| `RS_EMBED_WILDSAT_GDRIVE_ID`      | official sample file id     | Google Drive source (default auto-download path)     |
+| `RS_EMBED_WILDSAT_CKPT_FILE`      | `vitb16-imagenet-bnfc.pth`  | Local cached filename for GDrive path                |
+| `RS_EMBED_WILDSAT_HF_REPO`        | unset                       | Optional HF repo override (must pair with `HF_FILE`) |
+| `RS_EMBED_WILDSAT_HF_FILE`        | unset                       | Optional HF file override (must pair with `HF_REPO`) |
 
 ---
 
diff --git a/docs/models_reference.md b/docs/models_reference.md
index 67f8fa8..7d89016 100644
--- a/docs/models_reference.md
+++ b/docs/models_reference.md
@@ -25,11 +25,11 @@ Some linked detail-page filenames still retain older names for compatibility.
 
 ## Precomputed Embeddings
 
-| **Model** | **ID** | **Output** | **Resolution** | **Dim** | **Time Coverage** | **Notes** |
-|---|---|---|---|---|---|---|
-| **Tessera** | `tessera` | pooled / grid | 10m | 128 | 2017–2025 | GeoTessera global tile embeddings |
-| **Google Satellite Embedding (Alpha Earth)** | `gse` | pooled / grid | 10 m | 64 | 2017–2024 | Annual embeddings via GEE |
-| **Copernicus Embed** | `copernicus` | pooled / grid | 0.25° | 768 | 2021 | Official Copernicus embeddings |
+| **Model**                                    | **ID**       | **Output**    | **Resolution** | **Dim** | **Time Coverage** | **Notes**                         |
+| -------------------------------------------- | ------------ | ------------- | -------------- | ------- | ----------------- | --------------------------------- |
+| **Tessera**                                  | `tessera`    | pooled / grid | 10m            | 128     | 2017–2025         | GeoTessera global tile embeddings |
+| **Google Satellite Embedding (Alpha Earth)** | `gse`        | pooled / grid | 10 m           | 64      | 2017–2024         | Annual embeddings via GEE         |
+| **Copernicus Embed**                         | `copernicus` | pooled / grid | 0.25°          | 768     | 2021              | Official Copernicus embeddings    |
 
 ---
 
@@ -41,28 +41,28 @@ The source of truth for this section is the adapter code in `src/rs_embed/embedd
 
 Use this table for a first-pass side-by-side comparison of input assumptions and preprocessing behavior.
 
-| Model ID | Architecture / Backbone | Default Fetch Resolution | Input | Default Preprocessing | Resize / Crop / Pad | Output Structure | Training Alignment |
-|---|---|---|---|---|---|---|---|
-| `remoteclip` | `rshf.remoteclip.RemoteCLIP` (open_clip style CLIP ViT) | 10m | S2 RGB (`B4,B3,B2`) | raw SR `0..10000` -> `/10000` -> RGB `uint8`; then model transform if available, else CLIP norm | image size 224; fallback path uses `Resize + CenterCrop`; no pad | pooled vector or ViT token grid | Medium (high if wrapper transform matches training; fallback is generic CLIP pipeline) |
-| `satmae` | `rshf.satmae.SatMAE` | 10m | S2 RGB (`B4,B3,B2`) | raw SR -> `/10000` -> RGB `uint8`; prefer model transform, else CLIP norm | default 224; CLIP fallback has `Resize + CenterCrop`; no pad | token sequence -> pooled or patch-token grid | Medium |
-| `satmaepp` | `rshf.satmaepp.SatMAEPP` | 10m | S2 RGB (`B4,B3,B2`) | raw SR -> `/10000` -> RGB `uint8`; SatMAE++ fMoW eval preprocessing (`Normalize + Resize(short side) + CenterCrop`), default channel order `bgr` | default 224; source-aligned short-side resize + center crop; no pad | token sequence -> pooled or patch-token grid | High |
-| `satmaepp_s2_10b` | SatMAE++ grouped-channel source branch (`models_mae_group_channels.py`, `base` / `large` runtime families) | 10m | S2 SR 10-band (`B2,B3,B4,B5,B6,B7,B8,B8A,B11,B12`) | clip `0..10000`; source Sentinel min/max mapping to `uint8`; `ToTensor + Resize(short side) + CenterCrop` | default 96 with patch size 8; source-style resize/crop; no pad | grouped token sequence -> pooled or group-reduced spatial token grid | High |
-| `scalemae` | `rshf.scalemae.ScaleMAE` (ViT style) | 10m | S2 RGB (`B4,B3,B2`) + `input_res_m` | raw SR -> `/10000` -> RGB `uint8`; CLIP norm tensor; pass `input_res_m` | default 224; CLIP path has `Resize + CenterCrop`; no pad | token sequence or pooled vector depending on wrapper output | Medium |
-| `anysat` | AnySat from upstream `hubconf.py` (`AnySat`, `tiny` / `small` / `base`) | 10m | S2 10-band TCHW (or CHW auto-expanded) | clip to `0..10000`; normalize mode default `per_tile_zscore`; builds per-frame `s2_dates` | resize TCHW to default 24; no crop, no pad | grid defaults to dense sub-patch output `[D,H,W]`; pooled defaults to patch-grid mean/max, optional native tile vector | Medium |
-| `galileo` | `Encoder` from official `single_file_galileo.py` | 10m | S2 10-band TCHW (or CHW auto-expanded) | clip to `0..10000`; normalize mode default `none` with optional `official_stats`; constructs Galileo tensors with configurable `T` + per-frame `months` | default 64 with patch 8; bilinear resize; no pad | pooled token vector and official-style patch-mean token grid | Medium |
-| `wildsat` | WildSAT backbone + optional image head from checkpoint | 10m | S2 RGB CHW | clip to `0..10000` then `/10000`; default normalization `minmax`; convert to `uint8` then unit tensor | default 224; resize RGB; no pad | pooled branch output and optional grid (token or feature path) | Medium-Low |
-| `prithvi` | Vendored `PrithviMAE` runtime with HF checkpoints | 30m | S2 6-band (`BLUE,GREEN,RED,NIR_NARROW,SWIR_1,SWIR_2`) | raw SR -> `/10000` -> clamp `[0,1]`; prep mode from env | default mode `resize` to 224; optional `pad` to patch multiple (legacy) | token sequence -> pooled or patch-token grid | Medium |
-| `terrafm` | TerraFM-B from vendored runtime + HF weights | 10m | S2 12-band or S1 VV/VH | S2: `/10000` to `[0,1]`; S1: `log1p` + p99 scaling to `[0,1]` | resize to 224; no pad | pooled embedding, optional feature-map grid | Medium |
-| `terramind` | TerraTorch `BACKBONE_REGISTRY` TerraMind backbone | 10m | S2 SR 12-band | raw `0..10000`; resize 224; z-score with TerraMind v1/v01 pretrained mean/std | fixed 224; no pad | token sequence -> pooled or patch-token grid | High |
-| `dofa` | DOFA ViT (`base` / `large`, official checkpoints) | 10m | multi-band SR CHW + wavelengths | raw SR `0..10000` -> `0..255`-like scale -> official per-band mean/std; provide/infer wavelengths | bilinear resize to 224; explicitly no crop/pad | pooled vector or token grid (usually 14x14) | Medium-High |
-| `fomo` | FoMo `MultiSpectralViT` (FoMo-Bench) | 10m | S2 SR 12-band | clip `0..10000`; default `unit_scale` (optional minmax/none) | default 64; bilinear resize; no pad | token sequence pooled; grid as spectral-mean patch-token map | Medium |
-| `thor` | Fully vendored THOR runtime (`tiny` / `small` / `base` / `large`) | 10m | S2 SR 10-band | clip `0..10000`; default `thor_stats` z-score after reflectance scaling | default 288; bilinear resize; no pad | pooled tokens and grouped token grid | Medium-High |
-| `agrifm` | AgriFM `PretrainingSwinTransformer3DEncoder` | 10m | S2 10-band time series `[T,C,H,W]` | clip `0..10000`; default `agrifm_stats` z-score using official config stats | default 224; TCHW resize; no pad | feature map grid `[D,H,W]`, pooled by spatial mean/max | High |
-| `satvision` | `timm` `SwinTransformerV2` (SatVision-TOA checkpoints) | 1000m | TOA 14 channels in strict order | channel-aware normalization to `[0,1]` (`auto/raw/unit`, reflectance + emissive calibration) | default 128; bilinear resize; no pad | model output as pooled or grid depending on tensor shape | High (if band order and calibration match checkpoint) |
+| Model ID          | Architecture / Backbone                                                                                    | Default Fetch Resolution | Input                                                 | Default Preprocessing                                                                                                                                   | Resize / Crop / Pad                                                     | Output Structure                                                                                                       | Training Alignment                                                                     |
+| ----------------- | ---------------------------------------------------------------------------------------------------------- | ------------------------ | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
+| `remoteclip`      | `rshf.remoteclip.RemoteCLIP` (open_clip style CLIP ViT)                                                    | 10m                      | S2 RGB (`B4,B3,B2`)                                   | raw SR `0..10000` -> `/10000` -> RGB `uint8`; then model transform if available, else CLIP norm                                                         | image size 224; fallback path uses `Resize + CenterCrop`; no pad        | pooled vector or ViT token grid                                                                                        | Medium (high if wrapper transform matches training; fallback is generic CLIP pipeline) |
+| `satmae`          | `rshf.satmae.SatMAE`                                                                                       | 10m                      | S2 RGB (`B4,B3,B2`)                                   | raw SR -> `/10000` -> RGB `uint8`; prefer model transform, else CLIP norm                                                                               | default 224; CLIP fallback has `Resize + CenterCrop`; no pad            | token sequence -> pooled or patch-token grid                                                                           | Medium                                                                                 |
+| `satmaepp`        | `rshf.satmaepp.SatMAEPP`                                                                                   | 10m                      | S2 RGB (`B4,B3,B2`)                                   | raw SR -> `/10000` -> RGB `uint8`; SatMAE++ fMoW eval preprocessing (`Normalize + Resize(short side) + CenterCrop`), default channel order `bgr`        | default 224; source-aligned short-side resize + center crop; no pad     | token sequence -> pooled or patch-token grid                                                                           | High                                                                                   |
+| `satmaepp_s2_10b` | SatMAE++ grouped-channel source branch (`models_mae_group_channels.py`, `base` / `large` runtime families) | 10m                      | S2 SR 10-band (`B2,B3,B4,B5,B6,B7,B8,B8A,B11,B12`)    | clip `0..10000`; source Sentinel min/max mapping to `uint8`; `ToTensor + Resize(short side) + CenterCrop`                                               | default 96 with patch size 8; source-style resize/crop; no pad          | grouped token sequence -> pooled or group-reduced spatial token grid                                                   | High                                                                                   |
+| `scalemae`        | `rshf.scalemae.ScaleMAE` (ViT style)                                                                       | 10m                      | S2 RGB (`B4,B3,B2`) + `input_res_m`                   | raw SR -> `/10000` -> RGB `uint8`; CLIP norm tensor; pass `input_res_m`                                                                                 | default 224; CLIP path has `Resize + CenterCrop`; no pad                | token sequence or pooled vector depending on wrapper output                                                            | Medium                                                                                 |
+| `anysat`          | AnySat from upstream `hubconf.py` (`AnySat`, `tiny` / `small` / `base`)                                    | 10m                      | S2 10-band TCHW (or CHW auto-expanded)                | clip to `0..10000`; normalize mode default `per_tile_zscore`; builds per-frame `s2_dates`                                                               | resize TCHW to default 24; no crop, no pad                              | grid defaults to dense sub-patch output `[D,H,W]`; pooled defaults to patch-grid mean/max, optional native tile vector | Medium                                                                                 |
+| `galileo`         | `Encoder` from official `single_file_galileo.py`                                                           | 10m                      | S2 10-band TCHW (or CHW auto-expanded)                | clip to `0..10000`; normalize mode default `none` with optional `official_stats`; constructs Galileo tensors with configurable `T` + per-frame `months` | default 64 with patch 8; bilinear resize; no pad                        | pooled token vector and official-style patch-mean token grid                                                           | Medium                                                                                 |
+| `wildsat`         | WildSAT backbone + optional image head from checkpoint                                                     | 10m                      | S2 RGB CHW                                            | clip to `0..10000` then `/10000`; default normalization `minmax`; convert to `uint8` then unit tensor                                                   | default 224; resize RGB; no pad                                         | pooled branch output and optional grid (token or feature path)                                                         | Medium-Low                                                                             |
+| `prithvi`         | Vendored `PrithviMAE` runtime with HF checkpoints                                                          | 30m                      | S2 6-band (`BLUE,GREEN,RED,NIR_NARROW,SWIR_1,SWIR_2`) | raw SR -> `/10000` -> clamp `[0,1]`; prep mode from env                                                                                                 | default mode `resize` to 224; optional `pad` to patch multiple (legacy) | token sequence -> pooled or patch-token grid                                                                           | Medium                                                                                 |
+| `terrafm`         | TerraFM-B from vendored runtime + HF weights                                                               | 10m                      | S2 12-band or S1 VV/VH                                | S2: `/10000` to `[0,1]`; S1: `log1p` + p99 scaling to `[0,1]`                                                                                           | resize to 224; no pad                                                   | pooled embedding, optional feature-map grid                                                                            | Medium                                                                                 |
+| `terramind`       | TerraTorch `BACKBONE_REGISTRY` TerraMind backbone                                                          | 10m                      | S2 SR 12-band                                         | raw `0..10000`; resize 224; z-score with TerraMind v1/v01 pretrained mean/std                                                                           | fixed 224; no pad                                                       | token sequence -> pooled or patch-token grid                                                                           | High                                                                                   |
+| `dofa`            | DOFA ViT (`base` / `large`, official checkpoints)                                                          | 10m                      | multi-band SR CHW + wavelengths                       | raw SR `0..10000` -> `0..255`-like scale -> official per-band mean/std; provide/infer wavelengths                                                       | bilinear resize to 224; explicitly no crop/pad                          | pooled vector or token grid (usually 14x14)                                                                            | Medium-High                                                                            |
+| `fomo`            | FoMo `MultiSpectralViT` (FoMo-Bench)                                                                       | 10m                      | S2 SR 12-band                                         | clip `0..10000`; default `unit_scale` (optional minmax/none)                                                                                            | default 64; bilinear resize; no pad                                     | token sequence pooled; grid as spectral-mean patch-token map                                                           | Medium                                                                                 |
+| `thor`            | Fully vendored THOR runtime (`tiny` / `small` / `base` / `large`)                                          | 10m                      | S2 SR 10-band                                         | clip `0..10000`; default `thor_stats` z-score after reflectance scaling                                                                                 | default 288; bilinear resize; no pad                                    | pooled tokens and grouped token grid                                                                                   | Medium-High                                                                            |
+| `agrifm`          | AgriFM `PretrainingSwinTransformer3DEncoder`                                                               | 10m                      | S2 10-band time series `[T,C,H,W]`                    | clip `0..10000`; default `agrifm_stats` z-score using official config stats                                                                             | default 224; TCHW resize; no pad                                        | feature map grid `[D,H,W]`, pooled by spatial mean/max                                                                 | High                                                                                   |
+| `satvision`       | `timm` `SwinTransformerV2` (SatVision-TOA checkpoints)                                                     | 1000m                    | TOA 14 channels in strict order                       | channel-aware normalization to `[0,1]` (`auto/raw/unit`, reflectance + emissive calibration)                                                            | default 128; bilinear resize; no pad                                    | model output as pooled or grid depending on tensor shape                                                               | High (if band order and calibration match checkpoint)                                  |
 
 Here, "Default Fetch Resolution" refers to the default source-side resolution used when fetching raw inputs. It does not mean the final spatial size of the tensor after model-specific resize, crop, or pad.
 
-### Temporal Handling 
+### Temporal Handling
 
 Read this section before comparing any model that accepts `TemporalSpec.range(...)`.
 
@@ -80,11 +80,11 @@ All three split `TemporalSpec.range(start, end)` into `T` equal end-exclusive su
 
 Per-model temporal packaging:
 
-| Model ID | Frame count env (default) | Temporal side input | Notes |
-|---|---|---|---|
-| `agrifm` | `RS_EMBED_AGRIFM_FRAMES` (`8`) | none (uses `TCHW` directly) | Temporal information is encoded only in the frame stack. |
-| `anysat` | `RS_EMBED_ANYSAT_FRAMES` (`8`) | `s2_dates` (per-frame DOY, `0..364`) | DOY values are derived from each frame bin midpoint date. |
-| `galileo` | `RS_EMBED_GALILEO_FRAMES` (`8`) | `months` (per-frame month, `1..12`) | By default from frame bin midpoints; `RS_EMBED_GALILEO_MONTH` can force a constant month for all frames. |
+| Model ID  | Frame count env (default)       | Temporal side input                  | Notes                                                                                                    |
+| --------- | ------------------------------- | ------------------------------------ | -------------------------------------------------------------------------------------------------------- |
+| `agrifm`  | `RS_EMBED_AGRIFM_FRAMES` (`8`)  | none (uses `TCHW` directly)          | Temporal information is encoded only in the frame stack.                                                 |
+| `anysat`  | `RS_EMBED_ANYSAT_FRAMES` (`8`)  | `s2_dates` (per-frame DOY, `0..364`) | DOY values are derived from each frame bin midpoint date.                                                |
+| `galileo` | `RS_EMBED_GALILEO_FRAMES` (`8`) | `months` (per-frame month, `1..12`)  | By default from frame bin midpoints; `RS_EMBED_GALILEO_MONTH` can force a constant month for all frames. |
 
 ### Modality and Extra Inputs Matrix
 
@@ -94,24 +94,24 @@ Interpretation:
 
 "Backbone multimodal" means the upstream model family supports multiple modalities. "Current rs-embed path" means what this implementation actually feeds today. "Requires extra metadata" means the forward path needs non-image inputs as a hard requirement.
 
-| Model ID | Backbone multimodal? | Current rs-embed path uses multiple modalities? | Multi-input forward (beyond image tensor)? | Requires extra metadata? |
-|---|---|---|---|---|
-| `remoteclip` | No | No | No | No |
-| `satmae` | No | No | No | No |
-| `satmaepp` | No | No | No | No |
-| `satmaepp_s2_10b` | No (this adapter path) | No | No | No (but strict 10-band order is required) |
-| `scalemae` | No | No | Yes (`input_res_m`) | Yes: scale/resolution (`sensor.scale_m`) |
-| `anysat` | Yes | Partially (S2-only imagery, plus temporal date tokens) | Yes (`s2`, `s2_dates`) | Yes: day-of-year/date signal (derived from temporal range) |
-| `galileo` | Yes | Mostly S2 path in current adapter + temporal month tokens | Yes (multiple tensors + masks + `months`) | Yes: month/time signal (derived from temporal range) |
-| `wildsat` | No | No | No | No |
-| `prithvi` | No (this adapter path) | No | Yes (`x`, `temporal_coords`, `location_coords`) | Yes: location + time are required |
-| `terrafm` | Yes (`S1`/`S2`) | Yes (select one modality per call: `s1` or `s2`) | No | No hard extra metadata (optional S1 options: orbit, linear/DB path) |
-| `terramind` | Yes | Usually single selected modality (`S2L2A` default) | No (single selected modality tensor in this adapter) | No hard extra metadata |
-| `dofa` | Yes (spectral generalization) | Yes (multi-band spectral input) | Yes (image + wavelength list) | Yes: per-band wavelengths (explicit or inferable from bands) |
-| `fomo` | No | No | No | No |
-| `thor` | No (this adapter path) | No | No | No |
-| `agrifm` | No (this adapter path) | No | No extra side tensor, but temporal stack `[T,C,H,W]` required | Temporal coverage is important (no separate metadata tensor) |
-| `satvision` | No (this adapter path) | No | No separate side tensor | Yes: strict 14-channel order/calibration schema (band semantics) |
+| Model ID          | Backbone multimodal?          | Current rs-embed path uses multiple modalities?           | Multi-input forward (beyond image tensor)?                    | Requires extra metadata?                                            |
+| ----------------- | ----------------------------- | --------------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------- |
+| `remoteclip`      | No                            | No                                                        | No                                                            | No                                                                  |
+| `satmae`          | No                            | No                                                        | No                                                            | No                                                                  |
+| `satmaepp`        | No                            | No                                                        | No                                                            | No                                                                  |
+| `satmaepp_s2_10b` | No (this adapter path)        | No                                                        | No                                                            | No (but strict 10-band order is required)                           |
+| `scalemae`        | No                            | No                                                        | Yes (`input_res_m`)                                           | Yes: scale/resolution (`sensor.scale_m`)                            |
+| `anysat`          | Yes                           | Partially (S2-only imagery, plus temporal date tokens)    | Yes (`s2`, `s2_dates`)                                        | Yes: day-of-year/date signal (derived from temporal range)          |
+| `galileo`         | Yes                           | Mostly S2 path in current adapter + temporal month tokens | Yes (multiple tensors + masks + `months`)                     | Yes: month/time signal (derived from temporal range)                |
+| `wildsat`         | No                            | No                                                        | No                                                            | No                                                                  |
+| `prithvi`         | No (this adapter path)        | No                                                        | Yes (`x`, `temporal_coords`, `location_coords`)               | Yes: location + time are required                                   |
+| `terrafm`         | Yes (`S1`/`S2`)               | Yes (select one modality per call: `s1` or `s2`)          | No                                                            | No hard extra metadata (optional S1 options: orbit, linear/DB path) |
+| `terramind`       | Yes                           | Usually single selected modality (`S2L2A` default)        | No (single selected modality tensor in this adapter)          | No hard extra metadata                                              |
+| `dofa`            | Yes (spectral generalization) | Yes (multi-band spectral input)                           | Yes (image + wavelength list)                                 | Yes: per-band wavelengths (explicit or inferable from bands)        |
+| `fomo`            | No                            | No                                                        | No                                                            | No                                                                  |
+| `thor`            | No (this adapter path)        | No                                                        | No                                                            | No                                                                  |
+| `agrifm`          | No (this adapter path)        | No                                                        | No extra side tensor, but temporal stack `[T,C,H,W]` required | Temporal coverage is important (no separate metadata tensor)        |
+| `satvision`       | No (this adapter path)        | No                                                        | No separate side tensor                                       | Yes: strict 14-channel order/calibration schema (band semantics)    |
 
 In practice, the most obviously multi-input models here are `prithvi` (image plus temporal and location coordinates), `anysat` (time series plus `s2_dates`), `galileo` (image-derived tensors plus masks and `months`), `dofa` (image plus wavelengths), and `scalemae` (image plus `input_res_m`).
 
@@ -119,24 +119,24 @@ In practice, the most obviously multi-input models here are `prithvi` (image plu
 
 This table only lists env vars that materially change model input construction or temporal packaging.
 
-| Model ID | Main preprocessing env keys |
-|---|---|
-| `remoteclip` | fixed `image_size=224` in code path; no per-model preprocess env switch |
-| `satmae` | `RS_EMBED_SATMAE_IMG` |
-| `satmaepp` | `RS_EMBED_SATMAEPP_ID`, `RS_EMBED_SATMAEPP_IMG`, `RS_EMBED_SATMAEPP_CHANNEL_ORDER`, `RS_EMBED_SATMAEPP_BGR` |
+| Model ID          | Main preprocessing env keys                                                                                                                                                                                                            |
+| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `remoteclip`      | fixed `image_size=224` in code path; no per-model preprocess env switch                                                                                                                                                                |
+| `satmae`          | `RS_EMBED_SATMAE_IMG`                                                                                                                                                                                                                  |
+| `satmaepp`        | `RS_EMBED_SATMAEPP_ID`, `RS_EMBED_SATMAEPP_IMG`, `RS_EMBED_SATMAEPP_CHANNEL_ORDER`, `RS_EMBED_SATMAEPP_BGR`                                                                                                                            |
 | `satmaepp_s2_10b` | `RS_EMBED_SATMAEPP_S2_CKPT_REPO`, `RS_EMBED_SATMAEPP_S2_CKPT_FILE`, `RS_EMBED_SATMAEPP_S2_MODEL_FN`, `RS_EMBED_SATMAEPP_S2_IMG`, `RS_EMBED_SATMAEPP_S2_PATCH`, `RS_EMBED_SATMAEPP_S2_GRID_REDUCE`, `RS_EMBED_SATMAEPP_S2_WEIGHTS_ONLY` |
-| `scalemae` | `RS_EMBED_SCALEMAE_IMG` |
-| `anysat` | `RS_EMBED_ANYSAT_IMG`, `RS_EMBED_ANYSAT_NORM`, `RS_EMBED_ANYSAT_FRAMES`, `RS_EMBED_ANYSAT_GRID_MODE`, `RS_EMBED_ANYSAT_POOLED_SOURCE` |
-| `galileo` | `RS_EMBED_GALILEO_IMG`, `RS_EMBED_GALILEO_PATCH`, `RS_EMBED_GALILEO_NORM`, `RS_EMBED_GALILEO_FRAMES`, `RS_EMBED_GALILEO_MONTH` |
-| `wildsat` | `RS_EMBED_WILDSAT_IMG`, `RS_EMBED_WILDSAT_NORM` |
-| `prithvi` | `RS_EMBED_PRITHVI_PREP`, `RS_EMBED_PRITHVI_IMG`, `RS_EMBED_PRITHVI_PATCH_MULT` |
-| `terrafm` | modality and sensor-side options (`s2`/`s1`); image size fixed to 224 in implementation |
-| `terramind` | `RS_EMBED_TERRAMIND_NORMALIZE` (default z-score stats), image size fixed 224 |
-| `dofa` | image size fixed 224; provider/tensor channels and wavelengths drive preprocessing |
-| `fomo` | `RS_EMBED_FOMO_IMG`, `RS_EMBED_FOMO_NORM` |
-| `thor` | `RS_EMBED_THOR_IMG`, `RS_EMBED_THOR_NORMALIZE` |
-| `agrifm` | `RS_EMBED_AGRIFM_IMG`, `RS_EMBED_AGRIFM_NORM`, `RS_EMBED_AGRIFM_FRAMES` |
-| `satvision` | `RS_EMBED_SATVISION_TOA_IMG`, `RS_EMBED_SATVISION_TOA_NORM`, channel-index and calibration env keys |
+| `scalemae`        | `RS_EMBED_SCALEMAE_IMG`                                                                                                                                                                                                                |
+| `anysat`          | `RS_EMBED_ANYSAT_IMG`, `RS_EMBED_ANYSAT_NORM`, `RS_EMBED_ANYSAT_FRAMES`, `RS_EMBED_ANYSAT_GRID_MODE`, `RS_EMBED_ANYSAT_POOLED_SOURCE`                                                                                                  |
+| `galileo`         | `RS_EMBED_GALILEO_IMG`, `RS_EMBED_GALILEO_PATCH`, `RS_EMBED_GALILEO_NORM`, `RS_EMBED_GALILEO_FRAMES`, `RS_EMBED_GALILEO_MONTH`                                                                                                         |
+| `wildsat`         | `RS_EMBED_WILDSAT_IMG`, `RS_EMBED_WILDSAT_NORM`                                                                                                                                                                                        |
+| `prithvi`         | `RS_EMBED_PRITHVI_PREP`, `RS_EMBED_PRITHVI_IMG`, `RS_EMBED_PRITHVI_PATCH_MULT`                                                                                                                                                         |
+| `terrafm`         | modality and sensor-side options (`s2`/`s1`); image size fixed to 224 in implementation                                                                                                                                                |
+| `terramind`       | `RS_EMBED_TERRAMIND_NORMALIZE` (default z-score stats), image size fixed 224                                                                                                                                                           |
+| `dofa`            | image size fixed 224; provider/tensor channels and wavelengths drive preprocessing                                                                                                                                                     |
+| `fomo`            | `RS_EMBED_FOMO_IMG`, `RS_EMBED_FOMO_NORM`                                                                                                                                                                                              |
+| `thor`            | `RS_EMBED_THOR_IMG`, `RS_EMBED_THOR_NORMALIZE`                                                                                                                                                                                         |
+| `agrifm`          | `RS_EMBED_AGRIFM_IMG`, `RS_EMBED_AGRIFM_NORM`, `RS_EMBED_AGRIFM_FRAMES`                                                                                                                                                                |
+| `satvision`       | `RS_EMBED_SATVISION_TOA_IMG`, `RS_EMBED_SATVISION_TOA_NORM`, channel-index and calibration env keys                                                                                                                                    |
 
 ### Practical Guidance
 
diff --git a/docs/quickstart.md b/docs/quickstart.md
index c2c99d8..54d7e39 100644
--- a/docs/quickstart.md
+++ b/docs/quickstart.md
@@ -28,7 +28,6 @@ cd rs-embed
 pip install -e .  # use -e ".[terratorch]" if you need terramind
 ```
 
-
 Repository examples are available in `examples/playground.ipynb` and `examples/quickstart.py`.
 
 If this is your first time using Google Earth Engine, authenticate once:
@@ -62,7 +61,6 @@ meta = emb.meta
 
 Use `backend="auto"` unless you need to force a provider path such as `backend="gee"`.
 
-
 ### 2. Many ROIs, one model: `get_embeddings_batch(...)`
 
 Use this when the model is fixed and you have multiple ROIs.
diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css
index 1973025..9a8bcf8 100644
--- a/docs/stylesheets/extra.css
+++ b/docs/stylesheets/extra.css
@@ -13,7 +13,11 @@
   --rs-inline-code-bg: rgba(15, 23, 42, 0.06);
   --rs-inline-code-color: #334155;
   --rs-warm-soft: rgba(180, 120, 35, 0.08);
-  --rs-pipeline-bg: linear-gradient(180deg, rgba(247, 250, 252, 0.98), rgba(240, 247, 245, 0.98));
+  --rs-pipeline-bg: linear-gradient(
+    180deg,
+    rgba(247, 250, 252, 0.98),
+    rgba(240, 247, 245, 0.98)
+  );
   --rs-pipeline-step: #0f172a;
   --rs-pipeline-arrow: #1f7a66;
   --rs-pipeline-branch: #3452a5;
@@ -275,5 +279,4 @@
   .md-typeset h2 {
     font-size: 1.2rem;
   }
-
 }
diff --git a/mkdocs.yml b/mkdocs.yml
index 5f904a0..c93910e 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -59,39 +59,39 @@ not_in_nav: |
 
 nav:
   - Home:
-    - Overview: index.md
-    - Quickstart: quickstart.md
+      - Overview: index.md
+      - Quickstart: quickstart.md
   - Models:
-    - Overview: models.md
-    - Advanced Reference: models_reference.md
-    - Precomputed:
-      - Tessera: models/tessera.md
-      - GSE: models/gse.md
-      - Copernicus: models/copernicus.md
-    - On-the-fly:
-      - RemoteCLIP: models/remoteclip.md
-      - SatMAE: models/satmae.md
-      - SatMAE++: models/satmaepp.md
-      - ScaleMAE: models/scalemae.md
-      - WildSAT: models/wildsat.md
-      - Prithvi: models/prithvi.md
-      - TerraFM: models/terrafm.md
-      - TerraMind: models/terramind.md
-      - DOFA: models/dofa.md
-      - FoMo: models/fomo.md
-      - THOR: models/thor.md
-      - SatVision: models/satvision.md
-      - AnySat: models/anysat.md
-      - Galileo: models/galileo.md
-      - AgriFM: models/agrifm.md
+      - Overview: models.md
+      - Advanced Reference: models_reference.md
+      - Precomputed:
+          - Tessera: models/tessera.md
+          - GSE: models/gse.md
+          - Copernicus: models/copernicus.md
+      - On-the-fly:
+          - RemoteCLIP: models/remoteclip.md
+          - SatMAE: models/satmae.md
+          - SatMAE++: models/satmaepp.md
+          - ScaleMAE: models/scalemae.md
+          - WildSAT: models/wildsat.md
+          - Prithvi: models/prithvi.md
+          - TerraFM: models/terrafm.md
+          - TerraMind: models/terramind.md
+          - DOFA: models/dofa.md
+          - FoMo: models/fomo.md
+          - THOR: models/thor.md
+          - SatVision: models/satvision.md
+          - AnySat: models/anysat.md
+          - Galileo: models/galileo.md
+          - AgriFM: models/agrifm.md
   - API:
-    - Overview: api.md
-    - Specs & Data Structures: api_specs.md
-    - Embedding API: api_embedding.md
-    - Export API: api_export.md
-    - Inspect API: api_inspect.md
+      - Overview: api.md
+      - Specs & Data Structures: api_specs.md
+      - Embedding API: api_embedding.md
+      - Export API: api_export.md
+      - Inspect API: api_inspect.md
   - Extending:
-    - Overview: extending.md
-    - Contributing Guide: contributing.md
+      - Overview: extending.md
+      - Contributing Guide: contributing.md
   - Project:
-    - Releases and Versioning: releases.md
+      - Releases and Versioning: releases.md