AgentGames

Search titles, descriptions, models and tags. Press Enter to see results.

👾 Guide

How to make a pixel art game with AI

Pixel art drawn at browser resolution is not pixel art. It is small blurry art. Four settings decide which of the two you end up with.

Updated 5 October 2026 8 min read By the Agent Games team
Jump to a section
  1. Four steps to pixels that stay sharp
  2. Why pixel art comes out blurry
  3. Scale by three, not by 2.4
  4. A palette of twelve beats a palette of millions
  5. Why your sprite shimmers as it walks
  6. Common questions
  7. Where to go next

Pixel art is a resolution decision before it is a drawing style. Ask for a game that renders onto a canvas of 320 by 180 and is then blown up by a whole number. Ask for the same sprites at browser resolution and you get small blurry art, which is a different and much worse thing.

Two canvases, and one of them is tiny

The canvas you draw on is small and never changes size. The canvas the player sees is that one multiplied by 3, 4 or 5. Every fault in this article comes from confusing the two, or from letting the multiplier go fractional.

Four steps to pixels that stay sharp#

Fix the resolution in the first line you write

Name 320 by 180 before you name the game. Retrofitting it later means touching every draw call in the file.

Blow it up and stare at one sprite

A single art pixel should be a clean square block. If its edge is a grey halo, smoothing is still on somewhere.

Choose the palette, then refuse to add to it

Twelve colours is plenty. The model will offer you a gradient at some point. A gradient has no palette, so say no.

Build the game last

Rooms, enemies and sound are ordinary work. The look is the part that goes wrong quietly and stays wrong.

PromptCopy this, paste it, send it
Build a pixel art game as ONE self-contained .html file. No frameworks
and no image files. Every sprite is filled rectangles drawn in code.

RESOLUTION: keep a second canvas in memory, exactly 320 wide and 180
high, and draw the entire game onto it. The visible canvas only ever
draws that buffer, scaled up.

SCALING: find the largest WHOLE number that still fits the window, with
a floor of 1. Size the visible canvas to 320 and 180 times it. Never a
fractional scale. Centre it and leave the leftover space black.

CRISPNESS: set imageSmoothingEnabled to false on the visible context
after every resize, because changing a canvas size resets it. Add
image-rendering: pixelated to the canvas in the CSS, and also
canvas { touch-action: none; }

PALETTE: one array of exactly 12 hex colours at the top of the file.
Every fill reads a colour out of that array. No gradients, no
shadowBlur, no semi-transparent fills.

GAME: a room of 20 by 11 tiles, 16 pixels each. Arrow keys or WASD walk
a character. Collect five gems, avoid one slime that paces between two
points, and go back to the start on a touch.

DRAWING: entities hold fractional positions. Round with Math.floor at
the moment of drawing and nowhere else.

TIMING: multiply every speed by the seconds that have passed since the
last frame, and clamp that number to 0.05 so a tab left in the
background cannot jump the character through a wall.

PHONE: a swipe anywhere walks the character that way.

CONFIG: one object at the top holding the buffer width and height, the
tile size, the walk speed, the gem count and the palette, each with a
comment saying what it does.

Change the palette, the room and the walk speed freely. Leave the resolution block and the whole number scale alone. Those four lines are the only reason the result reads as pixel art, and they are the first thing a later request will quietly undo.

Why pixel art comes out blurry#

A browser has no idea you meant pixels. Hand it a canvas the size of the window and it draws a 12 pixel sprite as 12 real pixels. At that size a character is a smudge, and no amount of redrawing the sprite will fix it. Four separate settings have to agree before an art pixel stays a square.

