Files
OpenVR-AdvancedSettings-frame/docs/steamframe
matzmanandClaude Opus 5.5 5a10cdf7ca Wrap-up documentation after the first tests on the Steam Frame
README: status, new Steam Frame facts (Steam's generated app manifest,
OpenVR library, display and font metrics) and open points. PROGRESS:
partial results of T1, T2 and T4, and what is open next.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 00:21:52 +02:00
..

OVRAS for the Steam Frame: start here

This fork ports OpenVR Advanced Settings (OVRAS) so that it runs natively on the Steam Frame (SteamOS, aarch64, standalone) as a SteamVR dashboard tab. This file is the entry point for continuing the work on any computer.

Document Content
REQUIREMENTS.md Goal, decisions (with dates), requirements per iteration, feature classification
DESIGN.md Design of iteration 1 (approved): what changes where, and why
PROGRESS.md What was done per step, test results, test checklist for the Frame
OVRAS-FEATURES.md OVRAS's features and how they are implemented; issues found while reading
/CLAUDE.md Working rules and conventions (for people and for Claude Code)

Status (2026-10-08)

  • Iteration 1 ("native start on the Frame"): implemented; testing on the Frame has started (phase 4). OVRAS starts natively on the Frame, the dashboard tab appears, laser and navigation work, the root page and "Chaperone Settings" fit (OpenGL). Five problems found on the first deployment were fixed (details in PROGRESS.md): manifest commands without a display, wrong aarch64 OpenVR library, app key already registered by Steam, debug log flood, layout cut off (Material style).
  • Tested without a headset:
    • Linux x86_64 build.
    • aarch64 cross build: no private Qt API except QVulkan*, Qt 6.8, GLIBC ≤ 2.38.
    • Render tests with OpenGL and Vulkan; Vulkan with validation layers and no messages.
    • Release package (1.6 MB).
  • Next step: continue on the Frame: page-by-page layout check with --snapshot, then the rest of the test checklist T1–T11 (PROGRESS.md, "Wrap-up (2026-10-08)" lists what is open), then assessment.
  • After that: iteration 2. R5 hides the features that are native in SteamVR or don't work on the Frame. Then the remaining features are checked one by one.

Background in brief

  • Proton: The Windows build of OVRAS runs on the Frame through Proton. Its laser y-axis is mirrored there, which makes it unusable, and it is inefficient (x86 emulation + Wine).
  • Basis: the fork is based on upstream's qt6 branch, the maintainer's Qt 6.8 / CMake port, still in progress. master is fully merged into qt6.
  • Goal: a minimal change set against qt6, so changes can later go upstream as pull requests.
  • Template: the platform knowledge comes from the author's vrdashboard template, verified on the Frame. Its baseline is commit 4a5b090 in git@git.matzman.net:SteamFrame/FrameAssistant.git; its docs/STEAM-FRAME.md and CLAUDE.md describe the Frame. From it come the render backends (src/render/) and the build/package scripts (build_scripts/steamframe/).
  • Hard rule: only public Qt API. The binary must run on the Frame's system Qt (6.8.0). QRhi (private) was therefore replaced and QML is compiled to bytecode only.

Repository, branches, remotes

Branch Meaning
steamframe The work branch. Based on qt6 (2d4db7e).
qt6 Mirror of upstream's qt6 at 2d4db7e (reference / diff base)
master Mirror of upstream's master at 31df8b4 (5.8.17)

Commits on steamframe (one per step; use for later pull requests):

aac3edf Steam Frame port: requirements and design of iteration 1
266a2f9 Fix the Linux build of the qt6 branch, compile QML to bytecode only
423ea57 Add a Steam Frame build option; no chaperone commit at start; timer-based tick
4826686 Render through public Qt API: OpenGL and Vulkan backends, --graphics-api
b22c35a Manifest for Linux; connect as Background app where Utility is refused
bde675f Steam Frame build, packaging and deployment scripts; render test
3ed686d Read the version from build_scripts/compile_version_string.txt

Then the handover documentation (this file, CLAUDE.md, OVRAS-FEATURES.md).

Fork-only files that don't belong in an upstream pull request: docs/steamframe/, CLAUDE.md.

Setting up on another computer

git clone -b steamframe git@git.matzman.net:SteamFrame/OpenVR-AdvancedSettings-frame.git
cd OpenVR-AdvancedSettings-frame
git remote add upstream https://github.com/OpenVR-Advanced-Settings/OpenVR-AdvancedSettings.git
git fetch upstream          # to see whether upstream's qt6 has moved on

Requirements:

  • For the Frame build and the tests: Docker or Podman (containers based on Debian trixie; they bring Qt 6.8 and everything else).
  • For a local Linux build (optional):
    • CMake ≥ 3.20, Ninja, GCC/Clang (C++20).
    • Qt ≥ 6.8 with Quick, QuickControls2, QuickDialogs2, Multimedia, WebSockets, Svg, DBus; Test for the tests.
    • Vulkan headers.
    • libpulse, libX11, libXt, libXtst.
    • Tested on Arch with Qt 6.11.
  • For deployment: SSH access to the Frame, rsync.

