bsanchez@codesan.dev:~/blog$ _
EN
~$ cat opencode-modelos-gratis.md

7 modelos gratis de opencode, un solo prompt: qué entregó realmente cada uno

opencode trae una tanda de modelos gratuitos y la pregunta obvia es cuál sirve. No encontré una comparativa que me convenciera, así que hice la mía: un prompt, siete modelos, cero ayudas. Lo que sigue es la bitácora de esa mañana.

Adelanto el resultado que no esperaba: el fallo más grave no fue de diseño ni de código. Fue algo que ningún review de código habría detectado, y para verlo tuve que hacer peticiones HTTP.

Las reglas: todo vanilla

Esto es importante porque define qué mide el experimento y qué no. La prueba fue deliberadamente cruda:

  • Sin skills. Ninguna instrucción cargada.
  • Sin MCPs. Ningún servidor de contexto conectado.
  • Sin spec-driven development. Nada de documento de especificación previo, ni plan, ni fases.
  • Sin técnicas de desarrollo agéntico. Sin chain-of-thought forzado, sin auto-crítica, sin iteración, sin "revisa tu trabajo".
  • Un solo turno. Pegué el prompt, esperé, y lo que salió es lo que evalué. Sin correcciones ni segundas oportunidades.

Esto no mide el techo de cada modelo. Un buen andamiaje agéntico habría corregido la mitad de los problemas que encontré. Lo que mide es el piso: qué te entrega el modelo cuando le pides algo como se lo pedirías a un colega, sin ceremonia. Y para decidir cuál de los gratuitos vale la pena, el piso es justo lo que quieres saber.

El prompt, literal

PROMPT ENVIADO A LOS 7 MODELOS

Crea una landing page para promocionar una Escuela de música en Soacha, Cundinamarca llamada Javastudios. Esta debe cumplir con las siguiente características:

  1. Usar colores azules
  2. Tener un diseño minimalista muy atractivo
  3. tener al menos una leve animación
  4. tener un llamado a la acción que dirija a whatsapp
  5. Tener navegación y footer
  6. Tener imágenes de Unsplash

Seis requisitos verificables, un negocio local real y suficientemente específico como para que el modelo no pueda salir del piloto automático. Sin más contexto: ni teléfono, ni precios, ni años de trayectoria, ni catálogo de cursos. Retén ese detalle, porque termina siendo el centro del artículo.

Los contendientes

Modelo Tiempo Notas de ejecución
DeepSeek V4 Flash 42s Sin fricción
MiMo v2.5 1m 53s Con default no encontraba el provider; hubo que forzar variant: medium
Big Pickle 2m 05s Escribió en una subcarpeta propia
Ling 3.0 Flash 2m 17s Sin fricción
North Mini Code 4m 17s Sin fricción
Laguna S 2.1 20m 48s* *Casi todo fueron esperas por rate limit
Nemotron 3 Ultra Streaming response failed en todos los intentos

Empecemos por el que ni siquiera llegó a la pista.

Nemotron 3 Ultra: el que anunció y no entregó

El único "Ultra" de la tanda y el único que no produjo una sola línea. El patrón se repitió idéntico en cada intento: procesaba el prompt, anunciaba que iba a crear el index.html… y moría con Streaming response failed. Nunca llegó a escribir el archivo.

No es un juicio sobre la capacidad del modelo — es un juicio sobre su disponibilidad, que para quien va a trabajar es lo mismo. Un modelo que no responde tiene calidad cero, independientemente de lo que pudiera hacer. Queda fuera de la comparativa por incomparecencia.

Cómo evalué a los seis que sí entregaron

Además de abrirlos en el navegador y mirarlos como los miraría un cliente, hice tres cosas que resultaron ser las que separaron el grano de la paja:

  1. Renderizado completo a página entera con Firefox headless, desactivando loading="lazy" y forzando los reveals, para que la captura muestre la página real y no una a medio cargar.
  2. Verificación HTTP de cada recurso externo: cada URL de Unsplash, cada CDN, cada hoja de estilos.
  3. Lectura del JavaScript, no solo del HTML. Ahí es donde estaban escondidas las peores sorpresas.

Modelo por modelo

[1] Big Pickle 2m 05s · 26 KB · 575 líneas
Alto: 4365px Imágenes: 10/11 Scroll-reveal: Año en footer: 2026
Landing generada por Big Pickle: hero azul con trompeta, grid de 6 cursos, galería y testimonios
Big Pickle — hero con curva orgánica, grid 3×2 sin huérfanos. El hueco en la galería es su única imagen 404.

