git.lucas.co / cce-system-interface
system settings
git clone https://git.lucas.co/cce-system-interface.git

commit3c41ae470216d0b08077705513a045e58831b90f
parentabc2efb1db
authorLucas Galante <[email protected]>
date2026-07-28 22:56
feat: sections render as sunken wells with carved title tabs (the designer look)

PageContent claims section frames via the new section_relief hatch;
display_list carves each well with the designer union shape — bottom-open
title tab, concave-filleted throat, one piece owning the right run, a
bridge for the left wall — clipped to the page viewport and scroll-
shifted. Focused sections keep the green outline for ctrl-nav feedback;
relief-off styling keeps the legacy outline everywhere.

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

 src/app.rs      |  23 ++++++++++++-
 src/main.rs     | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/renderer.rs |   1 +
 3 files changed, 126 insertions(+), 1 deletion(-)

diff --git a/src/app.rs b/src/app.rs
index 104df59..88bb081 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -98,6 +98,10 @@ pub struct PageContent {
     pub rects: Vec<([f32; 4], f32, f32, f32, f32, f32, (bool, bool, bool, bool))>,
     pub texts: Vec<(String, f32, f32, f32, [f32; 4], Option<String>, Option<[f32; 4]>)>,
     pub buttons: Vec<(cce_ui::widget::Adapted<cce_ui::widget::Button>, AppAction)>,
+    /// Section wells claimed via `RenderTarget::section_relief` — the body box
+    /// plus the title tab box, carved into the window plate by display_list as
+    /// recess prims (page coordinates, pre-scroll).
+    pub reliefs: Vec<((f32, f32, f32, f32), Option<(f32, f32, f32, f32)>)>,
     pub clip_stack: Vec<[f32; 4]>,
     pub measure_only: bool,
 }
@@ -108,6 +112,7 @@ impl Default for PageContent {
             rects: Vec::new(),
             texts: Vec::new(),
             buttons: Vec::new(),
+            reliefs: Vec::new(),
             clip_stack: Vec::new(),
             measure_only: true,
         }
