Skip to Content
PresetsZX Spectrum

ZX Spectrum

SpecValue
Resolution256×192
Total colors15 unique
Simultaneous15
Constraint8×8 attribute clash (brightness-locked ink/paper)
DisplayCRT RF
Year1982
MakerSinclair

Color palette

The Spectrum has two brightness levels with 8 colors each. Black is shared between both levels, giving 15 unique colors.

Non-bright colors use a hardware voltage ratio of 255 × 0.85 = 216 (0xD8). Bright colors use full voltage (0xFF).

Normal brightness (0xD8)
Bright (0xFF)

Some emulators (FUSE) use 0xD7 instead of 0xD8. The difference is invisible on real hardware CRT displays but matters for pixel-accurate comparisons.

The key constraint: attribute clash

Every 8×8 pixel cell has a single attribute byte encoding:

  • INK (foreground color): 3 bits → one of 8 colors
  • PAPER (background color): 3 bits → one of 8 colors
  • BRIGHT: 1 bit → applies to BOTH ink and paper
  • FLASH: 1 bit → alternates ink/paper

The critical limitation: the BRIGHT bit applies to the entire cell. You can’t mix bright and non-bright colors within a single 8×8 block. This “attribute clash” is the defining visual characteristic of Spectrum graphics.

When an image has color boundaries that don’t align to the 8×8 grid, the constraint solver must choose which pair of colors best represents each cell — creating the distinctive color bleeding artifacts.

Interactive demo

Original
ZX Spectrum

Code example

import { process } from 'bitmapped'; import { getPreset } from 'bitmapped/presets'; const zx = getPreset('zx-spectrum')!; const result = process(imageData, { blockSize: 1, palette: zx.palette!, dithering: 'floyd-steinberg', distanceAlgorithm: 'redmean', constraintType: 'attribute-block', attributeBlockConfig: { width: 8, height: 8, maxColors: 2, brightLocked: true, }, });

Note brightLocked: true — this tells the constraint solver that colors within a block must all come from the same brightness level.

Hardware notes

The ZX Spectrum’s ULA chip reads the display file from two separate memory regions: a bitmap area (6144 bytes at 0x4000) storing 1-bit-per-pixel data, and an attribute area (768 bytes at 0x5800) storing one byte per 8×8 cell.

The color bleeding artifact known as “attribute clash” was the bane of Spectrum game artists. Many games worked around it by using monochrome graphics (single ink color on black paper) or carefully designing levels so color boundaries aligned to the 8×8 grid.

Some later games used advanced techniques like rendering at the attribute boundary to minimize visible clash, or using the FLASH bit for simple animation effects.

Last updated on