desktop grid client
git clone https://git.lucas.co/cce-grid.git
feat: draw the line relief as one Prim::Lattice, not a ring per cell
The per-cell recess rings stacked in colour space at every crossing and
overlapped each other along the rail centre. cce-ui's lattice carve is a
single evaluation over the nearest cell, so junctions are mitres and the
wall runs from each cell edge outward over the roll as documented.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
CLAUDE.md | 19 ++++++++++++-------
src/main.rs | 38 +++++++++++++++++++++++---------------
2 files changed, 35 insertions(+), 22 deletions(-)
diff --git a/CLAUDE.md b/CLAUDE.md
index 2e37d7b..e324f30 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -15,13 +15,18 @@ latched a patch yet, and its gap-colored backdrop always draws beneath as
the safety net beyond patch edges.
Rendering is a pure function of (patch, style config): flat rounded cells,
-with the relief on the LINES — per-cell `Recess` rings expanded by the
-half-gap, so the walls occupy exactly the half-rail around each cell
-(crest at the rail centerline, inner edge concentric with the cell arc)
-and neighboring rings abut without double-shading. Cell floors carry NO
-relief (user decision); the rails read as raised grout. The compositor
-fallback draws the same expanded-ring chamfer so the client latch never
-swaps the grid's material. `style.surface.desktop.line_relief` overrides
+with the relief on the LINES — ONE `Prim::Lattice` for the whole patch
+(cce-ui shader mode 13): the pixel is folded into the grid period and the
+wall is measured from the NEAREST cell's edge outward over the roll, so
+the rail between two cells and the crossing where four meet are a single
+profile evaluation and join as true mitres. It replaced one `Recess` ring
+per cell (2026-09-14): those were N free overlays whose rounded corners
+stacked in colour space at every crossing and read as several overlapping
+effects, and whose walls — straddling a boundary inflated by the roll —
+overlapped each other down the rail centre whenever the roll exceeded a
+quarter gap. Cell floors carry NO relief (user decision); the rails read as
+raised grout. The compositor fallback still draws its expanded-ring scenefx
+chamfer (a different renderer, shown only until this client latches). `style.surface.desktop.line_relief` overrides
the lip for the grid alone: a plain integer is the lip width in logical
px (0 = no lip; unset = follow the DE-wide relief material), and a
`(relief)` value carries a full custom material — width, depth, and wall
diff --git a/src/main.rs b/src/main.rs
index a5fd3f7..f5fa0d6 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -306,8 +306,6 @@ impl GridApp {
.max(0.0)
* s;
let lip = roll >= 0.5;
- let ring_radius = radius + roll as f32;
- let ring_depth = (roll as f32).max(1.0);
// One extra ring of cells beyond the patch: a border cell outside the
// patch still owns the inner half of the boundary rail's shading.
@@ -331,21 +329,31 @@ impl GridApp {
height: (len_h * s) as f32,
};
pc.rounded_rect(rect, radius, (true, true, true, true), st.cell_color);
- if lip {
- let ring = Rect {
- x: rect.x - roll as f32,
- y: rect.y - roll as f32,
- width: rect.width + 2.0 * roll as f32,
- height: rect.height + 2.0 * roll as f32,
- };
- pc.recess(
- ring,
- (ring_radius, ring_radius, ring_radius, ring_radius),
- ring_depth,
- );
- }
}
}
+ // The relief on the LINES is ONE primitive for the whole patch: a
+ // lattice carve, folded per pixel to the nearest cell, so the rail
+ // between two cells and the crossing where four meet are a single
+ // profile evaluation — true mitres. This replaced one recess ring per
+ // cell: N free overlays whose rounded corners stacked in colour space
+ // at every crossing and read as overlapping effects, and whose ring
+ // walls (straddling a boundary inflated by the roll) overlapped each
+ // other down the rail centre whenever the roll exceeded a quarter
+ // gap. The wall runs from each cell's edge outward over `roll`.
+ if lip {
+ let origin = (
+ ((inset_x + len_w * 0.5 - p.x) * s) as f32,
+ ((inset_y + len_h * 0.5 - p.y) * s) as f32,
+ );
+ pc.lattice(
+ Rect { x: 0.0, y: 0.0, width: size.width as f32, height: size.height as f32 },
+ ((period_x * s) as f32, (period_y * s) as f32),
+ origin,
+ ((len_w * s) as f32, (len_h * s) as f32),
+ radius,
+ (roll as f32).max(1.0),
+ );
+ }
// Pinned images sit ON the canvas, so they are placed by the same
// world->patch mapping as the cells and drawn after them. The whole