feat(quickshell): add dense telemetry bar #4

Open
luna wants to merge 18 commits from feat/quickshell-dense-bar into master
Collaborator

Summary

  • adds the approved dense cyberpunk desktop telemetry bar in near-black, safety orange, and light-gray linework
  • wires live node-exporter vitals, Hyprland workspace state/actions, PipeWire audio state, tray count, local date/time, and deterministic fallback states
  • keeps the visual core in an Item-rooted DenseBarContent with a thin multi-monitor PanelWindow adapter
  • preserves the existing sidebar, launcher variants, bottom rail, notification server, volume OSD, and vitals overlay
  • adds a pinned Docker/qsmcp headless preview pipeline that works with the rootless daemon via docker create + docker cp

Design / architecture

DenseBarContent.qml owns only rendering and interaction signals. DenseBar.qml adapts Quickshell/Hyprland/PipeWire/SystemTray/VitalsData runtime state and creates one top-anchored window per screen. The layout uses fixed edge modules plus responsive telemetry spans; at 1360px it removes the third resource metric, one state cell, and the audio rail while preserving the primary state hierarchy.

The renderer pins nixpkgs and qsmcp revisions and applies an exact, fail-closed qsmcp source edit to raise its hard-coded 1568px image cap to 4096px, allowing a true 1920px capture.

Slop diagnostic: 0/10 after the final render; no gradient, generic-indigo, feature-grid, blur, monument-stat, center-stack, default-type, or wrong-surface tells fired.

Verification

Passed:

  • TDD RED: ./tools/quickshell-preview/render.sh tests/DenseBarHeadless.qml /tmp/dense-red.png 1920 164 failed with DenseBarContent is not a type before implementation.
  • TDD GREEN / final 1920 render: ./tools/quickshell-preview/render.sh tests/DenseBarHeadless.qml .artifacts/quickshell-preview/dense-bar-1920.png 1920 164 -> ok: true, 1920x164, component_errors: [].
  • Responsive 1360 render: ./tools/quickshell-preview/render.sh tests/DenseBarHeadless.qml .artifacts/quickshell-preview/dense-bar-1360.png 1360 164 -> ok: true, 1360x164, component_errors: [].
  • Renderer smoke test: ./tools/quickshell-preview/render.sh -> ok: true, 720x120, component_errors: [].
  • bash -n tools/quickshell-preview/render.sh tools/quickshell-preview/entrypoint.sh
  • git diff --cached --check
  • added-line static security scan -> no matches
  • PNG header/dimension assertions -> 1920x164 and 1360x164
  • both final PNGs inspected with chafa; no blank render or panel overflow found

Known warning / unavailable checks:

  • qsmcp still reports its upstream theme probe warning: ReferenceError: Theme is not defined; this is separate from the empty component_errors list.
  • standalone qmllint was not usable because the container invocation lacked resolved QtQuick/Quickshell import paths; qsmcp's real Quickshell loader was used for component validation instead.
  • an independent reviewer subagent was unavailable in this runtime; the complete staged diff and added lines were self-reviewed and security-scanned.
  • a direct offscreen render of the PanelWindow adapter stops at No PanelWindow backend loaded, as expected without a Wayland/layer-shell backend.

Runtime limitation

The Item itself is verified offscreen at both target widths. Final real Hyprland workspace activation, multi-monitor placement, exclusive-zone behavior, and layer-shell integration still merit an on-device check. This PR does not deploy, restart Quickshell, or touch a homelab host.

## Summary - adds the approved dense cyberpunk desktop telemetry bar in near-black, safety orange, and light-gray linework - wires live node-exporter vitals, Hyprland workspace state/actions, PipeWire audio state, tray count, local date/time, and deterministic fallback states - keeps the visual core in an Item-rooted `DenseBarContent` with a thin multi-monitor `PanelWindow` adapter - preserves the existing sidebar, launcher variants, bottom rail, notification server, volume OSD, and vitals overlay - adds a pinned Docker/qsmcp headless preview pipeline that works with the rootless daemon via `docker create` + `docker cp` ## Design / architecture `DenseBarContent.qml` owns only rendering and interaction signals. `DenseBar.qml` adapts Quickshell/Hyprland/PipeWire/SystemTray/VitalsData runtime state and creates one top-anchored window per screen. The layout uses fixed edge modules plus responsive telemetry spans; at 1360px it removes the third resource metric, one state cell, and the audio rail while preserving the primary state hierarchy. The renderer pins nixpkgs and qsmcp revisions and applies an exact, fail-closed qsmcp source edit to raise its hard-coded 1568px image cap to 4096px, allowing a true 1920px capture. Slop diagnostic: 0/10 after the final render; no gradient, generic-indigo, feature-grid, blur, monument-stat, center-stack, default-type, or wrong-surface tells fired. ## Verification Passed: - TDD RED: `./tools/quickshell-preview/render.sh tests/DenseBarHeadless.qml /tmp/dense-red.png 1920 164` failed with `DenseBarContent is not a type` before implementation. - TDD GREEN / final 1920 render: `./tools/quickshell-preview/render.sh tests/DenseBarHeadless.qml .artifacts/quickshell-preview/dense-bar-1920.png 1920 164` -> `ok: true`, 1920x164, `component_errors: []`. - Responsive 1360 render: `./tools/quickshell-preview/render.sh tests/DenseBarHeadless.qml .artifacts/quickshell-preview/dense-bar-1360.png 1360 164` -> `ok: true`, 1360x164, `component_errors: []`. - Renderer smoke test: `./tools/quickshell-preview/render.sh` -> `ok: true`, 720x120, `component_errors: []`. - `bash -n tools/quickshell-preview/render.sh tools/quickshell-preview/entrypoint.sh` - `git diff --cached --check` - added-line static security scan -> no matches - PNG header/dimension assertions -> 1920x164 and 1360x164 - both final PNGs inspected with chafa; no blank render or panel overflow found Known warning / unavailable checks: - qsmcp still reports its upstream theme probe warning: `ReferenceError: Theme is not defined`; this is separate from the empty `component_errors` list. - standalone `qmllint` was not usable because the container invocation lacked resolved QtQuick/Quickshell import paths; qsmcp's real Quickshell loader was used for component validation instead. - an independent reviewer subagent was unavailable in this runtime; the complete staged diff and added lines were self-reviewed and security-scanned. - a direct offscreen render of the `PanelWindow` adapter stops at `No PanelWindow backend loaded`, as expected without a Wayland/layer-shell backend. ## Runtime limitation The Item itself is verified offscreen at both target widths. Final real Hyprland workspace activation, multi-monitor placement, exclusive-zone behavior, and layer-shell integration still merit an on-device check. This PR does not deploy, restart Quickshell, or touch a homelab host.
luna added 1 commit 2026-08-28 01:53:43 +02:00
darman added 3 commits 2026-08-28 09:04:20 +02:00
hosts/terra/home.nix ships dotfiles/quickshell via xdg.configFile, which
copies the tree into the store: ~/.config/quickshell is a read-only symlink
into /nix/store and every QML tweak costs a nixos-rebuild. quickshell does
hot-reload on file save -- but only for the files it watches, which are those
frozen store copies. `nix develop` now swaps the running shell to the working
tree (`qs -p`) and swaps it back on exit, so QML edits need no rebuild at all.

The swap starts the dev instance FIRST and kills the packaged one only once
dev is confirmed up. A QML error in the working tree then leaves you on your
normal bar instead of no bar, which matters because a broken save is exactly
when you would be running this. Liveness is "did `qs list -j` return json" --
it exits 0 whether or not it found anything, so the exit code says nothing.

Every kill is scoped to one config (`qs kill` = default, `qs kill -p` = that
path). A blanket kill would also take out unrelated instances; pkgs/rishot.nix
is one.

Three guards on the auto-swap, all learned by testing it:
  - interactive only. `nix develop --command X` EXECs X, replacing the shell
    that set the `trap ... EXIT`, so the restore never runs and you are left
    on the dev instance. Non-interactive use gets `nix develop -c qs-dev`.
  - WAYLAND_DISPLAY, so entering the shell over ssh cannot kill the desktop's
    bar and leave nothing in its place.
  - a sentinel, so a nested `nix develop` does not swap and restore twice.

