# Bevy: Font Families and System Fonts
## Requirements Summary
* Can easily assign typefaces to text entities.
* Can specify the font variant (bold, italic and so on) independently from the font family name.
* Can load fonts from a Bevy asset source.
* Can use system fonts, including a default system font as specified by OS preference.
* Provide for a list of fallback fonts if a specified font is not installed, or does not define the required glyph.
## Out of Scope
* Selection & editing
* Changing how text blocks are represented.
## Glossary
* **Font family**: a collection of different weights and styles of a particular typeface design. So for example, "OpenSans Medium", "OpenSans Bold" and "OpenSans Bold Italic" are all members of the same font family, even though these fonts are typically separate files or assets.
## Defining Font Families
Currently in Bevy, each individual font variation must be specified explicitly for each text section. If you want bold, italic text in "OpenSans", you have to load the "OpenSans_Bold+Italic.ttf" asset and assign the resulting handle to the text node; and this has to be done for each individual text node. This is both cumbersome and error-prone. Instead, we'd like to select the font file automatically, given a font family name and a text style config.
At a user API level, there should be no distinction between font attributes which alter the selection of font asset (like italic) from font attributes which merely change how the glyphs are drawn (like color). It's all just "text style".
For fonts loaded from assets, typically all of the fonts in a font family will be files located in the same parent directory. For example, if you download a font from Google Fonts and unzip the file, you'll see that the files are organized in this way.
Although the fonts will generally have filenames which indicate their weight and style ("Medium", "Italic" and so on) the naming and separator characters are not guaranteed to be consistent. Thus, the typical practice in the HTML/CSS world is to explicitly specify the font attributes using flags or attributes when defining a font family, using the `@font-face` directive.
This document proposes instead to follow the model of CSS and allow fonts to be defined in a global registry. The registry is stored in a Bevy resource, but there are convenience methods on `App` and `World` to make it easy to add entries to the registry.
Fonts can be added to the registry in one of three ways:
* Individual font face assets (`.ttf` files) can be added to a font family.
* A "font family asset" can be loaded which defines a whole family.
* For system fonts, the font families can be discovered via platform-specific mechanisms.
Here's how a "font family asset" might look as a .ron file:
```
// OpenSans.font.ron
[
FontFace {
src: "./static/OpenSans_Medium.ttf",
weight: 400,
},
FontFace {
src: "./static/OpenSans_Bold.ttf",
weight: 700,
},
FontFace {
src: "./static/OpenSans_MediumItalic.ttf",
weight: 400,
italic: true,
},
FontFace {
src: "./static/OpenSans_BoldItalic.ttf",
weight: 700,
italic: true,
},
]
```
Note that the `src` attributes are serialized asset paths, which can be either absolute or relative.
The `weight` and `style` attributes tell the registry when to choose that particular font based on the style options of the current text entity.
Even though the file does not parse the font file name to determine weight and style, it would be relatively easy to write a script that generates this file by scanning the directory of fonts. Such a script could be more tolerant of idiosyncratic naming conventions than we would want for Bevy itself.
When the font-familt asset is loaded and registered, all of the entries within the family are added as font faces to the registry, just as if they were added individually.
## Fallback
For any given font, we want to be able to define one or more fallback fonts in the case where either the requested font is platform-specific (Monaco vs Consolas) or the requested font is missing the glyph we want to draw.
However, we don't need to be quite as flexible as CSS here. CSS allows fallbacks to be specified per-style. In other words, every time you specify a `font-family` CSS attribute, you are specifying fallbacks.
Instead, we can probably get by with defining the fallback sequence just once when the font is initially registered. Changes are most developers are going to specify a fallback sequence in one place in the code and then use that generally.
## Font Aliases
Currently fonts are referenced by asset handle. Because loading of assets requires injecting an asset server reference, it means that any function that creates a text node has to have either a font handle or the asset server passed in as a parameter. This puts a constraint on the API design of, for example, widget libraries.
An alternative is to lookup fonts by name. However font names may be platform specific: It would be problematic to have the name "Monaco" appear everywhere in your source code.
A better approach would be to allow font families (including fallbacks) be associated with a short name or alias and refer to the fonts by that name. Each alias references a fallback sequence: that is, a series of font names to be applied in order.
It might be feasible for these ids to be const-constructable, either as a `&'static str'` or a newtype struct wrapper around a static string. This would allow libraries to be written around the requirement that a given standard font alias (like "widget_label") must be defined in the App, without requiring the library to define it itself.
An open question is whether aliases are the *only* way that fonts can be referenced: that is, do we allow fonts to be looked up either by alias or the original font name, or do we require defining an alias for every registered font?
## System Fonts
System fonts are discovered and loaded via a different mechanism than fonts loaded as assets. However, once loaded, they should be no different in usage. Fallback sequences should be able to contain both system and non-system fonts (a common practive will be to have a custom game font, but fall back to the system font for certain non-European scripts).
While it might be possible for system fonts to be completely automatic (ask for Courier and you get it, without pre-registration), I think this is undesirable for two reasons:
* Gamedevs want to make sure they only load what they need.
* If we migrate to a different font backend in the future, automatic registration might not be supported.
Therefore, I think that system fonts should be explicitly registered like asset fonts. Hopefully this won't be too onerous.