git.lucas.co / cce-status-interface
status bar
git clone https://git.lucas.co/cce-status-interface.git

commit293c76dee0d43737331028b52105634eba8c754a
parent2eff84a87b
authorLucas Galante <[email protected]>
date2026-08-24 14:50
feat: text_relief letterpress underlay + droplet core knob

module { text_relief } draws a translucent white copy 0.75px
down-right beneath each module text run (engraved text — a lit edge
that carries the letterforms on dark backdrops and vanishes on light
ones). module { droplet } gains the core key for cce-ui's new
interior-density term.

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

 CLAUDE.md     |  7 +++++--
 src/config.rs |  9 +++++++++
 src/main.rs   | 15 ++++++++++++++-
 3 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/CLAUDE.md b/CLAUDE.md
index 7a20b4e..a3a6069 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -140,14 +140,17 @@ background_blur tint scaling still applies on top) and `module { text_color }`
 style — cce-ui's `Prim::Droplet`, shader mode 10; the key's PRESENCE enables
 it, its value is whitespace-separated `k=v` pairs onto `DropletSpec` — sag,
 belly, belly_w, blend, sheet_r, attach, clarity, dome, band, gleam, shine,
-rim, bow, curve; defaults = the oval dewdrop (no belly; attach 0.42 +
+rim, bow, curve, core; defaults = the oval dewdrop (no belly; attach 0.42 +
 sheet_r 0.58 fill the height so there is NO straight side; bow arcs the
 bottom; curve 2.6 = superellipse joins, so everything but the flat top is one
 continuous curve), belly>0 brings back the pendant-pool look —
 warn-and-skip on unknown keys; the expanded menu box becomes the drop growing,
 and drops inset 1px from the surface bottom for the silhouette's AA feather)
 and `module { text_raise }` (lifts module text above vertical center, logical
-px, bar-side only — every module funnels through `centered_text_y`). Everything is read through
+px, bar-side only — every module funnels through `centered_text_y`) and
+`module { text_relief }` (letterpress underlay strength 0-1: a translucent
+white copy 0.75px down-right beneath each non-boxed text run — engraved text,
+guaranteed contrast on dark backdrops). Everything is read through
 `cce_ui::config::cached_config()`; KDL is converted to JSON
 (`cce_ui::config::parse_kdl_to_json`) and looked up by **explicit JSON
 pointer only**: every key names its canonical nesting
diff --git a/src/config.rs b/src/config.rs
index df69ca4..6a12e74 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -205,6 +205,7 @@ pub(crate) fn read_droplet_from_config() -> Option<cce_ui::scene::paint::Droplet
             "rim" => spec.rim = v,
             "bow" => spec.bow = v,
             "curve" => spec.curve = v,
+            "core" => spec.core = v,
             _ => log::warn!("module.droplet: unknown key '{}' — skipped", key),
         }
     }
@@ -218,6 +219,14 @@ pub(crate) fn read_text_raise_from_config() -> f32 {
     cfg_f32("/module/text_raise").unwrap_or(0.0)
 }
 
+/// `module { text_relief }` — letterpress underlay strength (0 = off, 1 =
+/// opaque): each module text run gets a white copy offset ~0.75px down-right
+/// BENEATH the glyphs, so dark text keeps a lit edge on dark backdrops (the
+/// engraved-text treatment, matching the DE's relief language). Bar-side only.
+pub(crate) fn read_text_relief_from_config() -> f32 {
+    cfg_f32("/module/text_relief").unwrap_or(0.0).clamp(0.0, 1.0)
+}
+
 pub(crate) fn read_status_box_corner_radius_from_config() -> f32 {
     // App-native ONLY (~/.config/cce/cce-status-interface/config.kdl,
     // merged over the shared config by cce-ui): `module { corner_radius }`.
diff --git a/src/main.rs b/src/main.rs
index 8f2bae3..6db6fd0 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -260,6 +260,9 @@ struct StatusApp {
     /// first so module content sits on the drop.
     droplet_boxes: Vec<(f32, f32, f32, f32, [f32; 4])>,
     droplet: Option<cce_ui::scene::paint::DropletSpec>,
+    /// Letterpress underlay strength for module text (0 = off) — see
+    /// `read_text_relief_from_config`.
+    text_relief: f32,
     text_prims: Vec<TextPrim>,
 
     scale_factor: f64,
@@ -367,6 +370,7 @@ impl StatusApp {
         self.box_bevel_depth = read_status_box_bevel_depth_from_config();
         self.droplet = read_droplet_from_config();
         self.droplet_boxes.clear();
+        self.text_relief = read_text_relief_from_config();
 
         self.status_bar.set_rect(0.0, 0.0, self.width as f32, self.height as f32);
         // The surface itself is transparent: every StatusApp is a single
@@ -1116,6 +1120,7 @@ impl cce_ui::engine::Application for StatusApp {
             rounded_boxes: Vec::new(),
             droplet_boxes: Vec::new(),
             droplet: None,
+            text_relief: 0.0,
             text_prims: Vec::new(),
             scale_factor: 1.0,
             width: if selected_module.is_some() { 120 } else { 1920 },
@@ -1412,7 +1417,15 @@ impl cce_ui::engine::Application for StatusApp {
         for (text, tsize, x, y, color, font, bounds, layout) in &self.text_prims {
             match layout {
                 Some(l) => pc.text_boxed(text.clone(), *x, *y, *tsize, *color, font.clone(), *bounds, cce_ui::scene::paint::TextAttrs::default(), *l),
-                None => pc.text_with(text.clone(), *x, *y, *tsize, *color, font.clone(), *bounds),
+                None => {
+                    // Letterpress underlay: a translucent white copy offset
+                    // down-right BENEATH the glyphs — dark text keeps a lit
+                    // edge on dark backdrops (the engraved-text treatment).
+                    if self.text_relief > 0.0 {
+                        pc.text_faded(text.clone(), *x + 0.75, *y + 0.75, *tsize, [255, 255, 255], self.text_relief, font.clone(), *bounds);
+                    }
+                    pc.text_with(text.clone(), *x, *y, *tsize, *color, font.clone(), *bounds)
+                }
             }
         }