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

commit9310999a6f7bfed3bad5bb911c078746af28c7c0
parent61e2cefd67
authorLucas Galante <lsgalante12@gmail.com>
date2026-09-28 13:11
fix: one roll width — pane plates roll over style.surface.relief.width

`colors::plate_bevel_width` returned a width of its own
(`style.surface.plate.bevel_width`, default 6) while `PlateSpec` pane
plates, the root plate, every control wall and `relief.edge_height`'s
ratio all used `layout::bevel_width` (`style.surface.relief.width`,
9.3). So two pane plates in one window rolled over different widths
depending on which painter drew them, the designer's panes could not be
made to match its own window lip by editing one key, and the edge height
was a rise against a width the panes never used.

The getter now returns the relief width. The old key survives as an
explicit override (an Option, cleared when absent on reload, reported
once at load) for a config that still carries it; it is unit-blind where
the relief width resolves lengths. `set_plate_bevel_width` takes the
Option. Pinned by
`the_pane_roll_is_the_relief_width_unless_a_legacy_key_overrides_it`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

 CLAUDE.md            | 14 ++++++++++++++
 src/color.rs         | 51 ++++++++++++++++++++++++++++++++++++++++++++-------
 src/scene/painter.rs |  7 ++++---
 3 files changed, 62 insertions(+), 10 deletions(-)

diff --git a/CLAUDE.md b/CLAUDE.md
index e8bfa32..7fbe98c 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -686,6 +686,20 @@ carries the drop as `h=` (a length: `h=0.5mm`, or bare px) beside `w=` and
 its section's depth numbers read in mm when the metric is real, and Save
 writes `height` as a `(mm)` length then, px otherwise.
 
+**There is one roll width.** `style.surface.relief.width` is the run of every
+roll and wall: the root plate's perimeter (`PlateSpec::window`), a `PlateSpec`
+pane plate, a bordered widget plate under relief (`append_widget_plate`, via
+`colors::plate_bevel_width`), every control wall, and the length
+`edge_height` is a rise against. Until 2026-09-28 the widget-plate path had a
+width of its own — `style.surface.plate.bevel_width`, default 6 against the
+relief's 9.3 — so two pane plates in one window rolled over different widths
+depending on which painter drew them, and no single key made a pane match the
+window lip. `plate_bevel_width()` now returns the relief width; the old key is
+an explicit override for a config that still carries it (reported once at
+load, and unit-blind where the relief width resolves lengths), and the test
+`the_pane_roll_is_the_relief_width_unless_a_legacy_key_overrides_it` pins the
+fallback.
+
 **And the relief can leave the screen.** `scene/heightfield.rs` integrates the
 height curves the shader only differentiates and samples a frame's plates into a
 height field — plates stack, carves etch, exactly the composite model the shader
