Skip to content

Add Horizon Lock (yaw-only head tracking)#178

Open
devindudeman wants to merge 1 commit into
wheaney:mainfrom
devindudeman:horizon-lock
Open

Add Horizon Lock (yaw-only head tracking)#178
devindudeman wants to merge 1 commit into
wheaney:mainfrom
devindudeman:horizon-lock

Conversation

@devindudeman

Copy link
Copy Markdown

What

Adds a Horizon lock toggle that flattens the head pose to yaw-only — the virtual display tracks only horizontal head movement and ignores pitch (looking up/down) and roll (head tilt). The screen stays level and at a fixed height; turning your head pans across it.

Why

A comfort/nausea aid. On some glasses (notably the Viture Pro) pulse and micro-movement jitter on the pitch and roll axes makes the virtual display visibly wobble — see #80 and #114. Smooth follow can't address this because it chases the noisy axes; horizon lock removes them from the rendered orientation entirely. For an ultrawide workflow you mostly look left/right anyway, so locking the vertical axis is a big comfort win.

How

  • applyHorizonLock() in DeviceDataStream does a swing-twist decomposition about the NWU up-axis (keep the up/scalar quaternion components, zero the others, renormalize; identity fallback when yaw is undefined). Applied to both packed orientation quaternions of the pose buffer and the smooth-follow origin, so the shader, look-ahead, and follow logic all inherit the yaw-only orientation.
  • New horizon-lock gschema key + GObject property, bound in extension.js (and unbound in disable()).
  • Exposed as a switch in the Features group of the settings UI, wired the same way as the existing curved-display toggle.

Notes

  • Gated behind the setting — no behavior change when off.
  • Horizon lock and follow mode are effectively alternative comfort modes; with horizon lock on, follow can only follow yaw. Happy to grey one out in the UI when the other is enabled if you'd prefer.

Testing

Built from source via meson; ran the extension on a Viture Pro (GNOME 50 / Wayland). With horizon lock on, looking up/down and tilting no longer move the display, while horizontal panning works as before.

Adds a "Horizon lock" toggle that flattens the head pose to yaw-only,
ignoring pitch (vertical) and roll (tilt). The display then only pans
horizontally as you turn your head, staying level and at a fixed height.

This is a comfort/nausea aid — particularly on glasses such as the Viture
Pro, where pulse and micro-movement jitter on the pitch/roll axes makes the
display visibly wobble (see wheaney#80, wheaney#114). Unlike smooth follow, which chases
those noisy axes, horizon lock removes them from the rendered orientation
entirely.

Implementation: a swing-twist decomposition about the NWU up-axis (Z),
applied to the pose quaternions in DeviceDataStream, so the shader,
look-ahead and follow logic all inherit the yaw-only orientation. Exposed
as a GtkSwitch in the GNOME settings (Features group) and wired through the
shared gschema.
@wheaney

wheaney commented Jul 2, 2026

Copy link
Copy Markdown
Owner

I think actually the fix is a bit simpler than this. If I'm understanding right, it sounds like you want "smooth follow" without the "smooth." We already have "follow mode" (the "smooth" is there, but implied instead of explicitly part of the naming for Breezy), the "track axes" settings are there (you would just disable the ones you don't want, in this case only horizontal tracking would stay enabled), the only thing that's missing is a "strict follow" setting that removes the elasticity of smooth follow -- essentially disables the "slerp" part of smooth follow.

So the changes here would be almost entirely in the driver, which has the added benefit of making the change available to breezy-kwin as well.

  • Add a new "strict_follow" setting to the smooth_follow_config in plugins/smooth_follow.h
  • Add the minimal config parsing needed to set the new flag
  • Update the slerp function so it short-circuits right after we set the target. The new logic would check the new flag, and if it's set and smooth_follow_enabled is still true, it hardcodes the follow state to SLERPING and simply returns the target quaternion.

Then we only need to wire the new setting into the UI (Advanced settings) and I think that's it.

@wheaney

wheaney commented Jul 2, 2026

Copy link
Copy Markdown
Owner

Actually I bet you could get what you want with no changes, try these settings:

  • Enable Follow mode
  • Set a generous dead-zone
  • Enable all-displays follow
  • Follow axis tracking: disable horizontal, enable the other two (my previous comment was wrong, you want to enable the inverse)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants