docs: link every client in the clients-page chooser + correctness sweep
apple / swift (push) Successful in 1m16s
apple / screenshots (push) Successful in 6m29s
ci / web (push) Successful in 1m11s
ci / docs-site (push) Successful in 56s
android / android (push) Successful in 13m53s
arch / build-publish (push) Successful in 12m20s
decky / build-publish (push) Successful in 19s
ci / bench (push) Successful in 5m50s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 10s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 9s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 34s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 59s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 5m45s
docker / deploy-docs (push) Successful in 29s
deb / build-publish (push) Successful in 11m25s
ci / rust (push) Successful in 24m23s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 18m16s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 18m8s

The "Which should I use?" table on the clients page listed most client
names as bold text, not links — only the Decky plugin and pf-webos were
clickable — so the client references appeared broken. Link each client to
its section (or dedicated page), and fix a stale Windows headless command.

Repo-wide docs correctness/staleness pass against the code:
- steam-deck: client-not-found -> flatpak-not-found (the real backend code)
- install: host cert is punktfunk-host-windows_<ver>.cer, not ..._setup.cer
- configuration: GPU_PRIORITY_CLASS default is auto; 10BIT/444 are default-on
- how-it-works/index: GameStream/Moonlight is opt-in (--gamestream)
- roadmap: clipboard sync is shipped, not planned
- install-client: MSIX/cert artifacts are arch-suffixed (_x64/_arm64)
- requirements: fix garbled 22H2/IddCx sentence
- status: Linux encode also covers AMD/Intel (VAAPI/Vulkan Video)
- automation: add the plugins.changed event
- windows-host: note the optional bundled VB-CABLE virtual mic
- sway: PUNKTFUNK_COMPOSITOR=hyprland is a wlroots-family alias
- running-as-a-service: punktfunk-probe is a source-build-only dev tool

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-18 09:50:29 +02:00
parent 2c0aee3979
commit 7f639f7cf5
14 changed files with 48 additions and 41 deletions
+1
View File
@@ -29,6 +29,7 @@ and nothing you configure here runs anywhere near the streaming path.
| `pairing.completed` / `pairing.denied` | a pairing is approved+stored / denied | device name, fingerprint, plane |
| `display.created` / `display.released` | a virtual display is minted / kept displays are released | backend + mode / count |
| `library.changed` | the game library is mutated | source: `manual`, or the provider id that reconciled (`PUT /api/v1/library/provider/{p}`) |
| `plugins.changed` | a plugin's registration changes (registered, restarted, deregistered, or its lease expired) | plugin id |
| `host.started` / `host.stopping` | the serve planes come up / wind down | version, whether GameStream is enabled |
Every event is a small JSON document with a monotonic `seq`, a `ts_ms` timestamp, a `schema`
+9 -9
View File
@@ -89,7 +89,7 @@ A headless CLI path exists for scripting/measurement:
```sh
punktfunk-client # open the WinUI 3 window (host list / settings)
punktfunk-client --discover # list hosts on the network
punktfunk-client --headless --connect <host>:9777 # no window: connect, count frames, print stats
punktfunk-client --headless --speed-test --connect <host>:9777 # no window: probe the link, print measured/recommended bitrate
```
Prefer the broadest compatibility, or no install? **Moonlight** also streams to Windows (see below).
@@ -121,13 +121,13 @@ punktfunk-probe --connect <host>:9777 --pin <fp> # connect to one
| You're streaming to… | Use |
|---|---|
| A Mac, iPhone, iPad, or Apple TV | The **Apple app** |
| A Linux desktop or laptop | **`punktfunk-client`** (GTK4) |
| A **Steam Deck** | The **[Decky plugin](/docs/steam-deck)** in Gaming Mode, or the GTK4 client in Desktop Mode |
| An Android phone or TV | The **Android app** |
| Windows | The native **`punktfunk-client`** (signed MSIX) or **Moonlight** |
| An **LG webOS TV** | The community **[`pf-webos`](https://github.com/dyptan-io/pf-webos)** client, or **Moonlight** |
| A browser, another smart TV, or any other device | **Moonlight** |
| Automated tests / latency measurement | **`punktfunk-probe`** (headless) |
| A Mac, iPhone, iPad, or Apple TV | The **[Apple app](#apple-app-mac-iphone-ipad-apple-tv)** |
| A Linux desktop or laptop | **[`punktfunk-client`](#linux-desktop-client-gtk4)** (GTK4) |
| A **Steam Deck** | The **[Decky plugin](/docs/steam-deck)** in Gaming Mode, or the [GTK4 client](#linux-desktop-client-gtk4) in Desktop Mode |
| An Android phone or TV | The **[Android app](#android-app-phone--android-tv)** |
| Windows | The native **[`punktfunk-client`](#windows-desktop-client)** (signed MSIX) or **[Moonlight](/docs/moonlight)** |
| An **LG webOS TV** | The community **[`pf-webos`](https://github.com/dyptan-io/pf-webos)** client, or **[Moonlight](/docs/moonlight)** |
| A browser, another smart TV, or any other device | **[Moonlight](/docs/moonlight)** |
| Automated tests / latency measurement | **[`punktfunk-probe`](#linux-reference-client-headless)** (headless) |
Whichever you choose, the first connection needs a one-time [pairing](/docs/pairing).
+3 -3
View File
@@ -88,8 +88,8 @@ See your desktop page ([KDE](/docs/kde), [GNOME](/docs/gnome)) for when to set t
| Setting | Values | Meaning |
|---|---|---|
| `PUNKTFUNK_FEC_PCT` | `N` (percent) | Forward-error-correction redundancy for lossy links (the default is sensible for a normal LAN). Higher = more loss-resilient, more bandwidth. |
| `PUNKTFUNK_10BIT` | `1` | HEVC Main10 / HDR. Honored only when the client also advertises 10-bit. **Windows host only** (the Linux host stays 8-bit). |
| `PUNKTFUNK_444` | `1` | Full-chroma HEVC 4:4:4 (Range Extensions) — sharper text/desktop, no chroma loss. **punktfunk/1 native only** (Moonlight stays 4:2:0), HEVC-only, honored only when the client advertises 4:4:4 **and** the GPU supports it (probed; NVENC is the validated path — VAAPI/AMF/QSV decline). Independent of 10-bit. |
| `PUNKTFUNK_10BIT` | `1` · `0` *(default on)* | HEVC Main10 / HDR. **On by default** — the host permits 10-bit; a session goes 10-bit only when the client advertises it (behind the client's HDR setting). Set `0` to force 8-bit. **Windows host only** (the Linux host stays 8-bit). |
| `PUNKTFUNK_444` | `1` · `0` *(default on)* | Full-chroma HEVC 4:4:4 (Range Extensions) — sharper text/desktop, no chroma loss. **On by default** on the host; the client's own 4:4:4 setting (default off) is the real switch. Set `0` to force 4:2:0. **punktfunk/1 native only** (Moonlight stays 4:2:0), HEVC-only, honored only when the client advertises 4:4:4 **and** the GPU supports it (probed; NVENC is the validated path — VAAPI/AMF/QSV decline). Independent of 10-bit. |
| `PUNKTFUNK_DSCP` | `1` | Opt-in DSCP / `SO_PRIORITY` QoS tagging on the media sockets. No-op on the wire on Windows without a qWAVE policy. |
| `PUNKTFUNK_OH264_THREADS` / `PUNKTFUNK_OH264_GOP` | `N` | Software (openh264) encoder tuning: encode threads (default 2 — latency over throughput) and GOP length (default 0 = encoder-auto). Only relevant with `PUNKTFUNK_ENCODER=software`. |
@@ -142,7 +142,7 @@ notes for context.
|---|---|---|
| `PUNKTFUNK_GSO` | `1` · `0` | UDP Generic Segmentation Offload on the send path (coalesce a frame's packets into kernel super-buffers) — cuts send CPU ~30%, but its line-rate packet trains can cost delivered throughput on constrained links (measured on a 2.5GbE hop). Off by default until send pacing spaces the super-buffers; set `1` to opt in (auto-falls back to `sendmmsg` on kernels/paths without support). |
| `PUNKTFUNK_SPLIT_ENCODE` | `0`/`disable` · `1`/`auto` · `2` · `3` | NVENC N-way split-encode for very high pixel rates (5K@240). `auto` picks automatically above ~1 Gpix/s. |
| `PUNKTFUNK_GPU_PRIORITY_CLASS` | `off` · `normal` · `high` · `realtime` | **(Windows)** GPU scheduling priority for capture/encode under a GPU-saturating game. Default `high`; `realtime` is the strongest lever but can freeze NVENC on some setups. |
| `PUNKTFUNK_GPU_PRIORITY_CLASS` | `off` · `normal` · `high` · `realtime` · `auto` | **(Windows)** GPU scheduling priority for capture/encode under a GPU-saturating game. Default `auto` (starts `high`, upgrades to `realtime` when it's safe — e.g. HAGS off); `high` pins the static pre-gate behaviour; `realtime` is the strongest lever but can freeze NVENC on some setups. |
| `PUNKTFUNK_IDD_DEPTH` | `N` (default `2`) | **(Windows)** IDD-push pipeline depth. `1` cuts latency once GPU priority is raised; higher smooths a contended GPU. |
## Diagnostics
+4 -4
View File
@@ -43,15 +43,15 @@ GPU path** that keeps latency low even at high resolutions and frame rates.
punktfunk speaks two protocols over the same host:
- **GameStream** — the protocol Moonlight uses. Any [Moonlight](/docs/moonlight) client connects with
no special software. This is the most compatible way in.
- **GameStream** — the protocol Moonlight uses. Start the host with `--gamestream` and any
[Moonlight](/docs/moonlight) client connects with no special software. This is the most compatible way in.
- **punktfunk/1 (native)** — a purpose-built protocol with a QUIC control channel and a UDP data
channel hardened with forward error correction and encryption. It's lower-latency and more resilient
on imperfect networks, and it's what the [native clients](/docs/clients) (Apple, Linux, Windows,
Android) use.
Both run from a single host process, so you don't choose up front — Moonlight clients use GameStream,
the native clients use punktfunk/1.
The native `punktfunk/1` plane runs by default (the secure default); add `--gamestream` and both planes
serve from a single host process — Moonlight clients use GameStream, the native clients use punktfunk/1.
## Pairing and trust
+3 -3
View File
@@ -18,9 +18,9 @@ It's built for the things that make streaming feel native:
plug to deal with, even on the secure desktop.
- **Low latency, GPU end to end.** Frames go straight from the compositor to the GPU encoder
(NVENC) with zero CPU copies, and over a transport tuned for responsiveness rather than throughput.
- **Works with the apps you already have.** punktfunk speaks the GameStream protocol, so any
**Moonlight** client connects out of the box — and a faster **native protocol** with dedicated apps
for **macOS, iOS, tvOS, Linux, Windows, and Android**.
- **Works with the apps you already have.** punktfunk also speaks the GameStream protocol, so with
`--gamestream` any **Moonlight** client connects — alongside a faster **native protocol** with
dedicated apps for **macOS, iOS, tvOS, Linux, Windows, and Android**.
- **Secure by default.** Hosts require a one-time PIN pairing; after that, devices reconnect on a
pinned identity. No accounts, no cloud.
+5 -3
View File
@@ -83,15 +83,17 @@ The Windows client ships as a **signed MSIX** in the package registry. Builds us
certificate, so you import that certificate once before Windows will install the package.
1. Open the [packages page](https://git.unom.io/unom/-/packages) (generic group), find
**`punktfunk-client-windows`**, and download the newest **`.msix`** and its matching **`.cer`**.
**`punktfunk-client-windows`**, and download the newest **`.msix`** and its matching **`.cer`** for
your CPU — the artifacts are arch-suffixed (`…_x64.msix` / `…_arm64.msix`).
2. **Trust the publisher certificate**, then install. The MSIX won't install until the certificate is
trusted — but it's the **same certificate for every release**, so this is genuinely one-time and
later updates need nothing. In an **admin** PowerShell:
```powershell
Import-Certificate -FilePath .\punktfunk-client-windows.cer `
# use the _arm64 files instead on an Arm device
Import-Certificate -FilePath .\punktfunk-client-windows_x64.cer `
-CertStoreLocation Cert:\LocalMachine\TrustedPeople
Add-AppxPackage .\punktfunk-client-windows.msix
Add-AppxPackage .\punktfunk-client-windows_x64.msix
```
If Windows reports a missing dependency, install the
+2 -2
View File
@@ -37,13 +37,13 @@ punktfunk also runs as a native host on **Windows 11 22H2+ (x64)**, shipped as a
installer — see [Windows Host](/docs/windows-host) for what it includes and its limitations.
1. From the [packages page](https://git.unom.io/unom/-/packages) (generic group), download the newest
**`punktfunk-host-setup-<ver>.exe`** and its matching **`.cer`**.
**`punktfunk-host-setup-<ver>.exe`** and the matching **`punktfunk-host-windows_<ver>.cer`**.
2. **Trust the publisher certificate once.** The installer is signed with a self-signed certificate
whose public `.cer` is published next to it — the **same certificate for every release**, so this is
genuinely one-time and later updates need nothing. In an **admin** PowerShell:
```powershell
Import-Certificate -FilePath .\punktfunk-host-setup.cer `
Import-Certificate -FilePath .\punktfunk-host-windows_<ver>.cer `
-CertStoreLocation Cert:\LocalMachine\TrustedPublisher
```
+2 -2
View File
@@ -33,8 +33,8 @@ Pick your distro to install, then your desktop to configure — the two are inde
needs one of these compositor backends to create a virtual display.
> **Windows host:** punktfunk also runs as a native host on **Windows 11 22H2 or newer (x64)** — a
> signed installer that registers a service and bundles a virtual-display driver (whose driver-
> framework needs make 22H2 the hard floor — Windows 10 is not supported). It encodes on NVIDIA
> signed installer that registers a service and bundles a virtual-display driver whose driver
> framework (IddCx 1.10) makes 22H2 the hard floor — Windows 10 is not supported. It encodes on NVIDIA
> (NVENC), AMD (AMF), or Intel (QSV), with a software fallback, and is newer than the Linux host; see
> [Windows Host](/docs/windows-host).
+7 -5
View File
@@ -51,6 +51,8 @@ see [Status & Progress](/docs/status).
(the encoder re-targets mid-stream when bitrate is set to Automatic).
- **Surround sound** — 5.1 and 7.1 end to end: the host encodes multichannel via multistream Opus and
the native clients render more than two channels, with clean, synchronous stereo where the path is stereo.
- **Clipboard sync** — bidirectional **text and images** between host and client, carried on a side
plane over the native protocol's QUIC channel.
## 🟡 In progress
@@ -90,11 +92,11 @@ see [Status & Progress](/docs/status).
rate and the client presents with tearing-control/VRR instead of a fixed cadence, for tear- and
judder-free gaming. Builds on the client's presentation-feedback path and the per-session virtual
outputs.
- **Desktop quality-of-life.** The essentials that make remote *work* pleasant, each a new side plane
over the existing QUIC datagram channel: bidirectional rich **clipboard sync** (text and images),
**multi-monitor streaming** (present the host's several outputs as separate client windows), and
**virtual-webcam redirection** (the client's camera shows up as a webcam on the host, so video calls
run on the remote machine).
- **Desktop quality-of-life.** More of the essentials that make remote *work* pleasant, each a new side
plane over the existing QUIC datagram channel: **multi-monitor streaming** (present the host's several
outputs as separate client windows) and **virtual-webcam redirection** (the client's camera shows up
as a webcam on the host, so video calls run on the remote machine). *(Clipboard sync already shipped —
see above.)*
## ⛔ Parked / blocked
@@ -87,7 +87,7 @@ Intel (QSV); the host falls back to software H.264 without one.
After a reboot, from another machine on the network:
```sh
punktfunk-probe --discover # or just look for the host in a native client / Moonlight
punktfunk-probe --discover # source-build dev tool (not packaged); or just open a native client / Moonlight and look for the host
```
If the host is listed, it's up. If not, check `journalctl --user -u punktfunk-host` on the host.
+3 -3
View File
@@ -32,9 +32,9 @@ host is newer than the Linux host.)
- **Native resolution, no scaling.** Every session gets a virtual display at the client's
exact resolution and refresh rate, via per-compositor backends for **KWin**,
**gamescope**, **Mutter**, and **Sway/wlroots**.
- **Zero-copy GPU pipeline.** Captured frames stay on the GPU (dmabuf → CUDA → NVENC) with
automatic split-encode at very high resolutions. Stable 240 fps at 5120×1440 has been
measured. A GPU-less software H.264 encoder exists as an explicit fallback.
- **Zero-copy GPU pipeline.** Captured frames stay on the GPU dmabuf → CUDA → NVENC on NVIDIA, and
VAAPI or Vulkan Video on AMD/Intel — with automatic split-encode at very high resolutions. Stable
240 fps at 5120×1440 has been measured. A GPU-less software H.264 encoder exists as an explicit fallback.
- **HDR (10-bit), on the Windows host.** An HDR Windows desktop is captured and encoded as HEVC
Main10 (BT.2020 PQ) to HDR-capable clients (Windows, Android). Linux hosts stream 8-bit for now —
HDR there is blocked upstream at the compositor.
+2 -2
View File
@@ -28,7 +28,7 @@ You need three things on the Deck:
```
(Full options: [Install a Client → Steam Deck](/docs/install-client#steam-deck). Without it, the
panel's **Stream** button reports `client-not-found`.)
panel's **Stream** button reports `flatpak-not-found`.)
3. **A punktfunk host** running on your LAN — see [Install the Host](/docs/install). The Deck finds
it automatically over mDNS, so nothing to configure here.
@@ -103,7 +103,7 @@ The plugin check follows the [channel](/docs/channels) you installed from: a plu
| Symptom | Fix |
|---|---|
| **Stream** shows `client-not-found` | Install the client Flatpak in Desktop Mode (see [Before you start](#before-you-start)). |
| **Stream** shows `flatpak-not-found` | Install the client Flatpak in Desktop Mode (see [Before you start](#before-you-start)). |
| No hosts listed | Make sure the host is running and on the **same LAN**; the Deck needs `avahi` (shipped on SteamOS). Tap **Refresh**. |
| Pairing fails / "not armed" | The PIN is shown only after you **arm pairing on the host**. Arm it, then enter the PIN within the window. |
| Stream launches but doesn't focus | Start it from the panel (not by launching the Flatpak by hand) so Steam/gamescope focuses it. |
+1 -1
View File
@@ -27,7 +27,7 @@ The host auto-detects a wlroots session, so you usually need nothing here. To fo
these in `~/.config/punktfunk/host.env`:
```ini
PUNKTFUNK_COMPOSITOR=wlroots # aliases: sway, wlr (Hyprland has its own: PUNKTFUNK_COMPOSITOR=hyprland)
PUNKTFUNK_COMPOSITOR=wlroots # aliases: sway, wlr, hyprland (all the wlroots family; the exact backend is auto-detected)
PUNKTFUNK_INPUT_BACKEND=wlr
PUNKTFUNK_VIDEO_SOURCE=virtual
# GPU zero-copy capture→encode is ON by default; auto-falls back to CPU. Set PUNKTFUNK_ZEROCOPY=0 to force CPU.
+3 -1
View File
@@ -49,6 +49,8 @@ Download the signed `punktfunk-host-setup-<ver>.exe` from the
displays,
- installs the bundled **virtual gamepad drivers** (DualSense, DualShock 4, Xbox 360),
- registers the bundled **HDR Vulkan layer** so Vulkan games can enable HDR over the virtual display,
- optionally installs **VB-CABLE** (VB-Audio, donationware) as the virtual microphone for client
mic passthrough — a checkbox in the installer,
- sets up the **web management console** (see below).
For an unattended install, append `/VERYSILENT`. Upgrades and uninstall go through **Add/Remove
@@ -122,7 +124,7 @@ pipeline orchestration are all shared with the Linux host. The Windows host is a
| **Input — mouse/keyboard** | libei / wlr protocols | **SendInput** (Win32 VK + absolute mouse) |
| **Input — gamepads** | uinput Xbox 360 + UHID DualSense/DS4 | **UMDF** virtual pads — DualSense, DualShock 4, Xbox 360 (XUSB) + rumble |
| **Audio capture** | PipeWire sink-monitor | **WASAPI loopback** |
| **Virtual mic** | PipeWire `Audio/Source` | WASAPI virtual mic |
| **Virtual mic** | PipeWire `Audio/Source` | **VB-CABLE** virtual device (optional), captured via WASAPI |
The virtual display is **pf-vdisplay**, Punktfunk's own all-Rust **Indirect Display Driver (IDD)**. The
host creates a shared GPU texture ring and the driver pushes finished frames straight into it — a real