Adding OpenType Features in FontLab VI, Part 4: Alternates

In the last post I wrote about features that were relatively minor for Protest (fractions, ordinals, diacritics for caps, and ligatures).

Here’s what I’m covering in this post in the feature order for Protest™ (in bold):

  1. script language specific forms (locl)
  2. fractions (frac, numr, dnom)
  3. ordinals (ordn)
  4. all caps (case)
  5. various alternates (calt, salt, ss01, ss02, ss…)
  6. ligatures (liga, dlig)
  7. manual alternate access (aalt)

What are alternates?

Alternates are basically different versions of glyphs in a font. There are all sorts of reasons to want alternates:

  • a language demands it by the nature of its script (with initial, medial, and final forms of certain letters, such as in Arabic and Hebrew)
  • swash capitals, initial, and final forms of calligraphic (or generally fancy-shmancy) fonts
  • variations in letter styles (like two story vs. one story a or g)
  • specialized forms for specific typesetting situations (like titling)
  • slight deviations from the original letterform to make a font seem imperfect and hand drawn (like Protest)

There are specific features for each of these kinds for different situations:

  • Swashes (swsh) and contextual swashes (cswh)
  • Titling (titl)
  • Stylistic alternates (salt)
  • Stylistic sets (ss01, ss02, ss03… ss20)
  • Contextual alternates (calt)

There are more features for special cases, which can be found in the Microsoft registered features documentation. What I’m concerned with for Protest are the contextual alternates.

When I added alternates to Protest I figured I was adding stylistic sets (ss01, etc.). I’m wondering if the alternates in Protest should have been named .alt1, .alt2, and .alt3 to be more accurate? They’re different glyphs, sure, but stylistically not different.

The alternates for Protest just vary a bit in form in order to simulate being hand drawn. Thankfully, this doesn’t make a difference in how the font functions (as far as I can tell). It’s just a naming convention.

Contextual Alternates

When I drew all those alternates for Protest they were for the purpose of making it look more hand drawn by creating slight variation in texture and form. So how do I make that happen in practice? Enter contextual alternates.

Contextual alternates are for substitutions that take place based on what’s around the target of substitution. These contextual substitutions are GSUB LookupType 5 and 6. (Technically, 5 is a subset of 6, but that’s neither here nor there.) These lookups mark the glyph or glyphs to be substituted, while noting the surrounding glyphs for context. For example:

sub @punctuation space' space' @Uppercase by space;

Here “@Uppercase” is the class containing all uppercase glyphs, and “@punctuation” is the class containing all punctuation. This lookup would change all instances of punctuation followed by two spaces followed by an uppercase glyph (where a new sentence is started) to just one space in between the punctuation and capital (as it should be).

As far as cycling alternate letterforms, this kind of substitution looks for characters in previous sets in the cycle, and substitutes a following or preceding glyph with the same character from another set of alternates.

Options For Contextual Alternates

What I imagined for Protest is this: Each base glyph would have priority—it would be the first one typed. These were, after all, the forms I chose as optimal. The next time that character would be typed the second form (ss01) would occur, and the next time the third form (ss02), and then the fourth form (ss03). The fifth time the character was typed, the cycle starts again. Seems simple enough.

I looked up character cycling methods, and there are a number of ways to do cycling. Three of these methods are detailed in Tal Leming’s OpenType Cookbook. This is a great place to start, as Tal Leming is an expert in OpenType. In his tutorial he talks about basic cycling, eliminating duplicates, and what he has termed “Quantum” randomization.

Basic Cycling

Basic cycling is when each character typed cycles through base (i.e.– base glyphs), ss01, ss02, ss03, and back to the beginning. So no matter what gets typed, the set the preceding character belongs to determines the set of the character being typed. Using classes containing all base glyphs (@BASE), all glyphs from stylistic set 1 (@SS01), set 2 (@SS02), and set 3 (@SS03), basic cycling looks something like this:

sub @BASE @BASE' by @SS01;
sub @SS01 @BASE' by @SS02;
sub @SS02 @BASE' by @SS03;

It’s easy to add in lookups that account for glyphs with no alternates (such as spaces), but those can be covered in the tutorials I linked to.

Using this method for Protest, if I type “for instance” it would look like:
f o.ss01 r.ss02 space i.ss03 n s.ss01 t.ss02 a.ss03 n c.ss01 e.ss02
In this case, the n’s are the only repeated character, but end up being the same form, which doesn’t fit the purpose for Protest.

Duplicate Elimination

Duplicate elimination is only concerned with concurrent repeated characters. This is great for words like “bookkeeper” since it assures the double letters aren’t duplicated. This script is simple, but it has to look through every possible glyph:

sub A A' by A.ss01;
sub B B' by B.ss01;
sub C C' by C.ss01;
.
.
.
sub zero zero' by zero.ss01;

It also doesn’t use any more than one alternate set, and means that words like “Mississippi” still have duplicate s’s and i’s within the same word, even if not right next to each other.
M i s s.ss01 i s s.ss01 i p p.ss01 i

“Quantum” Cycling

“Quantum” cycling is something best explained in detail on the OpenType Cookbook site. Suffice it to say, “each glyph state is dependent on the state of all the glyphs that precede it” (from OpenType Cookbook). It’s imperfect and perhaps a bit slow, but it simulates randomness really well. The thing is, I don’t wan’t randomness in Protest, I want to showcase the best glyphs first, and cycle through the rest as needed.

While looking for other options, I found a Glyphs tutorial about contextual alternates. In it, Rainer Erich Scheichelbauer covers basic cycling, but also introduced the concept of concurrent cycling.

Concurrent cycling

Concurrent cycling is when two sets of glyphs get cycled at the same time. In this case (and here’s the clever part) the two sets are vowels and consonants. With this solution a word like “vowels” will cycle v, w, l and s while cycling o and e separately, to generate v o w.ss01 e.ss01 l.ss02 s.ss03. This is hit and miss, just like basic cycling, but a bit less so. It works pretty well for “vowels,” but “consonants” still ends up with a duplicate s.
c o n.ss01 s.ss02 o.ss01 n.ss03 a.ss02 n t.ss01 s.ss02

Not satisfied with these solutions, I thought I could do one better.

This next part is a bit more of a story—an adventure, if you will—about trying to come up with solutions and chasing the idealist dream. I’m documenting what I did so you might not repeat my mistakes. If you want to skip the story and cut to the solution I arrived at, then be my guest. But if you think to yourself, “There’s got to be a better way to do this,” then please read the story about what didn’t work, just in case.

Generating Scripts Using Python

I figured that cycling while comparing individual letters was pretty easy, at least conceptually. Again, I was thinking each base glyph has priority. The next time that character occurs it gets cycled to the second form (ss01), then next time the third form (ss02), and then the fourth form (ss03). On the fifth occurrence of the character the cycle starts again.

This is like a combination of basic cycling and duplicate elimination. All I had to do was duplicate elimination for every glyph with an alternate, while cycling through as well. Then I could make a class containing all glyphs (@AllGlyphs) and repeat the code with this class in between each duplicate. Then do that again for as many glyphs as I was willing to have it look back through.

Considering each set of glyphs with an alternate form has 299 glyphs, that would be a lot of lines to write on my own. But it would be easy to generate that with code.

The go-to language for coding fonts is Python. Since it would be good to learn that at some point, I thought, “Why not take a crash course now?” I used the python website to get started. They have great tutorials and I even found tutorials on YouTube (of course).

After trying (and uninstalling) a number of different options, I ended up using PyCharm as the IDE. I then wrote a program that would write to a text file that I could paste into FontLab.

[fusion_imageframe image_id=”2523|full” max_width=”” style_type=”” blur=”” stylecolor=”” hover_type=”none” bordersize=”” bordercolor=”” borderradius=”” align=”none” lightbox=”no” gallery_id=”” lightbox_image=”” lightbox_image_id=”” alt=”” link=”” linktarget=”_self” hide_on_mobile=”small-visibility,medium-visibility,large-visibility” class=”” id=”” animation_type=”” animation_direction=”left” animation_speed=”0.3″ animation_offset=””]http://staging.quakercreative.com//wp-content/uploads/2018/11/OTpt4-PyCharm.png[/fusion_imageframe]

In a nutshell:

  • I put in lists (arrays) containing all of the base glyphs. This array can have the alternate set suffix (e.g.– “.ss01”) appended to it for loops referring to each alternate set.
  • The program makes a single loop through all the glyphs, writing a duplicate elimination substitution lookup for each glyph.
  • I can input how far I want the font to look backward in terms of number of glyphs. The program loops that many additional times through all the glyphs, adding another @AllGlyphs class in between duplicates with each loop.

When I only use a few glyphs (A, B, C), and only look back 3 glyphs (A A’), the code works. So the idea worked in principle. But…

Failure

When I put in all the glyphs, even when only looking back 3, it was 5,000 lines of code. It was too much to even compile successfully. (I think FontLab said it gave up around line 3,840-something).

What I learned was that fonts are meant to be compact, and doing too many lookups wont’t work. So while my idealistic cycling model works in theory, it’s not something that can be done in practice. (Or at least not something that a novice like me could do in practice.) If anyone comes up with a way to do this, I’d love to know about it. But if it’s not already out there on the internet, I’m not sure it’s possible at this point.

The other thing I realized is that this method probably isn’t necessary. Why did I want to make the contextual alternates give priority to the base glyphs first, and other ones less? It’s because I thought of those glyphs as the “nice ones.”

Really, I ended up editing my less-than-optimal glyphs enough that they retain the same color and character as the base glyphs. So there’s really no reason to prioritize. Also, I may have edited them too much, making the forms more homogenous than perhaps they should be.

So what did I end up doing instead?

Vowel & Consonant Cycling FTW

In Rainer’s Glyphs tutorial on contextual alternates he says, “Now, if you’re really geeky, you’ll figure out three separate cycles.” While I didn’t do a third cycle, I did look back and additional glyph for both consonants and vowels. I also cycled through an additional set of alternates.

It’s fairly straightforward, if a bit long. But at least it isn’t 5,000 lines.

feature calt {

    # --------------------------------------------
    # Cycle through the 4 versions of each letter
    # based on whether it is a consonant or vowel.
    # --------------------------------------------

    # Consonant followed by consonant

    sub @CONS @CONS' by @CONS1;
    sub @CONS1 @CONS' by @CONS2;
    sub @CONS2 @CONS' by @CONS3;

    # Consonant followed by another character followed by a consonant

    sub @CONS [@VOWL @VOWL1 @VOWL2 @VOWL3 @NoAlt] @CONS' by @CONS1;
    sub @CONS1 [@VOWL @VOWL1 @VOWL2 @VOWL3 @NoAlt] @CONS' by @CONS2;
    sub @CONS2 [@VOWL @VOWL1 @VOWL2 @VOWL3 @NoAlt] @CONS' by @CONS3;

    # Consonant followed by 2 other characters followed by a consonant

    sub @CONS [@VOWL @VOWL1 @VOWL2 @VOWL3 @NoAlt] [@VOWL @VOWL1 @VOWL2 @VOWL3 @NoAlt] @CONS' by @CONS1;
    sub @CONS1 [@VOWL @VOWL1 @VOWL2 @VOWL3 @NoAlt] [@VOWL @VOWL1 @VOWL2 @VOWL3 @NoAlt] @CONS' by @CONS2;
    sub @CONS2 [@VOWL @VOWL1 @VOWL2 @VOWL3 @NoAlt] [@VOWL @VOWL1 @VOWL2 @VOWL3 @NoAlt] @CONS' by @CONS3;

    # Consonant followed by 3 other characters followed by a consonant

    sub @CONS [@VOWL @VOWL1 @VOWL2 @VOWL3 @NoAlt] [@VOWL @VOWL1 @VOWL2 @VOWL3 @NoAlt] [@VOWL @VOWL1 @VOWL2 @VOWL3 @NoAlt] @CONS' by @CONS1;
    sub @CONS1 [@VOWL @VOWL1 @VOWL2 @VOWL3 @NoAlt] [@VOWL @VOWL1 @VOWL2 @VOWL3 @NoAlt] [@VOWL @VOWL1 @VOWL2 @VOWL3 @NoAlt] @CONS' by @CONS2;
    sub @CONS2 [@VOWL @VOWL1 @VOWL2 @VOWL3 @NoAlt] [@VOWL @VOWL1 @VOWL2 @VOWL3 @NoAlt] [@VOWL @VOWL1 @VOWL2 @VOWL3 @NoAlt] @CONS' by @CONS3;

    # Vowel followed by a vowel

    sub @VOWL @VOWL' by @VOWL1;
    sub @VOWL1 @VOWL' by @VOWL2;
    sub @VOWL2 @VOWL' by @VOWL3;

    # Vowel followed by another character followed by a vowel

    sub @VOWL [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] @VOWL' by @VOWL1;
    sub @VOWL1 [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] @VOWL' by @VOWL2;
    sub @VOWL2 [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] @VOWL' by @VOWL3;

    # Vowel followed by 2 other characters followed by a vowel

    sub @VOWL [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] @VOWL' by @VOWL1;
    sub @VOWL1 [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] @VOWL' by @VOWL2;
    sub @VOWL2 [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] @VOWL' by @VOWL3;

    # Vowel followed by 3 other characters followed by a vowel

    sub @VOWL [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] @VOWL' by @VOWL1;
    sub @VOWL1 [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] @VOWL' by @VOWL2;
    sub @VOWL2 [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] @VOWL' by @VOWL3;

    # Vowel followed by 4 other characters followed by a vowel

    sub @VOWL [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] @VOWL' by @VOWL1;
    sub @VOWL1 [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] @VOWL' by @VOWL2;
    sub @VOWL2 [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] [@CONS @CONS1 @CONS2 @CONS3 @NoAlt] @VOWL' by @VOWL3;

} calt;

Manual Alternate Access

Alternate access (aalt) is an important feature. If there must be only one feature for alternates, this is the one. It’s super simple, and it gives users access to all the alternate glyphs the designer wants them to access.

The aalt feature uses a GSUB LookupType 2 (multiple substitution). However, rather than use the keyword by, it uses from (as in sub <glyph> from <glyphclass>;). This is what allows programs like InDesign to suggest other forms of a highlighted glyph. It also allows the user to see all the glyphs listed in the glyphs palette.

This was another simple but long one, and here it was helpful to use Python to generate the list.

[fusion_imageframe image_id=”2522|full” max_width=”” style_type=”” blur=”” stylecolor=”” hover_type=”none” bordersize=”” bordercolor=”” borderradius=”” align=”none” lightbox=”no” gallery_id=”” lightbox_image=”” lightbox_image_id=”” alt=”” link=”” linktarget=”_self” hide_on_mobile=”small-visibility,medium-visibility,large-visibility” class=”” id=”” animation_type=”” animation_direction=”left” animation_speed=”0.3″ animation_offset=””]http://staging.quakercreative.com//wp-content/uploads/2018/11/OTpt4-aaltListGen.png[/fusion_imageframe]

What I ended up with was a big list that looks like this:

feature aalt {

    # -------------------------------------
    # List alternates for each @BASE glyph
    # -------------------------------------

    sub A from [A.ss01 A.ss02 A.ss03];
    sub AE from [AE.ss01 AE.ss02 AE.ss03];
    sub AEacute from [AEacute.ss01 AEacute.ss02 AEacute.ss03];
    sub Aacute from [Aacute.ss01 Aacute.ss02 Aacute.ss03];
    .
    .
    .
    sub zdotaccent from [zdotaccent.ss01 zdotaccent.ss02 zdotaccent.ss03];
    sub zero from [zero.ss01 zero.ss02 zero.ss03];
    sub ampersand from [ampersand.salt ampersand.salt1 ampersand.salt2 ampersand.salt3];

} aalt;

I also added the IJ ligature to the list of alternates for I and J, and added the IJ acute glyph to the list for I acute and J acute.

Lastly, I ended up adding the last line with the ampersands, since those weren’t alternates in the way the others were. These were true stylistic alternates. This brings me to another good point.

I read a post on the Typophile forum by Mark Simonson that explained aalt versus salt very well:

aalt just specifies any and all alternates, including anything covered by other features. There is no specific user interface item to apply aalt, but it does affect what you see in the Glyph palette, specifically those little arrows that indicate alternate forms for a glyph and what appears under the little pop-up on the arrows.

salt at first seems similar to a stylistic set, except that it is intended to be applied to individual characters and can include more than one glyph alternate. However, the user interface for this feature is inconsistent: In Illustrator there is a single on/off button, with the result that you can only access the first available alternate (you can get at the rest via the glyph palette). InDesign doesn’t have any obvious support for salt, at least in its OT submenu, but you see them listed under Stylistic Alternates in the glyph palette.

I added a stylistic alternate (salt) feature just for the ampersands, but I get the sense that I could take or leave it. It consists of the same one line that’s at the end of aalt. The salt feature goes after the calt and before the ligatures.

Up Next

Thanks for bearing with me through an excruciatingly long post! Next time, I cover the mark and mkmk features to the best of my understanding at this point.

  • Part 5: mark, mkmk
  • Kerning!

Posted

in

,

by

Comments

2 responses to “Adding OpenType Features in FontLab VI, Part 4: Alternates”

  1. chiara Avatar
    chiara

    This is super interesting, i’m actually trying to do the same with a font for comics. It would be really nice to follow a video tutorial cause i don’t have any experience in this.

    1. Brandon Avatar

      Thanks, Chiara! I’m a one man band, but one of these days I hope to do video tutorials. However, it’s not in the works at the moment. There are lots of great resources out there, though. Unfortunately, those resources are not usually in video form. I guess I’d better get on it and fill that void, huh?

      Thanks for the suggestion!

Leave a Reply to chiara Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.