# Roadmap: Beyond 2 SteamVR Proximity Driver

## Milestones

- ✅ **v1.0 Beyond 2 SteamVR Proximity Driver** — Phases 1-9 (shipped 2026-03-23)
- 📋 **v2.0 Live IPD Change** — Phases 10-13 (planned)

## Phases

<details>
<summary>✅ v1.0 Beyond 2 SteamVR Proximity Driver (Phases 1-9) — SHIPPED 2026-03-23</summary>

- [x] Phase 1: Skeleton Driver and Coexistence (2/2 plans) — completed 2026-03-21
- [x] Phase 2: HID Access Validation (2/2 plans) — completed 2026-03-22
- [x] Phase 3: Proximity Component Spike (2/2 plans) — completed 2026-03-22
- [x] Phase 3.1: Remove Virtual Tracker (2/2 plans) — completed 2026-03-22
- [x] Phase 3.2: Integrate into Official Beyond Driver Package (2/2 plans) — completed 2026-03-22
- [x] Phase 4: HID Data Pipeline (2/2 plans) — completed 2026-03-22
- [x] Phase 5: Proximity Algorithm (2/2 plans) — completed 2026-03-22
- [x] Phase 6: Standby/Wake Integration (2/2 plans) — completed 2026-03-22
- [x] Phase 7: Configuration (2/2 plans) — completed 2026-03-23
- [x] Phase 8: Robustness and Logging (2/2 plans) — completed 2026-03-23
- [x] Phase 9: Installer for Tester Distribution (2/2 plans) — completed 2026-03-23

</details>

### v2.0 Live IPD Change

- [x] **Phase 10: Feasibility Spike** - Confirm property-based IPD works from sidecar and determine lighthouse driver interaction (completed 2026-03-24)
- [x] **Phase 10.1: SetDisplayEyeToHead Spike** - Test whether sidecar can call SetDisplayEyeToHead for HMD it doesn't own (critical gate for Phase 11) (completed 2026-03-24, GO)
- [x] **Phase 11: Core IPD Pipe Command** - Named pipe `ipd` command with validation, query, CLI support, and startup state (completed 2026-03-26)
- [x] **Phase 12: SteamVR IPD Slider UI** - Enable dashboard slider and detect slider-driven IPD changes (completed 2026-03-28)
- [x] **Phase 13: Slider Persistence and Hardening** - Persist slider IPD changes to headset config via lighthouse_console (completed 2026-04-06)

## Phase Details

### Phase 10: Feasibility Spike
**Goal**: Confirm the property-based IPD mechanism works from the sidecar driver, resolving all go/no-go unknowns before implementation begins
**Depends on**: v1.0 shipped driver (existing sidecar infrastructure)
**Requirements**: FEAS-01, FEAS-02, FEAS-03
**Success Criteria** (what must be TRUE):
  1. SetFloatProperty(Prop_UserIpdMeters_Float) from sidecar produces a visible change in rendered eye separation (verified via GetEyeToHeadTransform or visual inspection)
  2. Lighthouse driver behavior regarding SetDisplayEyeToHead is documented (confirmed whether it blocks property-based IPD)
  3. Setting IpdUIRange properties from sidecar either triggers or does not trigger the SteamVR slider UI, with the result documented
  4. A clear go/no-go decision is recorded: property-based IPD is viable, or an alternative strategy is identified
**Plans:** 2/2 plans complete
Plans:
- [ ] 10-01-PLAN.md — Implement spike pipe commands (ipd_test, eyetohead_check, slider_test) and VREvent polling
- [ ] 10-02-PLAN.md — Execute spike tests against live SteamVR and document findings with go/no-go decision

### Phase 10.1: SetDisplayEyeToHead Spike (INSERTED)

