Your Game Is Not Ugly, It Is Unfinished
Stop Shipping Ugly "Vibe-Coded" Games! (7 Polish Layers Explained)
By RUN.team · September 1, 2026
The seven layers that take a vibe coded game from raw to polished
You know the look. Sky blue background, pure green ground, a red box gliding between gray boulders, Arial text in a purple rounded rectangle. You have seen it a hundred times on your feed, and if you have ever asked an AI to "make a 3D game in the browser," you have probably shipped it.
There is a reason every vibe coded game looks like that, and it is not that the models are bad at games. Every code-generating model learned from the same starter tutorials, the same default examples, the same template projects. When your prompt does not specify an art direction, the model falls back to the statistical average of everything it has read, and the statistical average is sky blue and purple gradients. The fix is not a better model. The fix is knowing what to ask for.
To prove it, we built the same game twice. Same engine, same mechanics, same afternoon. The left side of every demo below is what default prompting produces. The right side adds one layer at a time, seven in total, until the same red-box flyer becomes a dusk world with a ringed planet, a winding canyon road, and a ship that barrel-rolls through its own engine wake. The left side never changes. Watch what each layer does.
Every layer below ends with two things: the 2D version, because all of this applies to Phaser and Canvas games just as much as Three.js, and a performance warning, because some polish is free and some will melt a phone.
Layer 1: Art direction, write it down before you prompt
The single highest-leverage thing you can do costs nothing: pick a palette before you build, write it down, and never use a color outside it.
Ask your model to define the palette at the top of the project and make it a law: every color in the game comes from that list and nowhere else.
One dominant hue family, one accent color, and the accent has to be earned. In our demo the rust red appears only on the ship's markings and the enemy ring. The teal appears only where energy lives: engine flames, bullets, drone cores. That discipline is what makes a scene read as one universe instead of a pile of assets.
The same rule extends to generated art. We made the hero ship by prompting one concept image in the locked palette, then feeding it to an image-to-3D model. Twenty minutes later the drones, rocks, and crystals came from the same session with the same style words, which is exactly why they all look like they belong together. This is the workflow the RUN team uses too. In a recent Run Game Helpers session the developer dropped all of his art into the project before the first prompt, and called out the alternative: leave the visuals to the model and you get, in his words, rounded rectangles in the default purpley colors.
Color is only half of the decision. The other half is shape language. Do you want your walls made of spiky, dangerous shapes or round, friendly ones? Decide, write it down, and tell the model. Palette plus shape family is the whole art direction, and once both are law, everything you generate belongs to the same world.
For 2D: identical. Sites like Lospec have thousands of ready palettes, and you can quantize any AI-generated sprite down to your chosen colors so mismatched assets snap into the same world.
Performance cost: zero. This layer is free forever.
Layer 2: Pipeline, how your engine turns math into visuals
AI starter code ships flat and blurry, and the fixes are almost insultingly small. Ask for them by name: ACES tone mapping, a pixel ratio clamped to two, and antialiasing. Your model knows exactly what each one means.
Tone mapping is the difference between plastic and cinematic. The pixel ratio line is the difference between crisp and mysteriously blurry on every phone and retina display, and models leave it out constantly. In Canvas 2D the same fix is sizing your buffer at CSS size times devicePixelRatio and scaling the context.
Then fix the light. Ambient-only lighting, which is what generated code usually ships, multiplies every face by the same color: that is why everything looks flat. The ask: replace the ambient light with a warm key light and a cool sky fill.
Two traps we hit ourselves while building the demo, so you do not have to: standard materials with metalness above 0.1 render black if there is no environment map, including materials inside loaded GLB files, and canvas textures you paint yourself need texture.colorSpace = THREE.SRGBColorSpace or the colors wash out. Both bugs look like mysteries and both are one line.
Finish with a little post-processing, and a little goes a long way: one bloom pass, bonus points for a vignette. The vignette does not even need a shader: a CSS radial-gradient overlay div is free and looks the same.
Performance warning: pixel ratio 3 renders nine times the fragments of ratio 1, so clamp at 2. Every post-processing pass is a full-screen render target; on mobile, stop at bloom.
Layer 3: Grounding, make the world feel like a place
Objects floating on a flat color plane are the fastest tech-demo tell there is. Grounding is a stack of cheap tricks that painters have used for centuries.
Blob shadows first: a soft dark ellipse under every character and prop, scaled and faded with height. It is one radial-gradient texture and it glues everything to the floor. Real shadow maps are the expensive version; a single point light casting shadows renders your whole scene six times. The blob costs nothing and reads almost as well.
Then aerial perspective. Fog matched to your horizon color, a gradient sky instead of a flat one, and distant silhouette ridges hand-tinted toward the sky so far means lighter and hazier. Add a planet, a star field, a few drifting clouds if your world wants them; each is minutes of work and together they give the sky the depth a flat color never will.
And here is the part nobody puts in these lists: level design is polish too. A dead-straight corridor of randomly scattered rocks reads as generated. Give the path a curve, layered sine waves are enough, and place your props relative to the path so boulders hug the corners. Suddenly the world looks designed, the camera sways, parallax works, and the same twenty rocks feel intentional. That is when a level stops being a corridor and becomes a world you can spend time in.
For 2D: blob shadow ellipses under sprites, two or three parallax layers, gradient sky, far layers desaturated toward the sky color.
Performance warning: fog, gradients, and blob shadows are near free. Real-time shadows are the thing to fear on mobile.
Layer 4: Juice, make the screen feel physical
Masahiro Sakurai has spent an entire video series making one point: game feel comes from presentation, not from input. The same tap can feel dead or electric depending on what the screen does in the next tenth of a second. The famous talks on this, Vlambeer's The Art of Screenshake and Jonasson and Purho's Juice It or Lose It, are both twenty minutes and both worth your time. The short version, in the order you should ask your model for it:
Hitstop. Freeze the game for 3 to 6 frames on light hits, up to 20 on kills, by multiplying your delta time by a timeScale you can zero. While frozen, flash the victim white and jitter its rendered position only, never its hitbox. The freeze exists so the flash can be read.
Camera kick. One directional nudge along the impact vector, two or three frames out, eased back, beats random shaking every time. If you do shake, keep it under 200 milliseconds.
Easing everywhere. Nothing in nature moves linearly. Ease out for movement, overshoot for pops, bounce for landings, and squash and stretch on anything that lands or gets hit.
None of this costs a single millisecond of GPU time. It is the highest ratio of feel to effort in all of game development.
Then spend your budget where it shows: propulsion. Our ship's engine flames are tube meshes with a dissolve shader, a noise threshold that rises with age so the flame erodes into embers instead of fading like a ghost. The flames exit straight and stiff, only the cooled tail bends, and every eleven seconds the ship charges up, fires an ignition burst, and barrel-rolls through a warp with streak lines flying past the camera and a field-of-view surge. That entire sequence follows a three-act rule you can reuse for any big moment: anticipation, climax, dissipation.
For 2D: every timing above transfers directly, and Phaser has camera shake, flash, and zoom built in.
Performance warning: juice is free until particles enter the picture. Overdraw from stacked transparent sprites is the number one mobile framerate killer, so fewer, smaller, shorter-lived.
Layer 5: Rhythm, effects that play in sequence
Ask a model for an explosion and you get twenty identical orange blobs fading out linearly over a second and a half, all at the same time. That is a single loud note. A good effect is a phrase: it plays in sequence, and the sequence is what your eye reads as quality.
A good explosion is five layers, each starting on its own beat, and the brightest one dies first: a white flash for one to three frames, radial spikes for around 140 milliseconds, sparks in mixed sizes that hold and then erode over about 400, one expanding ring, and dark smoke that lingers last at low opacity where it never steals focus. Total particle count: maybe twenty five. Diablo III ships effects with seven to twelve live particles. Richness comes from layering and timing, not from count.
Two rules do most of the work. Mixed sizes: one big element, several medium, many tiny specks, because uniform particle sizes are the single most recognizable amateur tell. And value discipline: white-hot core, one hue, dark accents baked in so the effect reads against a bright sky as well as a dark one.
Scale the whole thing to the value of the moment. A pickup gets a small pop. A kill gets the full stack. A boss gets slow motion and a cascade that arrives in waves. When everything is celebrated equally, nothing is.
For 2D: the same five beats as sprite layers, straight out of a Phaser or Pixi emitter.
Performance warning: it is overdraw that kills, not count. Shrink and separate particles before you delete them, and prefer additive blending, which is cheaper and needs no sorting.
Layer 6: UI presentation, the half of the screen you forgot
Half of every screenshot is interface, and default AI interface is Arial in purple boxes parked wherever the model felt like it. The fix list is short:
One display font and one clean sans from Google Fonts. Tabular numerals for anything that counts. An 8 pixel spacing grid. Everything anchored to the edges, because the center of the screen belongs to the game; any banner that must cross it lives for less than 1.2 seconds. Every piece of text over gameplay carries a subtle shadow so it survives a bright sky.
Then make the data feel alive. Scores should count up with easing and pop when they change. Rewards should fly from the kill to the counter, and the counter should tick when they land, so every effect terminates at the ledger that changed. Damage is an edge vignette with a transparent center, never a full-screen red slab. And gauges beat bars: our hull indicator is a radial arc with a tick track, a gradient stroke, a glow, and a dot riding the arc's tip, and it shifts color as you get closer to danger. Same data as a rectangle, ten times the instrument.
This is the one layer that is literally identical in 2D and 3D, because your HUD is DOM either way.
Performance warning: backdrop-filter is a real GPU cost on phones, and drawing text into a canvas every frame is slow, so cache it.
Layer 7: Eyes, give your model yours
Here is the meta-problem behind every ugly vibe coded game: the model cannot see what it renders. Your tests pass, the build runs, the model reports success, and the game is blurry, z-fighting, and wearing a HUD that says WAVE undefined. Nobody looked, so nothing caught it.
You are the eyes. The habit that separates shipped-looking games from demos is a screenshot loop: change, look, direct, repeat. Direct like an art director, not a programmer. "Reduce the bloom about 20 percent." "The trail does not start at the nozzle." "The mountains show their bottom edge." Those sentences fix more visual bugs than any prompt engineering.
When eyeballing is not precise enough, calibrate. While building our demo, the engine flame position was wrong twice in a row from guessing, so we added three sliders behind a hidden dev flag, tuned the emitters by eye in thirty seconds, and baked the numbers back into code. Expose the tunable, tune it visually, commit the value. Models are excellent at adding dev panels; use that.
And test on a real phone early. The median player is not on your machine. RUN makes this one genuinely easy: deploy privately, open it on your device, and nobody sees it but you.
Give your model the whole playbook
Everything above works as prompts you type one at a time. It works better as a spec your model reads every session, because a spec is a durable creative brief and a one-shot prompt is a suggestion.
So we wrote the spec for you. The Vibe Polish spec is a single model-facing file with all seven layers, the exact one-liners, the frame counts, the five-beat explosion recipe, the 2D equivalents, and every performance warning, ready to drop into your repo. There is also a Claude Code skill and a Cursor rule if you want it wired in automatically.
>>GRAB THE ZIP FILE<<
Grab it, point your model at your game, and ask it to apply the layers in order. Then look at the screen and tell it what you see. And tell me which layer you had been forgetting, and send screenshots when you apply them. I want to see your games. Go make something beautiful.
Built and tested on RUN. https://run.world