Releases: kfox/c64cast
Release list
c64cast v0.2.1
Downloads
- 📘 c64cast User's Guide 0.2.1 (PDF)
— 10 chapters, read in order, starting from nothing. - 📕 c64cast Programmer's Reference Guide 0.2.1 (PDF)
— every scene, knob and register, with nine generated appendices. - 🎛️ c64cast Performance Card 0.2.1 (PDF)
— two pages for the desk next to the controller. - 📦
c64cast-0.2.1-py3-none-any.whl
·c64cast-0.2.1.tar.gz
— or justuv tool install 'c64cast[all]'
(PyPI).
Added
-
The documentation is a website.
kfox.github.io/c64cast publishes all three
books — User's Guide, Programmer's Reference Guide, Performance Card — plus
the caveats, troubleshooting and extending notes, rendered from the same
Markdown the PDFs are set from and republished on every push tomain. Each
book gets a contents page, a chapter sidebar, prev/next paging and a link to
its typeset PDF; a section link resolves identically on github.com, in the
PDF and on the site, because all three use GitHub's own anchor rule. The
renderer (scripts/build_site.py) is stdlib-only and shares its reading of
the Markdown — and every check that reading makes — with the PDF builder, so
the two cannot disagree about what a page says.make sitebuilds it
locally; a pull request now proves every book still renders, which previously
nothing did until release day. -
Every book has a permanent download link. A release now carries each PDF
twice —c64cast-users-guide-X.Y.Z.pdfas before, and an unversioned
c64cast-users-guide.pdf— so
https://github.com/kfox/c64cast/releases/latest/download/c64cast-users-guide.pdf
(and the same forc64cast-reference-guide.pdfand
c64cast-performance-card.pdf) always serves the current release. The README
links all three that way; every past release keeps its version-stamped copy. -
--doctornames the opencv build that actually loaded. Every opencv
wheel — plain, contrib, and the headless variants — unpacks into the same
cv2/directory under a different distribution name, so an installer will
co-install several and the last one written wins. Installing thevision
extra (orall) bringsopencv-contrib-pythonalong with mediapipe, which
means theopencv-pythonversion c64cast pins is not the one that runs, and
nothing said so. ENVIRONMENT now reports the build in place, flags it when
more than one distribution is providingcv2, and warns when the winner is a
headless wheel — the cause of[preview]opening no window.
Fixed
-
DAC audio can no longer come up silent for a whole session. On some
machines a run would play no audio at all from the first frame to the last —
never a dropout, never a recovery, and the video also ran noticeably fast.
Three writes start the NMI audio consumer, and the write transport is built to
absorb a dropped write rather than fail loudly; if any of the three went
missing the consumer never started, and nothing on the host noticed (the fast
playback was the pacing loop correctly chasing a reader that never read). The
bring-up now checks that the consumer actually started and re-sends the writes
if it didn't, up to five times, logging when a retry was needed and warning
outright if it never takes. A consumer that dies mid-session also warns now
instead of playing out as unexplained silence.--calibrate-dacuses the same
verified bring-up, so a run can no longer spend 50 seconds measuring nothing. -
Ensemble systems no longer record over each other.
[recording].path
cascaded from the master like the rest of the section, so every system in a
wall opened acv2.VideoWriteron one file and finished with a single
truncated recording — silently, since the writers have no way to detect the
collision.pathis now per-system likeultimate64.url: leave it unset and
each system writesrecording-<system>.mp4; set it and that path is used as
written.enabledstill cascades, so recording a whole wall is still one
key.--doctorreports an error if two systems are pointed at one file
explicitly. -
--doctorfindings can no longer go missing. The report printed only
those categories named in a hard-coded list, so a check reporting under any
other name returned findings that never reached the screen — indistinguishable
from passing. Unlisted categories now print after the known ones. -
Corrected the troubleshooting advice for a shadowed opencv, which prescribed
reinstallingc64cast[all]— the install that causes the shadowing.
Changed
- The README is a landing page again. It had grown a reference section for
each surface it introduced — the full keyboard table with its chord
precedence rules, nine config-discovery commands, the machine-settings
precedence, the SID-player rationale — all of which the books now state
properly, from the code. Those are cut down to what someone deciding whether
to install this needs, and the space goes to what was missing: the pixel
effect chain (four of the eight effects were listed, and the chain not at
all), the live performance surfaces (a clip grid, a beat grid, pad LEDs,
looks and the/perfconsole had no mention outside the docs list), audio
files as quick-playback arguments, the bitmap spectrum overlay, and the
character ROM your first run reads off your own machine.
c64cast v0.2.0
Downloads
- 📘 c64cast User's Guide 0.2.0 (PDF)
— 10 chapters, read in order, starting from nothing. - 📕 c64cast Programmer's Reference Guide 0.2.0 (PDF)
— every scene, knob and register, with nine generated appendices. - 🎛️ c64cast Performance Card 0.2.0 (PDF)
— two pages for the desk next to the controller. - 📦
c64cast-0.2.0-py3-none-any.whl
·c64cast-0.2.0.tar.gz
— or justuv tool install 'c64cast[all]'
(PyPI).
Added
- c64cast reads the C64 character ROM off your own machine. Every glyph
drawn as C64 text — the text overlays on bitmap modes (scrolling_text,
marquee,corner_text,logo),big_text, the on-C64 menu, the
oscilloscope's labels, the preview window and the stream recorder — comes from
the character ROM. Previously the only way to have one was to find a dump and
drop it at a working-directory-relative path in a source checkout, which meant
an installed c64cast could never resolve it and a user report of "the
scrolling text looks bad" was, in full, "there is no character ROM". Now the
first run against a machine reads it off the C64 and caches it at
<data dir>/roms/chargen.bin; every later run picks it up. It costs about a
second, once per machine, and no ROM bytes are shipped or downloaded — they
move from your hardware to your disk.--dump-char-romre-reads on demand
(after swapping in a different character ROM, say),--install-char-rom PATH
installs a 2 KB or 4 KB dump you already have with no hardware involved, and
[hardware].dump_char_rom = falseturns the automatic read off.--doctor
reports which ROM is in use and whether it verifies. - A second book: the Programmer's Reference Guide (
docs/reference/), the
volume you open at the page you need rather than read in order. Seven
chapters: the configuration language and its precedence rules, the catalog
of every scene and overlay, the display pipeline from frame to VIC-II
register, the sound path in both directions, the link into the Commodore's
memory and what lands there, every input and output that reaches the show from
outside, and how to extend the program itself. Its appendices
are generated from the code byscripts/gen_reference_appendices.py: every
configuration section and field, every scene key, every overlay parameter, the
overlay against display-mode matrix, every generator and effect, every
live-tune target, every command-line flag, every packaged example and every
optional install extra. They
read the same definitions that answer--describe,--compatand
--print-schema, so a table in the book cannot disagree with the program.
make referencerenders it,make booksrenders every book, andmake reference-appendicesrewrites the generated ones — which CI checks for drift. - A third book: the Performance Card (
docs/card/), two printable pages for
the desk beside the controller. Every control surface and what it is mapped to
out of the box, the pad chords and pad-light states, every live-tune target,
the clip-grid and tempo syntax, the console's routes, how a channel addresses
one Commodore of an ensemble, and the four commands worth running before the
doors open.make cardrenders it; its live-target table is generated
alongside the reference guide's appendices. It takes thecardlayout: the
same palette, faces and tables as the other two books, set two-up at 8.5pt
with no cover, contents or chapter openers. - The GitHub release now carries every book, each stamped with the version:
the User's Guide, the Programmer's Reference Guide and the Performance Card.
Removed
docs/usage.mdis gone. Its 1,867 lines were the end-user reference
before there was a book to put them in; every part of it that was not already
duplicated by the User's Guide has been rewritten into the Programmer's
Reference Guide, which states the same rules from the code rather than from
prose that had drifted from it. Every link that pointed there now points at
the chapter or appendix that answers the question, and a test fails if a new
one appears.
Changed
- The Programmer's Reference Guide now documents what a reload actually
re-reads, and the signals.POST /reloadwas described as re-reading the
configuration and rebuilding the playlist, which overpromised: a reload swaps
[[scenes]]and[interstitial]and nothing else — the connection, the audio
path, the capture device and even[playlist]'s ownloopand
fade_duration_sare fixed at startup. Chapter 6 now says so, and gains a
Signals section coveringSIGHUP(the control-plane-free spelling of the
same reload, POSIX-only, which the User's Guide advertised and the reference
never mentioned),SIGTERM, and the ensemble rule that each system re-reads
its own file while the master is not re-read. No behavior changed. - The
hopalonggenerator's live targetsource.ais nowsource.shape.
Every other live target is named for what turning it does —drift_speed,
ring_freq,zoom_speed— and this one was named for the letter Barry
Martin's map gives the constant, which tells a performer looking at a knob
label nothing. Sweeping it reshapes the attractor, so it isshape. The
constant is stillain the implementation, where it matches the published
map.source.awas never settable from a config; the one thing this breaks is
a hand-written[[midi.mappings]]entry naming it, which now silently fails to
match — rename the target. [preview] charset_pathnow defaults to unset, meaning "use the character ROM
c64cast resolved". Set it to force a specific file. A configured path that
doesn't exist now warns and falls back to the built-in font instead of raising
FileNotFoundErrorand killing the run.- The built-in fallback font now fills screen codes
$80-$FFas the reverse-video
complement of$00-$7F, like the real ROM. They were blank, so with no
character ROM installedbig_text's glyph pixels, theblocksPETSCII style
and most of the PETSCII shading ramp — all of which paint$A0and up —
rendered as nothing. - The User's Guide build now renders a book rather than the guide, in
preparation for a second volume.scripts/build_guide.pyis
scripts/build_book.py --book-dir docs/<book>, the Typst template and the
vendored OFL fonts moved fromdocs/guide/todocs/shared/, and each book's
book.tomlnames the layout it takes.make guideand the released PDF are
unchanged. - The reference guide's generated appendices are set as two columns instead of
four. A field's name, type and default are three facts about one setting,
and given a column each on a 6.24in page they left the description — the only
part written for a human — about a third of the measure and four words to a
line, with a single field running most of a page. They are now stacked into
one fixed-width column with the description taking the rest, at the same width
in every such table, so a scene key, an overlay parameter and a CLI flag all
line up down the book. The reference is 20 pages shorter for it. - Chapter and appendix cross-references are links. "See Appendix F" in the
prose jumps to Appendix F, and every line of the table of contents jumps to
its page. A reference to a chapter the book does not have now fails the build,
which is what catches a renumbering the prose was not told about. - Every section of every book can be linked at, and the chapter opener pages
are clickable. The contents page already navigated; the opener page listed
its sections and did nothing when you pressed one. Each##and###heading
now carries an anchor, the opener bullets jump to the section they name, and
the prose can link at a section —[Fades](04-display-pipeline.md#fades)—
rather than only at a whole chapter, so a pointer can mean a row in a table
instead of a page with a big numeral on it. The anchor is GitHub's own, because
the Markdown is the book: the same link resolves on github.com and in the PDF.
One that resolves nowhere fails the build and names the nearest ones it knows. - The Programmer's Reference Guide has an index, and it is generated like
its appendices. Every name the program can utter goes in — configuration
sections and keys, command-line flags, scene types, overlays, display modes,
generators, effects and live-tune targets — against the pages that discuss it.
Locators are clickable page numbers in the PDF and section links on
github.com, from the one source, because the Markdown is the book in one place
and there are no pages in the other. A key is listed bare, and again under its
section where two sections share the name; a parameter belonging to a
generator, an effect or a display mode is filed under its own name with the
holder in parentheses, soaxisis where you look andaxis (effect)is what
you find. A short curated set of ordinary words — "camera", "dithering",
"display mode" — is in there for the reader who does not yet know what the
program calls the thing. Section titles are deliberately not entries: a
topic belongs to the contents page, and nobody looks up "Saving What a Run
Changed". - Each appendix section opens with a worked TOML fragment. A table of
settings says what each one means and nothing about where the line is
written, which...
c64cast v0.1.0
Downloads
- 📘 c64cast User's Guide 0.1.0 (PDF)
— 10 chapters, read in order, starting from nothing. - 📦
c64cast-0.1.0-py3-none-any.whl
·c64cast-0.1.0.tar.gz
— or justuv tool install 'c64cast[all]'
(PyPI).
The first public release. c64cast has been in daily use against real hardware
since June 2026 — this is the point where it becomes installable rather than
cloneable.
Added
Two hardware backends, selected by URI. -u u64://HOST (or http(s)://)
drives an Ultimate 64, Ultimate II+, or Commodore 64
Ultimate: memory writes go over the Ultimate DMA Service on TCP port 64 with
REST for the handful of operations that have no DMA equivalent. -u tr://
drives a TeensyROM+ cartridge in an
original C64 over auto-detected USB serial, an explicit serial device
(tr:///dev/cu.usbmodemXYZ, tr://COM3), or raw TCP (tr://HOST[:PORT]).
Per-link knobs ride along as query parameters (u64://host?dma_port=64,
tr:///dev/…?baud=2000000). $C64CAST_URL is the environment fallback.
Ten scene types, mixed freely in a TOML playlist with per-scene durations
and an "UP NEXT" interstitial between them:
- video — MP4/MKV/etc. with its soundtrack, paced off the audio clock so
A/V cannot drift. YouTube and other streaming URLs resolve through yt-dlp. - webcam — live capture quantized to any display mode in real time.
- slideshow — still images from a directory or glob, aspect-fit.
- waveform — plays a
.sidon the real chip through a small player PRG
DMA'd into C64 RAM (deliberately not the firmware's own runner, which
hijacks the HDMI output), with a 3-voice oscilloscope driven by a host-side
py65 SID emulator. Handles multi-SID tunes up to 8 chips on the U64's
UltiSIDs, and matches 6581/8580 tunes to the installed chips. - midi — bridge a live MIDI source into the real SID and scope each voice.
- asid — receive an ASID stream (DeepSID in a browser, SIDFactory II,
Plogue chipsynth C64) and play it on the real SID with the same scope. - generative — 20 procedural sources (plasma, tunnel, fire, mandelbrot,
metaballs, game of life, fireworks, soap, …), optionally music-reactive. - launcher — hand the machine over to a native
.prg/.crtand reclaim it. - wled — turn the C64 into a virtual LED matrix fed by a realtime pixel
stream from LedFx or xLights (DDP or WLED realtime UDP). - blank — a solid PETSCII canvas as a foundation for overlays.
Six VIC-II display modes — petscii, mcm, hires, hires_edges,
mhires, blank — each with its own vectorized quantizer (≈30 fps bitmap,
50/60 fps character modes over a LAN). The [color] pipeline shapes any source
before quantization: spatial dithering, perceptual color matching, per-cell
strategy selection, motion smoothing, scene fades, and a forced-palette mode
that remaps a frame onto a chosen subset of the 16 C64 colors — with a rolling
palette that re-clusters as the content changes. --suggest-palette FILE
analyzes an image or video and ranks the colors that represent it most
faithfully.
Audio on the real SID. By default, video and file audio play through the
U64's Ultimate Audio FPGA PCM sampler for high fidelity; the lo-fi $D418 DAC
path (4-bit, or ≈6–7 bit via Mahoney companding) covers TeensyROM+, mic input,
and webcam audio everywhere. The sampler's effective clock ships calibrated, so
audio holds sync against host-paced video over long runs. --calibrate-dac
measures a per-machine DAC response curve through an HDMI capture device.
Thirteen stackable overlays — scrolling_text, marquee, rss,
spectrum_petscii, spectrum_bitmap, clock, weather, callsign,
countdown, network, logo, big_text, obs_status — composable onto any
compatible scene, with --compat printing the overlay × display-mode matrix.
Ensemble mode. One process drives N systems at once as a video wall, with
cross-system orchestration — a big_text message scrolling across every screen
as one continuous canvas, spans and mirrors — and audio-slot coordination so
the systems do not fight over the DAC.
Live control surfaces. The C64's own keyboard (C= pauses, CTRL skips, SHIFT
cycles the display style), an on-C64 menu for live scene tweaks, webcam hand
gestures, a FastAPI control plane (/pause, /resume, /skip, /reload),
MIDI CC mapped to any live parameter, and SIGHUP to reload the config. The
DJ/VJ layer adds a tempo/beat grid, a clip-launch grid with LED feedback on
grid controllers, a layerable chain of 8 pixel effects, snapshot-recall of
"looks", and a phone/web performance console.
WLED bridge, in three directions under one [wled] section: drive real LED
matrices from the C64's SID with no microphone, present c64cast as a virtual
WLED device that the WLED app and Home Assistant discover and control, and turn
the C64 into a matrix that LedFx/xLights stream pixels to.
Quick playback. c64cast clip.mp4 tune.sid pics/ 'https://youtu.be/…'
plays media straight from the command line with no config file, mapping each
argument to the right scene type by extension.
Config authoring and discovery, all offline. An annotated TOML reference,
an interactive wizard (--init), and a JSON Schema for editor autocomplete —
plus --describe, --list-scenes, --list-overlays, --list-modes,
--compat, and --print-schema, all generated from the same field metadata the
loader itself runs on, so they cannot drift from the code. --doctor collects
every config and environment problem in one pass. Machine-local defaults live in
~/.config/c64cast/settings.toml (written by --save-settings) and persisted
state in ~/.local/share/c64cast/, both XDG-aware.
Packaged demo configs. Every feature has a runnable single-scene demo
shipped inside the wheel: --config example:NAME runs one, --list-examples
lists them all, --print-example NAME copies one out to edit.
Preview and recording. An optional local window mirroring what the C64 is
showing, and recording the same to MP4. Both are cv2-based, so neither needs an
optional dependency.
Documentation. A typeset User's Guide (10 chapters), a full config
reference, symptom-first troubleshooting, an extension guide, and per-module
architecture notes covering the hardware constraints and the dead ends behind
each design decision. Every install instruction and every missing-extra hint
names uv; pipx is documented once as an equivalent fallback.
The guide is attached to every release as a PDF, stamped on its cover with the
version it documents, so a downloaded copy can always be matched to the install
it describes. make guide renders the same thing from a checkout.
A config written by --init or --save-settings carries a #:schema
directive pinned to its own release, so an editor validates it against the
schema this version actually accepts rather than whatever is currently on
main.
A leading ~ works in config-file paths. file, videos_dir,
songlengths_file, charset_path, model_path, a logo overlay's file, the
recording path and log_file all expand ~/… when they are used. A TOML file
has no shell to do it, and glob/os.path treat ~ as a literal directory
name, so such a path previously matched nothing. A Config still holds the
string as written, so serialized configs keep the ~ rather than baking in an
absolute home directory.
Windows is a supported platform. It always worked — casting to a real
Commodore from Windows is a routine path for one of the contributors — but the
published metadata and the User's Guide both called it untested, because CI only
ever ran on Linux. The test matrix now covers macOS, Linux and Windows across
Python 3.11–3.14, so the claim is backed on both halves: the matrix for the
host-side code, real hardware for the pipeline. The one platform difference worth
knowing is that SIGHUP config reload is POSIX-only; POST /reload on the
control plane does the same thing everywhere.