Multi-Language Fonts & CJK Support

The core challenge of multi-language text animation is correctly segmenting CJK (Chinese/Japanese/Korean) characters and handling Unicode code points. Texturge solves this through FCharBreakIterator, the Texturge::Unicode utilities, and code-unit/glyph bidirectional mapping.

NOTE

Texturge has no UTexturgeFontAsset, font atlas baking, or SDF glyph cache. Character rendering is handled by the standard UMG/Slate font pipeline; the plugin only handles animation curve logic and glyph segmentation.

Glyph Segmentation Pipeline

Why Special Handling Is Needed

  • CJK text does not use spaces for tokenization; every character is independently meaningful
  • UTF-16 code units (TCHAR) are not Unicode code points: supplementary-plane characters like Emoji consist of surrogate pairs (2 code units)
  • Per-glyph animation must operate on code points, not code units

FCharBreakIterator

FCharBreakIterator implements the IBreakIterator interface and precomputes all break points at SetString:

// Implements the IBreakIterator interface
FCharBreakIterator Iterator;
Iterator.SetString(InText);          // precomputes the break point array (including 0 and the end)
int32 Pos = Iterator.ResetToBeginning();
while ((Pos = Iterator.MoveToNext()) != INDEX_NONE)
{
    // each break point = one glyph boundary
}

Key capabilities:

  1. Surrogate-pair safe — supplementary-plane characters (Emoji 🎮 etc.) count as one glyph and never split
  2. CJK attachment — CJK punctuation attaches correctly (IsCJKPunctuation)
  3. Hangul syllables — Hangul syllable blocks are handled as a whole
  4. Full cursor interface: GetCurrentPosition() / MoveToPrevious() / MoveToCandidateBefore / MoveToCandidateAfter

Code Unit ↔ Glyph Bidirectional Mapping

UTextAnimator maintains two mapping arrays (introduced in 0.2.0, unified by code point index across the whole text):

MappingDescription
CodeUnitToGlyphIndexcode unit index → glyph index (both units of a surrogate pair map to the same glyph)
GlyphIndexToCodeUnitglyph index → code unit index

GetGlyphIndexForCodeUnit(int32) exposes a public query. Typewriter reveal and rich text segment extraction (SerializeSubstring) both operate on code point indices.

Compared with Traditional Methods

MethodLatinCJKEmoji (surrogate pairs)
Split by TCHAR (UTF-16 code unit)CorrectCorrectWrong (splits into 2 glyphs)
Split by byteWrongWrongWrong
FCharBreakIterator + code point indexCorrectCorrectCorrect

Unicode Utility Class

The Texturge::Unicode namespace provides code-point-level classification functions (UnicodeUtils.h, all FORCEINLINE):

FunctionClassification range
IsCJKUnifiedIdeographs(uint32)main block + Ext A~F/I + compatibility ideographs (0x3400-0x2FA1F)
IsHiragana(uint32)hiragana 0x3040-0x309F
IsKatakana(uint32)katakana 0x30A0-0x30FF, 0x31F0-0x31FF
IsHangulSyllables(uint32)Hangul syllables 0xAC00-0xD7AF, Hangul Jamo 0x1100-0x11FF
IsCJKPunctuation(uint32)CJK punctuation 0x3000-0x303F, 0xFE30-0xFE4F, 0xFF01-0xFF60, 0xFFE0-0xFFEE
IsCJK(uint32)aggregation of the above five
IsHighSurrogate(TCHAR) / IsLowSurrogate(TCHAR)UTF-16 surrogate zone classification
ComposeSurrogatePair(TCHAR, TCHAR)surrogate pair composition to a 32-bit code point

These utilities classify each glyph in BuildScheduleInfos (bIsWhitespace / bIsPunctuation / bIsCJK / bIsDecorator), determining its scheduling behavior.

Font Fallback

Texturge does not manage font assets directly and relies on the UMG font pipeline:

  1. Set the primary font in the Font property of UAnimatedTextBlock / UAnimatedRichTextBlock (inherited from the base class)
  2. UE5’s Composite Font system automatically handles missing-character fallback
  3. For complex multi-language coverage, use composite fonts’ Sub-Font feature to assign a font per writing system

TIP

For multi-language projects, use the composite font’s sub-font feature to assign fonts per writing system instead of stacking multiple widgets.

Testing CJK Animations

Enter the following mixed text in the preview text box of STextAnimationDesignerView (UTexturgePreviewSceneConfig::PreviewText) to verify support:

English 日本語 한국어 中文 العربية हिन्दी
Emoji: 🎮🎯✨
全角:ABCD1234

Verification Checklist

  1. Glyph count correct — each CJK character / Emoji counts as one glyph (surrogate pairs never split)
  2. Scheduling delay uniform — per-glyph rhythm does not skip frames due to varying character encoding lengths
  3. Classification correct — whitespace / punctuation / CJK / decorator classifications are correct in the BuildScheduleInfos output
  4. RTL text — Arabic lays out right-to-left correctly (layout handled by Slate)
images/cjk-animation-preview.png — CJK animation preview screenshot: mixed text (English 日本語 한국어 中文 العربية) revealed per-glyph in the designer viewport, with glyph count and code point indices annotated below, Emoji shown as a single glyph