diff --git a/blog/2026-04-14-formula-v5.md b/blog/2026-04-14-formula-v5.md new file mode 100644 index 0000000..f88d17e --- /dev/null +++ b/blog/2026-04-14-formula-v5.md @@ -0,0 +1,367 @@ +--- +title: "Fontist Formula v5: multi-format and variable font support" +description: "Formula v5 adds explicit schema versioning, multi-format resources, variable font metadata, and import provenance for Fontist formulas." +authors: + - Ronald Tse + - Hassan Akbar +date: 2026-04-14 +--- + +# Fontist Formula v5: multi-format and variable font support + + + +Fontist formulas have reached version 5. + +This release modernizes the formula schema for today's font ecosystem, where a +single family can be available as desktop fonts, web fonts, static files, +variable fonts, and source-specific system fonts. + +The main change is structural: Formula v5 describes what each resource contains +instead of treating every formula as a single download with implicitly-known +font files. + +## What formulas do + +A Fontist +[font formula](https://www.fontist.org/formulas/) +is a YAML file that tells Fontist where a font comes from, what files are +available, and how those files map to installable font styles. + +Formula v4 worked well for the earlier Fontist model: most formulas described +one downloadable package, usually an archive containing desktop font files. + +That model is no longer enough. Google Fonts, macOS supplementary fonts, SIL +fonts, and other sources increasingly expose the same family through different +file formats and different font technologies. Formula v5 adds the metadata +Fontist needs to make those differences explicit. + +## From implicit to explicit + +Formula v4 did not declare its schema version. Formula v5 does: + +```yaml +--- +schema_version: 5 +name: Courier Prime +description: Courier Prime +homepage: https://quoteunquoteapps.com +``` + +If `schema_version` is missing, Fontist continues to treat the formula as a v4 +formula. Existing private and custom formula repositories therefore keep +working. + +The explicit version field matters because it gives Fontist a deterministic way +to choose schema behavior. New fields can be added to v5 without changing how +older formulas are interpreted. + +## Resources now describe formats + +In v4, a resource was usually named after the download itself: + +```yaml +resources: + Courier_Prime.zip: + urls: + - https://quoteunquoteapps.com/courierprime/downloads/courier-prime.zip + sha256: d5d4faf1bee0d1f52bab1103cbfdfb354976331c86f999c110c22a098cb12d73 + file_size: 193595 +``` + +That structure is still valid for a migrated archive formula, but it does not +tell Fontist what font format the resource provides. + +Formula v5 can describe resources by capability. For example, the Abel formula +from Google Fonts provides static TTF and static WOFF2 resources: + +```yaml +resources: + ttf_static: + source: google + family: Abel + files: + - https://fonts.gstatic.com/s/abel/v18/MwQ5bhbm2POE6VhLPJp6qGI.ttf + urls: + - https://fonts.gstatic.com/s/abel/v18/MwQ5bhbm2POE6VhLPJp6qGI.ttf + format: ttf + woff2_static: + source: google + family: Abel + files: + - https://fonts.gstatic.com/s/abel/v18/MwQ5bhbm2POE6V1LPJp6qGI.woff2 + urls: + - https://fonts.gstatic.com/s/abel/v18/MwQ5bhbm2POE6V1LPJp6qGI.woff2 + format: woff2 +``` + +The important new field is `format`. A resource can now say whether it provides +`ttf`, `otf`, `woff`, `woff2`, `ttc`, or `otc` files. + +Each resource carries both a `files` list and a `urls` list. For Google Fonts +these are identical because each font file is downloaded directly by URL. For +archive-based formulas like Courier Prime, `urls` points to the downloadable +archive while `files` lists the font files extracted from within it. + +The resource name is also more meaningful. Names such as `ttf_static`, +`woff2_static`, `ttf_variable`, and `woff2_variable` make it clear whether the +resource is a desktop font, web font, static font, or variable font resource. + +## Styles know their available formats + +Formula v5 also records format information on each style: + +```yaml +fonts: +- name: Abel + styles: + - family_name: Abel + type: Regular + full_name: Abel Regular + post_script_name: Abel-Regular + font: MwQ5bhbm2POE6VhLPJp6qGI.ttf + formats: + - ttf + - woff2 + variable_font: false +``` + +The `font` field is how a style connects to its resources: its value is a +filename that appears in one of the resource `files` lists. The `formats` array +then tells Fontist that the same style is available in other resources as well. +In the example above, the `font` field references a `.ttf` filename found in +the `ttf_static` resource, but the `formats` array also lists `woff2`, +indicating that a WOFF2 version is available through the `woff2_static` +resource. + +This means Fontist can tell that "Abel Regular" is available in both TTF and +WOFF2. Users and tools can then request a format explicitly: + +```sh +$ fontist install "Abel" --format woff2 +``` + +When the user requests a specific format, Fontist first looks for a resource +that already provides it. If no exact match exists, Fontist checks whether +conversion from an available format is possible (for example, converting TTF to +WOFF2). An exact-match resource is always preferred over conversion. + +## Variable font metadata + +Variable fonts are one of the main reasons for Formula v5. + +A variable font can contain a range of designs in a single font file. Instead +of installing separate files for Regular, Bold, Condensed, or other fixed +instances, a variable font exposes axes such as weight (`wght`), width (`wdth`), +slant (`slnt`), or optical size (`opsz`). + +Formula v5 represents this with `variable_font` and `variable_axes`. + +Roboto Flex is a good example. (The `HASH` placeholders below stand in for +the long hashed filenames that Google Fonts uses.) + +```yaml +resources: + woff2_variable: + source: google + family: Roboto Flex + files: + - https://fonts.gstatic.com/s/robotoflex/v30/HASH.woff2 + urls: + - https://fonts.gstatic.com/s/robotoflex/v30/HASH.woff2 + format: woff2 + variable_axes: + - GRAD + - XOPQ + - XTRA + - YOPQ + - YTAS + - YTDE + - YTFI + - YTLC + - YTUC + - opsz + - slnt + - wdth + - wght + ttf_variable: + source: google + family: Roboto Flex + files: + - https://fonts.gstatic.com/s/robotoflex/v30/HASH.ttf + urls: + - https://fonts.gstatic.com/s/robotoflex/v30/HASH.ttf + format: ttf + variable_axes: + - GRAD + - XOPQ + - XTRA + - YOPQ + - YTAS + - YTDE + - YTFI + - YTLC + - YTUC + - opsz + - slnt + - wdth + - wght +``` + +The same metadata is available on styles. Notice that `font` references a +`.ttf` filename from the `ttf_variable` resource, while `formats` declares that +WOFF2 is also available: + +```yaml +fonts: +- name: Roboto Flex + styles: + - family_name: Roboto Flex + type: Regular + font: HASH.ttf # filename from ttf_variable resource + formats: + - ttf + - woff2 + variable_font: true + variable_axes: + - GRAD + - XOPQ + - XTRA + - YOPQ + - YTAS + - YTDE + - YTFI + - YTLC + - YTUC + - opsz + - slnt + - wdth + - wght +``` + +The `variable_axes` array appears on both resources and styles. They serve +different purposes: on a resource, axes describe what the font file physically +contains. On a style, axes describe what is available to the user across all +resources for that style. Style-level axes are derived automatically during +import and migration, so they stay in sync with the underlying resources. + +In practice the two lists are usually identical, but they can diverge when +resources for the same style offer different axis sets. When that happens and a +user requests specific axes, Fontist selects the resource that satisfies the +request. + +This enables capability-based workflows: + +```sh +$ fontist find --variable +$ fontist find --axes wght,wdth +$ fontist install "Roboto Flex" --variable-axes wght,wdth +$ fontist install "Roboto Flex" --prefer-variable +``` + +Fontist can now answer questions such as "which fonts support weight and width +axes?" and "install the variable version when one is available." + +## Import provenance + +Formula v5 can record where an imported formula came from. + +The `import_source` field is typed by source. For macOS supplementary fonts, it +tracks the framework version, posting date, and asset ID: + +```yaml +import_source: + type: macos + framework_version: 8 + posted_date: '2025-08-05T18:58:57Z' + asset_id: 10m11177 +``` + +Google and SIL formulas can carry source-specific metadata as well: + +```yaml +import_source: + type: google + commit_id: abc123def456 + api_version: v1 + last_modified: '2026-04-01T00:00:00Z' + family_id: roboto-flex +``` + +```yaml +import_source: + type: sil + version: 6.200 + release_date: '2024-02-01' +``` + +This improves auditing and update detection. Fontist can distinguish formulas +that came from different upstream sources and can compare source metadata when +checking whether an imported formula is outdated. For example: + +```sh +$ fontist check-updates --source google +Outdated formulas: + roboto_flex: local commit abc123, upstream commit def456 + abel: up to date +``` + +Without `import_source`, Fontist would have no way to tell whether a formula's +upstream has moved ahead. + +## Structural comparison + +| Aspect | Formula v4 | Formula v5 | +|---|---|---| +| Schema version | Implicit | Explicit `schema_version: 5` | +| Resource model | Usually one package or archive | Multiple resources by capability | +| Resource format | Inferred from files | Declared with `format` | +| Style format metadata | Not available | Declared with `formats` | +| Variable fonts | Not represented | `variable_font` and `variable_axes` | +| Capability search | Limited to formula/style names | Can filter by format, variable font support, and axes | +| Import provenance | Not represented | Typed `import_source` metadata | + +## What this enables + +Formula v5 gives Fontist a richer view of each font family. + +For desktop use, Fontist can still install TTF or OTF files as before. For web +projects, it can choose WOFF2 resources where they are available. For modern +typography workflows, it can find and install variable fonts by supported axes. + +The new structure also helps formula maintainers. Imported formulas can record +their upstream source, and migrated formulas can preserve their existing +installation behavior while gaining an explicit schema version. + +## Migration + +The official Fontist formulas repository has been migrated to v5. The current +repository contains more than 4,000 formula files, including Google Fonts, +macOS supplementary fonts, SIL fonts, and manually-maintained formulas. + +For formula maintainers, the recommended path depends on the source: + +* Re-import generated formula sets such as Google Fonts, macOS fonts, and SIL + fonts with `--schema-version=5`. +* Use the migration command for custom or manually-maintained formulas. + +```sh +$ fontist migrate-formulas ./Formulas ./output --dry-run +``` + +The migration keeps v4 compatibility in mind. A formula without +`schema_version` is still treated as v4, and existing custom formulas continue +to work. + +## Conclusion + +Formula v5 makes Fontist formulas explicit about the font capabilities they +describe. + +Instead of assuming one resource and one desktop-oriented format, formulas can +now declare multiple formats, identify variable font resources, list supported +axes, and record where imported metadata came from. + +That structure gives Fontist the foundation for better format selection, +variable font discovery, source auditing, and future schema evolution while +preserving compatibility with existing v4 formulas. diff --git a/lychee.toml b/lychee.toml index 56a4100..96b2863 100644 --- a/lychee.toml +++ b/lychee.toml @@ -29,4 +29,6 @@ exclude = [ "/blog/2022-02-11-macos-fonts$", "/blog/2024-01-23-office-fonts$", "/blog/2024-03-02-creating-formulas$", + # Exclude placeholder URLs in code examples + "fonts\\.gstatic\\.com/s/robotoflex/v30/HASH", ]