DSE2 location labels icon

DesignspaceEditor 2

Create and edit designspaces with RoboFont 4.5+, with support for scripting and notifications.
By TypeMyType and LettError.

Contents

This page is also available on GitHub.

Goals

DSE2 Toolbar ↑

Axes Tab Sources Tab Instances Tab Rules Editor Location Labels Editor Variable Fonts Editor Problems Tab
Open Preview Window Save the Designspace Open Documentation

Getting Started↑

This is
  1. Look for DSE2 in the RoboFont File menu: New Designspace, Open Designspace or Open Recent Designspace
  2. If you're starting from scratch: add the first axis in the Axes Tab.
  3. Go to the Sources Tab and at least two source UFOs Then edit the axis values for each new source. Make sure there is at least 1 source on the default value of all axes. Make sure there aren't multiple sources on one location.
  4. Save the designspace in the same folder as your sources, or one level up. The designspace format stores a relative path to the sources and instances, so keep them close together.
  5. Add instances, rules, axis labels, location labels and whatever else you need to do.
  6. Check the Problems Tab to see if there are no immediate issues with your setup.
  7. Preview selected instances in text, and create new instances
  8. Save early and often.
Note that DSE2 does not maintain formatting or comments in designspace it edits. We know some of you are very particular about the xml.

DSE2 axes icon

Axes Tab ↑

screenshot of DSE2 axes tab

Axes Buttons

Quick buttons for easy axes. Obviously you can edit these values here.

Axes Columns

Double click the icon to get the popover editor for axis labels and axis maps. The editor represents the labels and maps in a simple syntax for editing. When the panel is closed, the text is converted to designspace objects.
Name Nice human readable name for this axis. No spaces. This name will be for the default English language localisation.
Tag A 4-letter tag, the technical identifier for this axis.
  • All lowercase for a standard, pre-defined axis, such as wght, wdth, opsz, ital and slnt.
  • Use all-uppercase for your own axes. FORK, MONO.
Minimum The minimum value of this axis, required for continuous axes.
Maximum The maximum value of this axis, required for continuous axes.
Default The default value of this axis, required. For a continuous axis the default needs to be between minimum and maximum or equal to one of them. For a discrete axis the default must be one of the axis values.
Discrete Values To define discrete axis values enter space separated numbers. For instance 30 60 100. One of these values must match the default. Leave this field empty if this is to be a continuous, interpolating axis.
Hidden Corresponds with the OpenType variable font specification flag HIDDEN_AXiS. to "provided to indicate a recommendation by the font developer that the axis not be exposed directly to end users in application user interfaces."
πŸ“ˆ Indicates this axis has a map. Click the for the Axis Map editor.
🏷️ Indicates this axis has labels. Click the for the Axis Label editor.

Axis Map editor syntax

# user space value
#   (numbers exposed to the user in a UI)
# maps to
#   designspace value
#   (the internal values used to position sources and instances in the designspace)
50 > 10
100 > 20
125 > 66
150 > 990

# Please note: in these examples, lines starting with # are comments.
# The comments are not saved in the designspace.

Axis Label editor syntax

# Axis Labels syntax

# if the line starts with a ? <language tag> <localised string>
? fr 'Chasse'

# <label name> <value>
'Condensed' 50

# optionally add (elidable) or (olderSibling)
'Normal' 100 (elidable) (olderSibling)

# optionally add [linkeduservalue]
# for instance: upright style links to italic, on discrete italic axis:
'Upright' 0 (elidable) [1]
'Italic' 1 [0]

# set a range for a label name
# <label name> <min value> <default value> <max value>
'Extra Wide' 150 225 300
'Extra Light' 200 200 250

# add localisations for this 'Extra Light' label
? de 'Extraleicht'
? fr 'Extra lΓ©ger'

# Please note: in these examples, lines starting with # are comments.
# The comments are not saved in the designspace.

DSE2 sources icon

Sources Tab ↑

screenshot of DSE2 sources tab

Sources Tab Buttons

Sources Menus

Double click in the icon opens a popover editor for Localised Family Name and Muted Glyphs.

Control click on a source for a contextual menu:

Sources Tab Columns

