git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

commita594a7791908d33992ea455cb8a92cc5ef6c461c
parentf867cda14e
authorLucas Galante <[email protected]>
date2026-08-28 12:06
feat(bevel): concentrate the focus glint at the silhouette

Additive fixed the brightness; the band was still a linear ramp across the
full 10px rim, which reads as a wash rather than a lit edge. cce-ui's plate
raises its profile to `shininess` for exactly this reason — the light has
to be concentrated at the silhouette to read as a glint.

Same idea here, on the rim's slope: h = light_intensity * pow(slope, 3).
The band tightens from ~9px to ~5px and the edge gains definition.

3.0 rather than cce-ui's 24 because the two exponents act on different
quantities. cce-ui powers a cosine that genuinely reaches 1.0 inside the
band, so its peak survives; here `slope` at the outermost RENDERED sample
is already below 1.0 (it sits just inside t=0 and is feathered by edge_aa),
so the power costs peak brightness as it climbs. Swept it: green-channel
peak 242 at 1.0, 222 at 3.0, 198 at 6.0, 168 at 12.0, and past ~12 the
curve stops narrowing and only dims — 12 and 24 differ by 2/255. 3.0 keeps
a defined edge without washing the accent out toward white.

Focused rim, before the two fixes to now: [86,120,127] -> [169,222,237] at
the peak, reaching the window's own value by 8px instead of 10. Unfocused
windows unchanged (max 1 LSB, float reassociation).

If the peak cost ever matters more than matching cce-ui's formulation,
compressing t before the slope curve narrows the band without touching the
peak at all.

Co-Authored-By: Claude Opus 5 <[email protected]>

 scenefx/render/fx_renderer/shaders/bevel.frag | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/scenefx/render/fx_renderer/shaders/bevel.frag b/scenefx/render/fx_renderer/shaders/bevel.frag
index 086a0c1..8d15091 100644
--- a/scenefx/render/fx_renderer/shaders/bevel.frag
+++ b/scenefx/render/fx_renderer/shaders/bevel.frag
@@ -36,6 +36,16 @@ uniform float shoulder;
 uniform float focus;
 uniform vec3 focus_color;
 
+// Falloff exponent for the focus glint. 1.0 is a linear ramp across the whole
+// rim, which reads as a wash; higher concentrates the light at the silhouette.
+// Costs peak brightness as it rises — the outermost RENDERED sample sits just
+// inside t=0 and is feathered by edge_aa, so it is already below 1.0 and the
+// power pushes it down (measured peak, green channel: 242 at 1.0, 222 at 3.0,
+// 198 at 6.0, 168 at 12.0). Past ~12 the curve stops narrowing and only dims:
+// 12 and 24 differ by 2/255. 3.0 keeps a defined edge without washing the
+// accent out to white.
+#define FOCUS_SHARPNESS 3.0
+
 // Defined in corner_alpha.frag, which is concatenated after this source (the
 // same way box_shadow.frag gets it). Using the shared routine rather than a
 // private circular SDF is the whole point: at corner_shape > 2 the DE's
@@ -99,7 +109,12 @@ void main() {
         // edge shades as the one facing the light, in the accent color, no
         // shade side. Same slope profile, so band width and shoulder match
         // the unfocused rim exactly.
-        float h = light_intensity * slope;
+        // Concentrate the band toward the outer edge. The linear ramp
+        // spreads the glint over the whole rim, which reads as a wash; a
+        // power keeps the peak at the silhouette and falls away fast, which
+        // is what makes cce-ui's plate line read as a glint rather than a
+        // glow (shader2d.wgsl raises its profile to `shininess`).
+        float h = light_intensity * pow(slope, FOCUS_SHARPNESS);
         // ADDITIVE: alpha 0 with premultiplied colour gives dst + rgb under
         // the pass's GL_ONE/GL_ONE_MINUS_SRC_ALPHA blend, so the glint ADDS
         // light to the window instead of cross-fading toward the accent.