Side projectNight City
An endless pixel-art street at night that you walk along while the city quietly gets on with being alive around you. Built as an experiment in how much life you can give a picture that is mostly standing still — and in getting two dozen separately generated images to look like one place.
What it is
You walk right, and the place carries on without you. Windows go dark in towers a mile away, a lamp stutters, a police car tears past, a bus pulls in at a shelter and waits, pigeons scatter off a rooftop, rain lands on the kerb and splashes. None of it is scripted — it is a set of small systems each deciding for itself when to do something.
The target was that roughly a tenth of the screen is changing at any one moment and the rest is perfectly still. That sounds unambitious, and it is the entire difference between a city at night and a screensaver.
How it's built
Night City is vanilla JavaScript and one canvas. No framework, no build step, no dependencies and nothing to install — the page you load is the source that runs.
The world is painted onto a canvas just 320×180 pixels and then blown up four times with smoothing switched off. That second step is the whole trick: every pixel becomes a crisp block, and nothing can land on half a pixel. Draw straight onto a big canvas instead and everything shimmers the moment it moves.
The city is seven parallax layers, each a handful of tiles repeated forever in both directions. Walk far enough and you meet the same building again — but never the same lit building, because each tile asks a seeded random number generator "what am I?" using its own position as the seed. For any tile to be able to follow any other, the outer eight pixels of every tile are left empty. You cannot see the seams because there is nothing at them.
Features
- A city that is alive without being scripted. Traffic, pedestrians, rain, neon, pigeons and lighting all run as separate systems, each deciding for itself when to act — so no two minutes on the same street play out the same way.
- An endless street in both directions. Seven layers of parallax tiles, each asking a seeded generator what it is from its own position, so the city goes on forever and never repeats the same lit building.
- True pixel discipline. Everything is painted at 320×180 and scaled up four times with smoothing off, so every pixel is a crisp block and nothing ever lands on a half pixel.
- Artwork that drives its own behaviour. Windows, parapets, ledges and shopfronts are found by reading the images themselves, so adding a new building automatically gives it lights to switch off and ledges for birds to land on.
- Weather and reflection. Rain lands and splashes on the kerb, and wet asphalt picks up the neon above it.
- Layered audio. Streaming beds for music, rain and city ambience, with overlapping one-shots for footsteps, sirens and buses, so the same siren can pass twice without cutting itself off.
- Built for a phone as well as a monitor. Touch controls with auto-run, and a taller portrait viewport that uses artwork already sitting above the landscape view.
The art pipeline
Every image started as a written prompt, and none of them went straight into the game. Image generators cannot actually produce pixel art — they produce a large picture that resembles it, with blocks roughly square and colours roughly right. "Roughly" is fatal at four times magnification: a block 3.8 pixels wide instead of 4 is a ragged edge.
So everything passes through a conforming tool written in Python. It snaps the art to the pixel grid, forces every colour onto a locked 23-colour palette, hardens the transparency and checks the gutter rule — then prints the numbers, so how well a generation conformed is something you can measure rather than a feeling. The prompt pack is half the project, and it ships with it.
The stack
- Engine
- Vanilla JavaScript and one canvas — no framework, no build step, no dependencies
- Rendering
- A 320×180 backbuffer scaled 4× with smoothing off, over seven parallax layers
- World
- Seeded from tile position, so the city is endless in both directions and identical each time you pass
- Art
- AI-generated from a written prompt pack, then conformed to the grid and palette by a Python tool
- Audio
- Streaming beds for music, rain and city ambience; overlapping one-shots for footsteps, sirens and buses
- Mobile
- Touch controls with auto-run, and a taller portrait viewport using art above the landscape view
- Hosting
- Vercel
A detail I like
Most of these systems run alongside each other without ever noticing each other; the traffic has no idea the pavement exists. The bus is the exception. It reads the very same data that decides where the shelters go, picks the next one ahead of it, eases to a stop, waits a few seconds, and pulls away. It is a small thing, and it is the moment the city stops being several effects layered on top of one another and starts being a place.