button for the popover editor
πŸ’Ύ shows a checkmark if the UFO is where we expect it to be
πŸ“ Indicates this source is the default.
UFO the UFO filename and path relative to the designspace document
Family Name family name from the source UFO font info. Some applications look for these names so they do not have to open the UFOs. Optional
Style Name style name from the source UFO font info. Some applications look for these names so they do not have to open the UFOs. Optional
Layer Name name of the layer to be used as a source. Leave blank for default, "foreground". Optional See Note on Support Layers.
🌐 indicates if there are localised names for this source. Click the for the Localised Family Name editor .
πŸ”• indicates if there are muted glyphs in this source. Click the for the Muted Glyph editor.
column for each axis Axis values for sources are in designspace coordinates.
If you have discrete axes, make sure this value matches one of the values of the axis. Make sure it is between axis minimum and axis maximum. No anisotropy.

Localised Family Name editor syntax

# localised name starts with a ? <language tag> <localised string>
? fr 'Montserrat'
? ja 'γƒ’γƒ³γ‚»γƒ©γƒΌγƒˆ'

Muted Glyph editor syntax

# a space separated list of glyph names
a b c d

Notes on the Layer Name column and support layers

In the DSE Sources Tab, the Layer Name column can point to an optional layer name from the source UFO. If this field is empty, DSE2 will use the foreground layer. It can be useful, in some interpolations, to have an additional source for a glyph in a specific place. Perhaps the diagonals are getting a bit thin. Maybe a counter needs to be opened up a bit. The idea is that you can add a source only for that specific glyph at a very specific point in the designspace. Check out Mutator Sans for some examples of a Support Layer. The idea is the same, the names differ and the expectations and implementation also differ. MutatorMath designspaces always had this flexibility. Skateboard explored ways to make it easier to add such layers. And FontMake has implemented some support. But it is important to understand the limitations of this construction.

Support layer recommendations

How are support layers interpreted?

screenshot of DSE2 showing a sparse master in the Mutator Sans demo font.

DSE2 Preview window showing an absurdly wide S from a support layer in MutatorSans.

DSE2 instances icon

Instances Tab ↑

screenshot of DSE2 tab for instances

This tab shows the instances defined for this designspace. These items can become different things depending on the context. For instance, each instance can be compiled to a separate UFO file. But they can also be interpreted as named locations in a variable font.

Instances Tab Buttons

Instances Tab Menus

Control click on an instance for a contextual menu:

Instances Columns

button for the popover editor for additional names, as well as localised family and style names.
UFO path and filename of destination UFO (if that is where you want to go obviously)
Family Name Family name for the UFO
Style Name Style name for the UFO and variable font.
🏷️ Indicates if the instance has addtional names applied, like PostScript name (previously a column on the main table) or Style Map names. Click the for the Additional Names editor.
🌐 Indicates if there are localised names for this source. Click the for the Localised Family Name & Style Name editors.
πŸ“ The icons in this column indicate if the location values are specified as πŸ‘€userspace (a person icon, because user), or ✏️designspace (a pencil icon because design). See Note 1.
Column for Each Axis Axis values can be in userspace or design coordinates. Anisotropic values are separated by a space. See Note 2

Note 1: About userspace and designspace locations

Note 2: About anisotropic instances

Additional Names editor

Click the magic wand next to each field to generate a guess at what the value should be based on the Family and Style name provided on the main table. The authors make no warranties or guarantees that they are correct! You should double-check their validity.

Identifying Name A unique name that can be used to identify this font if it needs to be referenced elsewhere in the backend. If not provided it'll be made up.
PostScript Font Name Corresponds with font.info.postscriptFontName. Should ideally follow the rules for PostScript names, found in the OT Spec.
Style Map Family & Style Map Style Names Corresponds with font.info.styleMapFamilyName and font.info.styleMapStyleName. See some examples in the RF Docs.

Localised Family/Style Name editor syntax

# localised name starts with a ? <language tag> <localised string>
? fr 'Montserrat'
? ja 'γƒ’γƒ³γ‚»γƒ©γƒΌγƒˆ'

DSE2 rules icon

Rules Tab ↑

screenshot of DSE2 rules tab

The rules tab is an editor for defining rules and condition sets. Tools may interpret these rules into rvrn features. The Preview Window does not show the rules in action. While this would indeed be useful, it requires compiling the features and that is currently outside the scope of this extension. We recommend using FontGoggles for proofing the rules.

Rules syntax

# Rules syntax

# The name of the rule starts on a new line.
# The contents of the rule is indented:
switching a's
    # a list of source glyph > substituted glyph
    a > a.alt
    agrave > agrave.alt

    # conditions that trigger the rule:
    # <axis name> startRange-endRange
    optical 500-1000

    # a condition set with two conditions
    weight 800-1000 width 200-1000

# Please note: in these examples, lines starting with # are comments.
# The comments are not saved in the designspace.

DSE2 location labels icon

Location Labels Tab ↑

The location labels tab is an editor for defining labels for specific points in the designspace. This data can be used to define parts of a STAT table.

See fontTools documentation on the top-level labels element.

Location Labels syntax

# Location Labels

# styleName:
Neue Style Italic

    # optional localisations
    # starts with a ? <language tag> <localised string>
    ?  fr  "Un Style"
    # optionally translation
    ?  fr  "Un Style"

    # location name if the axis and value
    weight 300
    width 40
    italic 1
    boldness 30

# Please note: in these examples, lines starting with # are comments.
# The comments are not saved in the designspace.

DSE2 variable fonts icon

Variable Fonts Tab ↑

screenshot of DSE2 variable fonts tab

This describes different subset variable fonts that can be generated from the current designspace file. For instance this could mean a smaller number of axes, or a specific range of an axis. You can also specify different filenames for these variable fonts.

See fontTools documentation on the variable-font element.

Variable Fonts syntax

# Variable Font syntax

<name of the variableFont>
    # indent
    > "<fileName of the variable font file>"   # optional

    > "path/to/my/fontVF.ttf"

    # a full axis subset
    # i.e. "weight", not "wght"
    <axisName>

    # example: include the whole weight axis
    weight
    ...

    # an axis subset at specific userspace value
    # i.e. "weight", not "wght"
    <axisName> <value>

    # example
    weight 400
    ...

    # an axis subset with a sub range
    <axisName> <minimumUserValue> <userDefault> <maximumUserValue>

    # example
    weight 300 400 700
    ...

# Please note: in these examples, lines starting with # are comments.
# The comments are not saved in the designspace.

DSE2 problems icon

Problems Tab ↑

screenshot of DSE2 problems tab

This tab lists some of the problems this designspace might have. From structural issues that block any further processing, to missing ufos, missing or duplicate values and glyphs with compatibility issues. This uses DesignspaceProblems. to do the analysis. It aims to list all the problems that prevent the previews and test fonts from being generated. It does not go very deep into the more exotic issues that may occur.

DSE2 notes icon

Notes Tab ↑

This tab is for your notes and are stored in the Designspace. This can be any kind of note or remark. Notes are not processed in any way.

Preview Window↑

screenshot of DSE2 preview window

The most requested feature for designspace editing tools: a preview for instance and source locations.

DSE2 notes icon

Scripting with the current designspace↑

With a document open in DesignspaceEditor you can call CurrentDesignspace(), similar to CurrentFont() and CurrentGlyph(). This returns the designspace wrapped in a UFOOperator object that can calculate single glyphs, kerning and font info.

Making a glyph

This example calculates a single glyph at the default location. It returns a mathGlyph.
d = CurrentDesignspace()
loc = d.newDefaultLocation()
g = d.makeOneGlyph("A", location=loc)

# matGlyph objects can easily be converted
g2 = RGlyph()
g2.fromMathGlyph(g)
What is happening here? Step by step: CurrentDesignspace returns a UFOOperator object for the current designspace. d.newDefaultLocation() creates a dict representing the default location in design coordinates. For this example it is a quick way to get a valid location, but you will probably want to see more exotic locations. Then, makeOneGlyph creates a new glyph object for the given glyphName and a location dict. The result is a MathGlyph object that can be converted to a regular RoboFont glyph object.

Setting the preview location

DSE2 keeps track of the "current preview location". You can set this location with the UI and axis sliders in the Preview Window. But you can also set it with a script.

d = CurrentDesignspace()
previewLoc = d.randomLocation()
d.setPreviewLocation(previewLoc)

Going through all designspaces

You can use AllDesignspaces() to get a list of all open designspace documents. Optionally you can pass a font object with usingFont to get only the designspaces that use that font.
import os
d = AllDesignspaces()
for i, doc in enumerate(AllDesignspaces()):
    print(f"{i}: {os.path.basename(doc.path)}")
f = CurrentFont()
for doc in AllDesignspaces(usingFont=f):
    print(f"\nOnly using {os.path.basename(f.path)}:", f"{os.path.basename(doc.path)}")
0: Sans_wdth.designspace
1: Experimental_serif.designspace

Only using Test-Light.ufo: Experimental_serif.designspace

Calculating kerning and info

This example calculates a single kerning pair and a font info object. makeOneKerning accepts an optional list of pairs to calculate. This can be faster, for instance if you want to prepare a preview of just a handful of glyphs, but with proper kerning. If no pairs are given, all pairs will be calculated. This is still fast, but it all adds up,
d = CurrentDesignspace()
loc = d.newDefaultLocation()

pairs = [('public.kern1.i', 'public.kern2.b')]
kern = d.makeOneKerning(loc, pairs)
print(kern.items())

info = d.makeOneInfo(loc)
print(info)
    

Calculating an instance and drawing in Drawbot

With the Drawbot extension in RoboFont, you can call CurrentDesignspace() and draw interpolated glyphs.
#drawbot
size(1000, 500)
d = CurrentDesignspace()
fill(None)
stroke(0)
strokeWidth(.5)
with savedState():
    translate(100, 100)
    scale(0.5)
    for i in range(20):
        loc = d.randomLocation()
        g = d.makeOneGlyph("A", location=loc)
        bp = BezierPath()
        g.draw(bp)
        drawPath(bp)
More scripting examples in the GitHub designSpaceRoboFontExtension repository.

Useful methods of UFOOperator↑

CurrentDesignspace returns a UFOOperator object representing the designspace. UFOOperator takes care of the loading the fonts and it prepares interpolating objects for all the data, both in varlib and mutatorMath flavors. It understands anisotropic coordinates, and it can handle extrapolation. UFOOperator also caches its results, so there is some economy. The object is pretty easy to script with as well. To see how UFOOperator works, please check the source on GitHub.

UFOOperator has the many of the attributes and methods as the fonttools designspace object, and then some additional ones. Building a new designspace with UFOOperator is very similar to what is described here.
d = CurrentDesignspace()
# source objects
print(d.sources)
# instance objects
print(d.instances)
# axes objects
print(d.axes)

In general: d.useVarlib=True will appply the fonttools.varlib model interpolations. d.useVarlib=False will use the mutatorMath model for interpolations. The Varlib model is very close to how Variable Fonts work. MutatorMath is a bit more flexible: it can do anisotropic interpolation and it is much more flexible with incomplete sets of sources. Both models can extrapolate now, though their results might not be the same if there are unaligned, off-axis masters in the system.

UFOOperator will assume locations are in designspace coordinates. You can use the `bend` argument to indicate that a location has to be mapped from user coordinates to design coordinates. The competing coordinate systems can be a bit confusing, especially if you use userLocations in the instances. Often the axis mappings are added much later than the instances, so there will be a moment when you have to carefully look at where the instances are. The DSE has a menu for converting between User coordinates to Design coordinates. So, before you assume the code is getting the wrong results, check your axis mappings and locations, and make sure you are passing the right type to UFOOperator. If you're sure the location is in designspace coordinates, leave `bend=False`.

This is a selection of the methods available in UFOOperator that are probably must useful to the scripter. Check GitHub for more.

Methods for making things

Preparing a UFOOperator

Methods for locations

Miscellaneous

DSE2 notifications icon

Notifications↑

DesignspaceEditor2 sends notifications for events for the documents it has open. This means scripts and tools can subscribe to these and get access to live designspace data. With these notifications it will be easier to build new things that work with your designspaces.

The source for these notifications at github.com/LettError/designSpaceRoboFontExtension.

Receiving and responding to notifications↑

This is a demo of Subscriber receiving designspace notifications.

from mojo.subscriber import Subscriber, registerRoboFontSubscriber

class DesignspaceEditorSubscriber(Subscriber):

    debug = True

    def designspaceEditorDidOpenDesignspace(self, info):
        print("opened a designspace:", info["designspace"])

    def designspaceEditorDidCloseDesignspace(self, info):
        print("closed a designspace:", info["designspace"])

    def designspaceEditorAxesDidAddAxis(self, info):
        print("created a new axis:", info["axis"], "for", info["designspace"])

    def designspaceEditorRulesDidChange(self, info):
        print("rules did chagne for:", info["designspace"])

registerRoboFontSubscriber(DesignspaceEditorSubscriber)

Overview of DSE2 Notifications↑

Notification name Description Possble actions
Document related notifications
designspaceEditorWillOpenDesignspace DSE is about to open a designspace file.
designspaceEditorDidOpenDesignspace DSE has opened a designspace file. Load fonts, build mutators.
designspaceEditorDidCloseDesignspace DSE has closed designspace file.
Axis related notifications
designspaceEditorAxisLabelsDidChange DSE has changed one of the axis labels.
designspaceEditorAxisMapDidChange DSE has changed the map of one of the axes. Geometry has changed.
designspaceEditorAxesWillRemoveAxis DSE is about to remove one of the axes. Geometry will change.
designspaceEditorAxesDidRemoveAxis DSE has removed one of the axes. Geometry has changed.
designspaceEditorAxesWillAddAxis DSE is about to add a new axis. Rebuild
designspaceEditorAxesDidAddAxis DSE has added a new axis. Geometry has changed. Probably the new system will look the same, the geometry has changed and things need to rebuild anyway.
designspaceEditorAxesDidChangeSelection DSE changed the selected axis. (clarify) No rebuild needed.
designspaceEditorAxesDidChange DSE made a change to the axes. (clarify) Rebuild
Source related notifications
designspaceEditorSourcesWillRemoveSource DSE is about to remove a source. Geometry will change.
designspaceEditorSourcesDidRemoveSource DSE has removed a source. Geometry has changed.
designspaceEditorSourcesWillAddSource DSE is about to add a source. Geometry will change.
designspaceEditorSourcesDidAddSource DSE has added a source. Rebuild
designspaceEditorSourcesDidChangeSelection DSE changed the selected source. (clarify)
designspaceEditorSourcesDidCloseUFO DSE closed a UFO: there will be no visible change, but the source was closed RF and the UFO will load from file. Rebuild.
designspaceEditorSourcesDidOpenUFO DSE opened a UFO. Rebuild: there will be no visible change, but the source is now open in RF and the source will load from there.
designspaceEditorSourcesDidChanged DSE noticed one or more of its sources changed. Rebuild
Instance related notifications
designspaceEditorInstancesWillRemoveInstance DSE is about to remove an instance.
designspaceEditorInstancesDidRemoveInstance DSE has removed an instance. Rebuild instance lists
designspaceEditorInstancesWillAddInstance DSE is about to add an instance.
designspaceEditorInstancesDidAddInstance DSE had added an instance. Rebuild instance lists
designspaceEditorInstancesDidChangeSelection DSE changed the selected instance.
designspaceEditorInstancesDidChange DSE noticed one or more of its instances changed. (Clarify)
Rule related notifications
designspaceEditorRulesDidChange DSE reports one or more of the rules changed.
Label related notifications
designspaceEditorLabelsDidChange DSE reports one or more of the location labels changed.
Note related notifications
designspaceEditorNotesDidChange DSE reports a change in the notes.
Notifications related to editing source data in RoboFont
designspaceEditorSourceGlyphDidChange DSE reports changes to a glyph of one of the open sources. Rebuild glyph mutators
designspaceEditorSourceInfoDidChange DSE reports changes to font info of one of the open sources. Rebuild info mutators
designspaceEditorSourceKerningDidChange DSE reports changes to font kerning of one of the open sources. Rebuild kerning mutators
designspaceEditorSourceGroupsDidChange DSE reports changes to font groups of one of the open sources. Rebuild kerning mutators
designspaceEditorSourceGroupsDidChange DSE reports changes to font groups by a RF editor.
Experimental / unsupported
designspaceEditorDidChange DSE reports every change. Be careful, this will call a lot and might cause performance issues.
designspaceEditorPreviewLocationDidChange DSE report changes to the preview location.
designspaceEditorSourceDataDidChange DSE reports every change to the source data. Be careful, this will call a lot and might cause performance issues.
designspaceEditorSourceFontDidChangedExternally DSE reports every change noticed external changes to source data that is not open in RF. Be careful, this will call a lot and might cause performance issues.

Acknowledgements↑