# Couch Arcade Live

One shared two-player game. The display shows the match. Each phone is the controller for the role it was assigned. Phone port 1 is the first controller. Phone port 2 is the second. A phone cannot choose the other player's number.

This example was run on Dozer Dev with one owned display emulator and two owned phone emulators. A Codex test operator pressed the pads with real native touches, including both phones together. It is not a physical television, not a physical-phone test, and not two human players. No completed round was claimed: the fight was reached, and a connecting hit or finished stock was not shown.

## Prerequisites

Use a Linux desktop running Dozer Dev, and a normally configured project agent for the generated project. Pair one owned display emulator and two owned phone emulators. This example used a direct Iroh path to those receivers. Each receiver must answer with its own local Allow once. Pairing is not that consent.

The published Home request comes first. It asks the agent to create the project and its files. The build commands below are then run inside that generated project. They are not commands for an empty folder, and they do not launch an emulator process.

## Game and dependencies

The running core is JSNES 2.1.0, Apache-2.0, using its built-in Mapper 2 UxROM support. The offline game is Super Tilt Bro, title version 2.6, mapper 2, NES 2.0. The bundled game note says Super Tilt Bro is free for any use under the WTFPL. A separate native emulator package is not this example and is not required to repeat it.

Tested dependency hashes:

| Piece | SHA256 |
| --- | --- |
| JSNES 2.1.0 package | `167081846a907e19bdd7cba75c648d827d49ea50e0fb58c079ad1a6613dee3c1` |
| JSNES built core, 135545 bytes | `84946f0dae4bcf3b2dfebe84ad3bfeb1dbcb413bd9b1a69e1f45910a95fd7b41` |
| Super Tilt Bro 2.6 ROM | `847155bb712e474f71554174c9d9ed402bf651b13ff1e4afc9a42ec69cd03d8d` |

Inside the generated project, the previously successful commands were:

```sh
node arcade/build.mjs
node arcade/test-session.mjs
```

Both exited 0. They are shown here as that record. They were not run again for this note.

## Open one room

Ask the project agent to open the registered arcade gadget as one room. The display is the display because it has no touch. The two phones are the controllers. Phone port 1 is controller slot 0. Phone port 2 is controller slot 1.

Allow once on each receiver. A waiting screen is not a loaded page. A ready word is not play. Each phone should show Connected and Waiting for New match. The display should show the title.

## New match and manual menus

Press New match on a phone. That button runs an automatic menu script on the one shared game. The words Setting up two-player match and Ready to play are that script's labels. They are not phone presses. A real match is the Flatland fight on the display.

Manual menus are optional and separate. If you do not use New match, player 2 starts as a CPU. Set player 2 to Human, confirm both portraits, hold Start through the stage name, then both press Attack. That also starts the fight. Do not describe those manual presses as what New match did.

## Controls

The pad is landscape. Up jumps. Down shields. Left and Right move. Attack and Special can be held with a direction. Start confirms menus. Lifting one finger releases only that finger's buttons.

On this run the Codex operator used real native touches on each phone and on both together. Combined holds reached the correct player, and releases cleared. A 75-second recording completed at about 20 recorded frames per second. That rate is the recording, not the emulator's speed, and it is not a completed-round claim.

## Link loss

If one phone loses its link, its held buttons clear. The display and the other phone can keep answering. When that same phone process and role return, a later real press can work. That return is not a Stop, and it does not by itself prove the old fight is still on screen.

## Stop and same-role return

Use that phone's own native Stop while a direction and an action are held. The page goes blank or waiting. On this run both phones did that. The holds were empty at the 3-second observation. A check in the first second can still see the hold, so do not claim it clears instantly.

An old real press from the stopped page is refused because that presentation page is no longer allowed. The observed refusal was not HTTP 403.

Ask the room owner to use Try again, then Allow once again on that same phone. It must return as the same player and role. The new page gets a new native capability. A new hold and release can work. On this run that return put the shared game back at the title and Waiting for New match. Do not expect the fight to continue through Stop. The recording and a link-loss return are not this Stop proof.

## Close

When the example is finished, ask the owner project agent to close only its arcade room. Do not ask it to close another room, and do not treat closing as another play test. The repeat described here is already closed.

## What the supervised follow-ups showed

Control: native touches on each phone and both together moved only the assigned player. Releases cleared. New match is the automatic script. The manual Human, portrait, and stage steps are a different path.

Recovery: a phone-only link loss cleared holds while the display and the other phone kept answering, and the same role could press again after the link returned. Native Stop on both phones cleared holds by the 3-second observation. Old presses failed at the presentation capability boundary, not as HTTP 403. Same-role Try again plus a fresh Allow once issued a new capability and accepted a new hold and release. Stop and that return reset the game to the title.

Layout: the display had been reserving native chrome twice. The page used for the closed repeat reserves it once, keeps the full 256 by 240 frame with `object-fit: contain`, and does not crop or stretch it. The repaired pixel sizes are arithmetic for a 16 pixel rem and a zero safe area. They were not measured again on the display emulator.
