Skip to main content
Dalamud provides a powerful font system that allows you to load custom fonts, use game fonts, and manage font atlases for your plugin’s UI.

Default Fonts

Dalamud provides several built-in fonts that are ready to use:

Accessing Default Fonts

// In your Draw method
ImGui.PushFont(UiBuilder.DefaultFont);
ImGui.Text("Text in default font");
ImGui.PopFont();

// Icon font (FontAwesome)
ImGui.PushFont(UiBuilder.IconFont);
ImGui.Text(FontAwesomeIcon.Cog.ToIconString());
ImGui.PopFont();

// Monospace font
ImGui.PushFont(UiBuilder.MonoFont);
ImGui.Text("Monospaced text");
ImGui.PopFont();

Default Font Handles

Use font handles for safer, managed access:
using (pluginInterface.UiBuilder.DefaultFontHandle.Push())
{
    ImGui.Text("Text in default font");
}

using (pluginInterface.UiBuilder.IconFontHandle.Push())
{
    ImGui.Text(FontAwesomeIcon.Save.ToIconString());
}

using (pluginInterface.UiBuilder.MonoFontHandle.Push())
{
    ImGui.Text("Code: var x = 42;");
}
Font handles automatically handle font availability and provide safer access than raw font pointers.

Default Font Sizes

Get the default font size in your preferred unit:
float sizePx = UiBuilder.DefaultFontSizePx;  // Pixels
float sizePt = UiBuilder.DefaultFontSizePt;  // Points

// From UiBuilder instance
float sizePx = pluginInterface.UiBuilder.FontDefaultSizePx;
float sizePt = pluginInterface.UiBuilder.FontDefaultSizePt;

Font Atlas

Every plugin automatically gets its own private font atlas through UiBuilder.FontAtlas. This allows you to load custom fonts without affecting other plugins.

Font Atlas Properties

var fontAtlas = pluginInterface.UiBuilder.FontAtlas;

// Check if fonts are ready
if (fontAtlas.HasBuiltAtlas)
{
    // Atlas is built and ready
}

// Get atlas name (for debugging)
string name = fontAtlas.Name;

// Check if global scaling is applied
bool isScaled = fontAtlas.IsGlobalScaled;

Loading Custom Fonts

Font from File

Load a font from the filesystem:
private IFontHandle customFontHandle;

public void Initialize()
{
    var fontAtlas = pluginInterface.UiBuilder.FontAtlas;
    
    this.customFontHandle = fontAtlas.NewDelegateFontHandle(e => e.OnPreBuild(tk =>
    {
        tk.AddFontFromFile(
            @"C:\Windows\Fonts\arial.ttf",
            new SafeFontConfig
            {
                SizePx = 24.0f,
                GlyphRanges = tk.GetGlyphRangeDefaultEx()
            });
    }));
}

public void DrawUI()
{
    using (this.customFontHandle.Push())
    {
        ImGui.Text("Text in custom font");
    }
}

Font from Memory

Load a font from embedded resources or byte arrays:
this.customFontHandle = fontAtlas.NewDelegateFontHandle(e => e.OnPreBuild(tk =>
{
    var fontBytes = GetFontBytes(); // Your method to get font data
    tk.AddFontFromMemory(
        fontBytes,
        new SafeFontConfig { SizePx = 20.0f },
        "MyEmbeddedFont");
}));

Font from Stream

this.customFontHandle = fontAtlas.NewDelegateFontHandle(e => e.OnPreBuild(tk =>
{
    using var stream = File.OpenRead("path/to/font.ttf");
    tk.AddFontFromStream(
        stream,
        new SafeFontConfig { SizePx = 18.0f },
        leaveOpen: false,
        "StreamFont");
}));

Font Configuration

The SafeFontConfig struct controls how fonts are loaded:

Size Specification

new SafeFontConfig
{
    SizePx = 24.0f,  // Size in pixels
    // OR
    SizePt = 18.0f   // Size in points (1pt = 4/3px)
}

Glyph Ranges

Control which characters are loaded:
new SafeFontConfig
{
    SizePx = 20.0f,
    GlyphRanges = new ushort[]
    {
        0x0020, 0x00FF, // Basic Latin + Latin Supplement
        0x2000, 0x206F, // General Punctuation
        0,              // Null terminator
    }
}

Merging Fonts

Merge multiple fonts into one:
this.mergedFontHandle = fontAtlas.NewDelegateFontHandle(e => e.OnPreBuild(tk =>
{
    // Add base font
    var baseFont = tk.AddFontFromFile(
        "base.ttf",
        new SafeFontConfig { SizePx = 20.0f });
    
    // Merge icons into the base font
    tk.AddFontFromFile(
        "icons.ttf",
        new SafeFontConfig
        {
            SizePx = 20.0f,
            MergeFont = baseFont,  // Merge into base font
            GlyphRanges = iconRanges
        });
    
    // Set the final font
    tk.Font = baseFont;
}));

Additional Options

new SafeFontConfig
{
    SizePx = 20.0f,
    
    // Offset glyph positions
    GlyphOffset = new Vector2(0, 2),
    
    // Minimum advance X (for monospace)
    GlyphMinAdvanceX = 20.0f,
    
    // Extra spacing
    PixelSnapH = true,
    
    // Rasterizer settings
    OversampleH = 1,
    OversampleV = 1,
    
    // Rasterizer flags
    RasterizerMultiply = 1.0f
}

Dalamud Built-in Fonts

Adding Dalamud Default Font

The default Dalamud font includes game language support and icons:
this.dalamudFontHandle = fontAtlas.NewDelegateFontHandle(e => e.OnPreBuild(tk =>
{
    tk.AddDalamudDefaultFont(UiBuilder.DefaultFontSizePx);
}));

Adding FontAwesome Icons

this.iconFontHandle = fontAtlas.NewDelegateFontHandle(e => e.OnPreBuild(tk =>
{
    tk.AddFontAwesomeIconFont(new SafeFontConfig
    {
        SizePx = UiBuilder.DefaultFontSizePx
    });
}));

Adding Dalamud Asset Fonts

this.monoFontHandle = fontAtlas.NewDelegateFontHandle(e => e.OnPreBuild(tk =>
{
    tk.AddDalamudAssetFont(
        DalamudAsset.InconsolataRegular,
        new SafeFontConfig { SizePx = 20.0f });
}));
Available assets:
  • DalamudAsset.InconsolataRegular - Monospace font
  • DalamudAsset.FontAwesomeFreeSolid - FontAwesome icons

Adding Game Symbols

Add game’s built-in icon symbols:
this.symbolFontHandle = fontAtlas.NewDelegateFontHandle(e => e.OnPreBuild(tk =>
{
    var baseFont = tk.AddDalamudDefaultFont(20.0f);
    
    tk.AddGameSymbol(new SafeFontConfig
    {
        SizePx = 20.0f,
        MergeFont = baseFont
    });
    
    tk.Font = baseFont;
}));

Game Fonts

Use fonts from the game’s resources:
using Dalamud.Interface.GameFonts;

this.gameFontHandle = fontAtlas.NewGameFontHandle(new GameFontStyle
{
    FamilyAndSize = GameFontFamilyAndSize.Axis12,
    SizePx = 20.0f
});

Available Game Font Families

  • GameFontFamily.Axis - Standard UI font (sizes: 96, 12, 14, 18, 36)
  • GameFontFamily.Jupiter - Decorative font (sizes: 16, 20, 23, 46)
  • GameFontFamily.JupiterNumeric - Numeric font (sizes: 45, 90)
  • GameFontFamily.Meidinger - Sans-serif font (sizes: 16, 20, 40)
  • GameFontFamily.MiedingerMid - Mid-weight font (sizes: 10, 12, 14, 18, 36)
  • GameFontFamily.TrumpGothic - Gothic font (sizes: 184, 23, 34, 68)

