Vibe coding a ciegas: un juego que se ve muy bien y un código que no escala

Hay mucho hype alrededor de dejar que la IA construya sola. Y sí, puede: en unas 21 horas de trabajo con Claude armé un juego completo en el browser, con WebGL, mundos generados proceduralmente y sonido sintetizado. Se ve muy bien.

El código, no.

Hice el experimento a propósito: dejar a la IA en auto mode, sin guidance de arquitectura, y ver qué decidía por su cuenta. El resultado es un buen caso de estudio de lo que pasa cuando hacés vibe coding a ciegas — y de por qué un proceso de AI SDLC no es burocracia, sino lo que separa un demo de un producto.

El experimento

El proyecto es 5dimension.com.ar: hacés click, saltás al hiperespacio y llegás a un mundo distinto cada vez.

Las reglas que me puse:

  • Auto mode — la IA ejecuta sin pedir confirmación en cada paso.
  • Sólo features — yo pedía lo que quería ver en pantalla: planetas, un drone, mini-juegos, un cockpit. Nunca pedí arquitectura, tests ni lint.
  • Sin revisar el código — miraba el juego, no el diff.

Lo que costó

  • Tiempo total — unas 21 horas de trabajo activo.
  • Tokens totales — unos 613 millones.
  • Costo de API — alrededor de USD 240 a precio de lista (entre 225 y 270).

El resultado: se ve muy bien

Lo que la IA construyó en esas horas:

  • Diez clases de planeta y cuatro lugares secretos, generados desde un seed que va en la URL.
  • Un renderer WebGL fotorrealista, otro liviano para teléfonos y un fallback 2D.
  • Entrada atmosférica distinta en cada mundo, un drone que vuela donde mirás y un cockpit 3D.
  • Ocho mini-juegos de 20 segundos, un álbum de planetas, un mundo del día y sonido sintetizado con WebAudio.

Todo funciona. Si el criterio es “¿anda?”, el experimento es un éxito.

Y acá viene lo incómodo: el código

Todo el juego vivía en un único index.html de 4.486 líneas: markup, CSS y JavaScript juntos.

La IA nunca propuso partirlo. Durante 33 commits siguió agregando features sobre el mismo archivo. Cada feature hacía el archivo más difícil de cambiar, y la IA lo seguía cambiando igual.

La conclusión: sin guidance, la IA no eligió un anti-pattern o dos. Eligió casi todos.

Los 20 anti-patterns

Cada cifra está medida sobre el código antes de cualquier corrección.

Arquitectura y modularidad

  1. God Object / God File — un index.html de 4.486 líneas con todo adentro, que creció durante 33 commits sin que nadie propusiera partirlo.
  2. God entry point (hub dependency) — después del split, main.js importaba 25 módulos y frame() era un if/else de 107 líneas sobre cada estado.
  3. Big Ball of Mud — 32 archivos sin fronteras: el código se repartió, el diseño no cambió.
  4. Cyclic Dependency — cockpit → cruise → entry → cockpit.
  5. Temporal Coupling — importar un módulo ejecutaba código (listeners, cambios al DOM, escrituras a storage). El orden de carga importaba y no estaba documentado.

Cohesión y acoplamiento

  1. Low Cohesion — progress.js mezclaba storage, scoring, unlocks, el catálogo de naves, HTML y toasts.
  2. Global Mutable State — los objetos app, cam e input, escritos desde 10 módulos.
  3. Shotgun Surgery — cada mini-juego repartido en 5 a 7 archivos. Cambiar uno implica tocarlos todos.
  4. Fat Interface — sound.js exportaba 38 funciones, una por evento del juego.

Encapsulamiento

  1. Encapsulamiento roto — varios módulos le agregaban campos al objeto world después de crearlo, incluidos GPU handles. app.cruise y app.comms aparecían sin estar declarados.

Magic values

  1. Magic Strings — 9 estados como strings sueltos, escritos desde 4 archivos, y 268 comparaciones de strings sobre state, mode, kind o type. Un typo nunca falla: simplemente nunca matchea.
  2. Magic Numbers — unas 7.800 constantes numéricas inline en el JavaScript, sin nombre.

Estado y control de flujo

  1. State machine implícita — las transiciones pasan donde sea que alguien asigne app.state. Sin tabla de transiciones, sin validación, sin hooks de entrada o salida.
  2. Polling en vez de eventos — 6 setTimeout re-chequeaban el estado al disparar en vez de estar atados a la transición. Podían disparar en una visita posterior al mismo estado.

Separation of concerns

  1. Presentación dentro de la lógica — 262 colores hardcodeados en JS y 18 templates HTML armados a mano con innerHTML.
  2. Contenido acoplado a la lógica — 286 llamadas L(es, en) inline dentro de los módulos de juego.
  3. Code as strings — 2.725 líneas de GLSL dentro de template strings de JavaScript, con variantes de calidad armadas por text-replace.
  4. Reglas de juego acopladas al renderer — la altura del suelo para el drone se leía de la GPU con readPixels cada 50 ms. Una regla del juego dependía del pipeline de rendering, y la CPU esperaba a la GPU 20 veces por segundo.

Manejo de errores y seguridad

  1. Swallowed Exceptions — 7 bloques catch {} vacíos, y ningún manejo de context loss de WebGL: ante un reset de la GPU, la pantalla quedaba muerta.
  2. Datos untrusted (no confiables) sin encoding — nombres guardados en localStorage entraban a innerHTML sin escapar.

Afuera de la lista quedaron los problemas de legibilidad — 723 líneas de más de 160 caracteres, 218 con cinco statements o más, nombres de una o dos letras.

Lo que no es culpa del modelo

Sería fácil leer esto como “la IA programa mal”. No es eso.

La IA hizo exactamente lo que le pedí: features. Las hizo rápido y funcionan. Lo que no le pedí — arquitectura, límites entre módulos, un modelo de datos, tests — quedó en default. Y el default de un modelo optimizando la tarea inmediata es el camino más corto: agregar la línea donde ya está el resto del código.

Vibe coding a ciegas vs AI SDLC

En AI SDLC: un compendio de buenas prácticas para desarrollar con IA describí cómo trabajo con IA cuando el objetivo es producción. Este experimento es el contraste exacto.

  • Diseño — a ciegas, la arquitectura emerge sola, commit a commit, y emerge como god file. Con AI SDLC, vos decidís la arquitectura antes de escribir un solo prompt.
  • Plan — a ciegas, la IA ejecuta directo. Con AI SDLC, le pedís un plan detallado, lo revisás y lo dejás en un .md que los dos pueden modificar. El costo es más tiempo al principio; el ahorro es no refactorizar 4.486 líneas después.
  • Scope — a ciegas, cada pedido toca lo que haga falta. Con AI SDLC, cada cambio tiene un scope explícito y un test que lo verifica.
  • Revisión — a ciegas, mirás el resultado en pantalla. Con AI SDLC, revisás el diff, y los claims del commit message contra el código.
  • Guardrails — a ciegas, no hay lint, ni tests en el loop, ni gate de deploy, salvo que los pidas. Con AI SDLC, son parte del setup desde el primer día.
  • Human in the loop — a ciegas, el dev es un usuario que pide features. Con AI SDLC, el dev es responsable del sistema.

Maximiliano Díaz Doglia

AI Platform Engineer & Full-Stack Developer
Building Enterprise Integrations & Automations