git.lucas.co / cce-ui
GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git

commit8dcaf0c92e73e351ddcf2614a998194929921dd1
parent0681818239
authorLucas Galante <[email protected]>
date2026-08-18 12:22
tessellator: anti-alias rounded-rect corner fans

The corner fans rasterized hard triangle edges — no AA anywhere in the
silhouette. Invisible on HiDPI widget buffers, but a hard staircase on
the desktop grid's world-scale cells at native patch resolution. The fan
body now stops half a pixel short of the silhouette and a feather strip
fades from opaque at -0.5px to transparent at +0.5px, so the
50%-coverage line stays on the exact silhouette and perceived size is
unchanged. Radii under 1.5px keep the exact hard fan. The four
copy-pasted corner blocks collapse into one push_corner closure; the
dead zero-height else-quads are dropped.

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

 src/backend/window_runner.rs | 160 ++++++++++++-------------------------------
 1 file changed, 42 insertions(+), 118 deletions(-)

diff --git a/src/backend/window_runner.rs b/src/backend/window_runner.rs
index 96f9dfe..a463401 100644
--- a/src/backend/window_runner.rs
+++ b/src/backend/window_runner.rs
@@ -727,155 +727,79 @@ pub fn push_rounded_rect_vertices_corners(
         push_quad(out, x + mid_x1, y + r_tr, ww - mid_x1, h - r_tr - r_br);
     }
 
-    // Corner rendering
+    // Corner rendering. The fans are FEATHERED: the fan body stops half a
+    // pixel short of the silhouette and a strip fades from opaque at
+    // silhouette-0.5 to transparent at silhouette+0.5, so the arc
+    // anti-aliases instead of rasterizing a hard staircase — invisible on
+    // HiDPI widget buffers, glaring on the desktop grid's world-scale
+    // cells. Perceived size is unchanged (the 50%-coverage line stays on
+    // the exact silhouette). Radii too small to feather keep the hard fan.
     let segments = 16;
