Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Apprentice — The Making Of


Looking for the perfect colorscheme is no doubt part of everyone's experience with text editors and IDEs. For the luckiest among us, that perfect colorscheme will be the one enabled by default or the one that everyone on the internet seems to use. For the less lucky, the quest can be long and eventually lead them to actually build their own "perfect" colorscheme.

As a budding vimmer, it did not take long for me to start looking around for a nice colorscheme. I started my journey with that huge colorscheme test page that crashed so many browsers for so many years. Then, noticing that it did not have every colorscheme, I turned to the scripts section of and spent too much time looking at too many screenshots and installing too many colorschemes… is where I eventually found a beauty called Sorcerer, by Jeet Sukumaran. It was love at first sight.

Except it was GUI-only and I used my shell a lot.

For a while, I tried a compromise: Sorcerer in GVim/Macvim and Torte in Vim but there were too many difference and I soon tried two famous plugins that purported to "adapt" GUI-only colorschemes to 256/88/16-colors terminals. Needless to say, the result was far from perfect but that new compromise was far more acceptable.

What must happen unsurprisingly happened: a hack here, another there… and, slowly but surely, my Sorcerer started to deviate from the original in lesser and lesser subtle ways. After a good year of usage, small tweaks and CSApprox-related annoyances I took it upon myself to consolidate all my changes into a "better" Sorcerer that would look the same in GVim/MacVim and in 256-colors terminals.

Step one: consolidation

One thing that I noticed very early — way before I started work on my own colorscheme — was that Sorcerer's author used many colors. As a graphic designer, I could very well understand how all those colors ended up in there but it certainly made maintenance harder than necessary… and it lacked organization. Sorcerer definitely had a "mood", which is what attracted me in the first place, but it did not have much internal consistency. That was where I had to start.


For starters, I needed to list all the colors used in the colorscheme so I naturally turned to Vim:

  1. put every color code on its own line

  2. delete every line that doesn't contain a color code

  3. get rid of the extraneous stuff

     :%norm! f D
  4. sort and keep only unique lines

     :%!sort | uniq

After that little dance I ended up with fifty five different color codes, which was way too much.


My bad experience with CSApprox and Foobar lead me to photoshop where I created a document with a dark background and added every color patch, one by one:


Next step was to group those colors by proximity, forming clusters that would hopefully make the whole job easier:


But all those clusters didn't do anything to reduce the number of colors. I had to find a "median" color for each cluster using Photoshop's sgfdjkghf filter and a bit of hand-tuning:


At that point the number of colors was down to thirty five, which was still too high for me so I went a little further and reduced those mini-palettes from three colors to only two.


Twenty five colors. Not bad.


So… it looks like I reached my first goal but what measures should I take to make those colors look good in a 256-colors terminal?

While it is certainly possible to change the xterm palette, not many people know about colorcoke or its underlying magic so it is generally safe to assume that your user's terminal will render color 108 as #87af87. From there, I took every single color of my reduced palette and painstakingly chose an xterm counterpart from this extremelly useful document.

The well know limitations of the xterm palette made me throw away a few colors that were not heavily used in the original colorscheme but I managed to make most of my initial palette fit in the xterm color space:


and, except for the greys, nicely fit into the traditional ANSI pattern which was quite a feat in and of itself:

MADE-UP NAME    HEX        RGB                   XTERM  ANSI
almost black    #1c1c1c    rgb(28, 28, 28)       234    0
darker grey     #262626    rgb(38, 38, 38)       235    background color
dark grey       #303030    rgb(48, 48, 48)       236    8
grey            #444444    rgb(68, 68, 68)       238    8
medium grey     #585858    rgb(88, 88, 88)       240    8
light grey      #6c6c6c    rgb(108, 108, 108)    242    7
lighter grey    #bcbcbc    rgb(188, 188, 188)    250    foreground color
white           #ffffff    rgb(255, 255, 255)    231    15
purple          #5f5f87    rgb(95, 95, 135)      60     5
light purple    #8787af    rgb(135, 135, 175)    103    13
green           #5f875f    rgb(95, 135, 95)      65     2
light green     #87af87    rgb(135, 175, 135)    108    10
aqua            #5f8787    rgb(95, 135, 135)     66     6
light aqua      #5fafaf    rgb(95, 175, 175)     73     14
blue            #5f87af    rgb(95, 135, 175)     67     4
light blue      #8fafd7    rgb(143, 175, 215)    110    12
red             #af5f5f    rgb(175, 95, 95)      131    1
orange          #ff8700    rgb(255, 135, 0)      208    9
ocre            #87875f    rgb(135, 135, 95)     101    3
yellow          #ffffaf    rgb(255, 255, 175)    229    11

Step 2: when the boring gets tough

Now comes the "boring" part…

"Boring" as in "I won't get to play with colors and be creative and all" but… that's text editing and I'm a Vimmer!

Substituting every original color with its new and improved self

So I started by realizing that I didn't keep a conversion table while zipping through the consolidation step. This meant that I had to go back to Photoshop and sample every original color if I wanted to finish the job. Dumb me…

000000 000000 000000 ffffff

Whatever. Once I had the table above, it was very easy to turn it into a list of substitution commands using a bunch of macros and substitutions:

:%norm! I%s/\(
:%norm! A/g
:%norm! $F s\)/
:%s/ /\\|/g

" result

and run them on my buffer:


I could certainly have used a single substitution but I firmly beieve that an intuitive, non-elegant method is almost always better than an elegant, hard-to-get-right-the-first-time one. But that's just me.

Fixing styling and sorting the whole mess in logical "blocks"

Then it was time to sort the highlight commands and "fix" the haphazard styling. There was not much of a pre-existing order in there but I didn't really have a precise idea either so I went with this mostly random process:

  • move to some line,
  • fix the gui attribute if needed,
  • bubble it up or down next to a related line,
  • add empty lines to separate "blocks",
  • rince,
  • repeat…

Adding the terminal/GUI logic


Globally make the code more coherent


Step 3: maintenance


Step 4: automatization




Copy link

RichardBronosky commented Mar 10, 2022

Your image file has moved to
Note: you can add images to gists by cloning it to your machine, making changes there, and pushing it back out. I have an example of this at

Copy link

romainl commented Mar 10, 2022

@RichardBronosky thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment