Files
punktfunk/docs-site
enricobuehler bed58b75b6
ci / web (pull_request) Successful in 1m0s
ci / bun-nix (pull_request) Successful in 1m11s
ci / docs-site (pull_request) Successful in 1m18s
apple / swift (pull_request) Successful in 1m34s
apple / screenshots (pull_request) Skipped
ci / rust-arm64 (pull_request) Successful in 4m5s
ci / rust (pull_request) Successful in 6m27s
feat(apple): the statistics overlay is reachable on tvOS
An Apple TV session had no way to the stats overlay at all. Every other client
cycles it in-stream — Ctrl+Alt+Shift+S on the desktops, a three-finger tap on
touch — and tvOS has neither a keyboard nor a screen to tap, so the only route
was Settings before connecting (or a profile). The docs' own "cycle with" table
simply had no row for it.

Two surfaces, because an Apple TV may have a controller in the room or only the
remote:

- Select + X on a controller, cycling one tier per completion. Built like
  Android's mic chord (Select + Y) and deliberately disjoint from the escape
  chord — X is none of its four buttons, so reaching for one can never trip the
  other. Read off the wire mask like the escape chord, so a Select the
  hold-Select gesture has turned into a guide can't cycle the overlay on its way
  past. Available on every Apple platform: a controller in both hands is exactly
  the case the keyboard combo and the three-finger tap can't serve.

- Hold Play/Pause on the Siri Remote. Its right-click is therefore deferred until
  the press resolves — a tap still right-clicks, delivered on release with the
  release trailing by TAP_PRESS — because a right button held for half a second
  is a context menu on every desktop this streams.

A non-forwarding slot now claims the stats chord's elements too, alongside the
escape chord's: on tvOS an unclaimed button's press stays the system's and the
chord would silently never complete.

Tests pin both chords' masks against their GameController alias lists, that the
two overlap only on Select, and that the claim list covers both without
duplicates — the failure mode is nothing happening, with nothing logged.
2026-08-08 23:24:09 +02:00
..

punktfunk-docs

The Punktfunk documentation site: Fumadocs on TanStack Start (Vite + Nitro/bun preset).

Content lives in content/docs/ as .md/.mdx. This site is the source of truth for the user-facing guides; design rationale lives in the internal punktfunk-planning repo.

API reference

/api renders the host's management REST API as an interactive Scalar reference (linked from the top nav, the docs sidebar, and the landing page). It reads public/openapi.json — a snapshot of the repo's generated spec. Refresh it after a management-API change:

# from the repo root — regenerate the spec, then copy the snapshot in:
cargo run -p punktfunk-host -- openapi > api/openapi.json
cp api/openapi.json docs-site/public/openapi.json

Nothing in CI diffs the two, so the snapshot goes stale silently — that manual cp is the only thing keeping them in sync. Before publishing docs, check that they match:

diff <(jq -S . api/openapi.json) <(jq -S . docs-site/public/openapi.json)

That should print nothing. Right now it doesn't: the committed snapshot predates the /api/v1/update/check, /api/v1/update/apply and /api/v1/update/status endpoints, so the published /api reference is missing the host self-update surface — re-copy it.

Develop

bun install
bun run dev        # http://localhost:3001  (docs at /docs)

CI gates every change on bun run build followed by bun run lint (the TypeScript typecheck), in that order — the build emits the .source typegen the typecheck imports. Run both before you push.

Build & serve

bun run build
bun run start      # serves .output/ via Bun

Layout

source.config.ts          Fumadocs MDX collection (content/docs)
content/docs/             the docs content (.md/.mdx) + meta.json nav
src/
  routes/
    __root.tsx            RootProvider + html shell
    index.tsx            landing page
    docs/$.tsx           catch-all docs renderer (Fumadocs DocsLayout)
    api/index.tsx        Scalar API reference (reads public/openapi.json)
    api/search.ts        Orama search endpoint
  lib/source.ts          Fumadocs loader over the generated collection
  lib/layout.shared.tsx  shared nav chrome
  components/mdx.tsx      MDX component map
  styles/app.css          Tailwind 4 + Fumadocs preset