git.lucas.co / cce-data-editor
structured data editor
git clone https://git.lucas.co/cce-data-editor.git

commita03fee26ec5529fd77129dbe17c4c1840d70ef13
parent3bd1a2d7c0
authorLucas Galante <[email protected]>
date2026-08-18 14:18
relief values get the bevel-preview row; click opens cce-relief --key

A (relief)-annotated value — and any key named line_relief still in
integer form, the annotation only appears once a material is saved —
shows the BevelPreview cross-section (seeded from the value's k= knob
triple) instead of a plain int/text editor, and clicking it opens
cce-relief targeted at that single key (--key <flat.path>, plus
--config for the file being edited) rather than the file's shared
material. Verified in a shadow session: preview row on the
integer-form key, and the click spawns cce-relief with the right argv.

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

 CLAUDE.md   |  6 ++++++
 src/main.rs | 46 ++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 48 insertions(+), 4 deletions(-)

diff --git a/CLAUDE.md b/CLAUDE.md
index cea6b69..6424e40 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -80,6 +80,12 @@ appears is decided in two places that must stay in agreement: the layout block i
   "shoulder,base,bias" value; clicking opens `cce-relief`, whose Save is picked
   up by the disk-sync watch). The annotation stays `bevel` — it is a config key,
   and did not follow the tool's rename from `cce-bevel`.
+  `relief` → the same `BevelPreview`, seeded from the `(relief)` value's `k=`
+  knob triple (`cce_ui::relief_spec::ReliefSpec`), but clicking opens
+  `cce-relief --key <flat.path>` so Save rewrites that single value instead of
+  the file's shared material. Keys NAMED `line_relief` get this treatment even
+  while their value is still a plain integer (the annotation only exists once
+  a material was saved) — same key-name-heuristic convention as fonts.
 - **Key-name heuristics**: `font` / `*_font` / `*.font` → `FontSelector`; keybind-ish
   names (`key`, `shortcut`, `brightness_up`, …) → `KeybindRecorder`.
 - **Value shape**: `#`-prefixed string → `ColorSelector`, bool → `Checkbox`,
diff --git a/src/main.rs b/src/main.rs
index dd7ca7d..8c70f4b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -630,6 +630,21 @@ impl DataEditorApp {
         let local = format!("{home}/.local/bin/cce-relief");
         let cmd = if std::path::Path::new(&local).exists() { local } else { "cce-relief".to_string() };
         let mut command = std::process::Command::new(&cmd);
+        // A relief-valued key (the (relief) annotation, or a line_relief key
+        // still in integer form) targets its own single value: cce-relief
+        // --key seeds from it and Save rewrites only it. A (bevel) key keeps
+        // editing the file's shared material.
+        let relief_key = self.selected_key_idx.and_then(|idx| {
+            let key = self.flat_keys[idx].0.clone();
+            let by_anno = cce_ui::config::get_kdl_type_annotation(&self.raw_json_editor.text, &key)
+                .as_deref()
+                == Some("relief");
+            let by_name = key == "line_relief" || key.ends_with(".line_relief");
+            (by_anno || by_name).then_some(key)
+        });
+        if let Some(ref key) = relief_key {
+            command.args(["--key", key]);
+        }
         // Target the file being edited: per-app configs get their own
         // material instead of cce-relief's default shared-config.kdl save.
         if let Some(ref path) = self.current_file_path {
@@ -1600,6 +1615,7 @@ impl Application for DataEditorApp {
                     let mut menu_options = Vec::new();
                     let mut is_button_type = false;
                     let mut is_bevel_type = false;
+                    let mut is_relief_type = false;
                     let mut annotation_str = None;
                     if let Some(annotation) = cce_ui::config::get_kdl_type_annotation(&self.raw_json_editor.text, key_name) {
                         annotation_str = Some(annotation.clone());
@@ -1611,16 +1627,38 @@ impl Application for DataEditorApp {
                             is_button_type = true;
                         } else if annotation == "bevel" {
                             is_bevel_type = true;
+                        } else if annotation == "relief" {
+                            is_relief_type = true;
                         }
                     }
+                    // line_relief keys get the relief treatment even in
+                    // integer form (the (relief) annotation only appears once
+                    // a material was saved): the preview is the affordance
+                    // that opens cce-relief --key on them — same key-name
+                    // heuristic convention as fonts and keybinds.
+                    if !is_relief_type
+                        && !is_bevel_type
+                        && (key_name == "line_relief" || key_name.ends_with(".line_relief"))
+                    {
+                        is_relief_type = true;
+                    }
                     // Parked unless the bevel branch below places it (the other
                     // branches never show it, so one shared park suffices).
                     self.selected_bevel_editor.set_rect(-1000.0, -1000.0, 1.0, 1.0);
 
-                    if is_bevel_type {
-                        // The (bevel) preview: a mini lit cross-section of the
-                        // knob triple; clicking it opens cce-relief.
-                        if let serde_json::Value::String(st) = val {
+                    if is_bevel_type || is_relief_type {
+                        // The (bevel)/(relief) preview: a mini lit
+                        // cross-section of the knob triple; clicking it opens
+                        // cce-relief (targeted at the KEY for a relief value).
+                        if is_relief_type {
+                            let knobs = if let serde_json::Value::String(st) = val {
+                                cce_ui::relief_spec::ReliefSpec::parse(st).and_then(|s| s.knobs)
+                            } else {
+                                None
+                            };
+                            let (a, b, c) = knobs.unwrap_or((0.5, 0.5, 0.5));
+                            self.selected_bevel_editor.set_knobs_str(&format!("{a:.3},{b:.3},{c:.3}"));
+                        } else if let serde_json::Value::String(st) = val {
                             self.selected_bevel_editor.set_knobs_str(st);
                         }
                         self.selected_bevel_editor.set_rect(row_x + 245.0, row_y + 1.0, 125.0, 26.0);