Fable 5 vs Opus 5: dos modelos, la misma especificación, dos juegos distintos
En los experimentos anteriores comparé modelos con una landing: un prompt quirúrgico primero, una imagen de referencia y un brief corto después. Una landing se juzga en diez minutos. Este experimento va a por otra cosa: una aplicación entera, con lógica de negocio real, que tiene que funcionar.
Los dos contendientes son Claude Fable 5 y Claude Opus 5, los dos modelos grandes de Anthropic. Misma tarea, misma especificación, mismo agente (Claude Code), mismos assets. Un juego de puzles lógicos llamado ChronoGrid: coloca núcleos de energía en una rejilla para que cada fila y cada columna contenga cada nivel exactamente una vez. Suena a sudoku porque lo es, con celdas selladas, cinco tipos de pista y solución única certificada.
El resumen corto: los dos entregaron un juego jugable, completo y bien construido. Las diferencias no están en si funciona, están en dónde deciden que se haga el trabajo. Y esa decisión, que es puramente arquitectónica, es la que acabas notando con el mando en la mano.
Cómo monté el experimento
Nada de “hazme un juego de puzles”. El encargo fue spec-driven: doce documentos escritos por mí antes de abrir ninguna sesión.
ENGINE_SPEC.mdes el autoritativo: cuadrado latino con celdas bloqueadas, cinco tipos de pista con niveles de dificultad, dos resolutores (uno lógico y uno de conteo para certificar unicidad), graduación D0 a D5, generador determinista con mulberry32 y FNV-1a, puzle diario en UTC y doce tests obligatorios.- Los otros once cubren producto, reglas, arquitectura, sistema de diseño, accesibilidad, rendimiento, i18n, testing, guías de UI y assets.
- Los 20 assets (fondos, orbes, trofeos, logo) los generé aparte y los copié idénticos a los dos espacios de trabajo, para que ninguno tuviera ventaja visual.
Cada modelo arrancó su sesión desde su propia carpeta, con el mismo prompt corto que le decía “lee docs/ y construye el juego”. A partir de ahí, solos. Cinco intervenciones mías en cada sesión, ninguna de contenido.
El experimento está en github.com/ivanlhz/fable-vs-opus: especificación, protocolo, scripts de medición y el código exacto de cada modelo, sin retocar una línea. Y los dos juegos están desplegados tal cual los entregó cada modelo, para que los juzgues tú mismo:
- Fable 5 → chronogrid-fable-5.vercel.app
- Opus 5 → chronogrid-opus-5.vercel.app
Un aviso antes de que abras el de Fable y pienses que está roto: la primera rejilla tarda. Eso es parte del resultado y lo explico en la siguiente sección.
La primera pantalla: Opus estructura mejor
Lo primero que ves es la home, y ahí no hay debate.


Fable monta una home simétrica: logo centrado, título, descripción y tres tarjetas. Es correcta y está limpia, pero es plana. Todo pesa lo mismo y no hay ningún sitio evidente donde hacer clic.
Opus monta una jerarquía de verdad: etiqueta de categoría, título, promesa en una línea, explicación en tres, y un botón primario “Jugar historia” que te dice qué hacer. Debajo, cuatro tarjetas de modo y luego tres de contexto (las tres reglas, tu progreso, tu racha). Es la diferencia entre una portada y una pantalla de producto.
Y hay un detalle que no es estético: Opus expone cuatro modos en el menú porque tiene uno más, el generador de puzles.
La carga: por qué Opus se siente más rápido
Esta es, para mí, la diferencia más interesante del experimento, porque parece una impresión subjetiva y resulta que está escrita en el código.
Al entrar a un nivel de la historia, Fable te enseña esto durante varios segundos:

Opus, en cambio, te pone el tablero directamente. La razón es que cada modelo decidió un sitio distinto para generar los puzles.
Fable lo hace todo en el navegador. Cada vez que abres un nivel, tu máquina genera la rejilla desde cero y ejecuta el resolutor de conteo para certificar que la solución es única. De los 40 niveles de historia, solo 5 vienen precalculados en la base de datos, y incluso esos se vuelven a validar en el Web Worker antes de pintarse. De ahí el “Certificando una solución única”.
Opus lo resuelve en el servidor. Los niveles de historia y el puzle diario salen de tres rutas de API que cachean el resultado en SQLite. El primer jugador que abre un nivel paga la generación; todos los demás lo reciben ya hecho. Solo el modo infinito y el generador usan el Web Worker, porque ahí la semilla es tuya y no hay nada que compartir.
Lo medí. Con la caché caliente, la API de Opus devuelve un puzle en entre 16 y 23 milisegundos:
| Petición | Primera llamada (genera) | Llamadas siguientes (caché) |
|---|---|---|
| Historia nivel 1 | 1,36 s | 0,022 s |
| Historia nivel 25 | 0,50 s | 0,022 s |
| Historia nivel 39 | 0,31 s | 0,017 s |
| Puzle diario | 1,03 s | 0,023 s |
Lo curioso es que los dos motores son igual de rápidos. Los medí por separado, mismas semillas, mismas dificultades, sin navegador de por medio:
| Dificultad | Fable 5 (mediana) | Opus 5 (mediana) |
|---|---|---|
| Fácil | 1 ms | 1 ms |
| Media | 88 ms | 88 ms |
| Difícil | 134 ms | 67 ms |
| Experta | 551 ms | 219 ms |
| Pesadilla | 130 ms | 423 ms |
Van a la par, con ventaja para cada uno en distintas dificultades. Así que la sensación de “Opus carga antes” no viene del algoritmo, viene de la arquitectura. Fable escribió un motor igual de bueno y lo puso en el peor sitio posible para el jugador.
Hay dos detalles más que refuerzan lo mismo. El proveedor de puzles de Opus acepta un AbortSignal y termina el worker al salir de la pantalla; el de Fable no cancela nada y nunca destruye el worker, así que si navegas rápido entre niveles las generaciones se acumulan en la cola. Y Opus se escribió además un script de benchmark con presupuestos por dificultad sacados de la especificación. No se lo pedí.
El tablero: aquí gana Fable
Con el juego cargado, la cosa se da la vuelta.


El tablero de Fable es más fácil de leer, y no es una cuestión de gusto:
- Tiene un HUD de verdad arriba: tiempo, errores y pistas usadas, con etiqueta encima de cada número.
- La paleta muestra cuántos núcleos te quedan de cada nivel (×3, ×4, ×2). Eso es información que necesitas para razonar el puzle y en Opus está en letra pequeña al lado del número.
- Los botones llevan icono y texto: Notas, Borrar, Deshacer, Rehacer, Pista. En Opus son texto suelto en una fila, y “Notas desactivadas” ocupa media barra.
- Las pistas negativas se dibujan sobre la celda en rojo (ese ≠2 de la esquina), no solo en el panel lateral.
El de Opus es más sobrio y tiene un fallo visual claro: la celda seleccionada se pinta con fondo blanco sólido en modo oscuro. Destaca, sí, pero rompe la estética del resto de la pantalla.
En móvil los dos tableros funcionan bien y se dejan jugar sin zoom:


Los modos: uno gana cada uno
Generador de puzles: gana Opus. Es una pantalla que Fable directamente no tiene. Metes una semilla, eliges entre cinco dificultades y te genera la rejilla. Determinista y compartible: la misma semilla da siempre el mismo puzle.

Modo infinito: gana Fable. Los dos lo tienen, con semilla compartible y dificultad que sube cada pocos puzles. La diferencia es que Fable guarda tu partida y te ofrece continuarla donde la dejaste.

Lo mejor de esto es lo que encontré al mirar el código de Opus. Tiene declarada una clave de almacenamiento llamada infiniteRun para guardar la partida infinita, y no la usa en ninguna parte. Se acordó de la necesidad, reservó el sitio y se le olvidó implementarlo. Es exactamente el tipo de cabo suelto que un modelo deja cuando trabaja cuatro horas seguidas.
Modo historia: gana Fable, por poco. Los dos tienen 40 niveles con tutoriales encadenados. Fable lo presenta más ordenado y, sobre todo, respeta el bloqueo secuencial: si intentas entrar al nivel 5 sin haber terminado el 4, te frena. Opus también pinta los niveles como bloqueados en el mapa, pero si escribes la URL a mano te deja jugar el nivel 40 (una rejilla de 8×8 en dificultad Pesadilla) con el progreso a cero. La regla está en la interfaz y no en la lógica.
Diario, estadísticas y logros: empate. Los dos resuelven lo mismo con calidad muy parecida. Fable desglosa por dificultad con más columnas (errores y pistas usadas), Opus añade tasa de finalización y media por puzle. Elige el que prefieras, no hay ganador.


Responsive: el menú que delata a Fable
En las secciones, los dos cumplen. El fallo está en la cabecera, y es el error más visible del experimento.


A 390 píxeles de ancho, Fable no hace menú hamburguesa. Deja los seis enlaces en una fila que se desborda y añade una barra de desplazamiento horizontal con flechas. “Estadísticas” aparece cortado a la mitad y no hay nada que te sugiera que puedes deslizar. Es navegación que se descubre por accidente.
Está en una sola línea de código. La cabecera de Fable es un <nav> con overflow-x-auto y ninguna rama para móvil: la misma barra a todos los anchos. La de Opus tiene estado de apertura, aria-expanded, botón de cierre y se cierra sola al navegar. No es que Fable lo hiciera mal, es que no lo hizo.
El código, punto por punto
Aquí es donde el experimento deja de ser una opinión. Los dos proyectos tienen prácticamente el mismo tamaño (unas 12.000 líneas de TypeScript, 116 ficheros cada uno), los dos pasan tsc --noEmit y eslint sin una sola queja, y los dos aplican Clean Architecture con las capas separadas de verdad. Puntúo sobre 5 lo que pude verificar ejecutándolo.
| Eje | Fable 5 | Opus 5 |
|---|---|---|
| Estructura de directorios | ★★★★½ | ★★★★★ |
| Seguridad | ★★★★☆ | ★★★★☆ |
| Arquitectura | ★★★★★ | ★★★★½ |
| Legibilidad | ★★★★½ | ★★★★★ |
| Escalabilidad | ★★★½☆ | ★★★★★ |
| Rendimiento | ★★★☆☆ | ★★★★★ |
| Tests | ★★★★☆ | ★★★★½ |
| Lógica de juego | ★★★★½ | ★★★★☆ |
| Total | 33 / 40 | 37 / 40 |
Estructura de directorios. Los dos parten del mismo esqueleto (app, domain, application, infrastructure, features, components). Fable agrupa mejor el dominio en engine, modes y player. Opus gana por dos cosas: separa features/board de features/game en vez de meter todo el tablero en un fichero de 411 líneas, y organiza los tests en un árbol que refleja la arquitectura (unit/domain, unit/application, unit/presentation, integration, e2e, helpers).
Seguridad. Empate, con perfiles opuestos. Ninguno tiene eval, ni dangerouslySetInnerHTML, ni secretos, y los dos validan con Zod todo lo que cruza una frontera (localStorage, base de datos, worker, API). Fable tiene menos superficie de ataque porque no expone ninguna ruta de servidor para los puzles, pero activa dangerouslyAllowSVG en el optimizador de imágenes (lo mitiga con una CSP de sandbox y lo documenta) y no pone ninguna cabecera de seguridad. Opus valida los tres endpoints con límites explícitos, devuelve códigos de error sin filtrar detalles internos, apaga X-Powered-By y deja el hook de tests detrás de una variable de entorno. Su punto flojo es que /api/puzzles/generate acepta cualquier semilla en dificultad Pesadilla sin límite de peticiones ni caché: es un endpoint que quema CPU gratis. Ninguno de los dos escribe una CSP para la aplicación.
Arquitectura. Aquí gana Fable y es el único eje donde lo hace con claridad. Escribió un fichero application/ports.ts con puertos explícitos (StoragePort, ClockPort) y una implementación en memoria para tests y para SSR, y montó una raíz de composición que crea los stores por proveedor en vez de dejarlos como singletons de módulo. Eso es arquitectura hexagonal de manual y hace el código genuinamente más fácil de testear. Opus se queda a medio camino ahí, pero acierta en otra cosa importante: sacó toda la lógica de partida a un application/game/session.ts puro de 438 líneas y dejó el store de Zustand en 131. Fable mete las dos cosas en un store de 380 líneas.
Legibilidad. Los dos comentan el porqué, no el qué, y citan la sección de la especificación que justifica cada decisión. Opus va un punto por delante en disciplina: noUnusedLocals, noUnusedParameters y verbatimModuleSyntax activados en el tsconfig, dependencias fijadas a versión exacta en vez de rangos, engines y packageManager declarados, y ficheros más pequeños y mejor repartidos.
Escalabilidad. La diferencia más grande. Opus ya tiene la capa que necesitas para crecer: API, repositorio, caché en base de datos, cabeceras de caché y configuración de outputFileTracing para que la base de datos viaje con el bundle en serverless (con un comentario explicando que en un sistema de ficheros de solo lectura la escritura de caché falla sin romper nada). Fable es 100% cliente: funciona sin conexión y no cuesta un céntimo de servidor, que es una ventaja real, pero el día que quieras un ranking o partidas compartidas empiezas la capa de servidor desde cero.
Rendimiento. Ya está contado arriba. Motores equivalentes, decisiones opuestas. Opus además ajusta deviceSizes e imageSizes para las imágenes, pone cache inmutable en /assets y se escribió un benchmark propio.
Tests. Fable tiene 151 tests unitarios con 95,63% de sentencias y 93,11% de ramas cubiertas en dominio y aplicación, 24 tests end-to-end en seis ficheros, y algo que Opus no tiene: una barrera de accesibilidad con axe que falla si aparece cualquier violación WCAG AA seria, más un spec a 390 píxeles. Opus tiene 338 tests (más del doble) repartidos en unitarios e integración con Testing Library, cubre 92,92% de sentencias y 86,56% de ramas, y corre sus 31 tests end-to-end en dos dispositivos, escritorio y Pixel 7, con specs de contrato para la API. Fable cubre mejor el dominio; Opus cubre más capas y más dispositivos. Gana Opus por poco, y sin la barrera de axe no habría ganado.
Lógica de juego. Los dos implementan la especificación completa: cuadrado latino, cinco tipos de pista, dos resolutores, graduación D0 a D5, generación determinista y diario en UTC. Fable se lleva el punto por los tres detalles que ya conté: bloqueo secuencial de la historia aplicado de verdad, partida infinita que se reanuda, y contadores por símbolo en la paleta. Opus pierde por la clave de almacenamiento que declara y no usa y por la regla de bloqueo que solo vive en la interfaz.
Cuánto costó cada uno
Las dos sesiones corrieron el mismo día, con el mismo agente y esfuerzo máximo.
| Fable 5 | Opus 5 | |
|---|---|---|
| Duración | 4 h 17 min | 4 h 34 min |
| Turnos del modelo | 254 | 275 |
| Tokens de salida | 488.542 | 498.333 |
| Coste API equivalente | 139,66 $ | 74,04 $ |
Esta tabla tiene truco y conviene decirlo. Yo pago suscripción, así que ese dólar no salió de mi cuenta: es el coste que habría tenido la misma sesión facturada por API, que sirve para comparar los dos modelos entre sí y para nada más.
Dicho eso, el dato es difícil de ignorar. Los dos escribieron prácticamente los mismos tokens en prácticamente el mismo tiempo, y Fable costó 1,9 veces más. Por un resultado que, midiéndolo, sale por debajo.
Límites del experimento
- Es n=1. Una tarea, una pasada por modelo, un día. Medición honesta, no ley universal.
- Los tiempos de carga los observé en servidores de desarrollo, no en builds de producción. La diferencia arquitectónica es real y está en el código; los milisegundos exactos de una build optimizada serían otros.
- El coste no es dinero real, es coste API equivalente. Sirve para comparar, no para presupuestar.
- Puntuar código sobre 5 tiene una parte de criterio. He intentado que cada estrella se apoye en algo ejecutable (tests que pasan, cobertura medida, latencias cronometradas, líneas concretas) pero el peso de cada eje lo pongo yo.
- Los dos modelos siguen cambiando. Los números caducan; el método no.
Entonces, ¿cuál es mejor?
Opus 5, 37 puntos contra 33. Y gana por donde se nota en producción, no por donde luce en una captura: puso la generación de puzles donde tocaba, cacheó lo que se comparte, dejó montada la capa que necesitas para crecer y escribió el doble de tests. La home mejor jerarquizada y el generador con dificultad son la parte visible de una cabeza que estaba pensando en el producto entero.
Fable no queda mal parado. Escribió la mejor arquitectura de las dos, con puertos y raíz de composición de libro; hizo el tablero más jugable, que es la pantalla donde el usuario pasa el 90% del tiempo; y fue el único que puso una barrera de accesibilidad automática en la suite. Sus dos pérdidas grandes son evitables y muy concretas: el menú móvil que no existe y la decisión de regenerar cada puzle en el navegador del jugador.
Y creo que ahí está lo que de verdad me llevo de este experimento. Con una especificación de doce documentos, los dos modelos entendieron el encargo, respetaron las reglas del motor y entregaron software que funciona. La frontera ya no es “¿sabe programar esto?”. La frontera es si el modelo sabe dónde poner cada cosa, que es justo la decisión que separa a un desarrollador con oficio de uno que solo cumple el ticket. Fable escribió un motor tan bueno como el de Opus y lo colocó en el peor sitio para el jugador. Ninguna métrica de código habría detectado eso: solo se ve abriendo el juego y esperando.
Es la misma disciplina que aplico en proyectos de cliente: el coste y el rendimiento de un sistema no se estiman leyendo la documentación del proveedor, se miden con telemetría propia sobre la tarea real. Si estás decidiendo qué modelo meter en tu equipo y prefieres números a opiniones, hablamos 30 minutos.