Add headless streaming mode + Mac client + full docs

Headless mode (new) — for KVM-attached hosts streaming to disconnected clients
- --headless / --mirror flags; default headless on hostname JARVIS, mirror elsewhere
- New lib/headless.sh installs prep-cmd hooks to ~/.local/share/omarchy-moonlight/bin
- bin/sunshine-stream-do.sh creates/resizes a Hyprland HEADLESS-1 output to the
  connecting client's resolution and migrates the active workspace onto it
- bin/sunshine-stream-undo.sh tears down the headless output on disconnect and
  returns the workspace to a non-headless monitor when one is available
- lib/config.sh writes capture=wlr, output_name=HEADLESS-1, and the JSON
  global_prep_cmd entry referencing the installed hook paths
- lib/preflight.sh adds a preflight_headless step that checks hyprctl, jq, and
  a running Hyprland session (warn-only, install can proceed)
- lib/verify.sh adds checks for the hook scripts and the wlr/global_prep_cmd
  config lines

Mac client
- client/install-macos.sh: Darwin guard, Homebrew presence check, brew cask
  install of Moonlight, idempotent
- client/README.md: per-platform install (macOS / Android / iOS / Apple TV /
  Linux + Steam Deck) and the five-step first-pair walkthrough

Other
- jq added to the helper install set in lib/packages.sh (hooks parse Hyprland
  JSON output)
- README.md rewritten to cover both modes, the new flags, the tuned defaults
  per mode + per vendor, the headless internals, and the client pointer
This commit is contained in:
2026-05-18 10:31:08 -06:00
parent d6b0919149
commit 171ade4ff1
11 changed files with 590 additions and 72 deletions

125
client/README.md Normal file
View File

@@ -0,0 +1,125 @@
# Moonlight clients
This directory covers installing Moonlight on the devices that connect to your
Sunshine host. The host side (Sunshine on Linux) is documented in the
[top-level README](../README.md).
## Install
### macOS
From a Mac that has this repo checked out:
```sh
./client/install-macos.sh
```
The script verifies Homebrew is present and runs `brew install --cask moonlight`.
It will not install Homebrew for you.
Manual equivalent:
```sh
brew install --cask moonlight
```
Fallback (no Homebrew): download a signed DMG from the official releases page
and drag `Moonlight.app` into `/Applications`:
- https://github.com/moonlight-stream/moonlight-qt/releases
### Android
Install "Moonlight Game Streaming" from the Play Store:
- https://play.google.com/store/apps/details?id=com.limelight
### iOS / iPadOS
Install "Moonlight Game Streaming" from the App Store:
- https://apps.apple.com/us/app/moonlight-game-streaming/id1000551566
### Apple TV
Same listing on the tvOS App Store. Search "Moonlight Game Streaming" on the
Apple TV itself, or use the App Store link above from an iOS device signed in
to the same Apple ID.
### Steam Deck / Linux
Use `moonlight-qt` from your distro's package manager (Flatpak on Steam Deck,
`pacman`/`apt` elsewhere). It is the same Qt-based client as macOS and Windows.
## First pair
The pairing flow is the same on every client.
1. Confirm the host is healthy. On the host machine:
```sh
./install.sh --doctor
```
Sunshine must be running and reachable on the LAN.
2. On the client, open Moonlight. The host should appear automatically via
mDNS as long as the client is on the same LAN. If it does not appear, use
"Add Host Manually" and enter the host's LAN IP address.
3. Click or tap the host. Moonlight displays a 4-digit PIN.
4. On the host machine, open the Sunshine web UI:
```
https://localhost:47990
```
Accept the self-signed certificate. Log in (credentials are set the first
time you visit). Go to the PIN tab, enter the 4-digit PIN from the client,
and submit. Pairing typically completes within about 5 seconds.
5. Back in Moonlight, the host now shows as "Paired". Click it to see the
available apps. The default app is "Desktop", which is either a full-screen
mirror of the host's display or a headless virtual display, depending on
how the host is configured.
## Streaming notes
- **Resolution.** Moonlight lets you pick a target stream resolution per host.
On a headless-configured host, that resolution is what the host actually
renders at. On a mirror-configured host, the host renders at its native
resolution and Moonlight downscales on the client.
- **Bitrate.** Moonlight's defaults are conservative for general internet use.
For LAN streaming, bump it to 50-100 Mbps.
- **Audio.** By default, Moonlight captures audio from the host and plays it
on the client. If you want the host's speakers/monitor to keep playing
audio while you stream, enable "Play audio on host" in Moonlight's stream
settings.
## Troubleshooting
- **"Host not found" / host does not appear automatically.** Confirm both
machines are on the same LAN/VLAN. mDNS does not traverse VLANs without an
mDNS reflector. Fall back to "Add Host Manually" with the host's IP.
- **Pairing PIN does not work.** Two common causes: the Sunshine web UI
session has timed out (log in again and re-enter the PIN), or the PIN is
being entered into the wrong host (multiple Sunshine instances on the LAN).
Cancel and re-trigger pair from the client to get a fresh PIN.
- **Black screen after pairing.** This is a host-side problem. On the host:
```sh
./install.sh --doctor
```
- **Mac cannot reach `brew`.** Homebrew is not installed (or not on `PATH`).
Install it per https://brew.sh, open a fresh shell, then re-run
`./client/install-macos.sh`.
- **Android sees the host but cannot connect.** The Android device is
probably on a guest WiFi SSID that is isolated from the main LAN. Move it
to the main LAN, or use "Add Host Manually" with the host IP.