Spacing Macro

PabloImpallariPabloImpallari Posts: 527
edited March 2013 in Type Design Software
I have started playing around with an auto-spacing macro.
Inspired by Frank E. Blokland's talk at ATypI Reykjavik (that was the more interesting one for me) More info on

- It will work based on proportion conventions, somewhat ignoring many of your glyphs drawings.
- It will help you to "detect" and "correct" you drawing errors.
(for example: If you have drawn glyphs that are too wide or too narrow depending on the proportions conventions you have chosen, you will notice it after running the macro).

Basically, you feed it with some data first:
- "n stem width"
- "n counter width"
- "o stem width"
- "o counter width"
- chose proportions conventions from the "Proportions" list.
- choose "text" or "display".

Basically, this is all the info you need to space a font. Isn't it?
Everything else can them be done by the computer.

The "Proportions" list is the most important part, it will include:
- Textura (1 : 2 : 3)
- Jenson (2 : 3 : 4 : 6)
- JvKrimpen (2.4 : 3.2 : 4 : 6)
- more to come... I'm looking forward for feedback to add more "Proportions" options.

It is still too early to release (It's not yet working very well), but anyway I wanted to start the conversation.


  • Mark SimonsonMark Simonson Posts: 1,174
    edited April 2012
    Seems like the proportions feature ought to be open-ended, rather than just a fixed list of choices.

    I will be curious to see what you are able do with this.
  • James PuckettJames Puckett Posts: 1,669
    Wouldn’t it make more sense to just familiarize oneself with the proportions of a type style before using it as a model and to set the sidebearings of the letters as the type is drawn?
  • @Mark:
    That is a fantastic idea.. maybe the script can take a "proportion" file as input.
    This way you can save/edit/tweak/share your settings.
    Will work on that approach.

    Yep... but proportions is more like a "general" idea, while side-bearings are "specific" values.
  • James PuckettJames Puckett Posts: 1,669
    …side-bearings are "specific" values.
    What are sidebearings specific to, other than the preferences of the designer creating the typeface? Does your macro use some supplied values to calculate the rest the way iKern does? Or does it specifically generate values based on systems Frank Blokland sees in old types?
  • James MontalbanoJames Montalbano Posts: 926
    edited April 2012
    Yet another automation to keep the type designer from pondering their work.
  • What are sidebearings specific to, other than the preferences of the designer creating the typeface?
    That's the main point.
    On one hand, the spacing is specific to the each designer preferences.
    And at the same time, it's also based on conventions.
    It's somewhat subjective.. but not entirely. It also need to have some consistency.

    If you can feed the script with your own preferences.. you can find a balance between subjectivity and conventions.
    Does your macro use some supplied values to calculate the rest the way iKern does?
    I don't know the internals of how iKern works.
    My script was born initially to apply Blokland's system, but it's slowly mutating to allow each designer to define and apply their own system, as Mark suggested in his comment.
    The same kind of things you can do using Metric Classes, only a little easier.

  • James PuckettJames Puckett Posts: 1,669
    So then it isn’t so much an automated spacing tool as a tool for managing spacing and proportion systematically. Cool.
  • The more I get into this.. the more complex it's getting...
  • Nick ShinnNick Shinn Posts: 1,458
    I’m wary of this sort of automation, for the reason James M mentioned.
    Working with your defaults would be rather like limiting oneself to 122 web-safe colors.

    However, I think it could be useful if one were to apply various “conventions” to a design in progress, and see how they effect its color.

    Because ideally each new type is going to have its own proportions, not take them off the shelf, so trying on some ready-mades might help decide what kind of spacing system would work best.

    One could also tweak the “conventions” to establish one’s own settings.

  • PabloImpallariPabloImpallari Posts: 527
    edited April 2012
    Hi again:
    I'm making some progress.. hoping to release the first beta version soon, so you can try it for yourself.

    After analyzing the metrics (and drawings) from hundreds of fonts, JvK remark “there are no rules on the proportions of letters” is taking on new meaning for me.

    Along the way many questions began to appear.
    I'm trying to answer them, creating formulas when possible, and not always is.

    The very first step the macro has to get right, is spacing the /n and the /o.
    Q: Should the "advance width" of the /n be the same as the "advance width" of the /o? Should it be Bigger? Smaller? When should it be the same?
    A: In Serif typefaces about 90% of the time it's smaller. 10% is the same. In rare exceptions the /o is wider.
    In Sans Serif typefaces is about 40% smaller, 20% the same, 40% bigger.
    Clearly there is no rule here.

    Q: Should it be determined by the width of the stems and the width of the counter?
    A: Yes and No. It should be related the the widths of the stem and the counters, but its also adjusted for text or display settings. Also, in condensed; normal; and wide fonts, the relations are totally different.
    Maybe there is a rule, but it's not entirely clear.

    Q: Can we create some sort of magical formula to space them?
    A: Yes and No. What we can do, is create a formula to set the spacing using the info from the stems and counters, but then is up to the designer to adjust those values to account for specific preferences. For text or display settings, etc.
    Now we are getting closer. Maybe the macro can offer a suggestion, and let the designer adjust those results to their preferences.

    Q: Once the designer has tweaked the /n and /o spacing, and his happy with the results. Can we use that info to space "nobdhijlmpqu"
    A: Hell Yeah! Ok, so the script will not be like "click here and all the magic happens at once" but more like "click, tweak the result, click again, tweak, click, done".

    Q: Once we are happy with "nobdhijlmpqu". Is there any pattern for the other letters
    A: Yep, there are. Once we have the basic info of the /n and the /o, we can find relations with all the other letters. That's why is pretty easy for us to say "that /s is too wide" or "that /v is too narrow".
    For example, the /a is never wider than the /n.
    In sans, is about 85/95% of the /n. In serif, is about 80/90% of the /n.
    Of course, this only applies if the /a has a "roman" construction. If it's using a "italic" construction we can space it together with the "n and o" group (the same applies to the /g).

    At this point the script is producing "pretty decent" results.
    But it's a few steps process:
    Step 1) Look at the suggestions for "nobdhijlmpqu"
    Step 2) Easily adjust as desired by editing only 2 variables, and look again
    Step 3) When happy with "nobdhijlmpqu", look at the suggestions for "abcdefghijklmnopqrstuvwxyz"
    Step 4) Small (if any) adjustments to /a/c/e/f/g/k/r/s/t/v/x/z editing only 1 number for each glyph.

    Basically, it allows you to express your preferences, and the script takes cares of consistency.

    Instead of tweaking and tweaking and tweaking all the side-bearing by hand, you can get almost the same result by tweaking 10 or 15 values only.

    Here is a preview of the configuration file:
    # For "nobdhijlmpqu"
    nStem = 87
    nCounter = 219
    oStem = 91
    oCounter = 273
    globalAdjust = 94
    curvedMarginAdjust = 60
    # For "acefgkrstvxz"
    TypeStyle = 2 # 1 for sans, 2 for serif
    aConstruction = 1 # 1 for roman construction, 2 for italic construction
    gConstruction = 1 # 1 for roman construction, 2 for italic construction
    aLeftMarginAdjust  = 100
    cRightMarginAdjust = 100
    eRightMarginAdjust = 100
    fRightMarginAdjust = 94
    gBothMarginsAdjust = 50
    kRightMarginAdjust = 96
    rRightMarginAdjust = 100
    sBothMarginsAdjust = 100
    tRightMarginAdjust = 100
    vBothMarginsAdjust = 100 # aplies to v, w, y
    xBothMarginsAdjust = 100
    zBothMarginsAdjust = 100
    Does this approach/logic makes any sense?
  • Mark SimonsonMark Simonson Posts: 1,174
    Ha! You're using slash notation.

    (This is all very interesting.)
  • So far I have a working version that is producing very good result, but it's for the lowercase only.
    Should I release this or should I wait until it also works on Uppercase and Figures?
  • André SimardAndré Simard Posts: 148
    I would say, release what you've done so far on the lowercase, than the answer of use could help you to adjust the Uppercase and Figures.
  • Göran SöderströmGöran Söderström Posts: 117
    edited May 2012
    Instead of tweaking and tweaking and tweaking all the side-bearing by hand, you can get almost the same result by tweaking 10 or 15 values only.

    This is already possible by using some carefully selected metrics classes in FontLab, just so you know.

    But looking forward seeing what you come up with.
  • PabloImpallariPabloImpallari Posts: 527
    edited May 2012
    Oka. I will release it and make a small screencast to show how it works.
    Anyone wants to offer a font for the screencast? (a-z only, sidebearings set to zero, no kerning).
    This is already possible by using some carefully selected metrics classes in FontLab
    Yep, I know. But setting up the classes is a pain in the ass.
  • James PuckettJames Puckett Posts: 1,669
    Yep, I know. But setting up the classes is a pain in the ass.
    It would probably be a lot easier to write a Glyphs script that builds the classes and then just update the entire font’s metrics now and then.
  • Georg SeifertGeorg Seifert Posts: 605
    edited May 2012
    I have a script for Glyphs that sets the kerning classes. It could easily be adjusted to set the metrics keys as well. You can find it in: github
  • Göran SöderströmGöran Söderström Posts: 117
    edited May 2012
    Yep, I know. But setting up the classes is a pain in the ass.
    Surely building an application like yours must be far more complex than setting up some metrics classes in a Font App, but I think people will appreciate you app a lot, especially if you’re lazy ;-)
  • PabloImpallariPabloImpallari Posts: 527
    edited July 2012
    Spacing macro Beta07 released

    15' Screencast:

    Play around, and let me know how it can be improved.
  • Don't know if this is useful but I built macros to set side bearings based on the spacing of initial characters, H O and n o. My Python skills are not great so this is a little clumsy, but does the job. This sets a basic spacing that you can tweak and then I have macros to set composites, etc. accordingly. Based on Robofab.
    for lowercase

    # ua = n sidebeariing, ub = 90% of n sidebearing, uc = 50% of n sidebearing
    # ud = 20% of n sidebearing, ue = o sidebearing

    from import CurrentFont
    f = CurrentFont()

    la = f["n"].leftMargin
    la = int(la)
    lb = la *0.9
    lc = la *1.1
    ld = la *0.2
    le = f["o"].leftMargin
    lf = le *0.9

    f["a"].leftMargin = lb
    f["a"].rightMargin = lf
    f["ae"].leftMargin = lb
    f["ae"].rightMargin = lf
    f["b"].leftMargin = la
    f["b"].rightMargin = le
    f["c"].leftMargin = le
    f["c"].rightMargin = lf
    f["d"].leftMargin = le
    f["d"].rightMargin = la
    f["e"].leftMargin = le
    f["e"].rightMargin = lf
    f["f"].leftMargin = le
    f["f"].rightMargin = lf
    f["g"].leftMargin = le
    f["g"].rightMargin = la
    f["h"].leftMargin = lc
    f["h"].rightMargin = lb
    f["i"].leftMargin = lc
    f["i"].rightMargin = la
    f["j"].leftMargin = la
    f["j"].rightMargin = la
    f["k"].leftMargin = lc
    f["k"].rightMargin = ld
    f["l"].leftMargin = lc
    f["l"].rightMargin = la
    f["m"].leftmargin = la
    f["m"].rightmargin = lb
    f["p"].leftMargin = lc
    f["p"].rightMargin = le
    f["q"].leftMargin = le
    f["q"].rightMargin = la
    f["r"].leftMargin = la
    f["r"].rightMargin = ld
    f["s"].leftMargin = lb
    f["s"].rightMargin = lb
    f["t"].leftMargin = lb
    f["t"].rightMargin = lb
    f["u"].leftMargin = lb
    f["u"].rightMargin = lb
    f["v"].leftMargin = ld
    f["v"].rightMargin = ld
    f["w"].leftMargin = ld
    f["w"].rightMargin = ld
    f["x"].leftMargin = ld
    f["x"].rightMargin = ld
    f["y"].leftMargin = ld
    f["y"].rightMargin = ld
    f["z"].leftMargin = lb
    f["z"].rightMargin = lb


    for uppercase

    # ua = H sidebeariing, ub = 90% of H sidebearing, uc = 50% of H sidebearing
    # ud = 20% of H sidebearing, ue = O sidebearing

    from import CurrentFont
    f = CurrentFont()
    # sets integer values according to Tracy
    ua = f["H"].rightMargin
    ua = int(ua)
    ub = ua *0.9
    uc = ua / 2
    ud = ua * 0.2
    ue = f["O"].rightMargin

    f["A"].rightMargin = ud
    f["A"].leftMargin = ud
    f["B"].leftMargin = ua
    f["B"].rightMargin = uc
    f["C"].leftMargin = ue
    f["C"].rightMargin = uc
    f["D"].leftMargin = ua
    f["D"].rightMargin = ue
    f["E"].leftMargin = ua
    f["E"].rightMargin = uc
    f["F"].leftMargin = ua
    f["F"].rightMargin = uc
    f["G"].leftMargin = ue
    f["G"].rightMargin = ub
    f["I"].leftMargin = ua
    f["I"].rightMargin = ua
    f["J"].leftMargin = ud
    f["J"].rightMargin = ua
    f["K"].leftMargin = ua
    f["K"].rightMargin = ud
    f["L"].leftMargin = ua
    f["L"].rightMargin = ud
    f["M"].leftMargin = ub
    f["M"].rightMargin = ua
    f["N"].leftMargin = ub
    f["N"].rightMargin = ub
    f["O"].leftMargin = ue
    f["O"].rightMargin = ue
    f["P"].leftMargin = ua
    f["P"].rightMargin = ue
    f["Q"].leftMargin = ue
    f["Q"].rightMargin = uc
    f["R"].leftMargin = ua
    f["R"].rightMargin = ud
    f["S"].leftMargin = uc
    f["S"].rightMargin = uc
    f["T"].leftMargin = ud
    f["T"].rightMargin = ud
    f["U"].leftMargin = ua
    f["U"].rightMargin = ub
    f["V"].leftMargin = ud
    f["V"].rightMargin = ud
    f["W"].leftMargin = ud
    f["W"].rightMargin = ud
    f["X"].leftMargin = ud
    f["X"].rightMargin = ud
    f["Y"].leftMargin = ud
    f["Y"].rightMargin = ud
    f["Z"].leftMargin = uc
    f["Z"].rightMargin = uc

  • This reminds me of the method I used for spacing my Calouste
  • PabloImpallariPabloImpallari Posts: 527
    edited July 2012
    Yes Miguel, your "groups procedure" have also influenced the way the macro works.
    I've added your name in the "Thanks to:" list.
  • In Glyphs I implemented a metrics key system that is capable of something similar to what the macro does. You put in the name of the glyph you want to copy the metrics from in the LSB or RSB field. You have some options:
    =|n # will copy the opposite side baring e.g. you can say in the "u" LSB, copy the RSB from the "n".
    This is not as fast as the script but gives more control. And of cause you could easily adapt the script to set the metrics key.
  • PabloImpallariPabloImpallari Posts: 527
    edited July 2012
    Copying the "full" sidebearing value is of little use, and is not what the macro does.
    What the macro uses, is the distance from the sidebearing to the first segment intersected at the xheight/2 (similar to "using the measurement line"). That way the distance from the "stem mass" to the sidebearing remains constant, while the "full" sidebearing value can be different.

    If you can work your magic to somehow integrate a macro like this (maybe with a better interface) into glyphs, that will be awesome.

    I believe that the main benefit of this approach is that you can "quickly" see and explore how the changes in spacing affect the whole text color in the whole font, instead of setting each glyph manually.
  • The "measurement line" thing is missing. Will see how to do that.
  • I have a script for Glyphs that sets the kerning classes. It could easily be adjusted to set the metrics keys as well. You can find it in: github
    I'm not familiar with Glyphs but in Python you can set up various classes as strings rather than having to set all the metrics for composites individually. Is that possible in Glyphs?
  • This reminds me of the method I used for spacing my Calouste
    Yes, same idea. The scripts set an initial spacing based on the letter shapes and then I follow-up with the tedious fine tuning much as you describe. Saves me having to type it all in or set up metrics classes.
  • Some good reading about spacing (thinking in groups when spacing is nothing new or revolutionary) can be found in Letters of Credit by Walter Tracy. Perhaps you can pick up something from there regarding your spacing macro?
Sign In or Register to comment.