Template stripped to the overlay platform (examples, demo UI and Frame test package removed), renamed to FrameAssistant, and working rules for the project recorded in CLAUDE.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4.4 KiB
Steam Frame
How to build, deploy and run dashboards on the Steam Frame, and what was learned on the
device. Facts below were verified on a Frame with SteamOS holo 0.4.3 (system Qt 6.8.0,
Adreno 750 GPU with Mesa Turnip).
Building
Frame builds run in a Debian container (Docker or Podman), either cross-compiled on an x86_64 PC (no emulation) or natively on the Frame:
scripts/container-build.sh cross # on the PC → build/cross-arm64/stage
scripts/container-build.sh native # on the Frame itself (podman/distrobox)
scripts/container-build.sh cross-bundle # fallback variant, Qt bundled
scripts/container-build.sh cross shell # a shell in the build container
System Qt (default). Builds use SteamOS's own Qt; packages are about 3 MB.
- The container builds against Debian's Qt 6.8.2; at runtime the Frame's Qt 6.8.0 is used. Qt keeps binary compatibility within 6.8, as long as the program uses no Qt-internal API.
- QML is compiled to bytecode only (
VRDASH_QML_BYTECODE_ONLY), because Qt's QML-to-C++ compiler output is tied to the exact Qt version. - The binary then needs only the stable Qt API,
qt_version_tag(Qt ≥ 6.8), and Qt's Vulkan wrapper functions. Verified with an Arch container frozen at Qt 6.8.0 and on the Frame. - After a SteamOS update with a different Qt, rebuild, or use the bundled variant.
Bundled Qt (fallback, -bundle modes, about 46 MB).
- Qt, its plugins and QML modules, and their non-system dependencies are copied next to the
program (
cmake/BundleQt.cmake). - The GPU and display stack (GL/EGL, Vulkan loader, Wayland, X11, libffi, glibc) always comes from SteamOS; bundling it would break GPU access.
- The Debian copyright files of all bundled libraries are included, as their licenses require.
Packaging and deploying
scripts/package-release.sh # → dist/<exe>-<version>-linux-arm64/ + .tar.gz
scripts/package-release.sh --bundle-qt # → …-linux-arm64-bundled
scripts/deploy-to-frame.sh steamos@<frame> # rsync the newest package to ~/<exe>, run install.sh
A release folder contains the program, install.sh (install or update: stops a running
instance, registers with SteamVR, starts it), uninstall.sh, README.txt and the licenses.
SteamVR stores the folder's absolute path, so after moving the folder, run install.sh
again.
Without the deploy script: copy the .tar.gz, unpack it on the Frame, run ./install.sh
(SteamVR must be running). Over SSH this works too: SteamVR starts the dashboard itself.
What the Frame requires (all handled by the overlay platform)
| Finding | Consequence |
|---|---|
SteamVR is installed system-wide under /opt/steamvr; its log is ~/.local/share/Steam/logs/vrserver.txt |
Look there when a manifest or start fails |
The manifest needs binary_path_linux_arm; entries with only binary_path_linux are silently skipped ("must specify binary_path") |
The manifest template picks the key from the target architecture |
SteamVR refuses VRApplication_Utility (VRInitError_Init_NotAvailableToUtilityApps) |
Manifest commands connect as VRApplication_Background (needs a running SteamVR, never starts one) |
An executable named vrdashboard is taken for SteamVR's own dashboard (its watchdog then "restarts" it) |
Executable frame-assistant; CMake rejects SteamVR process names |
| OpenGL runs through zink on Vulkan (no native GL driver for the Adreno) | Vulkan is the default: 1.01 ms vs 1.89 ms per frame (--benchmark, 1600×1000) |
| OpenVR must shut down before the graphics device is destroyed | Teardown order in DashboardApplication::runOverlay() (else a crash at exit with Vulkan) |
| Qt needs a display connection even for off-screen rendering; over SSH none is set | SteamVR-launched instances inherit it; over SSH, set DISPLAY=:0 |
| Process names are cut to 15 characters | Scripts find running instances by command line, not by name |
| Floated/pinned dashboard tabs stay visible and operable in games | Rendering follows the overlay's visibility, not the dashboard's |
Notes
- The Frame's package repositories in
/etc/pacman.confare private (URLs marked "DO_NOT_SHARE"). Don't put them into scripts or this repository. - Valve's public Holo Core preview container (
registry.gitlab.steamos.cloud/holo/ holo-core-aarch64-preview/base-devel) ships Qt 6.10, newer than the Frame's 6.8. It is not usable for system-Qt builds.