Why pixel art comes out blurry All four have to be true at once. Three out of four still looks soft. 1 Small buffer Draw to a 320 by 180 canvas, never to the window size. 2 Whole number scale Multiply by 3 or 4. Never by 1.5 or 2.4. 3 Smoothing off imageSmoothingEnabled false on the canvas you blit to. 4 Pixelated in CSS image-rendering: pixelated on the visible canvas. Miss any one of the four and the other three will not save you.
Three of the four are one line each. The buffer is the one that changes how the rest of the file is written, which is why it goes in the prompt rather than in a later fix.

The buffer comes first. Create a second canvas in memory at 320 by 180 and draw everything onto it. The visible canvas then has one job per frame, which is to draw that buffer at the scaled size. Nothing in your game logic ever sees a screen pixel, so nothing in it has to care how big the window is.

Smoothing is the setting people turn off once and then lose. Assigning to a canvas's width or height resets its 2D context, and imageSmoothingEnabled resets with it. So a resize handler that changes the size and forgets to switch smoothing off again gives you a sharp game that goes soft the first time the window moves.

The CSS property does the same job one layer out. When a canvas element's CSS size differs from its width and height attributes, the browser scales the result itself, and image-rendering: pixelated tells it to do that without blending. Set both. They cover different stages and the second costs you nothing.

Scale by three, not by 2.4#

A fractional multiplier is the fault that survives a look at the screenshot, because it almost works. At 2.4 times, some art pixels come out two screen pixels wide and some come out three. The sprite develops a limp. One row of a face is fatter than the row above it, and which row is fatter changes with the window size.

The fix is a line of arithmetic. Divide the window width by 320 and the window height by 180, keep the smaller of the two, then floor it. Clamp the result to a minimum of 1 so a narrow phone still gets a playable screen rather than a blank one.

That arithmetic leaves gaps around the canvas, and the gaps are correct. A 320 by 180 buffer at scale 4 is 1280 by 720, and almost no window is exactly that. Centre the canvas and let the page background show through. A letterboxed pixel game reads as deliberate. A stretched one reads as broken.

  • 320 by 180. Sixteen by nine, so it fills a modern screen with no awkward bars. A 16 pixel tile gives 20 columns and 11 rows, which is a room you can see all of.
  • 256 by 224. Roughly the shape of an early nineties home console. Taller, which suits a playfield you look up and down rather than across.
  • 160 by 144. Handheld sized. So few pixels that every sprite has to read at a glance, which is a useful constraint and a hard one.
  • Anything you like, chosen once. The number matters less than never changing it. Half the file ends up written in terms of it.

A palette of twelve beats a palette of millions#

Part of what makes pixel art read as pixel art is the small number of colours, and a model will not restrain itself unless you ask. Request an array of twelve hex strings at the top of the file, and require every fill to come out of it by index. A change of mood is then one edited line rather than a search through the drawing code.

Choosing the twelve is easier than it sounds. Two or three ramps of three shades each will cover most of a scene: one for stone, one for plant life, one for metal or skin. Add a near black for outlines and a near white for highlights. Keep one loud colour that appears nowhere in the scenery and spend it only on things the player has to notice.

Two habits quietly break a palette. Gradients, because a gradient is every colour between two others. And partial transparency, because a sprite drawn at half alpha over grass produces a colour you never picked. If you want a ghost, draw it in a pale palette colour, or leave every other pixel empty in a checker pattern. Both were what the old hardware did, and both stay on palette.

It looks likeWhat is happeningAsk for
Soft grey haloes on every edgeSmoothing is on, or the scale is fractionalSmoothing off after resize, and a floored scale
Sprites look thin and fiddlyThe buffer is far bigger than 320 by 180A smaller buffer and fatter tiles
Colours that feel muddy togetherThe palette grew while the game grewEvery fill taken from the twelve by index
Text that does not match the artBrowser fonts are not pixel fontsLetters drawn as rectangles, or HTML text outside the canvas
Edges that crawl as things moveDraw positions are fractionalMath.floor at the draw call only

Say what you can see rather than what you think the line should be. The model can read the whole file and you cannot see it from inside.