Mi ganador, y por una razón concreta: es el único que consiguió ser completo sin dejar de ser minimalista. 4365px de alto contra los 4875 de MiMo y los 4964 de Ling, con la misma cantidad de secciones e imágenes. Cuando dos de los seis requisitos empujan en direcciones opuestas — "minimalista" y "navegación, footer, imágenes" — él fue el que mejor negoció.

Es también el único con personalidad de diseño: curva orgánica en la transición del hero, overlays en hover sobre la galería, y un @keyframes pulse-wa que hace latir suavemente el botón de WhatsApp. Los demás agotan su repertorio en fadeUp y float.

Y la localización más fina de los seis. No dice "clases de percusión": dice "batería, cajón, percusión latina y ritmos colombianos". No dice "producción musical": dice "FL Studio, Ableton, mezcla y masterización". Eso no es rellenar una plantilla.

Lo que le cobro: ocho enlaces href="#" y un link "Blog" en el footer que apunta a una sección inexistente. Navegación que promete y no cumple.

[2] MiMo v2.5 1m 53s · 24 KB · 538 líneas
Alto: 4875px Imágenes: 10/11 Scroll-reveal: Año en footer: 2026
Landing generada por MiMo: hero con foto de fondo y overlay azul, 6 cursos, galería 3x2
MiMo — el único con hero fotográfico de fondo. La caja gris junto a las estadísticas es su imagen rota.

Empate técnico con Big Pickle en todas las métricas duras. Su ventaja: es el único con hero fotográfico de fondo, con overlay azul degradado. Los demás o pusieron la foto al lado, o no pusieron ninguna. Es la diferencia entre parecer una landing y parecer un ejercicio de maquetación.

Y es, junto a Big Pickle, el único que cuadró todos los grids: 6 cursos en 3×2 exacto, 6 fotos en 3×2 exacto, 3 testimonios en fila. Cero tarjetas huérfanas. Ling y Laguna dejaron colgados en dos secciones cada uno. Elegir números que cierran es criterio de diseño, no suerte.

Detalle que me gustó: usó hola@javastudios.co, con el TLD colombiano. Nadie se lo pidió.

Nota de reproducibilidad: con la configuración por defecto opencode no encontraba el provider. Hubo que forzar variant: medium. Es un problema de plomería, no del modelo, pero si vas a repetir el experimento lo vas a encontrar.

[3] Ling 3.0 Flash 2m 17s · 34 KB · 1240 líneas
Alto: 4964px Imágenes: 6/7 Scroll-reveal: Año en footer: 2026
Landing generada por Ling: hero azul, sección de cursos, tabla de precios en COP y testimonios
Ling — el único que armó tabla de precios. La primera tarjeta de cursos es la que perdió su imagen.

El más largo de todos y el que mejor entendió que esto es una landing de negocio, no un ejercicio de CSS. Es el único que armó una tabla de precios — $150.000 / $280.000 / $450.000 COP mensuales, cifras perfectamente plausibles para Soacha — y el que puso testimonios con nombres colombianos. La localización más consciente después de Big Pickle.

Técnicamente hizo la animación como se debe: IntersectionObserver con threshold: 0.15 y transitionDelay escalonado generado en JS. Me costó capturarlo: el screenshot salía con tres secciones vacías hasta que forcé el reveal a mano.

Mala suerte con la imagen rota: de sus siete, la única 404 le cayó en la primera tarjeta de cursos — lo primero que el visitante mira después del hero.

Y una desobediencia interesante: el botón flotante de WhatsApp es verde, sobre una paleta que el prompt pedía azul. Comercialmente es la decisión correcta: el verde es reconocimiento de marca instantáneo. Respecto al brief, es incumplimiento. Yo la firmaría, pero hay que nombrarla.

[4] DeepSeek V4 Flash 42s · 13 KB · 363 líneas
Alto: 2621px Imágenes: 3/4 Scroll-reveal: no Año en footer: 2026
Landing generada por DeepSeek: hero con foto al lado, tres tarjetas de cursos, galería y CTA azul
DeepSeek — la mitad de alto que el resto. El más limpio y el más incompleto a la vez.

El más rápido por un margen ridículo: 42 segundos, cuando el segundo tardó casi tres veces más. Y el único que entendió "minimalista" literalmente: 4 secciones, 13 KB, 2621px de alto. La mitad que cualquier otro. Cero dependencias de JavaScript — el menú hamburguesa es un onclick inline de una línea.

