Headless & automation
Bizmuth runs without a window, which makes it a good fit for automated testing, regression checks and CI. Certain flags switch it into a batch mode: boot, run a fixed number of frames, do one thing (capture a frame, record video, dump state), then exit — no display, no throttling, as fast as the host allows.
Any of these flags triggers a headless run-and-exit:
| Flag | Batch action |
|---|---|
--screenshot <file.png> | run, save one PNG, exit |
--video <file.png> | run, save every frame as an animated PNG, exit |
--savestate <file> / --savestate-raw <file> | run, write a full savestate, exit |
--state-json <file> | run, write the machine state as JSON, exit |
--dump-snapshot <file> | decompose a snapshot and exit — no emulation at all |
Everything below composes: pick what to load, how to drive it, how long to run, and what to capture.
Capturing a frame
--screenshot runs --screenshot-frames frames (default 600 — ~12 s at 50 Hz, enough for the Next firmware to reach the video-mode screen), writes the PNG, and exits:
bizmuth --machine next --sd card.img --screenshot out.png --screenshot-frames 1600The PNG is the whole composited frame. To capture individual layers (ULA / LoRes / tilemap / Layer 2 / sprites) or an off-screen bank, drive the machine over ADP (screenshot <path> <layers>, bankshot) or from a Rhai script instead.
Recording video
--video out.png records every frame of the run into a single animated PNG (APNG), then exits — so --screenshot-frames sets the clip length. Useful for reviewing a boot sequence or a scripted demo run frame by frame.
Driving input headlessly
With no keyboard attached, you inject input one of four ways — from simplest to most capable:
| Flag | Effect |
|---|---|
--select | press ENTER once, when the NextZXOS browser is up, to launch the highlighted item |
--auto-keys [frame] | auto-press ENTER then Y starting at frame (bare flag → frame 160) — clears the usual boot prompts |
--keys "<f>:<tok> …" | a frame-timed key script: space-separated frame:token pairs, e.g. --keys "1300:enter 1360:enter" |
--script <file.rhai> | full Rhai control — key injection plus conditional logic, state reads and breakpoints |
Key tokens are the same as the ADP shorthands (enter, down, up, left, right, space, y, n, …). For anything conditional (“press ENTER once the menu settles”, “launch the third entry then screenshot”), reach for --script — see the Rhai on_menu_idle example.
# Boot, navigate two entries down and launch, run to frame 1600, capture:
bizmuth --machine next --sd card.img \
--keys "1300:down 1320:down 1340:enter" \
--screenshot out.png --screenshot-frames 1600Loading content
| Flag | Loads |
|---|---|
--machine <kind> | 48k / 128k / plus2a / plus3 / next |
--sd <img> (--sd0/--sd1) | SD card image(s) for the Next; --sd-ro opens read-only (writes kept in a RAM overlay) |
--nex <file> (--snapshot) | a .nex, or a .sna/.snx/.z80, via the host loader after boot |
--tape <file> | a .tap / .tzx tape |
--loadstate <file> | restore a full savestate and continue — skips boot/navigation entirely |
--loadstate is the fastest way to reach a known machine state for a test: capture a savestate once at the point of interest, then load straight into it on every run instead of re-driving the boot.
Dumping state
| Flag | Writes |
|---|---|
--savestate <file> | a full compressed savestate (AZST) after the run |
--savestate-raw <file> | the same, uncompressed (raw bincode) — wins over --savestate |
--state-json <file> | the machine state as JSON — diff-friendly for assertions |
--dump-snapshot <file> | decompose a .sna/.snx/.z80 and print it, then exit (no emulation) |
Tracing & audio diagnostics
| Flag | Effect |
|---|---|
--pc-trace <file> | append every instruction’s pc sp to a file (Next only; unbounded) |
--pc-trace-from <f> / --pc-trace-to <f> | gate the trace to a frame window (keeps it manageable) |
--esxdos-trace | log every esxDOS/NextZXOS RST $08 call (Next only) |
--wav <file> | dump the mixed speaker output (raw interleaved f32 LE) |
--wav-sources <dir> | capture each source (beeper / AY / DAC) as its own unity-mono file (mixer-balance measurement; windowed) |
For anything more selective than a full instruction trace — gating on a condition, watching a memory range, backtracing a crash — use a conditional breakpoint or a Rhai script rather than --pc-trace; see Conditional breakpoints and Rhai scripting.
Emulation faithfulness toggles
These are on by default (hardware-faithful); the flags turn them off for a run — only for diagnosing a divergence, never for normal use:
| Flag | Disables |
|---|---|
--no-mem-wait | the 28 MHz SRAM read-wait |
--no-im2-daisy | the IM2 hardware daisy-chain interrupt vector |
--max-speed <n> | caps the CPU-speed selector exponent (0=3.5, 1=7, 2=14, 3=28 MHz) |
Regression checks
A behaviour-preserving run is deterministic, so a captured screenshot is a stable fingerprint — byte-compare it against a known-good baseline to catch regressions:
bizmuth --machine next --sd card.img --screenshot new.png --screenshot-frames 1600 \
&& cmp baseline.png new.pngThis is exactly the boot-regression check the project uses: any change that shouldn’t alter output must keep the Next boot screenshot byte-identical. --state-json gives a coarser, text-diffable alternative when you care about register/paging state rather than pixels. And because every --script event and state read works headlessly, richer assertions can run with no display at all — see Rhai scripting.