Proof Portal

Project overview

Omarchy

ProbeLabs65 findings · 95 requirements

A proof layer — requirements, tests and verified fixes — for two of Omarchy's subsystems: the application menu (launcher scripts, QML model, JSONC config, search and selection) and the lock screen (lock scripts, QML, PAM authentication). Scope is deliberately limited to those components of omacom/omarchy; the rest of the distribution is not covered.

Inbox
ReportR-1808GitHub issuePublicDecided· Out of scope

Media bar widget marquee freezes mid-scroll, showing only a few leading characters

Reported by schotime · filed Aug 16, 2026 · open at source

Decided: Out of scope — decided by agents · verified 4 days ago.

At a glance

1 · What is claimed?
Only the report text below — no validator has restated it as checkable claims yet.
2 · What does it affect?
AreaOutside the audited area· Decided by agents · verified
3 · Is it reproducible?
No validation has been run yet.
4 · What remains unclear?
  • Not validated yet: no claims, no reproducer.
5 · What happens next?
Decided by agents and verified by a second, independent agent — see the decision.

Original report

Media bar widget marquee freezes mid-scroll, showing only a few leading charactersrevision 1 · captured 2026-09-28 21:29 UTC via poll

What happened

The omarchy.media bar widget's marquee (the scrolling now-playing label) gets
permanently stuck showing only the first few characters of the track title —
e.g. ⏸ For instead of ⏸ For Evigt · Volbeat, or ⏸ Giv instead of
⏸ Give It Up · Midtown — with no scrolling motion at all, sometimes for the
lifetime of the shell process.

Expected behavior

When the combined "title · artist" label is wider than the widget's
maxLabelWidth (180px), it should marquee-scroll continuously. When it's
narrower, it should just display in full, static, left-aligned.

Root cause

BarWidget.qml drives the label's horizontal position with a property-value-
source animation:

NumberAnimation on x {
  id: scrollAnim
  running: labelText.needsScroll && !root.popupOpen && !root.bar.vertical
  loops: Animation.Infinite
  duration: Math.max(6000, labelText.implicitWidth * 25)
  from: scrollClip.width
  to: -labelText.implicitWidth
  easing.type: Easing.Linear
}

A NumberAnimation on <property> is a value source: while running is
true it owns x outright, but the instant running flips to false —
because the track changed to something short enough that needsScroll goes
false, the popup opened, or the bar rotated to vertical — it simply **freezes
x at whatever mid-scroll offset it happened to be at**. Nothing ever resets
it back to 0.

Since scrollClip clips its contents (clip: true) and the label's x is
left sitting at some large offset (observed live via a temporary IPC probe:
x=130 inside a 165px-wide clip, for a 165px-wide label — i.e. it should
never have been scrolling in the first place, needsScroll was correctly
false, but x was stale from an earlier scroll cycle), only the last
clipWidth - x pixels of the clip are visible, which land on the very
leftmost glyphs of the label — a thin sliver of the string's start, not the
full text and not a scroll.

This reproduces reliably any time the active/selected MPRIS source changes
between tracks of different lengths, or the popup is opened/closed while the
label is mid-animation. It survives omarchy restart shell because it's
deterministic given the metadata at hand — a fresh process ends up in the
same stuck state on its own once a track transitions from
needing-to-scroll to not.

Proposed fix

Reset x explicitly whenever the animation stops, so the label always
returns to a clean left-aligned resting position:

         NumberAnimation on x {
           id: scrollAnim
           running: labelText.needsScroll && !root.popupOpen && !root.bar.vertical
           loops: Animation.Infinite
           duration: Math.max(6000, labelText.implicitWidth * 25)
           from: scrollClip.width
           to: -labelText.implicitWidth
           easing.type: Easing.Linear
+          onRunningChanged: if (!running) labelText.x = 0
         }

Verified fix in a local plugin clone (omarchy plugin clone omarchy.media)
— confirmed via screenshots taken a few seconds apart that after the patch
the label reliably shows the full static text when short, and genuinely
scrolls (not frozen) through the whole "title · artist" string when long.

File: shell/plugins/services/media/BarWidget.qml

Steps to reproduce

  1. Have two MPRIS sources active at once (e.g. a browser tab playing audio +

a Deezer/Spotify client), or just let a single source's track change.
2. Let the bar's media widget scroll through a title/artist combo longer than
180px.
3. Let the track change to something shorter (or open/close the widget's
popup) while it's mid-scroll.
4. The label freezes, showing only a few leading characters of the new
title, and never scrolls or corrects itself again.

System details

  • Omarchy: 4.0.0-1 (stable channel)
  • Hyprland: 0.56.2 (Wayland)
  • Kernel: Linux 7.1.8-arch1-3
  • Hardware: Dell XPS 15 9560, i7-7700HQ, GTX 1050 Mobile / HD Graphics 630 (hybrid GPU)
  • Display: 3840x2160 @ 2x, 16", 60Hz

