New plugin:hyprchrome:outline_size (px, 0 = off) and outline_color (default white) stroke the frame's outer silhouette - chamfers, title bar plateau and side notches - with a flat color, so it reads as a drawn line against the gradient-filled frame underneath. Off by default. The line sits inside the frame rather than centred on the silhouette. The outer path runs along the texture's own bounds, so half of a centred stroke would fall off the surface and vanish on exactly those sides; stroking at double width leaves the inner half, which comes to outline_size on every edge. The clip is the whole ring rather than just the outer path, so an outline thicker than the frame stops at the window's edge instead of spilling across the ring onto the window, and a miter spike at the plateau's dip stays confined to the frame. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
hypr-chrome
A Hyprland plugin that draws a chamfered HUD-style border frame behind each window, expanded past the window's own edges, with a floating title bar hanging off the top-left corner. The frame's corners are chamfered by an amount inferred from the window's own border rounding, so the border peeking out around a rounded window's corners reads as a matching diagonal cut rather than a hard rectangular corner. Border color tracks Hyprland's own active/inactive border color live, gradients included.
Config
plugin {
hyprchrome {
enabled = true # bool
extent = 12 # int, px the border extends past the window edge
follow_hyprland_border_color = true # bool, use Hyprland's own active/inactive border color instead of active_color/inactive_color below
active_color = 0xFFD063FF # focused-window border color, used when follow_hyprland_border_color is false
inactive_color = 0xFF6C6C6C # unfocused-window border color, used when follow_hyprland_border_color is false
titlebar_height = 8 # int, px height of the floating title bar
titlebar_text_size = 12 # int, px font size of the title bar's text
titlebar_font = sans-serif # string, passed to cairo_select_font_face
}
}
active_color/inactive_color take the same syntax as Hyprland's own
general:col.active_border — a single color, or several plus an optional
angle for a gradient:
active_color = rgba(ff0000ff) rgba(00ff00ff) 45deg
Installing
hyprpm add https://git.mgaction.town/darman/hypr-chrome.git
hyprpm enable hypr-chrome
hyprpm builds the plugin from source against your own installed Hyprland,
using the build commands declared in hyprpm.toml (the same cmake
invocations as below).
NixOS
flake.nix exposes packages.x86_64-linux.default, built against
pkgs.hyprland from this flake's own nixpkgs input (with Hyprland's own
compiler/stdenv, for ABI correctness). Add this repo as a flake input and
set inputs.hypr-chrome.inputs.nixpkgs.follows = "nixpkgs" (your own
system's nixpkgs input) so it's built against the exact Hyprland your
system runs - then add inputs.hypr-chrome.packages.${system}.default
directly to your wayland.windowManager.hyprland.plugins
(NixOS/home-manager) list. The package installs as lib/libhypr-chrome.so
(the lib<pname>.so convention that module derives its path from
automatically) even though the plain hyprctl/hyprpm path above uses
the unprefixed hypr-chrome.so.
Building
Requires the Hyprland headers/libs (hyprland, libdrm, libinput,
libudev, wayland-server, xkbcommon, pixman-1, cairo, etc.), ABI-locked
to the exact Hyprland build you'll load the plugin into. A pinned Nix flake
dev shell provides all of it:
nix develop
cmake -B build -S .
cmake --build build
This produces hypr-chrome.so at the repo root (not inside build/, so the
hyprctl/buildAndLoad.sh commands below can find it directly).
Developing
Load/reload the plugin into a running Hyprland session:
hyprctl plugin load "$(pwd)/hypr-chrome.so"
hyprctl plugin unload "$(pwd)/hypr-chrome.so"
buildAndLoad.sh chains build + reload for iteration. Hyprland's plugin
loader never fully unmaps a .so once dlopen'd, so reloading the same path
just re-serves the old (possibly stale) mapping — the script works around
this by copying each build to a uniquely-suffixed filename before loading it
and cleaning up prior copies. It also unloads any copy your own Hyprland
config loads (found by grepping $XDG_CONFIG_HOME/hypr for a hypr-chrome
.so path), since that one is a separate dlopen that would draw a second
frame on every window. It hardcodes an absolute checkout path at the top;
check it matches your checkout before running it.