Simulador de vuelo para navegador. Se vuela sobre Paraguay —el relieve es real, el paisaje lo pintamos nosotros— y se aterriza donde se pueda.
Estado: se puede volar de principio a fin. Del puesto de estacionamiento a la pista siguiendo la raya verde, despegue con V1 y Vr, circuito de tráfico, aproximación con PAPI y altura de decisión, aterrizaje o frustrada — y la frustrada puntúa igual que la toma, que es la lección. Seis aeródromos reales, relieve medido, sonido sintetizado y cuatro peldaños de edad. Funciona sin conexión a partir de la segunda visita.
Falta el arte final, las voces grabadas y el multijugador. Lo que falta está en los issues.
Producto de Oksigenia SL, publicado bajo la marca Granja Óga. Gratis para siempre para la educación paraguaya — ver LICENSE-CONTENIDO.md.
Porque una niña dijo que quería ser piloto "con las gafas de sol", y porque no había ningún simulador que la dejara reconocer su país desde el aire.
Esa niña tiene cuatro años y medio, y eso no es una anécdota: es la restricción de diseño más dura del proyecto. La jugadora más joven todavía no sabe leer. Nada de lo esencial puede depender de un texto.
El objetivo no es la fidelidad de un simulador de entrenamiento. Es que volar se sienta bien, que el paisaje se reconozca, y que un chico de ocho años pueda despegar en el primer intento sin leer un manual —y que uno de cuatro pueda hacerlo sin leer nada en absoluto.
npm install
npm run devAbre http://localhost:5173. No hace falta nada más: el escenario inicial se genera por código, sin descargar datos.
| Comando | Qué hace |
|---|---|
npm run dev |
Servidor de desarrollo con recarga en caliente |
npm run build |
Compila a dist/ (estático, se sirve con nginx) |
npm run typecheck |
Comprueba tipos sin compilar |
npm test |
Tests del modelo de vuelo |
npm run terreno |
Convierte teselas NASADEM a mapas de altura (sin uso: hoy el relieve sale de copernicus-a-relieve.mjs) |
npm run acceso |
Mide WCAG 2.2 AA: contraste, foco, teclado y movimiento |
npm run sin-red |
Compila, corta la conexión y comprueba que se vuela igual |
npm run rendimiento |
Mide el coste por fotograma con la CPU estrangulada |
A partir de la segunda visita, el juego funciona sin internet: un service worker guarda el armazón —HTML, código y estilos, 1,1 MB— y, según se usan, los mundos que se visitan. El escenario en el que se voló ayer está disponible hoy aunque no haya red, que es la diferencia entre una promesa educativa y un folleto. Se puede instalar en el escritorio de una tablet como una aplicación más.
Lo que no se guarda es lo de fuera de casa: las teselas de Google y el METAR en directo. Sin ellas el juego cae al mundo dibujado y al tiempo de casa, que es exactamente para lo que están esos dos caminos.
Comprobado con npm run sin-red, que apaga el servidor de verdad y vuelve a
entrar.
Todas las teclas se pueden cambiar desde la pantalla de mandos, y esa pantalla dice la verdad sobre lo que hace cada una. Esta tabla, hasta hace poco, no: prometía botones táctiles de cámara y de reinicio que no existían y una pantalla de ajustes que sigue sin existir (#149).
| Acción | Teclado | Táctil |
|---|---|---|
| Cabeceo / alabeo | Flechas o W A S D |
Palanca izquierda |
| Timón | Q / E |
Los dos pedales |
| Motor | + / − o X / Z |
Palanca derecha |
| Frenos | B o Espacio |
La mano roja del HUD |
| Cámara | C |
Botón, arriba a la izquierda |
| Pausa | Esc |
Botón, arriba a la izquierda |
| Reiniciar vuelo | R |
Desde el menú de pausa |
| Volver al hangar | — | Botón, y desde el menú de pausa |
| Nivel de dificultad | M |
— |
| Idioma | L |
— |
| Sonido | V |
Botón en pantalla |
| Cambiar de avión | P |
— |
| Misión | N |
— |
| Mandos, mapa, tiempo, créditos, cuaderno | K, F1 |
Botones de la barra |
También funciona con mando (Xbox / PlayStation) por la Gamepad API.
.
├── src/
│ ├── flight/ Modelo de vuelo, aeronaves, controles
│ │ ├── fdm.ts FDM propio de coeficientes (el corazón)
│ │ ├── model.ts Interfaz FlightModel — el punto de enchufe
│ │ ├── aircraft.ts Fichas técnicas de cada aeronave
│ │ └── input.ts Teclado, táctil y mando
│ ├── world/ Terreno, cielo, escenarios
│ ├── ui/ HUD, menús, créditos
│ ├── i18n/ es-PY y guaraní (gug)
│ └── game.ts Bucle de juego y ensamblaje
├── scripts/ Pipelines de datos y bancos de pruebas
├── docs/adr/ Decisiones de arquitectura y su porqué
└── public/assets/ Assets estáticos
FDM propio, escrito en TypeScript, de coeficientes aerodinámicos: calcula sustentación, resistencia, fuerza lateral y los tres momentos a partir del ángulo de ataque, el derrape y las velocidades angulares, e integra las ecuaciones de Euler del sólido rígido. Entra en pérdida de verdad.
| Guyrami | Tukã | Taguato | Taguato Ruvicha | |
|---|---|---|---|---|
| Edad orientativa | 4-6 | 7-9 | 10-13 | 14+ |
| Modelo de vuelo | sencillo | coeficientes | coeficientes | coeficientes |
| Pérdida | no existe | protegida | sí | sí |
| Alas | se enderezan solas | se enderezan solas | las nivelás vos | las nivelás vos |
| Instrumentos | ninguno | pictóricos | numéricos | seis analógicos |
| Unidades | km/h y metros | km/h y metros | km/h y metros | nudos y pies |
Lo que cambia entre peldaños no es el mundo ni el avión: es cuánta física
se le confía al jugador. Se cambia de nivel con M, incluso en el aire.
El primer peldaño usa otro modelo de vuelo, no el mismo con más ayudas
(src/flight/arcade.ts). Pelear con un modelo realista para que se comporte
de forma sencilla es luchar contra la física que uno mismo eligió: el fugoide
existe porque un avión intercambia altura por velocidad, y la manera de no
tenerlo no es amortiguarlo, es no tenerlo. Los otros tres peldaños comparten
el modelo de coeficientes y se distinguen por qué capas de ayuda llevan
(src/flight/assists.ts).
Está detrás de la interfaz FlightModel a propósito:
se le puede enchufar JSBSim
compilado a WebAssembly como implementación alternativa sin tocar el resto
del juego. El porqué —y las implicaciones de licencia LGPL, que son las que
nos hicieron no usarlo de entrada— está en
docs/adr/0002-modelo-de-vuelo-propio.md.
El relieve sale de Copernicus DEM GLO-30 (ESA/Airbus/DLR, gratuito y con
atribución literal obligatoria) en los quince escenarios paraguayos y de los
anillos de horizonte, y del MDT05 del PNOA-LiDAR del IGN (CC BY 4.0) en los
tres españoles. scripts/copernicus-a-relieve.mjs e ign-a-relieve.mjs los
convierten a los .bin de data/terrain/, cada uno con su ficha de
procedencia al lado.
Hubo un pipeline de NASADEM —scripts/hgt-a-heightmap.mjs, teselas .hgt a
PNG de 16 bits— y esta sección lo siguió describiendo mucho después de que
dejara de usarse. No carga ningún escenario: world/relieve.ts lee .bin.
El color sí sale de imaginería en tres escenarios —la ortofoto del PNOA en
Tenerife Norte y la de EOX en Silvio Pettirossi—; en el resto se pinta por
altitud, pendiente y bioma con shaders propios, que sale más bonito y no ata a
ningún proveedor. Las procedencias y sus licencias, en
CREDITOS.md.
Tres idiomas, que se pasan con L: español paraguayo (es-PY),
guaraní (gug) e inglés (en). Como en el resto de productos de
Granja Óga se aplica el test Ña Emy: si una abuela paraguaya no puede usar
la pantalla, la pantalla no está terminada.
Los rótulos de los instrumentos —IAS, ALT, HDG, V/S, THR— no se traducen en ningún idioma. Son los mismos en cualquier cabina del mundo, y aprenderlos es parte de lo que el juego enseña sin proponérselo. Debajo de cada uno va la palabra corriente en pequeño, que es la muleta de quien está aprendiendo a leer y que con el tiempo se deja de mirar.
Las unidades siguen al modo de vuelo: Arcade muestra km/h y metros, Piloto muestra nudos y pies. Quien decide que quiere volar en serio se encuentra con las unidades de verdad en el mismo gesto.
- Código — Apache-2.0. Úsalo, véndelo, no nos preguntes.
- Contenido y marcas — propietario, © Oksigenia SL.
- Toda la educación paraguaya — gratis, permanente, sin trámites. Detalles.
Procedencia y licencia de cada dependencia y cada dato: CREDITOS.md.
Gratis para siempre para toda la educación paraguaya. Eso está firmado en LICENSE-CONTENIDO.md y no depende de que haya dinero: mientras Óga Veve exista, a un colegio no se le cobra.
Lo que no está firmado es que vaya a existir siempre. Esto lo mantiene una empresa pequeña, no tiene ingresos y puede dar pérdidas y cerrarse. Conviene decirlo aquí y no en la letra pequeña, porque quien monte una clase encima de esto tiene derecho a saberlo: el código es Apache-2.0 y los datos son de OpenStreetMap y de dominio público, así que si un día esto se apaga, cualquiera puede volver a encenderlo.
Si quieres que dure, Liberapay y PayPal. Lo que llegue va a lo que de verdad cuesta dinero: las teselas del mundo real, que se pagan por vuelo.
Issues y pull requests, bienvenidos. Antes de mandar código, lee docs/adr/ para no chocar con una decisión ya tomada, y AGENTS.md si trabajas con herramientas de asistencia.
Al contribuir aceptas que tu aportación se publique bajo Apache-2.0.