**Goal:** Test whether VRServerDriverHost()->SetDisplayEyeToHead(0, ...) works from the sidecar driver for the HMD it doesn't own, resolving the critical gate for Phase 11's IPD implementation approach
**Requirements**: SPIKE-01, SPIKE-02, SPIKE-03
**Depends on:** Phase 10
**Success Criteria** (what must be TRUE):
  1. SetDisplayEyeToHead called from sidecar with device 0 either changes or does not change rendered eye separation (result documented)
  2. Euler angle decomposition of lighthouse config rotation matrices produces expected yaw values (~+/-6.17 deg)
  3. If successful, repeated calls confirmed to work (live-change, not one-shot)
  4. A clear go/no-go decision is recorded with evidence
**Plans:** 2/2 plans complete

Plans:
- [x] 10.1-01-PLAN.md — Implement eyetohead_set pipe command with config reading, matrix math, and SetDisplayEyeToHead call
- [x] 10.1-02-PLAN.md — Deploy, run visual test sequence in HMD, document findings with go/no-go decision

### Phase 11: Core IPD Pipe Command
**Goal**: Users can change IPD live via the named pipe interface and CLI, with the change taking effect immediately in SteamVR
**Depends on**: Phase 10 (feasibility confirmed)
**Requirements**: IPD-01, IPD-02, IPD-03, IPD-04, IPD-05, HARD-01, HARD-02
**Success Criteria** (what must be TRUE):
  1. Sending `ipd 63.5` via pipe or CLI sets IPD to 63.5mm in SteamVR without restart, and the rendered eye separation changes
  2. Sending an out-of-range value (e.g., `ipd 10` or `ipd 200`) returns an error and does not change IPD
  3. Sending `ipd?` returns the current IPD value in millimeters
  4. The `status` command includes the current IPD value in its response
  5. On driver startup, the driver reads and tracks the current IPD from the HMD container
**Plans:** 2/2 plans complete

Plans:
- [x] 11-01-PLAN.md — HID tracking serial extraction, config.json reading refactor, production ipd command, startup IPD
- [x] 11-02-PLAN.md — CLI tool update with production commands, end-to-end verification

### Phase 11.1: Proximity Sensor App Compatibility Spike (INSERTED)

**Goal:** Determine whether the sidecar driver can discover and update the lighthouse driver's `/user/head/proximity` input component handle, enabling proper proximity signaling to VR apps (VRChat, Beyond ET enrollment)
**Requirements**: SPIKE-01, SPIKE-02, SPIKE-03, SPIKE-04
**Depends on:** Phase 11
**Success Criteria** (what must be TRUE):
  1. The lighthouse driver's `/proximity` component handle is discovered (via handle probing, scheme analysis, or Monado/OpenVR source research)
  2. Calling UpdateBooleanComponent with the discovered handle changes the proximity state observed by SteamVR
  3. A clear go/no-go decision is recorded: handle discovery is viable for production use, or an alternative strategy is identified
  4. If GO: VRChat AFK detection and Beyond ET enrollment respond correctly to proximity state changes