Tiene el detalle de conversión más fino de los seis: el SVG oficial de WhatsApp embebido y, sobre todo, mensaje pre-cargado en el enlace (wa.me/...?text=Hola%20Javastudios...). Nadie más lo hizo. Eso es pensar en el usuario que va a dar clic, no en la checklist.

Su fallo, y es didáctico: la animación técnicamente existe pero es invisible. Las clases .fade-up se disparan al cargar la página, con delays por :nth-child. Sin IntersectionObserver, sin trigger de scroll. Todo lo que está bajo el fold termina de animarse antes de que llegues a verlo.

Peor: como .fade-up arranca en opacity: 0, mi primera captura salió con el <h1>, el párrafo y el CTA invisibles — la foto quedó tomada a mitad de animación. Durante casi un segundo el hero está en blanco. Eso es un golpe directo al LCP.

Su gran virtud, y no la vi hasta el final: es el único de los seis que no inventó una sola cifra de negocio. Ni "500+ estudiantes", ni "desde 2018", ni precios. Volveré sobre esto, porque resultó ser más importante que todo lo demás.

Detalles de descuido: declara @keyframes fadeIn y nunca lo usa. Su propio copy del hero promete "canto y más" pero solo hay tres cursos. Y el hamburguesa es un <div onclick> sin role, sin tabindex, sin aria-expanded: en móvil, un usuario de teclado o lector de pantalla no puede abrir el menú.

[5] Laguna S 2.1 20m 48s* · 29 KB · 937 líneas
Alto: 3913px Imágenes: 1/2 Scroll-reveal: no Año en footer: 2024
Landing generada por Laguna: hero sin imagen, tarjetas de servicios, y una foto de laptop en la sección Sobre Nosotros
Laguna — hero con la imagen rota, y la única foto que carga en toda la página es un laptop.

Aquí encontré tres bugs verificables, y uno de ellos es de los que no detectas leyendo el código.

Bug 1 — la tipografía nunca carga.

https://fonts.googleapis.com/css2=Inter:wght@300;400;500;600;700&display=swap
                                  ^ falta ?family

Esa URL devuelve 404; la corregida devuelve 200. Lo verifiqué. Inter no carga jamás y la página entera cae al sans-serif del sistema. El modelo diseñó con una tipografía y entregó otra — y ese carácter faltante explica buena parte de por qué se ve pobre.

Bug 2 — usó un icono que no existe. <i class="fas fa-piano">. Carga Font Awesome Free 6.5.0 desde cdnjs, pero fa-piano es un icono Pro. Por eso la tarjeta "Clases de Piano" muestra un cuadrado azul vacío mientras guitarra, voz y batería sí renderizan. Eligió 13 iconos correctos y falló justo en el que no verificó.

Bug 3 — el peor. Puso dos imágenes en toda la página. La del hero es 404: lo primero que ve el visitante es una caja gris con el texto alt "Estudiante de música tocando piano". Y la única que sí carga es una foto de dos manos señalando un laptop, en la landing de una escuela de música. No está rota: está mal elegida. Resultado neto: cero imágenes útiles.

Donde me equivoqué y le doy crédito: di por hecho que su formulario de contacto era un form muerto sin backend. No lo es. Hace e.preventDefault(), arma el mensaje y abre wa.me con el texto codificado. Convierte un formulario en un canal de WhatsApp sin servidor. Es la solución más elegante al requisito 4 de toda la tanda.

Ah, y el footer dice © 2024. Dos años atrasado, cuando DeepSeek acertó 2026 sin ayuda.

[6] North Mini Code 4m 17s · 26 KB · 803 líneas
Alto: 4814px Imágenes: 0/6 Scroll-reveal: no Año en footer: 2024
Landing generada por North: sección Galería de Fotos con seis rectángulos vacíos y solo texto alternativo
North — la sección se sigue llamando "Galería de Fotos". Son seis rectángulos vacíos.

Nueve etiquetas <img> sobre seis URLs únicas. Las verifiqué una por una, primero con HEAD y luego con GET para descartar falsos positivos:

404  photo-1494487041770-7a98d0a0c51d
404  photo-1511671782779-cfe11cab67eb
404  photo-1519669556163-dea1aeec3e26
404  photo-1520523839899-80a6bb11b6fd
404  photo-1522201190528-6a4c8f8c5e5b
404  photo-1598622886178-3ba0df9d1b69

control (ID real de otro modelo):
200  photo-1511379938547-c1f69419868d  (32 KB)

Seis de seis. Cero aciertos. No falló la red: inventó los seis identificadores. Y como es el único que no puso imagen en el hero, el resultado es que la página no tiene una sola imagen. El requisito 6 no está a medias: está en cero.

EL FALLO MÁS SERIO, Y NO ES VISUAL
console.log('Form submitted:', formData);
alert('¡Gracias por tu mensaje! Te contactaremos pronto.');
this.reset();

El formulario de contacto pide nombre, email, teléfono, curso de interés y mensaje… y lo tira a la consola. Le dice al usuario "te contactaremos pronto" y borra el formulario. Es una mentira ejecutable: cada lead entra, se pierde en silencio, y la persona se queda esperando una llamada que nunca va a llegar.

Compáralo con Laguna, que bajo las mismas restricciones enrutó su formulario a wa.me. Mismo problema, una solución honesta y una que no.

Y aquí está lo incómodo: North es el tercero más lento y produjo 803 líneas de HTML que, leídas, parecen perfectamente correctas. Nada en el código delata las seis imágenes muertas ni el formulario que engaña. Solo aparecen al abrir el navegador y al hacer peticiones HTTP reales.


Los tres patrones que atraviesan todo

Lo individual es anecdótico. Lo que se repite en los seis es lo que de verdad importa.

1. Cinco de seis inventaron estadísticas de negocio

Nunca di un teléfono, ni precios, ni años de trayectoria, ni número de estudiantes. Esto es lo que apareció igual — lo conté a mano sobre los seis archivos:

  • "500+ estudiantes" — Ling, Laguna, MiMo y Big Pickle
  • "Desde 2018" — Ling, North, MiMo y Big Pickle. Laguna prefirió "desde 2014"
  • "15+ profesores", "8 años", "10+ años de experiencia"
  • Precios concretos en COP — Ling ($150.000 / $280.000 / $450.000) y North ($150.000 / $170.000 / $180.000)
  • Horarios de atención, testimonios firmados con nombre y apellido, "Recital trimestral"

La excepción, y merece crédito: DeepSeek. Es el único de los seis que no fabricó una sola cifra. Ni estudiantes, ni años, ni precios, ni profesores. Se limitó a copy que no afirma nada verificable. Lo único que se inventó fue una oferta — "clase de prueba gratuita" — que sigue siendo un compromiso que nadie autorizó, pero está a años luz de atribuirle a un negocio 500 estudiantes que no tiene.

Un punto a favor de todos, eso sí: los seis usaron el mismo teléfono, +57 300 123 4567. Es un placeholder transparente — nadie va a confundirlo con un número real. Ahí sí señalaron el hueco en vez de taparlo, que es exactamente lo que debieron hacer con el resto.

ESTE ES EL RIESGO REAL

Ninguna checklist de "cumplió/no cumplió los 6 requisitos" detecta esto. Y si un cliente publica esa página tal cual, está haciendo publicidad engañosa — que en Colombia es competencia de la SIC. Los testimonios son todavía peor: son citas atribuidas a personas con nombre y apellido que no existen.

Lo peligroso no es que el modelo se equivoque en el CSS. Es que rellene los huecos con afirmaciones falsas redactadas con total naturalidad, y que revisar eso requiera leer cada frase pensando "¿esto me lo dijeron o se lo inventó?".

2. La mitad falló la animación por el mismo motivo

Tres de seis (DeepSeek, Laguna, North) implementaron @keyframes que se disparan al cargar la página, sin IntersectionObserver. El resultado es idéntico en los tres: todo lo que está bajo el fold termina su animación antes de que el usuario llegue a esa altura.

Cumplen la letra del requisito 3 y no la intención. Si revisas el código, hay animación. Si abres la página, no la ves. Los otros tres (Big Pickle, MiMo, Ling) sí usaron IntersectionObserver, y la diferencia al navegar es enorme.

3. Todos rompieron el requisito de "colores azules" en el mismo punto

Cada modelo que puso un botón destacado de WhatsApp lo puso verde. Es incumplimiento del requisito 1 y es, casi seguro, la decisión correcta: el verde de WhatsApp es reconocimiento de marca instantáneo. Es el único caso del experimento donde desobedecer el brief mejora el resultado.


El hallazgo que no esperaba: cómo alucinan las imágenes

Cuando vi que North tenía las seis imágenes rotas, se me ocurrió cruzar todos los IDs de Unsplash de los seis modelos. Hay 30 IDs únicos en total, y el patrón que salió es limpísimo:

Tipo de ID Cantidad Rotos Tasa de fallo
Elegido por 2 o 3 modelos de forma independiente 7 0 0%
Usado por un solo modelo 23 11 48%

Los siete IDs compartidos funcionan todos. Ninguna excepción. Y casi la mitad de los que aparecen una sola vez están muertos.

El caso más elocuente son MiMo y Big Pickle, que eligieron la misma foto:

MiMo        photo-1598488035139-bdbb2231cb64   404
Big Pickle  photo-1598488035139-bdbb2231ce04   200
                         mismo prefijo ^   ^ sufijo alucinado

Ahí se ve el mecanismo: los modelos memorizan la parte estable del ID — el timestamp — y alucinan el hash final. Los IDs que varios modelos comparten son los que están genuinamente en los datos de entrenamiento: las fotos virales de Unsplash, vistas miles de veces. Los que aparecen una sola vez son, la mitad de las veces, invención pura con la forma correcta.

HEURÍSTICA PRÁCTICA

Si un modelo te da una URL de Unsplash, verifícala siempre. Y si dos modelos distintos te dan la misma, casi con seguridad es real. Es una forma barata de auto-validación: pídele las imágenes a dos modelos y quédate con la intersección.


Tabla final

# Modelo Tiempo Peso Alto Imgs OK Reveal Año Veredicto
1 Big Pickle 2m 05s 26 KB 4365px 10/11 2026 Completo y compacto
2 MiMo v2.5 1m 53s 24 KB 4875px 10/11 2026 Empate técnico
3 Ling 3.0 Flash 2m 17s 34 KB 4964px 6/7 2026 El más comercial
4 DeepSeek V4 Flash 42s 13 KB 2621px 3/4 no 2026 El minimalista real
5 Laguna S 2.1 20m 48s* 29 KB 3913px 1/2 no 2024 Fuente 404, icono Pro, foto de laptop
6 North Mini Code 4m 17s 26 KB 4814px 0/6 no 2024 Cero imágenes, formulario que miente
Nemotron 3 Ultra Streaming response failed — no entregó

Qué me llevo

Sí, los modelos gratis de opencode sirven. Tres de siete entregaron algo que un freelance podría ajustar y cobrar el mismo día. Para prototipar, para arrancar un proyecto, para tener algo que enseñarle a un cliente en dos minutos: perfectamente utilizables.

Pero el experimento me dejó tres cosas más útiles que el ranking:

Uno: velocidad y calidad no correlacionan. El más rápido (DeepSeek, 42s) quedó cuarto. El segundo más lento (North, 4m17s) quedó último. Y el que más tiempo me costó (Laguna, 20 minutos) fue el penúltimo. Esperar más no compra nada.

Dos: revisar el código no basta. Este es el aprendizaje que me llevo de verdad. Las seis imágenes muertas de North, la fuente 404 de Laguna, su icono Pro inexistente y el formulario que le miente al usuario: ninguno de esos fallos se ve leyendo el HTML. Todos tienen sintaxis impecable. Aparecen al renderizar y al hacer peticiones HTTP. Si tu proceso de validación termina en "leí el diff y se ve bien", vas a publicar páginas rotas.

Tres: la alucinación de datos es el problema serio. Cinco de seis inventaron cifras de negocio con total naturalidad. Un enlace roto lo ves; un "500+ estudiantes satisfechos" falso pasa a producción sin que nadie parpadee. Y a diferencia del CSS, ese error tiene consecuencias legales para tu cliente. Que DeepSeek —el modelo más rápido y más simple— fuera el único que se abstuvo sugiere que no es una limitación técnica, sino una decisión de entrenamiento.

Última nota, y es la que más me hace pensar: todo esto se arregla con andamiaje. Un skill que obligue a verificar URLs. Un MCP que consulte la API real de Unsplash. Una instrucción que prohíba inventar datos no proporcionados. Un paso de spec-driven que fije el inventario de secciones antes de escribir una línea.

Nada de eso estaba aquí, y ese era el punto. Esta prueba mide el piso. La conclusión es que el piso de los modelos gratuitos está sorprendentemente alto en maquetación y sorprendentemente bajo en veracidad — y que la diferencia entre un resultado usable y uno peligroso no la pone el modelo. La pones tú, con lo que le montas encima.

~$ cd ..