Frame Control: Mac app, web UI, Android and Steam tooling

Package the Frame Control web UI as an installable Electron Mac app and
bring in the tooling built alongside it.

- app/: Electron wrapper that starts ui/server.py on a free loopback port,
  hardened window (sandbox, no navigation, runAsNode fuse off), login-shell
  PATH so Homebrew tools work from Finder, first-run offer to run
  connect.sh, ad-hoc signed DMG/zip via electron-builder.
- ui/: headset view (OpenVR screenshots), device status, library, Steam
  "Get games" (owned games, install, store search), Android apps as
  persistent Lepton instances with a rated F-Droid catalogue and a private
  compatibility database, Android display controls over ADB, file and
  clipboard transfer, Flatpaks, remote and power actions.
- apk-catalog/, compat-db/, frame/: catalogue build pipeline, Lakebed
  capsule for compatibility reports, Frame-side launchers.
- tests/ and CI: server guard and validation tests plus Steam helper tests,
  run on Python 3.9 with script and app syntax checks.
- Docs: README leads with the Mac app; new Android, panels, Steam games and
  field-notes docs; security notes on LAN-exposed ADB ports.

Screenshot values for the headset's IP and Wi-Fi name are placeholders.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
saphidandClaude Opus 5.5 committed 2026-09-25 22:21:20 +10:00
1 parent 6ccf562756
commit d4486a7681
56 files changed
+19298 -11

No files matched your search

+58
View File
@@ -0,0 +1,58 @@
# compat-db: Frame Control's compatibility database
A private [Lakebed](https://docs.lakebed.dev/) capsule holding compatibility
reports for Android apps on the Steam Frame. Only Frame Control can read or
write it.
- Live: `https://frame-compat.lakebed.app` (deploy `dep_dDmcsosVSiFirpW6`,
owned by `saphid`, doesn't expire). The browser page only says it's private.
- Access: `GET /v1/reports?since=<createdAt>` and `POST /v1/reports` with
`{"reports": [...]}`. Both need the `x-frame-control-key` header. There are
no Lakebed queries or mutations, so nothing else can reach the rows.
- Key: `FRAME_CONTROL_KEY` in `.env.lakebed.server` (git-ignored, synced on
deploy) and in the Mac's login Keychain (service `frame-control-compat-db`,
account `app-key`), where `ui/frame_compat_db.py` reads it.
- Duplicates: each report carries a `clientId`, and a report already stored is
skipped, so retries and restores are safe to repeat.
- Free-plan limits: 1 MiB of data and 16,384 rows per deploy, 1,000 writes a
day. A report is about 300 bytes, so roughly 3,000 reports fit.
## Backups
`scripts/compat-db-backup.sh` exports every report through the app key and
keeps dated copies in
`~/Library/Application Support/Frame Control/compat-db/backups` (newest 60).
When the data has changed, it also uploads them to Google Drive
(**the backup folder**, folder
`<drive-folder-id>`) with `gog`. The LaunchAgent
`frame-compat-backup` runs it daily at 03:40; the log is
`~/Library/Logs/frame-compat-backup.log`. If an export has fewer reports than
the last good backup (`backups/.last-good`), it's kept as `refused-*.json`,
nothing is uploaded, and every later run refuses too until you rerun with
`--accept-shrink`.
Reports that can't be sent (unreadable outbox lines, or ones the server
rejects, which it lists by `clientId`) are never dropped: they move to
`~/Library/Application Support/Frame Control/compat-db/compat-outbox.jsonl.rejected`,
with the reason.
Restore (to this deploy or a new one):
```sh
python3 ui/frame_compat_db.py import BACKUP.json # duplicates are skipped
python3 ui/frame_compat_db.py count
```
`npx lakebed db export dep_dDmcsosVSiFirpW6 --out full.json` is a second,
owner-only export path through the Lakebed CLI.
## Change and deploy
```sh
cd compat-db
npx lakebed dev --port 3917 # local; data resets on restart
npx lakebed deploy # updates frame-compat.lakebed.app
```
To rotate the key: generate a new one, update the Keychain item and
`.env.lakebed.server`, then deploy.