Control STAT table output in Glyphs? Specific problems with Optical Size

My basic question is: is there a way (such as a font-level custom parameter) to specify the exact STAT table I want to build, or do I have to get there through various custom parameters in Masters & Exports? If the latter is the case, is there a way to achieve the correct Optical Size entries I’m going for? Details below…

I have a Glyphs file that:

  • has Optical Size and Weight axes
  • outputs to one variable font and two static font families
  • has style names like “Semi Bold” which have spaces in them
  • has “Text” styles that are meant to elide the name “Text”

Lately, I’m building most fonts with the GF Tools Builder, but I’m exporting with Glyphs in this case because the GF Tools Builder doesn’t properly support Localized Family Names, in order to build into one variable font but multiple static families. (Technically, I think the limitation is in GlyphsLib).

However, in this setup, I’m having trouble generating the correct STAT table in the variable export. In YAML terms, here’s the STAT table I’m hoping to achieve:

  - name: Optical Size
    tag: opsz
    values:
      - name: Text
        value: 14
        flags: 2 # elidable name
      - name: Display
        value: 144
  - name: Weight
    tag: wght
    values:
      - name: Extra Light
        value: 200
      - name: Light
        value: 300
      - name: Regular
        value: 400
      - name: Medium
        value: 500
      - name: Semi Bold
        value: 600
      - name: Bold
        value: 700
      - name: Extra Bold
        value: 800
      - name: Black
        value: 900

However, by default, Glyphs is outputting this:

<STAT>
    <Version value="0x00010001"/>
    <DesignAxisRecordSize value="8"/>
    <!-- DesignAxisCount=3 -->
    <DesignAxisRecord>
      <Axis index="0">
        <AxisTag value="opsz"/>
        <AxisNameID value="256"/>  <!-- Optical size -->
        <AxisOrdering value="0"/>
      </Axis>
      <Axis index="1">
        <AxisTag value="wght"/>
        <AxisNameID value="257"/>  <!-- Weight -->
        <AxisOrdering value="1"/>
      </Axis>
      <Axis index="2">
        <AxisTag value="ital"/>
        <AxisNameID value="274"/>  <!-- Italic -->
        <AxisOrdering value="2"/>
      </Axis>
    </DesignAxisRecord>
    <!-- AxisValueCount=11 -->
    <AxisValueArray>
      <AxisValue index="0" Format="1">
        <AxisIndex value="0"/>
        <Flags value="0"/>
        <ValueNameID value="260"/>  <!-- Light -->
        <Value value="14.0"/>
      </AxisValue>
      <AxisValue index="1" Format="1">
        <AxisIndex value="0"/>
        <Flags value="0"/>
        <ValueNameID value="266"/>  <!-- Bold -->
        <Value value="144.0"/>
      </AxisValue>
      <AxisValue index="2" Format="1">
        <AxisIndex value="1"/>
        <Flags value="0"/>
        <ValueNameID value="260"/>  <!-- Light -->
        <Value value="200.0"/>
      </AxisValue>
      <AxisValue index="3" Format="1">
        <AxisIndex value="1"/>
        <Flags value="0"/>
        <ValueNameID value="260"/>  <!-- Light -->
        <Value value="300.0"/>
      </AxisValue>
      <AxisValue index="4" Format="3">
        <AxisIndex value="1"/>
        <Flags value="2"/>  <!-- ElidableAxisValueName -->
        <ValueNameID value="2"/>  <!-- Regular -->
        <Value value="400.0"/>
        <LinkedValue value="700.0"/>
      </AxisValue>
      <AxisValue index="5" Format="1">
        <AxisIndex value="1"/>
        <Flags value="0"/>
        <ValueNameID value="262"/>  <!-- Medium -->
        <Value value="500.0"/>
      </AxisValue>
      <AxisValue index="6" Format="1">
        <AxisIndex value="1"/>
        <Flags value="0"/>
        <ValueNameID value="272"/>  <!-- Semi -->
        <Value value="600.0"/>
      </AxisValue>
      <AxisValue index="7" Format="1">
        <AxisIndex value="1"/>
        <Flags value="0"/>
        <ValueNameID value="266"/>  <!-- Bold -->
        <Value value="700.0"/>
      </AxisValue>
      <AxisValue index="8" Format="1">
        <AxisIndex value="1"/>
        <Flags value="0"/>
        <ValueNameID value="273"/>  <!-- Extra -->
        <Value value="800.0"/>
      </AxisValue>
      <AxisValue index="9" Format="1">
        <AxisIndex value="1"/>
        <Flags value="0"/>
        <ValueNameID value="270"/>  <!-- Black -->
        <Value value="900.0"/>
      </AxisValue>
      <AxisValue index="10" Format="3">
        <AxisIndex value="2"/>
        <Flags value="2"/>  <!-- ElidableAxisValueName -->
        <ValueNameID value="275"/>  <!-- Roman -->
        <Value value="0.0"/>
        <LinkedValue value="1.0"/>
      </AxisValue>
    </AxisValueArray>
    <ElidedFallbackNameID value="2"/>  <!-- Regular -->
  </STAT>

The basic Glyphs output has a few issues:

  1. Weight names are getting chopped up, so “Semi Bold” becomes just “Semi.”
  2. Weight names are also being used where Optical Size names should be used. Instead of “Text” and “Display,” it gives “Light = opsz 14” and “Bold = opsz 144”.
  3. It adds an Italic axis, when this family doesn’t have any Italics. I’m not sure whether this matters, though. I’m not as worried about it.

I’ve been able to solve Issue 1 by adding “Style Name as STAT Entry” parameters to the Text Exports, like this:

However, I’m so far unable to figure out a way to specify opsz location names. When I solve for Issue 1, I get the Weight names I want, but the Optical Size location names disappear from the output table, altogether.

<STAT>
    <Version value="0x00010001"/>
    <DesignAxisRecordSize value="8"/>
    <!-- DesignAxisCount=3 -->
    <DesignAxisRecord>
      <Axis index="0">
        <AxisTag value="opsz"/>
        <AxisNameID value="256"/>  <!-- Optical size -->
        <AxisOrdering value="0"/>
      </Axis>
      <Axis index="1">
        <AxisTag value="wght"/>
        <AxisNameID value="257"/>  <!-- Weight -->
        <AxisOrdering value="1"/>
      </Axis>
      <Axis index="2">
        <AxisTag value="ital"/>
        <AxisNameID value="272"/>  <!-- Italic -->
        <AxisOrdering value="2"/>
      </Axis>
    </DesignAxisRecord>
    <!-- AxisValueCount=9 -->
    <AxisValueArray>
      <AxisValue index="0" Format="1">
        <AxisIndex value="1"/>
        <Flags value="0"/>
        <ValueNameID value="258"/>  <!-- Extra Light -->
        <Value value="200.0"/>
      </AxisValue>
      <AxisValue index="1" Format="1">
        <AxisIndex value="1"/>
        <Flags value="0"/>
        <ValueNameID value="260"/>  <!-- Light -->
        <Value value="300.0"/>
      </AxisValue>
      <AxisValue index="2" Format="3">
        <AxisIndex value="1"/>
        <Flags value="2"/>  <!-- ElidableAxisValueName -->
        <ValueNameID value="2"/>  <!-- Regular -->
        <Value value="400.0"/>
        <LinkedValue value="700.0"/>
      </AxisValue>
      <AxisValue index="3" Format="1">
        <AxisIndex value="1"/>
        <Flags value="0"/>
        <ValueNameID value="262"/>  <!-- Medium -->
        <Value value="500.0"/>
      </AxisValue>
      <AxisValue index="4" Format="1">
        <AxisIndex value="1"/>
        <Flags value="0"/>
        <ValueNameID value="264"/>  <!-- Semi Bold -->
        <Value value="600.0"/>
      </AxisValue>
      <AxisValue index="5" Format="1">
        <AxisIndex value="1"/>
        <Flags value="0"/>
        <ValueNameID value="266"/>  <!-- Bold -->
        <Value value="700.0"/>
      </AxisValue>
      <AxisValue index="6" Format="1">
        <AxisIndex value="1"/>
        <Flags value="0"/>
        <ValueNameID value="268"/>  <!-- Extra Bold -->
        <Value value="800.0"/>
      </AxisValue>
      <AxisValue index="7" Format="1">
        <AxisIndex value="1"/>
        <Flags value="0"/>
        <ValueNameID value="270"/>  <!-- Black -->
        <Value value="900.0"/>
      </AxisValue>
      <AxisValue index="8" Format="3">
        <AxisIndex value="2"/>
        <Flags value="2"/>  <!-- ElidableAxisValueName -->
        <ValueNameID value="273"/>  <!-- Roman -->
        <Value value="0.0"/>
        <LinkedValue value="1.0"/>
      </AxisValue>
    </AxisValueArray>
    <ElidedFallbackNameID value="2"/>  <!-- Regular -->
  </STAT>

My current workaround is to use gftools gen-stat, pointing to my desired STAT table as a YAML file, plus the already-built variable font. However, this isn’t an ideal approach, as it’s an extra step and would be easy to forget in future builds.

I imagine one potential answer is to add “Text” to the Style Names of the Text weights, but:

  • I want the variable font to only have Weight names (and I’m running a script to de-duplicate the instances in fvar, post-build), and…
  • I want the static Text fonts to not have the word “Text” in their family or style names.

So, if there is a way I’m missing to set this data up in Glyphs, I’d love to know about it! If there’s not, I’m just here to say that such a feature would be much appreciated.

I’m on Glyphs 3.2.3, by the way.

Thanks for any insights!

the first step would be to at “variable style name” entries in all “text” instances to contain “Text” and “Display”. Can you try that and report back what happens? What will also improve your fvar instances.

1 Like

Hi Georg, thanks for the quick response!

I’ve tried to test out my first interpretation of your suggestion, but now I’m not quite sure I understand properly.

As an example, what should the “variable style name” entry of the [Text] Semi Bold instance be?

