A warm, earthy VS Code theme in dark and light — built to sit comfortably behind mononoki, and tuned on TypeScript and Vue.
Most dark themes are lit by a blue-grey moon. Ubik is lit by a low fire: umber grounds, clay and ochre accents, moss and sage for the things you read most. It is soft without being murky — every syntax colour clears 4.5:1 against its background (comments and punctuation, which are meant to recede, clear 3.5:1), so long sessions don't cost you your eyes.
Mononoki is a warm, slightly hand-cut typeface with real italics. Ubik leans on that:
italics are used sparingly and deliberately — comments, this, decorators, Vue
directives, export/import — never as decoration.
From the Marketplace: search Ubik in the Extensions view.
Or locally:
git clone https://github.com/MatteoGabriele/ubik.git ~/.vscode/extensions/ubikThen ⌘K ⌘T → Ubik Dark or Ubik Light.
Get the font with brew install --cask font-mononoki-nerd-font, or from
madmalik/mononoki.
| Role | Dark | Light |
|---|---|---|
| Background | #181410 |
#FBF3E3 |
| Foreground | #E6DACA |
#3B3227 |
| Comment | #8B7B6A |
#7D7059 |
| Keyword · tag — clay | #F15B22 |
#D22E00 |
| Function · directive — ochre | #FFB700 |
#956600 |
| String — moss | #92CC36 |
#3F7D00 |
| Type · component — sage | #00DFC1 |
#007C6D |
| Constant · number — plum | #E473D9 |
#C000B8 |
| Property · key — stone | #A9B4D6 |
#45486B |
| Error — rust | #FF473A |
#DE0020 |
Accents run at CIELAB chroma 52–83 in the dark variant and 33–93 in the light one —
at or near the highest saturation sRGB can express at each hue while still clearing the
contrast floor. The light ground is a warm cream rather than paper-white: pulling the
field off #FFF takes the glare out and lets the accents read louder against it.
Neutrals stay deliberately quiet (foreground and comments carry almost no chroma) so
the accents do all the work. No two accent hues sit closer than 33°. stone is the one
low-chroma colour: properties sit in the same lightness band as the foreground but at
the opposite temperature, so payload.pull_request?.author_association shows where the
variable ends and the object walk begins without another accent entering the picture.
On a light ground, yellow and teal are gamut-capped: ochre and sage are already at
the sRGB ceiling for their hue at readable contrast, so they cannot be pushed further
without dropping below AA. That is a property of the colour space, not a style choice.
Roles are consistent across languages: a type is sage whether it's a TS interface, a Vue
component tag, or a generic parameter. A Vue directive (v-if, :prop, @click) reads as
ochre italic so template logic separates from plain attributes at a glance.
Both themes are generated from one palette so dark and light can never drift apart.
npm run build # palettes.mjs → themes/*.json, plus the icon
npm run check # WCAG contrast audit of every syntax colour
node scripts/preview.mjs # rebuild preview/preview.htmlEdit scripts/palettes.mjs for colour, and
scripts/build.mjs for which scope gets which colour. Never edit
themes/*.json by hand — it's generated.
npm run check fails the build on any colour that drops below its contrast floor.
MIT © Matteo Gabriele

{ "workbench.colorTheme": "Ubik Dark", "editor.fontFamily": "mononoki, Menlo, monospace", "editor.fontSize": 14, "editor.lineHeight": 1.7, "editor.letterSpacing": 0.3, // Ubik ships semantic colours for TS/Vue — leave this on. "editor.semanticHighlighting.enabled": true, "editor.bracketPairColorization.enabled": true, "terminal.integrated.fontFamily": "mononoki" }