2026 03 06 Chat Ui Ux Overhaul Design
Documentation for Plans
Chat UI/UX Overhaul Design
Session: 182.1 Date: 2026-03-06 Branch: session-182 Scope: Tier 1 (broken/ugly fixes) + Tier 2 (premium elevation) + Tier 3 (polish) Constraint: Frontend-only. No backend changes.
1. Problem Statement
The chat UI has layout overflow bugs, inconsistent theming across components, and tool-use cards that dump raw JSON to users. The goal is to make every piece of the chat provide the absolute best UX — perfect layout, intelligent content display, beautiful interactions — across all deployment contexts (full-page, side panel, VSCode extension, Chrome extension, desktop app).
2. Root Cause Analysis: Layout Overflow
Three compounding issues cause content to clip on the left side of messages:
2.1 Missing flex constraint on lib-unified-chat in ai-panel-tabs
File: libs/libs-ai/ai-panel-core/src/lib/components/ai-panel-tabs/ai-panel-tabs.component.scss
.tab-content is a flex column container with explicit flex rules for lib-ai-panel, agent-observatory, etc. but NOT for lib-unified-chat. The chat shell's :host is display: block; height: 100%; width: 100% which doesn't properly constrain in a flex context.
Fix: Add lib-unified-chat { display: flex; flex: 1; min-height: 0; overflow: hidden; } to .tab-content.
2.2 Missing overflow-x: hidden on messages container
File: libs/libs-ai/vitto-chat/src/lib/components/chat-shell/chat-shell.component.scss
__messages has overflow-y: auto but no overflow-x: hidden. Long unbroken content (raw URLs in tool cards) inflates the scroll width. The user sees the RIGHT portion of an overflowed container — text clipped on the LEFT.
Fix: Add overflow-x: hidden to __messages.
2.3 min-width: 280px fighting narrow panels
File: Same as above.
__chat-area has min-width: 280px which can force it wider than its parent in narrow AI panels (320-400px).
Fix: Change to min-width: 0 (flex default). The container queries handle responsive behavior.
3. Architecture: New Component Map
All new components are standalone, reusable, and use --chat-* design tokens.
libs/libs-ai/vitto-chat/src/lib/components/
tool-renderers/
tool-renderer-host.component.ts # Dispatcher: toolName -> renderer
renderers/
browser-renderer.component.ts # browser_navigate, browser_screenshot, browser_interact
screen-capture-renderer.component.ts # capture_user_screen
shell-renderer.component.ts # run_command, execute_code
search-renderer.component.ts # recall_memory, search_decisions, query_docs, web_search
delegation-renderer.component.ts # create_handoff, check_handoff_status
default-renderer.component.ts # Smart fallback for all other tools
smart-output/
smart-value-display.component.ts # Parses any string -> rich display
json-tree-view.component.ts # Collapsible recursive JSON viewer
Integration Pattern
ToolUseCardComponent remains the outer shell (header bar with icon + name + status + duration + expand toggle). When expanded, it renders <lib-tool-renderer-host [toolCall]="toolCall()" /> instead of raw JSON. The host dispatches to the right renderer via @switch on tool name.
Reuse (not duplicate)
| Need | Existing Component | Action |
|---|---|---|
| Code/JSON display | UxCodeBlockComponent (PrismJS) |
Import, use with language='json' or 'bash' |
| Markdown | UxMarkdownComponent (marked v17) |
Import for text blocks |
| Image display | CuScreenshotCardComponent pattern |
Follow same base64 <img> pattern |
| Status badges | AlertBadgeComponent |
Reuse severity variants |
| Animations | flash-animations lib |
Import flashFadeAnimation, flashScaleAnimation |
Renderer-to-Tool Mapping
| Renderer | Tool Names | Parse Strategy |
|---|---|---|
| BrowserRenderer | browser_navigate, browser_screenshot, browser_interact | Parse navigation.url, navigation.title, navigation.statusCode, screenshot.success |
| ScreenCaptureRenderer | capture_user_screen | Parse currentPage, viewportSize, pageContext, visibleContent |
| ShellRenderer | run_command, execute_code | Parse command, exitCode, stdout, stderr, timedOut |
| SearchRenderer | recall_memory, search_decisions, recall_vitto_memory, query_docs, search_docs, web_search | Parse results[] with title/snippet/score, answer for web_search |
| DelegationRenderer | create_handoff, check_handoff_status | Parse status, assignedTo, summary, tasks[] |
| DefaultRenderer | Everything else | Parse JSON into key-value pairs with smart formatting |
Data Constraint
Tool output is truncated to 500 chars in ToolCallRecord. Base64 screenshots will be corrupted. Renderers must handle this gracefully — show "Screenshot captured" placeholder, never render partial base64.
4. Visual Design: Tool Renderers
4.1 ToolUseCard Refresh (outer shell)
- Migrate ALL CSS vars to
--chat-*tokens - Add entrance animation (
chat-scale-pop200ms) - Expand/collapse with spring easing transition
- Contextual subtitle line (URL, command, query) visible without expanding
- Status dot with colored glow
- Add
--chat-font-monotoken
4.2 BrowserRenderer
- URL as styled pill (clickable, truncated with ellipsis)
- Page title in secondary text
- HTTP status as colored badge (2xx green, 4xx amber, 5xx red)
- Screenshot: placeholder card "Screenshot available" (base64 truncated)
browser_interact: action type badge + selector in mono
4.3 ScreenCaptureRenderer
- Page title as breadcrumb pill
- Viewport dimensions badge
- Page context summarized (2 lines, "Show more" toggle)
- "Show extracted text" toggle for visible content
- Screenshot placeholder if available
4.4 ShellRenderer
- Command in mono font with
$prompt prefix (or language badge for execute_code) - Output in
UxCodeBlockComponentwithmaxHeight='120px' - Stderr in red-tinted code block if non-empty
- Exit code badge: green check for 0, red X for non-zero
- Timeout warning badge if
timedOut
4.5 SearchRenderer
- Result count badge at top
- Each result: bold title + relevance score pill (right-aligned, color-coded) + 2-line snippet
- AI summary at bottom for web_search (
answerfield) - Scores: >=0.9 green, >=0.7 blue, <0.7 muted
- Zero results: friendly message with query
4.6 DelegationRenderer
- Agent type as colored badge
- Summary in quote style
- Priority indicator
- Status with animated dot (pending=amber pulse, in_progress=blue pulse, completed=green, failed=red)
4.7 DefaultRenderer (smart fallback)
- Parse JSON into key-value rows
- Smart formatting: paths get mono+icon, URLs become links, success/error get badges, numbers get formatting
- Nested objects: collapsible via JsonTreeView
- "Show full response" toggle reveals raw JSON in UxCodeBlockComponent
- Never shows raw JSON by default
5. Visual Design: Message Actions
- Every button gets Material Symbols icon + label
- Icons:
content_copy,refresh,bolt,thumb_up,thumb_down,edit_note - Copy: checkmark + "Copied!" with 2s auto-revert
- Hover:
--chat-primary-subtlebg,scale(1.02)spring - Active:
scale(0.95)press - 0.4 opacity default, 1.0 on message hover (keep existing)
- Rate selected:
--chat-primarybg fill - "Escalate" -> "Run as Task" with bolt icon
- "Mark incorrect" -> "Correct" — shorter
- Flex-wrap for narrow containers
6. Visual Design: Task Progress Card
- ALL tokens ->
--chat-* - Status icons: Material Symbols (
check_circle,cancel,bolt) — no HTML entities - Phase badge: gradient
--chat-primary->--chat-accent - Progress bar: gradient fill by phase (ANALYZE=blue, PLAN=indigo, EXECUTE=purple, VERIFY=green)
- Checkpoint alerts:
--chat-warningtokens - Action buttons:
chat-icon-buttonmixin - Entrance:
chat-scale-pop300ms
7. Visual Design: Task Feedback Card
- ALL tokens ->
--chat-* - Thumb buttons: Material Symbols, selected with
--chat-primary-subtlebg - Textarea:
--chat-surfacebg,--chat-primaryfocus ring - Submit: matches send button style
- Thanks state:
--chat-success+chat-fade-in
8. Layout & Overflow Fixes
| Fix | File | Change |
|---|---|---|
Add flex rule for lib-unified-chat |
ai-panel-tabs.component.scss |
lib-unified-chat { display: flex; flex: 1; min-height: 0; overflow: hidden; } |
Add overflow-x: hidden to messages |
chat-shell.component.scss |
__messages { overflow-x: hidden; } |
Remove min-width: 280px from chat-area |
chat-shell.component.scss |
Change to min-width: 0 |
Add overflow: hidden to tools container |
unified-message.component.scss |
__tools { max-width: 100%; overflow: hidden; } |
| Fix connectivity panel width on narrow | chat-shell.component.scss |
Container query for width < 360px |
| Ambient bar z-index | ambient-bar.component.ts |
999999 -> 50 |
| Ambient bar safe-area | ambient-bar.component.ts |
max(10px, env(safe-area-inset-left)) |
| Ambient bar word-break | ambient-bar.component.ts |
.ambient__msg { word-break: break-word; } |
9. Polish: Sidebar, Input, Welcome
Sidebar Session List Items
- Active: left border accent (2px
--chat-primary), elevated bg - Hover: bg shift + border-left at 30% opacity
- Preview: single line truncated, secondary color
- Delete: subtle X on hover
Input Bar
- Resize handle: 3-dot grip visual on hover (fade in 200ms)
- File drop zone: dashed border + "Drop files here" on drag-over
- Toolbar icons: consistent 20px Material Symbols
Welcome/Empty State
- Vitto icon centered with breathing animation
- "What can I help you with?" heading
- 3-4 clickable suggestion chips
- Fade in on creation, fade out on first message
10. New Design Tokens
// Mono font
--chat-font-mono: 'JetBrains Mono', 'Fira Code', ui-monospace, monospace;
// Z-index scale
--chat-z-sidebar: 30;
--chat-z-tab-panel: 25;
--chat-z-sidebar-backdrop: 29;
--chat-z-dropdown: 50;
--chat-z-ambient: 50;
--chat-z-modal: 100;
// Score colors (for search renderers)
--chat-score-high: var(--chat-success);
--chat-score-medium: var(--chat-primary);
--chat-score-low: var(--chat-text-muted);
11. Scope Summary
| Area | Count | Type |
|---|---|---|
| Tool renderer system | 9 new components | New |
| Tool use card | 1 | Refactor (tokens + renderer integration) |
| Task progress card | 1 | Refactor (tokens + icons) |
| Task feedback card | 1 | Refactor (tokens) |
| Message actions | 1 | Refactor (icons + animations) |
| Chat shell | 1 | Fix (overflow) |
| AI panel tabs | 1 | Fix (flex constraint) |
| Ambient bar | 1 | Fix (z-index, safe-area, word-break) |
| Unified message | 1 | Fix (tools overflow) |
| Session list item | 1 | Polish |
| Input bar | 1 | Polish |
| Welcome message | 1 | Polish |
| Design tokens | 1 | Foundation |
| Total | 22 component touches |
All standalone. All reusable. All --chat-* tokens. All container-query responsive.