Skip to content

Repository files navigation

The lwfa mark: three columns of the scrollable strip with the spring curve running across them

lwfa

literally work from anywhere

Latest release MIT licence Linux, Wayland

Run your Linux desktop from any browser. lwfa is a self-hosted remote desktop for Wayland. It runs as an ordinary window inside the compositor you already use, and serves that session to a browser on any other device: an iPad, a laptop, a phone. Video is hardware-encoded H.264 or HEVC, one stream per window, decoded with WebCodecs. Audio is Opus. Keyboard, mouse, touch and an on-screen gamepad the machine sees as a real controller all come back the other way.

There is nothing to install on the client. It is a browser tab, or a home screen icon if you add it as a PWA.

lwfa running on an iPad: a Linux terminal, video playing in Firefox, the on-screen game controller being edited over a running Steam game, and that game being played through it

An iPad driving a desktop in another room: a terminal on the on-screen keyboard, video in Firefox, the controller layout being edited while a game runs behind it, and that game played through the on-screen pad. Watch the full clip, with sound.

What makes it different

  • One video stream per window, not one per screen. The browser composites real DOM elements, so the shell lays windows out for the device in your hand rather than letterboxing a 16:9 desktop onto a tablet.
  • Nothing to install on the client. Any browser with WebCodecs. Add it to an iPad home screen and it runs edge to edge like an app.
  • It is a compositor, so the layout is real. Scrollable tiling, following niri: the tablet is not driving a mouse around a desktop built for a monitor.
  • Nested on purpose. lwfa is a client of Hyprland, niri, KWin or whatever you run. Starting it cannot take down the session you were working in, and it is not a session you log into.
  • Games work. Steam and Proton run under XWayland in the same strip, and the on-screen controller is a real /dev/uinput device, so games find it the way they find a plugged-in pad.

How it compares

What it is best at Where lwfa differs
Sunshine + Moonlight Game streaming, the lowest latency, native clients everywhere lwfa needs no client app, and streams windows individually rather than one screen
noVNC, TigerVNC Runs against almost anything, no GPU required lwfa uses hardware video encode and decode, carries audio, touch and a gamepad, and does not send a whole framebuffer
xrdp, RDP The mature choice for a full remote login session lwfa shares the machine you are already using instead of starting a session beside it
RustDesk, AnyDesk Remote support: see and drive somebody else's screen lwfa is for your own machine, and rearranges it for the screen you are on

If you want the lowest possible latency for one game on a device you can install software on, use Moonlight. lwfa is for the case where you want the whole desktop, on whatever device is nearby, without installing anything on it.

Install

Releases are a single self-extracting file. Download the latest from Releases:

chmod +x lwfa-*.run
./lwfa-*.run

It looks at the machine first (distribution, compositor, GPU, Xwayland, audio, /dev/uinput), shows what it is about to write, and asks. Then it prints a link with the password already in it.

Needs glibc 2.31 or newer, which means Debian 11+, Ubuntu 20.04+, Fedora 32+, RHEL 9+ and every rolling distribution. Full detail, including building from a checkout: docs/install.md.

Quick start

systemctl --user start lwfa          # or: cargo run -p lwfa-engine

Open the link it prints on the device you want to use, and bookmark it. For anything beyond your own machine you want TLS, because browsers refuse hardware video decode on an insecure page; if you have Tailscale, that is one command:

tailscale serve 6733

docs/remote-access.md covers that, the container with nginx, and bringing your own reverse proxy.

What works today

Daily-driven: a gaming PC in one room, an iPad on the couch, Steam games under Proton played over wifi with the on-screen controller.

Physical controllers in Safari/WebKit: the reported iPad setup has missed button presses and stuck input, especially LB/RB. The user reports that physical controls work in Chrome, and on-screen controls work in Safari. Try Chrome or the on-screen controller if affected. See the controller investigation for the test evidence and remaining limits.

  • Per-window hardware video (NVENC), decoded with WebCodecs, zero-copy from the GL texture into the encoder when the NVIDIA driver allows it
  • Adaptive bitrate driven by real socket backpressure, up to 32 Mbit/s, with the focused window getting the budget and unwatched windows paused
  • Audio over Opus, per-device opt-in, quality that degrades last
  • Keyboard, mouse, touch (long press for right click) and an on-screen gamepad that is a real /dev/uinput controller on the machine
  • XWayland, so Steam, Proton and everything X11 runs in the same strip
  • Sessions that survive their own network: a wifi blip costs nothing visible, 45 seconds of grace, the controller stays in the game's hands
  • One clipboard across the session, the desktop outside it and every connected device, text and files alike, with a history you can put anything back from
  • Accounts in SQLite, watch-only or interact, per-app launch permissions, enforced in the engine
  • Multi-device: one client drives, the rest watch, control is taken explicitly
  • Installs as a PWA, edge to edge on an iPad
  • Ships as one self-extracting file with an installer that detects the machine before it writes anything

Deliberately not done yet: built-in TLS (terminate it at a reverse proxy), multi-monitor, the layer-shell chrome path for the native output, and a TTY backend. The engine runs nested inside an existing compositor; it does not own a display outright.

Documentation

Install Releases, building from a checkout, requirements, what the installer writes
Running Nested and development modes, keyboard shortcuts, scrollable tiling
Configuration The config file, precedence, every environment variable
Remote access Another device, TLS, reverse proxies, the iPad home screen
The shell Navigation rail, on-screen keyboard and gamepad, audio, clipboard
Streaming Codecs, zero-copy capture, how the bitrate follows the network
Playing games Steam, Proton, the virtual controller, X11 by hand
Accounts Shared password, named users, permissions
Architecture The decisions and why. Read this before changing anything structural
Testing Test commands, protocol fixtures, the spring parity contract
Releasing Cutting a release, and why it builds in a container

docs/macos.md and docs/windows.md are research on what supporting those hosts would actually take. Neither is built.

How it is built

  • Engine: Rust, Smithay, running nested in a host compositor. Wayland plus XWayland, per-window NVENC encode, PipeWire audio capture, a uinput virtual gamepad. Owns mechanism, not policy.
  • Shell: TypeScript, React 19, shadcn/ui on Tailwind v4. Owns layout policy and everything the user touches.
  • Protocol: one WebSocket, one port. JSON messages for control, binary frames for video and audio, with a decoder on each side that rejects anything it did not expect. Fixtures round-trip between Rust and TypeScript in both directions so the two halves cannot drift.
  • Layout: scrollable tiling. Columns on an infinite strip, workspaces stacked vertically.
mise install && pnpm install
pnpm run build && cargo run -p lwfa-engine
pnpm run test:all

Brand

The mark, wordmark lockups, favicons and PWA icons live in brand/, with usage rules in brand/README.md. The shell references them directly; if you fork this, that is the one directory to replace.

Licence

MIT. See LICENSE.

One thing to keep in mind while working: niri is GPL-3.0, and lwfa follows its layout model (architecture doc, section 2.3). Reading niri as a reference is fine and encouraged. Porting its code is not, because that would force lwfa to GPL-3.0. If that ever looks worth doing, it is a deliberate relicensing decision to make first, not a consequence to discover afterwards.

About

Run your Linux desktop from any browser. Self-hosted remote desktop for Wayland: per-window H.264/HEVC streaming decoded with WebCodecs, audio, touch, and an on-screen gamepad games see as real hardware. No client app to install.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages