↑ / W: throttle ↓ / S: brake ← → / A D: steer R: restart
A texture-mapped ground plane in the SNES Mode 7 style, drawn scanline by scanline with the pen, with a kart on it, three laps and a stopwatch. THE SCANLINE MATHS Put the camera at height h looking horizontally, and fix the horizon at one screen row. A pixel row d pixels below the horizon is looking along a ray that drops d / FOCAL for every unit forward, so it meets the ground at z = h * FOCAL / d That single division per row is Mode 7. Everything else falls out of it: at depth z, one screen pixel sideways is z / FOCAL world units sideways, so once a row's z is known, marching across it is two additions per sample — no per-pixel divide anywhere. That is exactly why the SNES could do this in hardware with one affine transform per scanline, and it is why 60 rows of it fit in a Scratch frame. Two consequences you can see while driving. The horizon never moves, because the camera never pitches — a pitch would break the fixed mapping from d to z, which is precisely why Mode 7 games tilt the floor rather than the camera. And the far rows compress enormously: at d = 15 the row is 58 world units away, at d = 178 it is 4.8, so the top fifteen pixels of the ground cover more distance than the other 165 put together. That is where the haze has to come from. DECISIONS WORTH KNOWING ABOUT The texture is 192 strings, not 36,864 list entries. One list item per texel would be about 150KB of project.json; 192 rows of 192 characters is 37KB, and sampling costs one extra "letter of" block. The fog is six pre-blended copies of the nine-colour palette, so a scanline picks its entire hazed palette with one index instead of unpacking and blending RGB per texel. Runs, not samples. Adjacent samples along a row very often land on the same palette entry — tarmac and grass are both wide — so the row is run-length encoded and one pen stroke is emitted per run. Measured on the default view, 70 samples a row collapse to about a dozen strokes, which is where most of the frame budget went before. Physics never reads the texture. The 128-point centreline the texture was generated from is baked separately, so "am I on the track" is a distance to a curve and lap progress is an index along it. The centreline points are spaced evenly in arc length, not in the curve's parameter — even spacing in the parameter bunches points on the tight corners, which would make lap progress crawl through the hairpins and sprint down the straights. A lap only counts if the far side of the track was visited first, so reversing back over the line does nothing. The kart is a real world position, not a fixed sprite. The camera's heading lags the kart's by 24% per frame, so in a drift the two genuinely disagree and the kart slides across the frame. Its screen position and scale come from the same projection the ground uses. The handling is a linear tyre model: velocity is resolved into the kart's own frame, the forward component is barely damped and the lateral component is damped hard, and the ratio between those two numbers is what "grip" means — 0.80 on tarmac, 0.60 on grass. HONEST LIMITATIONS - The ground is sampled every 7 pixels across and every 3 down, so it is visibly chunky up close. The thumbnail is the same renderer at one ray per pixel, which is what it would look like with an unlimited budget. - No sprite scaling for scenery. All original - code, art and sound. See Inside is open.