From 721a99ed64d8dd1824a1fa5437172f471915d833 Mon Sep 17 00:00:00 2001 From: iris Date: Sat, 15 Aug 2026 11:43:50 +0200 Subject: [PATCH] docs(web-ui/shape): add routes header, trim historical framing --- docs/web-ui/shape.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/web-ui/shape.md b/docs/web-ui/shape.md index 0de8445c..718010d1 100644 --- a/docs/web-ui/shape.md +++ b/docs/web-ui/shape.md @@ -3,6 +3,8 @@ > Part of [Web UI](../web-ui.md). See also: > [Dashboard layout](dashboard.md) · [Per-agent page](agent.md) +## Shared routes + - `GET /` → `index.html` from the bundled frontend dist (see `frontend/`). Both binaries' routers declare their dynamic endpoints first and then `fallback_service(ServeDir::new(...))` @@ -19,8 +21,8 @@ `dashboard.css` / `flow.css` / `logs.css`); `common.css` inlines `base.css` + `terminal.css` via esbuild's `@import` resolution. `terminal.js` exports `{ create, linkify }` as ES module - members (no more `window.HiveTerminal` global outside the - back-compat shim the IIFE bodies still use). The dashboard's + members; a back-compat shim in the IIFE bodies still exposes + a `window.HiveTerminal` global for callers that need it. The dashboard's `#msgflow` and the per-agent `#live` log are both backed by this terminal — sticky-bottom auto-scroll, "↓ N new" pill, history backfill, SSE plumbing all live there. Each page @@ -209,13 +211,11 @@ soon as they blur. **Atomic section repaint:** every managed-section renderer goes through `paintAtomic(liveRoot, build)`: the builder appends into a fresh `DocumentFragment` (off-DOM) and the commit is one -`replaceChildren` call. The naive `root.innerHTML = ''; root.append(...)` -shape was visibly flashing empty on every poll cycle — on async -paths the await yield gave the browser a paint opportunity between -the clear and the re-append, and on complex builds (many `el()` -allocations) layout could escape the per-task budget even on the -synchronous path. The fragment approach keeps the intermediate -empty state invisible. Builders receive the fragment as their +`replaceChildren` call, so the intermediate empty state is never +visible — clearing and re-appending directly into the live root can +leave it empty for a paint (on async builders) or a whole frame (on +large synchronous ones), which reads as a visible flash on every +poll cycle. Builders receive the fragment as their `root`, so existing renderer code carries over unchanged; early returns inside the builder still commit whatever was appended before they returned.