Перейти к содержанию

Карты: OSM vs Яндекс vs 2GIS — что реально вкрутить в этот репозиторий

Дата исследования: 2026-09-17. Ветка: fix4/maps-research (от release/m1). Это не обзор «какой ГИС лучше», а выбор подложки под уже написанный MapCanvas и два стенда.


Brief (EN)

Recommend: self-hosted OSM vector tiles (Planetiler → PMTiles) + Copernicus DEM GLO-30 as terrain-RGB. This is the only option that keeps MapLibre + deck.gl, satisfies the isolated simulator stand (SIM-BIZ-09: no internet, no tile keys), and gives the planner a real DEM for terrain-following / AGL — already designed as MAP-08.

Fallback: Yandex Maps Tiles API as a MapLibre raster source, internet stands only (https://aerozveno.ff). Since 2025-06-03 Tiles API is a separate product that explicitly allows Leaflet / OpenLayers-class renderers. It does not replace DEM, has no satellite, and is illegal to archive for the isolated sim (cache ≤ 30 days). Do not scrape JS API v3 tiles into MapLibre — commercial JS API terms require display “solely by means of the Software”.

Kill: 2GIS MapGL as primary. Vector tiles may be consumed only through MapGL JS API; that replaces MapLibre and breaks the existing deck.gl overlay. On-Prem MVT export is an enterprise cycle, not a 15-day hackathon.

OpenFreeMap public CDN (https://tiles.openfreemap.org/styles/liberty) is phase 0 of the recommended path (same style format, one URL swap), not a third vendor. Acceptable for a hackathon demo on aerozveno (browsers have internet). Not acceptable as the sim-stand basemap.


1. Ограничения этого проекта (проверено в репо)

Каждый пункт — факт из кода или доки, не из общих знаний.

Факт Где
Карта уже есть: MapLibre GL JS 5 + deck.gl 9, MapboxOverlay src/frontend/apps/planner/package.json:13-22, src/frontend/README.md:3
Стиль сейчас — пустой фон, ноль sources / glyphs / sprite MapCanvas.tsx:20-24 (OFFLINE_STYLE)
Overlay в режиме interleaved: false; на terrain-RGB надо вернуть true MapCanvas.tsx:75-80; критерий — docs/task5/92-code/03-map-and-3d.md:61-71
attributionControl: false — при живой подложке это нарушение OSM/Яндекс MapCanvas.tsx:70
Подписи — TextLayer deck.gl, не symbol MapLibre: symbol требует glyphs-сервер MapCanvas.tsx:16-18, src/frontend/README.md:149-151
Рельеф — синтетика terrainAt(), диапазон 112…288 м MSL, район [37.6488, 55.7712] packages/domain/src/terrain.ts:15-36
Модель полёта — огибание рельефа (terrain following), иначе GSD плывёт terrain.ts:69-72, src/frontend/README.md:142-144
Целевой прод: DEM → terrain-RGB + maplibre-contour; подложка — OSM в PMTiles src/frontend/README.md:99-100; docs/task5/50-stack/04-frontend-3d.md:133-146
Задача MAP-08 уже расписана: протокол pmtiles://, raster-dem, тест MAP-R-13 docs/task5/92-code/03-map-and-3d.md:560,604
Бесполётные зоны и разрешённое ВП рисует deck.gl (nfz, allowed), не тайлы провайдера apps/planner/src/map/layers.ts:64-106
Стенд продукта: https://aerozveno.ff, кластер n1, ns aerozveno docs/task5/95-deploy/frontend-on-aerozveno.md:3,14; docs/task5/99-release/00-release-notes.md:140-142
Статику отдаёт nginx из MinIO (aerozveno-frontend) через mc mirror k3s/aerozveno/45-deployment-frontend.yaml:1-22,60
Симулятор обязан подняться без интернета и без ключей тайл-сервисов simulate/docs/90-final/02-requirements-registry.md:414 (SIM-BIZ-09, MUST)
Заказчик: третий вход — «карта высотных препятствий» (Q-09) docs/task5/00-brief/06-customer-qa-2026-09-16.md:102-109
Geoscan Planner по умолчанию берёт карту высот GEM и кеширует её офлайн docs/task5/20-analogs/01-geoscan-planner.md:39-41
Своя топосъёмка заказчика (GeoTIFF) имеет приоритет над любой глобальной ЦМР simulate/docs/10-world/01-geodata-sources.md:84-85,109
Браузеры пользователей aerozveno имеют интернет; стенд — tailnet-only CLAUDE.md (домен .ff); факт задачи
Диск n1 ≈ 800 ГБ свободно (данное задания; аэрозвено уже живёт на n1) не в репо — принимаем как ограничение стенда

Следствие, от которого крутится вся матрица: подложка — это style у уже существующего MapLibre, а не новый виджет. Слои галсов / БПЗ / полос захвата трогать не надо (layers.ts не знает про тайлы). Сломать это ради «привычной» Яндекс/2GIS-картинки — переписать MapCanvas и, для 2GIS-вектора, выкинуть MapLibre.


2. Три убийственных вопроса

2.1. Можно ли кормить тайлы Яндекса / 2GIS в MapLibre?

Яндекс JS API v3 — нет. Коммерческие «Условия использования» JS API (не путать с Tiles API):

  • п. 1.1.2: доводить полученное изображение до сведения только при помощи ПО (то есть JavaScript API Яндекс Карт);
  • п. 2.2.1: «Лицензиат имеет право обрабатывать получаемые данные исключительно для отображения их посредством ПО».

Источник: yandex.ru/dev/tariffs/doc/kk/jsapi/terms/ и EN yandex.com/dev/tariffs/doc/en/jsapi/terms/, прочитано 2026-09-17. Это как раз тот исторический запрет «не свой рендерер».

Кастомные слои / Deck внутри ymaps3 — да, документация это показывает (Custom layer implementations, прочитано 2026-09-17). Это замена MapLibre на Яндекс как движок вида, а не «тайлы в MapLibre».

Яндекс Tiles API — да, растром. Это отдельный сервис с 03.06.2025 бесплатный для коммерции и некоммерции. Продуктовая страница прямо пишет: тайлы «подходят для работы в популярных библиотеках для веб-картографии: Leaflet, OpenLayers и других» (yandex.ru/maps-api/products/tiles-api, 2026-09-17). Юридически п. 6.5.1 соглашения (yandex.ru/legal/maps_api, публикация 15.06.2026): пользователь вправе получать тайлы «как для коммерческого, так и для некоммерческого использования, в открытых и закрытых системах» и класть свои данные поверх. MapLibre в этом списке не назван по имени; класс «и других» / Leaflet-совместимый XYZ — достаточное основание, чтобы считать растровый source допустимым. Это не разрешение выдрать тайлы из JS API.

Ограничения Tiles API, проверенные по доке (Общие сведения, 2026-09-17):

  • только тип «схема»; спутник и гибрид недоступны;
  • 30 RPS на бесплатном тарифе;
  • логотип Яндекса нужно повесить самим;
  • проекция: projection=web_mercator обязательна, иначе сетка разъедется с deck.gl (формат запроса).

Общие запреты того же соглашения (дата публикации 15.06.2026):

  • п. 5.1.5 — хранить данные дольше 30 дней нельзя (кроме временного кеша). Офлайн-архив для симулятора этим пунктом закрыт;
  • п. 5.1.3 — системы мониторинга ТС / диспетчеризации в реальном времени — только на коммерческом тарифе. Планировщик (не live-трекинг) ближе к п. 6.5.1, но если на карте появятся «борт сейчас» с живым каналом — риск вырастет. Не замалчиваем.

2GIS вектор — нет. Официальный FAQ (docs.2gis.com/en/maps/overview, 2026-09-17):

Vector tiles: to access the Map Tiles API, you can use only the MapGL JS API library.

И там же: «Direct integration of vector tiles without using a library or SDK 2GIS is not supported» (Map Tiles API). Обход — On-Premise API Platform и экспорт MVT mapbox (6–14 ГБ, не хакатонный цикл) (Exporting vector tiles).

2GIS растр — серая зона. Тот же FAQ: сторонние библиотеки «можно», но «compatibility with 2GIS raster maps is not guaranteed and may be disrupted at any time without notice». Для демо-стенда с чужим ToS это не опора.

Текст «Services Use Agreement» на law.2gis.ae/rules/ (прочитано 2026-09-17) — общее пользовательское соглашение платформы 2GIS, не специфика Map Tiles. Российский law.2gis.ru в этой сессии не верифицирован дословно (см. §8). Опираемся на документацию API, не на догадку по .ae.

2.2. OSM: что стоит self-host по РФ и можно ли OpenFreeMap на демо?

Данные OSM — ODbL 1.0, атрибуция «© OpenStreetMap contributors» обязательна (Attribution Guidelines). Публичные рендеры OSMF — не «данные свободны ⇒ сервер свободен»:

  • tile.openstreetmap.org: офлайн и bulk запрещены явно, §4 (Tile Usage Policy, 2026-09-17);
  • vector.openstreetmap.org: то же — scraping / offline archive запрещены (Vector Tile Usage Policy).

Для этого репозитория tile.openstreetmap.org как прод-подложка неприемлема: MAP-R-13 запрещает внешние URL в стиле (92-code/03-map-and-3d.md:560), SIM-BIZ-09 запрещает ключи и сеть на симуляторе, а OSMF ещё и офлайн-пакет со своих серверов запрещает.

Self-host векторных тайлов по РФ — реалистичен на n1. Инструмент: Planetiler (OpenMapTiles-схема, выход PMTiles), Java 21+, без PostGIS (README Planetiler, 2026-09-17):

Экстракт PBF (Geofabrik, снимок ~2026-09-11) RAM Planetiler Диск temp (5–10× PBF) Оценка PMTiles
Демо-bbox s04 (~14×14 км вокруг 37.65°E 55.77°N) вырезать osmium extract из ЦФО < 2 ГБ < 2 ГБ десятки МБ
Центральный ФО 835 МБ ~1–4 ГБ ~5–8 ГБ ~0,5–2 ГБ
РФ целиком 3,9 ГБ (russia-latest.osm.pbf) ~2–8 ГБ (-Xmx ≈ 0,5× PBF) ~20–40 ГБ ~3–8 ГБ

Источник размеров: download.geofabrik.de/russia.html, 2026-09-17. Полный planet не нужен: сценарии крутятся вокруг московского ORIGIN (terrain.ts:15). n1 с ~800 ГБ свободными перекрывает даже полный РФ; рекомендуемый бюджет — ЦФО + DEM демо-района, ≤ 15 ГБ вместе с temp.

Альтернатива Planetiler — tilemaker (меньше RAM, медленнее) или готовый weekly planet OpenFreeMap (Btrfs / MBTiles). Полный planet OpenFreeMap на хакатон не качаем.

OpenFreeMap public CDN — для хакатон-демо на aerozveno да, для симулятора нет.

  • Код — MIT; данные — OSM / OpenMapTiles (LICENSE.md).
  • Сайт: public instance бесплатен, без ключей, без лимитов, коммерция разрешена, SLA нет (openfreemap.org, 2026-09-17).
  • ToS public instance: as-is, last updated 2025-02-26, венгерское право (openfreemap.org/tos).
  • Стиль MapLibre из коробки: https://tiles.openfreemap.org/styles/liberty (Quick Start, 2026-09-17).
  • Автор подтвердил отсутствие usage restrictions на public instance (issue #126).

Это легальный bootstrap на стенде, где у браузера есть интернет. На изолированном симуляторе URL tiles.openfreemap.org мёртв. Self-host того же стека = тот же Planetiler/PMTiles, что и рекомендация.

2.3. Откуда DEM? (терренный полёт — не «красивые холмы»)

Планировщику рельеф нужен как число, не как картинка:

  • постоянный GSD только при постоянной истинной высоте (terrain.ts:69-72);
  • G2-04 «запас над рельефом» на бэкенде сейчас без модели высот (docs/task5/95-manual/03-limitations.md:93);
  • заказчик принёс «карту высотных препятствий» (Q-09);
  • эталон отрасли — GEM в Geoscan Planner с офлайн-кешем (20-analogs/01-geoscan-planner.md:39-41).
  • исходный Q-33 «какой моделью рельефа пользуетесь (SRTM, своя съёмка)?» (00-brief/05-questions-to-customer.md:212-215) в протоколе 16.09 не отвечен: слот Q-33 занят другой репликой (06-customer-qa-2026-09-16.md:300).

Ни Яндекс Tiles API, ни 2GIS Map Tiles не отдают terrain-RGB / quantized-mesh. Рельеф в любом случае свой.

Источник Покрытие РФ Лицензия MapLibre Офлайн Вердикт для этого репо
Copernicus DEM GLO-30 полное (AM/AZ/MD открыты с 2023_1) Free & Open; при публикации: «© DLR e.V. 2010-2014 and © Airbus Defence and Space GmbH 2014-2018 provided under COPERNICUS by the European Union and ESA; all rights reserved» rio-rgbify → terrain-RGB → raster-dem да, COG с AWS copernicus-dem-30m (--no-sign-request) основа, уже выбрана в simulate/docs/10-world/01-geodata-sources.md:59 и 50-stack/04-frontend-3d.md:139
GLO-90 полное та же то же да резерв дыр
SRTM GL1 обрезан на 60° с.ш. — севернее СПб/Вологды нет public domain да да не основа
AWS Terrain Tiles (бывш. Mapzen, terrarium) глобально открытые, без SLA да после зеркала быстрый старт, источник неоднородный
Mapbox Terrain-RGB глобально коммерция, токен; офлайн-кеш в ToS неясен да нет убивает SIM-BIZ-09 / R-DOC-3
MapTiler on-prem глобально от 2 500 $/год да Custom не влезает в хакатон
Яндекс / 2GIS нет продукта нет не источник DEM
Свой GeoTIFF заказчика по факту работ заказчика тот же пайплайн да приоритет над GLO-30

Декод terrain-RGB уже зафиксирован в коде-спеке: h = −10000 + (R·65536 + G·256 + B) · 0,1 (92-code/03-map-and-3d.md:332-335). Район работ 14×14 км на z12 — единицы тайлов (там же:337-341).

Спутник (желателен, не обязателен):

  • Яндекс Tiles API — нет;
  • Яндекс JS API — есть, но только в их рендерере;
  • 2GIS — спутникового слоя в публичной доке Map/Raster Tiles не нашли (2026-09-17);
  • Esri World Imagery — коммерческое использование по общим Esri ToS платное / ограниченное (esri.com/en-us/legal/terms/web-site-service, 2026-09-17); в офлайн-пакет не кладётся;
  • Sentinel-2 (Copernicus) — открытые данные, мозаика демо-bbox в PMTiles за вечер;
  • ортофото заказчика из Metashape — уже в пирамиде симулятора (01-geodata-sources.md:163-166).

На защите достаточно гипсометрии + hillshade из того же DEM. Спутник — опциональный слой satellite из Sentinel-2 по bbox s04, не Esri и не Яндекс.


3. Разбор вариантов

3.1. OSM

Ось Растр OSMF Вектор OSMF OpenFreeMap public Self-host Planetiler + PMTiles
Лицензия / ToS данные ODbL; сервер — Tile Usage Policy, офлайн запрещён то же для vector.openstreetmap.org MIT + ODbL; ToS as-is 2025-02-26; коммерция да ODbL на данные, свой рантайм
РФ да да да да, экстракт Geofabrik
Ключ / цена нет / 0 ₽ нет / 0 ₽ нет / 0 ₽ 0 ₽ + CPU n1
MapLibre raster XYZ MVT, свой стиль нативный style URL нативный pmtiles://
Офлайн запрещён политикой запрещён нет (нужен интернет) да
DEM нет нет нет (кладу свой) свой Copernicus
Спутник нет нет нет Sentinel-2 / орто заказчика
Лимиты throttle / бан throttle нет заявленных, нет SLA диск / nginx

Вывод по OSM: публичные CDN OSMF отпадают по политике и по MAP-R-13. OpenFreeMap — легальный онлайн-bootstrap. Self-host — единственный путь, который закрывает симулятор.

3.2. Яндекс Карты

Ось JS API v3 Tiles API Static API
Лицензия / ToS отображение только «посредством ПО»; п. 5.1.3 (диспетчеризация) п. 6.5.1 явно про Leaflet/OL-класс и закрытые системы; кеш ≤ 30 дней 1000 req/сут (п. 6.3.1); не движок карты
РФ да, в реестре ПО РФ да да
Ключ / цена ключ ЛК; без ключа нельзя (п. 3.1.1) ключ; бесплатно с 03.06.2025 при соблюдении условий ключ; 1000/сут
MapLibre нет — свой рендерер растр XYZ, web_mercator одна картинка, не карта
Офлайн нет нет (5.1.5) нет
DEM нет нет нет
Спутник да, внутри JS API нет схема / ограниченно
Лимиты зависят от тарифа; панорамы 100/сут 30 RPS 1000/сут

JS API v3 на этом фронте = выкинуть maplibregl.Map и писать мост deck.gl → ymaps3. 15 дней хакатона и MAP-08 это не переживут. Static API — превью в отчёте, не планировщик.

Tiles API — честный запасной путь только для aerozveno, где браузер ходит в интернет.

3.3. 2GIS

Ось MapGL JS API + Map Tiles Raster Tiles / RasterJS On-Prem MVT
Лицензия / ToS вектор только через MapGL сторонние библиотеки «можно», совместимость не гарантирована договор On-Premise
РФ да да да
Ключ / цена demo 1 месяц; затем Map Tiles от 8 000 ₽ / 100k тайлов Raster от 3 500 ₽ / 500k enterprise
MapLibre нет растр, риск сломаться «в любой момент» MVT да, но цикл продаж
Офлайн нет нет да, после внедрения
DEM нет нет нет
Спутник в публичной доке не подтверждён не подтверждён
Лимиты 3000 единиц/мин; demo урезан то же по договору

Источник цен: Pricing and billing, 2026-09-17, рубли. MapGL «бесплатен» только как библиотека — тайлы платные.

2GIS как подложка «как у заказчика в городе» красивее OSM по зданиям/POI. Цена этого — второй WebGL-движок рядом с MapLibre и сломанный MapboxOverlay. Для хакатона — нет.


4. Матрица: веса из этого проекта, не «вообще»

Почему такие веса:

Критерий Вес Почему здесь, а не в абстрактном сравнении карт
Offline fit 0.25 SIM-BIZ-09 MUST; R-DOC-3 / MAP-R-13; защита может быть без интернета (TODO.md:106-107)
License fit 0.20 заказчик Геоскан / ЛЦТ, РФ; ToS-бан на защите = ноль продукта
MapLibre fit 0.20 MapCanvas уже написан; второй рендерер = выкинуть неделю фронта
Terrain 0.15 терренный полёт, GSD, G2-04, Q-09, GEM у Planner
Effort 0.10 окно 15–29.09; MAP-08 оценена в 2 захода
Cost 0.05 хакатон, закупки 2GIS/MapTiler не успеть
Satellite 0.05 в брифе «желательны», не вход ТЗ

Шкала 1–5. Итог = Σ(оценка × вес).

Вариант Lic 0.20 Off 0.25 ML 0.20 Ter 0.15 Sat 0.05 ₽ 0.05 Eff 0.10 Итог
OSM self-host PMTiles + GLO-30 5 5 5 5 3 5 3 4.70
OpenFreeMap public (фаза 0 OSM) 4 2 5 2 2 5 5 3.45
Яндекс Tiles API → MapLibre raster 3 1 4 1 1 5 3 2.40
OSMF raster tile.openstreetmap.org 2 1 4 1 1 5 5 2.40
2GIS Raster → MapLibre 3 1 3 1 1 2 3 2.05
Яндекс JS API v3 (свой рендерер) 2 1 1 1 4 4 1 1.50
2GIS MapGL (свой рендерер) 2 1 1 1 1 2 1 1.25
Яндекс Static API 2 1 1 1 2 3 2 1.40

OSM self-host выигрывает не «потому что open source», а потому что три самых тяжёлых веса (offline / license / MapLibre) у него пятёрки, а DEM уже спроектирован в MAP-07/08. Яндекс Tiles — лучший не-OSM вариант, который не ломает MapLibre. 2GIS MapGL — худший по сумме именно из-за принудительной смены рендерера.

quadrantChart
    title Подложка × этот репозиторий (офлайн vs MapLibre)
    x-axis "Чужой рендерер" --> "Нативный MapLibre"
    y-axis "Только онлайн" --> "Живёт офлайн"
    quadrant-1 "Берём"
    quadrant-2 "Дорого / не успеть"
    quadrant-3 "Не берём"
    quadrant-4 "Стенд aerozveno only"
    OSM self-host PMTiles: [0.88, 0.92]
    OpenFreeMap public: [0.90, 0.38]
    Yandex Tiles API: [0.72, 0.22]
    OSMF raster: [0.70, 0.12]
    2GIS Raster: [0.55, 0.18]
    Yandex JS API v3: [0.12, 0.10]
    2GIS MapGL: [0.08, 0.10]

5. Вердикт

Рекомендация: OSM-вектор self-host (Planetiler → PMTiles) + Copernicus DEM GLO-30 (terrain-RGB в том же PMTiles-контуре). Это прямое исполнение уже принятых MAP-08 и 50-stack/04, а не новая идея.

Запасной путь: Яндекс Tiles API как raster source в том же MapLibre, только на https://aerozveno.ff (браузер с интернетом). DEM всё равно свой. На симулятор этот путь не переносится.

Фаза 0 рекомендации (не отдельный вендор): пока Planetiler крутится на n1, aerozveno может открыть https://tiles.openfreemap.org/styles/dark / liberty — одна строка в style. На симулятор этот URL не попадает.

flowchart TD
    start[Нужна подложка в MapCanvas] --> q1{Симулятор / docker compose<br/>без интернета?}
    q1 -->|да| osmSelf[OSM PMTiles + GLO-30 на томе]
    q1 -->|нет, aerozveno| q2{PMTiles уже лежат в MinIO?}
    q2 -->|да| osmSelf
    q2 -->|нет, сегодня| ofm[OpenFreeMap style URL<br/>фаза 0]
    ofm --> later[Заменить URL на pmtiles://]
    later --> osmSelf
    osmSelf --> dem[raster-dem + interleaved true]
    start --> q3{Заказчик требует<br/>привычную Яндекс-схему?}
    q3 -->|да, и есть интернет| ya[Yandex Tiles API raster<br/>web_mercator + логотип]
    ya --> demOwn[DEM всё равно GLO-30]
    q3 -->|нет| q1
    start --> kill1[2GIS MapGL]
    kill1 --> no1[Ломает MapLibre / deck.gl]
    start --> kill2[Яндекс JS API тайлы в MapLibre]
    kill2 --> no2[ToS: только посредством ПО]
    start --> kill3[tile.openstreetmap.org]
    kill3 --> no3[Tile Usage Policy: офлайн запрещён]

6. Как вкрутить в ЭТОТ код

6.1. Рекомендация — проводка OSM + DEM

Точка врезки одна: src/frontend/apps/planner/src/map/MapCanvas.tsx. layers.ts не меняется. terrain.ts меняется по уже описанному контракту TerrainSource (92-code/03-map-and-3d.md:313-335).

Что меняется во фронте

  1. Зависимости @geoscan/planner: pmtiles, позже maplibre-contour (MAP-09).
  2. В MapCanvas до new maplibregl.Map:
import { Protocol } from 'pmtiles';
const protocol = new Protocol();
maplibregl.addProtocol('pmtiles', protocol.tile);
  1. Заменить OFFLINE_STYLE (MapCanvas.tsx:20-24) на стиль без внешних хостов (тест MAP-R-13):
const BASEMAP_STYLE: StyleSpecification = {
  version: 8,
  glyphs: '/tiles/glyphs/{fontstack}/{range}.pbf',
  sprite: '/tiles/sprite',
  sources: {
    osm: {
      type: 'vector',
      url: 'pmtiles:///tiles/basemap.pmtiles',
      attribution: '© OpenStreetMap contributors',
    },
    terrain: {
      type: 'raster-dem',
      url: 'pmtiles:///tiles/terrain.pmtiles',
      tileSize: 256,
      encoding: 'mapbox',
      attribution:
        'produced using Copernicus WorldDEM-30 © DLR e.V. 2010-2014 and © Airbus Defence and Space GmbH 2014-2018 provided under COPERNICUS by the European Union and ESA; all rights reserved',
    },
  },
  layers: [
    { id: 'background', type: 'background', paint: { 'background-color': '#0D1117' } },
    // слои OpenMapTiles/Protomaps, обрезанные под тёмную тему токенов
    // symbol-слои либо вендорим glyphs, либо НЕ кладём — подписи сценария
    // остаются TextLayer (MapCanvas.tsx:16-18)
  ],
  terrain: { source: 'terrain', exaggeration: 1 },
};
  1. attributionControl: true (сейчас false, строка 70) — иначе ODbL/Copernicus нарушены.
  2. Когда в стиле есть raster-dem: interleaved: true и map.once('load', …) до addControl(overlay) — как написано в 92-code/03-map-and-3d.md:64-71.
  3. Runtime-переключатель, не зашивать URL. Расширить AppRuntimeConfig (packages/state/src/runtime-config.ts:3-11):
mapBasemap?: 'pmtiles' | 'openfreemap' | 'yandex-tiles';

Читать из /config.json шелла (тот же файл, что уже не кешируется nginx, 45-deployment-frontend.yaml:38-40). На симуляторе значение только pmtiles.

  1. Glyphs. Это главная ловушка текущего кода: пустой стиль специально без glyphs, чтобы демо открывалось без сети. Векторная подложка с подписями улиц требует PBF-глифов (~несколько МБ). Два допустимых пути:
  2. вендорить glyphs OpenMapTiles в /tiles/glyphs/ (офлайн-честно);
  3. оставить style без symbol-слоёв, подписи сценария как сейчас через TextLayer. Второй путь быстрее и не ломает «карта не ходит в сеть» (README.md:149-151). Для защиты достаточно гидрографии / дорог / землепользования без OSM-лейблов.

  4. DemTerrain.preload(bbox) при loadScenario — район 14×14 км, z12, единицы тайлов. SyntheticTerrain остаётся для тестов и сценариев без файла.

Что self-host и куда

Стенд продукта уже на n1 (kubectl --context n1, ns aerozveno). Диск ~800 ГБ.

Артефакт Где собрать Куда положить Бюджет
basemap.pmtiles n1, разово: osmium extract bbox s04 или Planetiler --area=central бакет MinIO aerozveno-frontend/tiles/ → nginx /tiles/ демо-bbox: < 100 МБ; ЦФО: ~1 ГБ + 8 ГБ temp
terrain.pmtiles n1: AWS copernicus-dem-30m → clip bbox → rio-rgbify → PMTiles тот же /tiles/ демо 14×14 км: < 20 МБ
glyphs/ + sprite вендор из OpenMapTiles / Protomaps, если нужны OSM-лейблы /tiles/glyphs, /tiles/sprite < 20 МБ
Sentinel-2 мозаика (опц.) GDAL warp bbox s04, z8–z15 /tiles/satellite.pmtiles < 200 МБ на демо

Не класть PMTiles в git. Не класть в emptyDir как единственную копию: под пересоздаётся. Источник правды — MinIO, как у бандла (45-deployment-frontend.yaml:1-10). Nginx уже умеет try_files $uri — файл /tiles/basemap.pmtiles отдастся, SPA-fallback не перехватит существующий путь.

Сборку не держать в hot path деплоя. Скрипт scripts/build-map-tiles.sh (ещё нет) + ручной mc cp в бакет. Полный РФ не собираем, пока жюри не попросит «покрутить всю страну».

Симулятор, изолированная сеть

SIM-BIZ-09: docker compose up без интернета и без ключей, «фронт открывается, рельеф отображается». Те же два PMTiles копируются в образ / volume симулятора (сейчас офлайн-стиль simulatepublic/style/offline.json, simulate/docs/92-api/02-user-guide.md:80-82). mapBasemap зашит в pmtiles. Ни OpenFreeMap, ни Яндекс, ни OSMF. Исходящих URL в стиле нет — это тот же барьер MAP-R-13.

flowchart LR
    subgraph n1["n1 / ns aerozveno"]
      minio["MinIO aerozveno-frontend"]
      fe["geoscan-frontend nginx"]
      minio -->|mc mirror /tiles/*.pmtiles| fe
    end
    subgraph build["разовая сборка на n1"]
      pbf["Geofabrik ЦФО или osmium bbox"]
      planetiler["Planetiler → basemap.pmtiles"]
      glo["Copernicus GLO-30 COG"]
      rgbify["rio-rgbify → terrain.pmtiles"]
      pbf --> planetiler
      glo --> rgbify
      planetiler --> minio
      rgbify --> minio
    end
    subgraph browser["браузер оператора"]
      ml["MapLibre style pmtiles://"]
      deck["deck.gl layers.ts без изменений"]
      dem["TerrainSource.elevationAt"]
      ml --> deck
      ml --> dem
    end
    fe -->|HTTPS aerozveno.ff Range| ml
    subgraph sim["симулятор, air-gap"]
      vol["те же PMTiles в volume"]
      vol --> ml2["MapLibre, mapBasemap=pmtiles"]
    end

Фаза 0 на aerozveno (пока нет файла)

style: 'https://tiles.openfreemap.org/styles/dark' // или liberty

Атрибуция: OpenFreeMap / OpenMapTiles / OSM (MapLibre добавит сам, если не выключать attributionControl). Это нарушает MAP-R-13 — допустимо только как временный mapBasemap: 'openfreemap' на интернет-стенде, с тестом-исключением. На симулятор не тащить.

6.2. Fallback — Яндекс Tiles API в том же MapLibre

Только если к защите PMTiles не готовы и жюри/заказчик хочет «карту как в Яндексе», и стенд — aerozveno (интернет в браузере).

  1. Ключ Tiles API завести в ЛК Яндекса, сразу в creds-store project/geoscan / YANDEX_TILES_API_KEY (не в git, не в config.json публичным текстом без ограничения referrer).
  2. Проксировать тайлы через gateway /api/tiles/yandex/{z}/{x}/{y} или ограничить ключ HTTP Referer https://aerozveno.ff/*. Прямой ключ в бандле на tailnet терпим на 2 недели, на любой публичный контур — нет.
  3. Источник в стиле (не JS API):
https://tiles.api-maps.yandex.ru/v1/tiles/
  ?x={x}&y={y}&z={z}&lang=ru_RU&l=map
  &projection=web_mercator&apikey=…

projection=web_mercator обязателен: дефолт Яндекса — эллиптический меркатор, deck.gl живёт в Web Mercator. 4. Свой HTML-оверлей с логотипом-ссылкой на https://yandex.ru/maps — требование доки Tiles API, MapLibre сам его не нарисует. 5. raster-dem остаётся нашим PMTiles. Яндекс рельеф не подменяет. 6. Кеш браузера ≤ 30 дней, не собирать mbtiles из этих PNG — п. 5.1.5. 7. На симуляторе этот mapBasemap отсутствует. Ветка yandex-tiles в config.json симулятора — ошибка конфигурации, ловить тестом.

Не делать: подменять maplibregl.Map на ymaps3.YMap; не брать спутник из JS API «тихо»; не класть геокодер Яндекса на OSM-подложку (п. 6.6.1 — геокодер только вместе с JS API и только на их карте).


7. Что сознательно не берём

  • 2GIS MapGL как движок вида — ломает MapboxOverlay и MAP-08.
  • Яндекс JS API тайлы в MapLibre — ToS 1.1.2 / 2.2.1.
  • tile.openstreetmap.org — Tile Usage Policy §4 + MAP-R-13.
  • Mapbox / Cesium ion / Google Photorealistic 3D — токены и запрет офлайн-кеша; уже отведены в simulate/docs/10-world/01-geodata-sources.md:73-78.
  • Esri World Imagery как бесплатный спутник — коммерческие ToS Esri.
  • FABDEM — CC BY-NC-SA, несовместим с коммерческим продуктом (01-geodata-sources.md:67).

8. Что не удалось проверить

Вопрос Почему Как не гадаем
Полный текст российского law.2gis.ru (не .ae) на Map Tiles страница .ae открылась; .ru в этой сессии не сняли дословно опираемся на docs.2gis.com FAQ про third-party libraries — этого достаточно, чтобы отвести вектор
Платный офер Яндекса целиком (не публичные «Условия конкретных сервисов») часть тарифов за ЛК для Tiles API хватает публичного 6.5.* и продуктовой страницы от 03.06.2025
Актуальный SLA / аптайм OpenFreeMap ToS as-is, «may discontinue at any time» не ставим public instance в критерий приёмки симулятора
Точная точность GEM Геоскана ОВ-2 в simulate/docs/10-world/01-geodata-sources.md:336 объявляем GLO-30 в манифесте мира, не притворяемся GEM
Покрытие спутникового слоя 2GIS в overview / Map Tiles / Raster Tiles не описан считаем «нет», пока не покажут иначе
Свободное место n1 прямо сейчас в репо цифры нет бюджет ≤ 15 ГБ; если диск меньше — только bbox s04

9. Источники (дата обращения везде 2026-09-17, если не указано)

Юридика и доки провайдеров

Этот репозиторий — цитаты в §1 и по тексту.