FontForge Feature Inheritance Across Font Styles

Managing OpenType feature inheritance across multiple font styles in FontForge requires decoupling your layout logic from individual font files. Because FontForge stores OpenType Layout (GSUB/GPOS) data per .sfd (Spline Font Database) file rather than via a global dynamic project file, maintaining feature consistency across Regular, Bold, or Italic cuts relies on external feature files (.fea), lookup exports, and Python automation. This guide details how to implement a modular feature workflow that prevents repetitive manual configuration and keeps your font family synchronized.

The Strategy: Decoupling Logic with Adobe Feature Files

The most robust way to inherit and share OpenType layout features across multiple styles in FontForge is using external Adobe Feature File syntax (.fea). By centralizing shared substitutions into external text files, child styles can inherit parent feature definitions directly.

1. Structure Modular Feature Files

Instead of writing OpenType code inside FontForge’s internal GUI editors for every style, create a directory for .fea files:

  • common.fea: Stores shared features applicable to the entire family (e.g., standard ligatures liga, localized forms locl, tabular figures tnum, and discretionary ligatures dlig).
  • regular.fea: Contains code specific to the Regular weight.
  • bold.fea: Contains code specific to the Bold weight.

Using the include() directive, style-specific files inherit the parent file:

# In bold.fea
include(common.fea);

# Additional Bold-only substitution rules go here
feature ss01 {
    sub a by a.alt;
} ss01;

2. Import Feature Files into FontForge Styles

To apply your modular features to each style file:

  1. Open your style-specific font file in FontForge (e.g., MyFont-Bold.sfd).
  2. Go to File > Merge Feature Info....
  3. Select your corresponding feature file (e.g., bold.fea).
  4. FontForge parses the code and populates the GSUB/GPOS tables, automatically including everything defined in the parent common.fea.

Alternative GUI Method: Lookup Export and Import

If you prefer using the native FontForge interface without writing external text files:

  1. Establish the Master Style: Configure all GSUB substitutions (such as small caps, fractions, and ligatures) in your base style under Element > Font Info > Lookups.
  2. Export Lookups: Select a lookup in the list and click Save Feature to export it as an external file.
  3. Inherit into Other Styles:
    • Open the target style (e.g., Italic).
    • Go to Element > Font Info > Lookups.
    • Click Add Lookup, then select Import to load the exported lookup file.

Note: Lookups that rely on specific glyph geometry (like GPOS pair kerning) should generally not be shared wholesale across radically different weights, whereas substitution features (GSUB) inherit seamlessly.


Automating Inheritance Across Styles via Python

When managing larger families, updating features manually across each .sfd file is prone to human error. FontForge’s built-in Python scripting environment allows you to apply inherited features programmatically across the entire family.

Create a script named apply_features.py:

import fontforge
import glob

# Path to the base inherited feature file
common_fea = "features/common.fea"

# Target all SFD files in the directory
font_files = glob.glob("*.sfd")

for file_path in font_files:
    font = fontforge.open(file_path)
    
    # Merge the inherited features into the current style
    font.mergeFeature(common_fea)
    
    # Save the updated SFD
    font.save()
    font.close()
    print(f"Applied inherited features to {file_path}")

Run this script inside FontForge:

fontforge -script apply_features.py

Critical Rules for Smooth Feature Inheritance

  • Enforce Strict Glyph Naming: All inherited rules rely on exact glyph name matching. If common.fea references f_i or a.sc, every style in the family must use those exact names, or FontForge will reject the feature compilation.
  • Separate Substitution from Positioning: Keep GSUB (ligatures, alternates) separate from GPOS (kerning, mark-to-base). Substitution logic is typically 100% reusable across styles, whereas positioning metrics depend on individual glyph shapes and weights.
  • Compile at Build Time: Avoid manually saving complex lookups into .sfd files during early design phases. Instead, keep your .sfd files clean and use a Python build script to merge the inherited .fea definitions whenever you generate final OTF/TTF binaries.