googlefonts / googlefonts/fontc

glyphs v2 sources with a "toggle" axis (to distinguish regular and italic)

Open
#1,994 1 comment 0 reactions 0 assignees View on GitHub
crater
Dominant language
Rust
Stars
193
Forks
21
Avg merge
1d 17h
Merged PRs (30d)
65

Description

fontc crashes when compiling `.glyphs` files that use the Width axis as a binary 0/1 toggle to separate upright and italic masters in a single source. This is a Glyphs 2 pattern used by several Google Fonts families, e.g:

```bash
python3 -m ttx_diff 'https://github.com/m4rc1e/Chakra-Petch?6176529d05#source/Chakra Petch.glyphs'
```

The basic idea here as I understand it is that the naive compilation of these fonts produces a file that contains both the upright and the italic, but with only one of these reachable; when built with gftools, `varLib.instancer` is called to split this into the final two fonts.

I don't have a strong opinion on how this should be addressed? There's an argument to just fix it in source, by adding the `Axes` customParameter. Alternatively, we could just try to match fontmake; finally we could split this so that there are multiple configs, and have some config argument that tells the compiler to pin an axis or something (although this sounds pretty bad, as I type it out.)

full claude diagnosis below:

## full claude diagnosis
### Affected fonts

All 7 use the same structure: upright masters at `widthValue=0`, italic masters at `widthValue=1`, no explicit `Axes` customParameter.

| Font | Repo |
|------|------|
| Chakra Petch | `m4rc1e/Chakra-Petch` |
| KoHo | `cadsondemak/Koho` |
| Kodchasan | `cadsondemak/Kodchasan` |
| Fahkwang | `cadsondemak/Fah-Kwang` |
| Bai Jamjuree | `cadsondemak/Bai-Jamjuree` |
| Sarabun | `cadsondemak/Sarabun` |
| K2D | `cadsondemak/K2D` |

Notably, 3 other fonts use the same toggle pattern but have an explicit `Axes` customParameter mapping Width to `{Name=Italic, Tag=ital}`. fontc handles those correctly (Niramit and Nunito produce identical output).

### What the font source is doing

These sources put both upright and italic masters in a single `.glyphs` file, using the Width dimension as a build-time toggle (0 = upright, 1 = italic). The intention is **not** a variable wdth axis — gftools builds these by compiling a single VF and then slicing it into separate upright and italic variable fonts using `fonttools.varLib.instancer`.

### What fontmake does

fontmake doesn't crash. All 12 instances map to user-space width 100 (OS/2 width class "Medium (normal)"), so the instance-based axis mapping collapses to `{user 100 -> design 1}`. glyphsLib derives axis bounds from user-space mapping keys, producing a degenerate wdth axis (min=max=default=100). The upright masters (design=0) are in the designspace but unreachable in user space.

This degenerate VF is not useful on its own, but it's a necessary intermediate artifact — gftools then slices it to produce the final upright/italic fonts.

### What fontc does

`to_ir_axis` in `glyphs2fontir/src/toir.rs` computes axis min/max from master **design** coordinates (0.0 and 1.0), then calls `find_by_design_coord` to look up each in the mapping. The mapping only contains `design=1.0`, so the lookup for the default at `design=0.0` fails.

The core mismatch:
- **fontc**: design coords -> look up in mapping -> user coords (crashes if mapping is incomplete)
- **glyphsLib**: mapping keys ARE user coords -> compute axis range directly (always works)

### Suggested fix

When instance-based mappings don't cover all master design coordinates, `to_ir_axis` should derive axis min/max/default from user-space mapping values (matching glyphsLib), rather than requiring the mapping to contain entries for every master design coordinate. This allows degenerate axes where min == max == default.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start in glyphs2fontir/src/toir.rs at to_ir_axis and trace how instance-based mappings are used to derive axis bounds. Compare the design-coordinate lookup with the user-space mapping behavior described in the issue, then verify that the listed toggle-axis sources compile without a panic and produce the expected degenerate axis output.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
58/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.