7 free opencode models, one prompt: what each one actually shipped
opencode ships a batch of free models and the obvious question is which ones are worth using. I couldn't find a comparison that convinced me, so I ran my own: one prompt, seven models, zero help. What follows is the log of that morning.
Spoiler on the result I didn't see coming: the worst failure wasn't design or code. It was something no code review would have caught, and I needed HTTP requests to find it.
The rules: everything vanilla
This matters, because it defines what the experiment measures and what it doesn't. The test was deliberately raw:
- No skills. No instructions loaded.
- No MCPs. No context servers connected.
- No spec-driven development. No upfront spec document, no plan, no phases.
- No agentic techniques. No forced chain-of-thought, no self-critique, no iteration, no "review your work".
- A single turn. I pasted the prompt, waited, and whatever came out is what I graded. No corrections, no second chances.
This does not measure each model's ceiling. Decent agentic scaffolding would have fixed half the problems I found. What it measures is the floor: what the model hands you when you ask the way you'd ask a colleague, no ceremony. And when you're deciding which free model is worth your time, the floor is exactly what you want to know.
The prompt, verbatim
(original in Spanish) Build a landing page to promote a music school in Soacha, Cundinamarca called Javastudios. It must meet the following requirements:
- Use blue colors
- Have a very attractive minimalist design
- Have at least a subtle animation
- Have a call to action that leads to whatsapp
- Have navigation and footer
- Have images from Unsplash
Six verifiable requirements, a real local business, specific enough that the model can't coast on autopilot. No further context: no phone number, no pricing, no years in business, no course catalog. Hold on to that detail — it ends up being the heart of this article.
The contenders
| Model | Time | Run notes |
|---|---|---|
| DeepSeek V4 Flash | 42s | No friction |
| MiMo v2.5 | 1m 53s |
With default it couldn't find the provider;
needed variant: medium
|
| Big Pickle | 2m 05s | Wrote into its own subfolder |
| Ling 3.0 Flash | 2m 17s | No friction |
| North Mini Code | 4m 17s | No friction |
| Laguna S 2.1 | 20m 48s* | *Almost entirely rate-limit waits |
| Nemotron 3 Ultra | — |
Streaming response failed on every attempt
|
Let's start with the one that never made it to the track.
Nemotron 3 Ultra: announced it, never delivered
The only "Ultra" in the batch and the only one that produced not
a single line. The pattern repeated identically every attempt:
it processed the prompt, announced it was going to create
index.html… and died with
Streaming response failed. It never wrote the file.
That's not a judgment on the model's capability — it's a judgment on its availability, which for anyone trying to get work done is the same thing. A model that doesn't respond has zero quality, regardless of what it might have been able to do. It's out of the comparison by no-show.
How I graded the six that did deliver
Beyond opening them in a browser and looking at them the way a client would, I did three things that turned out to separate the wheat from the chaff:
-
Full-page headless rendering with Firefox,
disabling
loading="lazy"and forcing reveals, so the screenshot shows the real page and not a half-loaded one. - HTTP verification of every external resource: every Unsplash URL, every CDN, every stylesheet.
- Reading the JavaScript, not just the HTML. That's where the worst surprises were hiding.
Model by model
My winner, for one concrete reason: it's the only one that managed to be complete without giving up on minimalism. 4365px tall against MiMo's 4875 and Ling's 4964, with the same number of sections and images. When two of the six requirements pull in opposite directions — "minimalist" versus "navigation, footer, images" — it negotiated best.
It's also the only one with actual
design personality: an organic curve on the
hero transition, hover overlays on the gallery, and a
@keyframes pulse-wa that gently pulses the
WhatsApp button. The others exhaust their repertoire on
fadeUp and float.
And the sharpest localization of the six. It doesn't say "percussion classes": it says "drums, cajón, Latin percussion and Colombian rhythms". It doesn't say "music production": it says "FL Studio, Ableton, mixing and mastering". That's not filling in a template.
What I hold against it: eight
href="#" links and a "Blog" link in the footer
pointing at a section that doesn't exist. Navigation that
promises and doesn't deliver.
A technical tie with Big Pickle on every hard metric. Its edge: it's the only one with a full-bleed photographic hero, with a blue gradient overlay. The others either put the photo beside the text or skipped it entirely. That's the difference between looking like a landing page and looking like a markup exercise.
And it's the only one besides Big Pickle that squared every grid: 6 courses in an exact 3×2, 6 photos in an exact 3×2, 3 testimonials in a row. Zero orphaned cards. Ling and Laguna left danglers in two sections each. Picking numbers that close is design judgment, not luck.
A detail I liked: it used
hola@javastudios.co, with the Colombian TLD.
Nobody asked it to.
Reproducibility note: with the default
config opencode couldn't find the provider. It needed
variant: medium. That's plumbing, not the
model, but if you rerun this experiment you'll hit it.
The longest of the batch, and the one that best understood this is a business landing page, not a CSS exercise. It's the only one that built a pricing table — $150,000 / $280,000 / $450,000 COP per month, entirely plausible figures for Soacha — and the one that wrote testimonials with Colombian names. The most deliberate localization after Big Pickle.
Technically it did the animation right:
IntersectionObserver with
threshold: 0.15 and a staggered
transitionDelay generated in JS. It gave me
trouble to capture: my screenshot came out with three empty
sections until I forced the reveal by hand.
Bad luck with the broken image: of its seven, the single 404 landed on the first course card — the first thing a visitor looks at after the hero.
And an interesting act of disobedience: the floating WhatsApp button is green, on a palette the prompt asked to be blue. Commercially it's the right call: green is instant brand recognition. Against the brief, it's non-compliance. I'd sign off on it, but it deserves to be named.
Fastest by a ridiculous margin: 42 seconds,
when second place took almost three times longer. And the
only one that read "minimalist" literally: 4 sections, 13
KB, 2621px tall. Half of anyone else. Zero JavaScript
dependencies — the hamburger menu is a one-line inline
onclick.
It has the sharpest conversion detail of the six: the
official WhatsApp SVG inlined and, above all, a
pre-filled message in the link
(wa.me/...?text=Hola%20Javastudios...). Nobody
else did it. That's thinking about the person who will click,
not about the checklist.
Its failure, and it's instructive: the
animation technically exists but is invisible. The
.fade-up classes fire
on page load, with
:nth-child delays. No
IntersectionObserver, no scroll trigger.
Everything below the fold finishes animating before you ever
scroll to it.
Worse: since .fade-up starts at
opacity: 0, my first screenshot came out with
the <h1>, the paragraph and the CTA
invisible — the shot landed mid-animation.
For nearly a second the hero is blank. That's a direct hit
to LCP.
Its great virtue, which I didn't spot until the end: it's the only one of the six that invented no business figures at all. No "500+ students", no "since 2018", no pricing. I'll come back to this, because it turned out to matter more than everything else.
Sloppiness: it declares
@keyframes fadeIn and never uses it. Its own
hero copy promises "voice and more" but there are only three
courses. And the hamburger is a
<div onclick> with no role,
no tabindex, no aria-expanded: on
mobile, a keyboard or screen-reader user
cannot open the menu.
Three verifiable bugs here, and one of them is the kind you don't catch by reading code.
Bug 1 — the typeface never loads.
https://fonts.googleapis.com/css2=Inter:wght@300;400;500;600;700&display=swap
^ missing ?family
That URL returns 404; the corrected one returns 200. I checked. Inter never loads and the whole page falls back to the system sans-serif. The model designed with one typeface and shipped another — and that single missing character explains a good chunk of why it looks cheap.
Bug 2 — it used an icon that doesn't exist.
<i class="fas fa-piano">. It loads Font
Awesome Free 6.5.0 from cdnjs, but
fa-piano is a Pro icon. That's why the
"Piano Classes" card shows an empty blue square while
guitar, voice and drums render fine. It picked 13 correct
icons and failed on the one it didn't verify.
Bug 3 — the worst one. It placed two images on the entire page. The hero one is a 404: the first thing a visitor sees is a grey box with the alt text "Music student playing piano". And the only one that does load is a photo of two hands pointing at a laptop, on a music school landing page. It's not broken: it's wrong. Net result: zero usable images.
Where I was wrong, and credit where it's due:
I assumed its contact form was a dead form with no backend.
It isn't. It calls e.preventDefault(), builds
the message and opens wa.me with the encoded
text. It turns a form into a WhatsApp channel with no
server. It's the most elegant solution to requirement 4 in
the whole batch.
Oh, and the footer says © 2024. Two years
behind, when DeepSeek got 2026 right unprompted.
Nine <img> tags over six unique URLs. I
checked each one, first with HEAD and then with
GET to rule out false positives:
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 (real ID from another model):
200 photo-1511379938547-c1f69419868d (32 KB)
Six out of six. Zero hits. The network didn't fail: it invented all six identifiers. And since it's the only model that put no image in the hero, the result is that the page has not a single image on it. Requirement 6 isn't half-met: it's at zero.
console.log('Form submitted:', formData);
alert('¡Gracias por tu mensaje! Te contactaremos pronto.');
this.reset();
The contact form asks for name, email, phone, course of interest and message… and dumps it to the console. It tells the user "we'll contact you soon" and clears the form. It's an executable lie: every lead comes in, vanishes silently, and the person waits for a call that will never come.
Compare that with Laguna, which under the same constraints
routed its form to wa.me. Same problem, one
honest solution and one that isn't.
And here's the uncomfortable part: North is the third slowest and produced 803 lines of HTML that, read on the page, look perfectly correct. Nothing in the code betrays the six dead images or the lying form. They only surface when you open a browser and make real HTTP requests.
The three patterns that run through everything
Individual results are anecdotes. What repeats across all six is what actually matters.
1. Five of six invented business statistics
I never gave a phone number, pricing, years in business or student count. Here's what showed up anyway — counted by hand across all six files:
- "500+ students" — Ling, Laguna, MiMo and Big Pickle
- "Since 2018" — Ling, North, MiMo and Big Pickle. Laguna went with "since 2014"
- "15+ teachers", "8 years", "10+ years of experience"
- Concrete COP pricing — Ling ($150,000 / $280,000 / $450,000) and North ($150,000 / $170,000 / $180,000)
- Opening hours, testimonials signed with full names, "quarterly recital"
The exception, and it deserves credit: DeepSeek. It's the only one of the six that fabricated not a single figure. No students, no years, no pricing, no teachers. It stuck to copy that asserts nothing verifiable. The only thing it made up was an offer — "free trial class" — which is still a commitment nobody authorized, but it's light years away from crediting a business with 500 students it doesn't have.
One point in everyone's favor, though: all six used the same
phone number, +57 300 123 4567. That's a
transparent placeholder — nobody's mistaking it for a real
number. There they flagged the gap instead of papering over it,
which is exactly what they should have done with the rest.
No "met/didn't meet the 6 requirements" checklist catches this. And if a client publishes that page as-is, they're running false advertising — which in Colombia falls under the SIC. The testimonials are worse still: they're quotes attributed to named people who don't exist.
The dangerous part isn't the model getting CSS wrong. It's that it fills the gaps with false claims written with total confidence, and that reviewing for it means reading every sentence asking "was I told this, or did it make it up?"
2. Half of them failed the animation for the same reason
Three of six (DeepSeek, Laguna, North) implemented
@keyframes that fire on page load, with no
IntersectionObserver. The result is identical in
all three: everything below the fold finishes animating before
the user scrolls that far.
They satisfy the letter of requirement 3 and not its
intent. Review the code and there's animation. Open the
page and you never see it. The other three (Big Pickle, MiMo,
Ling) did use IntersectionObserver, and the
difference while scrolling is enormous.
3. Every one broke the "blue colors" requirement at the same spot
Every model that added a prominent WhatsApp button made it green. It breaks requirement 1 and it's almost certainly the right call: WhatsApp green is instant brand recognition. It's the one case in this experiment where disobeying the brief improves the outcome.
The finding I didn't expect: how images get hallucinated
Once I saw North had all six images broken, I cross-referenced every Unsplash ID across all six models. There are 30 unique IDs total, and the pattern is remarkably clean:
| Kind of ID | Count | Broken | Failure rate |
|---|---|---|---|
| Picked independently by 2 or 3 models | 7 | 0 | 0% |
| Used by a single model | 23 | 11 | 48% |
All seven shared IDs work. No exceptions. And nearly half of the ones that appear only once are dead.
The most telling case is MiMo and Big Pickle, which picked the same photo:
MiMo photo-1598488035139-bdbb2231cb64 404
Big Pickle photo-1598488035139-bdbb2231ce04 200
same prefix ^ ^ hallucinated suffix
That exposes the mechanism: models memorize the stable part of the ID — the timestamp — and hallucinate the trailing hash. The IDs several models share are the ones genuinely in the training data: the viral Unsplash photos, seen thousands of times. The ones that appear only once are, half the time, pure invention with the right shape.
If a model hands you an Unsplash URL, always verify it. And if two different models hand you the same one, it's almost certainly real. It's a cheap form of self-validation: ask two models for images and keep the intersection.
Final table
| # | Model | Time | Size | Height | Imgs OK | Reveal | Year | Verdict |
|---|---|---|---|---|---|---|---|---|
| 1 | Big Pickle | 2m 05s | 26 KB | 4365px | 10/11 | yes | 2026 | Complete and compact |
| 2 | MiMo v2.5 | 1m 53s | 24 KB | 4875px | 10/11 | yes | 2026 | Technical tie |
| 3 | Ling 3.0 Flash | 2m 17s | 34 KB | 4964px | 6/7 | yes | 2026 | Most commercial |
| 4 | DeepSeek V4 Flash | 42s | 13 KB | 2621px | 3/4 | no | 2026 | The real minimalist |
| 5 | Laguna S 2.1 | 20m 48s* | 29 KB | 3913px | 1/2 | no | 2024 | 404 font, Pro icon, laptop photo |
| 6 | North Mini Code | 4m 17s | 26 KB | 4814px | 0/6 | no | 2024 | Zero images, a form that lies |
| — | Nemotron 3 Ultra | Streaming response failed — did not deliver | ||||||
What I take away
Yes, opencode's free models are usable. Three of seven shipped something a freelancer could adjust and invoice the same day. For prototyping, for kicking off a project, for having something to show a client in two minutes: perfectly serviceable.
But the experiment left me three things more useful than the ranking:
One: speed and quality don't correlate. The fastest (DeepSeek, 42s) came fourth. The second slowest (North, 4m17s) came last. And the one that cost me the most time (Laguna, 20 minutes) came second to last. Waiting longer buys you nothing.
Two: reviewing the code isn't enough. This is the lesson I actually walk away with. North's six dead images, Laguna's 404 font, its nonexistent Pro icon and the form that lies to the user: none of those failures are visible in the HTML. All of them have impeccable syntax. They appear on render and on HTTP requests. If your validation process ends at "I read the diff and it looks fine", you're going to ship broken pages.
Three: data hallucination is the serious problem. Five of six invented business figures with total confidence. A broken link you can see; a fake "500+ satisfied students" ships to production without anyone blinking. And unlike CSS, that mistake has legal consequences for your client. That DeepSeek — the fastest and simplest model — was the only one to abstain suggests this isn't a technical limitation but a training decision.
One last note, and it's the one that gives me the most pause: all of this is fixable with scaffolding. A skill that forces URL verification. An MCP that queries the real Unsplash API. An instruction that forbids inventing data that wasn't provided. A spec-driven step that locks the section inventory before a line gets written.
None of that was here, and that was the point. This test measures the floor. The conclusion is that the floor of free models is surprisingly high on markup and surprisingly low on truthfulness — and that the difference between a usable result and a dangerous one isn't set by the model. You set it, with what you build around it.