fix(ui): use runtime :root color vars in shimmer gradient - #434
Conversation
There was a problem hiding this comment.
Pull request overview
Fixes the chat Shimmer text gradient by replacing references to Tailwind v4 @theme inline variables (--color-*, not available as runtime custom properties) with coss-ui’s runtime :root/.dark CSS variables (--background, --muted-foreground), ensuring the background-image computes correctly in both themes.
Changes:
- Update
Shimmer’sbackgroundImageto usevar(--background)andvar(--muted-foreground)so the gradient no longer resolves tononeat computed-value time. - Add an inline comment documenting why
--color-*variables are not safe to use at runtime.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
ℹ️ The fix is correct and I verified the premise independently. One comment-accuracy nit inline, plus a stacking question below.
Reviewed changes — the single commit 8f7e4fb0, one file.
- Shimmer gradient reads the
:rootvars —packages/presentation/ui/src/chat/shimmer.tsxswapsvar(--color-background)/var(--color-muted-foreground)forvar(--background)/var(--muted-foreground)in the inlinestyle.backgroundImage, and adds a one-line trap comment.
I confirmed the premise rather than taking it on faith, by compiling Tailwind 4.3.3 through its compile() API against a minimal repro of coss-ui's @theme inline block. The A/B was decisive: with no candidates the alias is not emitted; with a bg-muted utility candidate it is still not emitted (the value is inlined); only an arbitrary-value candidate like [background:var(--color-muted)] forces it into :root. A var(--color-*) written inside a JS inline style string is never a scanned candidate, so nothing forced --color-background to be emitted — the declaration was invalid at computed-value time and background-image fell back to none.
Worth recording that the blast radius was larger than "rendered with no colors": because the component itself sets bg-clip-text text-transparent, a background-image of none leaves nothing to clip, so every in-progress label was fully invisible — tool.tsx:85, reasoning.tsx:92, activity-run.tsx:131,138, compaction-marker.tsx:42, terminal.tsx:46 all sit behind an isStreaming ? <Shimmer>x</Shimmer> : x ternary, so the text vanished while running and popped in on completion. Only the reduceMotion early-return branch was spared.
I also reproduced the sweep: var(--color- has no remaining non-vendor hits. The packages/vendor/coss-ui hits are correctly out of scope — --color-white / --color-zinc-* come from Tailwind's non-inline default @theme and are emitted normally, and skeleton.tsx:14's arbitrary value does force emission.
ℹ️ A standalone user-visible fix is gated behind an unmerged branch
The base is ruocheng/code-525, not master, and master still carries the broken string. Every streaming label in chat is invisible until this lands, so stacking it behind an unrelated agent-adapter branch delays a fix that has no dependency on that work.
Technical details
# Shimmer fix is stacked behind `ruocheng/code-525`
## Affected sites
- PR base ref — `ruocheng/code-525` (`a730f54f`), whose recent commits are opencode/MCP
agent-adapter work unrelated to the shimmer gradient.
- `packages/presentation/ui/src/chat/shimmer.tsx` on `origin/master` — still has
`var(--color-background)` / `var(--color-muted-foreground)`.
## Required outcome
- A conscious decision about whether this one-line fix should reach `master` on its own
schedule rather than inheriting the parent branch's merge timeline.
## Open questions for the human
- Does this change actually depend on anything in `ruocheng/code-525`? If not, retargeting
the base to `master` makes it mergeable immediately.
- If the stack is intentional (e.g. CODE-575 is scoped as a follow-up to CODE-525), no
action needed — this is purely a sequencing observation.Claude Opus | 𝕏
lucas77778
left a comment
There was a problem hiding this comment.
No blocking findings. Independently verified the Tailwind 4.3.3 behavior: @theme inline utilities inline var(--background) / var(--muted-foreground) and do not emit the corresponding --color-* runtime declarations for this JS inline-style usage. Also confirmed coss-ui defines both replacement variables in :root and .dark, and both renderer entries import the shared stylesheet.
Checked the complete one-commit diff, all Shimmer call sites, reduced-motion behavior, applicable repository/frontend guidance, and current CI results. git diff --check is clean and all required GitHub checks are green. The non-master base affects sequencing only; it does not introduce a correctness dependency in this change.
8f7e4fb to
612f5c6
Compare
There was a problem hiding this comment.
✅ No new issues found. The one finding from the previous review is fixed, and the gradient line itself is unchanged from the version I already verified.
Reviewed changes — the delta from 8f7e4fb0 to 612f5c66: a rebase onto a newer ruocheng/code-525 plus a reword of the trap comment. The backgroundImage string is byte-identical to the previously reviewed version.
- Trap comment now states the real invariant —
packages/presentation/ui/src/chat/shimmer.tsx:30-31replaces "--color-*are @theme-inline-only (no runtime custom properties)" with wording scoped to coss-ui's semantic@theme inlinealiases, naming the actual rule: Tailwind never scans a JS style string, so nothing forces those aliases onto:root. That distinguishes "not emitted here" from "never exists", which is what the old wording got wrong for Tailwind's non-inline default palette and for@theme inlinealiases referenced by a scanned candidate.
One note on reading this delta, since it will matter again if the branch is rebased: git diff-tree 8f7e4fb0 612f5c66 returns roughly ten files (codex MCP slug extraction, opencode config-read catch, command-echo gating, tool-search headers). All of it is ruocheng/code-525 drift absorbed by the rebase, not work authored on this branch — the merge-base diff is still the single shimmer.tsx file, and that is what I reviewed.
The sequencing observation from the previous review stands unchanged and needs no action here: the base is still ruocheng/code-525 and master still carries the broken string, so every in-progress chat label stays invisible until the parent branch merges. Whether that is worth retargeting is the author's call, not a defect in this diff.
Claude Opus | 𝕏
|
On sequencing: keeping the stack — the branch was cut on top of code-525's tree and the stack merges bottom-up, so this lands with its parents rather than retargeting master. |
612f5c6 to
bc57dbe
Compare
bc57dbe to
3ed2768
Compare
3ed2768 to
8463156
Compare
|
Your Claude subscription has hit its usage limit. It resets at 3:10am (UTC). Re-trigger Pullfrog after the reset, or add an Add repo secret → · Model settings → · Setup docs → · Ask in Discord →
|
8463156 to
ed14e0f
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.
Suppressed comments (1)
packages/presentation/ui/src/chat/shimmer.tsx:31
- The new comment’s rationale is a bit misleading: Tailwind does scan TS/TSX files for class tokens (via
@source), but--color-*here comes from@theme inlineand is a Tailwind theme token rather than a runtime:rootcustom property. Rewording will prevent future readers from assuming this is a content-scanning issue.
// coss-ui's semantic --color-* aliases are @theme inline and Tailwind never scans a JS
// style string, so they are not emitted to :root — read the underlying vars directly.
There was a problem hiding this comment.
The stated Tailwind premise does not hold for the exact version and source layout in this branch, so this cannot yet be treated as a verified bug fix.
Tailwind 4.3.3 runs its CSS-variable extractor across arbitrary source text, including ordinary TSX strings. The imported packages/presentation/ui/src/styles.css registers @source "./" relative to packages/presentation/ui/src, so the existing inline backgroundImage string is scanned. An exact-version compile using that source registration produced:
relevantCandidates:
--color-background
--color-muted-foreground
emitted:
colorBackground: true
colorMutedForeground: true
Those emitted aliases forward to the same --background / --muted-foreground variables introduced by this patch. The replacement is safe and more direct, but under the current build it is behaviorally equivalent; the new comment at shimmer.tsx:30-31 is factually incorrect, and it does not explain the reported background-image: none.
Required outcome: reword/remove the comment and PR claim, then either provide a clean failing build whose generated CSS actually lacks these aliases or identify and fix the real cause of the observed none value. If the intent is only to avoid depending on theme-alias emission, describe it as that cleanup rather than a demonstrated user-visible fix.
Non-blocking sequencing note: this standalone change is based on #431, which is currently open and conflicting with master; if it is meant to ship independently, it should be rebuilt directly on master.

Summary
The chat
Shimmergradient referencedvar(--color-background)/var(--color-muted-foreground)— Tailwind v4@theme inlinenames that never exist as runtime custom properties, so the wholebackground-imagewas invalid at computed-value time and the shimmer silently rendered with no colors in both themes. Switch to the:root/.darkvars coss-ui actually defines (--background,--muted-foreground), matching the existingcolor-mix(in oklab, var(--foreground) …)pattern inpackages/presentation/ui/src/styles.css.Swept
packages/presentation/ui,packages/client/workbench, and both app renderers for othervar(--color-*)usages — this was the only one.Closes CODE-575
Verification
dev:mockwebview, on a liveShimmer("Running a command" during the showcase's streaming playback): computedbackground-imageresolves to a white sweep over a muted-gray fill in light, and a near-black sweep over a lighter muted fill with thedarkclass toggled. Before the fix the computed value wasnone.pnpm format:check,pnpm lint,pnpm typecheckclean;vitest run2722 passed. The singlegit-mutations.test.tsfailure is the signing-machine environment (productiongit commitpath hits headless gpg pinentry) — the file passes 5/5 withGIT_CONFIG_GLOBAL=/dev/null.Checklist
pnpm check:ciandpnpm testboth pass (pluscargo fmt/clippy/testfor Rust changes)WIRE_PROTOCOL_VERSIONis bumped