Case study / open source
Gogh
Color schemes for 19 terminal emulators, applied with one command. Started in 2013, now 1,250 themes from 177 contributors, with 10k+ stars.
The problem
Every terminal emulator keeps its colors somewhere different. GNOME Terminal reads them from dconf profiles, Alacritty and Kitty from config files, the Linux console from escape sequences. Changing a theme meant finding where your terminal hid its sixteen colors and typing them in by hand, once per machine and once per terminal.
Gogh started on November 18, 2013, inspired by the clean, minimal look of elementary OS: a way to try a color scheme in one step and keep it if you liked it.
One palette, many terminals
The whole project rests on one idea: a theme is data, and each terminal is an
adapter. A theme is a small YAML file with sixteen ANSI colors, plus the
background, foreground and cursor. apply-colors.sh works out which terminal
it is running in and calls that terminal's own apply_* function, which
writes the same palette in whatever shape that terminal expects.
Adding a terminal never touches the themes; adding a theme never touches the terminals. That split is why both lists could grow for more than a decade without the code growing with them.
# 1,250 palettes, 19 terminals, one command
❯ ~/gogh bash -c "$(curl -fsSL https://gogh.website/gogh)" -- "Dracula"
❯ ~/gogh ls
data/ installs/ themes/ tools/ apply-colors.sh gogh.sh README.md
❯ ~/gogh echo $TERMINAL && gogg
gnome-terminal
bash: gogg: command not found
❯ ~/gogh One file to contribute
Gogh's themes come from its community: 177 people have contributed so far.
So the path to contributing is a single file: drop a YAML file in themes/, open a pull
request, done. Contributors never touch an installer, a JSON file or a list
of names.
Pull requests are checked automatically: hex colors are uppercase, the file
name matches the theme's name, the variant is dark or light, the name
does not collide with an existing theme, and a theme pull request only
touches themes/. Foreground-to-background contrast below 2.5:1 is reported,
but it does not fail the check: contrast is a judgment call, not a fact like
a mismatched file name. And only newly added themes are checked, so an old
issue on a theme nobody is touching never blocks someone else's pull request.
Everything else is generated
Every push to master runs a ten-step pipeline (Python for the first nine,
Deno for the last) that builds everything from those YAML files: the theme
data as JSON, CSV and YAML, one install script per theme, the theme list
inside gogh.sh, and a WCAG contrast report for every palette. Nothing
generated is ever edited by hand, so nothing generated can drift from the
themes.
Tested where it runs
A color scheme that only works on my machine is not much use. Sixteen of the nineteen supported terminals have their own Docker test in the repository, so a change to one adapter can be checked in that terminal without installing it.
Data anyone can use
The themes are also published as plain static files (JSON, CSV and YAML) that need no API key and have no rate limit. Each palette carries a hash of its colors, so palettes can be compared and duplicates spotted across the whole collection. Other tools build on that data, including my own Omarchy × Gogh, which turns any Gogh palette into a full desktop theme.
What it taught me
- Make contributing a single file. Every step you remove from a contributor's path is one fewer reason to give up halfway.
- Generate, don't maintain. If a file can be built from another one, it should be, by a machine, every time.
- Separate gates from advice. Block only what is objectively wrong; report the rest. People keep contributing when the checks are fair.
- Keep the core boring. Bash and plain YAML are still the right tools after thirteen years, and that is a big part of why the project is still alive.