# 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.