
#003 - Vibe-coding doesn't work for visual canon
Constraint isn't a creative limitation. Constraint preserves creative choices you've already made.
Vibe-coding doesn't work for visual canon
HyperKourier devlog, May 17, 2026
Vibe-coding goes like this. With modern AI tools, you don't need to over-spec. Braindump the brief with Wispr Flow, prompt the model, iterate on what comes back, and the AI fills the gap between intent and output. It's basically become the de facto new productivity story for solo founders and it's the dominant pitch right now.
But when you're dealing with such a complex, multilayered, multi-faceted project like a video game, which is not just about coding in the backend parts and nuts and bolts of the engine and all that, it's also a lot about the visuals and the consistency across the world... then it doesn't work. AI doesn't fill the gap between vision and output. It widens it. The only thing keeping your project's identity from being silently re-eroded with every generation is encoding your vision with the kind of rigor you'd normally reserve for production code. The more AI you put in your content pipeline, the more spec you need. Not less.
I spent the weekend writing thousands of lines of structured Markdown instead of generating concept art. This is the argument for it.
The drift problem
Every AI image generation is a fresh re-interpretation by a model with no idea what your project is. For one asset, fine. The model produces something, you iterate, you ship. The moment you need consistency across hundreds of assets, characters, environments, UI, event overlays, all reading like they belong to the same world, the model becomes the antagonist.
The HyperKourier failure modes are concrete. Early generations of Fatih, one of the playable Kouriers, kept coming back with spiky anime hair. He has curly hair. The KottiExpress logo on his jacket kept rendering as red-and-black cyberpunk. The canonical brand is yellow-brick DHL-coded fleet logistics. Das Auge, N9's signature landmark in the heart of the city, kept getting confused with the Berlin Fernsehturm (the iconic tv tower in the middle of the city). Wrong silhouette, wrong cultural reference, wrong era. The hoverboard the courier rides kept turning into a motorbike or a flat skateboard.
These aren't model failures. They're my failures. The model has the prompt and whatever references I attach. A prompt that says "courier on a hoverboard in a Berlin-coded near-future city" gives the model every right to make assumptions. The assumptions are whatever shows up most often in training data. Berlin-coded city defaults to Fernsehturm. Cyberpunk courier defaults to motorbike. Tough young male defaults to spiky hair. None of that is wrong in the model's frame. It's wrong for this project.
You can fix any single instance with a more specific prompt. The problem is the next session, after you've forgotten which negations you used. The corrections drift, and three generations later the visual identity is silently eroded.
This is the worst kind of error because it's silent and compounds. By the time you notice the drift, you've already generated forty assets in the drifted style and they're easier to keep using than to redo. The drift becomes the canon. Your project becomes whatever the model defaults to, which is nothing in particular.
Vibe-coding produces this outcome by design. The pitch is "don't over-spec, let the AI infer." What the AI infers, absent specification, is the mean of its training data. The mean is not your project.
Why this fails specifically for visual work
Vibe-coding works for code because code has a forcing function. It compiles and runs, or it doesn't. A vibe-coded React component that's wrong gives you a blank screen or an error log. The output validates itself.
Visual canon has no forcing function. A render of Fatih with spiky hair looks like a character. It's not broken. The model can't detect it as wrong. It just isn't Fatih. If you don't have canonical Fatih on hand to compare against, you might not even notice.
This is the failure mode that destroys projects. Code that doesn't run is a known unknown. Visual drift is an unknown unknown (dat Donald Rumsfeld reference). The AI gives you confident output, you give it confident feedback, and the project's identity quietly shifts toward whatever was most common in the training data.
What encoding constraint actually looks like
I wrote a forty-thousand-word document called the HyperKourier Style Playbook, now currently in its v1.3, and most likely will continue to evolve by the time the project actually launches.
Palette. Line weight. Polycount budgets. Character proportions. District color zoning. The four-register UI model that separates world from characters from diegetic UI* from non-diegetic player overlays. Platform voice register. It's not aspirational. It's enforceable. Every rule has a failure mode it's preventing and a reference image it's anchored to.

