gum-runtime-fonts

$npx mdskill add vchelaru/Gum/gum-runtime-fonts

Reference Gum's complex runtime font loading system, detailing three distinct methods for acquiring BitmapFont assets.

  • Resolves issues when managing text rendering assets using MonoGame/KNI.
  • Details the interaction between TextRuntime, BitmapFont, and the LoaderManager.
  • Guides developers through the lookup cascade involving properties and file paths.
  • Provides technical documentation on font creation, caching, and loading fallbacks.

SKILL.md

.github/skills/gum-runtime-fontsView on GitHub ↗
---
name: gum-runtime-fonts
description: Reference guide for Gum's runtime font loading system in MonoGame/KNI — the three font loading paths (custom font, font-property cache lookup, in-memory generation), the lookup cascade, FontCache naming, and common gotchas. Load when working on TextRuntime font properties, BitmapFont loading, CustomSetPropertyOnRenderable.UpdateToFontValues, IInMemoryFontCreator, or font-related documentation.
---

# Runtime Font Loading

Gum renders text using **BitmapFont** — a `.fnt` descriptor file plus one or more `.png` texture atlases. There are three ways to get a BitmapFont onto a TextRuntime, each with different tradeoffs.

## Three Font Loading Paths

### Path 1: Custom Font File (UseCustomFont = true)

User provides a pre-built `.fnt` file directly:
```
textRuntime.UseCustomFont = true;
textRuntime.CustomFontFile = "fonts/MyFont.fnt";
```

- File path resolves relative to `FileManager.RelativeDirectory` (typically `Content/`)
- Loaded via `new BitmapFont(path)`, cached in `LoaderManager`
- If the file doesn't exist, load silently skips — element gets `DefaultBitmapFont`
- No property-to-filename mapping; user controls the exact file

### Path 2: Font Property Cache Lookup (UseCustomFont = false, the default)

Six properties combine into a deterministic filename in `FontCache/`:

| Property | Default | Effect on filename |
|----------|---------|-------------------|
| Font / FontFamily | "Arial" | Base name (spaces → underscores) |
| FontSize | 18 | Base size number |
| OutlineThickness | 0 | `_o{N}` suffix if non-zero |
| UseFontSmoothing | true | `_noSmooth` suffix if false |
| IsItalic | false | `_Italic` suffix if true |
| IsBold | false | `_Bold` suffix if true |

**Naming formula:** `FontCache/Font{size}{name}[_o{N}][_noSmooth][_Italic][_Bold].fnt`

Examples: `FontCache/Font18Arial.fnt`, `FontCache/Font24Times_New_Roman_o1_Bold.fnt`

`BmfcSave.GetFontCacheFileNameFor()` produces this name. Every property setter on TextRuntime (Font, FontSize, etc.) calls `UpdateToFontValues()`, which regenerates the filename and attempts to load.

**Key gotcha:** Unless an `IInMemoryFontCreator` or `IRuntimeFontService` is registered, the `.fnt` file must already exist in `FontCache/`. Users often set `FontSize = 24` expecting it to work, but silently get `DefaultBitmapFont` because `Font24Arial.fnt` was never generated. There is no error or warning — the text just renders in the default font.

### Path 3: In-Memory Font Creation (IInMemoryFontCreator) — New

Generates a `BitmapFont` entirely in memory at runtime — no pre-built `.fnt` files needed. The loading code already checks for this; it slots into the cascade between embedded resources and disk-based generation.

When registered on `CustomSetPropertyOnRenderable.InMemoryFontCreator`, font-property changes (Path 2) automatically create fonts on demand. This eliminates the FontCache pre-population requirement.

## Lookup Cascade

When `UseCustomFont = false` and a font property changes, `UpdateToFontValues` tries these sources in order:

1. **LoaderManager cache** — already-loaded BitmapFont by full path
2. **Embedded resource** — MonoGameGum ships `Font18Arial` (plus Bold/Italic/Bold_Italic variants) as embedded resources; these are the default fonts
3. **IInMemoryFontCreator** — generates BitmapFont in memory, no disk I/O
4. **IRuntimeFontService** — generates `.fnt`/`.png` files on disk, then falls through to step 5 (typically tool-only, not used in game code)
5. **Disk load** — `new BitmapFont(fullPath)` if the file exists
6. **DefaultBitmapFont fallback** — `Text.DefaultBitmapFont` (Font18Arial, set during `SystemManagers` initialization)

