Ferrum
Sign in Create account

Two themes ship. The rest you already have.

Ferrum comes with a light and a dark theme built from one design, and reads any theme installed in Visual Studio Code. That second half is a translation rather than a copy, and it is the half worth explaining.

What ships

The same design in two appearances: identical roles, identical accent hue, inverted lightness. Not a dark theme and an unrelated light one.

budget.rs main.rs
 1/// What a frame is allowed to cost. 2pub struct Budget { 3    pub frame: Duration, 4    pub input: Duration, 5} 6 7impl Budget { 8    // 60 Hz, less the compositor’s slice. 9    pub fn interactive() -> Self {10        Self {11            frame: Duration::from_micros(16_667),12            input: Duration::from_millis(8),13        }14    }1516    pub fn met_by(&self, measured: Duration) -> bool {17        measured <= self.frame18    }19}
main Ln 17, Col 24

Ferrum Dark

ferrum-dark

What a window opens with. The accent is the orange unmodified — on a near-black canvas it clears its contrast floor without being moved at all.

budget.rs main.rs
 1/// What a frame is allowed to cost. 2pub struct Budget { 3    pub frame: Duration, 4    pub input: Duration, 5} 6 7impl Budget { 8    // 60 Hz, less the compositor’s slice. 9    pub fn interactive() -> Self {10        Self {11            frame: Duration::from_micros(16_667),12            input: Duration::from_millis(8),13        }14    }1516    pub fn met_by(&self, measured: Duration) -> bool {17        measured <= self.frame18    }19}
main Ln 17, Col 24

Ferrum Light

ferrum-light

Warm near-neutrals over a white code canvas. The accent is the same hue at a lower lightness, because the dark theme’s orange manages only 3.12:1 on white.

Themes are written in roles, not colours

A theme sets accent, and every active state moves at once — the current tab, the caret, the focus ring, the selected row. A theme that set a hex value called “violet” would move nothing predictable.

How a role is painted is a property of the role and not of the theme that binds it. A theme cannot declare warn a hairline and exempt itself from the check below, because it does not get to choose.

Every colour is measured before it ships

Text has to reach 4.5:1 against the canvas, the panel and the raised surface, and 3:1 against the selection. Anything carrying state — a focus ring, a strong border — has to reach 3:1 on all three. The two built-in themes are audited against those floors by a test, so a colour that slipped could not reach a release.

That is why several values sit just above their floor rather than on a round number. The accent is a different orange in each theme for exactly this reason: on near-black it clears 4.54:1 untouched, and on white the same orange manages 3.12:1, so the light theme uses the same hue and chroma at a lower lightness.

Bring the theme you already use

People arrive with a theme they like, and being told to re-author it in a format they have never seen is a good way to be told no. Ferrum reads the file that is already on the machine.

  1. It reads the file you already have

    Themes are found the way VS Code finds them: every extension directory under .vscode, .vscode-insiders, .vscode-oss and .vscodium is scanned, and each extension's package.json is read for the themes it contributes. They are listed under the label you already see in VS Code's own picker, so the name you know is the name that works. A theme installed twice is offered once, and one broken package among two hundred is skipped rather than failing the scan.

  2. What the file does not set is derived

    Some VS Code themes define two hundred keys and some define twenty. Everything absent is worked out from what is present rather than treated as an error: the surfaces step away from the editor background, muted and subtle text are mixed between the foreground and the background, and the accent is taken from the keys VS Code uses for chromatic emphasis — the button, the badge, the progress bar — never from the caret. Dracula's caret is near-white, which is a fine caret and a terrible accent.

  3. Translucent colours are composited, not dropped

    VS Code allows alpha and Ferrum's surfaces are opaque, which is a latency rule as much as a visual one. A selection background is usually a translucent wash, so anything carrying alpha is composited onto the surface beneath it at import. Discarding the alpha instead would render a 30% selection as a solid block.

  4. It tells you what it invented

    An import reports which roles it had to derive. The contrast audit runs too, and reports without refusing: a comment colour at 4.3:1 is advice for whoever authored the theme, and turning your theme away over one would be the editor deciding it knows better than you do about your own screen.

Choosing one

In the editor

The Theme setting in the settings dialog. The two built-ins are listed first — they are the ones that are certainly there and certainly work — and every theme found in Visual Studio Code follows, each marked light or dark so picking a light one at night is not a surprise.

On the command line

--theme takes a built-in name, the label of a theme installed in Visual Studio Code, or the path to a theme file.

ferrum-shell --theme Dracula
ferrum themes

ferrum themes lists what is installed. A name that matches nothing leaves the window as it was rather than falling back to a built-in, so a typo does not look like the theme having been applied and being ugly.