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

commit3f943d507c233c408e1025afa223654ab268c271
parenta976f42111
authorLucas Galante <[email protected]>
date2026-07-20 13:10
feat: soften the plate-to-bar transition wall

The step where a menubar/status bar carves into the window plate read as a
crisp groove: a spec line, a below-face dip, and the bright shoulder all
alternating inside one bevel_width-wide wall. Two changes make it a broad
soft roll:

- Grouped-carve depth saturates at the nominal bevel_width in the
  tessellator, so a wall wider than the plate's own perimeter roll spreads
  the same step over the longer run (flatter slope) instead of cutting
  proportionally deeper. Carves at or under bevel_width are bit-identical.
- layout::bar_wall_width() (1.75x bevel_width) is the shared bar wall span,
  used by recessed MenuBar/StatusBar (flush single-wall cap loosened to
  0.6h; trough keeps 0.4h) and the demo's header/status bands.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XxjKyZK55xkRz43M8Fecsf

 src/backend/window_runner.rs     | 9 +++++++--
 src/layout.rs                    | 9 +++++++++
 src/main.rs                      | 4 ++--
 src/widget/container/menu.rs     | 7 +++++--
 src/widget/display/status_bar.rs | 5 +++--
 5 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/src/backend/window_runner.rs b/src/backend/window_runner.rs
index 7490cc0..7dde235 100644
--- a/src/backend/window_runner.rs
+++ b/src/backend/window_runner.rs
@@ -1566,10 +1566,15 @@ pub fn tessellate_display_list(
                         if !edges.2 { y1 += ext; }
                         if !edges.3 { x0 -= ext; }
                         let t_px = *depth * scale;
+                        // Depth saturates at the DE's nominal roll width: a wall
+                        // wider than the plate's own perimeter roll spreads that
+                        // same step over the longer run — a softer transition —
+                        // instead of cutting proportionally deeper (which would
+                        // keep the wall just as steep no matter how wide it got).
+                        let k_mag = RECESS_DEPTH_RATIO * t_px.min(crate::layout::bevel_width() * scale);
                         // Negative depth = raised (Boss); the shader's summed
                         // slope vectors and curvature sign follow it.
-                        let k_px =
-                            if raised { -RECESS_DEPTH_RATIO * t_px } else { RECESS_DEPTH_RATIO * t_px };
+                        let k_px = if raised { -k_mag } else { k_mag };
                         if let Some(p) = batches[bi].plate.as_mut() {
                             if p.host[1] == 0.0 {
                                 p.host[0] = features.len() as f32;
diff --git a/src/layout.rs b/src/layout.rs
index bc4a467..b1c506d 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -1517,6 +1517,15 @@ pub fn bevel_width() -> f32 {
     get_style_registry().read().unwrap().get_float("bevel_width").unwrap_or(9.3)
 }
 
+/// Roll-off width for the wall where a bar (menubar / status bar / the demo's
+/// header band) steps down into the window plate. Wider than the plate's own
+/// perimeter roll on purpose: the carve depth saturates at `bevel_width` in the
+/// tessellator, so the extra width flattens the wall's slope — a soft, gradual
+/// transition into the bar — instead of cutting a proportionally deeper groove.
+pub fn bar_wall_width() -> f32 {
+    bevel_width() * 1.75
+}
+
 pub fn toggle_corner_radius() -> f32 {
     lazy_init_style_registry();
     get_style_registry().read().unwrap().get_float("toggle_corner_radius").unwrap_or(4.0)
diff --git a/src/main.rs b/src/main.rs
index 358f377..25ae61d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -327,7 +327,7 @@ impl Application for DemoApp {
         pc.recess_edges(
             Rect { x: 0.0, y: 0.0, width: w, height: band_h },
             (0.0, 0.0, 0.0, 0.0),
-            bevel,
+            cce_ui::layout::bar_wall_width(),
             (false, false, true, false),
         );
 
@@ -342,7 +342,7 @@ impl Application for DemoApp {
         pc.recess_edges(
             Rect { x: 0.0, y: status_top, width: w, height: status_h },
             (0.0, 0.0, 0.0, 0.0),
-            bevel,
+            cce_ui::layout::bar_wall_width(),
             (true, false, false, false),
         );
 
diff --git a/src/widget/container/menu.rs b/src/widget/container/menu.rs
index 0eb3830..988707d 100644
--- a/src/widget/container/menu.rs
+++ b/src/widget/container/menu.rs
@@ -472,16 +472,19 @@ impl Paint for MenuBar {
             // renderer applies `bevel_depth` itself), capped so a deep DE-wide setting can
             // never swallow a short bar — the two walls would meet in the middle and the
             // flat floor would vanish.
-            let depth = crate::layout::bevel_width().min(rect.height * 0.4);
             if rect.x <= 0.5 && rect.y <= 0.5 {
                 // Flush with the plate's top-left: the bar is a plateau one step down, not a
                 // trough, so its only wall is the one facing the content. The other three
                 // sides are the plate's outer edge, where the plate's own roll already lives
-                // — carving there too would cut a second lip into the same pixels.
+                // — carving there too would cut a second lip into the same pixels. One wall
+                // straddling the boundary intrudes only half its width, so the cap is looser
+                // than the trough's.
+                let depth = crate::layout::bar_wall_width().min(rect.height * 0.6);
                 ctx.recess_edges(rect, (0.0, 0.0, 0.0, 0.0), depth, (false, false, true, false));
             } else {
                 // Inset from the plate edge: a real trough, walled all round, its corners
                 // rounded by the roll itself.
+                let depth = crate::layout::bar_wall_width().min(rect.height * 0.4);
                 ctx.recess(rect, (depth, depth, depth, depth), depth);
             }
         } else {
diff --git a/src/widget/display/status_bar.rs b/src/widget/display/status_bar.rs
index d6bbf28..7326375 100644
--- a/src/widget/display/status_bar.rs
+++ b/src/widget/display/status_bar.rs
@@ -140,8 +140,9 @@ impl Paint for StatusBar {
         if self.recessed {
             // The recess shading is a light/shadow overlay — whatever the plate painted
             // here shows through modulated, so no surface color is needed.
-            // Capped against the bar's own height so a deep DE-wide roll can't swallow it.
-            let depth = crate::layout::bevel_width().min(rect.height * 0.4);
+            // Capped against the bar's own height so a deep DE-wide roll can't swallow it
+            // (a single wall straddling the boundary intrudes only half its width).
+            let depth = crate::layout::bar_wall_width().min(rect.height * 0.6);
             ctx.recess_edges(rect, (0.0, 0.0, 0.0, 0.0), depth, (true, false, false, false));
         } else {
             // Always the plain background quad — the rounded-against-parent variant required a