diff --git a/src/color.rs b/src/color.rs
index 1ae7f6c..6bb747a 100644
--- a/src/color.rs
+++ b/src/color.rs
@@ -659,8 +659,17 @@ fn parse_and_set_colors(content: &str) {
     if let Some(t) = val.pointer("/style/surface/plate/border_thickness").and_then(|v| v.as_f64()) {
         if let Ok(mut lock) = PLATE_BORDER_THICKNESS.write() { *lock = t as f32; }
     }
-    if let Some(t) = val.pointer("/style/surface/plate/bevel_width").and_then(|v| v.as_f64()) {
-        if let Ok(mut lock) = PLATE_BEVEL_WIDTH.write() { *lock = t as f32; }
+    // The pane roll's OVERRIDE, not its width: absent (the shipped state), the
+    // roll is `style.surface.relief.width` like every other roll. Read as an
+    // Option so a key removed from config clears the override on reload.
+    {
+        let t = val.pointer("/style/surface/plate/bevel_width").and_then(|v| v.as_f64()).map(|t| t as f32);
+        if t.is_some() {
+            log::warn!(
+                "style.surface.plate.bevel_width is a legacy override: the pane roll follows style.surface.relief.width when it is unset"
+            );
+        }
+        if let Ok(mut lock) = PLATE_BEVEL_WIDTH.write() { *lock = t; }
     }
     if let Some(c) = get_color("/style/surface/param/color") {
         if let Ok(mut lock) = PARAM_BG_COLOR.write() { *lock = c; }
@@ -1807,9 +1816,10 @@ pub fn set_root_plate_statusbar_blur(b: bool) {
 static PLATE_COLOR: RwLock<Option<[f32; 4]>> = RwLock::new(Some([0.15, 0.15, 0.2, 0.95]));
 static PLATE_BORDER_COLOR: RwLock<Option<[f32; 4]>> = RwLock::new(Some([0.3, 0.3, 0.4, 1.0]));
 static PLATE_BORDER_THICKNESS: RwLock<f32> = RwLock::new(1.0);
-/// Roll width of the beveled plate border (the control_relief replacement for
-/// the flat border line) — `style.surface.plate.bevel_width`.
-static PLATE_BEVEL_WIDTH: RwLock<f32> = RwLock::new(6.0);
+/// A legacy override of the pane plate's roll width
+/// (`style.surface.plate.bevel_width`); `None`, the shipped state, means the
+/// roll is [`crate::layout::bevel_width`]. See [`plate_bevel_width`].
+static PLATE_BEVEL_WIDTH: RwLock<Option<f32>> = RwLock::new(None);
 
 pub fn plate_color() -> Option<[f32; 4]> {
     load_colors_once();
@@ -1838,12 +1848,27 @@ pub fn set_plate_border_thickness(t: f32) {
     style_write(&PLATE_BORDER_THICKNESS, t);
 }
 
+/// Roll width of a beveled pane plate (the control_relief replacement for the
+/// flat border line), in logical px.
+///
+/// **This is `style.surface.relief.width`** — the one roll width, the same
+/// number the root plate rolls over, every control wall runs, and
+/// `relief.edge_height` is a rise against. Until 2026-09-28 it was a second
+/// width of its own (`style.surface.plate.bevel_width`, default 6 against the
+/// relief's 9.3), so a `PlateSpec` pane plate and an `append_widget_plate`
+/// pane plate rolled over different widths in one window, the designer's
+/// panes could not be made to match its own window lip by editing one key,
+/// and the edge height was expressed against a width the panes did not use.
+/// The old key survives as an explicit override for a config that still
+/// carries it, reported once at load; it is unit-blind (a bare number) where
+/// the relief width resolves lengths through the metric.
 pub fn plate_bevel_width() -> f32 {
     load_colors_once();
-    style_read(&PLATE_BEVEL_WIDTH)
+    style_read(&PLATE_BEVEL_WIDTH).unwrap_or_else(crate::layout::bevel_width)
 }
 
-pub fn set_plate_bevel_width(t: f32) {
+/// Install (or with `None` clear) the legacy pane-roll override.
+pub fn set_plate_bevel_width(t: Option<f32>) {
     style_write(&PLATE_BEVEL_WIDTH, t);
 }
 
@@ -2194,6 +2219,18 @@ mod tests {
     }
 
     /// Rim refraction defaults OFF and clamps, like its neighbour.
+    /// The pane plates roll over the relief width — the one roll width — and
+    /// the legacy `plate.bevel_width` key is an override, not a second width.
+    #[test]
+    fn the_pane_roll_is_the_relief_width_unless_a_legacy_key_overrides_it() {
+        set_plate_bevel_width(None);
+        assert_eq!(plate_bevel_width(), crate::layout::bevel_width(), "unset: the relief width");
+        set_plate_bevel_width(Some(12.0));
+        assert_eq!(plate_bevel_width(), 12.0, "the legacy key still wins while a config carries it");
+        set_plate_bevel_width(None);
+        assert_eq!(plate_bevel_width(), crate::layout::bevel_width(), "cleared: back to the relief width");
+    }
+
     #[test]
     fn plate_refraction_defaults_off_and_clamps() {
         assert_eq!(plate_refraction(), 0.0, "off unless a config asks");
diff --git a/src/scene/painter.rs b/src/scene/painter.rs
index a3f216a..433521d 100644
--- a/src/scene/painter.rs
+++ b/src/scene/painter.rs
@@ -94,9 +94,10 @@ pub fn append_widget_plate(w: &dyn WidgetHost, pc: &mut PaintCtx) {
 /// [`append_widget_plate`] with an optional specular tint for the plate's
 /// bevel — the focused-pane treatment: the highlight colors the lit roll's
 /// glint instead of drawing a separate border ring. Under `control_relief` a
-/// bordered plate renders as a bevel (`plate_bevel_width` roll) — the beveled
-/// counterpart of the flat border line, exactly the controls' own
-/// outline→relief degradation.
+/// bordered plate renders as a bevel rolled over `plate_bevel_width` — the
+/// relief width, the same roll a `PlateSpec` pane plate and the root plate
+/// wear — the beveled counterpart of the flat border line, exactly the
+/// controls' own outline→relief degradation.
 pub fn append_widget_plate_tinted(w: &dyn WidgetHost, pc: &mut PaintCtx, tint: Option<[f32; 3]>) {
     let radii = w.corner_radii();
     append_widget_plate_radii(w, pc, tint, (radii.top_left, radii.top_right, radii.bottom_right, radii.bottom_left));