Zero-Width Characters for Complex Scripts in FontForge

Configuring zero-width characters in FontForge is essential for designing complex scripts such as Arabic, Devanagari, and Thai, where combining marks, diacritics, and control characters dictate proper text shaping. This guide covers how to accurately assign Unicode values, set advance metrics to zero, configure OpenType Glyph Definition (GDEF) tables, and establish anchor positioning for seamless script rendering in modern text shaping engines.

1. Create the Glyph and Assign the Unicode Codepoint

  1. Open your font project in FontForge.
  2. Navigate to View > Go to and enter the specific hex codepoint for your character. For invisible control characters, use standard codes such as U+200C (Zero-Width Non-Joiner / ZWNJ) or U+200D (Zero-Width Joiner / ZWJ). For combining marks or vowel signs (matras), locate the script-specific Unicode slot (e.g., U+094D for Devanagari Virama).
  3. If the slot is empty, double-click to open the glyph canvas, or right-click and select Glyph Info to confirm the correct name and Unicode mapping.

2. Set the Advance Width to Zero

A zero-width character must not advance the text cursor horizontally when rendered.

  1. Select the glyph in the font matrix or open it in the glyph editor window.
  2. Go to Metrics > Set Width... from the top menu.
  3. In the dialog box, enter 0 and click OK.
  4. Alternatively, open the Metrics Window (Metrics > New Metrics Window), type the character, and manually drag the right side bearing (RSB) line until the width displays as 0.

Note for invisible control characters (ZWJ/ZWNJ): The glyph should contain no outlines or contours—only a width of 0.

Note for combining marks: The glyph should contain your drawn outline. The advance width remains 0, while the visual contours will sit outside the zero-width boundary (often requiring negative left side bearings) so they overlap correctly with the base glyph.

3. Classify the Glyph in the GDEF Table

Complex text shapers (such as HarfBuzz and DirectWrite) rely on OpenType Glyph Definition (GDEF) tables to determine whether a glyph is a base, a mark, or a ligature.

  1. Go to Element > Font Info.
  2. Select Lookups from the left-hand panel, then switch to the GDEF tab.
  3. Under Glyph Class Def, ensure your zero-width combining marks are categorized as Mark.
  4. If using a mark attachment class, assign the glyphs to their respective mark sets so the shaping engine correctly skips or includes them during contextual lookups.

4. Implement Anchor Points for Mark Positioning (GPOS)

For visible zero-width marks, you must define anchor points to position them relative to base consonants:

  1. In Element > Font Info > Lookups, navigate to the GPOS tab.
  2. Click Add Lookup, choose Mark-to-Base Positioning (mark), and add a subtable.
  3. Open the base glyph canvas and place an anchor point via Point > Add Anchor, designating it as a "Base" point (e.g., top).
  4. Open the zero-width mark canvas, add an anchor point with the matching name (top), and set its type to "Mark".
  5. Align the mark anchor to the exact connection coordinate relative to the base glyph. Repeat this process for Mark-to-Mark (mkmk) lookups if diacritics stack vertically.

5. Configure Contextual Substitutions for ZWJ/ZWNJ (GSUB)

If the zero-width character is an invisible joiner used to force or suppress ligatures:

  1. Go to Element > Font Info > Lookups > GSUB.
  2. Create a Chaining Contextual Substitution or a standard Ligature lookup under features like akhn (Akhand), half (Half Forms), or ccmp (Glyph Composition/Decomposition).
  3. Define lookup rules where the presence of U+200D substitutes a base character with its half-form or explicit conjunct, and rules where U+200C blocks standard script ligation.

6. Verify and Export

  1. Open Metrics > New Metrics Window to test the character sequences.
  2. Input combinations of base characters, joiners, and zero-width marks to ensure the cursor does not advance unnecessarily and that attachments snap to the defined anchor points.
  3. Export the font as OpenType (.otf or .ttf) via File > Generate Fonts, and validate the compiled OpenType layout using external shaper tools such as hb-view or hb-shape.