Commands

# Local build (x86_64), optionally with tests
cmake -S . -B build/x86 -G Ninja -DCMAKE_BUILD_TYPE=Debug -DOVRAS_BUILD_TESTS=ON
cmake --build build/x86
ctest --test-dir build/x86                 # render tests: OpenGL and Vulkan
# -DOVRAS_STEAM_FRAME=ON: Frame capabilities/defaults (src/utils/platform_capabilities.h)

# Frame (aarch64) build in the container → build/steamframe-cross/Release/
build_scripts/steamframe/container-build.sh cross
build_scripts/steamframe/container-build.sh cross shell    # shell in the container

# Tests in the container, Vulkan with validation layers (must print "No Vulkan validation messages")
build_scripts/steamframe/container-test.sh
VK_DRIVER=lvp build_scripts/steamframe/container-test.sh    # software Vulkan

# Package → dist/AdvancedSettings-<version>-linux-arm64(.tar.gz)
build_scripts/steamframe/package-release.sh                # builds first; --no-build packages only

# Copy to the Frame and install (SteamVR must be running there)
build_scripts/steamframe/deploy-to-frame.sh <user>@<frame>

Check for private Qt API (R1). Only QVulkan* may appear:

docker run --rm -v "$PWD:$PWD" -w "$PWD" ovras-steamframe-cross-arm64 \
  aarch64-linux-gnu-objdump -T build/steamframe-cross/Release/AdvancedSettings_app \
  | grep Qt_6_PRIVATE_API | grep -v QVulkan

On the Frame (in ~/AdvancedSettings/):

Command Effect
./install.sh Registers with SteamVR (auto-start) and starts
./run.sh opengl|vulkan [options] Restarts with that graphics API; further options go to the program
./uninstall.sh Unregisters
AdvancedSettings.log Log (in the working directory, i.e. this folder)

Program options (new): --graphics-api opengl|vulkan (default opengl); --snapshot <file> (diagnosis: writes the rendered overlay as PNG at most once per second while visible). Existing ones include --force-install-manifest and --force-remove-manifest; see --help.

Steam Frame facts the code relies on

Verified with the template on SteamOS holo 0.4.3; details in FrameAssistant's docs/STEAM-FRAME.md.

  • Runtime:
    • The system Qt is 6.8.0, with Multimedia, WebSockets, DBus, Svg and Widgets.
    • libpulse is present.
    • GLIBC is 2.39.
  • Manifest and SteamVR:
    • The manifest needs binary_path_linux_arm; entries without it are skipped silently.
    • SteamVR refuses VRApplication_Utility. Manifest commands therefore fall back to Background, which needs a running SteamVR. (2026-10-07: with OVRAS, SteamVR accepted Utility; the fallback stays.)
    • Steam's generated ~/.local/share/Steam/config/steamapps.vrmanifest lists every VR app the user owns, installed or not, with a steam:// URL. For a key listed there, SteamVR keeps using Steam's entry even after our manifest is added (seen 2026-10-07).
    • Use the OpenVR SDK's bin/linuxarm64/libopenvr_api.so; the SDK's lib/linuxarm64 one looks for the path registry in /data/work and never finds SteamVR.
    • VR_Shutdown must run before the graphics device is destroyed (crash with Vulkan otherwise).
  • Rendering and input:
    • OpenGL runs through zink (no native GL driver); Vulkan is about 1.9× faster per frame.
    • SteamVR reports overlay mouse coordinates with y from the bottom.
  • Processes and display:
    • Over SSH there is no display: set DISPLAY=:0 (the scripts do). Commands that draw nothing run with QT_QPA_PLATFORM=offscreen.
    • X screen 1920×1080 with Xft.dpi: 144, yet Qt reports logical DPI 96 and device pixel ratio 1 for OVRAS; default font Noto Sans (20 pt = 27 px).
    • Process names are cut to 15 characters: find instances by command line.
    • An executable must not be named like a SteamVR process (e.g. vrdashboard).
  • Private package repositories: the Frame's /etc/pacman.conf points to private Valve repositories marked "DO_NOT_SHARE". Never put those URLs into the repository.

Known open points and risks

  • SteamVR keyboard: text fields may not get focus. The template had to send the offscreen window an explicit FocusIn; qt6 doesn't (T5).
  • App key taken by Steam's entry: whoever owns OVRAS on Steam has steam.overlay.1009850 in Steam's steamapps.vrmanifest, and SteamVR keeps using that entry (auto-start would launch the Steam version). On the author's Frame it is still listed after removing the license from the account. Possible fix: an own app key for the native build (option 2, DESIGN.md section 2a; needs its own design).
  • Unverified on the Frame: QML modules Dialogs and Multimedia (Controls, Layouts and the binary's libraries load, since OVRAS runs).
  • Remaining play-area commit: "auto-apply chaperone" (opt-in, default off) still commits at start-up; this belongs to R5.
  • Windows: the Windows build is broken on steamframe. There is no D3D11 render path anymore (decision D1: evaluated later, together with upstream).
  • Version: OVRAS's version comes from build_scripts/compile_version_string.txt.