How it's made
A game with no image files · Marko Krulc · Slovenia
Rev Rush contains no image files at all. Its asset catalogue holds the app icon and nothing else — no sprite sheets, no textures, no atlases. Every rider, obstacle, coin and cloud in all 21 worlds is a character map in the source code, drawn pixel by pixel at runtime from a shared palette.
- 0 image files in the game
- 179 sprites as character maps
- 36 entries in the shared palette
- 21 worlds, each with its own music
What a sprite actually is
The rider is not a PNG. It is an array of strings, and a dictionary that says what each letter means:
static let palette: [Character: UIColor] = [
".": .clear,
"K": UIColor(red: 0.055, green: 0.075, blue: 0.114, alpha: 1), // outline
"R": UIColor(red: 0.937, green: 0.165, blue: 0.075, alpha: 1), // bike red
"B": UIColor(red: 0.020, green: 0.329, blue: 0.945, alpha: 1), // suit blue
...
]
static let riderFrame1: [String] = [
".....................KKKKK............",
"....................KHHHHHKKK.........",
"...................KHHHHHHHHHK........",
"...................KHHHhKKKKK.........",
...
]
A drawing routine walks the rows, looks up each character in the palette and fills one square per character. That is the whole pipeline. There is no import step, no texture packer and no build tool between the art and the screen.
Why do it this way
Size. 21 worlds of art weigh what their source code weighs. The app downloads in seconds and then plays fully offline, in 20 languages, with no network call needed for anything except syncing a score to the leaderboard.
Recolouring becomes free. Because the art is characters plus a palette, changing a colour means changing the palette, not repainting an image. That is what makes the garage possible: 51 colours across 5 zones of the vehicle, and the bike repaints while your finger is still on the swatch. Shade and highlight are derived from the one colour you pick, so no combination can come out flat.
Nothing can drift. There is no second copy of the artwork to keep in sync — the code is the artwork.
No recorded sound either
Since version 1.2 the same is true of the sound. Every note of the 21 soundtracks and every one of the game's 216 effects is synthesised by code — a small studio written in Python — with nothing recorded, bought or borrowed. A metal crash is a sum of ringing resonances; a lute is a plucked string worked out sample by sample. How the old soundtrack was transcribed and recorded again, with 1.1 and 1.2 side by side, is on All-new sound.
The website is the same program
The motorbike you scroll past on the front page is not a drawing of the game and not a recording of it. An exporter reads the game's own Swift source — the character maps, the palette, the ground tiles, the skies, the weather, the sky events and the level names — and writes them out as JSON. The browser then runs the same drawing algorithm on that JSON.
Matching is not a target that gets approached by careful redrawing. It is a consequence of the input being identical. When the bike changes in the game, re-running the exporter changes it here.
You can read the exported data yourself: /data/sprites.json is the 179 character maps, /data/palette.json is the palette they are read against. The claim on this page is checkable, which is the only reason it is worth making.
Three implementations, one algorithm
The same drawing routine exists three times: in Swift for the game, in JavaScript for this website, and in Python as an independent reference used to build the icon and the sharing image. A separate page in this site draws the individual parts — rider frames, ghost, battlement, barrel, ground tiles — so the browser's output can be held against the Python one.
The sharing image is not a screenshot either. It is composed from the exported JSON with the same palette and the same sprites: sky in bands, wave silhouettes, ground, rider and the title in the game's 5×7 pixel font. A screenshot would depend on a window size and a moment; this does not.
The favicon is not drawn again either — it is the app icon, scaled down with nearest-neighbour sampling, because bilinear scaling blurs a pixel icon at exactly the 32-pixel size where it matters. The tab and the App Store have to show the same picture, or they are two products with one name.
The rest of the site
The page is static HTML with no framework, no bundler and no
node_modules. Audio is not downloaded at all until you
switch sound on, and then only one track at a time, as you enter each
world — the same AAC files the game ships, about a megabyte each,
looping on the same sample-exact window as they do in the game. The leaderboard on the front page
reads the same database the game writes, and fetches nothing until
you press the button.
The one piece of server code is a counter for AI crawlers. They take the HTML and never run a line of JavaScript, so the only place left to count them is in front of the page: it reads one header, counts the ones that say who they are, and hands over the same static file. For a visitor it does nothing at all.
Even the machine-readable files are generated rather than written: /facts.json takes its numbers from the game's source, and the build fails if a number cannot be found there any more. A hand-copied fact would eventually disagree with the game — and it would disagree exactly where somebody quotes it.
Written by Marko Krulc, who makes Rev Rush alone in Slovenia — design, code, pixel art, music and this website. More at Info, or on X.
You are welcome to quote this page with attribution to revrush.net. Numbers for press use are on the press page.
The text of this site may be quoted with attribution to revrush.net.