Skip to content

feat(dashboard): chat surface overhaul — drop bubbles, smart auto-scroll, per-message hover actions, batched streaming (v0.8.1) #241

Description

@subinium

Summary

The chat surface is the most-used view in CrowClaw and currently looks like a 2018 iMessage clone: 85%-max-width bubbles for both user and assistant, ALL-CAPS role tags above every message, no per-message actions, dumb auto-scroll that yanks users back to the bottom mid-read.

Modern agent dashboards (Claude Code preview, Cursor, Cline, LangSmith) render assistant content as full-width left-aligned blocks with subtle role indicators, and provide per-message actions on hover. This issue overhauls the chat surface to that standard.

Target milestone: v0.8.1 (Dashboard sweep).

Why this matters (no shortcut)

  • Bubbles waste 15% of horizontal space on every assistant message — code blocks and tables get cramped.
  • ALL-CAPS role-tag at 9px is visual noise that adds zero information once a user knows the layout.
  • The dumb auto-scroll is the single most-cited annoyance in dev-tool chat surfaces ("the page kept yanking me down while I was trying to read").
  • The shortcut is "rewrite CSS only". Don't take it — per-message actions (copy/retry/edit/branch) require state management and event plumbing, not just visual changes. Half-doing this is worse than not doing it.

Source / reference points

  • Cline's webview-ui/src/components/chat/ChatRow.tsx — full-width assistant blocks, hover-revealed action row.
  • Claude Code preview screenshots — left-margin avatar, no bubbles, message-level branch button.
  • LangSmith run viewer — hover shows copy/share/expand.

Scope

Files to change

File Change
packages/web/ui/src/views/chat-view.ts Remove .bubble class and 85% max-width on assistant messages. Assistant content renders full-width with a 24px left margin reserved for a subtle role indicator (small dot + name in muted text on hover). User messages stay right-aligned with a light surface background, no border. Remove the 9px ALL-CAPS role-tag entirely.
packages/web/ui/src/views/chat-view.ts Smart auto-scroll: replace unconditional _scrollToBottom() with an IntersectionObserver on a sentinel element near the bottom. Only auto-scroll if the sentinel is currently visible (user is reading the latest content). When user has scrolled up, show a floating "↓ N new" button that snaps to bottom on click.
packages/web/ui/src/views/chat-view.ts Per-message hover actions: each assistant message gets a hover-revealed row at the bottom with Copy, Retry, Branch from here. Each user message gets Copy, Edit. Edit replaces the message content with a textarea + Save/Cancel; Save deletes all subsequent messages and re-runs from that point (POST /api/sessions/:id/edit-from).
packages/web/ui/src/views/chat-view.ts Stream delta batching: accumulate onTextDelta chunks into a buffer flushed once per requestAnimationFrame. Today every chunk triggers a full Lit re-render.
packages/runtime-node/src/index.ts New endpoint POST /api/sessions/:id/edit-from { messageIndex, newContent } truncates session history at messageIndex, replaces the user message at that index with newContent, and re-runs from there. Returns the same shape as /message. Required for the Edit action to be functional, not cosmetic.

Visual changes (specifications)

  • Assistant message: full width, no bubble, no border, 16px vertical spacing between turns.
  • User message: right-aligned block with --surface-2 background, --radius-md border-radius, max-width 70%, no border.
  • Role indicator: 6px dot + name in --text-muted, only visible on hover or when the message is focused.
  • Per-message action row: 24px height, hidden by default, slides in on hover with 100ms opacity transition.

What must NOT change

Acceptance criteria

  • Assistant messages render full-width with no bubble. User messages stay right-aligned with subtle surface background.
  • Hovering an assistant message reveals Copy / Retry / Branch in an action row.
  • Hovering a user message reveals Copy / Edit. Clicking Edit puts the message into edit mode.
  • Editing a user message and saving truncates history correctly and re-runs from that point. Verified by sending message A, editing A → A', and confirming the next assistant turn reflects A'.
  • When a user has scrolled up by > 100px, the page does NOT snap to bottom on incoming stream chunks. A "↓ N new" button appears.
  • Streaming a response with 500+ chunks renders smoothly with one re-render per animation frame, not one per chunk. Measured: < 60 re-renders for a 5-second response on a 60Hz display.
  • No regression on send/abort/retry of the last assistant message.

Performance target

  • Stream delta batching: ≤ 60 Lit re-renders per second regardless of chunk arrival rate.
  • Smart auto-scroll: zero observable scroll yanks when the user is > 100px above the latest message.

Out of scope

  • Replacing the markdown engine (separate issue).
  • Inspector rail / consolidating floating toggles (separate issue).
  • Mobile chat layout (we will declare desktop-only).
  • Voice / audio messages.

Labels: enhancement, priority/critical, ux, polish, source/audit

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestpolishProfessional finish / accessibility / i18npriority/criticalCritical — fix before next releasesource/auditInternal audit findinguxUser experience / interaction design

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions