Estas páginas se generan a partir de la documentación interna del proyecto. Las referencias a ficheros de código y a offsets del binario se conservan como procedencia —para que se vea de dónde sale cada afirmación—, pero todavía no se pueden seguir: el motor aún no está publicado. Cuando lo esté, pasarán a ser enlaces.
2 · Disposiciones (layouts)
Qué disposiciones ofrece el port, para qué sirve cada una y qué cuesta.
Capturas nuevas. Las imágenes de este documento se generaron para él el 04-08-2026 contra un dev server propio (
:5271, worktreedocs-visual-01), sobre . Escenario fijo en todas: cabaña de Iolo, partida fresca, español, sin intro (?nointro&fresh&lang=es). Viven endocs/verdicts/layouts/.
El resumen, antes del detalle
El original tenía una disposición: 320×200, marco EGA fijo, mapa 11×11 arriba a la izquierda, roster y consola a la derecha. El port ofrece cinco cosas que se combinan:
| Opción | Dónde se cambia | Por defecto |
|---|---|---|
| Píxel cuadrado ↔ 4:3 de época | ⚙ → Vídeo | Píxel cuadrado |
| Layout clásico ↔ layout partido | botón ▤ / ⚙ → Vídeo | Partido en táctil, clásico en escritorio |
| Piel 1988 ↔ piel smooth | F9 / ◧ / ⚙ → Vídeo | 1988 |
| Pantalla completa | ⚙ → Vídeo | Apagado |
| Lado de los cursores (izq/dcha) | deck táctil | Derecha |
Y hay una decisión de arquitectura que las gobierna a todas: ninguna disposición fabrica un solo píxel. Cada panel del layout partido es un drawImage de un rectángulo del canvas de la piel fiel. Es la razón de que se pueda añadir una disposición sin tocar el calco.
1 · La disposición clásica (escritorio)
✨ El punto de partida: el marco de 1988 escalado por entero y centrado con letterbox.

Se ve el marco completo: visor 11×11 a la izquierda, roster con el oro de cada personaje, la caja de KPIs (C:63 O:150 y la fecha 4-5-139), la consola debajo, y las bandas de cielo y vientos arriba y abajo. En la esquina inferior derecha, los tres botones del shell: ES (idioma), ◧ (piel) y ⚙ (menú SISTEMA).
El botón de piel es ◧, no ▤ (ui/shell/skinSwitcher.ts:79). El ▤ es el del LAYOUT y en escritorio no está en este clúster: sólo lo instala el envoltorio del layout partido (
deck-ancho.ts:1535), o sea en táctil o con la bandera puesta — por eso en esta captura sólo hay tres botones. Desde el escritorio la vía al layout partido es ⚙ → Vídeo.
Para qué sirve: es la disposición fiel. Si lo que se quiere es ver el juego como era, esta es.
2 · Aspecto 4:3 de época
✨ AÑADIDO · ⚙ → Vídeo → «Aspecto 4:3 época (piel 1988)» · Código: game/src/skin/fiel/skin.ts (aspectStretchEnabled, clave u5clone:faithful:aspect43)
| Píxel cuadrado (por defecto) | 4:3 de época |
|---|---|
![]() | ![]() |
Un monitor CRT de 1988 no tenía píxeles cuadrados: estiraba los 320×200 a 4:3, o sea un píxel de 1:1,2. Con la casilla activada el port hace lo mismo, y todo se ve un 20% más alto.
La contrapartida, medida
Estirar cuesta superficie. En el viewport de prueba (1280×800 CSS) el canvas pasa de llenar el ancho a quedar en 960×720: la escala entera que cabe con el ratio bloqueado es menor. Se gana la geometría de época y se pierde tamaño.
Por eso el defecto es el píxel cuadrado (decisión F-0): la mayoría de la gente que abre esto hoy espera píxeles cuadrados, y quien busque la geometría del CRT sabe lo que está buscando.
Y una interacción que conviene conocer
El layout partido (§4) ignora aspectY a propósito. En el móvil el píxel es cuadrado en todos los paneles, y no por descuido: mezclar dos retículas —una estirada en el mapa y otra cuadrada en la banda— en la misma pantalla se ve mal. La invariante está atada por un test (tests/portrait-cuadrado.test.ts) que exige ratio 1 en los seis paneles, en las dos orientaciones y en los siete dispositivos del censo.
3 · La piel smooth, que también es una disposición
Cambiar de piel no mueve las cajas, pero cambia bastante lo que se ve:
| 1988 | smooth (xBR) |
|---|---|
![]() | ![]() |
El detalle que importa mirando las dos: el texto es idéntico. Sólo el rectángulo del visor pasa por el filtro. El porqué está en 1 · Imagen §1-2.
4 · El layout partido (móvil vertical)
✨ AÑADIDO · Código: game/src/skin/portrait/layout-cuadrado.ts, deck-ancho.ts, deck-nativo.ts · Se enciende con el botón ▤ o desde ⚙ → Vídeo → «Layout partido (vertical)»
Petición literal del usuario (25-07-2026)
«Quiero ver prototipo de Re-flow + botonera a ancho completo real. En general quiero que siempre el view del mapa sea cuadrado como en original.»
Antes / después, iPhone 15 (393×852)
Clásico (?reflow=off) | Partido (por defecto en táctil) |
|---|---|
![]() | ![]() |
En el clásico, el marco 320×200 entero se encoge para caber en el ancho del teléfono: el mapa queda minúsculo en el tercio superior y el resto de la pantalla es botonera. En el partido, el mapa es un cuadrado que llena el ancho, la banda de jugadores y log va debajo, y los botones al fondo.
Cómo se consigue el cuadrado
Con escala isótropa (sx == sy) en el bloque de mapa. La caja fuente ya es 178×178, así que basta con no estirar. Cero fabricación de píxel: cada panel es un rectángulo del canvas de la piel fiel, y no hay una sola línea nueva en skin/fiel/.
Lo que se ve y no está en el enunciado: la botonera también cambia
Comparando las dos capturas, no cambia sólo la geometría. El deck es otro:
| Clásico | Partido | |
|---|---|---|
| Aspecto | Botones marrones, con relieve | Monocromo, contorno fino |
| Selector de hojas | Fila «Mover / A-Z / 123 / Sí-No / Pantalla» | Desaparece: entra el teclado del sistema por el botón ⌨ |
| Disparo | En pointerdown (al apoyar el dedo) | En pointerup, y sólo si el dedo sigue dentro del botón |
Los dos van juntos por construcción y está declarado así en el código: el layout partido está construido alrededor del deck, y el deck sólo existe donde el puntero es grueso. El docstring de layoutPartidoInicial lo cuenta desde el reporte que lo originó — el usuario añadió el port a la pantalla de inicio del iPhone y lo vio «con la versión antigua de botones marrones, sin layout partido».
Ese cambio de disparo se detalla en 3 · Experiencia.
Con la piel smooth encima
| Partido, piel 1988 | Partido, piel smooth |
|---|---|
![]() | ![]() |
Que estas dos capturas existan es en sí el resultado de un carril. Durante un tiempo smooth y partido eran incompatibles, y la incompatibilidad estaba declarada por escrito en dos sitios como si fuera una decisión de producto. El diagnóstico (diagnostico-smooth-portrait) encontró que eran dos bloqueos de construcción con una declaración encima, y el lote C (lote-c-smooth-partido) los quitó:
PortraitSkinconsume cinco miembros del alojado queShaderSkinno reexportaba. Se resolvió con un contrato nuevo (skin/hostable.ts) y cero líneas editadas enskin/fiel/.- Alojada en un host oculto de 0×0, la shader colapsaba su backbuffer a ×1 y el xBR dejaba de suavizar sin dar ningún error.
🔴 La trampa que enseña el punto 2
Uno de los cinco miembros, sourceFrameGen, no se podía delegar a la fiel. Devuelve el contador de frames compuestos de la shader, que muta mucho más a menudo que el de la fiel (tweens del scroll, actores, overlays). Delegándolo, el gate de suciedad del envoltorio se habría saltado justo los frames del movimiento suave — o sea, lo único por lo que alguien elige esta piel. Cuatro de cinco eran passthrough; el quinto no, y era el que importaba.
Contrapartidas del partido
- El hueco entre bloques se paga del deck, no del mapa. La separación mapa↔banda pasó de 2 a 6 píxeles de juego el 02-08 a petición del usuario. Está medido: los 2 originales daban 4,1 px CSS en un iPhone 15, de los que las dos líneas separadoras se comían 3 — quedaba 1,1 px de negro, o sea que a la vista era un solo bloque pegado. Con 6 son 12,3 px y ~9 de negro. Y el coste sale del presupuesto del deck: la escala del visor en vertical es
W/FRAME_Wy no depende del alto. - La unidad es de juego, no de CSS. Los 6 píxeles escalan con el mapa, así que el hueco se ve igual de grueso en un SE que en un Pro Max. Y 6 < 8 = la altura de una fila de texto: el hueco no llega a valer un renglón.
- Sin el ▤ no habría vuelta. El botón que apaga el layout partido vive en la botonera del layout partido, así que al apagarlo desaparece con él. Por eso la casilla del menú ⚙ no es un duplicado por comodidad: es la única vía que puede devolver el partido, y el menú ⚙ existe en las dos disposiciones. Está escrito como comentario en ui/shell/sections.ts, y es el tipo de detalle que sólo se descubre encerrándose.
5 · Apaisado
| Clásico | Partido |
|---|---|
![]() | ![]() |
En apaisado el juego queda centrado y el deck se reparte: en el clásico, todo el mando a la izquierda; en el partido, dos raíles —modos y cruceta a la izquierda, comandos a la derecha— con el juego en medio.
⚠️ Un matiz honesto sobre estas dos capturas
layout-cuadrado.ts documenta una rama de apaisado propia: «mapa cuadrado a la izquierda llenando el ALTO, banda roster+log en UNA columna a la derecha». En estas capturas eso no se ve: lo que aparece es el marco 320×200 clásico en el centro.
No es un fallo, es el algoritmo funcionando. El tipo de composición (reflow vs clasico) se decide por área: si re-componer perdiese superficie útil frente al marco entero, se queda en clásico. A 852×393 gana el clásico. La rama de apaisado existe y se dispara en pantallas donde sale a cuenta (una tablet apaisada, por ejemplo); en un iPhone 15 tumbado, no.
Lo que sí cambia entre las dos capturas es el reparto del deck y su piel — que es suficiente diferencia como para que la elección importe en apaisado.
6 · Tablet vertical

820×1180. El mismo layout partido, y aquí se aprecia lo que gana: el mapa cuadrado ocupa casi toda la superficie útil y la banda cabe entera debajo sin apretar. Es el tamaño en el que la disposición está más cómoda.
7 · Pantalla completa
⚙ → Vídeo → «Pantalla completa». Alterna el fullscreen del documento y nunca lanza: sin soporte del navegador, es un no-op silencioso (try/catch explícito en ui/shell/sections.ts).
No se ilustra aquí porque una captura a pantalla completa en un navegador headless es indistinguible de la de arriba: lo que cambia es el cromo del navegador, no el juego.
8 · Dónde se cambia todo: el menú SISTEMA

El menú se abre con F10 o con el botón ⚙. Secciones (medidas en vivo el 04-08-2026): Partidas y paneles · Vídeo · Audio · Teclas · Comandos (original) · Ayuda · Debug (QA).
Tres detalles de diseño que se ven en la captura:
- Está dibujado con el chrome EGA y la fuente 8×8 del juego, no con widgets modernos. Es el veredicto #23 (20-07-2026): la «ventana 1988» pasó a ser el default bajo las dos pieles. El look vectorial redondeado sobrevive sólo como fallback de QA tras
?shellVector=1. - La sección Vídeo lista las pieles como botones, una por piel, con la activa mostrada arriba en «Piel activa». No hay desplegable: un clic salta a esa piel por el mismo camino de persistencia que F9.
- La casilla «Layout partido» no aparece en esta captura, y es correcto: sólo se pinta si el layout partido existe en la sesión (
layoutPartidoDisponible). En escritorio no existe, así que la fila no se ofrece en vez de ofrecerse desactivada.
El ⚙ y por qué se desvanece
El botón se desvanece tras 4 segundos sin movimiento del puntero, para no ensuciar la contemplación de la piel de 1988. Pero en pantallas táctiles (pointer: coarse) queda siempre visible: sin teclado, es la única puerta al menú. Dos comportamientos, y el motivo de cada uno está escrito en la cabecera de ui/shell/gear.ts.
Contrapartida: en escritorio, la única afordancia visible del shell desaparece sola. Quien deje de mover el ratón mirando la pantalla se queda sin ninguna pista de que hay menú, y F10 no se descubre solo — que es, literalmente, la razón por la que existe el botón. Se compra limpieza visual con descubribilidad, y el pago es en la moneda que más escasea: el primer minuto de un usuario nuevo.
Contrapartida del propio menú: se eligió coherencia sobre legibilidad
Que el menú esté dibujado con chrome EGA y fuente 8×8 (veredicto #23) cuesta algo real: una fuente de mapa de bits de 8 píxeles es menos legible que la tipográfica vectorial que había antes, sobre todo en las líneas de ayuda pequeñas. La captura de arriba lo enseña — compara los títulos de sección con las filas de «Teclas».
Se decidió a favor de la coherencia («la ventana 1988» bajo las dos pieles), y el look vectorial no se borró: sobrevive tras ?shellVector=1 como fallback de QA. Que se conservara un camino de vuelta es la señal de que la contrapartida se reconoció al tomar la decisión, no después.
Lo que este documento no cubre
- El lado de los cursores (izquierda/derecha, por defecto derecha «para los diestros»,
deck-nativo.ts:ladoGuardado) — es una preferencia del deck, no una disposición. - El companion / atlas, que se abre en otra pestaña y sólo aparece en el menú si está desplegado.
- La cinemática de intro, que corre antes de montar ninguna piel y no tiene layout alternativo.






