Skip to content

fix(app): chat UI polish — persistent dot, rail alignment, cohesive segments, smooth scroll - #629

Draft
jeonghun-jj-lee wants to merge 3 commits into
mainfrom
fix/628-chat-ui-polish
Draft

fix(app): chat UI polish — persistent dot, rail alignment, cohesive segments, smooth scroll#629
jeonghun-jj-lee wants to merge 3 commits into
mainfrom
fix/628-chat-ui-polish

Conversation

@jeonghun-jj-lee

Copy link
Copy Markdown
Contributor

Closes #628

Summary

Implements the four chat UI polish improvements for a seamless messaging feel:

1. Cohesive text segmentation (chunk-boundaries.ts)

  • Settled text parts render as multiple bordered cards at natural boundaries
  • Label heuristic: short labels (<40 chars ending with :) stay with their content
  • List-to-list guard: consecutive list blocks never split
  • Heading coherence: a heading at the start of content stays with its body
  • Monotonic: boundaries only grow during streaming (never retract)
  • 22 tests covering all edge cases

2. Smooth scroll (smooth-scroll.ts)

  • Custom RAF-based 180ms ease-out replaces instant scrollToEnd()
  • Cancels immediately on user scroll gesture
  • prefers-reduced-motion falls back to instant
  • 6 tests with mocked RAF for deterministic verification

3. Persistent dot overlay (thought-rail.tsx)

  • Turn-spanning sticky overlay — the AmicoWave never remounts while running
  • CSS position: sticky; top: 12px keeps it visible during long streams
  • 250ms spring animation (cubic-bezier(0.34, 1.56, 0.64, 1)) on step transitions
  • Crossfade (150ms opacity) on turn completion; per-row done-dots appear underneath
  • Deterministic vertical offsets by group type (no TreeWalker): 6 tests

4. Rail alignment

  • md:pl-3 on TimelineRowFrame aligns the rail inside the composer's visible left boundary

Verification

  • 1713 tests pass (119 test files, 0 failures)
  • Extension build passes cleanly (esbuild)
  • All new modules transpile and export correctly
  • prefers-reduced-motion disables all animations (global rule + per-component)

Pure logic modules for #628 chat UI polish:

- chunk-boundaries.ts: markdown text segmentation with label heuristic
  (<40 chars + colon suppresses split), list-to-list guard, heading coherence
- smooth-scroll.ts: custom RAF-based 180ms ease-out scroller with cancel(),
  instant fallback for reduced-motion
- dot-offsets.ts: deterministic vertical centre by row group type
  (prose=21, tool-group=11, single-tool=16, thinking=11)

All three modules are DOM-free and fully tested (34 tests, 0 failures).
- ChunkedMarkdown: settled text renders as multiple bordered cards
  using chunkBoundaries (streaming stays single-block for stability)
- Smooth scroll: anchorResizedBottom uses 180ms ease-out RAF scroller;
  cancelled immediately on user scroll gesture
- Rail alignment: md:pl-3 on TimelineRowFrame pushes content inside
  the composer's visible left boundary
- ThoughtRailOverlay: persistent AmicoWave dot in a sticky container,
  spanning the active turn; 250ms spring animation on step transitions
- CSS: thought-rail spring bezier, crossfade on settle, reduced-motion
  fallbacks disable all animations
- Re-export AmicoWave from @opencode-ai/ui/amicode-thinking
@jeonghun-jj-lee jeonghun-jj-lee added enhancement New feature or request area:ui labels Aug 28, 2026
@coderabbitai

coderabbitai Bot commented Aug 28, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

- Rail renders inside session-turn's left padding (left: 12px),
  within the existing px-4/md:px-5 content area — no extra outer
  padding that would push content off the compositor alignment
- Dot anchor centres at 18px from top for prose rows (aligns with
  first text baseline), 8px for thinking rows (aligns with wave)
- Import AmicoWave in message-timeline for the live working dot
- Rail segment only visible at md+ breakpoints (hidden md:block)
- Verified: 1713 tests pass, build clean
@jeonghun-jj-lee

Copy link
Copy Markdown
Contributor Author

Fresh implementation on rebased branch

All changes are now committed to the opencode fork at local/amicode (commit 4e17c126a9):

What's in:

  • Label heuristic in message-part-text.ts — short labels (<40 chars + colon) stay with content
  • CSS empty-fragment safety net[data-prose-fragment]:empty { display: none }
  • Smooth scroll utility — 180ms ease-out RAF loop, cancels on gesture, reduced-motion fallback
  • Smooth scroll wired into virtualizer's scrollToFn (only for small anchor-to-bottom increments)
  • Rail alignmentmd:pl-3 on assistant row frames
  • Persistent overlay dot — turn-spanning sticky HarmonicDot, positioned from virtualizer measurements
  • Per-row done-dot only — running dot removed from ThoughtRail, fragment TreeWalker removed
  • 250ms spring transitioncubic-bezier(0.34, 1.56, 0.64, 1) on dot + rail line
  • Crossfade class for turn completion

Test results:

  • 15/15 chunk-boundary tests pass (session-ui)
  • 11/11 timeline tests pass (app: thought-rail + smooth-scroll)
  • Full binary build + smoke test passes
  • All 30 packages typecheck clean

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:ui enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(app): chat UI polish — persistent dot, rail alignment, cohesive segments, smooth scroll

1 participant