Un arcade de navegador en TypeScript puro: ocho juegos, 35 kB y licencia MIT
El proyecto reúne Snake, Tetris, Breakout, Flappy, 2048, Buscaminas, Sudoku y Gomoku en una sola interfaz, sin framework ni motor de juego y con cero dependencias en tiempo de ejecución.

Ocho juegos clásicos de navegador, una sola carcasa de máquina recreativa y ningún framework. Eso es retro-arcade, un proyecto en TypeScript y Canvas 2D que se abre en el navegador sin instalar nada. Snake, Tetris, Breakout, Flappy, 2048, Buscaminas, Sudoku y Gomoku comparten barra superior, pantalla, superposición de resultados y pie de teclas, y funcionan igual con teclado o con el dedo. Licencia MIT y una demo pública para probarlo sin clonar nada.
Los números son los que llaman la atención de un desarrollador: cero dependencias en tiempo de ejecución, unos 35 kB comprimidos con gzip para todo el build (fuentes aparte), 269 pruebas unitarias y 28 de extremo a extremo con Playwright, todas en integración continua. Sin motor de juego detrás, casi todo el código que se envía es el que hace falta para jugar.
Una interfaz para ocho juegos
Cada juego implementa un único contrato y recibe un objeto de contexto con lo que tiene permitido usar: audio sintetizado con WebAudio, un envoltorio de localStorage, el servicio de entrada, ranuras del DOM y una llamada para pintar la tarjeta de resultado. El caparazón se encarga del resto. Añadir un noveno juego no obliga a tocar esa carcasa, y los menús de pausa, silencio y vuelta al hub se comportan igual en todos.
La separación entre reglas y dibujo es lo que sostiene el diseño. Cada juego tiene su logic.ts sin DOM ni Canvas, con la fuente aleatoria pasada como parámetro, y su index.ts que pinta el estado y traduce la entrada en llamadas a las reglas. El autor cuenta que a mitad de proyecto hizo un rediseño visual completo, del neón oscuro al papel cálido actual, y los ocho logic.ts y sus pruebas no cambiaron ni una línea. Las pruebas de la lógica corren en Node, sin navegador: un slideLine de 2048 se comprueba con entrada y salida, y ya.
Los controles son otra decisión deliberada. Los tableros van en Canvas y reciben clics ahí, pero el teclado numérico, el menú de dificultad y el botón de deshacer son <button> reales. El motivo es práctico: un botón del DOM ya trae anillo de foco, acceso por teclado y un área táctil fácil de dimensionar. Pintarlos sobre el lienzo obliga a reimplementar todo eso a mano.
La IA de Gomoku y el coste de no cancelar
El rival de Gomoku es un minimax con poda alfa-beta y tres niveles que corresponden a profundidades de búsqueda 1, 2 y 4. La profundidad 4 congela la interfaz si se ejecuta en el hilo principal, así que la búsqueda va en un Web Worker. Ahí aparece un problema clásico: el jugador puede reiniciar la partida mientras la IA piensa, y la respuesta vieja no debe aterrizar sobre el tablero nuevo. Cada reinicio incrementa un token que viaja con la petición y vuelve con la respuesta; el hilo principal lo compara antes de aplicar el movimiento. Eso descarta resultados obsoletos, pero no cancela la búsqueda anterior, que sigue consumiendo CPU y puede retrasar la siguiente petición.
La carga inicial se resuelve aparte. El hub solo trae el caparazón y el enrutador, y cada juego se descarga con import() dinámico cuando se abre. Conviene no confundir las dos cosas: el troceado de código mejora el primer arranque, no reduce por sí solo el tamaño total del build. La única petición a un tercero son las Google Fonts, y el proyecto las excluye de esa cifra de 35 kB.
Para quien mantiene front-end, el interés no está en los juegos sino en el patrón: contratos estrechos, lógica aislada y testeable sin navegador, y controles nativos donde el DOM gana. Es un ejemplo pequeño y completo de cómo repartir responsabilidades sin arrastrar una dependencia por el camino.


