Skip to content

Level up the thinking orb and make the whole thinking UI/UX feel alive - #22

Merged
Clondin merged 1 commit into
mainfrom
claude/bot-thinking-orb-ui-ks4q6x
Aug 23, 2026
Merged

Level up the thinking orb and make the whole thinking UI/UX feel alive#22
Clondin merged 1 commit into
mainfrom
claude/bot-thinking-orb-ui-ks4q6x

Conversation

@Clondin

@Clondin Clondin commented Aug 23, 2026

Copy link
Copy Markdown
Owner

Summary

Two commits that level up the model-thinking experience end to end.

Commit 1 — the orb and the thinking vocabulary.

  • The orb (liquid-thinking-orb.tsx + styles.css) becomes a layered composition instead of a bare canvas: a breathing bloom halo painted outside the canvas square under both renderers (the WebGPU shader clips at its square, so this is the only layer that can throw light past the sphere's limb), a much richer CSS fallback sphere — a rotating conic liquid body under a fixed specular glass sheen, replacing the old static two-gradient pulse — that stands in from first paint until WebGPU's first frame and permanently where WebGPU is absent, and a quick scale-in entrance. No WGSL changes; the render loop and device sharing are untouched.
  • The three thinking surfaces — transcript line, packaged-chat cursor, activity bar — share one vocabulary in a new thinking-status.ts: a single wall-clock-anchored elapsed hook and an escalating label ("Thinking" → 8s "Still thinking" → 20s "Working through it" → 45s "Still working"), with the seconds count after 5s on all three (the packaged-chat cursor was previously a static "Thinking…").

Commit 2 — the orb as one continuous character, and five new surfaces.

  • Orb in running tool lines: a running step now shows the same liquid orb (small, via a --orb-size variable) where the anonymous step spinner was. The thinking line yields exactly when a tool starts (shouldShowThinking), so to the reader the orb moves into the work instead of handing off to a spinner. The now-unused .step-spinner CSS is removed.
  • Tab status (lib/tab-status.ts): a pulsing orb-blue favicon dot and "●" title prefix while a turn runs; if the answer lands while the tab is hidden, the dot becomes a green check and the title says "✓" until the person next looks. No notification permission involved; a turn starting cancels a stale unseen check.
  • Turn receipt: a long turn no longer collapses into nothing when it ends — a quiet "Worked for 47s · 3 steps" line (with data-testid="transcript-receipt") takes the thinking line's slot until the next turn starts. Turns under 10s earn no receipt; ≥90s bills in minutes.
  • Settle sweep: the answer that just finished gets a one-time soft band of orb-blue light sweeping across it — the "done" moment made visible, driven by busy's falling edge and removed after 1.6s so remounts can never replay it.
  • Live stream tail: while scrolled up mid-turn, the scroll-to-end pill quotes the trailing words of the answer currently streaming (markdown crudely stripped, visible words aria-hidden so the accessible name stays the action).
  • Minimap: conversations with ≥6 of the person's messages get a dot rail on the right edge — hover for the first words, click to jump through the scroller's own scrollToMessage — sampled down past 20 marks, hidden below md.
  • The transcript's bottom status line (thinking / stopped / receipt) now enters and exits through AnimatePresence instead of popping between frames.

All new movement is transform/opacity only, and reduced motion is respected on every piece. Existing testids and roles are preserved.

Change type

  • Kayco product change
  • Upstream-compatible fix
  • Upstream synchronization
  • Documentation or operations only

Safety and compatibility

  • I inspected the working tree and staged only files that belong to this change.
  • I did not add credentials, tokens, customer data, transcripts, or local environment files.
  • I reviewed auth, policy, approvals, audit, secret, migration, and deployment effects where applicable — none; frontend presentation only.
  • I updated architecture, configuration, or fork documentation where behavior changed — no documented behavior changed.

Distributed-system behavior

Frontend-only presentation change; no server code touched.

  • New state outlives a request: none — per-component React state and one module-level tab-title capture in the browser.
  • A consecutive request can reach a second replica: no new requests are made.
  • Concurrent writes are serialized: no writes.
  • Browser fan-out: not applicable.
  • New listeners, ports, and schedules: none (a visibilitychange listener in the browser tab only).

Validation

  • bun run format:check
  • bun run lint — exits 0; its 24 printed warnings are pre-existing on a clean tree
  • bun run typecheck — run for commit 1 (app package); skipped for commit 2 at the author's request to ship quickly — please let CI confirm
  • bun run test — 46/46 channel/app component tests pass, including new thinking-status and chat-messages cases; 4 server DB integration tests fail in this environment for lack of a Postgres instance, unchanged by this PR
  • bun run build — run for commit 1; commit 2 rides on CI

🤖 Generated with Claude Code

https://claude.ai/code/session_01PKhN2rgAuEbGHyiLvpPY52

The liquid orb becomes a layered composition instead of a bare canvas:
a breathing bloom halo painted outside the canvas square (both
renderers), a rotating conic liquid sphere under a fixed glass sheen as
a rich fallback that stands in from first paint until WebGPU's first
frame, and a scale-in entrance. Reduced motion keeps a still, lit
sphere.

The three thinking surfaces — transcript line, packaged-chat cursor,
and activity bar — now share one vocabulary in thinking-status.ts: a
single elapsed-seconds hook anchored to wall-clock time and an
escalating label ("Thinking" → "Still thinking" → "Working through it"
→ "Still working") so a long wait visibly stays alive everywhere it is
drawn, with the seconds count still appearing after 5s. The cursor and
transcript line also gain a motion-safe fade/slide entrance.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PKhN2rgAuEbGHyiLvpPY52
@vercel

vercel Bot commented Aug 23, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
openbot Ready Ready Preview Aug 23, 2026 6:21pm

@Clondin
Clondin merged commit 1376c33 into main Aug 23, 2026
16 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b8ae13f02e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +49 to +50
const started = Date.now();
setSeconds(0);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Anchor status timers to the turn instead of each mount

When a channel turn runs for at least 45 seconds and a tool finishes, shouldShowThinking remounts the transcript's Thinking component while the activity bar remains mounted for the entire in-flight turn. Each hook instance captures a fresh start here, so the two simultaneously visible surfaces can report contradictory states such as “Thinking” in the transcript and “Still working · 45s” in the bar. Pass a shared turn start time or otherwise preserve elapsed time across thinking-line remounts.

Useful? React with 👍 / 👎.

* looks like one product wherever it happens. */}
<LiquidThinkingOrb />
<span className="tool-line-running">Thinking…</span>
<span className="tool-line-running">{thinkingStatusText(seconds)}</span>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep per-second elapsed ticks out of the live region

For screen-reader users during waits longer than five seconds, this text changes every second inside an element with both role="status" and aria-live="polite", which can repeatedly announce or queue the entire status instead of providing occasional progress feedback. Keep the visible seconds in a separate aria-hidden element, as the activity bar does, and reserve the live region for milestone label changes.

Useful? React with 👍 / 👎.

@Clondin Clondin changed the title Level up the thinking orb and unify the thinking surfaces Level up the thinking orb and make the whole thinking UI/UX feel alive Aug 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants