feat(packaging/flatpak,decky): Steam Deck client flatpak + plugin deploy + CI
apple / swift (push) Successful in 53s
android / android (push) Successful in 3m48s
ci / web (push) Successful in 29s
ci / docs-site (push) Successful in 34s
ci / rust (push) Successful in 2m21s
ci / bench (push) Successful in 1m36s
decky / build-publish (push) Successful in 31s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 5s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 6s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 5s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 3s
flatpak / build-publish (push) Failing after 4s
deb / build-publish (push) Successful in 2m38s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 5m9s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 4m42s
docker / deploy-docs (push) Successful in 16s

Ship the punktfunk Linux client to the Steam Deck as a Flatpak — the only viable
SteamOS install path, since /usr is read-only and lacks libadwaita/SDL3 — and
publish both it and the Decky plugin through Gitea. Built and validated live on a
Steam Deck (SteamOS 3.7): bundle installs user-scope, all libs resolve, libavcodec
resolves to the codecs-extra HEVC build, devices=all for DualSense hidraw.

packaging/flatpak (new):
- io.unom.Punktfunk.yml on GNOME 50 / freedesktop-sdk 25.08. rust-stable//25.08
  (rustc 1.96 — the GTK4 chain needs >=1.92; the EOL GNOME-48/24.08 rust-stable at
  1.89 could not build it) + llvm20 (libclang for bindgen in ffmpeg-sys-next/sdl3-sys).
  HEVC libavcodec comes from the runtime's auto codecs-extra extension point (no
  app-side codec declaration). Bundled SDL3 3.4.10 (matches sdl3-sys 0.6.6+SDL-3.4.10).
  finish-args: wayland/fallback-x11, --device=all (GPU/VAAPI + evdev + hidraw — flatpak
  cannot bind /dev/hidrawN char devices via --filesystem), pulseaudio, network,
  ~/.config/punktfunk.
- metainfo.xml, desktop, square SVG icon, build-flatpak.sh (offline cargo-sources;
  on-Deck org.flatpak.Builder or CI), README.

clients/decky:
- add LICENSE (MIT), fix package.json license (BSD-3-Clause -> Apache-2.0 OR MIT),
  add scripts/{package.sh,deploy.sh} (the plugins dir is root-owned: stage to /tmp,
  sudo install, restart plugin_loader), align the launcher fallback to the real
  flatpak app id io.unom.Punktfunk, rewrite the install section.

.gitea/workflows:
- flatpak.yml: privileged Fedora container builds the bundle and publishes to the
  Gitea generic registry (+ release attachment on tags).
- decky.yml: pnpm build -> store-layout zip -> registry (stable latest/ URL for
  Decky "install from URL").

