Building Elementar 2 as a variable font

06 May 2021

An account of how Elementar was implemented as a variable font, highlighting the major roadblocks in the process, and the solutions employed to overcome them.

Initial considerations about variable fonts

1. Variable fonts allow the user to dynamically interpolate instances at any location inside a predefined designspace. The variable font is built from multiple compatible masters.

2. The variable font format provides a mechanism to introduce local discontinuities in the designspace. This allows one glyph to be substituted by another depending on the current location, similar to a train changing tracks. The typical example is the dollar glyph, in which two vertical bars can become a single one in heavier weights.

3. Variable fonts are now widely supported in APIs and interfaces. For example, variable font parameters can be specified in CSS using the font-variation-settings rule, and in DrawBot using the fontVariations() command. Various design applications and testing tools offer an interface to control variable font parameters with sliders and/or nummerical input.

Fitting Elementar into the variable font format

Elementar 2 uses the variable font format in a very particular way:

A. The bitmap-based letter shapes are discontinuous and incompatible between the masters, so glyph interpolation (1) is bypassed almost entirely – it is used only to control the size and proportion of the elements.

B. The variations are produced by (ab)using the glyph substitution mechanism (2), which is employed to switch the entire glyph set at every new master location in the designspace. Since masters are required to be fully compatible, this means that every master must contain all glyphs from all other masters. This is the main bottleneck in the font generation process, causing execution time to increase exponentially as more glyphs and masters are added.

C. The variable font format is used mainly as a delivery and selection mechanism for discontinuous masters, taking advantage of the native integration of the variable font format in modern APIs and interfaces (3). The element width and element height axes are the only ‘true’ variable axes in the conventional sense, employing interpolation instead of glyph substitution.

First prototype (October 2020)

The first prototype of ‘Elementar Variable’ was built as a weekend experiment. I had already converted some of my other typefaces into variable fonts, and was curious to see if Elementar could be bent into that format too.

At this stage I was generating variable fonts with the approach described in the RoboFont documentation, using the Batch extension. I was able to build a small test font containing just a few glyphs and a subset of all axes (height, width and element size). I also built a test page in HTML/CSS/JS to preview the variable font interactively using sliders. I was pleasantly surprised with the performance of the variable font, in comparison to the previous implementation in which each style was a separate static font. Using a variable font also made building the interface a lot easier.

Having proven to myself that it could be done, and having more important things to work on at the time, I put the project on hold until I could pick it up again in March 2021.

Adding more axes and glyphs

With variable font generation and proofing automated, I started adding the remaining axes (vertical stroke and horizontal stroke, style) and more glyphs. This caused the number of glyphs in each master to increase very quickly, and font generation became too slow to work with – something in the order of over an hour for a font containing only the lowercase glyphs (a-z).1 It was clear that this approach would not scale to a complete font, and I began to look into ways to make variable font generation faster.

Optimising variable font generation

Between the UFO design sources and the compiled variable font is a series of preparation steps to mold the font data into the required format. At the end of the font generation pipeline is fontTools.varLib, which takes a .designspace file and a set of TTF masters with strict compatibility. The Batch extension takes care of the intermediate font preparation steps:

  • adding off-curve points to straight segments to make master glyphs compatible
  • decomposing mixed glyphs (glyphs with both contours and components)
  • converting cubic contours to quadratic
  • make kerning compatible between masters
  • generating TTF masters from UFO sources

The Batch extension can also be used without the interface by calling the variable font generator directly with Python:

from variableFontGenerator import BatchDesignSpaceProcessor
p = BatchDesignSpaceProcessor()
p.read('myfont.designspace')
p.generateVariationFont('myfont.ttf')

At this point I had already plugged this function into my custom tools, adding some extra steps to reduce the glyph set of the UFO sources, build the .designspace file automatically, etc. I had to take a step back and have a closer look inside the generateVariationFont function to search for optimization opportunities.

For example, because Elementar is not a typical interpolation-based variable font, all contour optimization steps were not needed. I could also draw the element glyph2 directly as a quadratic curve, so converting from cubic to quadratic would no longer be required. I ended up writing a custom version of the variable font generation function in Batch, and was able to reduce font generation time considerably. This was still running inside RoboFont.

Another speed gain was achieved by generating TTF masters using ufo2ft directly instead of with the AFDKO through font.generate(). After that change, the whole font generation pipeline could be executed outside of RoboFont – so I can now continue drawing in the app while the font is being generated in the background.

Slicing up the designspace into multiple fonts

Finally, to cut down the glyph count in the masters even further, I decided to split the single variable font containing all axes into several smaller fonts with height, width and element axes only. Since the masters are discontinuous, this could be done without causing a marked ‘break’ in the transitions. The interface had to be changed accordingly: instead of plugging the sliders only to the values in the font-variation-settings attribute, now it also switches the font-family when style or stroke parameters change.

With smaller fonts to generate, the whole process got faster and more fun, and I can go back to adding more glyphs again.


Notes

  1. It’s worth mentioning that this work is being done on a MacBook Air from 2012. Newer machines can probably run the same code in less time. 

  2. The element glyph is the only contour in the fonts – all other glyphs are built with components of the element.