Draft
edit

Planning the designspace

Before we start, it’s a good idea to make a sketch of the designspace we’re going to build:

  • How many masters will it contain? Along how many axes?
  • Where will the masters be positioned?
  • Are there any named instances? Where?
  • Will there be any special rules? (for example shape substitutions)

We’ll be using the MutatorSans family as an example. Its design space contains:

  • 4 masters along two axes, width and weight
  • 1 glyph substitution rule
  • 1 instance named Medium

Notice how the interpolation space does not include a Regular master, only extreme styles – this is a design decision. There are other ways to setup a weight/width designspace, give it a try!

Designing the masters

Having a blueprint of the designspace, we can now focus on designing the masters.

These are the 4 masters in MutatorSans, each one stored as a separate UFO font.

It’s also possible to store all masters as layers of a single font. If you choose to work this way, keep in mind that these layers do not have their own kerning.

The usual rules and recommendations about drawing for interpolation apply:

  • glyphs must be compatible across all masters (see next section)
  • use overlapping paths to have more control over the shapes

It’s usually a good idea to draw the masters and build the designspace iteratively: draw, preview interpolations, adjust the drawings and/or parameters, preview again etc.

Useful tools

Delorean: Interpolation Preview, Interpolation Slider
preview interpolation result while drawing
Overlay UFOs
view other masters in the background layer
ShowSparks
view one-to-one relations between points in all open fonts
EditThatNextMaster
easily switch between masters in glyph, space or font windows

Making sure all masters are compatible

Interpolation requires all master fonts to be compatible. This means that:

  1. all masters must have the same glyphs as the neutral
  2. in each glyph in all masters, the following must match:
    1. number of contours
    2. direction of each contour
    3. number of on-curve and off-curve points

Older interpolation tools may interpolate a straight segment with a curve by assuming there are off-curve points on top of the on-curves. In variable fonts this is not possible, and it is a good design practice to have all the points in the masters.

Useful tools

Prepolator
an extension to detect and fix compatibility problems between fonts
Checking interpolation compatibility
some examples of how to check interpolation compatibility with code

Creating the designspace

The .designspace file is where all information required to build a family of fonts or a variable font is stored.

  • each axis is given a name and a range of values
  • together, all axes define a coordinate space
  • masters are inserted into specific locations of this coordinate space
  • instances are defined as new locations with names

These are the axes and locations in the example MutatorSans designspace:

Useful tools

Different tools can be used to create .designspace files:

Superpolator
a stand-alone application with interactive preview of instances and designspace
DesignSpaceEditor
an open-source extension to edit raw designspace data
DesignSpaceDocument
a Python library to read & write .designspace files with code

Generating variable fonts

The recommended way of building variable fonts in RoboFont is using the Batch extension. Besides generating static fonts, Batch can also generate a variable font from a .designspace file (and a set of compatible UFO sources).

The Batch extension is open-source and can be installed with Mechanic 2.

The requirements for building variable fonts are stricter than those for building static fonts. Batch does a lot of work behind the scenes to fix compatibility issues between the masters. See the Batch documentation for more details.

Generating variable fonts with the Batch extension

Use the menu File > Batch to open the Batch window:

  1. drag the .designspace file into the list (or use the Open button)
  2. open the section Variable Fonts, and select the desired options
  3. click on the Generate button to generate the variable font

Generating variable fonts with code

The variable font generator included inside the Batch extension can also be used programmatically: you can import it into your scripts, and use it to generate variable fonts from .designspace files – without opening the Batch window.

The lib folder of every installed extension is added to the sys.path – so code from one extension can be accessed by another extension or by a script.

The example script below generates a variable font from the MutatorSans .designspace file and linked UFO sources.

import variableFontGenerator

desingSpacePath = 'myMutatorSansFolder/MutatorSans.designspace'
varFontPath = 'myMutatorSansFolder/MutatorSans.ttf'

p = variableFontGenerator.BatchDesignSpaceProcessor(desingSpacePath)
p.generateVariationFont(varFontPath)

Testing variable fonts

Testing with DrawBot

Variable fonts are supported natively in macOS 10.3 and higher.

DrawBot supports variable fonts too. The following commands are available:

fontVariations(wdth=0.6, wght=0.1, ...)
selects a location in the current variable font using parameters
listFontVariations(fontName=None)
returns a dictionary with variations data for the current font

The script below shows a simple DrawBot-based test interface for MutatorSans, using sliders to modify the parameters interactively.

import os

folder = os.getcwd()
fontPath = os.path.join(folder, 'MutatorSans.ttf')

variations = listFontVariations(fontPath)
print(variations)

