git.lucas.co / cce-designer
graphic design tool
git clone https://git.lucas.co/cce-designer.git

commit5f9b8fb1e622ee6d3eff6656516a0c4008d6326b
parent42bb569c36
authorLucas Galante <lsgalante12@gmail.com>
date2026-10-06 21:04
feat(playbar): the shelf meets the side lips in a cove

The shelf's top edge ran straight into the window's side lips and crossed
them, the two rolls stacked in a square at each end. It is drawn now as a
plate turned inside out (cce-ui's Prim::Frame): the face is everything below
the scene's opening, the roll runs round the opening's outline, and the
opening's bottom corners, at the plates' corner radius, are coves where the
top edge sweeps up into each side lip as one edge. The window's lip is drawn
over the coves as over the rest of the shelf.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

 CLAUDE.md     | 26 ++++++++++++++++----------
 src/render.rs | 40 ++++++++++++++++++++++++++--------------
 2 files changed, 42 insertions(+), 24 deletions(-)

diff --git a/CLAUDE.md b/CLAUDE.md
index 3955a8d..21d0ebd 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -3278,16 +3278,22 @@ bottom like the other plates. Its height is `PLAYBAR_H` over the window's
 bottom lip (`playbar_shelf_h`, `PLAYBAR_H + bevel_width`): the shelf runs
 down INTO the lip, and only its top edge is a plate's.
 
-- **Drawn as part of the window's edge** (the PLAYBAR_IDX render arm):
-  its plate runs out past the window's sides and bottom with square
-  corners, so only the TOP is rolled on screen, and the window's own lip
-  (`State::append_window_lip`, the viewport's) is drawn again over the
-  shelf, clipped to it — so the side lips run down unbroken into the
-  bottom corners and along the bottom, as around a window with no bar.
-  For its first hours it was a plate rolled all round, its top corners
-  rounded in from the side lips, and the two rolls stood side by side at
-  its ends and along its bottom. The lip goes on after the transport (a
-  quad between a plate and its carves drops them to the overlay shading).
+- **Drawn as part of the window's edge** (the PLAYBAR_IDX render arm): a
+  plate turned inside out (cce-ui's `PaintCtx::frame`, see its CLAUDE.md),
+  whose face is everything below the scene's opening and whose rolled edge
+  runs round the opening's outline. So the top edge meets each side lip in
+  a COVE — the opening's bottom corner, at `plate_corner_radius` in the
+  DE's corner family — one outline with the top. The face runs out past
+  the window's sides and bottom, so it has no other edge on screen, and
+  the window's own lip (`State::append_window_lip`, the viewport's) is
+  drawn again over the shelf and its coves, clipped to them, so the side
+  lips run down unbroken into the bottom corners. For its first hours the
+  bar was a plate rolled all round, its top corners rounded in from the
+  side lips, the two rolls side by side at its ends and along its bottom;
+  then for an hour its top edge ran straight into the side lips, crossing
+  them, the two rolls stacked in a square at each end. The lip goes on
+  after the transport (a quad between a plate and its carves drops them to
+  the overlay shading); the transport's carves group into the frame.
 - **The transport stands clear of the lip**: `Playbar::frame` is the lip's
   width, and the widget lays its buttons, track and readout out in its
   rect less that on the left, right and bottom (`Playbar::content`). Zero
diff --git a/src/render.rs b/src/render.rs
index 89c17ee..9feac71 100644
--- a/src/render.rs
+++ b/src/render.rs
@@ -422,22 +422,34 @@ impl State {
             let (wx, wy, ww2, wh2) = w.rect();
             if self.slots.playbar.inner().frame > 0.0 {
                 // A SHELF of the window's bottom edge, not a plate laid on
-                // it: the plate runs out past the window's sides and bottom
-                // with square corners, so only its TOP is rolled on screen,
-                // and the window's own lip is drawn again over its band —
-                // the side lips run down unbroken into the bottom corners
-                // and along the bottom, as they do around a window with no
-                // bar. Until this the bar was a plate rolled all round,
-                // its top corners rounded in from the side lips, and the
-                // two rolls stood side by side at its ends and its bottom.
-                // The lip goes on AFTER the transport: a quad between a
-                // plate and its carves drops them to the overlay shading,
-                // and the transport stands clear of the lip
-                // (`Playbar::frame`), so nothing it draws is under it.
+                // it: a plate turned inside out (cce-ui's `frame`), whose
+                // face is everything below the scene's opening and whose
+                // rolled edge runs round the opening's outline. So the top
+                // edge meets each side lip in a COVE — the opening's bottom
+                // corner, at the plates' corner radius — one outline with
+                // the top, where a straight edge running into the lip
+                // crossed it and stacked the two rolls. The face runs out
+                // past the window's sides and bottom, so it has no other
+                // edge on screen, and the window's own lip is drawn again
+                // over the shelf and its coves: the side lips run down
+                // unbroken into the bottom corners, as they do around a
+                // window with no bar. The lip goes on AFTER the transport —
+                // a quad between a plate and its carves drops them to the
+                // overlay shading — which stands clear of it
+                // (`Playbar::frame`).
                 let e = cce_ui::colors::plate_bevel_width() + 1.0;
-                append_plate_at(w, pc, rect(wx - e, wy, ww2 + 2.0 * e, wh2 + e), None, (0.0, 0.0, 0.0, 0.0));
+                let cove = cce_ui::layout::plate_corner_radius().min(wh2);
+                let face = rect(wx - e, wy - cove, ww2 + 2.0 * e, wh2 + cove + e);
+                let opening = rect(wx, wy - self.height, ww2, self.height);
+                let material = cce_ui::scene::material::Material::from_fill(w.color());
+                let depth = if cce_ui::layout::control_relief() {
+                    w.plate_bevel().unwrap_or_else(cce_ui::colors::plate_bevel_width)
+                } else {
+                    0.0
+                };
+                pc.frame(face, opening, (0.0, 0.0, cove, cove), &material, depth);
                 w.paint_self(&self.ui_context, pc);
-                pc.clip(rect(wx, wy, ww2, wh2), |pc| self.append_window_lip(pc));
+                pc.clip(rect(wx, wy - cove, ww2, wh2 + cove), |pc| self.append_window_lip(pc));
             } else {
                 append_widget_plate_radii(w, pc, None, self.pane_plate_radii(wx, wy, ww2, wh2));
                 w.paint_self(&self.ui_context, pc);