Attachments

Screenshots showing the stuck state and the working scroll after the fix are
available locally and will be attached to the issue.

View raw text
## What happened

The `omarchy.media` bar widget's marquee (the scrolling now-playing label) gets
permanently stuck showing only the first few characters of the track title —
e.g. `⏸ For` instead of `⏸ For Evigt · Volbeat`, or `⏸ Giv` instead of
`⏸ Give It Up · Midtown` — with no scrolling motion at all, sometimes for the
lifetime of the shell process.

## Expected behavior

When the combined "title · artist" label is wider than the widget's
`maxLabelWidth` (180px), it should marquee-scroll continuously. When it's
narrower, it should just display in full, static, left-aligned.

## Root cause

`BarWidget.qml` drives the label's horizontal position with a property-value-
source animation:

```qml
NumberAnimation on x {
  id: scrollAnim
  running: labelText.needsScroll && !root.popupOpen && !root.bar.vertical
  loops: Animation.Infinite
  duration: Math.max(6000, labelText.implicitWidth * 25)
  from: scrollClip.width
  to: -labelText.implicitWidth
  easing.type: Easing.Linear
}
```

A `NumberAnimation on <property>` is a value source: while `running` is
`true` it owns `x` outright, but the instant `running` flips to `false` —
because the track changed to something short enough that `needsScroll` goes
false, the popup opened, or the bar rotated to vertical — it simply **freezes
`x` at whatever mid-scroll offset it happened to be at**. Nothing ever resets
it back to `0`.

Since `scrollClip` clips its contents (`clip: true`) and the label's `x` is
left sitting at some large offset (observed live via a temporary IPC probe:
`x=130` inside a `165`px-wide clip, for a 165px-wide label — i.e. it should
never have been scrolling in the first place, `needsScroll` was correctly
`false`, but `x` was stale from an earlier scroll cycle), only the last
`clipWidth - x` pixels of the clip are visible, which land on the very
leftmost glyphs of the label — a thin sliver of the string's start, not the
full text and not a scroll.

This reproduces reliably any time the active/selected MPRIS source changes
between tracks of different lengths, or the popup is opened/closed while the
label is mid-animation. It survives `omarchy restart shell` because it's
deterministic given the metadata at hand — a fresh process ends up in the
same stuck state on its own once a track transitions from
needing-to-scroll to not.

## Proposed fix

Reset `x` explicitly whenever the animation stops, so the label always
returns to a clean left-aligned resting position:

```diff
         NumberAnimation on x {
           id: scrollAnim
           running: labelText.needsScroll && !root.popupOpen && !root.bar.vertical
           loops: Animation.Infinite
           duration: Math.max(6000, labelText.implicitWidth * 25)
           from: scrollClip.width
           to: -labelText.implicitWidth
           easing.type: Easing.Linear
+          onRunningChanged: if (!running) labelText.x = 0
         }
```

Verified fix in a local plugin clone (`omarchy plugin clone omarchy.media`)
— confirmed via screenshots taken a few seconds apart that after the patch
the label reliably shows the full static text when short, and genuinely
scrolls (not frozen) through the whole "title · artist" string when long.

File: `shell/plugins/services/media/BarWidget.qml`

## Steps to reproduce

1. Have two MPRIS sources active at once (e.g. a browser tab playing audio +
   a Deezer/Spotify client), or just let a single source's track change.
2. Let the bar's media widget scroll through a title/artist combo longer than
   180px.
3. Let the track change to something shorter (or open/close the widget's
   popup) while it's mid-scroll.
4. The label freezes, showing only a few leading characters of the new
   title, and never scrolls or corrects itself again.

## System details

- Omarchy: 4.0.0-1 (stable channel)
- Hyprland: 0.56.2 (Wayland)
- Kernel: Linux 7.1.8-arch1-3
- Hardware: Dell XPS 15 9560, i7-7700HQ, GTX 1050 Mobile / HD Graphics 630 (hybrid GPU)
- Display: 3840x2160 @ 2x, 16", 60Hz

## Attachments

Screenshots showing the stuck state and the working scroll after the fix are
available locally and will be attached to the issue.

Validation

Not checked yet. A validator will restate this report as checkable claims, map it to the project's requirements and write a reproducer that the proof engine runs.

Linked

Not linked to any known issue, other report or change yet.

Decision

Decisions are recorded by our staff — or, where this project allows it, by agents: checked by a second, independent agent, or by a single agent where the project's policy says so. Any decision reached so far is shown below.

  • Out of scopeDecided by agents · verified · 2026-10-09 04:17 UTC