c64cast

c64cast turns a real Commodore 64 — driven over the network through an Ultimate 64 or TeensyROM+ — into a programmable display and audio device. It runs a playlist of scenes on the real hardware: play videos and images, stream a live webcam, visualize SID music on a 3-voice oscilloscope, synthesize a MIDI keyboard or an ASID stream through the real SID chip, render reactive generative visuals, or hand the machine over to a native game or demo. Frames from any source are quantized in real time to a VIC-II display mode (PETSCII, MCM, hi-res bitmap, multicolor hi-res); audio plays through the SID's $D418 DAC or the hi-fi Ultimate Audio PCM sampler. Stackable overlays decorate any scene with scrolling text, spectrum analyzers, clocks, weather, RSS, logos, and more; a performance layer puts the whole show on a MIDI controller or a phone; and ensemble mode drives a wall of C64s at once.

The full documentation lives at <https://kfox.github.io/c64cast/> — three books (User's Guide, Programmer's Reference Guide, Performance Card) plus the caveats and troubleshooting notes, rebuilt from this repository on every push.

User’s Guide

Turn a real Commodore 64 into a programmable display

Read online

Programmer’s Reference

Every scene, every knob, every register

Read online

Performance Card

One printable sheet for the desk beside the controller

Read online

Install#

uv tool install 'c64cast[all]'          # or: pipx install 'c64cast[all]'
c64cast --config example:hello -u u64://192.168.2.64

That puts a c64cast command on your PATH. To try it without installing anything permanently:

uvx --from 'c64cast[all]' c64cast clip.mp4 -u u64://192.168.2.64

[all] pulls in every optional feature — video files and YouTube URLs, mic capture, MIDI, webcam gestures, the WLED bridge, the HTTP control plane, the browser console (the web extra), the config wizard. Plain uv tool install c64cast gets a much smaller core install (no mediapipe, no yt-dlp) that still covers every generative scene, PETSCII/bitmap rendering, SID playback, and overlays; add extras à la carte later (uv tool install 'c64cast[video,midi,web]'). Extras don't accumulate, so name every one you want in a single command.

Later, c64cast --upgrade is the upgrade — it works out whether you're on uv tool, pipx, or plain pip and runs that installer's own command, so you never have to remember which. c64cast --check-for-updates just asks. See Upgrading.

You need a reachable Ultimate 64 or TeensyROM+ — there is no emulator path for the streaming side. An Ultimate ships with the three firmware services c64cast needs switched off; Hardware needed lists the switches, and it is worth following Quick Start through the menus the first time — miss one and c64cast connects and then hangs rather than printing anything useful.

What do you want to do?#

Every row below is a runnable demo that ships inside the package — pass it to --config and it loops forever until you Ctrl+C. Point it at your hardware with -u (see Quick start). The Programmer's Reference Guide documents every option for these scenes and overlays.

I want to…TryReference
Play a video (or YouTube URL)c64cast clip.mp4 · example:scene-videoQuick playback
Play an audio track with visuals that react to itc64cast tune.mp3Quick playback
Show a live webcam as C64 artexample:scene-webcam-petsciiwebcam
Visualize a SID tune (oscilloscope)example:scene-waveformwaveform
Play a SID from a MIDI keyboardexample:scene-midimidi
Stream from DeepSID / SIDFactory IIexample:scene-asidasid
Slideshow of imagesexample:scene-slideshowslideshow
Generative / music-reactive visualsexample:scene-generative-plasmagenerative
Stack pixel effects on any sceneexample:effect-chainGenerators + effects
Play the show live from a controller or a phoneexample:performance-clipsPerforming
Run a native .prg/.crt game or demoexample:scene-launcherlauncher
An info board (clock/weather/RSS)example:overlay-clockOverlays
Drive multiple C64s as one video wallexample:ensemble/masterEnsemble mode
Make the C64 a WLED LED matrixexample:scene-wledwled
Control c64cast from the WLED appexample:wled-controlWLED bridge

Run any of them with c64cast --config example:<name>, or list the whole set with c64cast --list-examples (one demo per scene type and per overlay).

Features#

Quick start#

# "Hello world": scrolls big text across a solid canvas. Needs nothing but a
# reachable U64/TR+ — no webcam, mic, SID, or video files. Ctrl-C to exit.
c64cast --config example:hello -u u64://192.168.2.64

# Save the connection target so you never type -u again:
c64cast -u u64://192.168.2.64 --save-settings
c64cast --config example:hello

-u/--url is a scheme-aware target that picks the backend + endpoint: u64://HOST or http(s)://HOST (Ultimate 64 / II+), tr:// (TeensyROM+ over auto-detected USB serial), tr:///dev/cu.usbmodem* / tr://COM3 (a specific serial device), or tr://HOST (TeensyROM+ over TCP). $C64CAST_URL is the env fallback, and --save-settings persists it — along with the capture device and SID model — to ~/.config/c64cast/settings.toml, where it applies to every later run including quick playback.