-
-    // Top-Left
-    if r_tl > 0.1 {
-        let cx = x + r_tl;
-        let cy = y + r_tl;
-        let start = std::f32::consts::PI;
-        let end = 1.5 * std::f32::consts::PI;
+    let fade = [color[0], color[1], color[2], 0.0];
+    let to_ndc = |px: f32, py: f32| -> [f32; 2] {
+        [(px / sw) * 2.0 - 1.0, 1.0 - (py / sh) * 2.0]
+    };
+    let push_corner = |out: &mut Vec<Vertex>, cx: f32, cy: f32, r: f32, start: f32, end: f32| {
+        let feather = r > 1.5;
+        let r_fan = if feather { r - 0.5 } else { r };
+        let r_out = r + 0.5;
         for i in 0..segments {
             let theta1 = start + (i as f32) * (end - start) / (segments as f32);
             let theta2 = start + ((i + 1) as f32) * (end - start) / (segments as f32);
-            
+
             let (c1, s1) = superellipse_pt(theta1, corner_e);
             let (c2, s2) = superellipse_pt(theta2, corner_e);
-            let x0 = clamp_x(cx);
-            let y0 = clamp_y(cy);
-            let x1 = clamp_x(cx + r_tl * c1);
-            let y1 = clamp_y(cy + r_tl * s1);
-            let x2 = clamp_x(cx + r_tl * c2);
-            let y2 = clamp_y(cy + r_tl * s2);
-            
-            let ndc_x0 = (x0 / sw) * 2.0 - 1.0;
-            let ndc_y0 = 1.0 - (y0 / sh) * 2.0;
-            let ndc_x1 = (x1 / sw) * 2.0 - 1.0;
-            let ndc_y1 = 1.0 - (y1 / sh) * 2.0;
-            let ndc_x2 = (x2 / sw) * 2.0 - 1.0;
-            let ndc_y2 = 1.0 - (y2 / sh) * 2.0;
-            
-            out.push(Vertex { position: [ndc_x0, ndc_y0], color, clip_circle });
-            out.push(Vertex { position: [ndc_x1, ndc_y1], color, clip_circle });
-            out.push(Vertex { position: [ndc_x2, ndc_y2], color, clip_circle });
+            let p0 = to_ndc(clamp_x(cx), clamp_y(cy));
+            let p1 = to_ndc(clamp_x(cx + r_fan * c1), clamp_y(cy + r_fan * s1));
+            let p2 = to_ndc(clamp_x(cx + r_fan * c2), clamp_y(cy + r_fan * s2));
+
+            out.push(Vertex { position: p0, color, clip_circle });
+            out.push(Vertex { position: p1, color, clip_circle });
+            out.push(Vertex { position: p2, color, clip_circle });
+
+            if feather {
+                let q1 = to_ndc(clamp_x(cx + r_out * c1), clamp_y(cy + r_out * s1));
+                let q2 = to_ndc(clamp_x(cx + r_out * c2), clamp_y(cy + r_out * s2));
+                out.push(Vertex { position: p1, color, clip_circle });
+                out.push(Vertex { position: q1, color: fade, clip_circle });
+                out.push(Vertex { position: q2, color: fade, clip_circle });
+                out.push(Vertex { position: p1, color, clip_circle });
+                out.push(Vertex { position: q2, color: fade, clip_circle });
+                out.push(Vertex { position: p2, color, clip_circle });
+            }
         }
+    };
+
+    // Top-Left
+    if r_tl > 0.1 {
+        push_corner(out, x + r_tl, y + r_tl, r_tl, std::f32::consts::PI, 1.5 * std::f32::consts::PI);
         if mid_x0 > r_tl {
             push_quad(out, x + r_tl, y, mid_x0 - r_tl, r_tl);
         }
-    } else {
-        push_quad(out, x, y, mid_x0, 0.0);
     }
 
     // Top-Right
     if r_tr > 0.1 {
-        let cx = x + ww - r_tr;
-        let cy = y + r_tr;
-        let start = 1.5 * std::f32::consts::PI;
-        let end = 2.0 * std::f32::consts::PI;
-        for i in 0..segments {
-            let theta1 = start + (i as f32) * (end - start) / (segments as f32);
-            let theta2 = start + ((i + 1) as f32) * (end - start) / (segments as f32);
-            
-            let (c1, s1) = superellipse_pt(theta1, corner_e);
-            let (c2, s2) = superellipse_pt(theta2, corner_e);
-            let x0 = clamp_x(cx);
-            let y0 = clamp_y(cy);
-            let x1 = clamp_x(cx + r_tr * c1);
-            let y1 = clamp_y(cy + r_tr * s1);
-            let x2 = clamp_x(cx + r_tr * c2);
-            let y2 = clamp_y(cy + r_tr * s2);
-            
-            let ndc_x0 = (x0 / sw) * 2.0 - 1.0;
-            let ndc_y0 = 1.0 - (y0 / sh) * 2.0;
-            let ndc_x1 = (x1 / sw) * 2.0 - 1.0;
-            let ndc_y1 = 1.0 - (y1 / sh) * 2.0;
-            let ndc_x2 = (x2 / sw) * 2.0 - 1.0;
-            let ndc_y2 = 1.0 - (y2 / sh) * 2.0;
-            
-            out.push(Vertex { position: [ndc_x0, ndc_y0], color, clip_circle });
-            out.push(Vertex { position: [ndc_x1, ndc_y1], color, clip_circle });
-            out.push(Vertex { position: [ndc_x2, ndc_y2], color, clip_circle });
-        }
+        push_corner(out, x + ww - r_tr, y + r_tr, r_tr, 1.5 * std::f32::consts::PI, 2.0 * std::f32::consts::PI);
         if ww - mid_x1 > r_tr {
             push_quad(out, x + mid_x1, y, ww - mid_x1 - r_tr, r_tr);
         }
-    } else {
-        push_quad(out, x + mid_x1, y, ww - mid_x1, 0.0);
     }
 
     // Bottom-Right
     if r_br > 0.1 {
-        let cx = x + ww - r_br;
-        let cy = y + h - r_br;
-        let start = 0.0;
-        let end = 0.5 * std::f32::consts::PI;
-        for i in 0..segments {
-            let theta1 = start + (i as f32) * (end - start) / (segments as f32);
-            let theta2 = start + ((i + 1) as f32) * (end - start) / (segments as f32);
-            
-            let (c1, s1) = superellipse_pt(theta1, corner_e);
-            let (c2, s2) = superellipse_pt(theta2, corner_e);
-            let x0 = clamp_x(cx);
-            let y0 = clamp_y(cy);
-            let x1 = clamp_x(cx + r_br * c1);
-            let y1 = clamp_y(cy + r_br * s1);
-            let x2 = clamp_x(cx + r_br * c2);
-            let y2 = clamp_y(cy + r_br * s2);
-            
-            let ndc_x0 = (x0 / sw) * 2.0 - 1.0;
-            let ndc_y0 = 1.0 - (y0 / sh) * 2.0;
-            let ndc_x1 = (x1 / sw) * 2.0 - 1.0;
-            let ndc_y1 = 1.0 - (y1 / sh) * 2.0;
-            let ndc_x2 = (x2 / sw) * 2.0 - 1.0;
-            let ndc_y2 = 1.0 - (y2 / sh) * 2.0;
-            
-            out.push(Vertex { position: [ndc_x0, ndc_y0], color, clip_circle });
-            out.push(Vertex { position: [ndc_x1, ndc_y1], color, clip_circle });
-            out.push(Vertex { position: [ndc_x2, ndc_y2], color, clip_circle });
-        }
+        push_corner(out, x + ww - r_br, y + h - r_br, r_br, 0.0, 0.5 * std::f32::consts::PI);
         if ww - mid_x1 > r_br {
             push_quad(out, x + mid_x1, y + h - r_br, ww - mid_x1 - r_br, r_br);
         }
-    } else {
-        push_quad(out, x + mid_x1, y + h, ww - mid_x1, 0.0);
     }
 
     // Bottom-Left
     if r_bl > 0.1 {
-        let cx = x + r_bl;
-        let cy = y + h - r_bl;
-        let start = 0.5 * std::f32::consts::PI;
-        let end = std::f32::consts::PI;
-        for i in 0..segments {
-            let theta1 = start + (i as f32) * (end - start) / (segments as f32);
-            let theta2 = start + ((i + 1) as f32) * (end - start) / (segments as f32);
-            
-            let (c1, s1) = superellipse_pt(theta1, corner_e);
-            let (c2, s2) = superellipse_pt(theta2, corner_e);
-            let x0 = clamp_x(cx);
-            let y0 = clamp_y(cy);
-            let x1 = clamp_x(cx + r_bl * c1);
-            let y1 = clamp_y(cy + r_bl * s1);
-            let x2 = clamp_x(cx + r_bl * c2);
-            let y2 = clamp_y(cy + r_bl * s2);
-            
-            let ndc_x0 = (x0 / sw) * 2.0 - 1.0;
-            let ndc_y0 = 1.0 - (y0 / sh) * 2.0;
-            let ndc_x1 = (x1 / sw) * 2.0 - 1.0;
-            let ndc_y1 = 1.0 - (y1 / sh) * 2.0;
-            let ndc_x2 = (x2 / sw) * 2.0 - 1.0;
-            let ndc_y2 = 1.0 - (y2 / sh) * 2.0;
-            
-            out.push(Vertex { position: [ndc_x0, ndc_y0], color, clip_circle });
-            out.push(Vertex { position: [ndc_x1, ndc_y1], color, clip_circle });
-            out.push(Vertex { position: [ndc_x2, ndc_y2], color, clip_circle });
-        }
+        push_corner(out, x + r_bl, y + h - r_bl, r_bl, 0.5 * std::f32::consts::PI, std::f32::consts::PI);
         if mid_x0 > r_bl {
             push_quad(out, x + r_bl, y + h - r_bl, mid_x0 - r_bl, r_bl);
         }
-    } else {
-        push_quad(out, x, y + h, mid_x0, 0.0);
     }
 }