README keeps intro, feature list linking docs/, install, two sessions, usage, the complete options table, changes outside Nix, rollback, uninstall. Each feature's details (problem, what you get, configuration, limitations, how it works) move to its own page in docs/; docs/dashboard.md is split per feature and docs/changes-outside-nix.md becomes docs/cleanup.md.
3.7 KiB
Window curvature
dashboard.windowCurvature.*, module window-curvature (options).
Problem
SteamVR dashboard windows are either curved (fixed radius) or flat, and world windows start flat.
What you get
The "Toggle Curvature" row of a window's three-dot menu becomes a control showing the window's value; the same control in the bottom bar (see window control bar) works without the value, with haptic steps.
- click: curved → flat, flat → stock (1);
- drag up/down with the laser: curvature from 0 (flat) to
max, relative to stock (2 = half the radius), rounded tostep, with a detent ofdetentPixelsof drag at each ofdetentPoints(no values skipped), and haptics (haptics) for detents, edges and steps. Drag distance:dragPixelsPerUnitin the menu,barDragPixelsPerUniton the bar button, afterdragThresholdPixels.
A window without its own value is shown at initial once curved in the
world or on a hand, at 1 in the dashboard or theater. Values are kept per
window until SteamVR restarts.
Configuration
steamFrame.dashboard.windowCurvature = {
enable = true;
# initial = 1.0; max = 3.0; step = 0.05;
# detentPoints = [ 0 1.0 ]; detentPixels = 24;
# dragPixelsPerUnit = 60; # full range in one drag (see below)
};
Limitations
- Laser only; with gamepad navigation the row is the stock toggle.
- No thumbstick scrolling (SteamVR sends no wheel events to the menu).
- The laser stops at the menu's edge (~190 px above the row): with the
default 120 px per 1.0, 0 → 1 fits into one drag, 0 → 3 takes two. Lower
dragPixelsPerUnit(≤ 60) for the full range in one drag.
How it works
Stock curvature: the frame renders a transform frame:<id>:curvature-origin
at z = DashboardStore.curvatureDistance when curved, else 1000; its panels
reference it as curvature-origin-id and vrcompositor bends them onto a
cylinder around it (curvature = 1/radius). Those MobX properties are
non-configurable, so the patch hooks the mailbox SendMessage
(shared hooks, shared with
dashboard windows) and rewrites the origin's z in
outgoing scene graphs to stock / value. On/off stays the stock toggle state,
so stock toggle and wheel always agree.
Values are kept per window (key: first overlay key) in
window.__sfuiWindowCurvatureState, across re-patch and unpatch, not across
a dashboard reload. The bar button uses the coordinates SteamVR keeps
sending past the pressed panel's edge while the trigger is held; the bar
panel is never resized.
Debugging: window.__sfuiWindowCurvature.dump() (.log recent events).
Contract for other patches
For patches handling presses on the curvature controls (e.g. the window
control bar's long press): every element the patch drives has class
sfui-curv-ctl; when a press becomes a drag, a bubbling CustomEvent
sfui-curv-dragstart (detail { frameID, where: 'menu' | 'bar' }) is
dispatched on it, and sfui-curv-dragend when it ends;
window.__sfuiWindowCurvature.scalePressDragThreshold(factor) sets the
current press's drag threshold to factor × dragThresholdPixels (from the
press start; returns whether it applied, i.e. a press that is not yet a
drag); window.__sfuiWindowCurvature.cancelPress() ends a press without its
click. A patch with its own gesture lets mousemove through while
undecided, drops its gesture on sfui-curv-dragstart, may raise the
threshold while its gesture is under way, and calls cancelPress() when it
takes the press over. The window control bar uses factor 3 once its
progress ring shows.