Font Styling

var gameFont = new GameFontStyle(GameFontFamily.Axis, 20.0f)
{
    Bold = true,
    Italic = true,
    Weight = 1.0f,      // Boldness amount
    SkewStrength = 0.2f // Italics amount
};

this.styledFontHandle = fontAtlas.NewGameFontHandle(gameFont);

Supporting Multiple Languages

Add glyphs for languages not included by default:
this.multiLangFontHandle = fontAtlas.NewDelegateFontHandle(e => e.OnPreBuild(tk =>
{
    var baseFont = tk.AddFontFromFile(
        "myfont.ttf",
        new SafeFontConfig { SizePx = 20.0f });
    
    // Add extra glyphs for Dalamud's configured language
    tk.AttachExtraGlyphsForDalamudLanguage(new SafeFontConfig
    {
        SizePx = 20.0f,
        MergeFont = baseFont
    });
    
    tk.Font = baseFont;
}));

Specific Language Support

using System.Globalization;

tk.AttachWindowsDefaultFont(
    new CultureInfo("ja-JP"),  // Japanese
    new SafeFontConfig
    {
        SizePx = 20.0f,
        MergeFont = baseFont
    });

Font Rebuilding

The font atlas can be rebuilt when needed:

Automatic Rebuilding

// Atlas automatically rebuilds when needed
var autoRebuildMode = fontAtlas.AutoRebuildMode;
Modes:
  • FontAtlasAutoRebuildMode.Async - Rebuild asynchronously (recommended)
  • FontAtlasAutoRebuildMode.OnNewFrame - Rebuild synchronously on main thread
  • FontAtlasAutoRebuildMode.Disable - Manual rebuilding only

Manual Rebuilding

// Asynchronous rebuild (recommended)
await fontAtlas.BuildFontsAsync();

// Synchronous rebuild (blocks main thread)
fontAtlas.BuildFontsImmediately();

// Queue rebuild on next frame
fontAtlas.BuildFontsOnNextFrame();

Rebuild Events

fontAtlas.RebuildRecommend += () =>
{
    // Font atlas recommends rebuilding
    // (e.g., due to scale change)
};

fontAtlas.BuildStepChange += (step) =>
{
    // Build step changed (for progress tracking)
};

Suppressing Auto-Rebuild

When adding multiple fonts, suppress rebuilding until done:
using (fontAtlas.SuppressAutoRebuild())
{
    this.font1 = fontAtlas.NewGameFontHandle(style1);
    this.font2 = fontAtlas.NewGameFontHandle(style2);
    this.font3 = fontAtlas.NewGameFontHandle(style3);
}
// Rebuild happens once after the using block

Font Handles

Using Font Handles

Font handles provide safe access to fonts:
private IFontHandle myFontHandle;

public void DrawUI()
{
    // Method 1: Using statement (recommended)
    using (this.myFontHandle.Push())
    {
        ImGui.Text("Text in custom font");
    }
    
    // Method 2: Manual push/pop
    this.myFontHandle.Push();
    ImGui.Text("More text");
    this.myFontHandle.Pop();
}

Waiting for Fonts

Fonts may not be immediately available:
// Wait for font to be ready
await this.myFontHandle.WaitAsync();

// Check if font is ready
if (this.myFontHandle.Available)
{
    using (this.myFontHandle.Push())
    {
        ImGui.Text("Font is ready!");
    }
}

// Check for load errors
if (this.myFontHandle.LoadException != null)
{
    // Handle font load error
    var error = this.myFontHandle.LoadException;
}

Conditional Font Usage

if (this.myFontHandle.TryLock(out var errorMessage) is { } lockedFont)
{
    using (lockedFont)
    {
        var font = lockedFont.ImFont;
        // Use font
    }
}
else
{
    // Font not available, errorMessage contains reason
}

Font Change Events

