Skip to main content
GAIA looks like one product in a desktop window and a terminal. This page pins the colour roles both implement, the values behind them, and the contrast each surface is tested against. The website shares their roles, floors and status hues but wears AMD’s brand palette instead of the copper; see The website. This page is the source of truth for website/src/design/tokens.css, the Agent UI’s CSS custom properties, and tui/internal/ui/theme/theme.go. Implements milestone 0 of the UI redesign plan proposed in amd/gaia#3803.

Roles, not numbers

A surface asks for a role — canvas, primary text, accent — and never for a hex literal. That is what keeps a value tuned against one background from going unreadable on another, and it is why every surface routes colour through tokens rather than inline hexes. Most of the screen is neutral. Colour marks the prompt, focus, selection, the one primary action — and, in rendered markdown, headings and inline code. Nothing else; ordinary prose stays uncoloured. Headings and code spans are structure, not emphasis. A reader scans for them rather than reading them, there are few per screen, and the accent is what makes them findable at a glance. Emphasis inside a sentence is the opposite: accent on every bold word turns running prose into the speckle the palette reserves for the prompt and the one primary action. That is why the TUI’s markdown renderer paints strong in primary text and leaves the accent to the two structural marks (tui/internal/ui/components/markdown_style.go).

The terminal has no canvas, and its status band is not the raised surface

