For the complete documentation index, see llms.txt. This page is also available as Markdown.

Font Oversampling

Introduction

When the camera or a layer zooms in, text is scaled up along with everything else. The font was drawn at its normal FontSize, so the letters end up soft or blocky next to art that is drawn at full size. Font oversampling fixes this. While the view is zoomed in, Gum builds the font again at a larger size, then draws the letters smaller so they fit. The text takes up the same space in your layout, but it is made of more pixels, so the edges stay sharp.

Font oversampling is a preview feature. It first shipped in the 2026.8.18.1-preview.1 packages. You can also use it by building Gum from source.

Works on MonoGame, KNI, FNA, and Raylib. SkiaGum and Silk.NET do not need it, since SkiaSharp draws text at whatever size it is asked for, so the text stays sharp when you zoom.

Enabling Oversampling

You need two things:

  1. Turn on the flag: TextRuntime.UseFontOversampling = true. This is one static switch for the whole game, not a property on each text. If you want blocky text in a pixel art game, leave it off.

  2. Give Gum a way to build fonts while the game runs (IInMemoryFontCreator on MonoGame/KNI/FNA, IRaylibFontCreator on Raylib). KernSmith does both, see Dynamic KernSmith Generation. Oversampling needs this, because a FontCache folder only holds the sizes you built ahead of time and cannot add a new one later.

// Initialize
TextRuntime.UseFontOversampling = true;
CustomSetPropertyOnRenderable.InMemoryFontCreator =
    new KernSmithFontCreator(GraphicsDevice);

After that it runs on its own. Each frame, every text you can see checks the zoom of the Layer it sits on. If that zoom moved enough to change the font by a full pixel, the text builds its font again. You do not need to write any code that runs each frame.

The layer matters here. A layer with LayerCameraSettings.IsInScreenSpace = true, which is how most HUDs are set up, keeps its own Zoom (1 by default) no matter where the camera goes. Text on that layer never builds a new font, which is right, because it never looks zoomed. Only text on a layer that follows the camera zoom is oversampled. See Layer, LayerCameraSettings.

Manual Control

RegenerateOversampledFont(oversampleRatio) is the method the automatic path calls. You can call it yourself to pick a size, such as during a cut scene that zooms without touching Camera.Zoom. It returns false and does nothing if UseFontOversampling is off, if no IInMemoryFontCreator is set, or if oversampleRatio is zero or less.

The automatic path debounces continuous zooming: it only rebuilds a font's atlas once the requested size has moved TextRuntime.OversamplingRegenerateThresholdPixels (1 pixel by default) from what was last rasterized. That 1px absolute threshold is a bigger fraction of a small FontSize than a large one, so small text can stay noticeably blurry for longer while zooming. Lower the threshold (down to 0 to regenerate on any change) if you want small text to re-crisp sooner, at the cost of rebuilding the atlas more often.

Limitation: System Fonts vs. Registered .ttf

For the text to keep the same size while its font is built again at other sizes, Font (or CustomFontFile) has to point at a real .ttf file, not just a font name like "Arial". Oversampling still runs with a font name, but the width and the line breaks may shift a little each time the font is built. See Font Strategies, System Fonts vs Registered Fonts to learn how to register a .ttf.

Limitation: [FontSize]/[IsBold]/[IsItalic]/[OutlineThickness] BBCode Runs on Raylib

On Raylib, oversampling builds the base font of a TextRuntime again. Runs that only scale that font, meaning runs with no tag or with a [FontScale=...] tag, come out at the right size, the same as on MonoGame, KNI, and FNA. Runs that ask for a different font, meaning [FontSize=...], [IsBold=...], [IsItalic=...], and [OutlineThickness=...], keep their own size and are not oversampled. Changing them would upset the line height and baseline math they already rely on. MonoGame, KNI, and FNA do not have this limit, and oversampling works with every kind of run there.

Try It

Drag the Zoom slider to zoom the camera. The text stays sharp because it is oversampled. Turn off Oversampling to see how the same text looks without it. The font (std/DroidSans.ttf) ships with XnaFiddle, so there is nothing to upload.

Try on XnaFiddle.NET

The fiddle runs in a browser, so it creates its font creator as new KernSmithFontCreator(GraphicsDevice, KernSmith.RasterizerBackend.StbTrueType). KernSmith always starts with the FreeType backend, and FreeType is native code that a browser cannot run. Without that second argument, Gum throws a PlatformNotSupportedException on browser-wasm the moment it tries to build a font, rather than failing silently. On desktop you can use the code above as it is. See Backend Selection.

  • Font Strategies: building fonts with KernSmith and registering .ttf files.

  • Automatic Glyph Growth: adding characters to a live font that weren't baked in ahead of time.

  • Camera: zooming the camera.

  • Layer: LayerCameraSettings and screen space layers.

Last updated

Was this helpful?