MusePi

MusePi GUI Design Specification

English 中文

Status: living document (established 2026-08-06) — defines the design style and interaction standards for packages/gui / packages/desktop-web (what it looks like, how it moves, how it is organized). Kept in sync with the implementation; implementation files are authoritative.

Implementation contracts, daemon RPC shapes, pitfall records, and verification methods live in docs/gui-implementation.md (split out of this file on 2026-08-06). Early wireframe/architecture drafts (gui-prototype / gui-architecture / gui-migration) have been deleted — the implementation shipped long ago; this document and gui-implementation are authoritative.

Editing convention: change the implementation → update this file in sync; when this document disagrees with code, code wins and this document gets updated.

i18n contract (desktop-web/src/i18n)

0. Tree/Trajectory glossary (normalized 2026-08-21, eliminating naming misalignment)

Term Refers to Component/carrier Notes
Session list Sessions aggregated in the left sidebar by group/project/date/scheduled task (multi-select/pin/status marking) SessionTree.tsx (file name kept from the old name; its job is a list) Don’t call it “session tree”; docs/comments say “session list”
Session/message tree In-session entry tree: entry id/parentId hierarchy, fork branches, leaf navigation (the semantics of TUI /tree) TUI tree-selector.ts + session-level session-manager.ts; GUI-side carrier lib/message-tree.ts (buildMessageTree) Two data layers distinct from the “session list”: the list governs “which session to pick”, the message tree governs “how a session branches”
Trajectory The current session’s event timeline: turn grouping + Overview timeline + inspector + jumping Right ContextPanel “Trajectory” tab (TrajectoryView + TimelineOverview) Time-projection axis; same source as the message tree (same batch of entries) but a different projection dimension
/trace (planned) Fusion view of message tree × trajectory in the TUI: time/cost/token columns overlaid on the tree structure New TUI command (reuses the tree-selector data source) Plan in docs/tui-trace-plan.md; /tree stays a pure structural projection

Naming iron rule: in code/docs/UI copy, “session tree” may only mean the message tree (/tree semantics); trees in the session sense are always “session list”; timelines are always “trajectory”.

1. Layout system

Trajectory timeline & inspector (DSH Trajectory Overview parity, 2026-08-21)

The top of TrajectoryView in the right ContextPanel’s “Trajectory” tab = a fixed Overview time bar (TimelineOverview.tsx, does not scroll with the list): a 44px rounded band with sunken inset + 1px border; background = the time domain ([earliest start, latest end] across all turns), mono start/end clocks at both ends; one segment per turn (traj-ov-segment, accent 26% → hover 42%; spanning the full round duration when the agent_end-frozen round duration hits, otherwise ending at that turn’s last event), and one dot per tsMs-bearing event within a turn (traj-ov-dot, colored by kind; user dots slightly lower/staggered).

Interaction contract (aligned with DSH Overview drag-focus, restrained pacing):

CSS naming: traj-ov-* / traj-focus-* / traj-inspector-* / traj-event--selected|--dim all live in the trajectory section of gui-workspace.css. Icons reuse the oc-icons sprite (focus chip uses target; never the nonexistent focus-3).

2. Design tokens & theme

3. Motion standard (core standard, finalized 2026-08-06)

Scenario Component Mechanism
Conditional block (visibility follows another option) <Reveal open> (components/Reveal.tsx) useCollapse px-height 240ms cubic-bezier(0.22,1,0.36,1) + outer 160ms fade-in; closed state aria-hidden+inert; node stays mounted
Stays mounted but changes height (tab switches/list growth) <HeightMorph morphKey> (components/HeightMorph.tsx) Capture old height at render → commit new content → height transition → settle auto; same outer 160ms fade-in restarts per key; during the morph the container clips content with overflow:hidden, otherwise new content instantly fills (overflow pins the short box) and you only see box edges moving = “no animation”; restored after settle; when height is unchanged (|target-prev|<1, e.g. the fixed-height scroll container of settings section switches) skip pinning/clipping and keep only the fade — otherwise the scrollbar vanishes 300ms and scrolling gets disabled; duration adapts to height delta 240→480ms (delta/6 capped) — the ease-out curve is extremely front-loaded, so even a fixed 240ms large expansion (e.g. the 2200px provider grid) still reads as a quick pop

4. Component & settings patterns

Desktop subagent operations (2026-08-11, TUI Agent Hub parity): daemon adds RPCs agents.kill (abort + release tombstone→aborted) / agents.revive (ensureLive) / agents.chat (ensureLive + prompt steer, isomorphic to the collab host’s agent-cmd, beside agents.list in server.ts). In the GUI right ContextPanel, AgentsPanel renders an AgentControls action bar for the selected row (gui/src/components/AgentControls.tsx): running→stop, parked/aborted→revive, chat input (Enter sends), errors in small print. Collab guests go through agent-cmd frames, desktop through RPC — both paths semantically identical. The SDK events.ts agent-progress payload comment corrected to SubagentProgressPayload wrapper (the shape the daemon actually sends). RPC verified live: kill idle→{ok}+ref aborted, kill/revive error paths, chat→ensureLive+steer effective; the running-state kill timing window wasn’t captured (the step-3.7-flash subagent finishes too fast), abort path isomorphic to the collab host. i18n completion: schema UI strings cover 100% of translatable items — labels/descriptions/option labels/option descriptions fully translated (≈240 newly hand-translated entries, reusing 78 coding-agent zh entries); only proper nouns (models/providers/voices/hardware/API-key names/numbers) stay in English, consistent with TUI; zh-CN.ts fully formatted via biome –write.

Companion (Agent Companion, BitFun parity, 2026-08-06)

5. i18n & sound effects

5b. Animation & library choices (evaluated 2026-08-07)

5c. Reference resources (design ↔ implementation mapping)

Resource Used for Notes
opencode (../opencode dev) Session tree/header/server instances/settings v2 shape Its three sound categories (agent/permissions/errors) were the blueprint for per-event sound configuration
openchamber (../openchamber v1.18.1) Three-column shell/settings layout/notification templates/remote instances (SSH+port forwarding) Primary reference for the settings page shape; message partial-selection float/save-as-image/new-session-from-answer (partial selection + save-image landed 2026-08-07; fork modal not done)
bitfun (../bitfun main) Companion (Petdex/frame animation/mood)/SSH remote workspaces/approvals Primary reference for desktop-pet visuals & interaction
clawd-on-desk (/tmp/clawd-on-desk, rullerzhou-afk, AGPL) Pet floater layout/permission bubbles/status indication Content-driven window design reference (analyzed 2026-08-11): fixed width + adaptive height (window width constant → no anchor clipping); bubble-stack placement priority below→side (whichever has room, right preferred)→corner; entry slides in from the pet’s side (translateX 60→0 spring). The “width first” idea (size stable before animating) landed as panel entry gating
kimi-code (../kimi-code) Icon card-in-card 80.5%/dot-matrix brand background/provider grid Dock visual alignment baseline
ZCode Connect wizard 4 steps (SSH/Docker) ConnectDialog step skeleton
../ui-references/aicss/ AI interface CSS recipes (thinking/code-block/comparison-table…) Message-stream detail comparison
../ui-references/cuelume/ border-beam/ thinking-orbs/ Sound/beams/thinking-orbs references Inspiration sources for self-built components
reactbits.dev (since 2026-08-07) Animation-component source reference Landed: CountUp/BlurText/ShinyText/SpotlightCard (all zero-dependency variants); candidate: glyph particle background (needs WebGL, not adopted)

5d. Design gaps & follow-ups (logged 2026-08-07)

