Why Alpenglow

Structure exists beneath the surface. Light makes it visible.

The name

Alpenglow is the light that stays on the mountains after the sun has gone. The valley is already dark; the high ground is still lit. The system is also named after my daughter Leonor — a name to which the sense of “light” is usually attributed — and its theme, Eleonora, for the same reason.

The first sentence is not decoration. It is the reason this system’s dark mode is built the way it is, and the rest of this page is that sentence unpacked.

Structure beneath the surface

Every clear interface rests on decisions nobody sees: which grey the text is, how far apart two controls sit, what a border is for, which of two surfaces is higher. Most systems make those decisions once and then describe them. This one measures them. Every ratio on this site is calculated from the tokens as the page renders, by the same function the test suite runs — the numbers in the gutter are the structure, brought to light.

The landscape below is how the layers relate. Each has a name from the terrain, and each maps to a file.

Clarity, layer by layer

Crestapp/Pathspatterns — none yetTerrainsrc/componentsContourstheme, elevationOutcropscale, typography, motionBedrockprimitives
Clarity, layer by layer.

Bedrock

Raw colour, with no meaning attached: primitives.ts. Nothing in a component references a primitive, and that is on purpose. A primitive does not change with the light, so a component that used one directly would be right in one mode and wrong in the other.

Outcrop

Bedrock that reaches the surface: spacing, radius, border width, type and motion, in scale.ts, typography.ts and motion.ts. A component uses these directly, without an alias, because 16px is 16px by day and by night.

Contours

The semantic roles — surface/raised, text/secondary, border/focus, elevation/md. A contour line does not alter the terrain; it joins every point at the same height. A role does the same: it joins every place in the interface that means the same thing, and every one is an alias with no value of its own. They are the keys of theme.ts and elevation.ts.

Light

Eleonora. The values the contours take under each mode — the light and dark columns of theme.ts and elevation.ts. In the drawing it is not a band but a direction, because light has a source.

Terrain

The components, in src/components. Every one is built from contours and outcrop and nothing else; the test suite reads each stylesheet to make sure.

Paths

Patterns: recommended ways through a task. None exists yet, so the line is dashed — the cartographic convention for ground not yet surveyed. Nothing in the code answers to it.

Crest

Any product built on the system. This site is the first: every page you are reading is laid out with the tokens and components it documents. In the code it is app/.

The rule

A value needs a contour only if the light changes it.

16px is 16px by day and by night, so spacing is outcrop and a component may use it directly. A grey is near-black by day and near-white by night, so colour is buried and reaches a component only through a role. That is the whole reason the token files are split as they are — and the reason the Figma primitives collection is hidden while the scale collection is published. The Figma split is the same rule in literal form.

Day, night, and the twilight between

Light and dark are not two themes. They are two modes of one theme: one theme.ts, every token carrying both values. Day is the light mode, night is the dark mode, and Eleonora is what the two share — the theme is what stays constant when the light changes. Alpenglow itself is a twilight phenomenon, morning and evening, which is why the theme lives at the intersection and not in either mode.

It is also the explanation for the decision that gets mistaken for a bug most often. In light, a card and a modal are both white and a shadow separates them. In dark, shadows stop reading as elevation, so the higher surface has to be the lighter colour step — because in the evening the valley darkens first and the crests stay lit. The numbers are on the Decisions page; the surfaces themselves are on Colour.

How to read a page

Every component page has the same shape, so what you learn on one carries to the next. It opens with the thing itself to try, then says when to choose it over its neighbours — a select over radios, a menu over a select, a dialog over a page. Then the anatomy with its drawn numbers, the states, the accessibility it carries, and the props. The foundation pages do the same for a token: how it is organised, how to choose one, and what is measured.

The margin on the right is the evidence. Every number there is calculated from the tokens as the page renders, by the function the test suite runs, so it cannot drift from the code without the build noticing. A grey box with a rule down its left is a decision that was rejected, or a gap that is kept on purpose, with the number that decided it — the part other systems leave out. The list on the left is the page’s sections, and the page before and after are at the foot.

The site is built from what it documents, and it holds itself to the same rules: a skip link and landmarks for a keyboard, every specimen reachable by Tab, both modes on the toggle in the sidebar, and no colour anywhere in its chrome that is not a token. If something here fails on your screen, it is a defect in the system, and the measurement that would have caught it belongs on the page.