2026-09-18 — Ruta Maya: navegación smooth con stack abierto

Contexto

Recetario del diseño confirma que la sensación “smooth” de Google Maps no depende de la API de Google, sino de coreografía de cámara + sincronía lista↔mapa + panel deslizante. Podemos replicarlo con stack 100% abierto.

Stack técnico decidido

Mapa vectorial

  • MapLibre GL JS (BSD, fork de Mapbox GL v1)
    • Tiene todas las primitivas: flyTo, easeTo, fitBounds, pitch, bearing
    • Extrusión 3D de edificios + terreno
    • setFeatureState sobre GeoJSON → resaltado GPU (no DOM)

Teselas vectoriales

  • OpenFreeMap (gratis, sin API key, OSM)
  • Alternativa soberana: PMTiles de Protomaps en Cloudflare R2
    • Archivo estático, sin servidor de teselas
    • Autoalojado en R2 → costos mínimos

POIs (puntos de interés)

  • Overture Maps Places (CDLA-Permissive-2.0)
    • Cobertura buena en México
    • Datos abiertos, sin restricciones de Google ToS
  • Photon / Nominatim: geocodificación y búsqueda
  • Wikimedia Commons / Panoramax: fotos abiertas
  • Valhalla / OSRM: rutas opcionales

Móvil (si SPAB requiere app)

  • @maplibre/maplibre-react-native + Expo (development build)
  • Misma lógica de cámara web → móvil

Primitivas de navegación smooth

// Vuelo con easing cúbico, pitch, padding para panel
map.flyTo({
  center: place.coords,
  zoom: 16.5,
  pitch: 55,              // inclinación 3D
  bearing: -20,           // rotación
  padding: { left: panelWidth },  // lugar visible junto al panel
  speed: 0.9,
  curve: 1.6,             // qué tanto "sale" antes de entrar
  easing: t => 1 - Math.pow(1 - t, 3)
});
 
// Sincronía lista ↔ mapa con setFeatureState
map.setFeatureState(
  { source: 'places', id: placeId },
  { hover: true }
);

Arquitectura de la Ruta Maya

1. Narrativa geográfica

Concepto: Ruta continua por destinos mayas (Tulum → Cobá → Bacalar → Chetumal → Calakmul) con 5 lugares top por parada.

Datos:

{
  "slug": "ruta-maya-qroo",
  "nombre": "Ruta Maya - Quintana Roo",
  "paradas": [
    {
      "destino": "tulum",
      "orden": 1,
      "lugares": [ /* top 5 por rating */ ]
    },
    {
      "destino": "coba",
      "orden": 2,
      "lugares": [ /* top 5 */ ]
    }
  ]
}

2. UX de navegación

  • Vista inicial: Mapa con todas las paradas numeradas (1→2→3)
  • Clic en parada: flyTo + panel lateral muestra los 5 lugares
  • Clic en lugar: zoom a nivel street, panel de detalle completo
  • Botón “Siguiente parada”: transición smooth a la siguiente coordenada

3. Panel de detalle austero pero intencional

Brecha real: Google tiene fotos/reseñas/horarios que OSM no iguala.

Solución de diseño:

  • Fotos: Wikimedia Commons + placeholders con colores dominantes (ya en places-explorer)
  • Reseñas: Solo mostrar rating agregado de Google Places (no texto de reseñas)
  • Horarios: OSM opening_hours tag + fallback manual
  • Descripción: Wikipedia extract (ya en spab-retrieval/src/lib/connectors/wikipedia.ts)

Austero → intencional:

  • Tipografía editorial (Bricolage Grotesque + Atkinson Hyperlegible)
  • Paleta limitada (terracota, jade, arena)
  • Skeletons animados mientras carga
  • “Datos abiertos” como badge de orgullo

Datos ya disponibles

✅ Destinos con coordenadas: spab-retrieval/data/destinos.json
✅ Lugares con rating: googleplaces.ts → base/lugares.csv
✅ Descripciones Wikipedia: wikipedia.ts
✅ Navegación smooth: places-explorer/src/maplibre-adapter.js

Próximo paso: prototipo Ruta Maya

Alcance del prototipo

  1. Mapa base: OpenFreeMap con estilo Positron
  2. GeoJSON de paradas: línea conectando Tulum → Cobá → Bacalar
  3. Panel lateral: al clic en parada, muestra top 5 lugares
  4. Transición smooth: flyTo con pitch + bearing entre paradas
  5. Detalle de lugar: mismo panel de places-explorer adaptado

Estructura de archivos

ruta-maya/
├── index.html
├── data/
│   └── ruta-maya-qroo.json   # paradas + lugares
├── src/
│   ├── ruta-store.js         # estado de la ruta (parada actual, progreso)
│   ├── ruta-panel.js         # panel de paradas + lugares
│   ├── maplibre-adapter.js   # extendido de places-explorer
│   └── ruta-api.js           # carga ruta + top 5 por parada
└── README.md

