Omahub
← All plugins
J

Scrolling Position

by Jvaxx

Where you are on the tape: column position indicator for Hyprland's scrolling layout.

Security review

No obvious issues detected

Deterministic scan — not a security guarantee

None
Risk level
None
Analyzed commit
c253f6b
Scanned
1 month ago

No potentially dangerous behavior detected in the analyzed commit.

Automated analysis only — not a security guarantee.

AI advisory review

No obvious issues detected

Language-model assessment · ~deepseek/deepseek-v4-flash-latest — advisory only

None
AI risk level
None
Recommendation
install
Model
~deepseek/deepseek-v4-flash-latest
Analyzed commit
c253f6b
Reviewed
1 month ago

This is a straightforward QML/JavaScript widget that reads Hyprland IPC data to display a scrolling-layout position indicator. It performs no network access, executes no shell commands, and only writes to its own settings entry in shell.json via the standard Omarchy API. The code is clear, well-commented, and contains no suspicious or obfuscated behavior.

How this check works

This review combines the deterministic scan (the rule-based results above) with an independent look at the plugin's code by a language model. The model reads a trimmed sample of the repository's files, the manifest, and the README, then gives a plain-language risk level and a recommendation: install (no notable danger), review (look closer first), or avoid (clearly dangerous).

It runs on the same analyzed commit as the deterministic scan and is strictly advisory — it is not a security guarantee and never blocks a plugin by itself. A human moderator still reviews plugins before they are listed.

AI advisory only — automated analysis, not a security guarantee.

Install
$ omarchy plugin add https://github.com/Jvaxx/omarchy-scrolling-position --enable
Widgets #Hyprland #bar #workspaces

Scrolling Position

A bar widget for Omarchy that shows where you are on the tape when a workspace uses Hyprland's scrolling layout.

Scrolling Position in the Omarchy bar

The scrolling layout is a one-dimensional strip of columns, usually wider than the screen. The screen itself can only ever show you the part you are looking at. This widget shows the part you are not: how many columns exist, which one has focus, and how much tape is parked off each edge.

It hides itself completely on workspaces that use any other layout.

Two modes

Click the widget to switch; the choice is written back to your shell.json, so it survives a restart.

  • map — columns drawn to scale, with a bracket underneath marking the slice currently on screen. Reads like a scrollbar: a wide segment is a wide column, and a bracket that runs off the end means empty space beyond the last column.
  • pips — one dot per column, the focused one drawn as a filled pill. Position and count only, in a fraction of the width.

In both modes, opacity encodes visibility: focused, fully on screen, peeking in at an edge, or entirely off screen.

Requirements

  • Omarchy 4 (the Quattro Quickshell shell, omarchy-shell)
  • Hyprland with the native scrolling layout — developed and tested on 0.56.2
  • No external dependencies: no extra packages, no helper binaries, no network access. The widget reads Hyprland's own IPC through Quickshell and nothing else.

Install

omarchy plugin add https://github.com/Jvaxx/omarchy-scrolling-position.git --enable

--enable asks which bar section to place it in. The natural spot is left, directly after omarchy.workspaces, so workspace number and column position sit together:

"left": [
  { "id": "omarchy.workspaces" },
  { "id": "io.github.jvaxx.scrolling-position" },
  { "id": "omarchy.active-window" }
]

Or place it later with:

omarchy bar move io.github.jvaxx.scrolling-position --section left

Remove

omarchy plugin remove io.github.jvaxx.scrolling-position

That deletes ~/.config/omarchy/plugins/io.github.jvaxx.scrolling-position/ and drops the widget from the bar. The plugin writes nothing outside its own entry in ~/.config/omarchy/shell.json, creates no state files, and leaves no background process behind, so nothing else needs cleaning up.

To keep the plugin installed but take it off the bar, delete its entry from the bar.layout section of shell.json.

Settings

Set these inline on the widget's entry in ~/.config/omarchy/shell.json; they hot-reload on save.

Key Default What it does
mode "map" "map" or "pips". Clicking the widget rewrites this.
mapLength 110 Length of the minimap along the bar, in pixels, before text scaling. Ignored in pips mode.
pollInterval 600 Fallback refresh in milliseconds. 0 makes the widget purely event-driven — see below.
hideWhenSingleColumn false Hide the widget when the workspace has only one column, since there is nowhere to scroll.
{ "id": "io.github.jvaxx.scrolling-position", "mode": "pips", "hideWhenSingleColumn": true }

How it stays in sync

Hyprland keeps off-screen columns in hyprctl clients with their real coordinates — a column parked left of the viewport reports a negative x — so the whole tape can be reconstructed from geometry alone. Windows stacked in one column share an x/width pair and collapse into a single segment.

Refreshing is the interesting part, because Hyprland has no event for a layout geometry change. Verified on .socket2: moving focus emits activewindowv2, while layoutmsg colresize moves every column on the tape and emits nothing at all. So the widget uses three paths:

  1. Events. Any Hyprland IPC event fires a three-shot refresh at 0/120/380 ms — one read for the dispatch, the rest for the animation settling. This covers all ordinary scrolling, which is focus movement, instantly.

  2. A heartbeat, pollInterval (600 ms default). This is what catches the eventless changes: column resizes and mouse-drag resizes. An unchanged tape is compared by signature and dropped without repainting, so a static strip costs a socket read and a string compare.

  3. An IPC hook, for anyone who would rather not poll:

    omarchy-shell -q io.github.jvaxx.scrolling-position refresh
    

    Add that line to a script that reshapes columns (a colresize bind, for instance) and the widget updates on the dispatch. With every such bind wired up you can set pollInterval: 0 and run fully event-driven — at the cost of mouse-drag resizes, which no script can intercept, going stale until the next focus change.

Registering a new IPC target requires a full omarchy restart shell; plugin hot-reload alone does not pick it up.

Notes

  • Multi-monitor: each bar reads its own screen's active workspace, not the focused one, so the widget on your second monitor describes that monitor's tape.
  • Fullscreen needs no special handling: Hyprland gives the fullscreen window exactly the viewport and pushes its neighbours off both edges, which the map renders correctly as one column filling the screen.
  • Cold start: Quickshell only learns the active window from an activewindowv2 event and never seeds it, so the focused column falls back to focusHistoryID from the same snapshot as the geometry. The right column is lit on a freshly started bar, before you have touched anything.
  • Floating windows and the scratchpad are excluded from the tape.
  • Colors come from the active Omarchy theme (bar.text); there is nothing to configure and nothing to restyle when you switch themes.

License

MIT — see LICENSE.