Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
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.