Skip to content

feat(ui): put Eval on the Redrob brand tokens - #20

Merged
cursor[bot] merged 3 commits into
mainfrom
cursor/eval-design-tokens-8171
Aug 31, 2026
Merged

cursor[bot] merged 3 commits into
mainfrom
cursor/eval-design-tokens-8171

Conversation

@its-janghoon

Copy link
Copy Markdown
Member

Eval now uses Console’s --rr-* primitives and semantic roles instead of a local palette.

What changed

  • apps/web/src/app/globals.css is three bands: 68 --rr-* primitives, Console semantic roles at Console’s exact light/dark values, then Eval’s existing names as aliases.
  • Local palette and dark twins are gone. --muted became --muted-foreground (name clash with Console’s surface). Teal --accent-* selected states map to brand blue.
  • Pretendard loads the same pinned variable subset the other products use.
  • scripts/test/design-tokens.test.mts fails if a primitive drifts from Console, a colour is hardcoded, or a dark twin comes back.

Labs is not in this PR. No Labs files were changed.

Proof (Kiro)

  • yarn typecheck exit 0
  • yarn lint exit 0
  • yarn test exit 0 (1000/1000)
  • yarn verify:theme exit 0
  • yarn build exit 0

Commits: f74fba5, 9811927, 841e414 on cursor/eval-design-tokens-8171.

Remaining risks

  • Dark --line on --panel is Console’s 1.18:1 join; recorded in CONSOLE_FLOOR rather than a lowered floor.
  • Three surfaces change look (sunken, hover, titlebar). Want an eye on the running app.
  • DeployTerminal getComputedStyle of var() inside a custom property was not exercised here.
Open in Web Open in Cursor 

cursoragent and others added 3 commits August 30, 2026 17:02
The palette was this app's own: Tailwind greys for the page and the lines, a
navy titlebar, a teal accent left over from when the primary button was teal,
and a second copy of every colour in the dark block. None of it was a brand
value, so the same screen in Eval and in Console were two shades of the same
idea.

The stylesheet now carries the same three bands Console does. The brand
primitives are transcribed verbatim from Console's `globals.css`, all sixty-eight
of them. On top of that sit Console's eighty semantic roles at Console's exact
values in both themes, plus the handful of roles Console has no equivalent of:
the titlebar and its inks, the terminal, the two ends of the run bar, a status
strip's edge, and a control boundary under the cursor. Each of those is built
from primitives only and commented where it is declared.

The four thousand three hundred lines of rules below are not rewritten. The
names they already spell are rebound as aliases onto the roles, one line each,
which is how the Office and Work ports did it: `--panel` is `var(--card)` and
`--line` is `var(--border)`, and the dark twins those names used to carry are
deleted, because the role each one points at is already re-pointed for dark.

Four names went instead of moving:

  --muted         was secondary text here and a surface in Console, and the two
                  cannot both hold the name. Renamed to `--muted-foreground`,
                  which is what it always was.
  --brand-solid   was `--brand` with the theme lifted off it, so that a white
                  label stayed readable. On dark the ink is Redrob Black now, so
                  the fill does not need to stay saturated and the two collapse.
  --brand-ink     was a third step of brand text between `--brand-deep` and the
                  fill. Under the brand scale it is `--brand-deep`.
  --accent-*      four teal tokens, every caller a selected state. A selected
                  state is brand blue.

Two smaller things fall out of it. The four literal copies of the Pretendard
stack and the eight of the monospace stack are gone: both are declared once, in
`@theme inline`, and named through `var()`. And the titlebar is one colour in
both themes rather than two navies, because the dark theme's requirement fixes
it: a bar darker than a Gray 9 page measures 1.19:1 against it, which is to say
it is not visible.

Not taken: the type size, leading and tracking scale. Its steps differ from the
ones in use at every level, so adopting it re-flows every screen at once, which
wants reviewing against the live layouts rather than arriving with a colour
change. Console and Office made the same call. Radius and spacing are unchanged.

`--line` on `--panel` is 1.18:1 in dark, under the 1.25:1 this repo asks of a
surface join. That is Console's value: the brand grayscale has three steps at
the dark end, the raised panel is a mix of two of them, and a Gray 8 border
drawn on it lands there. Recorded per pairing in `CONSOLE_FLOOR` rather than by
lowering the floor, so the exemption cannot quietly grow.

Co-authored-by: janghoonlee <janghoonlee@mckinleyrice.co>
Same CDN and same pin as before, but the full variable file rather than the
dynamic subset. The subset carries the whole weight axis and splits the face into
slices the browser fetches only when a page renders glyphs from them, which for
an English screen is Latin and some punctuation where the full file is mostly
Hangul it will never draw. Console, Office and Code all load the subset; this was
the one product on the full file.

The URL moves to a named constant, so the version is written in exactly one place
and `--font-sans` in `globals.css` names only the family it registers. The
`preconnect` matters more than usual here: the stylesheet and the slices it names
are two round trips to a third party before any text is in its real face.

Co-authored-by: janghoonlee <janghoonlee@mckinleyrice.co>
Two repositories cannot import from each other, so the palettes agree only for
as long as somebody checks. This file is the joint: every primitive and every
semantic role Console declares is transcribed here, and each test compares Eval's
copy against it. If either side changes a colour alone, it fails and names the
token.

Fourteen assertions, and the ones that earn their place:

  - every primitive at Console's value, and no primitive this app invented
  - no primitive re-pointed for a theme, because Blue 6 is Blue 6 in both
  - every role where Console points it, in light and in dark
  - the dark block re-points exactly the seventy-two roles Console re-points,
    plus the four roles Console does not have. A role missing from it would fall
    through to a light value on a dark page
  - no literal colour outside the primitive band, so a role is decided once
  - every local name a plain alias with no dark twin, which is the property that
    makes the band safe to keep
  - no rule and no component naming a primitive, so nothing reaches past the
    roles for a colour that cannot follow the theme
  - no hardcoded colour under `apps/web/src`, with one exception that has to
    prove itself: xterm paints to a canvas and cannot resolve `var()`, so
    `DeployTerminal` needs literals for the case where `getComputedStyle` returns
    nothing, and both are asserted equal to the primitives their tokens hold
  - Pretendard first in the stack, the stack written once, the version pinned once
  - the monospace stack named only by the eight code surfaces, listed, so adding
    a ninth is a decision somebody writes down
  - the reason the type scale was not taken, so a later change cannot take half
    of it without noticing

Checked by mutation: drifting a primitive, hardcoding a colour in a component and
reintroducing a dark twin each fail, and each fails in the test that should catch
it rather than somewhere downstream.

Co-authored-by: janghoonlee <janghoonlee@mckinleyrice.co>
@its-janghoon
its-janghoon marked this pull request as ready for review August 30, 2026 17:06
@cursor
cursor Bot merged commit d154073 into main Aug 31, 2026
7 checks passed
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