this.myFontHandle.ImFontChanged += (handle, lockedFont) =>
{
    // Font has been rebuilt
    // Update any cached font metrics
};

Creating Isolated Font Atlases

For advanced scenarios, create separate font atlases:
var customAtlas = pluginInterface.UiBuilder.CreateFontAtlas(
    FontAtlasAutoRebuildMode.Async,
    isGlobalScaled: true,
    debugName: "CustomAtlas");

var fontHandle = customAtlas.NewDelegateFontHandle(e => e.OnPreBuild(tk =>
{
    tk.AddFontFromFile("special.ttf", new SafeFontConfig { SizePx = 30.0f });
}));

// Don't forget to dispose when done
customAtlas.Dispose();
Custom font atlases must be manually disposed. The plugin’s default atlas is automatically disposed on plugin unload.

Best Practices

1
Load Fonts Once
2
Load fonts during plugin initialization, not every frame.
3
Use Font Handles
4
Prefer IFontHandle over raw ImFontPtr for safety and automatic management.
5
Dispose Properly
6
Always dispose custom font handles and atlases when your plugin unloads.
7
Check Availability
8
Check Available or use WaitAsync() before using fonts that may not be ready.
9
Support Multiple Languages
10
Use AttachExtraGlyphsForDalamudLanguage to support international users.
11
Use Appropriate Sizes
12
Respect UiBuilder.DefaultFontSizePx and scale your fonts accordingly.

Complete Example

using Dalamud.Interface.ManagedFontAtlas;

public class FontExample : IDisposable
{
    private IFontHandle regularFont;
    private IFontHandle largeFont;
    private IFontHandle gameFont;
    
    public FontExample(DalamudPluginInterface pluginInterface)
    {
        var fontAtlas = pluginInterface.UiBuilder.FontAtlas;
        
        // Suppress rebuilding while loading multiple fonts
        using (fontAtlas.SuppressAutoRebuild())
        {
            // Regular custom font with icon support
            this.regularFont = fontAtlas.NewDelegateFontHandle(e => e.OnPreBuild(tk =>
            {
                var font = tk.AddFontFromFile(
                    @"C:\Windows\Fonts\segoeui.ttf",
                    new SafeFontConfig { SizePx = UiBuilder.DefaultFontSizePx });
                
                // Add FontAwesome icons
                tk.AddFontAwesomeIconFont(new SafeFontConfig
                {
                    SizePx = UiBuilder.DefaultFontSizePx,
                    MergeFont = font
                });
                
                // Add extra language support
                tk.AttachExtraGlyphsForDalamudLanguage(new SafeFontConfig
                {
                    SizePx = UiBuilder.DefaultFontSizePx,
                    MergeFont = font
                });
                
                tk.Font = font;
            }));
            
            // Large display font
            this.largeFont = fontAtlas.NewDelegateFontHandle(e => e.OnPreBuild(tk =>
            {
                tk.AddDalamudDefaultFont(36.0f);
            }));
            
            // Game font
            this.gameFont = fontAtlas.NewGameFontHandle(new GameFontStyle
            {
                FamilyAndSize = GameFontFamilyAndSize.Axis14,
                SizePx = 20.0f
            });
        }
    }
    
    public void DrawUI()
    {
        ImGui.Begin("Font Demo");
        
        using (this.regularFont.Push())
        {
            ImGui.Text("Regular custom font with icons: ");
            ImGui.SameLine();
            ImGui.Text(FontAwesomeIcon.Heart.ToIconString());
        }
        
        using (this.largeFont.Push())
        {
            ImGui.Text("Large Display Text");
        }
        
        using (this.gameFont.Push())
        {
            ImGui.Text("Game Font (Axis)");
        }
        
        ImGui.End();
    }
    
    public void Dispose()
    {
        this.regularFont?.Dispose();
        this.largeFont?.Dispose();
        this.gameFont?.Dispose();
    }
}

See Also

Build docs developers (and LLMs) love