"Screens unchained — turn any spare computer into an extra screen for your main PC."
Overview • Use cases • Features • Architecture • Quickstart • Development • Security • Roadmap
Telecastt turns one or more spare computers into extra screens for your main PC — in the browser, across operating systems. Your primary PC shares its screen over WebRTC; each secondary PC either mirrors the whole desktop or shows a different tiled region of it (an extended wall), and can drive the host with its own mouse and keyboard. Quality adapts per screen to each link, and the whole thing runs peer-to-peer on your LAN.
Web-first: a secondary needs nothing but a browser (and can be installed as a PWA). The only thing you install is a small host companion on the PC you want to share — that's what performs OS-level input injection and display provisioning.
Telecastt is an active, honest work-in-progress. What works today is described below; what doesn't yet is called out just as plainly in Honest scope.
- A second monitor, instantly. Set a laptop beside your desktop, hit Extend, and the desktop spills onto it — no cables, no dock.
- Reuse an old PC as a display. Turn a spare machine into a dashboard, chat, or reference screen for your main rig.
- Control from across the room. Drive your desktop from a laptop on the couch — its own mouse and keyboard included.
- Present without dongles. Mirror your screen into any nearby computer's browser.
- Cross-OS by default. A secondary is just a browser, so a Mac or Linux laptop can be a screen for your Windows PC today (host companions for more OSes are on the roadmap).
- 🖥️ Multi-PC by design. One primary → N secondary PCs, each its own peer connection (a mesh). Add or drop a screen without disturbing the others.
- 🧩 Mirror or Extend. Mirror the full desktop to every screen, or Extend — tile the desktop into a wall where each secondary shows a distinct region. One-click toggle on the host.
- 🕹️ Remote control. Drive the host from any secondary; input maps to the correct region and absolute position. Held keys/buttons are safely released if a secondary drops mid-action.
- 📶 Adaptive quality. Per-secondary bitrate/framerate that senses the network (RTT, jitter, received FPS) and battery, with the host fair-sharing its bitrate budget across all connected screens.
- ⚡ Low-latency input. Pointer moves ride a dedicated unreliable data channel (no head-of-line blocking under packet loss), are paced to the display refresh, and carry a live RTT readout in the on-stream telemetry.
- 📋 Clipboard sync. Text clipboard shared between host and secondaries.
- 🎞️ Codec-smart. Prefers modern screen-content codecs (AV1 → HEVC → VP9) to spend the fewest bits on a mostly-static desktop.
- 🔒 Authenticated pairing. CSPRNG room codes + QR join, an authenticated host, rate-limited signaling, host-only OS input injection, and token-gated device-control endpoints.
Because trust matters more than hype:
| Area | Status |
|---|---|
| Multi-PC mesh, mirror/extend, remote control, adaptive quality, clipboard | ✅ Works today, in-browser, over LAN |
| OS input injection + virtual-display provisioning | 🪟 Windows host companion (Win32 InjectTouchInput / SetCursorPos / keybd_event); IDD virtual-display scripts are experimental and need a signed driver or test-signing mode. macOS/Linux injection is planned |
| Extend-mode tiling | ✅ Mirror/Extend toggle on the host; vertical-column auto-tiling, regions map to fill each screen (some aspect stretch). True OS-level extension across machines needs N virtual displays (planned) |
| Transport security | ws:// by default on the LAN — TLS/wss:// is on the roadmap |
| Cross-NAT / internet use | |
| Spatial layout drag-and-drop | 🚧 Preview only — it does not change the host's real monitor arrangement, and is labelled as such in the UI |
| File transfer, rich (image) clipboard | 🚧 Not yet |
| Native mobile/desktop store apps | ❌ Not planned — this is a web-first PWA |
See docs/MASTER_PLAN.md and docs/OPTIMIZATION_777.md
for the full roadmap, plus docs/USE_CASES.md and
docs/SECURITY_AUDIT.md for the edge-case and security analyses.
┌──────────────────────────────────────────────┐
│ PRIMARY PC (host + host companion) │
│ • Browser: getDisplayMedia screen capture │
│ • Node signaling server (:3001) │
│ • Win32 input injection (host companion) │
│ • Manages one connection per secondary │
└───────────────────┬──────────────────────────┘
│ WebRTC (DTLS-SRTP) video + data channels
┌────────────────────────────┼────────────────────────────┐
┌────▼──────────┐ ┌─────────▼────────┐ ┌──────────▼──────┐
│ Secondary 1 │ │ Secondary 2 │ ... │ Secondary N │
│ (any browser) │ │ (any browser) │ │ (any browser) │
│ region + input│ │ region + input │ │ region + input │
└───────────────┘ └──────────────────┘ └─────────────────┘
- Transport: WebRTC — DTLS-SRTP media, reliable
control/clipboardchannels, and an unreliablecursorchannel for low-latency pointer moves. Node +wsbroker signaling. - Roles: the host holds a
Map<peerId, RTCPeerConnection>; each secondary is a single connection back to the host, addressed by peer id. - Adaptation: secondaries send quality requests over their control channel; the host caps each sender independently and fair-shares the total bitrate budget.
telecastt/
├── backend/ # Node signaling server + Windows host companion
│ ├── server.js # Express + ws signaling, rate limiting, device APIs
│ ├── lib/ # room-registry (multi-peer), input-controller, idd-controller, ...
│ └── test/ # unit tests (npm test)
├── frontend/ # React + TypeScript + Vite web app (both host & client roles)
│ └── src/
│ ├── hooks/ # useWebRTC (the mesh), usePointerCapture, useDisplayCapture, ...
│ ├── components/ # HostView, ClientView, VideoStage, ControlDock, ...
│ └── lib/ # peer-io, api, types, env
├── scripts/ # Windows PowerShell helpers (virtual display, input, Bluetooth PAN)
├── docs/ # roadmaps, optimization, use-case matrix, security audit, demo
└── assets/ # brand logo
You need the repo on your primary PC (Windows for input injection) and any device with a browser as a secondary, on the same network.
1. Start the host companion + signaling server
cd backend
npm install
npm start # signaling + input injection on port 30012. Launch the web app
cd frontend
npm install
npm run dev # served with --host so other devices can reach it3. Host your screen
- On the primary PC, open the app, click Initialize Host, and pick the screen/window to share. A room code + QR appear.
4. Connect a secondary
- On another PC, open
http://<PRIMARY-LAN-IP>:5173(or scan the QR) and enter the code. - Repeat for more secondaries.
5. Mirror or Extend
- In the host's Display mode, choose Mirror (all screens show the whole desktop) or Extend (the desktop tiles across your secondaries). Control the host from any secondary.
Tip: several browser APIs (screen capture, clipboard) require a secure context. On the LAN,
localhostis fine on the host; for secondaries, serve over HTTPS or use the host's IP as allowed by your browser. TLS-by-default is on the roadmap.
Everything below is optional — the defaults work on a LAN.
Frontend (frontend/.env, read at build time by Vite):
| Variable | Purpose |
|---|---|
VITE_TURN_URLS |
Comma-separated TURN URLs, appended to the default STUN list. Required for cross-NAT (hotspots, symmetric NAT) — STUN alone cannot punch through. |
VITE_TURN_USERNAME / VITE_TURN_CREDENTIAL |
Credentials for the above. |
VITE_ICE_SERVERS |
A JSON RTCIceServer[] that replaces the ICE list wholesale. |
Backend (backend/.env, loaded via dotenv):
| Variable | Default | Purpose |
|---|---|---|
PORT |
3001 |
Signaling / device-control port. |
MAX_PEERS_PER_ROOM |
8 |
Host + secondaries per session. |
MAX_WS_CLIENTS |
200 |
Global cap on concurrent signaling sockets. |
MAX_WS_CLIENTS_PER_IP |
24 |
Per-source cap on concurrent signaling sockets. |
TELECASTT_PS_TIMEOUT_MS |
120000 |
Timeout for a host-companion PowerShell call. |
Requirements: Node 18+ (20 recommended). Install per package.
Backend
cd backend
npm install
npm test # unit tests: binary protocol, rate limiter, room registry, input sanitizer,
# PowerShell result parsing & argument quoting
npm start # signaling server + host companion (port 3001)Frontend
cd frontend
npm install
npm run dev # dev server (Vite, --host so other devices can reach it)
npm run build # production build
npm run typecheck # tsc --noEmit
npm run lint # oxlintEverything above passes clean. The backend tests run cross-platform — OS input injection degrades gracefully when it can't spawn (e.g. off Windows), so you can develop and test the app on any OS; only the actual OS-level injection needs a Windows host.
Telecastt injects OS input, so it treats authorization seriously:
- Authenticated host — the host proves itself with a per-room token on join, compared in constant time; a reconnecting host reclaims its slot instead of being locked out.
- Host-only injection — only the authenticated host peer may drive OS input over the socket; a joined secondary cannot inject directly.
- 40-bit room codes — 8 CSPRNG symbols from an ambiguity-free alphabet. Failed joins draw on a dedicated per-IP budget (~12/min) and the socket is dropped once it's spent, so each further guess costs a full reconnect — which is itself capped per IP.
- Rate-limited, bounded signaling — per-connection message limits, per-IP HTTP throttling, and caps on concurrent sockets both globally and per source.
- Token-gated device control — virtual-display / Bluetooth endpoints (incl. an elevated driver install) require the host token.
- Server-enforced origin allow-list — a request from an untrusted origin is rejected with 403
before any handler runs, so a drive-by page cannot fire a side effect it merely can't read.
Responses carry a strict CSP,
frame-ancestors 'none',nosniffandno-store. - Sanitized input — every remote input payload is coerced to a fixed, allow-listed, clamped shape before it reaches the injector, which is spawned with no shell and fed JSON on stdin. Writes respect backpressure, so an input flood can't grow an unbounded buffer.
- Verified driver package — the virtual-display archive is pinned by SHA-256 and checked before extraction; a mismatch refuses the install rather than trusting the download.
Known gap: signaling is plain ws:// on the LAN by default — see
docs/SECURITY_AUDIT.md for the full audit, what has since been
remediated, and what remains (TLS, host-approval consent).
| Component | Stack |
|---|---|
| Frontend | React 19, TypeScript, Vite, WebRTC, installable PWA |
| Backend | Node.js, Express, WebSocket (ws), token-bucket rate limiter |
| Host companion | Win32 User32 interop (InjectTouchInput, SetCursorPos, keybd_event) |
| Transport | WebRTC DTLS-SRTP media + data channels; STUN |
Highlights (full plans in docs/):
- Extended-display: grid tiling, drag-to-arrange layouts, per-region input mapping to real monitors.
- Transport: TLS/
wss://by default, TURN for cross-NAT, host-approval consent, longer codes. - Continuity: file/folder transfer, rich (image) clipboard.
- Performance: motion-to-photon instrumentation, dirty-rectangle encoding, WebGPU compositor.
- Reach: macOS/Linux host companion.
Distributed under the MIT License. See LICENSE.