Skip to content
SiteEmail

Getting your custom fonts into Gameface is straightforward, but the engine handles global scopes and fallbacks differently than a standard web browser.

This guide explores the global persistence of fonts across different views, explains how to architect reliable font fallbacks, and demonstrates how to build high-contrast text effects to ensure HUD readability against complex 3D environments.

How Gameface Renders Text: SDF, Raster, and Path Tessellation

Section titled “How Gameface Renders Text: SDF, Raster, and Path Tessellation”

Before loading custom fonts, it is useful to understand which rendering mode Gameface will use for your text. The engine does not use a single path - it chooses between three strategies based on font size:

Font sizeRendering modeKey behavior
Any size (default)SDF glyph renderingGlyphs baked at 32px, 52px, or 72px; upscaled via distance field math
Any size (opt-in via @font-face)Raster glyph renderingGlyphs CPU-rasterized at exact pixel size; separate glyph per size
Above 256pxPath tessellationGlyph outlines tessellated as geometry; regenerated every frame

Most text in Gameface uses Signed Distance Field (SDF) rendering. The engine bakes each glyph at one of three fixed sizes (32px, 52px, or 72px), then uses distance field math to scale it without regenerating glyph data. This is the fast path and the reason you can animate font-size without triggering expensive glyph uploads every frame.

The spread value (10% of the generation size - 4px, 6px, or 8px) controls how sharp or soft edges appear when scaling. The engine automatically picks the closest larger tier for a given font size.

SDF rendering has a known weakness with decorative or intricate fonts. When a font has fine serifs, tight ink traps, or complex stroke interactions, the SDF approximation smooths those details into rounded blobs - the font looks “melted” or mushy rather than sharp. This is a deliberate trade-off, not a bug.

The fix is coh-font-sdf: off inside the @font-face rule for the affected font:

fonts.css
@font-face {
font-family: 'OrnateTitleFont';
src: url('OrnateTitleFont.ttf');
coh-font-sdf: off; /* Forces CPU rasterization at exact pixel sizes */
}

With raster rendering active, Gameface generates one glyph per character per pixel size, producing pixel-accurate results where fine details survive.

SDF OFF vs SDF ON

The trade-off is GPU atlas memory: each size requires its own atlas entry rather than one shared baked glyph. Reserve coh-font-sdf: off for fonts where the quality loss is genuinely noticeable - display fonts, logos, and title cards rather than body copy.

Large Scale Text: Path Tessellation Above 256px

Section titled “Large Scale Text: Path Tessellation Above 256px”

When text renders above 256px, Gameface switches to path tessellation. Each glyph outline is tessellated as geometric path data drawn directly as 2D geometry - sharp at any size, but regenerated from scratch every frame.

If the visual accuracy of giant text is not critical (a large background watermark or a score counter), disable tessellation with text-rendering: optimizeSpeed:

hud.css
.score-display {
font-size: 320px;
text-rendering: optimizeSpeed; /* Falls back to SDF - no per-frame tessellation */
}

This makes sense when the size is transient (an animation briefly passing through 256px) or when the text is reading-functional but not decorative. For large static display text that is a visual centrepiece, keep path tessellation on and accept the per-frame cost.


Just like standard web development, the recommended way to load and use custom fonts in Gameface is through the CSS @font-face declaration. Gameface supports standard TrueType (.ttf) and OpenType (.otf) fonts, along with their collection formats (.ttc, .otc).

Exactly as you would in a standard browser, you must explicitly define separate @font-face blocks for different font weights and styles so the engine knows how to properly map them.

fonts.css
/* 1. Registering a standard TrueType font for headings */
@font-face {
font-family: 'SciFi-Header';
src: url('../fonts/SciFi-Header.ttf');
}
/* 2. Registering an OpenType font for body text */
@font-face {
font-family: 'Roboto';
src: url('../fonts/Roboto-Regular.otf');
font-weight: normal;
}
/* 3. Registering the Bold variant explicitly */
@font-face {
font-family: 'Roboto';
src: url('../fonts/Roboto-Bold.otf');
font-weight: bold;
}

The Gameface Difference: Global Persistence

Section titled “The Gameface Difference: Global Persistence”

In a standard web browser, fonts are scoped to the specific page you are currently viewing. If you navigate to a new HTML page, the browser unloads the old fonts and parses the new ones.

Gameface behaves entirely differently. A major difference from the HTML Standard is that fonts are global to the whole system and not unloaded after changing views.

If you load SciFi-Header in your Main Menu view, it stays in memory and can be used immediately in your in-game HUD view without being re-downloaded or re-parsed. Gameface keeps the fonts alive because it is common behavior in games to use the same fonts across multiple pages, avoiding the performance hit of reloading the same asset.

In game UI, especially when dealing with player names or global chat, a user might type a character (like a specific Kanji or an Emoji) that doesn’t exist in your primary font.

Gameface supports standard CSS per-character font fallbacks. You can specify a list of fonts, and the engine will seamlessly substitute missing characters with the next available font in the list.

fallbacks.css
.chat-message {
/* If Roboto is missing a character, Gameface checks Noto Sans CJK, then an Emoji font */
font-family: 'Roboto', 'Noto Sans CJK', 'EmojiFont';
}

While CSS handles the basics, Gameface has a few strict rules regarding how it matches those fallback fonts:

  • Style Fallbacks are Unsupported: Gameface won’t automatically match fonts with the same family name but different styles (like Italic or Oblique). These must be specified explicitly.
  • Generic Families: Gameface recognizes standard generic keywords (serif, sans-serif, monospace), but it maps them to a specific custom font defined by your engineering team via the C++ cohtml::SystemSettings::GenericFontFamilyNameFont option.
  • The Last Resort: If all CSS fallbacks fail, Gameface embeds a minimal “last resort” font that renders standard ASCII characters and displays a square symbol for missing Unicode characters.

If you are displaying third-party content (like an RSS feed or cross-platform player profiles) and do not have total control over the CSS, Gameface provides a powerful native override.

Your engineering team can use the C++ API cohtml::View::SetAdditionalFontFallbacks to specify global fallback font families. This acts as an invisible safety net, automatically appending these native fallbacks to the very end of any font-family list defined in your CSS.

A common challenge in game UI is ensuring that white text remains readable when the camera pans over a bright 3D environment.

To solve this, we can utilize the CSS text-shadow property. Because Gameface’s layout engine handles these standard properties natively, you can create complex text effects without writing custom shaders.

Here are three essential text styling techniques for game UIs:

Great for general HUD elements, menus, and subtitles. A simple offset shadow detaches the text from the 3D world behind it.

An example of a heavy drop shadow that creates a strong contrast against bright 3D background:

drop-shadow.html
<div class="map-marker">Riverheart Pool</div>
drop-shadow.css
.map-marker {
color: white;
/* offset-x | offset-y | blur-radius | color */
text-shadow: 1px 1px 10px black;
}

Great for player names and floating combat text. Gameface supports the text-stroke CSS property, which draws a solid stroke directly around the text glyphs in a single declaration.

crisp-outline.html
<div class="hud-player crisp-outline">Player One</div>
crisp-outline.css
.crisp-outline {
color: white;
text-stroke: 1px #000;
}

Great for critical warnings, sci-fi themes, or active states. A zero-offset shadow with a massive blur radius creates a seamless glowing effect around the text.

An example of a neon glow effect in a sci-fi skill tree UI that blends perfectly with the other glowing elements:

neon-glow.html
<div class="skill-cost">Skill cost 2</div>
neon-glow.css
.glowing-text {
color: white;
text-shadow: 0px 0px 1vh;
}