Comando para arrancar

# Generar ruta-maya-qroo.json desde base/lugares.csv
node scripts/build-ruta.js
 
# Servir
cd ruta-maya && python3 -m http.server 8000

Referencias

Decisión final

SÍ, armamos el prototipo. La infraestructura de places-explorer ya tiene el 70% del camino hecho — solo falta:

  1. Cargar GeoJSON de ruta (línea + paradas)
  2. Extender maplibre-adapter.js para transiciones entre paradas
  3. Adaptar places-panel.js para modo “ruta” (parada actual + siguiente)

✅ Completado: Quintana Roo + Corredor Tren Maya

Datos agregados

Destinos nuevos en spab-retrieval/data/destinos.json:

  1. Puerto Morelos (lat: 20.8485, lon: -86.8728) - Estación Tren Maya
  2. Felipe Carrillo Puerto (lat: 19.5783, lon: -88.0456) - Estación Tren Maya
  3. Chetumal (lat: 18.5001, lon: -88.2960) - Aeropuerto CTM
  4. Isla Mujeres (lat: 21.2311, lon: -86.7310) - Pueblo Mágico

Total Quintana Roo: 9 destinos (Cancún, Puerto Morelos, Playa del Carmen, Cozumel, Tulum, Felipe Carrillo Puerto, Bacalar, Chetumal, Isla Mujeres)

GeoJSON: ruta-maya/tren-maya-quintana-roo.geojson

  • 8 estaciones principales del Tren Maya en Q. Roo
  • LineString del corredor completo (456 km)
  • Metadata por estación: municipio, aeropuerto, POIs cercanos, sección/tramo, fecha de inauguración
  • Puntos de interés vinculados: 151 sitios arqueológicos, 67 reservas naturales, 23 templos, 21 museos, 13 pueblos mágicos

API: ruta-maya/src/tren-maya-api.js

  • 35 lugares distribuidos en 7 estaciones (top 5 por estación)
  • Categorías extendidas: cenote, playa, patrimonio, comida, estancia, arqueología, naturaleza
  • Datos simulados con estructura real de Google Places (rating, reviewCount)
  • Método placesByStation(estacion) para filtrar por parada

Estaciones mapeadas

EstaciónDestinoAeropuertoPueblo MágicoInauguración
Cancún AeropuertoCancúnCUN-2023-12-15
Puerto MorelosPuerto Morelos--2024-02-29
Playa del CarmenPlaya del Carmen--2024-02-29
TulumTulum-✓2024-09-20
Tulum AeropuertoTulumTQO-2024-09-20
Felipe Carrillo PuertoFelipe Carrillo Puerto--2024-09-20
BacalarBacalar-✓2024-12-15
Chetumal AeropuertoChetumalCTM-2024-12-15

Próximos pasos

  1. HTML de visualización (ruta-maya/index.html) - adaptar places-explorer/index.html
  2. Selector de estación en el panel lateral
  3. Transición smooth estación→estación con flyTo
  4. Capa de línea del corredor en MapLibre
  5. Conectar con datos reales de base/lugares.csv

Ramas creadas

places-turismo (base de datos + componentes)

  • 0f8bf46: adaptar places-explorer para turismo (top 5 por rating)
  • c6f7b68: completar destinos Quintana Roo (4 nuevos)

Contenido:

  • places-explorer/ - componente reutilizable de navegación smooth
  • spab-retrieval/data/destinos.json - 9 destinos de Q. Roo

campana-ruta-maya (prototipo navegable)

  • 7bc1f62: GeoJSON y API del corredor Tren Maya Q.Roo
  • 1a6373c: prototipo navegable Ruta Maya con smooth nav

Contenido:

  • ruta-maya/tren-maya-quintana-roo.geojson - 8 estaciones + corredor
  • ruta-maya/src/tren-maya-api.js - 35 lugares (top 5 × 7 estaciones)
  • ruta-maya/index.html - navegación smooth entre estaciones
  • ruta-maya/README.md - documentación completa

Cómo probar

cd ~//nef/estado_turismo
 
# Cambiar a la rama de la campaña
git checkout campana-ruta-maya
 
# Servir el prototipo
cd ruta-maya && python3 -m http.server 8000
 
# Abrir http://localhost:8000

Navegación:

  1. Selector de estaciones en panel izquierdo
  2. Clic en estación → vuelo smooth con pitch 45°
  3. Marcadores en mapa con popups
  4. Panel de lugares con detalle (rating, reseñas, fotos)

Stack: MapLibre GL JS + OpenFreeMap + Vanilla JS + Web Components