Getting started
Requirements
Section titled “Requirements”Node 22 or later and pnpm 11. The repo is a pnpm workspace; nothing is published to npm.
Install
Section titled “Install”git clone https://github.com/mcp-tool-shop-org/mcp-arcade-cabinets.gitcd mcp-arcade-cabinetspnpm installPlay in the browser
Section titled “Play in the browser”pnpm -F @mcp-arcade-cabinets/cabinets devOpen the address Vite prints. The tape list shows a difficulty label (fixture, seat, or live) derived from the tape’s header and wire shape. Hover the i for the why: how the server was reached, how many waves and bosses, how dense the wire is. The why never mentions a fact. Press Play. The published site also serves the game at Play Ghost on the Menu with every tape bundled. The landing page header Play link goes there too.
Controls
Section titled “Controls”| Key or control | Does |
|---|---|
| Left / Right, or A / D | Move the ship |
| Space | Fire |
| F, or the Full screen button | The field alone, letterboxed, full screen |
| Click the field | Restart the same tape once the round has ended |
| Next tape | On the end scene, play the next fixture tape in the list |
| Shift | Four calls drawn from the roster, back to back, with a card between them; the lamps refill at every call and the bursts climb call by call. Its own difficulty select beside it. |
| (shift code) | Four words the closing scene spells, like frost robin chalk garden. Type them in the box and press Replay to take the same shift again, or hand them to someone. A code from another menu of tapes says so. |
| Next call / End the shift | On a call’s end scene, the next card, or the closing scene after the last call |
| Sound on / off | Mute; sound starts on the first key or click |
| feel: calm / medium / loud | How much the field shakes and how big the pops are |
| shake | Turn the shake off entirely; hitstop and the trophy stay |
| difficulty | As recorded, seat, live, or hardcore |
| Ollama bosses | Local daemon or Ollama Cloud. The model sits in the boss through the cabinet server’s own tools: it calls each boss’s shots and writes the boss’s lines behind a gate (twelve words, one sentence, no digit, no fact word, no tool or model name; a refused line plays one of the boss’s own). It never sees lies. Pages cannot reach it. |
| (model list) | Cloud tags first when ollama signin has pulled :cloud models. The say seat sits a Claude agent instead when ANTHROPIC_API_KEY is set for the dev server; the key never reaches the browser. |
| (seat status) | Two words beside the picker, one per seat: warming, thinking, the tool each called (seat called fire: spread, seat called say (cloud)), or why it fell back to the script or the boss’s own line. Never on the field. |
| Voice | The boss speaks its lines in its own preset voice through the local voice worker (pnpm voice in another terminal). Every take is heard back and receipted by fx-dub before it plays; a failed receipt is never played; a take that misses its beat waits for the breather. Enabled only when the worker answers; Pages never has one. |
| (voice status) | voice ready, voice speaking ahead, voice: receipt ok, voice: spoke on the beat, voice: held for the breather, voice: receipt failed, not played, voice: no worker. Words only. |
Difficulties
Section titled “Difficulties”A tape carries the tier it was recorded at: a fixture is tier 0, a seated run on a lab server tier 1, a live server tier 2. As recorded plays the tape at its own tier. Seat and live force the tier, so any tape can be played harder. Seat is the default: at tier 0 the formations neither fire nor dive, which is honest to the recording but not much of a fight.
- Tier 0, as recorded: only the boss fires, slowly. A gallery with teeth.
- Seat: formations fire straight down and dive; the boss aims at you. A player who keeps moving loses about a lamp a round.
- Live: faster, denser, the boss rages sooner. Meant to be survived, not cleared; a careful player finds every lie about half the time.
- Hardcore: never derived from a tape. One lamp, rage from the first shot, boss hazards (echoes, bands, plates). Later waves fire faster. The scripted reader is not a human; a person who dodges can take it.
Seat, live and hardcore also get parallelism bursts: extra honest copies, hotter fire, and the music sped up under them. The first burst is a blink; later waves hold it longer. Recorded tapes stay a gallery.
The music: a round opens on one of the five wave beds, picked by the round’s seed, holds it for two minutes, then rotates to the next; a boss wave brings its boss’s bed once the hold is up. In a shift the music carries through the cards, so four calls hear a run of beds. There is no burst track; a burst speeds the playing bed up and lets it back down.
A downed boss drops a lamp that falls straight down; a cleared formation drops a spread the same way. Move under them. The wave card carries a dry line in the voice of an agent, and the boss enters with another. Short asides keep talking during the wave.
The shift
Section titled “The shift”A shift is a run of four tapes as one agent session: the rig has a task list and you are the one it sends. The draw is seeded from the clock, never from anything on a tape, and it stays fresh against the last two shifts your browser took. Between calls a card names the next tape, its server, its policy and the tools the agent was asked to run, in header words only. The difficulty is the shift’s, fixed by its code. The climb is data (patterns/shift.json says how far up each call sits; copiesShift and intensityShift in parallelism.json are the reach the last call ends on): the last call’s bursts start where a tape played alone would end. Measured on the band: as the last call at live, the scripted mover dies on nine tapes of twenty against five alone, and still survives half the roster with half the lies found.
The closing scene lists the four calls and spells the code. Nothing is ranked, counted or scored; the code carries the draw, the difficulty and a check of the roster, and nothing else.
Prove a round from the terminal
Section titled “Prove a round from the terminal”pnpm test:play ghost --fixture naive-ndjsonA scripted bot (the reader, which fires only at the sequence tells) plays a whole round and the runner prints a transcript: the tape, the server, the policy, the end scene’s words, and the lies it revealed. It exits non-zero if any lie was missed or if a forbidden word or a digit reached the screen. Three tapes run this way in CI.
Look at a round without a browser
Section titled “Look at a round without a browser”pnpm film --fixture naive-ndjson --bot reader --tier 1 --times 6,14,22,35Writes one PNG per listed second under film/, drawn through the same renderer the shell uses, with rectangles instead of sprites, plus a line per frame naming every live sprite and its position.