A couple of things I have tested:

  1. Keeping everything else as-is, but adding “Variable Style Names” entries for each instance, with values like “Text Semi Bold” for the opsz=14 wght=600 instance and “Display Medium” at opsz=144 wght=500.
  2. Setting the main, basic “Style Name” entries to include “Text” and “Display” fragments, then also adding “Localized Style Name” entries such as “Semi Bold” for opsz=14 weight=600, as well as in the “Variable Style Names” entry.

Neither approach achieved my goals, as outlined in the first comment.

But, again, I now wonder if Test 1 was misinterpreting your suggestion.

In case it’s helpful, the results of Test 1 were as follows:

<STAT>
    <Version value="0x00010001"/>
    <DesignAxisRecordSize value="8"/>
    <!-- DesignAxisCount=3 -->
    <DesignAxisRecord>
      <Axis index="0">
        <AxisTag value="opsz"/>
        <AxisNameID value="256"/>  <!-- Optical size -->
        <AxisOrdering value="0"/>
      </Axis>
      <Axis index="1">
        <AxisTag value="wght"/>
        <AxisNameID value="257"/>  <!-- Weight -->
        <AxisOrdering value="1"/>
      </Axis>
      <Axis index="2">
        <AxisTag value="ital"/>
        <AxisNameID value="287"/>  <!-- Italic -->
        <AxisOrdering value="2"/>
      </Axis>
    </DesignAxisRecord>
    <!-- AxisValueCount=9 -->
    <AxisValueArray>
      <AxisValue index="0" Format="1">
        <AxisIndex value="1"/>
        <Flags value="0"/>
        <ValueNameID value="258"/>  <!-- Text Extra Light -->
        <Value value="200.0"/>
      </AxisValue>
      <AxisValue index="1" Format="1">
        <AxisIndex value="1"/>
        <Flags value="0"/>
        <ValueNameID value="260"/>  <!-- Text Light -->
        <Value value="300.0"/>
      </AxisValue>
      <AxisValue index="2" Format="3">
        <AxisIndex value="1"/>
        <Flags value="0"/>
        <ValueNameID value="286"/>  <!-- Text -->
        <Value value="400.0"/>
        <LinkedValue value="700.0"/>
      </AxisValue>
      <AxisValue index="3" Format="1">
        <AxisIndex value="1"/>
        <Flags value="0"/>
        <ValueNameID value="264"/>  <!-- Text Medium -->
        <Value value="500.0"/>
      </AxisValue>
      <AxisValue index="4" Format="1">
        <AxisIndex value="1"/>
        <Flags value="0"/>
        <ValueNameID value="266"/>  <!-- Text Semi Bold -->
        <Value value="600.0"/>
      </AxisValue>
      <AxisValue index="5" Format="1">
        <AxisIndex value="1"/>
        <Flags value="0"/>
        <ValueNameID value="268"/>  <!-- Text Bold -->
        <Value value="700.0"/>
      </AxisValue>
      <AxisValue index="6" Format="1">
        <AxisIndex value="1"/>
        <Flags value="0"/>
        <ValueNameID value="270"/>  <!-- Text Extra Bold -->
        <Value value="800.0"/>
      </AxisValue>
      <AxisValue index="7" Format="1">
        <AxisIndex value="1"/>
        <Flags value="0"/>
        <ValueNameID value="272"/>  <!-- Text Black -->
        <Value value="900.0"/>
      </AxisValue>
      <AxisValue index="8" Format="3">
        <AxisIndex value="2"/>
        <Flags value="2"/>  <!-- ElidableAxisValueName -->
        <ValueNameID value="288"/>  <!-- Roman -->
        <Value value="0.0"/>
        <LinkedValue value="1.0"/>
      </AxisValue>
    </AxisValueArray>
    <ElidedFallbackNameID value="2"/>  <!-- Regular -->
  </STAT>

The problems with this are:

  • The STAT labels should only include weight fragments
  • There are still no specific opsz labels included

The fvar table now shows that the family has entries for every static export, like “Text Semi Bold” and “Display Regular.” As I understand it, this would prevent auto optical sizing in Mac apps, which is only possible if a VF with optical sizing excludes optical size-based instances.

A good example of this is Roboto Flex. It has a very impactful Optical Size axis, but it only includes instances for weights and italics. For example, here is “ExtraBlack” in the 9pt opsz (zoomed in) versus the 144pt opsz (at default zoom):

(Apologies if this is obvious / old news to you. I am also trying to explain this for others who might come along and read this later.)

Best way currently is the Post Production mekkablue script Read and Write STAT. Run it after export and it will add Axis Values parameters to your variable font setting. Edit them accordingly and run the script again (then it will write them to your most recent export).

Okay, thank you for that answer! In my current case, my command-line workaround (gftools gen-stat) seems somewhat simpler, but this might come in handy in the future.

Hopefully, there might be a more native way to set up STAT tables, someday, but I know you have a lot needs to balance in running the app. I really appreciate your great work, and also your help here.

“Text Semi Bold” or “Semi Bold Text”

Can you send me the file (you can remove most glyphs and replace the Family name if needed).

Sure thing – done!