Fonts

ETA ships five SDF-rendered typefaces and a short-name alias system so you can reference them without typing full namespace:path strings. You can also register your own fonts and use them in any markup.

AliasResourceLocationHas bold variantLicense
norseemberstextapi:norseyes (via norse_bold)Free with attribution (Copyright 2011 Joel Carrouche)
norse_boldemberstextapi:norse_boldn/aFree with attribution (Copyright 2011 Joel Carrouche)
metamorphousemberstextapi:metamorphousnoSIL Open Font License 1.1
metaemberstextapi:metamorphousnoSIL Open Font License 1.1
cinzelemberstextapi:cinzelyes (via cinzel_bold)SIL Open Font License 1.1
cinzel_boldemberstextapi:cinzel_boldn/aSIL Open Font License 1.1
almendraemberstextapi:almendrayes (via almendra_bold)SIL Open Font License 1.1
almendra_boldemberstextapi:almendra_boldn/aSIL Open Font License 1.1
cardoemberstextapi:cardoyes (via cardo_bold)SIL Open Font License 1.1
cardo_boldemberstextapi:cardo_boldn/aSIL Open Font License 1.1

meta is a convenience alias for metamorphous; both resolve to emberstextapi:metamorphous.

Full license text and designer credits for each font are in FONT_LICENSES.md in the repository.

Pass the alias (or a full namespace:path string) as the name attribute of the <font> tag:

<font name="cinzel">Chapter I</font>

When hasBoldVariant is true for the resolved font, wrapping with <bold> automatically switches to the bold variant:

<bold><font name="cinzel">Chapter I</font></bold>

That renders using emberstextapi:cinzel_bold. For metamorphous (and any custom font registered without a bold variant), <bold> applies vanilla bold styling instead.

ETA uses multi-channel signed distance fields (MSDF) to render these fonts. Each font file is loaded via FreeType at game start, and the SDF glyph provider bakes signed-distance data into a texture atlas on a background thread. The common Latin codepoints (U+0020 through U+00FF) are pre-baked on load; any glyph outside that range is baked on first use and cached in memory.

The pre-bake cache is keyed on a SHA-256 hash of the raw font bytes plus every config parameter (sdf_resolution, padding, px_range, etc.), so changing a field in the JSON manifest invalidates only that font’s cached glyphs.

  1. Place the font file at assets/<your-modid>/font/<name>.ttf (or .otf) inside your mod’s resource pack.

  2. Create the JSON manifest at assets/<your-modid>/font/<name>.json. The provider type must be emberstextapi:sdf:

    {
    "providers": [
    {
    "type": "emberstextapi:sdf",
    "file": "<your-modid>:<name>.ttf",
    "size": 16.0,
    "sdf_resolution": 48,
    "padding": 4,
    "px_range": 8.0,
    "angle_threshold": 3.0,
    "oversample": 2.0,
    "shift": [0.0, 0.0],
    "skip": ""
    }
    ]
    }

    Field reference:

    FieldTypeDescription
    filestringnamespace:path to the font file inside your assets folder
    sizefloatReference pixel size used for glyph metric calculations
    sdf_resolutionintPer-glyph texture resolution before padding; capped at 128
    paddingintPixel border added around each glyph cell; capped at 16
    px_rangefloatSDF spread in pixels; wider = softer edges at small sizes
    angle_thresholdfloatEdge coloring threshold in radians; 3.0 works for most fonts
    oversamplefloatScale multiplier for advance width calculation
    shift[x, y]Per-font pixel offset applied to all glyphs
    skipstringCharacters to exclude from the glyph set (e.g. "@#")
  3. Register an alias in your mod’s client init so you can use a short name in markup:

    FontAliasRegistry.registerCustom("myfont", ResourceLocation.fromNamespaceAndPath("yourmodid", "myfont"));

    This step is optional. You can always use the full yourmodid:myfont string directly in <font name="yourmodid:myfont">. If you do register an alias, pick a name that won’t clash with ETA’s built-in aliases; attempting to overwrite a built-in alias is silently ignored.

  4. Reload or restart the game so the SDF glyph provider picks up the new manifest and pre-bakes the atlas for your font.

The most common cause is that the SDF atlas hasn’t been built yet. Check the game log for Pre-baked N SDF glyphs; if N is zero, the font file path in the JSON file field is wrong or the file isn’t in the resource pack. Also verify that ascender and descender read correctly from the FreeType face (ETA derives these directly from the font binary; a corrupt or incompatible font file can produce zeroed metrics).

FontAliasRegistry.registerCustom must be called before the first markup parse that uses that alias. Register in client init, not on a server event or in a constructor that runs before the registry is locked. Also check for namespace typos; alias lookup is case-insensitive but the ResourceLocation path is not.