docs: packaging/README + packaging/flatpak/README.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-15 01:43:35 +02:00
parent 79217eb93d
commit 8956bc14de
16 changed files with 882 additions and 19 deletions
+9
View File
@@ -0,0 +1,9 @@
# Generated by flatpak-cargo-generator.py from Cargo.lock in CI (offline crate cache for the
# manifest's punktfunk-client module). Regenerated on every build — never commit it.
cargo-sources.json
# flatpak-builder scratch / output (when building locally in this dir).
.flatpak-builder/
build-dir/
repo/
*.flatpak
+122
View File
@@ -0,0 +1,122 @@
# punktfunk client — Flatpak (Steam Deck / SteamOS, and any flatpak distro)
The native Linux **client** (crate `punktfunk-client-linux`, binary `punktfunk-client`) is
published as a single-file **`.flatpak` bundle** to **Gitea's generic package registry** in
the public `unom` org. CI (`.gitea/workflows/flatpak.yml`) builds and publishes on every push
to `main` (a rolling `0.0.1-ciN.<sha>` build) and on `v*` tags (a clean `X.Y.Z`), and on tags
also attaches the bundle to the Gitea release.
> The **host** is NOT a flatpak (it needs unsandboxed `/dev/uinput` + zero-copy NVENC — see
> [`../README.md`](../README.md) "Why not Flatpak"). Only the **client** is sandbox-friendly.
## Why flatpak for the Steam Deck
SteamOS `/usr` is read-only and image-based, and the system is **missing `libadwaita` and
`libSDL3`** — so a bare `punktfunk-client` binary dropped into `~/.local/bin` won't run. Flatpak
is the Deck's native, update-survivable app path (the user already runs Moonlight and chiaki-ng
as flatpaks), and the bundle carries libadwaita (from `org.gnome.Platform//50`) + a bundled SDL3,
with HEVC-capable FFmpeg supplied automatically by the runtime's `codecs-extra` extension.
App id: **`io.unom.Punktfunk`** (matches the Apple bundle id family and the Decky plugin's
flatpak fallback).
## Install on the Deck (one-time)
The generic registry is a plain HTTP file store, so just download the bundle and install it
per-user (no root, survives SteamOS updates):
```sh
# Pick a version: a tag like 1.2.3, or the newest main build's 0.0.1-ciN.gSHA.
VER=1.2.3
URL="https://git.unom.io/api/packages/unom/generic/punktfunk-client-flatpak/$VER/punktfunk-client-$VER.flatpak"
# Flathub must be enabled (it is on the Deck) so the GNOME runtime + ffmpeg-full pull in:
flatpak remote-add --user --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
curl -fL -o /tmp/punktfunk-client.flatpak "$URL"
flatpak install --user --bundle /tmp/punktfunk-client.flatpak
```
Run it:
```sh
flatpak run io.unom.Punktfunk # GUI host list (mDNS)
flatpak run io.unom.Punktfunk --connect HOST:PORT
```
The **Decky plugin** launches exactly this (`flatpak run io.unom.Punktfunk --connect …`) once
installed — see [`../../clients/decky/README.md`](../../clients/decky/README.md).
## Updates
A bundle has no remote to track, so updates are "download the newer bundle and reinstall":
```sh
flatpak install --user --bundle /tmp/punktfunk-client.flatpak # same command, newer file
```
(If you want `flatpak update` to track new builds automatically you'd need a hosted OSTree
repo, which Gitea cannot serve — see "Alternatives" below. The bundle is the simplest path.)
## Build locally / the CI fallback
CI builds this in a **`--privileged`** Fedora container, because `flatpak-builder` runs
`bubblewrap`, which needs user namespaces the default Docker executor denies. **If the Gitea
runner can't grant `--privileged`** (the job fails at `flatpak-builder` with
*"Creating new namespace failed: Operation not permitted"*), build it out-of-band and upload
by hand. The easiest place is **on the Deck itself** (it can run `org.flatpak.Builder`
user-scope, no root):
```sh
# On the Deck (or any flatpak box), one-time:
flatpak install --user -y flathub org.flatpak.Builder
# build-flatpak.sh auto-detects org.flatpak.Builder, generates cargo-sources.json (or reuses an
# existing one — see below), builds, and exports dist/punktfunk-client-<version>.flatpak:
bash packaging/flatpak/build-flatpak.sh
# Upload to the generic registry (PAT with write:package):
curl -fsS --user "enricobuehler:$REGISTRY_TOKEN" \
--upload-file dist/punktfunk-client-*.flatpak \
"https://git.unom.io/api/packages/unom/generic/punktfunk-client-flatpak/0.0.1-manual/punktfunk-client.flatpak"
```
> `cargo-sources.json` generation needs `python3` + `aiohttp` + `tomlkit`, which the Deck lacks.
> Generate it on a dev box (`build-flatpak.sh` does it, or run the upstream
> `flatpak-cargo-generator.py Cargo.lock -o packaging/flatpak/cargo-sources.json`), rsync it next
> to the manifest, and `build-flatpak.sh` reuses it (it only regenerates when the file is absent
> or `FORCE_GEN=1`).
> The Mac build host **cannot** build a Linux flatpak (no flatpak-builder for macOS), and
> home-worker-2 has no flatpak and no passwordless sudo to install it — so the Deck or the
> privileged CI container are the only two viable build sites.
## Manifest
[`io.unom.Punktfunk.yml`](io.unom.Punktfunk.yml). Runtime `org.gnome.Platform//50`
(GTK 4.20 + libadwaita 1.8 ≥ the crate floors of v4_16 / v1_5), built on freedesktop-sdk 25.08,
with two build-time SDK extensions: `org.freedesktop.Sdk.Extension.rust-stable` (→ //25.08,
**rustc 1.96** — the GTK4 dep chain, e.g. pango-sys 0.22, needs ≥ 1.92, which the EOL GNOME-48 /
24.08 rust-stable at 1.89 could not provide) and `org.freedesktop.Sdk.Extension.llvm20` (libclang,
needed by bindgen in ffmpeg-sys-next / sdl3-sys). HEVC-capable libavcodec (soname 61, accepted by
ffmpeg-next 8.x) is supplied **automatically at runtime** by the freedesktop `codecs-extra`
extension point (auto-downloaded with the runtime; no app-side codec declaration). A bundled
**SDL3 3.4.10** module (pinned to match `sdl3-sys 0.6.6+SDL-3.4.10`), and finish-args for Wayland +
`--device=all` (GPU/VAAPI render node + evdev + the hidraw char-devices SDL3 needs for DualSense)
+ `--socket=pulseaudio` (PipeWire-pulse: playback + mic) + `--share=network`. Alongside it:
`io.unom.Punktfunk.desktop`, `io.unom.Punktfunk.metainfo.xml`, `io.unom.Punktfunk.svg` (all
installed by the manifest). `cargo-sources.json` (the offline crate cache) is a pure function of
`Cargo.lock`; CI regenerates it each build and it is **gitignored** — generate it on any box with
network + `python3`/`aiohttp`/`tomlkit` (`build-flatpak.sh` does this automatically) and, for a
build host that lacks those (the Deck), rsync the generated file in alongside the manifest.
## Alternatives considered (and why the bundle wins)
- **Generic registry bundle (chosen):** one curl to publish, one `flatpak install --bundle` to
consume; mirrors the existing deb/rpm curl-upload pattern exactly. No auto-update.
- **Release attachment:** also done on tags (the bundle is attached to the Gitea release), good
for a human-facing download page; the generic registry gives the stable per-version URL the
Decky fallback and scripts use.
- **Self-hosted OSTree repo (rejected):** would enable `flatpak update`, but Gitea has no
flatpak/ostree registry, so it would mean serving a static OSTree tree over Gitea raw/Pages —
more moving parts than the appliance needs today.
+85
View File
@@ -0,0 +1,85 @@
#!/usr/bin/env bash
# Build the punktfunk Linux client as a single-file `.flatpak` bundle.
#
# Works on the Steam Deck (org.flatpak.Builder from Flathub, user-scope, NO root) and on any
# Linux box with flatpak + flatpak-builder. The CI does the same steps (.gitea/workflows/flatpak.yml).
#
# On the Deck (one-time):
# flatpak install --user -y flathub org.flatpak.Builder
# Then run this script from the repo root:
# bash packaging/flatpak/build-flatpak.sh
# Output: dist/punktfunk-client-<version>.flatpak (install with `flatpak install --user <file>`)
#
# Env knobs:
# VERSION=... version string for the bundle name (default: git describe / 0.0.1-dev)
# ONLINE=1 skip offline cargo-sources.json; build with --share=network (fast local
# iteration, non-reproducible). Default: offline (regenerates cargo-sources).
# BUILDER=... override the flatpak-builder invocation (default: auto-detect host
# flatpak-builder, else `flatpak run org.flatpak.Builder`).
set -euo pipefail
ROOTDIR="$(cd "$(dirname "$0")/../.." && pwd)"
cd "$ROOTDIR"
APP_ID="io.unom.Punktfunk"
MANIFEST="packaging/flatpak/io.unom.Punktfunk.yml"
VERSION="${VERSION:-$(git describe --tags --always --dirty 2>/dev/null || echo 0.0.1-dev)}"
VERSION="${VERSION#v}"
BUNDLE="dist/punktfunk-client-${VERSION}.flatpak"
# --- pick a flatpak-builder (host binary, or the org.flatpak.Builder flatpak on the Deck) ---
if [ -n "${BUILDER:-}" ]; then
FPB=($BUILDER)
elif command -v flatpak-builder >/dev/null 2>&1; then
FPB=(flatpak-builder)
elif flatpak info org.flatpak.Builder >/dev/null 2>&1; then
FPB=(flatpak run org.flatpak.Builder)
else
echo "error: need flatpak-builder. On the Deck: flatpak install --user -y flathub org.flatpak.Builder" >&2
exit 1
fi
# --- ensure Flathub is available for the runtime/SDK/extensions ---
flatpak remote-add --user --if-not-exists flathub \
https://dl.flathub.org/repo/flathub.flatpakrepo
# --- offline crate cache (skip with ONLINE=1) -------------------------------------------
EXTRA_ARGS=()
if [ "${ONLINE:-0}" = "1" ]; then
echo "==> ONLINE build (cargo fetches from crates.io; non-reproducible)"
EXTRA_ARGS+=(--build-args=--share=network)
# The manifest references cargo-sources.json; provide an empty list so it stays valid.
[ -f packaging/flatpak/cargo-sources.json ] || echo '[]' > packaging/flatpak/cargo-sources.json
elif [ -f packaging/flatpak/cargo-sources.json ] && [ "${FORCE_GEN:-0}" != "1" ]; then
# Reuse a cargo-sources.json that was generated elsewhere (e.g. on a dev box with network +
# python aiohttp/toml, then rsynced to a build host that lacks them — like the Deck). The
# offline crate cache is a pure function of Cargo.lock, so this is reproducible. FORCE_GEN=1
# to regenerate anyway.
echo "==> reusing existing packaging/flatpak/cargo-sources.json (FORCE_GEN=1 to regenerate)"
else
echo "==> generating offline cargo-sources.json from Cargo.lock"
GEN=/tmp/flatpak-cargo-generator.py
if [ ! -f "$GEN" ]; then
curl -fsSL -o "$GEN" \
https://raw.githubusercontent.com/flatpak/flatpak-builder-tools/master/cargo/flatpak-cargo-generator.py
fi
# Needs python3 + aiohttp + toml. On a host that lacks them (e.g. the Deck), generate on the
# Mac / a dev box instead and rsync the result next to the manifest (reused by the branch above).
python3 "$GEN" Cargo.lock -o packaging/flatpak/cargo-sources.json
fi
# --- build into a local ostree repo, then export a single-file bundle --------------------
echo "==> flatpak-builder ($APP_ID, version $VERSION)"
"${FPB[@]}" --user --force-clean --disable-rofiles-fuse \
--install-deps-from=flathub \
"${EXTRA_ARGS[@]}" \
--repo="$ROOTDIR/.flatpak-repo" \
"$ROOTDIR/.flatpak-build" "$MANIFEST"
mkdir -p dist
flatpak build-bundle "$ROOTDIR/.flatpak-repo" "$BUNDLE" "$APP_ID"
echo "built $BUNDLE"
ls -lh "$BUNDLE"
echo
echo "install: flatpak install --user -y $BUNDLE"
echo "run: flatpak run $APP_ID (or: flatpak run $APP_ID --connect host:port)"
@@ -0,0 +1,10 @@
[Desktop Entry]
Type=Application
Name=Punktfunk
Comment=Stream a remote punktfunk host
Exec=punktfunk-client
Icon=io.unom.Punktfunk
Terminal=false
Categories=Network;Game;
Keywords=streaming;remote;game;moonlight;
StartupNotify=true
@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- AppStream metainfo for the punktfunk Linux client flatpak. Validate with:
appstreamcli validate packaging/flatpak/io.unom.Punktfunk.metainfo.xml
The component id MUST equal the flatpak app-id; the <launchable> MUST name the installed
desktop file (io.unom.Punktfunk.desktop). -->
<component type="desktop-application">
<id>io.unom.Punktfunk</id>
<metadata_license>CC0-1.0</metadata_license>
<project_license>MIT OR Apache-2.0</project_license>
<name>Punktfunk</name>
<summary>Low-latency desktop and game streaming client</summary>
<description>
<p>
Punktfunk is the native Linux client for the punktfunk low-latency desktop and game
streaming stack. It discovers hosts on the LAN over mDNS, trusts them via certificate
pinning with a SPAKE2 PIN pairing ceremony, and streams HEVC video (GF(2^16) Leopard
FEC plus AES-GCM over UDP, with a QUIC control plane) at exactly the requested
resolution and refresh rate — no scaling.
</p>
<p>Features:</p>
<ul>
<li>Hardware-accelerated HEVC decode (VAAPI zero-copy on AMD and Intel, software fallback)</li>
<li>PipeWire audio playback and microphone uplink</li>
<li>Full gamepad support including DualSense touchpad, motion, adaptive triggers and lightbar (SDL3)</li>
<li>LAN host discovery, TOFU fingerprint pinning and PIN pairing</li>
</ul>
</description>
<launchable type="desktop-id">io.unom.Punktfunk.desktop</launchable>
<categories>
<category>Network</category>
<category>Game</category>
<category>RemoteAccess</category>
</categories>
<keywords>
<keyword>streaming</keyword>
<keyword>remote</keyword>
<keyword>game</keyword>
<keyword>moonlight</keyword>
</keywords>
<url type="homepage">https://git.unom.io/unom/punktfunk</url>
<url type="bugtracker">https://git.unom.io/unom/punktfunk/issues</url>
<url type="vcs-browser">https://git.unom.io/unom/punktfunk</url>
<developer id="io.unom">
<name>unom</name>
</developer>
<content_rating type="oars-1.1"/>
<branding>
<color type="primary" scheme_preference="light">#a79ff8</color>
<color type="primary" scheme_preference="dark">#6c5bf3</color>
</branding>
<!-- Bump on each release; the version/date should track the published bundle. -->
<releases>
<release version="0.0.1" date="2026-06-15">
<description>
<p>Initial flatpak packaging of the native Linux client for the Steam Deck and Wayland desktops.</p>
</description>
</release>
</releases>
</component>
+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="1000" height="1000" viewBox="0 0 1000 1000" version="1.1"
xmlns="http://www.w3.org/2000/svg"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<!-- Brand mark: three overlapping circles (flattened from clients/apple punktfunk_Logo.icon).
Order back-to-front: large violet circle (layer 1), deep-purple circle (layer 2),
light lens highlight (layer 3). -->
<rect x="0" y="0" width="1000" height="1000" rx="180" ry="180" fill="#1c1530"/>
<path d="M403.037,791.672c107.586,0 194.41,-86.824 194.41,-194.41c0,-107.586 -86.824,-194.41 -194.41,-194.41c-107.586,0 -194.41,86.824 -194.41,194.41c0,107.586 86.824,194.41 194.41,194.41Z" fill="#a79ff8"/>
<path d="M735.276,540.321c76.075,-76.075 76.075,-198.862 0,-274.937c-76.075,-76.075 -198.862,-76.075 -274.937,0c-76.075,76.075 -76.075,198.862 0,274.937c76.075,76.075 198.862,76.075 274.937,0Z" fill="#6c5bf3"/>
<path d="M647.84,590.737c-64.853,17.403 -136.871,0.597 -187.885,-50.416c-51.013,-51.013 -67.819,-123.032 -50.416,-187.885c64.853,-17.403 136.871,-0.597 187.885,50.416c51.013,51.013 67.819,123.032 50.416,187.885Z" fill="#d2c9fb"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