The result is cached in `LoaderManager` so subsequent lookups for the same font properties hit step 1.

## Wiring

`SystemManagers` initialization (called by `GumService.Initialize`) sets up the font system:
- Loads embedded Font18Arial as `Text.DefaultBitmapFont`
- Wires `GraphicalUiElement.UpdateFontFromProperties` → `CustomSetPropertyOnRenderable.UpdateToFontValues`

Game code can optionally set `CustomSetPropertyOnRenderable.InMemoryFontCreator` to enable Path 3.

## Key Files

| File | Purpose |
|------|---------|
| `MonoGameGum/GueDeriving/TextRuntime.cs` | User-facing font properties; each setter calls `UpdateToFontValues()` |
| `RenderingLibrary/Graphics/Text.cs` | Renderable; holds `BitmapFont` instance and static `DefaultBitmapFont` |
| `RenderingLibrary/Graphics/Fonts/BitmapFont.cs` | Loads `.fnt` + `.png` textures; stores character metrics |
| `RenderingLibrary/Graphics/Fonts/BmfcSave.cs` | `GetFontCacheFileNameFor()` — deterministic cache filename from properties |
| `Gum/Wireframe/CustomSetPropertyOnRenderable.cs` | `UpdateToFontValues()` — orchestrates the lookup cascade |
| `RenderingLibrary/Graphics/Fonts/IInMemoryFontCreator.cs` | Interface for runtime font generation without disk I/O |
| `RenderingLibrary/Graphics/Fonts/IRuntimeFontService.cs` | Interface for disk-based font generation (typically tool-only) |
| `RenderingLibrary/SystemManagers.cs` | Wires font delegates and loads default embedded font |

More from vchelaru/Gum

SkillDescription
bump-nuget-versionBump the NuGet package versions for all 12 Gum projects (11 libraries + GumCli). Queries NuGet to check if a version exists for today, then sets the new version to YYYY.M.D.V where V increments from the latest published version today (or starts at 1). Creates a release branch named ReleaseCode_YYYY_M_D_V, commits the changes, and pushes. Run this before triggering the nuget release workflow.
gum-cliReference guide for GumCli — the headless command-line tool for Gum projects. Load this when working on gumcli commands (new, check, codegen, codegen-init), Gum.ProjectServices, HeadlessErrorChecker, ProjectLoader, HeadlessCodeGenerationService, CodeGenerationAutoSetupService, or the FormsTemplateCreator.
gum-docs-writingReference guide for writing Gum documentation in GitBook markdown. Load when writing or editing docs/ files, adding pages to SUMMARY.md, using GitBook hints/figures, linking between pages, or adding images.
gum-forms-behaviorsCovers Gum's behaviors system and the design-time → runtime Forms wrapping lifecycle. Load this when working on BehaviorSave, ElementBehaviorReference, StandardFormsBehaviorNames, FormsUtilities.RegisterFromFileFormRuntimeDefaults, DefaultFromFileXxxRuntime classes, or when investigating why Forms properties cannot be set at design time in the Gum tool.
gum-forms-controlsReference guide for Forms controls — classes inheriting from FrameworkElement. Load this when working on Button, CheckBox, ListBox, ComboBox, TextBox, ScrollViewer, or any class in Gum.Forms.Controls (or FlatRedBall.Forms.Controls). Also load when working on FrameworkElement itself, the Visual/InteractiveGue relationship, state machines, DefaultVisuals, or ReactToVisualChanged.
gum-forms-default-visualsReference guide for Forms DefaultVisuals — the code-only visual classes that back Forms controls. Load when working on ButtonVisual, any *Visual class in DefaultVisuals/, Styling, DefaultFormsTemplates registration, or building custom code-only Forms visuals.
gum-forms-itemscontrolReference guide for ItemsControl and ListBox — the Items/ListBoxItems relationship, templates, InnerPanel sync, and gotchas. Load this when working on ItemsControl, ListBox, ListBoxItem, VisualTemplate, FrameworkElementTemplate, Items collection behavior, ListBoxItems desync, or adding/removing items from a list box.
gum-layout>
gum-layout-engine>
gum-localizationReference guide for Gum's runtime localization system — ILocalizationService, CSV/RESX loading, Text vs TextNoTranslate paths, Forms control localization patterns, and gotchas.