Guide
Text and languages
The engine has its own text stack, from Unicode data to glyph pixels. Text in any language is shaped, broken into lines and drawn the way a browser does it.
Fonts
Fonts come from font-family and @font-face. Put the file in Assets/Resources/DevCoreUIEngine/Fonts and name it by URL:
@font-face {
font-family: "Title";
src: url(Fonts/Title-Bold.ttf);
font-weight: 700;
}
h1 { font-family: "Title", sans-serif; }
Store the file with a .bytes ending (Title-Bold.ttf.bytes) so that Unity keeps the font's own bytes; the URL is written without it.
- Read: TTF, OTF, TTC, CFF outlines, and the color formats COLR v0, CBDT and sbix.
- Not read: WOFF, WOFF2, variable fonts, COLR v1 and SVG glyphs. Glyphs are not hinted.
- Bold and oblique are synthesized like Chromium does when a family has no such face.
- Generic families (
sans-serif,serif,monospace) are the system's, the way Chromium maps them.
Fallback, character by character
When the fonts you named do not have a character, the engine looks further, per character, in this order:
- Your game's font packs for the character's script or language.
- The platform's choice. On Windows this is what Chromium picks, measured over 30,000 characters.
- System fonts for the script, then any installed font that has the glyph.
The lang attribute picks the right CJK glyph variants (ja, zh-Hans, zh-Hant, ko). Emoji come from a color font. When nothing has the character, a hollow box is drawn.
Font packs
A Font Fallback Settings asset (Assets → Create → DevCore UI → Font Fallback Settings) lists fonts per script, by ISO 15924 code: Arab, Hebr, Deva, Thai, Hans, Hant, Jpan, Kore, Emoji, Symbols, Math, Default. It also says whether system fonts may be used.
WebGL and consoles have no system fonts to fall back on: ship packs for every script your game shows, including Default.
Shaping
Shaping turns characters into positioned glyphs: joining Arabic letters, reordering Indic vowels, stacking marks. The engine's shaper is a C# port of HarfBuzz and gives identical output (glyphs, clusters, positions) to HarfBuzz 14.5.0 on 20,000 test texts in 38 scripts.
| Shaper | Scripts |
|---|---|
| Arabic | Arabic, Persian, Urdu, Syriac; presentation-form fallback for fonts without OpenType tables |
| Hebrew | Hebrew, with marks |
| Indic | Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, Malayalam |
| South-East Asian | Thai, Lao, Khmer, Myanmar |
| Hangul | Korean |
| Universal | Tibetan, Javanese, Balinese and the other scripts of the Universal Shaping Engine |
| Default | Latin, Greek, Cyrillic, CJK and everything else, with kerning and ligatures |
Unicode
- Line breaking: UAX #14 with Chromium's rules for CJK, and
line-break,word-break,overflow-wrap. - Dictionaries for Thai, Lao, Khmer and Burmese, which have no spaces between words. They are loaded on first use.
- Bidirectional text: UAX #9, with
direction,dir,dir="auto",unicode-bidiand<bdi>. Text editing works right to left. - Segmentation: UAX #29 graphemes and words, so the caret and deletion treat an emoji or a syllable as one.
- Also: normalization, CJK punctuation trimming (
text-spacing-trim), CJK justification, tabs, soft hyphens.
The data is Unicode 17.
Glyphs
The engine rasterizes glyphs itself, filtered like DirectWrite's grayscale text, into a shared atlas. There are two kinds:
| Kind | Best for |
|---|---|
| Bitmap | Text that keeps its size: sharp, pixel for pixel like a browser |
| Distance field (SDF) | Text that is scaled, rotated or animated, and world panels: one glyph serves every size |
-devcore-text-rendering: auto (the default) uses bitmaps unless the text is transformed. Set sdf for text whose size animates.
Text that changes every frame
A timer or a score written as {time:F1} makes no string: digits are written straight into the page, only that line is laid out again, and only the glyphs that changed are painted. From code, Text.SetData takes a ReadOnlySpan<char>.
Use font-variant-numeric: tabular-nums on timers so digits keep their width.