Gap Current state Completion design draft Status
Plan-approval 3-option GUI support The GUI ApprovalCard only approves/denies (tool.approve/deny); the TUI has approve-and-run (new session) / approve-and-compact-context / approve-and-keep-context — those ride the xd://propose device flow → handlePlanApproval → in-process session.prompt, a TUI-only mechanism; the daemon’s approval-request payload carries only {requestId, tool} with no plan metadata, and the GUI has no matching RPC ① daemon approval-request attaches plan context for plan tools (planFilePath/title/planExists, mirroring the TUI propose dispatch shape); ② add an approve mode parameter (tool.approve extended with mode: "run"\|"compact"\|"keep"); ③ GUI ApprovalCard detects tool === plan and shows 3 options, defaulting to keep-context; ④ pet approval cards share the same source Logged, unscheduled
New-session-from-answer modal Fork exists (session.forkAt, non-destructive branching); openchamber uses a config modal (model/thinking level/agent/instructions/worktree/goal run) Lightweight modal reusing ModelSelector/ThinkingSelector, defaults = current session Logged, unscheduled (optional)
Aurora/Particles welcome background Not adopted (WebGL/persistent rAF violates CSS-first; DotMatrixMark is already the brand visual) If users want a “vibe change”, offer a CSS gradient-animation alternative or a toggle Alternative, not doing

5f. Design asset extension points (pluggable, finalized 2026-08-16)

Built-in design assets are organized around tokens + an override mechanism; third-party/theme/motion packs extend by overriding tokens, never by forking components.

Motion parameter table (gui.css :root)

Token Default Purpose How to override
--spring / --spring-snappy / --spring-bouncy spring(300,30)/(400,34)/(320,16) linear() All UI morph easings Inject CSS overriding the :root variables
--gui-motion-menu-in/out 130ms Float-layer menu enter/exit Same
--gui-motion-chip 180ms Chips/small elements Same
--gui-motion-fade-in/out 160ms Fades Same
--gui-motion-height / -max 240ms / 480ms Height morphs (HeightMorph, delta/6 capped) Same
--gui-motion-blur 280ms Blur-type effects (BlurText) Same
--gui-motion-roll 240ms Roll/page-flip type Same
--gui-motion-slide-y / -lg 6px / 10px Translation distances Same
--gui-motion-blur-amt / -lg 8px / 24px Blur amounts Same
--gui-ease-out cubic-bezier(0.22,1,0.36,1) Height/morph easing alias Same

Override mechanism: keyframes and transitions always read tokens (var(--gui-motion-*)); a motion pack/theme injects a stylesheet (later-loaded wins) overriding the variables for a whole-skin swap — no keyframe edits needed. gui-motion-off (prefers-reduced-motion) disables globally.

Component parameterization (customizable without forking)

Intake contract for new motion components

  1. Durations/offsets/blur amounts must read tokens; bare values forbidden (bare values = uncapturable by theme/motion packs).
  2. Enter animations go two-phase (useTwoPhaseEnter, or opacity:0 + next-frame --entered) to prevent Chromium skipping backdrop sampling.
  3. Respect gui-motion-off (disabled state appears directly, no animation).
  4. Reuse the gui-menu-in/out / gui-fade-in/out keyframes or build same-parameter ones (named gui-<name>-in/out).

5e. Dialogs, keyboard & selectors (finalized 2026-08-14)

Dialog animation & keyboard priority

Floating positioning standard (finalized 2026-08-25, benchmarked against openchamber v1.20.0)

Single-entry iron rule: all popup float layers (menus/dropdowns/context menus/color pickers/attachment menus) must route through components/Pop.tsxlib/use-floating-menu.tsx (the only implementation: portal to React root + global exclusivity + gui-menu-in/out animation). Hand-written position: fixed/absolute popup floats are forbidden — openchamber uses @base-ui/react (floating-ui popper engine internally); we hand-write the same semantics without the dependency:

Model selector (provider compound key)

Fetch available models (custom provider form)

Board canvas & group glow

Settings search & new project

5g. Recent landed features (2026-08-24 → 2026-08-26)

Design decisions and patterns for work landed after the early sections; implementation contracts and pitfalls in docs/gui-implementation.md §18, per-feature specs in the referenced docs.

5h. Absorption round additions (2026-08-29)

6. Brand icon (App Icon, redesigned 2026-08-06)