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

commit0a08794d7798af934999a8eb807aa8d030fd430c
parentc2fccf89f3
authorLucas Galante <[email protected]>
date2026-07-09 10:12
docs(rfc): Phase 6 plan — definition of done, 6a/6b recorded, per-app order

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016MjP3pGQEDLkJbV5WEmYBe

 docs/rfc-core-rebuild.md | 36 +++++++++++++++++++++++++++++++++++-
 1 file changed, 35 insertions(+), 1 deletion(-)

diff --git a/docs/rfc-core-rebuild.md b/docs/rfc-core-rebuild.md
index 117ce2e..f30ab7a 100644
--- a/docs/rfc-core-rebuild.md
+++ b/docs/rfc-core-rebuild.md
@@ -748,7 +748,41 @@ Constraint respected: **each crate still builds standalone** — the new core is
     which point the `as_*_controller` pairs and the `Input` capability hooks die together
     (callers hold concrete types or `&dyn XController`).
 - **Phase 6 — Per-app migration.** Move each `cce-*` app onto the new core; delete legacy paths
-  once the last app is across.
+  once the last app is across. **Definition of done per app:** the whole frame — geometry AND
+  text — is one `Application::display_list()` (+ `display_list_text()`), layout runs through
+  the scene solver where the app has a real tree, events reach widgets through routed dispatch
+  rather than hand-rolled per-widget loops, and no embedded-base container
+  (Layer/Page/Plate/Backplate/ScrollBox/List) is load-bearing. Seven apps already feed
+  geometry through `display_list()` (colors, data-editor, files, fonts, graph, text-editor,
+  system-settings) — their remaining gaps are text, layout, and events.
+  - **6a — display-list text. DONE (live-A/B verified via cce-notifier).** `Prim::Text` now
+    carries `font: Option<String>` + `bounds: Option<[f32;4]>` (`PaintCtx::text_with`; plain
+    `text` emits None/None), and the backend renders a list's Text prims through the glyphon
+    pass — shaped via the shared `get_text_buffer` cache, clipped to the item clip ∩ the prim
+    bounds, held in `EngineState::dl_text_items` so the `TextArea`s can borrow the buffers.
+    **Opt-in via `Application::display_list_text()` (default false)**: the seven Phase 3
+    adopters' lists already carry Text prims that those apps ALSO push as `TextItem`s —
+    rendering both would double-draw; each app flips the flag when it stops pushing its own.
+    `Application::view`/`text_items` gained no-op defaults so a fully migrated app implements
+    neither. Known limitation (scoped out, not a bug): the legacy `text_areas`
+    popover-occlusion clip is not applied to display-list text yet — a popover plate does not
+    hide list text beneath it (text draws after all geometry); apps with popovers keep their
+    own text path until that lands. The 5s/5t labels hatches become expressible as prims once
+    hosts consume lists directly.
+  - **6b — `cce-notifier` (first app fully on one path). DONE (live-A/B on a private D-Bus
+    session: text/accent pixel-identical; 60-px residual is compositor translucency noise in
+    the alpha-0.9 background region).** The whole frame is one display list (accent quad +
+    three `text_with` prims in the configured bundled family); deleted: the app-side
+    `FontSystem`, the `TextItem` cache, `rebuild_layout`, and the scale/rebuild bookkeeping.
+    Non-interactive, so no event surface. This is the reference shape for a minimal Phase 6
+    app.
+  - **Still to do (per-app, roughly smallest-first):** wallpaper/screenaver (likely trivial),
+    the seven display_list() adopters (flip `display_list_text` + drop their TextItem
+    assembly, one at a time, each A/B'd), then the widget-tree apps (routed events + scene
+    layout + dissolving the embedded-base containers), the demo (`cce-ui/src/main.rs`) as the
+    reference `Application`, and popover-occlusion for display-list text before any app with
+    popovers flips the flag. Delete the legacy `view*`/`text_items` paths, the per-widget
+    text getters, and finally `Element` + `Adapted` once the last app is across.
 
 Order rationale: each phase is independently valuable and reversible, and no phase requires the
 next to compile. Phase 0 can land immediately regardless of the rest.