**Spike findings (pre-spike):**
  - CreateBooleanComponent on HMD container from sidecar fails with VRInputError_InvalidParam (err=4) — cross-device input component creation is not allowed
  - TrackedDeviceButtonPressed/Unpressed does not exist in IVRServerDriverHost_006
  - VendorSpecificEvent only allows events in range 10000-19999
  - The lighthouse driver DOES create `/user/head/proximity` but never updates it (Tundra SiP doesn't receive proximity data from Beyond 2)
  - Property toggling (Prop_ContainsProximitySensor_Bool) works for SteamVR standby/wake but causes issues in other apps
**Plans:** 2/3 plans complete

Canonical refs:
- `extern/openvr/headers/openvr_driver.h` — IVRDriverInput, IVRServerDriverHost_006, EVRInputError, VRInputComponentHandle_t
- https://gitlab.freedesktop.org/monado/monado — reverse-engineered OpenVR/SteamVR internals

Plans:
- [x] 11.1-01-PLAN.md — Implement probe_proximity and test_handle spike pipe commands, build and deploy
- [ ] 11.1-02-PLAN.md — Build beyond_spike_monitor companion app (OpenVR client for proximity state observation)
- [ ] 11.1-03-PLAN.md — Execute coordinated spike test, verify app compatibility, record go/no-go decision

### Phase 12: SteamVR IPD Slider UI
**Goal**: Users can adjust IPD using SteamVR's built-in dashboard slider, and the driver correctly responds to slider-driven changes
**Depends on**: Phase 11 (core IPD mechanism working)
**Requirements**: SLIDER-01, SLIDER-02, HARD-04
**Success Criteria** (what must be TRUE):
  1. The SteamVR IPD slider appears in the dashboard when a Beyond 2 HMD is connected
  2. Moving the slider changes the rendered eye separation in real time
  3. The slider does not appear when a Beyond 1 HMD is connected (serial starts with 'BS1')
**Plans**: 2 plans
Plans:
- [x] 12-01-PLAN.md -- HMD serial parsing, Beyond 1 detection, ApplyIpd refactor, VREvent auto-apply, Track B spike
- [x] 12-02-PLAN.md -- Track A settings tab resources, settings polling, deploy and verify

### Phase 13: Slider Persistence and Hardening
**Goal**: IPD changes made via the SteamVR slider persist to the headset's lighthouse config so they survive SteamVR restarts
**Depends on**: Phase 12 (slider UI working)
**Requirements**: SLIDER-03, SLIDER-04, HARD-03
**Success Criteria** (what must be TRUE):
  1. An IPD change made via the SteamVR slider is written to the headset's lighthouse config (default_mm field) via lighthouse_console
  2. After a SteamVR restart, the IPD value set by the slider is preserved (lighthouse config is the source of truth)
  3. If lighthouse_console invocation fails, the live IPD change still takes effect (failure is logged, not blocking)
  4. The driver correctly reads the headset's lighthouse serial from HID config data to invoke lighthouse_console
**Plans**: 1 plan
Plans:
- [x] 13-01-PLAN.md -- IPD persistence via lighthouse_console with CMake compile flag, Cleanup hook, hardware verify

## Progress

| Phase | Milestone | Plans Complete | Status | Completed |
|-------|-----------|----------------|--------|-----------|
| 1. Skeleton Driver | v1.0 | 2/2 | Complete | 2026-03-21 |
| 2. HID Access | v1.0 | 2/2 | Complete | 2026-03-22 |
| 3. Proximity Spike | v1.0 | 2/2 | Complete | 2026-03-22 |
| 3.1 Remove Tracker | v1.0 | 2/2 | Complete | 2026-03-22 |
| 3.2 Package Integration | v1.0 | 2/2 | Complete | 2026-03-22 |
| 4. HID Pipeline | v1.0 | 2/2 | Complete | 2026-03-22 |
| 5. Proximity Algorithm | v1.0 | 2/2 | Complete | 2026-03-22 |
| 6. Standby/Wake | v1.0 | 2/2 | Complete | 2026-03-22 |
| 7. Configuration | v1.0 | 2/2 | Complete | 2026-03-23 |
| 8. Robustness | v1.0 | 2/2 | Complete | 2026-03-23 |
| 9. Installer | v1.0 | 2/2 | Complete | 2026-03-23 |
| 10. Feasibility Spike | 2/2 | Complete    | 2026-03-24 | - |
| 10.1 SetDisplayEyeToHead Spike | v2.0 | Complete    | 2026-03-24 | 2026-03-24 |
| 11. Core IPD Pipe Command | v2.0 | 2/2 | Complete    | 2026-03-26 |
| 11.1 Proximity Fix | v2.0 | 1/3 | Complete    | 2026-03-27 |
| 12. SteamVR IPD Slider UI | v2.0 | 2/2 | Complete    | 2026-03-28 |
| 13. Slider Persistence | v2.0 | 1/1 | Complete    | 2026-04-06 |
