A faithful recreation of the iconic Matrix "digital rain" effect, running natively on Apple II hardware in 6502 assembly. Renders in real-time on the Hi-Res Graphics page using custom Katakana-inspired glyphs, sine-wave column offsets, and a shadow-buffered dirty-rect engine for smooth animation.
- Pure 6502 assembly — no ProDOS or DOS dependency, runs on bare metal
- Hi-Res Graphics (HGR) rendering — 280×192 monochrome, full-screen
- Custom glyph set — 16 Katakana-inspired 7×8 pixel characters
- Organic rain motion — sine-wave phase offsets per column for natural-looking cascades
- 4-level brightness pipeline — head (solid white) → body (shimmer) → dim (bit-masked) → erase
- Body glyph shimmer — body cells slowly cycle glyphs for a subtle living-trail effect
- Shadow buffer optimization — only redraws cells whose brightness changed since last frame
- LFSR-seeded column density — 16-bit Galois LFSR generates a unique rain pattern every launch
- Interactive settings menu — press ESC to open a mixed-mode overlay; adjust speed, dim pattern, shimmer rate, and re-randomize rain while it keeps falling
- Runtime-adjustable everything — speed, dim mask, body shimmer, and rain density all changeable without rebuilding
- RTS-trick dispatch — fully relocatable draw dispatch
- Clean exit — Q key restores text mode and returns to the Apple II monitor
- Hardware: Apple II, II+, IIe, or IIgs (48K+ RAM)
- Toolchain: cc65 suite (using the
cl65compile and link utility) - Emulator (optional): AppleWin, MicroM8, or Virtual II
Use apple2-asm.cfg provided by cc65. Because the default config reserves 3 bytes for a DOS header, we explicitly force the start address to $0800.
# Assemble and Link in one step
cl65 -t apple2 -C apple2-asm.cfg --start-addr 0x0800 matrix_screensaver.s -o MATRIX.BINThis produces MATRIX.BIN, a raw binary loadable at $0800.
Apple II file systems require specific metadata (File Type and Load Address) to execute binaries correctly.
- Rename your compiled
MATRIX.BINtoMATRIX#060800(this tells CiderPress it is a Binary file meant for address$0800). - Drag and drop
MATRIX#060800into a.dskor.poimage using CiderPress. - Boot the disk image in your emulator.
- At the
]prompt, type:BRUN MATRIX
If you prefer to load it manually without executing immediately:
] BLOAD MATRIX
] CALL 2048(Or from the System Monitor: *0800G)
Transfer MATRIX.BIN to a ProDOS or DOS 3.3 disk image using ADTPro, CiderPress, or similar tool. Then type BRUN MATRIX from the BASIC prompt.
Always active:
| Key | Action |
|---|---|
ESC |
Toggle settings menu |
Q |
Quit — exit to Apple II monitor |
+ / = |
Increase rain speed |
- |
Decrease rain speed |
Settings menu only (press ESC to open):
| Key | Action |
|---|---|
D |
Cycle dim pattern ($55 → $AA → $33 → $11) |
B |
Cycle body shimmer rate ($00 → $07 → $03 → $0F) |
R |
Re-randomize rain pattern (uses current frame as LFSR seed) |
ESC |
Close menu and return to full-screen rain |
When the menu is open, rain continues falling on the top 20 rows while a 4-line settings panel displays at the bottom using Apple II mixed mode. Current values are shown as live hex readouts. Key labels appear in inverse video.
Default values are set as constants at the top of matrix_screensaver.s. All are adjustable at runtime through the settings menu:
| Constant | Default | Description |
|---|---|---|
INIT_SPEED |
3 |
Starting rain speed (1–5) |
INIT_DIM |
0 |
Starting dim mask index (0=$55, 1=$AA, 2=$33, 3=$11) |
INIT_BODY |
1 |
Starting shimmer rate index (0=every frame, 1=every 8, 2=every 4, 3=every 16) |
LFSR_SEED_LO/HI |
$B4/$37 |
LFSR seed — change for a different startup rain pattern |
The TAIL_LEN_TBL is seeded at startup by a 16-bit Galois LFSR, so every launch produces a unique rain pattern. Press R in the settings menu to re-randomize at any time. Values below 100 become blank columns (~40% density). To get a fixed pattern instead, remove the SEED_TAILS call from INIT_ALL — the hardcoded fallback table will be used.
Each frame walks a 40×N grid (N=24 full-screen, or 20 when the menu is open). For every cell:
- Phase calculation — A sine-wave lookup offsets each column's rain position, creating the organic "falling at different speeds" effect
- Brightness classification — The distance from the wave head determines one of four states: head (3), body (2), dim (1), or empty (0)
- Glyph animation — Head cells cycle glyphs every frame; body cells shimmer on a configurable slow cycle; dim/erased cells stay static
- Shadow buffer check — If the brightness hasn't changed since last frame, skip the draw entirely
- Dispatch — RTS-trick jump to the appropriate draw routine (fully relocatable)
The settings menu uses Apple II mixed mode ($C053), which composites HGR on the top 160 scanlines and text page 1 on the bottom 32 scanlines (text lines 21–24). When the menu opens, GRID_ROWS drops from 24 to 20 so the rain loop doesn't overwrite the text area. When it closes, GRID_ROWS returns to 24 and INVALIDATE_BOTTOM forces the bottom rows to redraw. Runtime parameters like DIM_MASK are stored in zero page for fast access in the hot loop; the body shimmer mask uses a single self-modified operand byte.
| Address | Usage |
|---|---|
$00–$1E |
Zero page working registers, LFSR state, menu state |
$0400–$07FF |
Text page 1 (used for settings menu in mixed mode) |
$0800+ |
Program code and data |
$2000–$3FFF |
HGR Page 1 (video output) |
$6000–$63FF |
Shadow brightness buffer (40×24 bytes) |
| Routine | Effect |
|---|---|
DRAW_HEAD |
Solid white block ($7F across all 8 scanlines) |
DRAW_MED |
Full glyph render from FONT_DATA |
DRAW_DIM |
Glyph ANDed with runtime DIM_MASK_ZP for a faded look |
DRAW_ERASE |
Zeros out all 8 scanlines |
├── README.md
├── LICENSE
├── matrix_screensaver.s # Complete source (single-file, self-contained)
└── .gitignore
MIT License. See LICENSE for details.
Inspired by the digital rain effect from The Matrix (1999). Built for the love of 6502 assembly and the Apple II.