The first two rows are the Agent UI’s grounds (its light theme substitutes white; see Surface mappings). A terminal’s background belongs to the user’s emulator, so the TUI sets none — it paints foregrounds onto whatever the reader already chose. The status band is the one place the TUI fills a background, and it uses its own pair (#C2B8A8 light, #615D69 dark) rather than the raised surface above. The raised-surface values would vanish there: pale stone measures 1.25:1 on a white terminal and warm slate 1.32:1 on a black one, both under the 1.5:1 chrome floor a band has to clear to be seen at all. Those two values are cards on a canvas GAIA controls; the band sits on a background it does not. What carries across is the cast — warm stone on light, violet graphite on dark — not the literal. See SurfaceBG in tui/internal/ui/theme/theme.go.

Why copper is two different values, and one of them is not the obvious one

The dark copper #EBA474 is the identity colour. The light value is not a simple darkening of it, because the light accent has to survive a constraint the dark one does not. macOS Terminal is 256-colour only, so every value is rounded to the nearest of 256 fixed indices before it reaches the screen. Among the colours dark enough to hold 4.5:1 on every light terminal background the TUI measures — pure white through Solarized Light #FDF6E3 — that cube offers exactly one saturated warm entry: #875F00, and #875F00 is already where Warning and Selected land. A light copper that rounds there stops being a distinct colour and silently becomes the warning colour. The qualifier is load-bearing. Against pure white alone the cube offers two: #AF5F00 reads 4.71:1 there and 4.51:1 on One Half Light, then drops to 4.37:1 on Solarized Light. Judging the palette against white only is how a value that fails on a real terminal passes review. #9A4930 is the most saturated light copper that rounds to #875F5F instead: a warm near-neutral. On a 256-colour light terminal GAIA’s accent therefore reads as a dark warm grey rather than copper. That is the documented, intended degradation — the palette’s rule is that a colour may fade toward neutral, but may never land on a different saturated meaning. Truecolor terminals and the Agent UI render #9A4930 as copper. Using the same #9A4930 in the Agent UI as in the terminal is deliberate: the surfaces previously carried three near-but-unequal golds, and one shared literal is what makes “the same assistant” true rather than approximate.

The website

amd-gaia.ai is where people decide whether to install GAIA, not where they work with it, so it carries AMD’s brand rather than the assistant’s working palette. It is dark-only: black ground, white type, AMD red as the single accent, and AMD orange for release candidates and nothing else. AMD red #ED1C24 measures 4.01:1 on the raised surfaces, below the 4.5:1 text floor, so it is held to the 3:1 large-text floor and used only at display size. Text-size red is lifted to #FF4B51 instead. The filled button is deepened to #D3121A, which carries white at 5.42:1; the brand red itself carries white at only 4.38:1. Red is the brand here, not a status. That does not break “a hue that carries a status meaning is not available for decoration”: the site shows no status outside a code panel, and inside one, danger keeps its own #F2787C, a distinctly pinker red than the brand. What still matches the other two surfaces: the roles and their floors, and the status hues inside a code panel (cross-surface.test.ts holds green, amber and danger equal to the Agent UI’s). What does not: the accent, the grounds, and the typography — Antonio, a tall condensed face, for headings, buttons and figures, and Titillium Web for body text (it stands in for Klavika, AMD’s licensed face). The AMD logo is never drawn, imitated or used as a pattern; “AMD” appears as text. Motion is allowed on the website, within limits. The site has one ambient layer: a canvas of stars streaking past, which arrives at speed, settles to a cruise, and speeds up as the visitor scrolls. On top of it go entrance and scroll reveals, a headline that resolves out of noise once on load, a red glow on the primary action and on the hero’s red phrase, and a breathing dot on the release-candidate line. Nothing else moves. Every one of these stops under prefers-reduced-motion, which gets a single static frame, and the footer carries a control that pauses the background and the dot for good. Below the hero the field dims, so body text never sits on a full-strength streak. The “no glow” and “no simulated typing” rules below still govern the Agent UI and the TUI.

Semantic colours keep their conventional hues

The brand motif moves off green; status does not. Success stays green, warning amber, danger red, information blue. A terminal that paints a failed check in copper to stay on-brand is a worse terminal. The plan’s “no green motif” governs the accent, mascot, and brand marks — not whether a passing check looks like a passing check. Status must never depend on colour alone. Every state carries a word or an icon as well, so the palette degrading to neutral on a limited terminal costs polish, never meaning. The reservation runs the other way too: a hue that carries a status meaning is not available for decoration. Green, amber, red, and blue are spoken for, which leaves no palette to give each tool or file type its own colour — so those stay neutral and are told apart by their icon. The alternative is a green badge beside a red failure icon in the same row. One recognised exception: a link stays blue. That convention is older than this palette and readers arrive already knowing it, so the blue is carrying meaning rather than decorating — which is why the TUI’s markdown links resolve to the information role rather than to neutral text.

Contrast floors

Each surface enforces these in its own test suite; the floors are the same everywhere so a role cannot be legible in the browser and marginal in the terminal. Measured minimums for the roles above, against their own canvas and raised surface: 6.62:1 dark, 4.97:1 light. Accent-as-fill carries white at 6.23:1. The TUI additionally re-checks every floor against ten real terminal backgrounds and against the ANSI-256 value that actually lands, because a colour that clears its floor in truecolor can drop below it once rounded. See tui/internal/ui/theme/contrast_test.go.

Surface mappings

The Agent UI’s light theme is neutral, not porcelain. Its light canvas is white (#FFFFFF) with faintly cool greys for raised surfaces, rules and hover, because the warm stone read as brown in a full-window app. The accent, the accent fill and every status hue are the shared values above, and the dark theme is the shared graphite. contrast.test.ts holds the Agent UI’s values to the same floors.

Rules for adding a colour

  1. Add a role, not a literal. A new hex in a component file is a colour nothing can police, and every surface has a test that catches it — website/src/design/literals.test.ts, src/gaia/apps/webui/src/styles/__tests__/contrast.test.ts, and tui/internal/ui/theme/literals_test.go. Each sweeps its own tree and keeps a short allowlist where every entry says why a role cannot carry it.
  2. Declare what it owes the reader. The TUI will not compile past its tests without a contrast floor and a hue family for the new token.
  3. Check the degraded value, not just the one you typed. Truecolor contrast is not evidence; the TUI test measures what a 256-colour terminal shows.
  4. Never let two roles share a hue family. That is how “selected” and “warning” become the same thing on a user’s machine but not on yours.

Typography and spacing

Shared starting points, not pixel-matched measurements:
  • Body text 15–16px, readable proportional type for prose on the website.
  • System monospace for composer input, the > prompt, labels, and activity lines. The terminal follows the user’s own font — never force size, truecolor, or background.
  • Roughly 760px readable content width; a 240–260px collapsible sidebar.
  • Restrained rounding, subtle borders, generous spacing. No glow, no gradient-filled panels.
  • No simulated typing. A blinking cursor means output is still streaming — it is a status indicator, never decoration, and never runs when nothing is being written.
  • Light, dark, and system appearance in the Agent UI (the website is dark-only); motion that honours prefers-reduced-motion; visible keyboard focus at every interactive element.
Two gaps stand between those rules and what ships today. “No glow” is enforced by a test in the app (styles/__tests__/contrast.test.ts), and “no gradient-filled panels” by a test on both web surfaces (that file, and design/literals.test.ts on the site); the rest are held by review. Where each gap is scheduled in the redesign plan:
  • outline: none appears in most component stylesheets. Most sit on a :focus rule that draws a border or ring in its place, but the pairing is unverified and nothing fails when it is missing. Milestone 3 covers keyboard behaviour.
  • “A hue that carries a status meaning is not available for decoration” is enforced for red only. Extending it to amber, green, blue, cyan and purple surfaces 84 rules that wear a status hue for decoration — a switch whose on state is the information blue, memory categories each given their own colour, links tinted green — so closing it is a repaint across 18 stylesheets, not a test change. Milestone 3 for the task surfaces, Milestone 4 for Settings and the document and memory panels.
The mobile design system remains the responsive baseline, including its 768px boundary and 44px touch targets.