Deliberately not wired to direnv (no .envrc): programs.direnv is enabled for
this user, so a `use flake` would swap the running desktop shell on every `cd`
into the checkout.

Verified end to end on terra: swap, hot-reload of a working-tree edit, and
restore, plus both the interactive and non-interactive paths.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SgcWkm3t6BDQktYHQvb8Hx
The dense bar's panel chrome gets a squarer outline (top-right and bottom-left
chamfers only, square on the other two corners) and a second accent line in
the lower right to balance the existing upper-left one.

The chrome then moves out of DenseBarContent's inline `component
TelemetryPanel` into its own file. The call sites are unchanged apart from the
name -- children still come from the default property -- and the widgets they
pass in (RadarGauge, NetworkTrace, MetricBlock) stay declared in
DenseBarContent, so their scope is unaffected by moving only the definition.

Two things could not come along and had to be reproduced locally, because a
component in its own file has no access to the enclosing scope:

  - the palette and the two font families, previously read off `root`. They
    are properties with defaults matching DenseBarContent's, which is this
    repo's per-component convention. Duplicated on purpose for now; a shared
    theme singleton is the place to collapse it.
  - MicroText, which is an *inline* component of DenseBarContent and so
    invisible from another file. Expanded to the Text it desugars to.

Also qualified the bare offsetY/chamfer/accentLineThickness references as
panel.*; they resolved through the component scope before, but being explicit
avoids ComponentBehavior: Bound warnings in the new file.

Verified the move was verbatim by normalising the old inline block and the new
file body and diffing them -- the only differences are the relocated property
block, the panel.* qualification and the MicroText expansion. Loads clean both
headlessly and in the real layer-shell shell.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SgcWkm3t6BDQktYHQvb8Hx
The shell was running two unrelated palettes: an amber one (#FFD063 accent,
#EEEEEE text, #0F1012 panels) hardcoded as ~200 raw hex literals across the
launchers, sidebar, systray, vitals and notifications, and an orange one
(#e8722a) that only the dense bar had, tokenized as per-file properties.

This unifies on the ORANGE values under the AMBER naming scheme, and moves the
lot into widgets/theme/Theme.qml. `surface` takes the dense bar's void
(#0a0a0a) rather than the old panel background. Zero color and font literals
remain anywhere under widgets/ outside Theme.qml.

Collisions resolved, all near-duplicates that wanted to be one token:
  - #0F1012 + #0A0A0C + #0a0a0a -> surface
  - #EEEEEE + #dedede           -> text
  - #7A7B7D + #858585           -> muted
  - #292C30 + #22262C           -> raised
  - #FFD063 + #e8722a           -> accent

Two derived things rather than literals. accentSoft (the pale flash the
top/bottom bars show while a launcher is open) was a hand-picked #FFF3C0
against amber, which is simply wrong against orange; it is now
Qt.tint(accent, white 55%), a ratio checked against the original (amber tinted
55% gives #FFE9B8 vs the hand-picked #FFF3C0). And the dense bar had been
hand-encoding Qt.rgba(0.87,0.87,0.87,a) and Qt.rgba(0.91,0.45,0.16,a), which
are just text and accent at alpha -- now textAlpha(a)/accentAlpha(a), so they
track a palette change instead of silently drifting.

Fonts came along too. Digital-7 Mono is dropped for DepartureMono: it was
never packaged, relying on a manual ~/.dots/fonts/digital_7 install that does
not exist on terra, so `fc-match "Digital-7 Mono"` resolved to DejaVu Sans and
all 38 of those sites -- the launcher lists, sidebar clock, systray labels,
every vitals readout -- were silently rendering in a PROPORTIONAL fallback.
Numeric columns should visibly improve. readoutFont is an alias of displayFont
rather than a second literal so the two roles cannot drift apart.

quickshell/CLAUDE.md updated: it said "No shared theme/tokens file yet" and
told contributors to grep for the existing hex color, which would now
reintroduce exactly what this removes.

Verified: no file references Theme. without the import, none imports it
unused, and the whole shell -- launchers, sidebar, vitals, systray,
notifications, not just the harness -- hot-reloaded clean on terra.
tests/HeadlessSmoke.qml deliberately keeps its own copies; its value is having
no dependencies.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SgcWkm3t6BDQktYHQvb8Hx
luna added 1 commit 2026-08-28 09:35:10 +02:00
Author
Collaborator

Launcher follow-up pushed in fdc00a8.

  • Adds ApplicationLauncher variant 8 as the primary SUPER launcher while preserving variants 1-7.
  • Reuses Theme and StatusBarPanel; visual core remains Item-rooted for headless rendering.
  • Supports ranked search, keyboard navigation, desktop-entry execution, selected-target inspection, click dismissal, and compact-screen whole-component scaling.
  • Verified: 1080x620 qsmcp render stable with component_errors: []; status-bar and smoke regression renders pass; Nix syntax parse, shell syntax, whitespace, security scan, and independent review pass.
  • Remaining runtime check: real Hyprland focus/layer-shell behavior on device.
Launcher follow-up pushed in fdc00a8. - Adds ApplicationLauncher variant 8 as the primary SUPER launcher while preserving variants 1-7. - Reuses Theme and StatusBarPanel; visual core remains Item-rooted for headless rendering. - Supports ranked search, keyboard navigation, desktop-entry execution, selected-target inspection, click dismissal, and compact-screen whole-component scaling. - Verified: 1080x620 qsmcp render stable with component_errors: []; status-bar and smoke regression renders pass; Nix syntax parse, shell syntax, whitespace, security scan, and independent review pass. - Remaining runtime check: real Hyprland focus/layer-shell behavior on device.
luna added 1 commit 2026-08-28 22:48:26 +02:00
Author
Collaborator

Blade launcher variant pushed in 5ecc73f.

  • Adds launcher9 on SUPER CTRL 9; launcher8 remains the primary SUPER launcher.
  • Uses a compositionally distinct custom QML surface: category rotor, command mast, staggered result blades, open-bracket dossier, and caution lane.
  • Does not reuse StatusBarPanel; it only shares Theme and AppModel contracts.
  • Verified: 1120x640 offscreen render stable with component_errors: []; launcher8 and dense-bar regressions pass; Nix parse, Theme literal scan, whitespace, and independent review pass.
  • Real Hyprland layer-shell/focus behavior remains an on-device check.
Blade launcher variant pushed in 5ecc73f. - Adds launcher9 on SUPER CTRL 9; launcher8 remains the primary SUPER launcher. - Uses a compositionally distinct custom QML surface: category rotor, command mast, staggered result blades, open-bracket dossier, and caution lane. - Does not reuse StatusBarPanel; it only shares Theme and AppModel contracts. - Verified: 1120x640 offscreen render stable with component_errors: []; launcher8 and dense-bar regressions pass; Nix parse, Theme literal scan, whitespace, and independent review pass. - Real Hyprland layer-shell/focus behavior remains an on-device check.
luna added 1 commit 2026-08-28 22:58:40 +02:00
Author
Collaborator

Final launcher variant pushed in 9b6b799.

  • Adds Orbit launcher10 on SUPER CTRL SHIFT 0; launcher8 remains primary.
  • New radial composition: orbital app nodes, central target core, crosshair search rail, and execution tape.
  • Verified: 1120x660 offscreen render stable with component_errors: []; launcher8 and Blade regressions pass; Nix parse, Theme scan, whitespace, and independent review pass.
  • Real Hyprland layer-shell/focus behavior remains an on-device check.
Final launcher variant pushed in 9b6b799. - Adds Orbit launcher10 on SUPER CTRL SHIFT 0; launcher8 remains primary. - New radial composition: orbital app nodes, central target core, crosshair search rail, and execution tape. - Verified: 1120x660 offscreen render stable with component_errors: []; launcher8 and Blade regressions pass; Nix parse, Theme scan, whitespace, and independent review pass. - Real Hyprland layer-shell/focus behavior remains an on-device check.
darman added 1 commit 2026-08-28 23:03:43 +02:00
luna added 1 commit 2026-08-30 18:54:21 +02:00
Author
Collaborator

Cyber Dock launcher pushed in abccf53.

  • Adds launcher11 on SUPER CTRL SHIFT D; launcher8 remains primary.
  • Preserves V5 behavior: bottom-anchored rising deck, horizontal app carousel, keyboard search/navigation.
  • New self-contained cyberpunk chassis: lifted cartridges, system coupler, telemetry clamp, command spine, caution rail, and 240ms retract animation.
  • Handles rapid reopen by resetting query/selection/focus on every active transition.
  • Verified: 1440x272 offscreen render stable with component_errors: []; Orbit and Blade regressions pass; Nix parse, Theme scan, whitespace, and independent review pass.
  • Real Hyprland layer-shell/focus/animation behavior remains an on-device check.
Cyber Dock launcher pushed in abccf53. - Adds launcher11 on SUPER CTRL SHIFT D; launcher8 remains primary. - Preserves V5 behavior: bottom-anchored rising deck, horizontal app carousel, keyboard search/navigation. - New self-contained cyberpunk chassis: lifted cartridges, system coupler, telemetry clamp, command spine, caution rail, and 240ms retract animation. - Handles rapid reopen by resetting query/selection/focus on every active transition. - Verified: 1440x272 offscreen render stable with component_errors: []; Orbit and Blade regressions pass; Nix parse, Theme scan, whitespace, and independent review pass. - Real Hyprland layer-shell/focus/animation behavior remains an on-device check.
darman added 9 commits 2026-08-30 21:18:14 +02:00
A second shell chrome under dotfiles/quickshell/hyprchrome, built around a
BarPanel that carries TWO renderings of its data: the default children are the
expanded detail view, `summary` the terse one shown while collapsed. Both stay
bound to the same sources, so the densities cannot disagree, and the panel
cross-fades between them while its height animates.

Panels: HostPanel (hostname, user, timezone, clock), VitalsPanel (CPU load and
temperature, memory, GPU load and temperature, all metered), TrayPanel (system
tray, self-sizing). HyprChromeBar pins them to DP-2 and owns `expanded` for the
whole rail — SUPER A, via GlobalShortcut "chrome".

GPU busy comes off sysfs rather than the node_exporter scrape VitalsData
already does: the hwmon collector carries the card's temps, power and clocks
but not its utilisation.

The bar's height binds to each panel's `targetHeight` — where it will settle,
not where the animation currently is — because the exclusive zone is
window-sized by default, and binding to the animated height relayouts every
tiled window on the output twelve times per toggle. The zone follows the target
immediately so the desktop reflows once, at the start; the surface itself
shrinks only after the panels finish, or it would clip them mid-animation.

DebugWindow stages a widget in the middle of the secondary monitor
(SUPER CTRL D), masked so only the staged widget takes pointer input.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HEtXvseVb5gwAtKNhFx2PU
The expanded body is a RowLayout, so the divider's `y`/`width`/`height`, the
clock column's `width: 210`, and the user/zone text's `y: 32` were all being
discarded silently — a layout assigns its children's geometry, and a Column
positions its own. Only the anchors among these ever warned.

The divider's 8px inset becomes Layout margins, and `Layout.alignment` goes
from the clock column, where it is ignored while the item fills.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HEtXvseVb5gwAtKNhFx2PU
A full-screen scrim carrying the dense bar's drafting grid, shown while the
rail is expanded and faded out with it.

It sits on the TOP layer while the bar moves to OVERLAY. Both on one layer
would stack by surface creation order, which is not something to rely on; a
layer apart makes "above windows, below the bar" a guarantee. The mask is an
empty Region, so the scrim takes no clicks and reserves nothing.

The grid is the dense bar's, at twice the spacing and with registration
crosses on every other intersection. Its 0.018 opacity was tuned against a
near-black panel and is invisible over a scrim on lit windows, so grid and
crosses are both properties rather than constants, and the lines take a
desaturated accent derived from the palette instead of plain text colour.

Cross geometry rounds with Math.floor on both the mark's offset and the bars
inside it. anchors.*Center halves the box unfloored, which put an even-sized
mark half a pixel off the 1px rule it registers against. crossThickness is in
steps for the same reason: 1 -> 1px, 2 -> 3px, 3 -> 5px, since only an odd
width straddles a rule symmetrically.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HEtXvseVb5gwAtKNhFx2PU
qs-log follows the working-tree instance's log filtered to WARN|ERROR (-a for
everything), and the shellHook starts it in the background once qs-dev is up,
taking it down again in the exit trap alongside qs-prod. A binding loop or a
failed binding is a WARN, and easy to miss when it scrolls past unwatched.

It starts at the end of the log rather than replaying the backlog, and
re-attaches in a loop: `qs log -f` ends when the instance it attached to exits,
and the dev shell outlives individual instances.

Also corrects the hot-reload note added in 7268221, which was wrong on both
counts. Tested against the running shell: `touch` never reloads (mtime is not a
content change) and inode-replacing edits like `sed -i` are picked up fine. The
reliable check is whether `qs log` shows a "Reloading configuration..." line.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HEtXvseVb5gwAtKNhFx2PU
A third line under user // timezone, muted so the identity block stays a
descending three tiers.

Unlike the name, user and zone — none of which can change under a running
shell — addresses can, so this polls on a 30s timer instead of joining the
startup one-shot. The local one is read off the interface holding the default
route with tailscale0 excluded: as an exit node tailscale0 holds that route
itself, and the panel would show the tailnet address on both sides.

Drops the expanded body's `height: 48`. A third line has to grow the panel,
and BarPanel measures the body to decide how tall it is, so a fixed height
would have clipped the new row instead. The bar follows through targetHeight.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HEtXvseVb5gwAtKNhFx2PU
Two causes, both outside the panel animation itself.

bodyBottom and bodyEndPadding are animated reals, so their sum spends the tail
of every transition on a fraction. A layout rounds that up, then drops a pixel
the moment the animation lands on its exact value — a 1px hop after the motion
has visibly finished. implicitHeight and targetHeight now round.

The rest was the surface. Hyprland animates layer-surface resizes (animations
enabled, `layers` left at its default), and the deferred shrink put that resize
exactly where the panel motion ended. The bar is now sized once to the expanded
rail via the new BarPanel.expandedHeight and never resizes; only exclusiveZone
tracks the state, so the desktop still reflows once per toggle, at the start.
That retires barHeight, the content-height handler and the 340ms shrink timer.

A surface that stays tall would swallow clicks across the screen while the rail
is collapsed, so input is masked to the panel row.

Instrumenting BarPanel per frame ruled the panels themselves out first: slug
and summary hold the same absolute y through an entire collapse.

The bar and scrim also get their own layer namespaces. Nothing depends on them
yet; they are the handle for a layerrule that would exempt the rail from
compositor animations without catching the launchers, which share the default
"quickshell" namespace and do want their fade.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HEtXvseVb5gwAtKNhFx2PU
At spacing 0 a row of panels read as separate tiles, each closing its own
silhouette. BarPanel can now drop either cut corner — rightChamfer (top-right)
and leftChamfer (bottom-left), the only two the shape cuts — so an edge that a
neighbour butts against runs square into it. The bar turns off the host's right
and the vitals' left; the tray keeps both, since the spacer between them is not
a panel and that edge is free.

A side with its chamfer off also draws a connector: the shared edge restroked
in accent at outlineWidth + 2, so the join reads as a deliberate seam rather
than two outlines that happen to touch. The outline's own width becomes a
property so the connector can be defined against it instead of as a second
literal.

The lower-right accent strip takes accentLineWidth, the same slug-derived width
the upper-left one already used, instead of its own Math.min(49, width / 3).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HEtXvseVb5gwAtKNhFx2PU
Comments out both the plugin and its `plugin.hyprchrome` settings — Hyprland
rejects plugin config for a plugin that is not loaded, so the two have to go
together. The flake input stays, so re-enabling is two uncommented lines.

With the window frames gone, decoration rounding goes 10 -> 25 and
rounding_power 2.0 -> 1.0 (previously unset). Both were applied live first via
`hyprctl eval 'hl.config{...}'`; plain `hyprctl keyword` is refused by the lua
config's non-legacy parser.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HEtXvseVb5gwAtKNhFx2PU
This pull request doesn't have enough required approvals yet. 0 of 1 approvals granted from users or teams on the allowlist.
You are not authorized to merge this pull request.
This branch is out-of-date with the base branch
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin feat/quickshell-dense-bar:feat/quickshell-dense-bar
git checkout feat/quickshell-dense-bar
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: darman/homelab#4