New plugin:hyprchrome:glow_size (px, 0 = off) and glow_strength (0-1)
bleed the border's own gradient inward past the window edge, over the
window's own pixels. Off by default, so existing setups are unchanged.
Drawn into the hole the ring's even-odd fill already leaves behind, from
overlapping layers - one per px of depth - each covering the window edge
inward to a progressively greater depth. Overlapping rather than abutting
disjoint bands avoids an antialiasing seam at every shared edge; the cost
is that a layer composites over every deeper one, so its alpha is solved
outermost-inward from the target profile rather than being it.
That profile is strength * (1 - d/glow)^2.2: steep off the window edge,
easing into a tail that reaches zero tangentially so there's no ring
where it stops.
Corner handling, in order of how much it mattered:
- Each layer's outer edge is the ring's inner boundary verbatim, chamfer
vertices and all. Anything else detaches the glow from the frame and
opens a sliver of unpainted window at each corner.
- Each layer's inner edge - which is what the falloff's contours actually
follow - is filleted in proportion to its own depth, so the glow reads
as chamfered where it meets the frame and rounder as it fades inward.
- Those inner edges also shrink their chamfer by (2-sqrt2) per px of
inset. Insetting a chamfered rect while holding the chamfer constant
moves the 45-degree face in by d*sqrt(2) rather than d, which had the
glow running ~41% deeper at every corner than along the sides.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
New plugin:hyprchrome:shadow_size (px, 0 = off), shadow_color and
shadow_offset (vec2). Off by default, so existing setups are unchanged.
The silhouette is the frame's own outer boundary - extracted out of
GetBorderTexture into AppendFrameOuterPath so the shadow and the shape
casting it can't drift apart - filled into an A8 mask, blurred with three
box passes, then tinted. The frame's cutouts (side notches, the strip
beside the title bar) are part of that outline, so they cast their shape
for free.
Three things worth not undoing later:
- The window's interior is cleared after the blur, not before. Punching
it first leaves the blur smearing shadow inward across the window's own
content. Clearing afterwards puts the cut exactly on the ring's inner
boundary, where the frame's opaque pixels hide it.
- The shadow is not part of the decoration's reserved extents, since
reserving it would push neighbouring windows away by the shadow's
width. It's drawn past the decoration's box instead, which is why
damageEntire() and boundingBox() expand by ShadowMarginLogical().
- It renders at no more than kShadowMaxDim px on the long edge and lets
the GPU upscale. A blurred blob loses nothing to that, and a
full-resolution blur would otherwise be re-run per frame for the whole
length of a resize animation.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Developto hypr-chrome v0.1.3