An arcade cabinet feels finished when the games launch, the controls respond, the marquee changes, and the buttons glow.
That is usually the moment when nobody thinks to write the manual.
The wiring is still fresh in memory. The unusual startup command is obvious because it was edited yesterday. We remember which controller must use X mode, why one group of RGB pins appears backwards, and which service creates the virtual Player 1 device. If something breaks, surely we will remember what we did.
Then six months pass.
The cabinet still looks like one machine, but it is actually a collection of systems that happen to start together: Raspberry Pi hardware, a Linux operating system, RetroPie, EmulationStation, emulator cores, an I-PAC, wireless controllers, virtual input devices, RGB lighting, a Pixelcade marquee, a Sinden Lightgun, launch hooks, metadata tools, ROM collections, BIOS files, configuration archives, and a four-terabyte SSD.
The hard part of maintaining it is rarely remembering that those components exist. It is remembering why they were connected in precisely this way.
That is why we wrote an owner and service manual.
A custom cabinet is an integration, not an appliance
A commercial appliance usually has a defined model number, a factory configuration, and a manual written by the organization that designed the whole product.
A custom arcade cabinet has manufacturers for its individual parts, but no manufacturer for the assembled system.
Ultimarc can document the I-PAC Ultimate I/O. Raspberry Pi can document the computer. RetroPie can document its setup scripts. Pixelcade can document its listener. Sinden can document the lightgun. None of them can describe what happens when all of those components share this cabinet’s USB buses, startup sequence, controller mappings, lighting rules, and recovery process.
Only the owner can document the integration.
Our manuals therefore serves three different purposes:
- a quick operating guide;
- a reference to the emulators used and different configurations;
- a technical service reference; and
- a disaster-recovery starting point.
Those purposes overlap, but they are not identical. The person turning off the cabinet needs a short, safe procedure. The person diagnosing a missing Player 2 controller needs device identities, service names, and expected mappings. The person rebuilding a failed drive needs file locations, dependencies, backups, and evidence of the last known-good state.
Trying to make one undifferentiated list satisfy all three audiences produces a document nobody can use. We organized ours around questions.
Start with the questions a future owner will ask
The manual’s navigation is based on practical needs:
| Question | Information required |
|---|---|
| How do I start or shut down the cabinet safely? | Power sequence, front-end procedure and expected startup behavior |
| What hardware is installed? | Exact models, quantities, connections and intended roles |
| Why does this USB device have several names? | Kernel nodes, stable identities, aliases and physical topology |
| Which controls should work for each player? | Physical layout, raw inputs, logical mappings and known exceptions |
| Why are these RGB pins backwards? | Wiring evidence and the required Player 2 BGR compensation |
| What starts automatically? | Services, launch hooks, dependencies and expected status |
| Which emulator runs this title? | System defaults, per-game overrides, BIOS requirements and test titles |
| What do I back up? | Configuration payloads, ROM and BIOS boundaries, full-drive image and checksums |
| How do I know a repair worked? | Commands, expected results and end-to-end tests |
This changes the tone of the document. It is not a catalogue assembled for its own sake. Every detail should help someone operate, diagnose, change, or recover the machine.
Record what is observed, not what seems likely
The cabinet provided an early example of why assumptions are dangerous.
The Raspberry Pi 4 has a 64-bit processor. The running kernel reports aarch64. It would have been natural to describe the installation as a 64-bit operating system.
The live package architecture told a more precise story:
Hardware: Raspberry Pi 4 with a 64-bit-capable CPU
Kernel: aarch64
Userspace: 32-bit armhf
OS release: Raspbian GNU/Linux 10 (Buster)
That distinction explained why a 64-bit Pixelcade executable could exist on disk yet fail with the misleading message No such file or directory. The program required a loader that the 32-bit userspace did not provide. Replacing it with the correct ARMv7 build resolved the problem.
“Raspberry Pi 4” was true but insufficient. “64-bit kernel” was also true but insufficient. The combination of hardware, kernel, userspace, and actual executable format was the useful fact.
We use that standard throughout the manual:
- live output is stronger than an assumption based on hardware;
- a running process is stronger than an installer description;
- an exact device property is stronger than a temporary
/devnumber; - a photographed lighting result is stronger than an attractive-looking XML file; and
- a game tested from launch through exit is stronger than a configuration that merely parses.
Document reasons as carefully as settings
A configuration file can tell a future maintainer what value is present. It rarely explains why changing it would be a mistake.
Player 2’s RGB pin triplets are a good example. They descend where Player 1’s values ascend because that side of the panel is physically wired in BGR order. Tidying the numbers would swap red and blue across the right side of the cabinet.
The I-PAC provides another. It is kept in Dual DInput mode because the panel must appear as two game controllers while the cabinet’s real keyboard remains available to emulated computers. Returning it to keyboard mode might simplify one old tool while reintroducing conflicts throughout the rest of the system.
The controller merger exists because four physical gamepads should become two logical players:
I-PAC Player 1 + first 8BitDo ──> Arcade Merged Player 1
I-PAC Player 2 + second 8BitDo ──> Arcade Merged Player 2
The trackball merger is activated only for listed games because globally taking control of mouse-like devices would interfere with classic computers, adventure games, and other pointer-driven software.
The Pixelcade listener uses a USB by-id path because ttyACM0 and ttyACM1 exchanged roles after reboot. The numbered nodes were observations from one boot, not hardware identities.
These explanations turn configuration trivia into engineering decisions. Without them, a future repair can easily undo the solution while appearing to simplify the system.
Map the whole path from hardware to game
Input problems are particularly hard when documentation stops at the physical panel or begins only inside an emulator.
Our manual follows the path through every layer:
Physical button or controller
↓
Linux input device and USB identity
↓
Translation or virtual-device service
↓
RetroArch player assignment
↓
Emulator or MAME input type
↓
Observed behavior in a game
That path revealed details which would otherwise be almost impossible to reconstruct from memory. Player 1 and Player 2 report Coin and Start in opposite raw button order. The virtual-controller service normalizes those inputs before RetroArch sees them. MAME uses the resulting stable Joy 1 and Joy 2 devices, with global input types named START1, START2, COIN1, and COIN2.
The manual also records known imperfections. At the time of testing, the fourth action-button column did not emit DInput events. That is not hidden simply because most games do not need those buttons. A service document should distinguish “working and verified,” “installed but untested,” and “known follow-up.”
Give every custom service an address
Custom integrations become much less mysterious once their active locations are recorded.
The manual and its companion technical reference identify components such as:
/usr/local/sbin/arcade-gamepad-merger
/usr/local/sbin/arcade-trackball-merger
/usr/local/sbin/arcade-trackball-game-hook
/etc/systemd/system/arcade-gamepad-merger.service
/etc/systemd/system/arcade-trackball-merger.service
/opt/retropie/configs/all/runcommand-onstart.sh
/opt/retropie/configs/all/runcommand-onend.sh
/usr/sbin/rgbcommander/rgbcmdd.xml
/opt/retropie/configs/all/autostart.sh
A useful service entry includes more than a pathname. It explains:
- what starts it;
- which hardware or files it depends on;
- what other component consumes its output;
- how to check whether it is running;
- where its logs appear;
- what normal success looks like; and
- what else will fail if it is absent.
This allows troubleshooting to proceed in layers. We can ask whether Linux sees a physical controller, whether the merger reads it, whether the virtual device exists, whether RetroArch selects it, and whether MAME receives the expected input. “The controls do not work” becomes a series of answerable questions.
Use test titles as part of the documentation
An emulator inventory tells us what is installed. It does not tell us whether the surrounding integration works.
We record representative games as regression tests. Bubble Bobble helped verify two-player MAME controls. Demon Attack became the recovery and regression title for the custom IBM PCjr cartridge launcher. Marble Madness verifies the conditional trackball merger.
A named test title is valuable because it fixes several variables at once:
- the ROM exists;
- its launch path is known;
- its emulator selection is known;
- its controls have an expected behavior; and
- a previous successful run provides a comparison.
“Test the PCjr” leaves too much room for interpretation. “Launch Demon Attack and confirm immediate joystick movement, firing, and a clean status-zero exit in the launcher log” is a service procedure.
Separate quick backups from complete recovery
Our RetroPie installation occupies a four-terabyte SSD. A raw drive image is the most complete recovery artifact because it captures the partition table, boot files, operating system, installed software, configuration, and data exactly as they exist.
It is also enormous and slow to create.
The manual therefore defines two complementary backup levels.
Configuration snapshots
Frequent snapshots preserve the files that embody our custom work:
- RetroPie and emulator configuration;
- virtual-controller and trackball scripts;
- systemd services;
- launch hooks;
- RGB Commander configuration and animations;
- controller profiles;
- current gamelists;
- metadata tools; and
- selected recovery records.
The backup and restore scripts are kept payload-symmetric: every archive the backup creates has a corresponding restore path. Manifests, checksums, and README records are used to validate a snapshot rather than being copied blindly into the live filesystem.
Full-drive images
A full image is slower but protects against failure of the boot drive or the loss of installed package state. The manual records the SSD’s model, capacity, partition scheme, and observed macOS disk identifier—while warning that the identifier must be reconfirmed every time.
That warning is not decorative. Reversing the input and output of dd can destroy the wrong disk.
I keep one precious backup image, two current backup images on two NASes, and offsite backups with friends.
ROM and BIOS preservation is also stated explicitly. The configuration snapshot intentionally excludes BIOS files. The complete BIOS directory and ROM library require their own preservation strategy or the full-drive image. I have several copies of both across my two NASes and an additional hard drive.
A backup policy is only trustworthy when it records what is absent as clearly as what is included.
Add photographs and a change log
Some cabinet facts are easier to prove visually than verbally.
We retain photographs of the default illuminated panel – a ColecoVision calibration pattern, and the console at boot up. Those images establish physical button positions and show what a successful lighting profile looked like on the real hardware.
The change log then records when a behavior changed and how it was validated. Entries include XML checks, live service inspection, hardware tests, game launches, backup audits, and recovery dry runs.
This prevents the manual from pretending to be timeless. It is a record of a changing machine. A statement verified against the running cabinet has a date and a basis. When the system changes again, we know which conclusions require retesting.
Writing the manual with an agent
The manual itself was developed through agentic work under my direction.
That did not mean asking an AI to invent documentation from a list of products. We used the agent to inspect the real system, correlate configuration files, read service status and logs, compare documentation with live behavior, identify contradictions, organize the results, and maintain both focused references and the consolidated manual.
I built up trust in the agent. I started small with some small fixes, and built up to granting it full access to my Retropie console to make direct changes as we fixed issues and built tools. It preformed flawlessly and that built up a corpus of knowledge about the inner workings of the console. It completed months of work in a matter of a few days.
I supplied the intent, physical context, acceptance decisions, and hands-on validation. The agent supplied persistence across hundreds of small details and the ability to trace relationships that crossed several subsystems.
This division of work proved particularly useful during documentation audits – a human MUST be in the loop, and the agent provided a wholistic view of everything.
A claim in one guide could be compared with the running operating system, a service file, the contents of a backup script, and the behavior recorded in another troubleshooting session. When the evidence disagreed, the document was corrected rather than averaging the stories together.
Human-in-the-loop matters here for the same reason it mattered in the metadata project. A generated paragraph can sound authoritative while being wrong. The cabinet, its files, its logs, and its observed behavior remain authoritative. The agent helps turn that evidence into durable knowledge.
That’s what people miss about using artificial intelligence – a human is prescriptive, directs and provides clarity, and a human must be in the loop to review.
The manual is part of the machine
The final documentation is not one giant file trying to contain everything. The owner and service manual provides the map, while companion references hold detailed lighting profiles, controller integration, maintenance tools, and the system-and-emulator inventory. Markdown remains easy to search and revise; generated PDFs provide convenient archival and offline copies.
The documentation archive belongs beside the working cabinet and beside its backups. If the only copy of the recovery instructions lives on the drive that fails, that is not a recovery plan.
More importantly, the manual is treated as another maintained component. When we add a system, change a controller mode, update a service, alter the USB arrangement, or discover that an old assumption was wrong, the documentation changes with it.
That may be the most important idea in the entire project.
The cabinet’s most valuable knowledge is not merely which files exist. It is why the machine works, how we know it works, and how to recognize when it no longer does.
Nobody thinks to write that manual while the attract mode is running and everything feels finished.
We did—and the cabinet is more maintainable because of it.





