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.
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}Ferrum Dark
ferrum-darkWhat 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.
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}Ferrum Light
ferrum-lightWarm 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.
-
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.
-
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.
-
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.
-
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.