diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..9662167 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,96 @@ +# CLAUDE.md + +Guidance for Claude Code (and humans) working in this fork. Fork-only file: not part of +upstream pull requests. + +**Start with [docs/steamframe/README.md](docs/steamframe/README.md):** goal, status, setup, +commands, Steam Frame facts. Then [REQUIREMENTS.md](docs/steamframe/REQUIREMENTS.md) +(decisions), [DESIGN.md](docs/steamframe/DESIGN.md) and +[PROGRESS.md](docs/steamframe/PROGRESS.md) (status, Frame test checklist). + +## Working rules (agreed with the user, always apply) + +- **Proper software engineering:** follow established procedures and processes, not ad-hoc + hacking. +- **Nothing without explicit permission.** + - Propose first, then act only on the user's go-ahead. + - Permission covers only what was asked. No extra changes, renames, rewrites or "while I'm + at it" fixes: suggest those instead. +- **Ask, don't assume.** When a requirement, decision or detail is unclear, ask. Give a + recommendation with the question. +- **Iterations in phases.** Each phase ends with the user's OK (informal is enough): + 1. requirements + 2. design + 3. implementation + 4. tests + 5. assessment +- Keep iterations small. +- **Document everything** in `docs/steamframe/`: requirements, decisions (with date), design, + progress, test results. Report results faithfully, including what was *not* tested. Keep + the docs in sync with every change. +- **Communication:** the user writes German or English; answer in the user's language. Docs + and code comments are in English. + +## Goal and constraints (details: REQUIREMENTS.md) + +- OVRAS runs natively on the Steam Frame (SteamOS, aarch64). Windows is out of scope for now. +- **Minimal change set against upstream's `qt6` branch**, because changes are meant to go + upstream later. + - Change existing code only where needed. + - Bring new parts in as self-contained files. +- **Only public Qt API.** No `GuiPrivate`/QRhi, and QML is compiled to bytecode only. + `objdump -T … | grep Qt_6_PRIVATE_API` may only show `QVulkan*`. +- **Frame differences:** + - Switched by the CMake option `OVRAS_STEAM_FRAME`. + - It is evaluated **only** in `src/utils/platform_capabilities.h`, which turns it into + capability constants named by capability (e.g. `k_chaperoneCommitSupported`). + - The code asks for capabilities, never for the platform. + +## Code conventions + +- **Comments:** every change gets comments that explain it fully (what and why, e.g. which + Frame or SteamVR fact). Keep them direct and concise. Trivial mechanical changes such as + `LOG(INFO)` → `qInfo()` are explained in the commit message instead. +- **Style:** + - OVRAS style (`.clang-format`, since 2018) everywhere, including code taken over from the + template. + - **Format only changed lines:** `git add …; git clang-format; git add …`. Never + reformat whole existing files, because a dozen files already deviate. + - New files are formatted completely (`clang-format -i`). + - Separate new comments from existing commented-out code with a blank line. Otherwise + clang-format reflows the old block and the diff grows. +- **Commits:** + - One commit per step / topic, with a message that explains the why. + - End every commit message with `Co-Authored-By: Claude …`. + - Push to `origin` (the fork); `upstream` is the GitHub OVRAS repository. +- **Template code** (`src/render/`, `build_scripts/steamframe/`) carries a note about its + origin (vrdashboard template, FrameAssistant `4a5b090`). + +## Architecture notes (what is easy to break) + +- **`main.cpp` order:** + 1. parse the command line + 2. choose the render backend (`--graphics-api`) + 3. `initializeOpenVR(Overlay)` + 4. `backend->initialize(openvr_init::renderInterop())` + 5. `QQuickWindow::setGraphicsApi()` + 6. `OverlayController` + + `setGraphicsApi` must come before any `QQuickWindow` exists, and `OverlayController` owns + one. +- **`OverlayController`:** + - Owns `m_renderBackend`, declared *before* `m_renderControl` / `m_window`: Qt's device + comes from the backend. + - `SetWidget()` and `renderOverlay()` follow the call order in `src/render/RenderBackend.h`. +- **Shutdown:** + - OVRAS ends with `exit()`. + - `Shutdown()` (once only) calls `vr::VR_Shutdown()` *before* `releaseRenderTarget()` / + `detachWindow()`. +- **Tick:** + - `m_pumpEventsTimer`: 1 ms polling in "vsync" mode; in "vsync disabled" mode it runs + directly at `customTickRateMs` (`applyTickInterval()`). + - Frame defaults: vsync disabled, 11 ms. +- **Mouse:** SteamVR reports y from the bottom, so it is flipped on every platform. +- **Logging:** OVRAS writes `AdvancedSettings.log` into the working directory. +- **SteamVR Input:** `action_manifest.json` and `default_action_manifests/` (incl. + `…_default_frame.json` for `frame_controller`) lie next to the binary. diff --git a/docs/steamframe/OVRAS-FEATURES.md b/docs/steamframe/OVRAS-FEATURES.md new file mode 100644 index 0000000..85e3156 --- /dev/null +++ b/docs/steamframe/OVRAS-FEATURES.md @@ -0,0 +1,197 @@ +# OVRAS: features and how they are implemented + +Analysis of 2026-10-07, based on upstream `master` (`31df8b4`, 5.8.17). Line numbers refer to +that state. `qt6` has the same features, so the numbers are close. Paths are relative to +`src/`. Which of these features SteamVR now offers itself is in +[REQUIREMENTS.md](REQUIREMENTS.md), "Feature classification". + +## Architecture + +- **Dashboard overlay:** + - `VR_Init(VRApplication_Overlay)`, app key `steam.overlay.1009850`. + - QML UI (1200×800) rendered off-screen via `QQuickRenderControl`. + - The texture goes to `SetOverlayTexture`. On `steamframe` the render backends in `render/` + do this; before, it was an OpenGL FBO, and on `qt6` QRhi. +- **Input:** SteamVR mouse/scroll events are turned into Qt events (`overlaycontroller.cpp`, + `mainEventLoop()`). +- **Main loop (`OnTimeoutPumpEvents` → `mainEventLoop()`):** + - Timer; "vsync" mode once per compositor frame (`GetTimeSinceLastVsync`). + - Per tick: + 1. input actions + 2. VR events + 3. poses + 4. `eventLoopTick` of the tab controllers (always) + 5. `dashboardLoopTick` (only while the dashboard is visible) +- **SteamVR Input:** `package_files/action_manifest.json`, 5 action sets: + - `motion`: space drag/turn, gravity, snap/smooth turn, height toggle, offsets, auto-turn + - `music`: media keys + - `misc`: axis locks, chaperone toggle, keyboard shortcuts + - `system`: push-to-talk, exclusive input, haptic clicks + - `haptic`: vibration, proximity sensor + + Default bindings exist for Vive, Index, WMR, HP, Touch, generic HMD and Frame controllers. +- **Persistence:** + - App settings in a `QSettings` INI file (`settings/`). Profiles are stored as arrays + (`ISettingsObject`). + - SteamVR's own settings go directly through `vr::VRSettings()` (`openvr/ovr_settings_wrapper`). +- **Platform:** + - Windows: WASAPI / `IPolicyConfig`, `SendInput`. + - Linux: PulseAudio, X11 XTest, D-Bus MPRIS. + - Elsewhere: dummies. + +## Features + +### Playspace movement (`tabcontrollers/MoveCenterTabController.cpp`) + +Almost everything shifts or rotates the **working standing zero pose** through +`IVRChaperoneSetup` and shows it live with `ShowWorkingSetPreview()`. Nothing is committed +per frame. This mechanism does **not work on the Frame** (inside-out tracking). + +- **Core, `updateSpace()` (:2497–2721):** + - Offsets X/Y/Z and the rotation (centidegrees) are multiplied with the stored basis. + - The result goes to `SetWorkingStandingZeroPoseToRawTrackingPose`, in seated mode + additionally to the seated pose. + - Safety limit: about 40 km. +- **Space drag:** + - The controller's position delta, multiplied by `dragMult`, is added to the offsets. + - Axis locks; the speed is kept for fling. + - Comfort mode skips frames. +- **Space turn:** the change of the yaw angle via quaternions + (`q·conj(q_last)`, `quaternion/quaternion.h`). Rotation pivots on the HMD by default. +- **Snap/smooth turn:** fixed angle per press resp. per tick, so smooth turn depends on the + frame rate. +- **Gravity/momentum:** Euler integration with friction, terminal velocity 50 m/s, landing on + the floor, reversible. +- **Height toggle:** Y offset plus a new gravity floor. +- **Offset profiles, apply/reset:** + - "Apply" commits with `CommitWorkingCopy(Live)` (limit 990 m). + - `zeroOffsets()` / `updateChaperoneResetData()` also commit at start-up. On the Frame + this shifts the play area, hence R7. + +### Rotation (`tabcontrollers/RotationTabController.cpp`, via `setRotation`) + +- **Auto-turn:** + - Rotates the space when the user gets near a wall, either as a snap or smoothly. + - Direction: from the corner shared with the last wall, otherwise cord untangling (HMD + total rotation count). +- **Vestibular motion:** rotation as if walking on a circle of radius r + (`2·asin(d/2r)`). +- **View ratchetting:** amplifies head turns away from the wall. + +### Fix floor / recenter (`tabcontrollers/FixFloorTabController.cpp`) + +- **Fix floor:** + - Measures the lower controller over 25 frames. + - Subtracts the controller thickness per model and orientation (Vive / Knuckles). + - Commits the result as a Y offset; undo is possible. +- **Recenter:** `VRChaperone()->ResetZeroPose(...)`. + +### Chaperone (`tabcontrollers/ChaperoneTabController.cpp`) + +- **Settings:** + - Visibility, color, fade distance, wall height, center marker, floor bounds and style. + - These are keys in `k_pch_CollisionBounds_Section`. + - "Disable" sets the fade distance to 0 and remembers the old value. +- **Own center marker overlay:** shows the rotation count (cord). +- **Dim when crouching:** below a height, the fade distance goes to 0 over 10 s. +- **Proximity warnings:** + - Distance of HMD and controllers to the walls (`utils/ChaperoneUtils.cpp`: projection onto + each wall segment). + - Reactions: switch to the beginner style, vibration (own thread, + `TriggerHapticVibrationAction`), alarm sound with distance-dependent volume, open the + dashboard. +- **Chaperone profiles:** + - Save the geometry (`GetLiveCollisionBoundsInfo`, zero pose, size) and the settings. + - Apply them with `SetWorking…` + `CommitWorkingCopy`. + - Autosave profile. + +### Video (`tabcontrollers/VideoTabController.cpp`) + +- **Brightness:** a black overlay right in front of the HMD. Its alpha `(1−x)^(1/3)` + compensates for perception. +- **Color tint:** + - either a colored overlay (`SetOverlayColor`) + - or SteamVR's `HmdDisplayColorGainR/G/B` +- **SteamVR keys:** supersampling (incl. manual override), motion smoothing, supersample + filtering. +- **Video profiles.** + +### Audio (`tabcontrollers/AudioTabController.cpp`, `audiomanager/`) + +- **Interface:** `AudioManager` with a Windows, a PulseAudio and a dummy implementation. +- **Windows:** + - WASAPI/MMDevice, `IAudioEndpointVolume`. + - The default device is set via the undocumented `IPolicyConfig`. + - External changes come in via `IMMNotificationClient`. +- **Linux:** + - PulseAudio: `pa_context_set_default_sink/source`; existing source outputs are moved to + the new source. + - The original state is restored at exit. + - **No mirror device.** +- **Mirror device and device override:** these are SteamVR keys (`k_pch_audio_*`), not + OVRAS's own routing. +- **Push-to-talk / -mute:** SteamVR Input action → mic mute + notification overlay on the + HMD. +- **Mute the mic when the HMD is taken off:** proximity sensor action. +- **Audio profiles.** + +### SteamVR tab (`tabcontrollers/SteamVRTabController.cpp`) + +- **Toggles:** each is a SteamVR setting. + - performance graph, multiple drivers, do not disturb, no-HMD mode + - camera options + - system button to all apps, don't fade to grid, controller power auto-launch +- **Restart SteamVR:** Windows only, via `.bat`. +- **Per-game controller bindings:** + - Use SteamVR's web server `localhost:27062`, with a spoofed `Referer`. + - Saved as JSON and applied when the scene app changes. +- **Receiver/tracker pairing:** WebSocket to the lighthouse web interface (`start_pairing`). +- **`openvr/lh_console_util.cpp`** (`lighthouse_console`) is compiled but **not used**. +- There is no base-station power management. + +### Utilities (`tabcontrollers/UtilitiesTabController.cpp`, `keyboard_input/`, `media_keys/`, `alarm_clock/`) + +- **Keyboard:** + - Buttons (Enter, Alt-Tab, Ctrl-C/V, …) and 3 freely defined shortcuts. + - A parser for the syntax `^`=Ctrl, `*`=Alt, `>`=Shift, `#`=Super. + - Sent via Windows `SendInput` or X11 XTest. On the Frame (gamescope) the X11 path probably + doesn't reach games. +- **Media keys:** + - Windows: `VK_MEDIA_*`. + - Linux: D-Bus to every `org.mpris.MediaPlayer2.*`. +- **Tracker battery:** icon overlay on each tracker (`Prop_DeviceBatteryPercentage_Float`), + only while the dashboard is visible. +- **Alarm clock:** HMD overlay at a set time, shown for 3 s. + +### Statistics (`tabcontrollers/StatisticsTabController.cpp`) + +- **Frame counters:** `VRCompositor()->GetCumulativeStats()` gives presented, dropped, + reprojected and timed-out frames. "Reset" only stores an offset. +- **Distance traveled:** horizontal HMD movement, every 11th tick, steps ≥ 1 cm. +- **Rotation count, maximum controller speed.** + +### Settings tab (`tabcontrollers/SettingsTabController.cpp`) + +Autostart (`SetApplicationAutoLaunch`), native chaperone import, block Oculus SDK, desktop +mode, tick rate (vsync / custom tick rate). + +## Issues found while reading (not verified) + +| Place (master) | Issue | +|---|---| +| `MoveCenterTabController.cpp:1198` | `updateChaperoneResetData()` allocates `new vr::HmdQuad_t[]` on every call and never frees the old array (memory leak) | +| `MoveCenterTabController.cpp:2512` | `if ( m_chaperoneHasCommit ) { m_chaperoneHasCommit = true; … }` looks like a slip | +| `MoveCenterTabController.cpp:1332` | `leftHandSpaceDrag`: the final `else` overwrites the swap/override choice | +| `MoveCenterTabController` | Rotation is wrapped inconsistently (snap/smooth/auto-turn 0–36000 vs. ±18000 elsewhere) | +| `VideoTabController.cpp:114` | Sets the sort order of the brightness overlay instead of the color overlay | +| `ChaperoneTabController.cpp:903` | Floor bounds are read as Bool but written as Int32 | +| `MoveCenterTabController::zeroOffsets` | If `GetCalibrationState() == 200`, init never completes and the commit repeats every tick (with commits enabled) | +| `utils/FrameRateUtils.cpp`, `openvr/lh_console_util.cpp` | Compiled but unused | + +Found on the `qt6` branch and fixed on `steamframe` (see PROGRESS.md): +- the build fails on Linux +- QRhi Vulkan path: wrong `m_nFormat` (Qt enum instead of `VkFormat`); no layout transition, + no SteamVR extensions, no choice of the HMD's GPU +- mouse y not flipped on Linux +- no `VR_Shutdown` +- hard-coded version 5.7.4 diff --git a/docs/steamframe/PROGRESS.md b/docs/steamframe/PROGRESS.md index 8c9fc9e..2dd9d52 100644 --- a/docs/steamframe/PROGRESS.md +++ b/docs/steamframe/PROGRESS.md @@ -1,5 +1,8 @@ # Steam Frame port: progress +**Status (2026-10-07): iteration 1 implemented. Next: test checklist T1–T11 on the Frame +(at the end of this file), then assessment. Getting started: [README.md](README.md).** + ## Iteration 1 ### Step 1: build fixes, bytecode-only QML (2026-10-07) @@ -186,3 +189,12 @@ Deploy: `build_scripts/steamframe/deploy-to-frame.sh @` (SteamVR ru | T9 | Auto-start after a SteamVR restart / reboot | R2 | open | | T10 | `pidstat -p $(pgrep -f AdvancedSettings_app) 10 6`: dashboard closed / OVRAS visible / other tab visible | R6 | open | | T11 | `uninstall.sh` unregisters it | R2 | open | + +### Wrap-up (2026-10-07) + +- **Remotes:** `origin` = `git@git.matzman.net:SteamFrame/OpenVR-AdvancedSettings-frame.git` + (branches `steamframe`, `qt6`, `master`); `upstream` = GitHub OVRAS. +- **Handover documentation:** `docs/steamframe/README.md` (entry point), `CLAUDE.md` + (working rules, conventions), `docs/steamframe/OVRAS-FEATURES.md` (feature analysis). +- **Still open in iteration 1:** phase 4 (tests on the Frame, T1–T11) and phase 5 + (assessment). diff --git a/docs/steamframe/README.md b/docs/steamframe/README.md new file mode 100644 index 0000000..200c6b1 --- /dev/null +++ b/docs/steamframe/README.md @@ -0,0 +1,170 @@ +# 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](REQUIREMENTS.md) | Goal, decisions (with dates), requirements per iteration, feature classification | +| [DESIGN.md](DESIGN.md) | Design of iteration 1 (approved): what changes where, and why | +| [PROGRESS.md](PROGRESS.md) | What was done per step, test results, **test checklist for the Frame** | +| [OVRAS-FEATURES.md](OVRAS-FEATURES.md) | OVRAS's features and how they are implemented; issues found while reading | +| [`/CLAUDE.md`](../../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 (3.0 MB). +- **Next step:** test checklist T1–T11 on the Frame ([PROGRESS.md](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 **`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 + +```sh +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 + +```sh +# 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--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 @ +``` + +**Check for private Qt API** (R1). Only `QVulkan*` may appear: + +```sh +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 to + `Background`, which needs a running 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). + - 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). +- **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`.