← All work
Computer Graphics · Prototype · 2026

ZX Spectrum engine

Python recreations of a textured 3D engine and a masked-sprite scroller first written in Z80 in 1981-82: six programs on one menu, 1-bit at 256x192, integers only.

ZX Spectrum engine
Year
2026
Status
Prototype
Category
Computer Graphics
Role
Architect & Lead

Key metrics

6
Programs
15
Demonstrator stages
3.4 ms
Room frame (256x192)
99.5%
Pixels matching float renderer (avg)
0 px
Incremental redraw mismatches

Architecture

Everything runs on integers: floats and square roots only build lookup tables up front. Two integer Bresenham walks, one for lines and one for ellipses, drive every edge, span and texture step. There is no raycasting: walls are polygons projected per corner, and each sprite scan line maps to a line or a curve in texture space for flat and spherical textures. Sprites are stored sprite and mask maps (AND the mask out, OR the figure in) with a save-under touched only at the mask's edges, and scenery scrolls by rotating bits through carry. Techniques the 1980s original didn't have live in a separate, labelled modern/ folder.

Case study

ZX Spectrum engine

Steve Messina prototyped this engine on a ZX81 in 1981, aged 13. The ZX81 got more vertical resolution by swapping block graphics characters between interlace sweeps; horizontally it was still limited to half a character cell.

In 1982, aged 14, he wrote a textured 3D engine and a masked-sprite side-scroller on the ZX Spectrum, in Z80, a decade before Wolfenstein 3D (1992) and Doom (1993).

This project recreates those techniques in Python, faithfully, from his memory of the methods, and adds modern takes built on them. It is a private project.

The original's rules, all kept at run time

  • Integer arithmetic only: no floating point and no square roots while running. Floats and square roots only build lookup tables up front.
  • Two integer Bresenham walks: one for lines and one for ellipses.
  • No raycasting: walls are polygons projected per corner.
  • Textures by scan line: each sprite scan line maps to a line or a curve in texture space, giving flat and spherical textures.
  • Sprite and mask maps: AND the mask out, OR the figure in, with a one-pixel outline.
  • Save-under only at the mask's edges: restore the trailing edge, save the leading edge. A naive whole-box restore flickered.
  • Byte-rotate scrolling: scenery scrolls by rotating bits through carry into the next byte.
  • 1-bit: black, white and dithered grey, at the Spectrum's 256x192.

Six programs on one menu

  1. 3D room: doors, windows, columns, bouncing textured balls (including a spiral barber's-pole ball), collision and physics. TAB switches between 256x192, 768x576 and the largest 4:3 size that fits the desktop (up to 2048x1536).
  2. Caveman walk: a side-scroller in the style of mid-80s Spectrum adventures. A textured grey caveman with a club swipe and a shadow stays centred while the scenery scrolls; flags flap on poles as animated masked sprites.
  3. How it works: a 15-stage animated demonstrator. Life without floating point, the two Bresenham walks, lookup tables, the masked blit, save-under (with the naive flicker shown for comparison), the byte-rotate scroll, a 1980s desktop with a mouse cursor, flat and spherical texture mapping, then raycasting (Wolfenstein 3D, 1992) and two Doom (1993) engine panes for comparison, 3D without raycasting, and the room.
  4. 3D chess (isometric): plays against Sunfish, a small open-source chess engine (GPL-3.0, vendored). Press M to switch between two labelled styles: MODERN (ray-traced pieces, noise-textured board) and PERIOD 1980s (pieces built from stacked ellipse rings, table dither, integer-only board).
  5. Checkers: English draughts against our own alpha-beta engine, with compulsory captures, multi-jumps and crowning, in the same two styles.
  6. VEINRUNNER: an original 6DOF tunnel flyer. Tunnels run at any angle: they climb, dive, bank and corkscrew, with a shaft, a chimney and a hall. Integer only, with a Q14 orientation matrix kept orthonormal without square roots, portal visibility, plane-sign collision, and masked alien and ore sprites.

Period and modern

Any technique the 1980s original didn't have lives in a separate, labelled modern/ folder: the ray-traced chess pieces, the noise board, and the comparison raycaster. The demonstrator's raycasting and Doom stages are marked as later techniques.

Checked

  • The integer renderer matches the earlier floating-point renderer on 99.5% of pixels on average over 60 views (98.5% at minimum).
  • The caveman's incremental redraw matches a full repaint with 0 mismatched pixels.
  • The room takes 3.4 ms a frame at 256x192 and 19 ms at 768x576.
  • Test suites pass: chess 14, checkers 13, VEINRUNNER 12.

Gallery

Every screenshot is a frame saved from the programs' own code.

The menu

3D room

Caveman walk

How it works: the 15-stage demonstrator

3D chess

Checkers

VEINRUNNER

Tech stack

Python 3numpypygame-ceFixed-point integer mathsBresenham line and ellipse walksMasked sprites

Other 2026 work