RCWeb Spacewar

Spacewar is one of the early RCWeb asymmetric-game prototypes. It turns a shared screen into a simple multiplayer space shooter while phones act as lightweight steering controllers. More than anything, it is useful as a developer example of the original RCWeb communication style: a viewer app exposes a small public API, controller apps send targeted remote calls into it, and the viewer sends UI updates back to specific controllers.

Icon

icon

Screenshot

screenshot

The Prototype

On the gameplay side, Spacewar is intentionally direct. Each joining phone gets its own ship in the same arena. Ships steer, accelerate, fire missiles, bounce off the arena edges, and respawn with a short invulnerability window after being destroyed. The display keeps the score labels and all combat state in one place.

From a developer perspective, the interesting part is that this version predates the more structured snapshot-driven style used by later RCWeb apps. It is a compact example of how far you can get with only room-scoped JavaScript dispatch and a few exposed viewer methods.

RCWeb Communications

Spacewar uses the classic RCWeb asymmetric pattern:

  • The viewer app runs at /spacewar/ and owns all canonical game state.
  • The controller app runs at /spacewar-control/ and sends input events into the viewer.
  • The viewer redirects any non-viewer client in the room to the controller URL with rc.send(js, "!" + rc.client), using the room id already injected by the server.

The communication style is deliberately simple and very "early RCWeb":

  • The viewer exposes a public API on window.spacewar, mainly controlShip(player, direction).
  • Controllers call that API remotely with rc.sendFunctionCall("spacewar", "spacewar.controlShip", rc.client, "left" | "right" | "forward" | "fire").
  • The controller's rc.client value becomes the stable player id on the viewer side, so the viewer does not need a separate matchmaking layer.
  • The viewer sends updates back to specific controllers by targeting those client ids directly.

This app is therefore a good model when you want:

  • one authoritative display loop
  • tiny controller messages
  • no shared JSON schema beyond a few arguments
  • direct mapping from controller connection to player entity

Why It Matters

For someone building a new RCWeb game, Spacewar shows the minimum viable communication architecture:

  1. The display owns simulation and rendering.
  2. The display publishes a QR code containing /spacewar-control/?r=<room>.
  3. Controllers connect with rc.connect() and only send intent.
  4. The viewer turns that intent into state changes.
  5. The viewer targets feedback back to the specific controller that needs it.

It is also a reminder of the tradeoff in these early prototypes: direct remote code execution keeps the app small and fast to build, but the coupling between viewer and controller UI is tighter than in later snapshot-based apps. For a new RCWeb app, this prototype is still a very useful reference when you want the communication layer to stay minimal and you are comfortable exposing a small public API on the viewer.

DocumentationServer TelemetryServer StatsServer HTTP LogServer WebSocket Log