diff --git a/README.md b/README.md index c07490d..07559e1 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,41 @@ # game-controller -Phone/controller client for **Space Console** — turns a phone into a game -controller that joins a launcher (the TV) via a short room code, AirConsole-style. -Pairs with the `game-launcher-web` repo (the TV/screen side). +The **phone/controller** app for **Space Console** — turns a phone into a game +controller that joins the launcher (the TV) by a short **room code** or a scanned +QR, AirConsole-style. Pairs with the `game-launcher-web` repo (the TV/screen side). + +It opens a **WebRTC DataChannel straight to the TV** and sends input peer-to-peer; +the `web-api` service only brokers the handshake (room code + SDP/ICE) and vends +STUN/TURN. The controller renders whatever pad the running game asks for over that +channel: + +- a **d-pad** + action buttons for menus and classic games; +- a **landscape analog driving pad** (steering joystick + gas / brake / drift, + with optional tilt steering) for racing games, streamed as continuous frames; +- **name entry** on join (shown in the TV's player roster), and **auto-rejoin** + if the tab is backgrounded or the network blips. Zero-build, zero-backend static site — plain ES modules, no bundler, no framework. Open `index.html` and it runs. ```sh -npm install # dev server only -npm run dev # http://localhost:5174 (auto-reload) +npm install # dev tooling only +npm run dev # http://localhost:5174 (auto-reload) ``` -This is an early **placeholder**: a join screen + a stubbed control pad whose -transport (`assets/js/session.js connect()/send()`) is a seam to fill in with a -real WebSocket / WebRTC / AirConsole client. +## Transport + +The client lives in `assets/js/session.js`: + +- `send(intent)` — a discrete button press (`up/down/left/right/enter/back`, plus + game-declared aux buttons like `reset` / `powerup`). +- `sendAnalog(steer, throttle, brake, handbrake)` — a continuous driving frame. + +Both go over the DataChannel; the TV relays them into the running game. Signaling +defaults to the page's own origin, and ICE/TURN is fetched from the server at +`/api/ice` (a `?signal=` / `?turn=` query param can override per device). For real +phones, the controller, the launcher and the signaling socket must share **one +origin** — the `web-api` repo serves them together (see its README). ## Documentation