ci / bun-nix (pull_request) Successful in 25s
ci / web (pull_request) Successful in 1m8s
ci / docs-site (pull_request) Successful in 1m16s
ci / rust-arm64 (pull_request) Successful in 1m41s
android / android (pull_request) Successful in 3m22s
ci / rust (pull_request) Failing after 7m33s
Android was the one app that could open a punktfunk:// link but never hand one out, so every Android link had to be typed by hand — and the host's stable record id, which is the part that keeps a link working after the box changes address, isn't shown anywhere in the UI to type. Both homes now offer Copy link: the touch grid's card overflow menu, and the controller home's host options (Up on a tile). A pinned card copies its own profile with it, matching Linux and Apple; a host card copies none and so keeps honouring the host's binding, exactly like tapping it does. The URL is the shared self-emitted form (DeepLinks.forHost), already covered by the cross-language vector tests, so the three emitters stay in step. Android 13+ draws its own clipboard confirmation and we add nothing on top of it; below that we say so ourselves, as a toast in the console home, which renders neither banner.
197 lines
11 KiB
Markdown
197 lines
11 KiB
Markdown
---
|
|
title: Profiles and links
|
|
description: How settings profiles override your client defaults per host or per connect, and how punktfunk:// links start a stream from a shortcut, a script or a browser.
|
|
---
|
|
|
|
Two features that landed together in 0.22.0 and work with each other: **settings profiles**, named
|
|
bundles of stream settings you can attach to a host, and **`punktfunk://` links**, URLs that start a
|
|
stream you have already set up.
|
|
|
|
Both live in the client apps — the Apple app, the Linux GTK client, the Windows client and the
|
|
Android app. Neither exists in the host's [web console](/docs/web-console).
|
|
|
|
The controller-driven surfaces are a half-exception: Apple TV, the Android app's console mode and
|
|
the Steam Deck console the Decky plugin launches all *use* the profile a host is bound to and can
|
|
pin one as its own card, but none of them can create or edit one. Do that on a desktop or a phone
|
|
first. The Decky panel itself only *shows* those pins, nested under their host as one-tap cards.
|
|
|
|
## What a profile is
|
|
|
|
A profile is a *sparse* set of overrides on top of your normal client settings. Only the rows you
|
|
actually touch are stored. Everything else keeps following your defaults **live**, so changing a
|
|
default later also moves every profile that never overrode it.
|
|
|
|
Touching a row records the override even when you pick the value the default already has. That is a
|
|
deliberate *pin*: the profile keeps that value when the default later moves. The only way back to
|
|
inheriting is the row's explicit **Reset**.
|
|
|
|
Where the catalog is kept:
|
|
|
|
| Client | Stored in |
|
|
|---|---|
|
|
| Linux | `~/.config/punktfunk/client-profiles.json` |
|
|
| Windows | `%APPDATA%\punktfunk\client-profiles.json` |
|
|
| Apple | the app-group store, beside your saved hosts |
|
|
| Android | app-private storage |
|
|
|
|
The catalog is per device, and nothing syncs it, so a profile you make on your laptop doesn't appear
|
|
on your phone.
|
|
|
|
## Creating and editing one
|
|
|
|
Profiles are created and edited in the client's own **Settings** screen — there is no second editor,
|
|
so a profile can never drift from the surface it overrides.
|
|
|
|
1. Open Settings. At the top is a scope switcher listing **Default settings**, your profiles, and a
|
|
**New profile** entry. Linux, Windows and iOS label the control **Editing**; macOS heads the
|
|
preferences window with the layer's name; Android shows the choices as a row of chips.
|
|
2. Create a new profile. Linux, Apple and Android ask for a name (and a colour) first; Windows
|
|
creates one called *Profile 1* and opens its edit sheet, where you rename it. Names must be
|
|
unique, ignoring case.
|
|
3. Change the rows you want. Every row shows the *effective* value — the inherited default until you
|
|
touch it.
|
|
4. A row you have overridden grows a marker and a **Reset** control. Reset drops that one override
|
|
and puts the row back to following your defaults.
|
|
|
|
Each profile can carry a colour from a small preset palette (the exact swatches differ slightly
|
|
between apps). It tints the profile's chip on host cards, so a grid of hosts is readable at a
|
|
glance.
|
|
|
|
Renaming, duplicating (overrides and colour included) and deleting sit next to the switcher on
|
|
Linux and in the same menu on Apple. Windows puts them in the sheet the switcher's **Edit** entry
|
|
opens; Android puts them on the selected profile's own chip — tap it a second time.
|
|
|
|
While a stream runs with a profile, the profile's name closes the first line of the
|
|
[stats overlay](/docs/stats) — on the Apple client, from the Normal tier up.
|
|
|
|
## What a profile can't change
|
|
|
|
In profile scope, rows that aren't profileable simply don't render. They are facts about *this
|
|
device* — the video decoder and GPU it uses, its audio endpoints, which physical controller you
|
|
hold, whether it wakes hosts on connect and whether it shows a game library — not about how you
|
|
want a stream to look. **Share clipboard** is out for the neighbouring reason: it's a per-host trust
|
|
decision stored on the host record rather than a client setting at all — see
|
|
[Clipboard](/docs/clipboard).
|
|
|
|
The row-by-row list, and why each row stays global, is on
|
|
[Client settings](/docs/client-settings#settings-that-are-facts-about-your-device).
|
|
|
|
## Three ways to use a profile
|
|
|
|
**Bind it to a host.** Open a saved host's edit sheet and set **Profile**. Every plain click on that
|
|
host's card now uses it. This is the only sticky choice. (The Apple app also offers **Connect with ▸
|
|
Set Default Profile** on the card itself.)
|
|
|
|
**Use it once.** A card's menu has **Connect with** — pick a profile for this connect only. It never
|
|
rebinds the host. **Default settings** in that menu is a real choice: on a bound host it forces your
|
|
globals for one session. (Android lists the same choices flat, as *Connect with: …*.)
|
|
|
|
**Pin it as its own card.** A pinned profile gets its own card beside the host — one click, no menu.
|
|
Pin it in the host's edit sheet on Linux, Android and Apple, or from a card menu: **Pin as Card** on
|
|
Apple, **Pin as card: …** on Android, **Pin tiles** on Windows. A pinned card is a shortcut, not a
|
|
second host: unpinning changes neither the profile nor the host's binding.
|
|
|
|
## Deleting a profile
|
|
|
|
The confirmation tells you what breaks: how many hosts will fall back to **Default settings**, and
|
|
how many pinned cards will disappear. Bindings and pins are deliberately left pointing at the gone
|
|
profile rather than rewritten; everywhere they are read, a dangling reference resolves as "no
|
|
profile", which is exactly your defaults. Nothing errors and no connect is blocked.
|
|
|
|
## `punktfunk://` links
|
|
|
|
A link starts a stream on a host this device already trusts. All four apps register the scheme with
|
|
the operating system, so a link works from a browser (behind the browser's own "open this app?"
|
|
prompt), a desktop shortcut, a home-automation rule or a script:
|
|
|
|
```text
|
|
punktfunk://connect/<host-ref>[?fp=<64-hex>][&host=<addr[:port]>][&launch=<id>][&profile=<ref>][&name=<label>]
|
|
```
|
|
|
|
`<host-ref>` is a saved host's stable record id, its name (unique, ignoring case), or `addr[:port]`.
|
|
Resolution goes in that order, and a name matching two saved hosts is refused rather than guessed.
|
|
|
|
| Parameter | Means |
|
|
|---|---|
|
|
| `fp` | the host certificate fingerprint the link expects — 64 hex characters |
|
|
| `host` | `addr[:port]` to fall back on when the reference no longer resolves; port defaults to `9777` |
|
|
| `launch` | a store-qualified [library](/docs/game-library) id such as `steam:570`, launched on arrival |
|
|
| `profile` | a settings profile, by id or unique name — for this connect only |
|
|
| `name` | a display label, shown as *claimed*, never trusted |
|
|
|
|
The scheme and the route word are case-insensitive, a trailing slash is fine, a `#fragment` is
|
|
dropped, unknown parameters are ignored, an empty value means "not given", and if a parameter
|
|
appears twice the first one wins. `pf://` parses as an input alias, but nothing emits it and no app
|
|
registers it with the operating system, so write `punktfunk://`.
|
|
|
|
`connect` is the only route any client acts on today; `wake` and `browse` parse, but every client
|
|
answers them with a notice. Values are capped (2048 for the whole URL, 128 for the host reference
|
|
and `launch`, 64 for `profile` and `name`), and `launch` must be printable ASCII with no spaces,
|
|
quotes, backslashes, `$` or backticks.
|
|
|
|
Worked examples:
|
|
|
|
```text
|
|
punktfunk://connect/Living%20Room%20PC
|
|
punktfunk://connect/Living%20Room%20PC?launch=steam:570
|
|
punktfunk://connect/Living%20Room%20PC?profile=Work
|
|
```
|
|
|
|
## What a link can and can't do
|
|
|
|
The rule the grammar exists to keep: **a link may only do what clicking a card you already have
|
|
could do, minus every trust decision.**
|
|
|
|
- It carries *references*, never values. There is no resolution, bitrate, codec or HDR parameter,
|
|
so a web page cannot shape your session beyond choosing among your own configurations.
|
|
- There is no `pair` route and never will be. `punktfunk://pair/...` is refused outright;
|
|
[pairing](/docs/pairing) stays something you do with the fingerprint on screen.
|
|
- A link naming a host you don't know is never connected. When it carries an address — as
|
|
`<host-ref>` or as `host=` — Linux and Android open the app's normal trust prompt, pre-filled with
|
|
that address and any `fp` the link carried, so the first connect is verified rather than blind.
|
|
Windows and the Apple apps show a notice naming the host instead, and you pair from the host list
|
|
yourself. A link with no address to fall back on — a bare name or a stale record id — is simply
|
|
refused with a notice.
|
|
- If the link's `fp` contradicts the fingerprint already pinned for that host, it is a hard refusal
|
|
with a notice. Nothing connects.
|
|
- A `profile=` that names nothing on this device, or two profiles at once, refuses **before**
|
|
anything is dialled — a shortcut that can't honour its profile says so rather than streaming with
|
|
the wrong settings. A link with no `profile=` honours the host's binding, exactly like a click.
|
|
- A link never preempts a running session. Linux and Windows say "A session is already running — end
|
|
it first". Apple and Android do the same, except when the link points at the host you are already
|
|
streaming, which just brings the app forward.
|
|
|
|
## Getting a link, and making a shortcut
|
|
|
|
On Linux and Windows a host card's menu has **Copy link** and **Create shortcut…**. On macOS and iOS
|
|
the card menu has **Copy Link**; tvOS has no clipboard, so it isn't offered there. Android has
|
|
**Copy link** in both of its homes — the touch grid's card menu, and the controller home's host
|
|
options (press Up on a host's tile).
|
|
|
|
On Linux, Apple and Android a pinned card has its own menu, and the link it hands out carries that
|
|
card's profile. Windows pinned tiles have no menu, and neither Windows action adds a `profile=`, so a
|
|
Windows link always uses the host's binding until you edit the URL yourself.
|
|
|
|
A copied link carries the host's stable record id, plus `host=` and `fp=` (the fingerprint only when
|
|
one is pinned). That is what keeps a shortcut written today working after the host changes address
|
|
or you reinstall the client.
|
|
|
|
**Create shortcut…** writes a launcher wrapped around that URL:
|
|
|
|
- **Linux** — a desktop entry in `~/.local/share/applications/`, which shows up in your app menu.
|
|
Under Flatpak the sandbox can't write there, so the app offers you the URL to place yourself.
|
|
- **Windows** — a `.lnk` on your Desktop that runs `punktfunk-client.exe` with the URL as its
|
|
argument, so it keeps working across updates.
|
|
|
|
Any other launcher works too, as long as it hands the URL to the client. From a script, or on a
|
|
headless box, use the `punktfunk` CLI:
|
|
|
|
```bash
|
|
punktfunk profiles list # ids, names, how many settings each overrides
|
|
punktfunk open 'punktfunk://connect/Desk?profile=Work'
|
|
```
|
|
|
|
It ships in the Linux client packages and in the Windows MSIX. The Flatpak build has it too, but
|
|
inside the sandbox — reach it with `flatpak run --command=punktfunk io.unom.Punktfunk`. See
|
|
[Clients](/docs/clients) for the rest of its verbs.
|