wghtMin = variations['wght']['minValue']
wghtMax = variations['wght']['maxValue']
wdthMin = variations['wdth']['minValue']
wdthMax = variations['wdth']['maxValue']

txt = "Amazingly few discotheques provide jukeboxes."

Variable([
    dict(name="wght", ui="Slider", args=dict(value=400, minValue=wghtMin, maxValue=wghtMax)),
    dict(name="wdth", ui="Slider", args=dict(value=400, minValue=wdthMin, maxValue=wdthMax)),
    dict(name="txt", ui="EditText", args=dict(text=txt)),
    dict(name="pt", ui="Slider", args=dict(value=64, minValue=12, maxValue=640)),
], globals())

newPage(800, 600)

margin = 20
x = y = margin
w = width() - margin*2
h = height() - margin*2

font(fontPath)
fontSize(pt)
fontVariations(wght=wght, wdth=wdth)
textBox(txt.upper(), (x, y, w, h), align='center')

font("Menlo-Regular")
fontVariations(resetVariations=True)
fontSize(12)
textBox('MutatorSans weight=%3.3f width=%3.3f / %3.3fpt' % (wght, wdth, pt), (x, y, w, 14), align='center')

imgPath = os.path.join(folder, 'testing-DrawBot.png')
saveImage(imgPath)

Testing in the browser

Variable fonts are supported in all major browsers.

Below is a simple HTML test page for MutatorSans. It includes examples of:

  • selecting fonts parametrically with font-variation-settings
  • animating font variation parameters with CSS
  • controlling parameters interactively using sliders
<!DOCTYPE html>
<html>
  <head>
    <title>MutatorSansTest</title>
    <meta charset="utf-8" />
    <style>
      @font-face {
        font-family:'MutatorSans';
        src: url('MutatorSans.ttf') format("truetype");
      }
      body {
        font-family:'MutatorSans';
        text-transform: uppercase;
        font-size: 3em;
        line-height: 1.1;
      }
      p, input {
        margin : 0.4em;
        padding : 0;
      }
      output {
        font-family: monospace;
        font-size: 0.4em;
      }
      #sample0 { font-variation-settings: "wght" 500, "wdth" 327; }
      #sample1 { font-variation-settings: "wght" 750, "wdth" 600; }
      #sample2  {
        font-variation-settings: 'wght' 0, 'wdth' 0;
        animation-duration: 8s;
        animation-iteration-count: 3;
        animation-direction: alternate;
        animation-timing-function: ease-in-out;
        animation-name: mutator-sans-animate;
      }
      @keyframes mutator-sans-animate {
        0%   { font-variation-settings: 'wght' 0,    'wdth' 0;    }
        25%  { font-variation-settings: 'wght' 0,    'wdth' 1000; }
        50%  { font-variation-settings: 'wght' 1000, 'wdth' 1000; }
        75%  { font-variation-settings: 'wght' 1000, 'wdth' 0;    }
        100% { font-variation-settings: 'wght' 0,    'wdth' 0;    }
      }
    </style>
  </head>
  <body>
    <p id='sample0' contenteditable='true'>Five quacking zephyrs jolt my wax bed.</p>
    <p id='sample1' contenteditable='true'>Jackdaws love my big sphinx of quartz.</p>
    <p id='sample2' contenteditable='true'>frisch</p>
    <input  id="wgthSlider" name="weight" type="range" value="500" step="1" min="0" max="1000">
    <output id="wgthSliderValue" name="weightValue">500</output>
    <input  id="wdthSlider" name="width"  type="range" value="327" step="1" min="0" max="1000">
    <output id="wdthSliderValue" name="widthValue" >327</output>
    <p id='sample3' contenteditable='true'>“How razorback jumping frogs can level six piqued gymnasts”</p>
  </body>
  <script>
    var wgthSlider = document.getElementById('wgthSlider'),
        wdthSlider = document.getElementById('wdthSlider'),
        wgthSliderValue = document.getElementById('wgthSliderValue'),
        wdthSliderValue = document.getElementById('wdthSliderValue'),
        sampleText = document.getElementById('sample3');
    function updateSample(){
        var wgthValue = wgthSlider.value,
            wdthValue = wdthSlider.value;
        wgthSliderValue.value = wgthSlider.value;
        wdthSliderValue.value = wdthSlider.value;
        sampleText.style.cssText = 'font-variation-settings: "wght" ' + wgthValue + ', "wdth" ' + wdthValue + ';'
    };
    wgthSlider.addEventListener('input', updateSample)
    wdthSlider.addEventListener('input', updateSample)
  </script>
</html>
  • add explanation of rules & conditions for switching glyphs (example: turning off I-serifs in narrower widths of MutatorSans)
  • move tests to MutatorSans repository?
Last edited on 09/09/2018