Distributed Mesh — Overview
The system could have been built with a central server: one Mac that all iPhones connect to, coordinating all decisions. That was the original architecture (the multicam-server at `:9404`).
Full Public Reader
Distributed Mesh — Overview
Why Distributed
The system could have been built with a central server: one Mac that all iPhones
connect to, coordinating all decisions. That was the original architecture (the
multicam-server at `:9404`).
The distributed architecture replaced it for specific reasons:
- No laptop in the room: for outdoor shoots, location shoots, and portable
setups, there's no Mac. The distributed model makes the system work on any
shared WiFi, including a phone hotspot.
- Single points of failure hurt: if the Mac goes down, the show stops.
In the distributed model, each device is self-contained.
- The devices already have everything they need: iPhones have cameras, microphones,
processors, and network stacks powerful enough to run the full pipeline
independently. There's no reason to centralize functions they can perform locally.
- Less total code: the distributed model deletes the dependency on a 13,000-line
Rust server (multicam-server) instead of porting it to yet another platform.
The Four Documents in This Section
[camera-node-contract.md](camera-node-contract.md) — The full HTTP + SSE API
contract that every camera node (iPhone) must implement: all endpoints, request
formats, response formats, error handling, Bonjour advertisement spec.
[stageview-console.md](stageview-console.md) — How StageView discovers nodes,
manages connections, fans out commands, displays live feeds, and shows the contact
sheet. The three discovery paths (Bonjour, mDNS hostname prober, subnet scanner).
[mesh-topology.md](mesh-topology.md) — The full device map: every device, its
role, its IPs (LAN + Tailscale), what services run on it, and how devices connect
to each other.
The Network Contract
All devices communicate over HTTP + SSE on port 8081. No custom protocol,
no binary framing, no WebSocket (for the camera-control path).
This was chosen deliberately:
- HTTP is debuggable with curl
- SSE is one-directional push, which is exactly what camera events need
- Any device on the network can talk to any camera node with zero setup
- Port 8081 is fixed across all iPhones — no port negotiation needed
MJPEG streaming (`/stream`) is also HTTP — `multipart/x-mixed-replace` — which
makes it renderable in a standard `URLSession` without any special media framework.
The Bonjour Discovery Protocol
Camera nodes advertise themselves as `_mmcam._tcp` with TXT records containing:
deviceName = "iPhone 16 Plus"
model = "iPhone17,2"
role = "camera"
apiPort = "8081"StageView's `NetServiceBrowser` discovers nodes automatically as they appear on
the network. A node that joins the network (after being turned on, or joining
the WiFi) is discovered within 1–3 seconds via Bonjour.
The subnet scanner and mDNS hostname prober fill gaps:
- Nodes that are already on the network before StageView launches (Bonjour
announcements may have been missed)
- Nodes on different subnets than the iPad (e.g., iPhone 16 Pro Max on 10.0.0.x
while iPad is on 192.168.1.x)
Tailscale for Remote Access
All devices have Tailscale installed, assigning them stable 100.x.x.x IPs:
- These IPs work regardless of WiFi network
- They allow Mac1 to access the iPhones even when they're on different LANs
- The multicam-server (Mac1:9404) uses Tailscale IPs to register all three phones
For StageView, Tailscale is the fallback when a device is not reachable on LAN.
The manual IP entry field in StageView accepts Tailscale IPs directly.
Promotion Decision
Promote into a technical note or architecture paper with implementation anchors.
Source Anchor
computational-choreography/06-distributed-mesh/overview.md
Detected Structure
Method · Architecture