+159
View File
@@ -0,0 +1,159 @@
# Flatpak manifest for the native punktfunk Linux client (crate punktfunk-client-linux,
# binary `punktfunk-client`). Built into a single-file `.flatpak` bundle and published to
# Gitea's generic package registry (see .gitea/workflows/flatpak.yml + packaging/flatpak/README.md).
#
# Why flatpak for the CLIENT (the host stays an RPM/deb — see packaging/README.md "Why not
# Flatpak"): on SteamOS the Steam Deck's /usr is read-only and image-based, so a bare
# `punktfunk-client` binary in ~/.local/bin can't bring its own libadwaita / SDL3 (both
# MISSING from the SteamOS system) — but flatpak is the Deck's native, update-survivable app
# path (the user already runs Moonlight + chiaki-ng as flatpaks). Unlike the host, the client
# is sandbox-friendly: it only needs the GPU render node, the host PipeWire socket, the
# network, Wayland, hidraw for DualSense, and its config dir — all expressible as finish-args.
#
# Runtime: GNOME 50 ships GTK 4.20 and libadwaita 1.8 — both far exceed the crate floors
# (gtk4 0.11 "v4_16", libadwaita 0.9 "v1_5"). GNOME 50 is built on freedesktop-sdk 25.08, so
# `org.freedesktop.Sdk.Extension.rust-stable` resolves to //25.08 (rustc 1.96 — the GTK4 dep
# chain, e.g. pango-sys 0.22, needs >= 1.92, which the older GNOME-48/24.08 rust-stable at 1.89
# could NOT satisfy). GNOME 50 is also a *supported* runtime (GNOME 48 went EOL in March 2026).
# libopus and the PipeWire client lib are in the freedesktop base; SDL3 is NOT, so it is built
# from source as a bundled module.
#
# HEVC decode: the base runtime's libavcodec is a stripped build (no encumbered codecs). The
# freedesktop runtime declares `org.freedesktop.Platform.codecs-extra` as a built-in extension
# point (directory lib/x86_64-linux-gnu/codecs-extra, add-ld-path lib, auto-downloaded with the
# runtime), whose full libavcodec.so.61 transparently shadows the base one at runtime. So HEVC
# (software + VAAPI) works with NO app-side codec extension to declare — we just build against
# the SDK's linkable libavcodec.so.61 and let the runtime swap in the capable build.
app-id: io.unom.Punktfunk
runtime: org.gnome.Platform
runtime-version: '50'
sdk: org.gnome.Sdk
# Build-time SDK extensions:
# - rust-stable: cargo/rustc 1.96 + the bundled mold linker (/usr/lib/sdk/rust-stable/bin).
# - llvm20: provides libclang (/usr/lib/sdk/llvm20/lib), which bindgen needs — ffmpeg-sys-next
# and sdl3-sys generate their FFI bindings via bindgen at build time. The base SDK ships no
# clang/libclang, so without this the build panics ("Unable to find libclang").
# Both are added to PATH / LIBCLANG_PATH in build-options below.
sdk-extensions:
- org.freedesktop.Sdk.Extension.rust-stable
- org.freedesktop.Sdk.Extension.llvm20
command: punktfunk-client
cleanup:
- /include
- /lib/pkgconfig
- /lib/cmake
- /share/aclocal
- /man
- /share/man
- '*.a'
- '*.la'
finish-args:
# --- display ---
- --socket=wayland # GTK4 native Wayland window (the client is Wayland-first)
- --socket=fallback-x11 # Xwayland fallback when no Wayland socket is exposed
- --share=ipc # required alongside X11 for shared-memory surfaces
# --- GPU + all input devices ---
# --device=all (not just --device=dri): covers the GPU render node (VAAPI HEVC decode + GL),
# evdev joysticks, AND the hidraw CHAR devices SDL3's HIDAPI needs for DualSense touchpad/
# motion/adaptive-triggers/lightbar. flatpak cannot bind individual /dev/hidrawN via
# --filesystem (they are char devices — "unsupported type 0o20000"), and there is no granular
# --device=hidraw; --device=all is what game/emulator flatpaks (RetroArch, Dolphin) use. We
# self-host via the Gitea generic registry — NOT Flathub — so its --device=all review rule
# does not apply.
- --device=all
- --filesystem=/run/udev:ro # SDL/HIDAPI enumerates devices via udev
# --- audio: PipeWire via its PulseAudio shim — covers playback AND mic uplink. SteamOS
# exposes PipeWire-pulse here; --socket=pulseaudio is the portable arg Moonlight/chiaki
# also use on the Deck (a bare --socket=pipewire would also need the camera/portal dance
# for capture; the pulse shim gives mic + speaker in one grant). ---
- --socket=pulseaudio
# --- network: QUIC control + UDP data plane + mDNS discovery (_punktfunk._udp) ---
- --share=network
# --- persistent client identity / pairing store (shared with punktfunk-client-rs) ---
- --filesystem=~/.config/punktfunk:create # client-{cert,key}.pem, known-hosts, settings
build-options:
append-path: /usr/lib/sdk/rust-stable/bin:/usr/lib/sdk/llvm20/bin
# The rust build resolves everything via pkg-config: gtk4/libadwaita/pipewire/opus AND a
# linkable libavcodec.so.61 from org.gnome.Sdk//50 (the multiarch /usr dir), plus the bundled
# SDL3's .pc from /app. (At runtime the codecs-extra extension swaps in the HEVC-capable
# libavcodec — see the header.)
env:
PKG_CONFIG_PATH: /app/lib/pkgconfig:/usr/lib/x86_64-linux-gnu/pkgconfig:/usr/lib/pkgconfig
# bindgen (ffmpeg-sys-next / sdl3-sys) loads libclang from the llvm20 extension.
LIBCLANG_PATH: /usr/lib/sdk/llvm20/lib
# mold (shipped in rust-stable) speeds the ~450-crate link on the Deck APU.
RUSTFLAGS: -C link-arg=-fuse-ld=mold
modules:
# ---------------------------------------------------------------------------------------
# SDL3 — NOT provided as a linkable libSDL3.so.0 by org.gnome.Platform/freedesktop-sdk
# 25.08, and there is no SDL3 recipe in flathub/shared-modules. Build it from source.
# Pinned to 3.4.10 to match the crate exactly: sdl3-sys is `0.6.6+SDL-3.4.10`, i.e. its
# bindings target SDL 3.4.10 — building an older SDL risks missing symbols at link time.
# HIDAPI is enabled (DualSense touchpad/motion/triggers/lightbar over hidraw).
# ---------------------------------------------------------------------------------------
- name: sdl3
buildsystem: cmake-ninja
config-opts:
- -DCMAKE_BUILD_TYPE=Release
- -DSDL_SHARED=ON
- -DSDL_STATIC=OFF
- -DSDL_HIDAPI=ON # DualSense full fidelity over hidraw
- -DSDL_TEST_LIBRARY=OFF
- -DSDL_EXAMPLES=OFF
sources:
- type: archive
url: https://github.com/libsdl-org/SDL/releases/download/release-3.4.10/SDL3-3.4.10.tar.gz
# `sha256sum SDL3-3.4.10.tar.gz` (verified 2026-06-15). Bump url + sha together.
sha256: 12b34280415ec8418c864408b93d008a20a6530687ee613d60bfbd20411f2785
x-checker-data:
type: anitya
project-id: 4974
stable-only: true
url-template: https://github.com/libsdl-org/SDL/releases/download/release-$version/SDL3-$version.tar.gz
cleanup:
- /bin
- /include
- /lib/cmake
- /lib/pkgconfig
# ---------------------------------------------------------------------------------------
# The client. cargo-sources.json is the GENERATED offline crate cache:
# python3 flatpak-cargo-generator.py Cargo.lock -o packaging/flatpak/cargo-sources.json
# (run from the repo root; the CI step does exactly this). With it present the build is fully
# offline (CARGO_NET_OFFLINE). For quick LOCAL iteration WITHOUT regenerating it, drop the
# cargo-sources.json source and pass --build-args=--share=network to flatpak-builder
# (non-reproducible; cargo fetches from crates.io during the build).
# ---------------------------------------------------------------------------------------
- name: punktfunk-client
buildsystem: simple
build-options:
env:
CARGO_HOME: /run/build/punktfunk-client/cargo
CARGO_NET_OFFLINE: 'true'
build-commands:
- cargo --offline build --release --locked -p punktfunk-client-linux
- install -Dm0755 target/release/punktfunk-client ${FLATPAK_DEST}/bin/punktfunk-client
# Desktop entry (renamed to the app id; Exec is the in-sandbox binary).
- install -Dm0644 packaging/flatpak/io.unom.Punktfunk.desktop
${FLATPAK_DEST}/share/applications/io.unom.Punktfunk.desktop
# AppStream metainfo (required for a well-formed flatpak / Software listings).
- install -Dm0644 packaging/flatpak/io.unom.Punktfunk.metainfo.xml
${FLATPAK_DEST}/share/metainfo/io.unom.Punktfunk.metainfo.xml
# Scalable icon named for the app id (GNOME runtime renders SVG via librsvg).
- install -Dm0644 packaging/flatpak/io.unom.Punktfunk.svg
${FLATPAK_DEST}/share/icons/hicolor/scalable/apps/io.unom.Punktfunk.svg
sources:
# The repo checkout. For a Flathub/published build, replace with a pinned git source:
# - type: git
# url: https://git.unom.io/unom/punktfunk
# tag: vX.Y.Z
# commit: <sha>
# For ON-DECK / CI builds we build the checked-out working tree in place:
- type: dir
path: ../..
# Generated offline crate cache (see the comment block above). Remove for --share=network.
- cargo-sources.json