fontc Crater Analysis
Analysis of fontc vs fontmake compilation differences to prioritize fontc bugfixes. Data from googlefonts/fontc_crater.
Progress Over Time
OpenType Table Diff Frequency
Which tables differ most often between fontc and fontmake output. Color indicates average similarity (green=high, red=low). "Impact" = targets that would become identical if this table alone were fixed.
Fix Prioritization
Ranked by number of affected targets. Issues are from fontc GitHub annotations; table entries are unannotated patterns.
Diff Profile Clusters
Targets grouped by their set of differing tables. Targets with the same diff signature likely share a root cause.
Failure Breakdown
All Non-Identical Targets
Library Sources Tracking
Progress tracking for upstream repository documentation
Status Breakdown
Progress Over Time
Upstream Repository Archive
Show repos not yet archived (0)
Data generated: --
google/fonts had a valid repository_url and commit hash in METADATA.pb. This audit informed the design of the reproducible build system. The data reflects a one-time snapshot and is no longer actively updated — the Build System page now provides live, continuously-updated verification.
Repository Audit
Verifying METADATA.pb repository_url and commit hash
Designers
Google Fonts designer profiles
Pending Pull Requests
PRs to be created in google/fonts repository
Pending Questions
Questions that need answers from designers or font engineers
Message Log
Friday Status Update
Weekly status report for Google Fonts team call
Build Approaches
Classification of upstream font repositories by build system and source format
Each upstream font repository uses a different combination of build tools and source formats to compile binary font files. Understanding these patterns helps with onboarding, quality assurance, and migration planning.
Build System Distribution
Source Format Distribution
Build Approach Descriptions
Data generated: --
Reproducible Build System
Validates METADATA.pb source stanzas by building fonts from upstream sources and comparing against google/fonts binaries
How the Build System Works
The reproducible build system lives in google/fonts/build_tools/reproducible_build.py. For each font family, it:
- Reads the source commit and repository URL from
METADATA.pb - Downloads a source snapshot from GitHub at that exact commit
- Runs any prebuild commands (e.g.
glyphs2ufo, custom Python scripts) - Builds with
gftools-builderusing the family'sconfig.yaml - Compares the output byte-for-byte against what's shipped in
google/fonts
Build Registry — All per-family build configuration is stored in google/fonts/build_tools/build_registry.json. Each family entry contains:
enabled— whether the family is included in batch buildsisolation—"shared"(uses the main gftools venv) or"custom"(per-family venv with pinned tool versions)overrides.requirements— pinned pip packages for custom venvs (e.g.["gftools==0.9.79", "fonttools==4.56.0"])prebuild— shell commands to run before building (source patching, format conversion)build_timeout— per-family timeout in seconds (default 600)skip_build— for families that ship pre-built fonts in their upstream reporeproducible_build— the comparison result (yes,compiler-version,build-failure, etc.)source_format,config_yaml_source,failure_category— diagnostic metadata
Achieving byte-identical builds requires matching the exact tool versions used when the font was originally built. Since google/fonts CI doesn't record pip freeze outputs, we use software archaeology: extracting tool version hints from the font binaries (ttfautohint version in the name table), cross-referencing git commit dates with PyPI release timelines, and testing version combinations per family. Families using custom venvs with pinned versions that produce byte-identical output are recorded in the registry with isolation: "custom".
Why most families aren't byte-identical: The main blockers are (1) GPOS table compilation differences across fonttools versions, (2) gftools-fix post-processing that adds postscriptNameID attributes and renumbers name table entries, and (3) glyphsLib glyph ordering differences for .glyphs-source families. These produce functionally identical fonts with different binary encoding.
- Families Tested = Byte-Identical + Compiler Version + Build Failure + other. Untested = 1266 − Tested.
- Reflow risk is counted per font file (a family may contain multiple files).
Data generated: --
Font Normalization Pipeline
Canonical normalization of font binaries to prove functional equivalence between reference and rebuilt fonts
When we rebuild a font from source, the output often differs from the google/fonts reference binary — not because anything is wrong, but because different tool versions encode the same data differently. The normalization pipeline transforms both fonts into a canonical binary form, stripping encoding choices that don't affect functionality. If the normalized forms match, the fonts are provably equivalent.
Pipeline Overview
Both the reference font and the rebuilt font pass through the same sequence of normalization steps. Each step is safe (preserves all functional behavior) and deterministic (same input always produces the same output).
reference.ttf ──┐ ┌── normalized_ref.ttf
├── font-normalize ──┤ ══ byte compare ══
rebuilt.ttf ────┘ └── normalized_built.ttf
Normalization Steps
Each step has a clear safety argument for why normalized and original fonts are interchangeable.
Step 1: Strip DSIG table
| What | Remove the DSIG (Digital Signature) table entirely. |
| Why safe | Google Fonts ships fonts with a 4-byte DSIG stub (empty signature). No browser, OS, or application validates DSIG in web fonts. The OpenType spec marks it as optional. Removing it has zero effect on rendering, layout, or any observable behavior. |
| Determinism | Trivially deterministic — table is deleted unconditionally. |
Step 2: Normalize head table timestamps
| What | Set head.modified and head.created to a fixed canonical value (epoch 0). |
| Why safe | These timestamps record when the font was compiled, not what it contains. No text shaper, rasterizer, or layout engine reads these fields. The OpenType spec says modified is "number of seconds since 12:00 midnight, January 1, 1904" — purely informational. Browsers, operating systems, and applications never use these values for rendering decisions. |
| Determinism | Both values set to the same constant → always identical. |
Step 3: Normalize name table
| What | Remove platform 1 (Macintosh) name records. Renumber name IDs ≥256 sequentially. Sort remaining records by (platformID, encodingID, languageID, nameID). |
| Why safe | Mac platform removal: Platform 1 records are legacy — all modern software uses platform 3 (Windows/Unicode). Apple's own documentation recommends platform 3. Google Fonts serves web fonts where only platform 3 is relevant. ID renumbering: Name IDs ≥256 are "font-specific" per the spec — their numeric value is meaningless; only their content and the references to them (from fvar, STAT) matter. Renumbering + updating references preserves all semantics. Sorting: The name table spec does not require a specific order; record order is purely a serialization choice. |
| Determinism | Deletion rules are fixed, renumbering is sequential from 256, sort order is lexicographic on the 4-tuple key. |
Step 4: Normalize GPOS/GDEF/GSUB layout tables
| What | Decompile layout tables via fontTools, then recompile. This forces fontTools to choose its own canonical subtable formats (PairPos Format 1 vs 2, Extension vs inline, ClassDef ordering). |
| Why safe | OpenType layout tables encode rules (kerning pairs, mark positioning, ligature substitutions) that text shapers interpret. The rules are preserved exactly — only the binary encoding changes. For example, kerning "AV = -80" can be stored as PairPosFormat1 (individual pair) or PairPosFormat2 (class-based) — both produce identical shaping output. fontTools' decompile→recompile round-trip preserves all rules. This is the same approach used by otl-normalizer in the fontc project (by Rod Sheeter, Colin Rofls et al.). |
| Determinism | fontTools compilation is deterministic for a given version. Both fonts are recompiled with the same fontTools, so the binary encoding choices are identical. |
Step 5: Normalize gvar (variable font deltas)
| What | Decompile the gvar table (variation deltas), disable IUP optimization, recompile. This stores explicit deltas for all points rather than relying on Interpolation of Untouched Points. |
| Why safe | IUP (Interpolation of Untouched Points) is a compression technique: some point deltas are omitted because they can be inferred from neighboring points. Different fontTools versions choose different sets of points to omit — all producing identical rendering. Disabling IUP and storing all deltas explicitly is the uncompressed, canonical form. The resulting font renders identically at all axis positions. |
| Determinism | With IUP disabled, every point has an explicit delta — no optimizer choices remain. The output is uniquely determined by the variation data. |
Step 6: Normalize glyph order
| What | Sort glyphs into a canonical order: .notdef first (required by spec), then by Unicode codepoint (lowest first), then by glyph name (alphabetical) for non-encoded glyphs. Update all internal references (cmap, GSUB, GPOS, loca, hmtx, etc.). |
| Why safe | Glyph order is an internal implementation detail. Text shapers access glyphs via the cmap table (Unicode → glyph ID mapping), never by raw glyph index. All internal references are updated consistently by fontTools' setGlyphOrder(). The only requirement is that .notdef is glyph 0, which the canonical order preserves. Different versions of glyphsLib produce different glyph orders from the same .glyphs source — this normalization eliminates that variation. |
| Determinism | Sort key is (has_codepoint, lowest_codepoint, glyph_name) — a total order with no ties possible (glyph names are unique). |
Step 7: Reserialize with canonical table order
| What | Save the font with reorderTables=True (OpenType 1.4 recommended order) and recalculate head.checkSumAdjustment. |
| Why safe | Table order in the SFNT container is not semantically meaningful — font parsers locate tables by tag from the table directory, not by position. The OpenType spec recommends a specific order for performance (tables accessed first should come first) but does not require it. checkSumAdjustment is a whole-file checksum that is recalculated automatically. |
| Determinism | Table order follows the fixed OpenType 1.4 recommendation. Checksum is computed from the byte content. |
What Is NOT Normalized
These aspects are not touched by the pipeline because they affect rendering or functionality:
- Glyph outlines (
glyf/CFF) — coordinate values, curve types, point counts - Advance widths (
hmtx) — any difference here means real reflow risk - Line metrics (
hhea,OS/2) — affect line spacing - Hinting instructions (
fpgm,prep,cvt, per-glyph hints) — affect rendering at small sizes - Layout rule semantics — which kerning pairs exist, what values they have
- Unicode mappings (
cmap) — which characters map to which glyphs
If the normalized fonts differ, the difference is in something that actually matters.
Prior Art
- otl-normalizer (fontc repo, Rust) — Normalizes GPOS/GDEF to canonical text for diffing. Covers kerning and mark positioning. Our Step 4 is the binary equivalent of this approach.
- ttx_diff (fontc repo) — Compares fontc vs fontmake output by normalizing "expected differences" before TTX diffing. Similar philosophy but specific to the fontc comparison use case.
- diffenator2 (Marc Foley) — Visual/rendering comparison at the pixel level. Complementary to binary normalization — diffenator2 proves visual equivalence, our pipeline proves structural equivalence.
- fontTools
reorderFontTables()— Canonical table ordering, used in our Step 7. - ufonormalizer — Normalizes UFO source files. Our pipeline normalizes compiled binaries.
Results
Of 1,267 families: 319 are byte-identical (25.2%), 34 more match after normalization (2.7%), and 79 more are within 100 bytes of matching (6.2%). Combined: 353 families (27.9%) are provably functionally equivalent to the google/fonts reference binaries.
34 Normalized-Match Families
adlamdisplay, annapurnasil, anton, anuphan, aubrey, bahiana, bytesized, capriola, chivomono, comicneue, cormorantupright, dmmono, epundasans, francoisone, harmattan, homenaje, londrinaoutline, londrinashadow, lxgwmarkergothic, notable, sansitaswashed, shizuru, solitreo, sono, stacksansheadline, stacksansnotch, stacksanstext, tasaexplorer, tirobangla, tirogurmukhi, tirokannada, tirotamil, voces, wireone
79 Close Matches (≤100 bytes after normalization)
These families differ by only a few bytes after normalization — typically single glyph coordinate rounding or a head.flags bit difference.
Closest: bahianita (3 bytes), barriecito (3 bytes), cause (3 bytes), badscript (4 bytes), coiny (4 bytes), farro (4 bytes), jacquard12 (4 bytes), triodion (4 bytes).
Roadmap: Possible Next Steps Toward 100%
These are candidate improvements under investigation. Each requires careful analysis to confirm safety before implementation.
Tier 1: Quick Wins — Additional Normalization Steps
head.flags bit 3
Bit 3 ("instructions may alter advance widths") is set by ttfautohint and is purely informational — it advises the rasterizer to be careful but does not affect actual output. Clearing this bit would convert at least 9 families (bahianita, barriecito, farro, and others that differ by only 2–3 bytes after normalization, all in head.flags).
Status: needs verification that no rasterizer changes behavior based on this bit alone.
name table version string encoding
Some families (e.g. cause) differ by a single byte in the name table after normalization. This is likely a character encoding or whitespace difference in the version string. Normalizing version strings to a canonical encoding could fix these.
Status: needs investigation of what specific name record differs.
OS/2 informational fields
Fields like panose (font classification), achVendID (vendor identifier), and fsType (embedding flags) are metadata that doesn't affect text rendering. Different gftools-fix versions may set these differently.
Status: needs careful enumeration of which OS/2 fields are truly non-functional.
Tier 2: Medium Effort — Deeper Normalization
glyf table padding and encoding
Some families differ by 2–4 bytes in the glyf table due to padding/alignment differences, not actual coordinate changes. The glyf binary format allows variable-length padding between glyphs. A decompile→recompile round-trip through fontTools might normalize this, but needs verification that it doesn't alter actual point coordinates.
Status: 33 families in the 6–20 byte range may benefit. Needs investigation of whether glyf diffs are padding-only or include real coordinate changes.
The current Step 4 recompiles GPOS through fontTools, but if the decompiled representation already differs between versions (different kerning class definitions, different lookup ordering from different glyphsLib versions), the recompile still produces different output. A deeper normalization would canonicalize class memberships (sort glyph members), sort lookups deterministically, and normalize value record formats.
This is the approach taken by otl-normalizer, but that tool outputs text, not canonical binary. We would need to either extend it or implement equivalent logic in fontTools.
Status: this is the single biggest blocker — GPOS differences account for hundreds of non-matching families. Needs careful design to ensure all kerning pairs and positioning rules are preserved.
135 families could not be compared because the normalizer crashed or no built font was found. Some are missing builds (never rebuilt after the last batch), some hit edge cases in the normalizer (unusual table structures, CFF fonts). Fixing these expands the testable population.
Status: needs triage — separate missing-build errors from normalizer bugs.
Tier 3: Hard Problems — Root Causes
When fontmake/ufo2ft versions differ, they produce slightly different coordinate rounding (±1 unit at 1000 UPM). This is a real functional difference, though usually invisible at normal rendering sizes. Cannot be normalized without changing the outlines — this is where "software archaeology" (matching exact tool versions) remains the only path.
Status: affects the majority of non-matching families. The cohort version matching approach yielded 15 additional byte-identical families but cannot be scaled further without original pip freeze data.
Different ttfautohint versions produce different hinting programs (fpgm, prep, cvt tables, per-glyph hints). Stripping hinting entirely would be a normalization option, but it is not safe — hinting affects rendering on Windows at small sizes and is functionally significant. Instead, hinting differences should be reported as "known ttfautohint version difference" without normalization.
Status: affects ~93 families classified as "ttfautohint-version" root cause. Matching the exact ttfautohint version (via ttfautohint-py pinning) is the correct approach but requires per-family version identification.
The fundamental barrier to reproducibility is that google/fonts does not record the exact tool versions used to build each font. If pip freeze output were saved alongside every font onboarding/update (e.g. in METADATA.pb or a companion file), future rebuilds could recreate the exact environment. This is a process change for the Google Fonts team, not a normalization step.
Status: recommendation for the Google Fonts team. Would make all future onboardings reproducible by construction.
Last updated: 2026-03-16
Build Dependencies
All dependencies used to build fonts in the Google Fonts Library, with version distribution and per-family cross-reference
Current Build Environment
| Tool | Installed Version |
|---|
| Category | Dependency | Families | Family List |
|---|
Data generated: --
Build Timings
How long each font family takes to build from source. Multiple data points are preserved when families are rebuilt.
| Family | Latest Build Time | Status | Builds | History |
|---|
Data generated: --
Build Failure Investigation
Categorization of all build failures with fix plan and progress tracking over time
Fix Plan
Failure Categories
| Category | Count | Fixable? | Fix | Families |
|---|
Data generated: --
Implementation Plans
Documented plans with timestamps and original prompts
Disk Usage
Storage monitoring for /mnt/shared
Storage Breakdown
| Directory | Size |
|---|
Last updated: --
Designer Bio Editorial Guide
Standards and conventions for writing mini biographies in the Google Fonts designers catalog
Contents
1. Overview
Each designer in the Google Fonts catalog has a profile page with a short biography. These bios serve as the public-facing introduction to the people and organizations behind the typefaces in the library. They should be concise, accurate, and professional.
Bios are stored as HTML in the bio.html file within each designer's directory in the google/fonts repository at catalog/designers/{designer_id}/bio.html.
2. Bio Structure
Every bio follows a consistent structure:
3. Voice and Perspective
- Write in third person ("Alice Savoie is a type designer...")
- Use present tense for current roles and activities
- Use past tense for completed education, past positions, and historical events
- Maintain a neutral, encyclopedic tone — factual and respectful
- Use first person ("I am a designer...")
- Use second person ("You'll love their fonts...")
- Use promotional or marketing language ("award-winning genius")
- Editorialize or offer personal opinions about the designer's work
4. Writing for Individual Designers
For individual type designers, the opening sentence should follow this pattern:
<p>{Full Name} is a {role/title} based in {City, Country}.</p>
If the location is unknown, omit the "based in" clause. If the designer has multiple roles, list the most relevant ones:
"Alexei Vanyashin is a type designer and Cyrillic specialist dedicated to thoughtful, collaborative work."
"Adam Jagosz is a Polish type designer and frontend developer based in Bielsko-Biała."
"Adam is a cool designer who makes awesome fonts." (too casual, subjective)
After the opening, provide 1–3 sentences of context. Prioritize in this order:
- Notable typefaces in the Google Fonts library
- Professional background relevant to type design
- Education in type design or related fields
- Foundry affiliation or studio
- Awards and recognitions (stated factually, not promotionally)
5. Writing for Studios and Foundries
For organizations, the opening should identify what the entity is, where it is located, and who founded it:
<p>Based in {City}, {Studio Name} is a {type of organization} founded by {Founder Name}.</p>
"Based in Tel Aviv, AlefAlefAlef is a leading Hebrew type foundry and design collective founded by Avraham Cornfeld."
"Based in Lagos, Nigeria, Afrotype, founded by Seyi Olusanya, intends to subvert cliches around African graphic design and identity by creating typefaces that are grounded in African history and culture."
For companies with a broader mission statement (beyond type), keep it brief and focused on their type-related work.
6. Length Guidelines
The links paragraph at the end does not count toward the word limit.
7. What to Include
| Element | Priority | Notes |
|---|---|---|
| Full name | Required | As it appears in the designer directory. Use proper diacritics. |
| Professional role | Required | "type designer", "graphic designer", "type foundry", etc. |
| Location (city, country) | Recommended | Where they are currently based. Omit if unknown. |
| Notable typefaces | Recommended | Especially those available on Google Fonts. |
| Foundry or studio | Recommended | If they founded or are affiliated with one. |
| Education | Optional | Relevant type design or design programs only. |
| Awards | Optional | State factually: "recipient of the Prix Charles Peignot (2013)". |
| Script specialization | Optional | Cyrillic, Arabic, Devanagari, etc. Highly relevant for multi-script designers. |
| Website / portfolio link | Required | At least one link when available. Placed in the final paragraph. |
8. What to Avoid
The following elements must never appear in designer biographies. These policies ensure consistency, professionalism, and accuracy across the catalog.
- Arctic Code Vault or any GitHub badge/recognition — not relevant to professional profiles
- Personal contact information (email addresses, phone numbers)
- Subjective superlatives ("the best", "world-renowned", "legendary")
- Pricing or commercial information about font sales
- Unverified claims or information that cannot be corroborated
- Lengthy project descriptions — keep to typeface names, not full project narratives
- Broken or placeholder URLs (e.g.,
https://This,https://one:) - Content copied verbatim from external sources without verification
- Redundant references to Google Fonts in link text (e.g., "on Google Fonts", "available on Google Fonts") — the bios are already hosted on Google Fonts, so this is redundant. For specimen links, use just the typeface name as link text.
9. Link Formatting
Links go in the final paragraph of the bio, separated by pipes with spaces:
<p><a href="https://example.com">example.com</a> | <a href="https://instagram.com/user">Instagram</a></p>
- Use the platform name as link text for social media: "Instagram", "LinkedIn", "Behance"
- Use the domain name as link text for personal websites: "example.com", "foundryname.co"
- All links must use HTTPS where available
- Add
target="_blank"attribute for external links - Verify all links are working before submission
- Prefer permanent, canonical URLs (not shortened or tracking links)
Preferred link order: Personal website, then social profiles alphabetically (Behance, GitHub, Instagram, LinkedIn, X/Twitter).
10. HTML Format Reference
Bios are stored as HTML fragments (not full documents). The only tags used are:
| Tag | Usage |
|---|---|
<p> |
Wraps each paragraph. Every bio must use <p> tags. |
<a href="..."> |
Hyperlinks. Used in the final paragraph for website/social links. |
Do not use <b>, <i>, <br>, <div>, <span>, or any other HTML tags. Keep the markup minimal.
<p>{Full Name} is a {role} based in {City, Country}. {Additional context}.</p>
<p><a href="https://website.com" target="_blank">website.com</a> | <a href="https://instagram.com/handle" target="_blank">Instagram</a></p>
11. Examples
Minimal bio (1 sentence + links)
Alexander Örn is a type designer based in Malmö, Sweden and co-founder of Kanon Foundry.
<p>Alexander Örn is a type designer based in Malmö, Sweden and co-founder of Kanon Foundry.</p>
Standard bio (2–3 sentences + links)
Abdullah Aref is an Egyptian art teacher, calligrapher, and Arabic type designer.
<p>Abdullah Aref is an Egyptian art teacher, calligrapher, and Arabic type designer.</p> <p><a href="https://www.behance.net/abdoullah_aref" target="_blank">Behance</a> | <a href="https://www.facebook.com/areffonts" target="_blank">Facebook</a></p>
Detailed bio (multiple paragraphs + links)
Alexei Vanyashin is a type designer and Cyrillic specialist dedicated to thoughtful, collaborative work. After graduating from BHSAD Moscow in 2010, he founded Cyreal, the foundry behind popular open-source fonts such as Lora, Prata, and Alice. He worked with Swiss Typefaces, Optimo, Dalton Maag, Newlyn, and Google Fonts, with notable projects like the YouTube Sans redesign (2021). From 2016 to 2024, he served as Cyrillic Script Chair at the Granshan Foundation. Currently based in Almaty, Kazakhstan, he teaches typography at ACDS.
<p>Alexei Vanyashin is a type designer and Cyrillic specialist dedicated to thoughtful, collaborative work. After graduating from BHSAD Moscow in 2010, he founded Cyreal, the foundry behind popular open-source fonts such as Lora, Prata, and Alice. ...</p> <p><a href="https://alexeiva.cyreal.org">alexeiva.cyreal.org </a> | <a href="https://instagram.com/avanyashin">Instagram </a></p>
Studio/foundry bio
Based in Lagos, Nigeria, Afrotype, founded by Seyi Olusanya, intends to subvert cliches around African graphic design and identity by creating typefaces that are grounded in African history and culture.
<p>Based in Lagos, Nigeria, Afrotype, founded by Seyi Olusanya, intends to subvert cliches around African graphic design and identity by creating typefaces that are grounded in African history and culture.</p> <p><a href="https://www.afrotype.com">afrotype.com</a> | <a href="https://x.com/useafrotype">X </a></p>
12. Pre-Submission Checklist
Bio Audit Report
Full compliance review of all designer biographies against the Editorial Guide
gftools-builder can compile them. This research directly informed the prebuild mechanism in the reproducible build system, which now supports per-family prebuild commands in the build registry. The data is a snapshot and does not reflect prebuilds added since.
Pre-Build Scripts Research
Analysis of pre-compilation actions across Google Fonts upstream repositories. Related: gftools issue #1171 — issue #1170
Key Finding: Most Patterns Already Covered
After reviewing the gftools-builder documentation, we discovered that the builder already has features covering the top pre-build patterns:
| Pattern | Existing Feature | Status |
|---|---|---|
| UFO Source Merging | includeSubsets config key + addSubset operation | COVERED |
| Glyphs-to-UFO Conversion | glyphs2ds operation (auto-triggered) | COVERED |
| flattenComponents filter | flattenComponents: true (default) | COVERED |
| Arbitrary pre-processing | exec recipe operation | ESCAPE HATCH |
| Post-compilation steps | postCompile config key | COVERED |
| Designspace axis manipulation | subspace operation, instances config | PARTIAL |
The originally proposed mergeUFOs config key is largely redundant with the existing includeSubsets,
which already supports local files, remote repos, named glyphsets, codepoint ranges, layout handling, and force-replace.
Context
Many upstream Google Fonts repos need to run preparation commands before invoking gftools-builder.
Currently they do this with custom wrapper scripts (build.sh, build.py, Makefiles),
which means they can't use a pure config.yaml-driven build. Simon Cozens, and presumably also Rod Sheeter, oppose a
generic preCompile shell-execution feature (issue #1170).
Instead, we should implement well-defined, declarative builder operations for the most common patterns.
Data source: Full scan of 404 Makefiles and 86 build.py/build.sh files across 280 organizations in the fontc crater cache, plus GitHub code search results.
Action Types Summary
Pre-Build Action Types by Repo Count
Priority Assessment (Revised)
| Status | Action Type | Repo Count | Existing Feature | Remaining Gap |
|---|
Existing Feature: includeSubsets
~47 repos depend on ufomerge (5 with explicit merge scripts + ~42 as build dependency),
making UFO merging the most widespread pre-compile operation. The builder's existing includeSubsets
config key already provides declarative UFO merging:
sources:
- sources/MyFont.designspace
includeSubsets:
- from: "Noto Sans"
name: GF_Latin_Core
- from: {repo: "notofonts/devanagari", path: "sources/NotoSansDevanagari.glyphspackage"}
name: Devanagari
layoutHandling: closure
- from: "path/to/local/donor.designspace"
ranges:
- start: 0x3000
end: 0x30FF
force: replace
includeSubsets supports local files, remote GitHub repos (with version refs),
pre-defined Noto sources, named glyphsets, custom Unicode ranges, layout/kerning handling,
force-replace, and glyph/codepoint exclusions. When used with Glyphs sources, the conversion
to UFO happens automatically via glyphs2ds.
Repos to Investigate for includeSubsets Migration
These repos currently use custom merge scripts and should be checked to see if includeSubsets can replace them:
Migration Analysis
Per-repo assessment of whether pre-build scripts can be fully replaced by existing gftools-builder features.
Fully Convertible (3 repos)
These repos can eliminate their pre-build scripts entirely today by pointing sources: directly at their .glyphs/.glyphspackage files:
Partially Convertible (10 repos)
The merge/conversion parts can use existing features, but other operations still need custom scripts or new builder features:
Not Convertible (3 repos + 2 siblings)
These repos have pre-build scripts too custom for any existing builder features:
Grouped Missing Features (Proposals)
Missing gftools-builder features grouped by type, ordered by priority and number of repos that would benefit.
Full Repo Inventory
Complete inventory of repos and their pre-compile action types.
Key Insights (Revised)
- 3 repos can convert today — 42dot-Sans, Asta-Sans, and Overpass can eliminate pre-build scripts by pointing sources directly at .glyphs/.glyphspackage files
- 10 repos are partially convertible — merge/conversion parts work with existing features, but designspace manipulation, target subsetting, and source modification gaps block full migration
preCompilehooks would unblock all 13 repos — despite opposition to generic shell execution (issue #1170), it's the single most impactful missing feature- Source-level DS manipulation is the most targeted gap — a
dropSources/axisRanges/dropAxesconfig would help 3 Google Sans repos - Other gaps are too niche —
include_glyphs(youtube-sans only), target UFO subsetting (googlesans-gurage only), custom filter injection (2 repos) - ~66 repos have fully custom pipelines not using gftools-builder — builder features won't help them
Research date: --
fontc compiler against the full library. Understanding where automated target discovery fails informed both the fontc project and our reproducible build system's config resolution logic. The data is a one-time snapshot.
fontc_crater Target Discovery Failures
Analysis of 17 repos where fontc_crater failed to find build targets. Source: fontc_crater report
Analysis date: --
Investigation Reports
Detailed research reports documenting upstream URL and commit decisions
Fontspector Issue Triage
Issues from the fonttools/fontspector public tracker, categorized for triage.
Open Issues by Category
Low-Hanging Fruit (Open)
Issues with clear scope and straightforward fixes - good candidates to tackle first.
All Issues
New Check Proposals
Proposed new checks for fonttools/fontspector, grouped by type. Open proposals only.
Proposals by Type
Low-Hanging Fruit
Proposals with clear scope that could be implemented quickly.
All Proposals by Type
Low-Hanging Fruit Triage Report
Detailed analysis of all 30 open low-hanging fruit issues from fonttools/fontspector, with recommendations. Model: Claude Opus 4.6 | Date: 2026-03-06
Recommended to Implement
Recommended to Reject
Dev Log
Ongoing chronicle of the reproducible build system project — progress, discoveries, techniques, and decisions
About the Dashboard
Project Overview
The Google Fonts Agents Dashboard is a data-driven, single-page web application that serves as a centralized monitoring tool for the Google Fonts ecosystem. It is built using a vanilla tech stack (HTML5, CSS3, and JavaScript) to ensure it is lightweight and easy to deploy.
Key Features & Capabilities:
- Progress Tracking (Library Sources): Visualizes the status of documenting upstream font repositories.
- Repository Auditing: Verifying METADATA.pb repository_url and commit hash.
- Designer Catalog: Displays Google Fonts designer profiles and biographies.
- Workflow Management: Tracks pending PRs and questions for maintainers.
- Research & Diagnostics: Analyzes build approaches, fontc_crater failures, and disk usage.
- Reporting: Generates Friday Status updates and Bio Audit compliance reports.
Technical Details:
- Data Source: Fetches data from JSON files in the
data/directory, generated by Python scripts. - Navigation: Tabbed interface with URL fragment tracking.
- Local Server: Uses a
run.shscript (Python-based local server).
Workflow: Adding fontc_crater Targets
The workflow for adding more fontc_crater targets involves enriching font family metadata in the google/fonts repository. This allows the fontc compiler to identify, build, and test these fonts.
1. Requirements for Enrollment
A font family's METADATA.pb must contain:
repository_url: Upstream Git repository URL.commit: Specific Git commit hash.config_yaml: Path to agftools-builderconfiguration (e.g.,config.yaml).
2. The Discovery Process
- Scanning Upstream:
scripts/find_config_yaml.pyscans cached repositories for valid build configs. - Local Overrides: If
config.yamlexists locally in the family directory, it overrides the need for theconfig_yamlfield in metadata.
3. Implementation Steps
- Find the Config: Run discovery scripts to identify eligible families.
- Update Metadata: Use
scripts/add_config_yaml_to_metadata.pyto updateMETADATA.pb. - Submit PR: Commit changes to
google/fonts. - Update Targets: The
fontc_craterrepository must have itstargets.jsonfile updated via a PR before it can recognize the new targets. Such PR is prepared by running thegoogle-fonts-sourcestool that detects theconfig.yamloverrides and the relevant fields inMETADATA.pbfiles of thegoogle/fontsrepository.