Files
punktfunk/docs-site
enricobuehler 979ed8f426 docs(clients/pads): say that an X-Box virtual pad has nowhere to put motion
G17's motion half. The docs described what the CLIENT sends and stopped there, which
made a promise the host does not always keep.

The support matrix said a desktop client forwards motion from any pad SDL exposes a gyro
on "and the host injects it into the matching virtual pad". The first clause is true; the
second is only true when the virtual pad has a motion plane. The X-Box 360 and One
backends do not — no gyro in their HID contract — so the host parses every sample and
discards it. That is where *Automatic* lands anything it does not recognise as Sony or
Valve, an 8BitDo with a perfectly good gyro included, and where a Switch Pro lands on a
Windows host with no `hid-nintendo` backend to fold it into.

A reader following the old text would conclude their gyro was broken. The failure has no
other symptom: motion just does nothing.

So both pages now say what to do about it — pick a DualSense-class type — and the
client-settings page says it where the choice is actually made, next to the degrade
paragraph that explains why a session ends up on an X-Box pad in the first place.

The Deck's Steam-Input requirement moves out of Decky's settings blurb, which is the one
place a Deck user streaming FROM the Deck would never look. With Steam Input on, Steam
hands the app its own virtual X-Box pad, so no controller-type choice can help: there is
no gyro on the pad the client can see.

The picker help text now mentions motion on GTK and Android, which is where it was
missing — Windows already said it and Apple says it in its own words. One sentence, the
same sentence, so the four clients answer the question the same way.

This is the doc side of the on-screen notice that shipped earlier in this branch. The two
exist for the same reason and now agree: the client says it when it detects the case, the
docs say it when someone goes looking.

Not covered: the preset COUNTS in note 1 ("Android and the console home offer six …
Windows and Apple offer five") are still unverified against the four pickers, and the
Apple picker's missing Steam Deck entry is a code gap rather than a doc one. Both are
noted in the plan and left for their own change rather than guessed at here.

Gate: Linux CI image fmt + `clippy --locked --all-targets -D warnings` on
punktfunk-client-linux (the GTK string is compiled) plus the core crates and their tests;
Android `:app:compileDebugKotlin` + `:app:testDebugUnitTest`. Green.
2026-08-07 20:11:28 +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