← Rev Rush

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.

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.

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 177 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 1.4 MB of WAV that is not downloaded at all until you switch sound on, and then only one track at a time, as you enter each world. The leaderboard on the front page reads the same database the game writes, and fetches nothing until you press the button.

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.

© 2026 Marko Krulc. Code, pixel art and music: all rights reserved.
The text of this site may be quoted with attribution to revrush.net.