Steam writes every VR app the user owns into its generated steamapps.vrmanifest, installed or not. Whoever owns OVRAS on Steam therefore always has steam.overlay.1009850 registered, as a steam:// URL without a working directory, and --force-install-manifest failed with "Could not find working directory of already installed application: VRApplicationError_PropertyNotSet" (found on the Steam Frame). Such an entry has no manifest file to remove, so OVRAS now leaves it alone and adds its own manifest. Whether SteamVR accepts a second manifest for the key, and which entry it then uses, is not documented: logApplicationEntry() logs what SteamVR reports for the key after installing, so a test on the Frame shows it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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-07)
- Iteration 1 ("native start on the Frame"): implemented, not yet tested on the Frame.
- 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: test checklist T1–T11 on the Frame (PROGRESS.md), record the results there, 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
qt6branch, the maintainer's Qt 6.8 / CMake port, still in progress.masteris fully merged intoqt6. - 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
4a5b090ingit@git.matzman.net:SteamFrame/FrameAssistant.git; itsdocs/STEAM-FRAME.mdandCLAUDE.mddescribe 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;
Testfor 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 |
Restarts with that graphics API |
./uninstall.sh |
Unregisters |
AdvancedSettings.log |
Log (in the working directory, i.e. this folder) |
Program options (new): --graphics-api opengl|vulkan (default opengl). 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 toBackground, which needs a running SteamVR. VR_Shutdownmust run before the graphics device is destroyed (crash with Vulkan otherwise).
- The manifest needs
- 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). - 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).
- Over SSH there is no display: set
- Private package repositories: the Frame's
/etc/pacman.confpoints 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;qt6doesn't (T5). - Unverified on the Frame:
- QML modules: Controls/Material, Layouts, Dialogs, Multimedia.
- libXt/libXtst present? libstdc++ ≥ GLIBCXX_3.4.32?
- 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.