*(Diegetic UI exists within the game world and is visible to the characters themselves (like the health spine on Isaac’s suit in Dead Space), while non-diegetic UI is a screen overlay only the player sees and has no presence in the game world, like a health bar or minimap in the corner of the screen.)
Yesterday I built five /command skills that encode pieces of this playbook automatically. /hyperkourier-world enforces hard-cel discipline, painterly skybox, hoverboard not motorbike, Das Auge not Fernsehturm. /hyperkourier-character encodes the four canonical characters with their non-negotiable identifiers, Fatih's curly hair included as an explicit corrective. /hyperkourier-ui-diegetic enforces the CivicLoop OS visual language: sterile-corporate sharp-cornered panels, no graffiti on platform surfaces, KottiExpress yellow-brick not red-and-black.
A few hundred kilobytes of structured Markdown across fifteen files. That's a lot of writing for what amounts to a frame around prompts I was already writing. The writing isn't optional. The writing is the only thing standing between "the project has a visual identity" and "the project is whatever the model defaulted to last session."
This is the opposite of vibe-coding
Vibe-coding says under-specify, iterate on output, trust the AI to close the gap. The discipline I'm describing says
- over-specify
- enforce constraints at prompt-construction time
- never trust the AI to close any gap that matters
Constraint isn't a creative limitation. Constraint preserves creative choices you've already made. Once I decided Fatih has curly hair, that's not a creative parameter anymore. It's a constraint. Once I decided R3 is sterile-corporate CivicLoop OS and R4 is graffiti-pop event reveals, register separation isn't a creative parameter. It's a constraint. Skills enforce constraints. The creative work happened before the constraints existed.
This separation is what most "AI-assisted solo dev" discourse misses. AI doesn't help you make creative decisions. AI is mediocre at creative decisions because AI averages. AI helps you propagate creative decisions, at speed, across many assets, once those decisions exist. The encoding is the bottleneck.
You can't vibe-code the encoding. The encoding is rigorous by nature. Lists of failure modes, color hex codes, polygon budgets, prompt-template fillers, reference attachment protocols. It looks more like documentation than like prompts.
It probably looks boring from the outside. It isn't boring to do. Every constraint encoded is a fight you don't have to fight again with the next generation. Every fight you don't have to fight is creative energy preserved for the next real decision.
The actual leverage point
The thing I underestimated until I built the skills and started using them. Skills matter less than the asset library they reveal you need.
When /hyperkourier-world generates a Kotti scene, it doesn't just enforce hard-cel discipline through prose. It attaches the canonical KottiExpress logo as a Higgsfield medias reference. It attaches Fatih's canonical character render. It attaches the Holocom turnaround. When the references exist, the generation lands canonically. When they don't, the skill prose-falls-back and logs a warning. The output is approximate, not locked.

The asset library is the actual canon. The skills are how the canon gets injected into generations. The playbook is how the canon was authored. Three load-bearing layers, none replacing the others.
Starting over, I'd populate the asset library before building the skills. The asset library is the slow load-bearing work. The skills are the fast frame-only work. I did them in the wrong order. If you're earlier in your project than I am, flip the sequence.
The takeaway
If you're shipping anything that needs visual consistency across many AI-generated assets (a game, a brand identity, an animated series, a product line), your AI tools won't save you from constraint work. They make constraint work more critical, not less. The faster you can generate, the faster you can silently drift. The volume of output AI gives you is a multiplier on whatever discipline you bring. Zero discipline gives you zero output that's identifiably yours.
The discipline isn't doing your taste for you. The discipline is documenting your taste in machine-readable form so the taste you've already exercised doesn't have to be re-exercised in every prompt. The skills are the medium. The taste is yours.
That's the work. It's slower than vibe-coding. It's the only thing that doesn't drift.
The launch trailer drops... soon. TBD. The asset library is half-populated. Two skills are calibration-validated. Three are pending install. I'm writing this post at 1am after a four-hour skill-building sprint, heavily sleep deprived, because the post is part of the same work as the skills. Both are exercises in making invisible discipline visible, so it stops being invisible to me, to you, and to the agents we work with.
If you're shipping anything visual with AI in the pipeline, this is the discipline. Don't let anyone tell you the AI fills the gap. The AI IS the gap.