@@ -116,7 +121,7 @@ impl Default for PageContent {
 
 impl PageContent {
     pub fn new() -> Self {
-        Self { rects: Vec::new(), texts: Vec::new(), buttons: Vec::new(), clip_stack: Vec::new(), measure_only: false }
+        Self { rects: Vec::new(), texts: Vec::new(), buttons: Vec::new(), reliefs: Vec::new(), clip_stack: Vec::new(), measure_only: false }
     }
 
     fn get_clipped_rect(&self, x: f32, y: f32, w: f32, h: f32) -> Option<(f32, f32, f32, f32)> {
@@ -246,6 +251,22 @@ impl RenderTarget for PageContent {
         self.texts.push((content.to_string(), size, x, y, color, Some(font.to_string()), cb));
     }
 
+    fn section_relief_style(&self) -> bool {
+        cce_ui::layout::control_relief()
+    }
+
+    fn section_relief(&mut self, f: &cce_ui::layout::SectionFrame) -> bool {
+        // Focused sections keep the legacy green outline (the ctrl-nav feedback);
+        // relief-off styling keeps the outline everywhere.
+        if f.focused || !cce_ui::layout::control_relief() {
+            return false;
+        }
+        if !self.measure_only {
+            self.reliefs.push(((f.x, f.y, f.w, f.h), f.tab));
+        }
+        true
+    }
+
     fn push_clip_rect(&mut self, x: f32, y: f32, w: f32, h: f32) {
         if self.measure_only { return; }
         let clip = if let Some(&parent_clip) = self.clip_stack.last() {
diff --git a/src/main.rs b/src/main.rs
index 0b41210..9eabae3 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -90,6 +90,9 @@ struct SystemInterface {
     // window pass reads last frame's value, exactly as the legacy Page did.
     page_scroll_bar: cce_ui::widget::Adapted<crate::scroll_bar::ScrollBar>,
     content_h: f32,
+    // Section wells: body box + title tab (page coords, pre-scroll) — carved by
+    // display_list.
+    page_reliefs: Vec<((f32, f32, f32, f32), Option<(f32, f32, f32, f32)>)>,
     // Root Backplate + StatusBar DISSOLVED (Phase 6s): the window plate and the status
     // bar are emitted as tuples in rebuild_layout.
     sans_serif_family: String,
@@ -178,6 +181,7 @@ impl cce_ui::engine::Application for SystemInterface {
             page_dropdown,
             page_scroll_bar: crate::scroll_bar::ScrollBar::new(),
             content_h: 0.0,
+            page_reliefs: Vec::new(),
             sans_serif_family: sans_family,
             serif_family,
             monospace_family,
@@ -281,6 +285,105 @@ impl cce_ui::engine::Application for SystemInterface {
                 pc.quad(rect, color);
             }
         }
+        // The section wells, carved after the page's flat quads so the walls shade
+        // the fills they cross (the designer relief order), clipped to the page
+        // viewport so a scrolled-off well can't shade the status bar or search row.
+        if !self.page_reliefs.is_empty() {
+            let view = Rect {
+                x: self.sidebar_width,
+                y: self.header_height,
+                width: width - self.sidebar_width,
+                height: (height - self.header_height - self.status_height
+                    - if self.search_open { 42.0 } else { 0.0 }).max(0.0),
+            };
+            let r = 13.0f32;
+            let scroll_y = self.scroll_y;
+            pc.clip(view, |pc| {
+                for &((cx, cy, cw, ch), tab) in &self.page_reliefs {
+                    let cy = cy - scroll_y;
+                    let depth = cce_ui::layout::bevel_width().min(ch * 0.2);
+                    match tab {
+                        Some((tx, ty, tw, th)) => {
+                            // The designer union carve: the title tab bottom-open, one
+                            // piece owning the whole right run so its corners are real
+                            // turns, a left piece carrying the left wall — pieces
+                            // extend past their interior seam by `depth` so the walls
+                            // crossfade there instead of notching — and the throat's
+                            // inside corner rounded by a concave fillet.
+                            let ty = ty - scroll_y;
+                            let rt = r.min(th * 0.45);
+                            let throat_r = tx + tw;
+                            let rho = 10.0f32; // designer SECTION_FILLET_R
+                            let body_lr = |x_run: f32, pc: &mut cce_ui::scene::paint::PaintCtx| {
+                                pc.recess_edges(
+                                    Rect { x: x_run, y: cy, width: cx + cw - x_run, height: ch },
+                                    (0.0, r, r, 0.0),
+                                    depth,
+                                    (true, true, true, false),
+                                );
+                                pc.recess_edges(
+                                    Rect { x: cx, y: cy, width: x_run + depth - cx, height: ch },
+                                    (0.0, 0.0, 0.0, r),
+                                    depth,
+                                    (false, false, true, true),
+                                );
+                            };
+                            if cx + cw > throat_r + 2.0 * rho {
+                                // Filleted throat: the tab's right wall ends at the
+                                // fillet's vertical tangent, a left-only bridge
+                                // carries the left wall across the fillet span.
+                                pc.recess_edges(
+                                    Rect { x: tx, y: ty, width: tw, height: (cy - rho) - ty + depth },
+                                    (rt, rt, 0.0, 0.0),
+                                    depth,
+                                    (true, true, false, true),
+                                );
+                                pc.recess_edges(
+                                    Rect { x: tx, y: cy - rho, width: tw, height: rho + depth },
+                                    (0.0, 0.0, 0.0, 0.0),
+                                    depth,
+                                    (false, false, false, true),
+                                );
+                                body_lr(throat_r + rho - depth, pc);
+                                pc.concave_fillet(throat_r + rho, cy - rho, rho, depth, std::f32::consts::FRAC_PI_2, false);
+                            } else if cx + cw > throat_r + 0.5 {
+                                // Too narrow for the fillet: the plain square throat.
+                                pc.recess_edges(
+                                    Rect { x: tx, y: ty, width: tw, height: (cy - ty) + depth },
+                                    (rt, rt, 0.0, 0.0),
+                                    depth,
+                                    (true, true, false, true),
+                                );
+                                body_lr(throat_r - depth, pc);
+                            } else {
+                                // The tab spans the body: no top wall at all.
+                                pc.recess_edges(
+                                    Rect { x: tx, y: ty, width: tw, height: (cy - ty) + depth },
+                                    (rt, rt, 0.0, 0.0),
+                                    depth,
+                                    (true, true, false, true),
+                                );
+                                pc.recess_edges(
+                                    Rect { x: cx, y: cy, width: cw, height: ch },
+                                    (0.0, 0.0, r, r),
+                                    depth,
+                                    (false, true, true, true),
+                                );
+                            }
+                        }
+                        None => {
+                            pc.recess_edges(
+                                Rect { x: cx, y: cy, width: cw, height: ch },
+                                (r, r, r, r),
+                                depth,
+                                (true, true, true, true),
+                            );
+                        }
+                    }
+                }
+            });
+        }
+
         cce_ui::widget::hover_animation::post_render_check();
         if let Some((qx, qy, qw, qh, qc)) = cce_ui::widget::hover_animation::get_quad() {
             pc.quad(Rect { x: qx, y: qy - self.scroll_y, width: qw, height: qh }, qc);
diff --git a/src/renderer.rs b/src/renderer.rs
index e9cbca0..53c4e1e 100644
--- a/src/renderer.rs
+++ b/src/renderer.rs
@@ -257,6 +257,7 @@ impl SystemInterface {
 
         // Page content in LOGICAL coordinates, then scale to physical
         let pc = self.render_page_content(lcx, lcy, lcw, lch);
+        self.page_reliefs = pc.reliefs.clone();