You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
With the Brain mounted as the Chat's full-bleed background (slice #59) and the AA-floored Glass tokens available (slice #60), the chat's content cards are still styled for a solid chat surface: user bubbles carry an opaque --surface-base fill and assistant prose has no background at all — over the living Brain they would tile the motion away or become illegible. See #56 for the "everything floats, legibly" why.
Approach
Apply slice #60's two Glass tiers to the real content cards: the standard tier on user bubbles, assistant prose, and the composer; the dense tier on code blocks, diffs, run-plots, and tool cards. Bare assistant prose gains its own standard card; muted/secondary text is routed off the ultra-transparent standard tier onto the dense tier (the prose meta on a dense-backed inline zone — slice #60's dense token, no new literal); timeline row frames and gutters stay transparent so the Brain shows in the gaps. Then re-validate that each real archetype's rendered text clears its tier's contrast floor over the running-brain reference frame in both chat themes — extending slice #60's synthetic contrast test onto a component→tier mapping.
Scope
In: the seven content archetypes get a data-glass tier (standard: user bubble, assistant prose, composer; dense: code block, diff, run-plot, tool card); the opaque bubble fill is replaced by the glass tint; assistant prose gets a standard card; muted text rides the dense tier (a dense-backed inline zone for the prose meta); row frames/gutters stay transparent; a component→tier contrast mapping is validated over the reference frame in both themes. Out: mounting the Brain / retiring the inline strip / one render loop (slice #59 owns the room; this slice only styles what floats on it); deriving tints/blur + the synthetic reference-frame validator (slice #60 owns the tokens + contrast helpers; this slice consumes them); motion / at-rest / data-true heartbeat (slice 4); the laptop-webview perf gate + motion-ease fallback (slice 5); Rail, titlebar, Panels, and the in-timeline sticky session-title header (nav/timeline chrome stays solid — not floating content); new geometry/accent tokens (the tier token already carries radius/border/shadow — no per-component literals).
Acceptance Criteria
Tier assignment: the user-message bubble, the assistant prose text-part, and the composer each carry data-glass="standard"; a markdown code block, a diff view, a run-plot/run-window, and a tool card each carry data-glass="dense". No third tier value and no data-glass on any non-content element are present.
Nothing bare, nothing opaque: every persistent readable region above (bubble, prose, code, diff, plot, tool, composer) resolves a Glass tint whose alpha is < 1 (translucent) — none is transparent (would be illegible over the Brain) and none is opaque (would tile the Brain away).
Gaps stay live: the timeline row frame (session-turn) and the centered column/gutter wrappers carry no glass background and resolve a transparent background — only leaf content cards float, so the Brain is visible between top-level cards.
Contrast over the reference frame (both chat themes): measured with slice Derive two AA-floored, chat-theme-keyed Glass tint tiers with a contrast test #60's validator against its worst-case running-brain reference frame — body text on a standard card clears ≥4.5:1 with the same safety margin; code/diff text on a dense card clears ≥4.5:1; graphical marks (syntax colors, diff fills, plot lines) on a dense card clear ≥3:1. The mapping is asserted per archetype, not eyeballed.
No muted text on standard: every muted/secondary-role text element (e.g. the copy/timestamp meta inside a prose card) sits in a dense-tier element or a dense-backed inline zone (slice Derive two AA-floored, chat-theme-keyed Glass tint tiers with a contrast test #60's dense token — never a new tint/literal); the mapping table rejects any (muted-role → standard) pairing.
No ad-hoc blur/tint literal: a source scan of the seven restyled cards' style-rules finds zero backdrop-filter/blur-radius/rgba-tint literals outside slice Derive two AA-floored, chat-theme-keyed Glass tint tiers with a contrast test #60's Glass token CSS — the scan is scoped to those card rules and explicitly excludes the in-timeline sticky session-title header's pre-existing chrome blur (out-of-scope chrome that stays), so styling the diff seam that lives alongside it does not require touching it; and the previous opaque --surface-base bubble fill is gone (replaced by the standard tint).
Chrome untouched: no data-glass appears on the Rail, titlebar, Panels, or the in-timeline sticky session-title header.
Testing Decisions
Extends slice Derive two AA-floored, chat-theme-keyed Glass tint tiers with a contrast test #60 test surface — component→tier contrast mapping (CREATE, alongside slice 2's glass-token contrast test): a table test over {archetype → (tier, text-role)} for the seven archetypes, asserting tierContrast(theme, tier, colorForRole(role)) ≥ floor(+margin) in both shipped chat themes using slice 2's exported contrast/tierContrast and the theme's real text tokens: body→standard ≥4.5:1+margin, code/diff→dense ≥4.5:1, marks→dense ≥3:1. The table also asserts no muted-role text maps to the standard tier — it rides dense / a dense-backed inline zone (guards the exact grey-on-glass failure the earlier build hit).
Tier-assignment DOM test (CREATE glass-float behavior test): render each archetype through the real message renderer / composer / tool / run-plot components and assert the correct data-glass value on the leaf card; assert the wrapping session-turn/column frame has no data-glass and a transparent resolved background (the "gaps stay live" + "nothing bare/opaque" criteria).
No-literal source guard (CREATE, static scan): scan the seven restyled cards' style-rules (not whole files) for backdrop-filter, blur radii, and rgba tint literals; assert zero outside the Glass token CSS; explicitly exclude the in-timeline sticky session-title header's pre-existing chrome blur (chrome that stays); and assert the user bubble no longer sets an opaque --surface-base fill.
Reuse existing component tests: extend the tool-card, run-card, and run-plot render tests to cover the new data-glass="dense" attribute rather than adding parallel harnesses; do not re-test the token derivation (that is slice 2's).
All tests are external-behavior (rendered attribute + computed style + slice-2 validator math) — none reach into engine internals or attempt live canvas/backdrop-filter pixel compositing (jsdom cannot composite backdrop-filter; the reference-frame floor stands in for "legible over the running brain").
Key Decisions
Tier map (the contract): standard = {user bubble, assistant prose, composer}; dense = {code block, diff, run-plot, tool card}. Composer is standard (a control surface holding body text), per the ADR grouping — the old branch's separate chrome tier collapses into standard.
data-glass attribute contract: values are standard | dense, defined and emitted by slice Derive two AA-floored, chat-theme-keyed Glass tint tiers with a contrast test #60; this slice only applies them and consumes the emitted CSS utility + validator. Applying an undefined tier value is a slice-2 change, never a local literal.
Assistant prose gains a card: assistant text-parts are bare (no background) today; they get a standard card so prose is legible over the Brain.
Nesting is conservative: a dense card nested in a standard card (code inside prose) keeps its dense tier; every tier's floor is derived over the bare worst-case Brain, and nesting only adds opacity, so contrast is guaranteed without per-nesting recomputation.
Muted/secondary text: rides the dense tier — the prose card's meta (copy/timestamp) is the concrete case, wrapped in a dense-backed inline zone (slice Derive two AA-floored, chat-theme-keyed Glass tint tiers with a contrast test #60's dense token, no new literal) so it never composites directly against the standard tint. This is the ADR's "locally-dimmed zone", realized without a third token.
Motion lives in the gaps, not thinner cards: cards stay at slice 2's derived tint; the visible Brain comes from the transparent row gaps/gutters — do not dilute a card's tint to "let more Brain through."
Do not define new glass tints, blur values, or geometry — consume slice Derive two AA-floored, chat-theme-keyed Glass tint tiers with a contrast test #60's two tokens verbatim (they already carry radius/border/shadow); a value the tokens lack is a slice-2 change, not a per-component literal. The dense-backed inline zone for muted text uses the existing dense token — not a new one.
The standard tier's tint alpha is bounded below by its contrast floor; never override it lower locally.
Row frames (session-turn), the centered column, and inter-card gutters must never receive a glass fill — that would tile and hide the Brain.
Rail, titlebar, Panels, and the in-timeline sticky session-title header stay as-is; no data-glass on them, and their existing chrome blur is left untouched.
Amicode design-system law holds for the card chrome: geometry from the tier token, single-yellow accent — yellow is never a card fill; #fff676 stays the Brain's live-thought color.
Prior Art / Patterns
Real seams to restyle (current branch): the message renderer `packages/ui/src/components/message-part.tsx` + `message-part.css` — user bubble `[data-slot="user-message-text"]` (currently `background: var(--surface-base)`), assistant `[data-component="text-part"]` / `[data-slot="text-part-body"]`, markdown code `[data-component="markdown-code"]` (`packages/ui/src/components/markdown.tsx` + `markdown.css`); the timeline `packages/app/src/pages/session/message-timeline.tsx` — `TimelineRowFrame` → `[data-component="session-turn"]`, diff group `session-turn-diffs-group` / `session-turn-diff-view` (note: this file also holds the sticky session-title header with a pre-existing `backdrop-blur` — that is out-of-scope chrome; do not touch it); the composer `packages/app/src/pages/session/composer/session-composer-region.tsx` — `[data-component="session-prompt-dock"]`; the tool card `packages/ui/src/components/basic-tool.tsx` — `[data-component="tool-trigger"]`; the run-plot `packages/ui/src/amicode/run-window.tsx` — `[data-component="amicode-run-window"]`; diffs `packages/ui/src/components/diff-changes.tsx`.
Old-branch raw material to reuse (design-neutral, slice #60 lands it, this slice consumes it): `opencode-brain-atmosphere-wt/packages/ui/src/amicode/glass.css` — the `[data-glass=...]` tier utilities, the `@supports not (backdrop-filter)` opaque fallback so text never lands on bare canvas, and `glass-tokens.ts`'s `contrast`/`tierContrast` validator functions; note its three tiers (airy/dense/chrome) collapse to slice 2's two (standard/dense) with the composer moving from `chrome` to `standard`. The mounted background is slice #59's `BrainAtmosphere` (old `brain/brain-atmosphere.tsx`), which paints on a transparent, `aria-hidden`, pointer-events-none ground beneath the cards.
Important
Problem
With the Brain mounted as the Chat's full-bleed background (slice #59) and the AA-floored Glass tokens available (slice #60), the chat's content cards are still styled for a solid chat surface: user bubbles carry an opaque
--surface-basefill and assistant prose has no background at all — over the living Brain they would tile the motion away or become illegible. See #56 for the "everything floats, legibly" why.Approach
Apply slice #60's two Glass tiers to the real content cards: the standard tier on user bubbles, assistant prose, and the composer; the dense tier on code blocks, diffs, run-plots, and tool cards. Bare assistant prose gains its own standard card; muted/secondary text is routed off the ultra-transparent standard tier onto the dense tier (the prose meta on a dense-backed inline zone — slice #60's dense token, no new literal); timeline row frames and gutters stay transparent so the Brain shows in the gaps. Then re-validate that each real archetype's rendered text clears its tier's contrast floor over the running-brain reference frame in both chat themes — extending slice #60's synthetic contrast test onto a component→tier mapping.
Scope
In: the seven content archetypes get a
data-glasstier (standard: user bubble, assistant prose, composer; dense: code block, diff, run-plot, tool card); the opaque bubble fill is replaced by the glass tint; assistant prose gets a standard card; muted text rides the dense tier (a dense-backed inline zone for the prose meta); row frames/gutters stay transparent; a component→tier contrast mapping is validated over the reference frame in both themes.Out: mounting the Brain / retiring the inline strip / one render loop (slice #59 owns the room; this slice only styles what floats on it); deriving tints/blur + the synthetic reference-frame validator (slice #60 owns the tokens +
contrasthelpers; this slice consumes them); motion / at-rest / data-true heartbeat (slice 4); the laptop-webview perf gate + motion-ease fallback (slice 5); Rail, titlebar, Panels, and the in-timeline sticky session-title header (nav/timeline chrome stays solid — not floating content); new geometry/accent tokens (the tier token already carries radius/border/shadow — no per-component literals).Acceptance Criteria
data-glass="standard"; a markdown code block, a diff view, a run-plot/run-window, and a tool card each carrydata-glass="dense". No third tier value and nodata-glasson any non-content element are present.session-turn) and the centered column/gutter wrappers carry no glass background and resolve a transparent background — only leaf content cards float, so the Brain is visible between top-level cards.backdrop-filter/blur-radius/rgba-tint literals outside slice Derive two AA-floored, chat-theme-keyed Glass tint tiers with a contrast test #60's Glass token CSS — the scan is scoped to those card rules and explicitly excludes the in-timeline sticky session-title header's pre-existing chrome blur (out-of-scope chrome that stays), so styling the diff seam that lives alongside it does not require touching it; and the previous opaque--surface-basebubble fill is gone (replaced by the standard tint).data-glassappears on the Rail, titlebar, Panels, or the in-timeline sticky session-title header.Testing Decisions
{archetype → (tier, text-role)}for the seven archetypes, assertingtierContrast(theme, tier, colorForRole(role)) ≥ floor(+margin)in both shipped chat themes using slice 2's exportedcontrast/tierContrastand the theme's real text tokens: body→standard ≥4.5:1+margin, code/diff→dense ≥4.5:1, marks→dense ≥3:1. The table also asserts no muted-role text maps to the standard tier — it rides dense / a dense-backed inline zone (guards the exact grey-on-glass failure the earlier build hit).glass-floatbehavior test): render each archetype through the real message renderer / composer / tool / run-plot components and assert the correctdata-glassvalue on the leaf card; assert the wrappingsession-turn/column frame has nodata-glassand a transparent resolved background (the "gaps stay live" + "nothing bare/opaque" criteria).backdrop-filter, blur radii, and rgba tint literals; assert zero outside the Glass token CSS; explicitly exclude the in-timeline sticky session-title header's pre-existing chrome blur (chrome that stays); and assert the user bubble no longer sets an opaque--surface-basefill.data-glass="dense"attribute rather than adding parallel harnesses; do not re-test the token derivation (that is slice 2's).Key Decisions
chrometier collapses into standard.data-glassattribute contract: values arestandard|dense, defined and emitted by slice Derive two AA-floored, chat-theme-keyed Glass tint tiers with a contrast test #60; this slice only applies them and consumes the emitted CSS utility + validator. Applying an undefined tier value is a slice-2 change, never a local literal.Constraints & Invariants
session-turn), the centered column, and inter-card gutters must never receive a glass fill — that would tile and hide the Brain.data-glasson them, and their existing chrome blur is left untouched.#fff676stays the Brain's live-thought color.Prior Art / Patterns
Real seams to restyle (current branch): the message renderer `packages/ui/src/components/message-part.tsx` + `message-part.css` — user bubble `[data-slot="user-message-text"]` (currently `background: var(--surface-base)`), assistant `[data-component="text-part"]` / `[data-slot="text-part-body"]`, markdown code `[data-component="markdown-code"]` (`packages/ui/src/components/markdown.tsx` + `markdown.css`); the timeline `packages/app/src/pages/session/message-timeline.tsx` — `TimelineRowFrame` → `[data-component="session-turn"]`, diff group `session-turn-diffs-group` / `session-turn-diff-view` (note: this file also holds the sticky session-title header with a pre-existing `backdrop-blur` — that is out-of-scope chrome; do not touch it); the composer `packages/app/src/pages/session/composer/session-composer-region.tsx` — `[data-component="session-prompt-dock"]`; the tool card `packages/ui/src/components/basic-tool.tsx` — `[data-component="tool-trigger"]`; the run-plot `packages/ui/src/amicode/run-window.tsx` — `[data-component="amicode-run-window"]`; diffs `packages/ui/src/components/diff-changes.tsx`. Old-branch raw material to reuse (design-neutral, slice #60 lands it, this slice consumes it): `opencode-brain-atmosphere-wt/packages/ui/src/amicode/glass.css` — the `[data-glass=...]` tier utilities, the `@supports not (backdrop-filter)` opaque fallback so text never lands on bare canvas, and `glass-tokens.ts`'s `contrast`/`tierContrast` validator functions; note its three tiers (airy/dense/chrome) collapse to slice 2's two (standard/dense) with the composer moving from `chrome` to `standard`. The mounted background is slice #59's `BrainAtmosphere` (old `brain/brain-atmosphere.tsx`), which paints on a transparent, `aria-hidden`, pointer-events-none ground beneath the cards.Source
packages/app/docs/adr/0002-brain-as-chat-background.md.