Private, real-time co-commentary rooms inside desktop Lichess broadcasts.
Relay Room adds private co-commentary rooms directly to desktop Lichess broadcasts.
- Invite another commentator with a room link.
- Follow any connected commentator’s game and exact move.
- Follow local analysis variations, even when the branch does not exist yet on the other board.
- Promote a co-commentator to room admin.
- Share arrows and circles through Lichess’s existing Chessground renderer.
- Drag the Relay Room panel to any convenient place on screen.
- Let either commentator lead; following is directional.
- Reconnect automatically through a persistent anonymous SpaceTimeDB identity.
Relay Room does not modify the Lichess broadcast, its PGN, or its saved annotations. It runs only on
https://lichess.org/broadcast/*.
The distributable extension is already configured for:
- SpaceTimeDB server:
https://maincloud.spacetimedb.com - Database:
sagar-cbi-r69i7 - Database dashboard: https://spacetimedb.com/sagar-cbi-r69i7
- Download site: https://relay-room-lichess.vercel.app
End users do not need to run a server or create a database.
Requirements:
- Desktop Chrome or Edge 116 or newer.
- Access to the Lichess broadcast being discussed.
Steps:
- Download the latest extension and unzip it.
- Open
chrome://extensionsoredge://extensions. - Enable Developer mode.
- Select Load unpacked and choose the unzipped extension folder.
- Open a desktop Lichess broadcast.
The Relay Room control appears at the upper-right of the broadcast. Enter a display name, create a room, and copy the invitation link. The invited commentator also needs the extension. Drag the panel by its header to move it; the position is saved for future broadcast tabs.
Each participant shares their current broadcast round, chapter/game, and analysis-tree path. Select Follow beside a commentator to lock your board to their view. Select Unfollow to explore independently.
When a leader makes a different move, Relay Room decodes Lichess’s native tree path and rebuilds the missing branch through Lichess’s own analysis controller. The follower therefore reaches local variations that were not already present on their board.
Following is directional: Alice can follow Bob or Bob can follow Alice. Circular follow chains are rejected so two boards cannot fight each other.
The room creator is the owner and first admin. An admin can promote another commentator with + Admin. The owner cannot be demoted. If the owner leaves, ownership transfers to an existing admin or the earliest remaining participant.
Relay Room roles are independent of Lichess broadcast permissions. Promoting someone here does not make them a Lichess broadcast contributor.
Relay Room uses the active Lichess Chessground instance. When Lichess exposes its board API, the
bridge reads state.drawable.shapes and calls setShapes. On the current broadcast frontend, where
that API is private, the bridge reads Chessground’s own cgHash shape data and replays
Chessground’s native mouse drawing events on the real board.
There is no replacement board, canvas, SVG overlay, or second drawing tool. The fallback still asks the Chessground already mounted by Lichess to create and render every arrow or circle.
- Right-drag: green arrow.
- Shift/Control + right-drag: red arrow.
- Alt + right-drag: blue arrow.
- Alt + Shift/Control + right-drag: yellow arrow.
- Right-click a square: circle in the same color.
Shapes are scoped to the exact round, game, and move. Existing Lichess arrows for that position are retained. Each commentator owns their room arrows, while admins can clear everyone’s room arrows for the current position.
The production path is:
Lichess broadcast page
↕ page bridge: current round / game / move + Chessground drawable shapes
Chrome MV3 extension
↕ generated TypeScript bindings over secure WebSocket
SpaceTimeDB Maincloud module
↕ identity-scoped realtime views + authorized reducers
Other commentators
The SpaceTimeDB module lives in spacetimedb/src/index.ts. Its room, participant, shape, invite, and
cleanup tables are private. The invite secret never appears in a client subscription. Identity-scoped
views expose room state only to anonymous SpaceTimeDB identities that joined that room. Reducers
authorize every state mutation from ctx.sender.
An internal hourly schedule removes rooms whose inactivity marker has passed 24 hours. Leaving the last seat removes a room immediately.
apps/server contains the earlier Node/WebSocket implementation for local reference and optional
self-hosting. It is covered by unit and integration tests, but the release extension does not use it.
Requirements:
- Node.js 22 or newer.
- SpaceTimeDB CLI 2.7.x.
- Chromium installed by Playwright for the end-to-end test.
Install dependencies:
npm installBuild and generate SpaceTimeDB client bindings:
spacetime build --module-path spacetimedb
spacetime generate \
--lang typescript \
--out-dir apps/extension/src/module_bindings \
--module-path spacetimedbBuild the extension:
npm run build:extensionContributions are welcome. Read CONTRIBUTING.md before opening a pull request, especially if a change touches Lichess DOM integration, room authorization, or generated SpaceTimeDB bindings.
To use another SpaceTimeDB deployment:
RELAY_ROOM_SERVER_URL=https://your-spacetimedb-host.example \
RELAY_ROOM_DATABASE=your-database-name \
npm run build:extensionThe build adds the configured server origin to the extension manifest.
The repository’s spacetime.json points to Maincloud:
spacetime publish sagar-cbi-r69i7 \
--module-path spacetimedb \
--server maincloudPublishing to a different database is also supported; update the extension build’s
RELAY_ROOM_DATABASE.
npm run typecheck
npm test
npm run build
npm run verifynpm run verify includes a two-browser extension test against the configured Maincloud database. It
creates isolated Chromium profiles and verifies room creation, invitation, admin promotion,
directional follow, missing-variation reconstruction, draggable panel positioning, automatic game
switching, and native Chessground shape synchronization.
An opt-in compatibility test runs the same extension against real Lichess broadcast pages and draws through the actual Chessground board:
RELAY_ROOM_LIVE_URL='https://lichess.org/broadcast/.../round-id/game-id' \
RELAY_ROOM_LIVE_ALT_URL='https://lichess.org/broadcast/.../round-id/another-game-id' \
npx playwright test tests/e2e/live-lichess.spec.tsnpm run packageThis builds and writes:
artifacts/relay-room-extension.zipartifacts/relay-room-source.zip- matching versioned files in
outputs/ - matching downloads in
public/downloads/
Local environment files, Vercel metadata, test output, previous releases, and dependencies are excluded from the source archive.
- No Lichess password, OAuth token, microphone, or camera access is requested.
- SpaceTimeDB issues a persistent anonymous identity token, stored in Chrome local storage.
- Room writes are authorized server-side by that identity.
- Invite secrets and room backing tables are private.
- Room state is exposed through identity-scoped views.
- Input lengths, Lichess URLs, board squares, colors, participant count, and shape count are validated.
- The extension’s Manifest V3 CSP contains no
unsafe-evalor remotely hosted code.
Anyone holding an invitation URL can join that room, so share it only with intended commentators. See SECURITY.md and the deployed privacy notice.
- Supported: current desktop Chrome and Edge, version 116 or newer.
- Not included: mobile apps or mobile browsers.
- Every participant must independently have access to a private Lichess broadcast.
- Relay Room supports both the older exposed Lichess page objects and the current broadcast DOM plus
native Chessground events. A future Lichess frontend change may require updating
apps/extension/src/bridge.ts. - This is an independent project and is not affiliated with or endorsed by Lichess.
MIT
