Alternate-history fiction: Avenell Stagecraft and the Cyclorama console never existed. The hardware described here is real — fully specified, and emulated at playcyclorama.com. Play ERG: NIGHTSIDE RUN

Cyclorama SDKCommand-line reference

Command-line reference

Every tool is a TypeScript file in tools/ that Node runs directly. Most have an npm run script; npm run <script> -- <arguments> passes the arguments on (the -- is npm's). The usage line under each heading is quoted from the tool's own source, so this page and the tool cannot disagree. Tools exit 0 on success and non-zero otherwise: 1 when a build or check fails, and 2 for arguments they cannot use (frame, verify, the test tiers; asm and scrim use 1 for both).

Building

npm run asm: assemble a CYASM program

From tools/asm.ts, lines 4–4

// npm run asm -- input.asm -o out.rom [--sym out.sym] [--lst out.lst]

Assembles input.asm and everything it .includes into a cartridge image, with the header's checksum filled in. An .include "x.art.inc" or "x.song.inc" that does not exist on disk is converted from x.art or x.song. --sym writes the symbol table, one symbol per line: BB:HHHH name for a label (its bank and address) and HHHH name for a constant (its value); --lst writes a listing. Errors print as file:line: error: message and nothing is written. The language is chapter 8 of the manual.

npm run asm -- examples/tutorial-1/step2.asm -o .tmp/step2.rom --sym .tmp/step2.sym

npm run scrim: compile a SCRIM program

From tools/scrim.ts, lines 4–4

// npm run scrim -- input.scr -o out.rom [--asm out.asm] [--report]

Compiles SCRIM to CYASM and assembles it. --asm also writes the generated assembly; --report prints each procedure's size in bytes and its static worst-case cycle count for one pass. Errors print as file:line:col: error: message. The language: SCRIM specification.

npm run scrim -- roms/lantern-scrim/lantern-scrim.scr -o .tmp/lantern-scrim.rom --report

npm run build:roms: every ROM, reproducibly

From tools/build-roms.ts, lines 4–4

// npm run build:roms [-- --write-manifest]

Builds each roms/<name>/<name>.asm or .scr and each conformance ROM in tests/conformance/ into build/roms/. The build is a pure function of the sources; roms/manifest.json records every ROM's size and SHA-256, and the tests require two builds to match it byte for byte. After adding a cartridge folder or changing a ROM on purpose, run it with --write-manifest and commit the manifest with the change.

npm run player: a cartridge as one web page

From tools/build-player.ts, lines 4–4

// npm run player -- <cartridge.asm | cartridge.scr> [out.html]

Builds the cartridge and bundles the reference player with the ROM into one HTML file (default build/player/index.html) that runs from file:// with no network. Keys: arrows = D-pad, Z X C = A B C, Enter = START; a standard gamepad works too. The page title is the ROM header's title.

Running and measuring

npm run conformance: the machine's own tests

From tools/conformance.ts, lines 4–4

// npm run conformance

Runs every conformance ROM in tests/conformance/ twice: each must reach STOP with 600D in work RAM word 8000 and both runs must end in the same state hash. A failing ROM reports the number of its failing check. See Conformance.

npm run budget: what a cartridge costs

From tools/budget.ts, lines 4–6

// npm run budget [-- name... [--frames N] [--replays <dir>]]
// Resource budget report for each cartridge, measured by running the real ROM on the emulator. A
// name is a ROM of the project (roms/<name>/, conformance/<name>) or the path of a .asm or .scr

Runs each cartridge on the emulator (600 frames without input, or its completion replay) and measures what a real console would limit: ROM size and the smallest cartridge board it fits, CPU cycles busy per frame against the 59,736 available, sprites per line against 16, lights per line against 4, and the Cue voices used. A displayed frame that never reaches WAI has overrun. It writes build/budget/<name>.json and exits 1 if anything is over a limit or a completion replay fails. With no names it checks every cartridge and every replay.

npm run budget -- examples/tutorial-1/step2.asm --frames 120

npm run replay: completion replays

From tools/replay.ts, lines 4–4

// npm run replay [-- --dir <folder>]

A completion replay (replays/<name>.replay.json) is the controller input that wins a cartridge, frame by frame. The tool rebuilds the ROM, requires its SHA-256 to match the replay and the manifest, plays the input from power-on, and passes only if the final machine state and the game's own win variable match what the replay records. replays/slice-test.replay.json is one.

npm run frame: a screenshot from the emulator

From tools/render-frame.ts, lines 4–4

// npm run frame -- <cartridge.asm | cartridge.scr | image.rom> <frames> <out.png> [--pad <bits>] [--from <frame>] [--scale <n>]

Runs the cartridge from power-on for the given number of frames and writes the last picture as a PNG. --pad holds controller-1 buttons from frame --from on (bit 0 Up, 1 Down, 2 Left, 3 Right, 4 A, 5 B, 6 C, 7 START); --scale repeats each pixel. The same arguments always give the same bytes: every picture in these guides is made this way and re-rendered by the tests (docs/guide/images/images.json).

npm run frame -- examples/tutorial-1/step2.asm 40 .tmp/step2.png --pad 9 --from 10

node tools/song-wav.ts: hear a song

From tools/song-wav.ts, lines 4–4

// node tools/song-wav.ts [cartridge.asm] [--song SONG_name] [--seconds N] [--out file.wav] [--skip-frame F]

Runs a cartridge until the Cue Sound Driver starts the named song, then records the Cue's output to a 16-bit mono WAV at its own sample rate (47,940 Hz). The default is the Sound Test's theme. It also prints the driver's measured cost per frame.

npm run golden: golden frames

From tools/golden-frames.ts, lines 4–4

// node tools/golden-frames.ts [--update]

Plays each completion replay and compares the picture at a few checkpoints with tests/golden/frames.json and its reference PNGs; a mismatch writes the expected, actual and difference pictures to .tmp/golden/. --update rewrites them (only after a deliberate change of what a cartridge draws).

Checking

npm run verify: the whole gate

From tools/verify.ts, lines 6–6

//   node tools/verify.ts [--allow-dirty] [--part <static|emulation|browser>]... [--list]

Every check in order, each in its own process with a timeout: the doctor, the type check, the ROM build, budgets and completion replays, the conformance ROMs and every test tier. It prints one PASS or FAIL line per step and writes each step's full output to .tmp/verify/. --part runs one part (static, emulation or browser) as CI does; --list shows the plan; --allow-dirty lets the doctor pass with uncommitted changes.

npm test and the test tiers

From tools/test-tier.ts, lines 5–5

//   node tools/test-tier.ts <fast|slow|browser|node|all>[,<tier>...] [--list] [<node --test flags>] [-- <flags>]

npm test runs every tier; npm run test:fast, npm run test:slow and npm run test:browser run one. A test file's tier comes from what it does: browser files import Playwright, slow files carry a // test-tier: slow line (whole-game playthroughs), everything else is fast. CYC_TEST_CONCURRENCY=<n> sets how many files run at once. See Testing.

npm run coverage

From tools/coverage.ts, lines 4–4

// npm run coverage [-- --tier fast|node] [--enforce]

Line, branch and function coverage from Node's built-in coverage, written to .tmp/coverage/ (an lcov file and a summary). The thresholds are reported, and fail the run only with --enforce.

npm run doctor and npm run typecheck

From tools/doctor.ts, lines 4–4

// npm run doctor [-- --allow-dirty] [--no-browser]

The doctor checks the Node version against .nvmrc, every dependency's installed version against package.json, that headless Chromium launches, and that the git working tree is clean. npm run typecheck runs the TypeScript compiler over the whole tree without emitting anything.

npm run typecheck

node tools/doc-check.ts: the docs are real

From tools/doc-check.ts, lines 6–6

//   node tools/doc-check.ts [file.md ...]      (no files: the SDK docs of this tree)

Checks the guides: every relative link resolves, and every code block is either an exact excerpt of a file the tests build or run, marked <!-- sample: path lines a-b -->, or shell commands this tree can run. See CONTRIBUTING.md ("Docs are code").

Other scripts