The first run against a machine spends about a second reading that machine's character ROM over the wire and caching it under ~/.local/share/c64cast/, so every glyph c64cast draws is your Commodore's own font rather than a built-in approximation.

From example:hello, the next steps:

# Try a single feature in isolation — one demo per scene type / overlay:
c64cast --config example:scene-webcam-petscii
c64cast --config example:overlay-clock

# Build your own: the wizard walks you through a single scene or a whole
# playlist and writes a ./c64cast.toml, which later runs pick up on their own
# (needs the 'wizard' extra, included in [all]):
c64cast --init

# ...or by hand, starting from the fully-annotated reference config:
c64cast --print-example c64cast.example > c64cast.toml && $EDITOR c64cast.toml
c64cast

# Check a config and your installed extras without touching the C64:
c64cast --doctor --config c64cast.toml --skip-probe

The demos ship inside the package, so example:NAME works the same from an installed wheel, from uvx, or from a git checkout — c64cast/examples/README.md is the narrative tour of them. c64cast -h lists every CLI flag, grouped by section.

Quick playback (no config file)#

Pass media files/directories/globs/URLs as positional arguments to play them once, in order, without writing a TOML (mutually exclusive with --config). Audio is on by default; --no-audio mutes.

# A video, a SID tune, then a folder of pictures, on an Ultimate 64:
c64cast -u u64://192.168.1.64 clip.mp4 tune.sid ~/Pictures/

# A YouTube URL, on a TeensyROM+ over auto-detected USB serial (the 'yt'
# extra, included in [all]); an audio file works too — the track plays
# through the C64 while a generative visual reacts to it.
c64cast -u tr:// 'https://youtu.be/dQw4w9WgXcQ'

Configuration#

A config is a single TOML file (--config PATH, else ./c64cast.toml, else built-in defaults) that defines the playlist and every overridable option. c64cast --init builds one interactively, --print-example c64cast.example prints a fully-annotated one to edit, and --doctor --skip-probe validates the result without touching the C64. The whole config surface is discoverable from the command line (--describe, --list-scenes, --list-overlays, --list-modes, --compat, --print-schema), and every one of those reads the same field metadata the loader runs on, so the answers can't drift from the code. See The Configuration Language for the complete walkthrough and Appendix A for every section and field.

Live control#

While the show is running you can drive it from the C64's own keyboard (pause, skip, cycle styles, an on-C64 menu of live knobs), a MIDI controller (a clip-launch grid quantized to a beat grid, CC knobs mapped to live parameters, pad LEDs driven from actual state, saved looks that recall a scene and its whole effect chain in one press), a browser, webcam gestures, or plain HTTP + signals with [control] enabled = true.

The browser gets two pages, both served by c64cast itself. GET /perf is the zero-dependency phone console — clips, the effect rack, the current scene's tune knobs, tempo, transport, looks and a jump to any scene — and needs only [control] enabled = true. c64cast --serve (the web extra) is the full console: the same performance surface plus the C64's live screen, a form that edits and validates a configuration, save-back of anything you tuned, and a read-only link to hand out.

Inputs and Outputs documents every surface in full, and the Performance Card is the printable version for the desk beside the controller.

Documentation#

Everything below is also a website: <https://kfox.github.io/c64cast/> reads all three books and the notes beneath them in one place, built from these same files on every push to main.

Each PDF link above always serves the newest release; every past release keeps its own version-stamped copy on its release page.

Hardware needed#

One of the following:

Nothing else needs enabling by hand: c64cast turns on the REU and maps the Ultimate Audio sampler itself when a run needs them, and puts both back at teardown.

Depending on how you use it, you'll also want some of these things:

There is no software emulator path for the streaming side: c64cast writes directly to C64 memory and VIC-II registers over the wire, and SID playback runs a small player PRG in the machine's own RAM so the real 6510 calls PLAY at IRQ time. See docs/caveats.md for why, and for the PSID-only limitation that follows from it.

Contributing#

Bug reports, feature ideas, and pull requests are all welcome. See CONTRIBUTING.md for the development setup (a git checkout and uv sync --all-extras), the make check gate, and the conventions this repo follows. Security reports go through SECURITY.md rather than a public issue.

Acknowledgments#

License#

MIT — see LICENSE.

Third-party assets. The books are typeset in two fonts that are redistributed in this repository under the SIL Open Font License 1.1, not under MIT: Jost\ (Copyright 2020 The Jost Project Authors) and Inconsolata* (Copyright 2006 The Inconsolata Project Authors). They live in docs/shared/fonts/ alongside their license texts — see that directory's README for provenance and for what has to travel with them.