/ concept-collection / commonroom
Sign in
concept-collection / commonroom
commonroom / README.md
5.4 KBPreviewCodeBlameHistoryRaw

commonroom#

Serverless group video calls in the browser.

Live page: https://concept-collection.github.io/commonroom/

Enter your name and a room name — any string you like (no spaces) — and you're in. Share the room URL with anyone; everyone who joins the same room is connected to everyone else over a full WebRTC mesh, up to 8 people. You enter with your microphone and camera off and turn them on when you're ready. Click any tile to enlarge it (the rest shrink to a filmstrip); click it again or press Esc to return to the gallery.

The room has shared settings that anyone can change and that apply to everyone — currently the video quality (low / medium / high / auto, medium by default). You can also share your screen in place of your camera, and there's a room chat (with join/left notices and clickable links) that is as ephemeral as the call itself: you only see what's said while you're in the room, and nothing is stored anywhere.

How it works#

There is no backend and no room registry. The techniques come from the sibling projects commonview (the auto-connecting mesh) and commoncall (WebRTC media, quality presets, screen share):

The relay, and how one token covers a room#

Most pairs of browsers can reach each other directly once STUN has told them their public addresses. Some cannot: symmetric NAT at both ends, or a firewall that only permits outbound 443. Those pairs need a TURN relay, which costs bandwidth and therefore cannot simply be handed to everyone who loads the page.

The arrangement here is that relay credentials are bought with a token, but only one person in the room needs to have one. Whoever has it types it into the landing form; their browser exchanges it at the credential Worker in worker/ for a short-lived ICE configuration, and that configuration is then shared with the rest of the room over the same control data channels that carry chat and settings. Everyone else adopts it and gains relay candidates of their own, so the relay is available to every pair in the room rather than only to the token holder.

What travels between peers is the credential, never the token. The token stays in the browser it was typed into; the credential expires on its own and can be revoked at the Worker. Credentials arriving from a peer are treated as untrusted input and validated down to a bounded list of well-formed ICE URLs before they go anywhere near an RTCPeerConnection.

Note that a credential cannot help the connection that carried it: a peer learns it from the first peer it manages to reach, and uses it for every connection after that. In practice the token holder's own relay candidates are what make that first connection work for a peer that has none. A pair that stalls in the meantime is rebuilt by the ordinary connection retry, which picks up whatever credentials have arrived since, so recovery takes up to about twenty seconds.

The control bar shows where the room's relay came from — your token, another participant's, or none at all. All of this is optional: with no VITE_TURN_ENDPOINT configured at build time the token field is hidden entirely, and calls fall back to STUN plus a free public relay exactly as before. See worker/README.md for deployment and costs.

Development#

npm install
npm run dev

Identity is per-browser-profile (localStorage), so two tabs in the same profile are the same peer — to try a room with multiple participants, use a second browser or a private window.

npm run build type-checks and bundles to dist/. Pushes to main deploy to GitHub Pages via .github/workflows/deploy.yml.

To work on the relay as well, copy .env.example to .env.local and point VITE_TURN_ENDPOINT at a Worker (cd worker && npm install && npm run dev serves one locally on port 8787). The Worker is deployed separately from the page, with npx wrangler deploy.

moveopenescclose