Why your sprite shimmers as it walks#

A character moving at 37 pixels a second will sit at x equals 41.37 on some frame. Draw it there and its edges fall between two pixels of the buffer, so the browser blends them. At a scale of 4 that blend is four screen pixels wide, and it changes every frame. That is the shimmer.

A sprite that shimmers as it walks Keep the real position fractional and round only at the draw call. Shimmers drawImage(s, x, y)x is 41.37 on this frameThe sprite lands between pixelsEdges flicker on every step Steady drawImage(s, floor(x), floor(y))x stays 41.37 in the entityOnly the drawn position is wholeSlow movement still adds up Round the stored position instead and anything slower than a pixel a frame stops moving.
The rounding has to happen on the way out, not on the way in. It is a two character change and it is the difference between a sprite that walks and a sprite that vibrates.

Round at the draw call and nowhere else. The entity keeps 41.37 and a floor happens as the number enters drawImage or fillRect. Round the stored position instead and slow movement stops working altogether. A speed that adds 0.4 of a pixel each frame gets rounded straight back to where it started, every frame, forever.

The camera needs the same treatment, and it is where the rule gets forgotten. A scrolling room offset by a fractional amount knocks every tile edge off the grid at once. Then the whole screen crawls rather than one sprite, which is harder to diagnose because nothing looks specifically wrong. Floor the camera offset before anything is drawn with it.

  • Rotation. A sprite turned by seven degrees has to be resampled, and resampling invents colours that are not in your twelve. Draw a few pre turned frames instead.
  • Half pixel sizes. A rectangle 12.5 pixels wide has a soft edge at the half. Keep every width and height a whole number too.
  • Strokes. A one pixel line is centred on the path, so at a whole coordinate it straddles two pixels and both come out grey. Use fillRect rather than strokeRect.
  • Scaling inside the buffer. If a sprite is drawn at 1.5 times its own size, you have reinvented the fractional scale at the worst possible layer.

👾Pixel art games written by AI

Common questions#

Can AI make a pixel art game?

Yes, and the sprites are the easy half. A model will draw a readable character out of a few dozen filled rectangles. What it will not do unless asked is pin the resolution, so the usual result is correct code rendering at the wrong size.

Why does my pixel art look blurry?

One of four things. The game is drawing at window resolution instead of to a small buffer. The scale is fractional. Smoothing was never switched off, or was switched off and then reset by a resize. Or the CSS is missing image-rendering: pixelated. Check them in that order.

What resolution should a pixel art game use?

320 by 180 if you want it to fill a widescreen monitor cleanly. 256 by 224 for a taller playfield. The important part is picking one at the start and writing every tile size and sprite size in terms of it.

Do I need two canvases, or will one do?

One can work. Set the canvas width and height attributes to 320 and 180, then give it a CSS size that is a whole multiple of those, with image-rendering: pixelated. The browser does the scaling. You get fewer lines and less say over how the leftover space looks.

Do I need sprite image files?

No, and skipping them keeps the game in one file. At this resolution a sprite is a grid of a few hundred coloured squares, which the code can hold as an array of palette indices and draw with fillRect. It also means a palette change recolours everything at once.

Why do my sprites flicker when they move slowly?

Their draw positions are fractional, so each frame lands on a slightly different blend of two pixels. Floor the position where it is drawn and keep the real value on the entity. Do not round the stored value, or anything moving under a pixel a frame will never move.

Where to go next#

Once the buffer is right, the look is settled and the rest is ordinary game building. Publish it when it is worth a few minutes of somebody else's time. The page records the model and the prompt behind it, which is the part other people learn from.

The method behind all of this is in how to make a game with AI, and the canvas and input details are in the 2D guide. If the look is settled and the game needs a shape, the platformer guide and the roguelike guide both suit a small screen. Fixes for specific faults are in the prompt guide, and the pixel art games here are the fastest way to see which resolutions hold up.