Skip to content
larproberPublic

About

Consent-first remote desktop. WebRTC screen sharing with real mouse & keyboard control. AnyDesk-style, open source.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

BeamDesk

Consent-first remote desktop, open source. A host shares its screen over WebRTC; a viewer in any browser sees it live and controls the host's real mouse and keyboard. AnyDesk-style, ~1000 lines, no accounts, no cloud.

HOST (Electron)                  SIGNALING (Node+ws)          VIEWER (browser)
 ├─ desktopCapturer ─┐                                        ┌─ <video> fullscreen
 │                   ├── WebRTC video ─── P2P (STUN/TURN) ────┤
 │  consent prompt   │   relay SDP/ICE via signaling only     │  capture mouse/kbd
 └─ input-worker ◄───┴── WebRTC data channel ◄────────────────┘  send input events
    (Node + nut-js)
    injects real OS input

Why the split process design

The classic pain of native modules: nut-js ships a prebuilt binary for the standard Node ABI, not Electron's. Instead of running electron-rebuild on every install, BeamDesk runs OS input injection in a separate plain-Node child process (worker/input-worker.js) that the Electron host spawns. Electron does what it's best at (hardware-accelerated screen capture); system Node does what nut-js needs (a matching ABI). No native rebuild step, ever.

The signaling server never sees pixels or keystrokes — media and control travel peer-to-peer once the two sides find each other.

Components

Path Runtime Job
server/signal.js Node Serves the viewer, relays SDP/ICE, owns codes
viewer/ (index/js/css) Any browser Answers the offer, shows screen, sends input
host/ (Electron) Electron Captures screen, consent UI, makes the offer
worker/input-worker.js System Node Injects mouse/keyboard via nut-js

Run it (two machines, or two windows on one)

npm install

1. Start the signaling server (also serves the viewer page):

npm run signal

2. Start the host (the machine to be controlled):

npm run host

Click Start sharing — a 6-digit code appears.

3. Open the viewer in a browser: http://localhost:8080 Enter the code, click Connect. The host gets an Accept / Reject prompt. Accept, and you're driving the host.

To point the host at a signaling server on another machine, set the field in the host window, or launch with BEAMDESK_SIGNAL=ws://SERVER_IP:8080 npm run host.

Controls

  • Mouse — move, click, right-click, drag, scroll all forward to the host.
  • Keyboard — every key is sent to the host while control is on (so f fullscreens YouTube there, Alt+Tab switches windows there, etc.).
  • ⛶ Fullscreen — view the remote edge-to-edge.
  • control toggle — flip to view-only without disconnecting.

Consent & safety

This is a remote-support tool, by design:

  • The host must click Start sharing, then explicitly Accept each viewer.
  • The session code is short-lived and single-use (one viewer per host).
  • Nothing is captured or injected until both steps happen.

Don't use it to access a machine whose owner hasn't agreed. That's the whole point of the accept prompt.

Known limits (MVP)

  • Single monitor. Capture + input mapping assume the primary display.
  • NAT. STUN handles most networks; hosts behind strict/symmetric NAT need a TURN server — add one to RTC_CONFIG in viewer/viewer.js and host/host.js.
  • No encryption beyond WebRTC's (DTLS-SRTP, which is mandatory) and the signaling channel (use wss:// behind a TLS reverse proxy in production).
  • No file transfer / clipboard sync yet. Natural next features.

Build a Windows .exe

npm run dist

Outputs to dist/:

  • BeamDesk-<version>-x64.exe — NSIS installer (choose install dir, start-menu shortcut)
  • BeamDesk-<version>-portable.exe — single-file, no install

The app has no external Node dependency: input injection runs in an Electron utilityProcess, and nut-js's N-API prebuild loads under Electron's ABI. The native binary is asarUnpacked so it can be dlopen'd at runtime.

Windows without Developer Mode / admin

electron-builder eagerly extracts its winCodeSign bundle, which contains macOS .dylib symlinks. Creating symlinks on Windows needs Developer Mode or an elevated shell, so extraction fails with "a required privilege is not held by the client" — even though those files are useless for a Windows build.

Fix once by pre-extracting the bundle (the 2 symlink errors are harmless):

CACHE="$LOCALAPPDATA/electron-builder/Cache/winCodeSign"
"node_modules/7zip-bin/win/x64/7za.exe" x "$CACHE"/*.7z -o"$CACHE/winCodeSign-2.6.0" -y
rm -rf "$CACHE"/[0-9]*

Then npm run dist succeeds. (Or just enable Windows Developer Mode / run the build from an elevated terminal.)

Builds are unsigned — Windows SmartScreen will warn on first run. Add a real code-signing cert via CSC_LINK / CSC_KEY_PASSWORD for distribution.

License

MIT © larprober

About

Consent-first remote desktop. WebRTC screen sharing with real mouse & keyboard control. AnyDesk-style, open source.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages