This guide covers the basics of setting up and using UniText in your Unity project.
Add the UniText component to any UI GameObject:
- Select any GameObject with RectTransform (or create via GameObject > UI > Image)
- Add component: Add Component > UniText
- Enter text in the Text field
Default fonts and appearance from Project Settings are applied automatically.
// Via code — you must assign FontStack and Appearance manually:
var uniText = gameObject.AddComponent<UniText>();
uniText.FontStack = myFontStack; // Required
uniText.Appearance = myAppearance; // Required
uniText.Text = "Hello, World!";Note: Editor defaults (from Project Settings > UniText) are only applied when adding the component via Inspector.
UniText uses its own font format supporting three rendering modes:
| Mode | Description | Use Case |
|---|---|---|
| SDF | Signed Distance Field — resolution-independent | Default. Supports outlines, shadows, glow at any scale |
| Smooth | Anti-aliased grayscale bitmap | Pixel-perfect at specific size |
| Mono | 1-bit monochrome bitmap | Retro/pixel art style |
Context Menu (from fonts already in the project):
- Import your font files (
.ttf,.otf, or.ttc) into Unity - Select one or multiple fonts in the Project window
- Right-click > Create > UniText > Font Asset
- A
.assetfile is created next to each source font
Supports batch creation — select 10 fonts, get 10 assets in one click.
Font Tools Window (also useful for creating from fonts outside the project):
If the font file is somewhere on your computer but not imported into the Unity project:
- Open Tools > UniText > Font Tools
- Drag-and-drop font files from the Project window, or click Browse Files to pick fonts from anywhere on your computer
- Click Create N UniText Font Asset(s)
- For external fonts, you will be prompted for an output folder within Assets
This is also useful for quick drag-and-drop workflow without manually importing fonts first.
Font bytes are embedded directly in the asset — there is no external file dependency at runtime.
Select a UniTextFont asset to configure in the Inspector:
| Setting | Range | Default | Description |
|---|---|---|---|
| Sampling Point Size | 8–256 | 90 | Size at which glyphs are rasterized into the atlas. Higher = more detail but larger atlas |
| Atlas Size | 256–4096 | 1024 | Atlas texture dimensions (square). Increase if many glyphs need to fit |
| Spread Strength | 0.1–1.0 | 0.25 | SDF spread as fraction of point size. Controls how far the distance field extends. Higher = smoother edges at large scales but thicker padding |
| Render Mode | SDF/Smooth/Mono | SDF | Glyph rendering mode |
After changing settings, click Apply to rebuild the atlas.
The Inspector also shows:
- Font Data Status — whether font bytes are embedded
- Runtime Data — glyph count, character count, atlas memory
- Atlas Preview — visual preview of atlas texture(s)
UniTextFontStack defines which fonts to use and in what fallback order. The first font is the main font; subsequent fonts serve as fallbacks for glyphs the main font doesn't have.
There are two creation modes when you select multiple UniTextFont assets:
- Select 2+ UniTextFont assets in the Project window
- Right-click > Create > UniText > Fonts (Combined)
- Creates one UniTextFontStack containing all selected fonts
UniTextFontStack (Combined)
├── Inter-Regular <- fonts[0] — main font (Latin, Cyrillic)
├── NotoSansArabic <- fonts[1] — fallback for Arabic
└── NotoSansHebrew <- fonts[2] — fallback for Hebrew
When rendering "Hello مرحبا עולם":
- "Hello" — Inter-Regular has Latin glyphs, used directly
- "مرحبا" — Inter-Regular has no Arabic glyphs, falls back to NotoSansArabic
- "עולם" — Neither of the above has Hebrew, falls back to NotoSansHebrew
Use case: Multilingual text in a single component. One component can render text in any language.
- Select 1+ UniTextFont assets in the Project window
- Right-click > Create > UniText > Fonts (Per Font)
- Creates one separate UniTextFontStack for each selected font
Inter-Regular FontStack.asset <- contains only Inter-Regular
NotoSansArabic FontStack.asset <- contains only NotoSansArabic
NotoSansHebrew FontStack.asset <- contains only NotoSansHebrew
Use case: When different components use different fonts. Swap font stacks per component rather than building fallback chains.
UniTextFontStack has a fallbackStack field that references another UniTextFontStack. The system searches the primary fonts first, then walks the fallbackStack chain. Circular references are handled automatically.
This is useful when you have a shared set of language fonts that you want to reuse across different stacks without copying the same font list everywhere.
Example: Create one stack with all language fallbacks, then reference it from any other stack:
LanguageSupportStack <- create once
├── NotoSansArabic
├── NotoSansHebrew
├── NotoSansDevanagari
├── NotoSansThai
└── NotoSansCJK
HeadingStack <- for headings
├── Montserrat-Bold
└── fallbackStack → LanguageSupportStack
BodyStack <- for body text
├── Inter-Regular
└── fallbackStack → LanguageSupportStack
CaptionStack <- for captions
├── Inter-Light
└── fallbackStack → LanguageSupportStack
All three stacks get full language support through one shared reference. Add a new language font to LanguageSupportStack — all stacks pick it up automatically.
UniTextAppearance maps fonts to rendering materials. It separates what fonts to use from how to render them.
Different fonts in a fallback chain may need different materials:
- Connected scripts (Arabic, Persian, Urdu) — letters connect into words. A single-pass outline/shadow creates visible seams at glyph boundaries. Solution: 2-pass shader (outline layer first, then text on top)
- Different SDF spread — fonts generated with different spread values need matching shader settings
- Visual variety — some fonts need glow, others need outlines
- Assets > Create > UniText > Appearance
- Set Default Material — used for all fonts unless overridden
- Optionally add Font Materials — per-font material overrides
UniTextAppearance
├── Default Materials: [UniText-SDF]
└── Font Materials:
├── NotoSansArabic → [UniText-SDF-2Pass-Outline, UniText-SDF-2Pass-Face]
└── HeaderFont → [UniText-SDF-Glow]
Material resolution order:
- Font-specific override (if set) — exact match by font asset
- Default materials — fallback for any font without an override
- Emoji fonts always use their own built-in material automatically
- 1 material — standard single-pass rendering
- 2 materials — 2-pass rendering:
[0]= outline/shadow pass,[1]= face pass. Essential for connected scripts
- One Appearance per visual style — create separate appearances for "body text", "heading", "caption", etc.
- Share across components — Appearance is a ScriptableObject. Assign the same asset to hundreds of components. Change the material once — all update
- Arabic/Persian always use 2-pass — single-pass outlines create visible seams between connected letters
- Don't duplicate materials — if all fonts use the same shader settings, just set the Default Material
Open via Tools > UniText > Font Tools. Two tabs:
Batch creation of UniTextFont assets from source files.
Adding fonts:
- Drag & drop — drop
.ttf/.otf/.ttcfiles into the drop area - Browse Files — opens file dialog with multi-select
- Project selection — selecting font files in the Project window auto-adds them
Each entry shows the font name and file size. Click Create N UniText Font Asset(s) to generate all assets.
Additional features:
- Copy All Characters — extracts every codepoint the font supports and copies to clipboard. Useful for checking font coverage or as input for the Font Subsetter
Output:
- Project fonts (within Assets): saved next to the source file
- External fonts (outside Assets): prompts for output folder
Create optimized subset fonts by keeping or removing specific character ranges. Reduces font file size for builds where you don't need full Unicode coverage.
Two modes:
Keep Mode — only selected characters remain in the font:
- Select script ranges (Latin, Cyrillic, Arabic, etc.) and/or type custom text
- The output font contains only those characters (plus GSUB-related composed forms)
- Example: Keep only "Basic Latin + Cyrillic" for a game targeting English/Russian
Remove Mode — selected characters are removed from the font:
- Select script ranges and/or type custom text to remove
- Intelligent composition detection: combined characters (emoji sequences, ligatures) are removed as glyphs while preserving their component codepoints
- Two-pass process:
- Codepoint removal with GSUB closure (handles contextual forms)
- Composition glyph removal without closure (preserves components)
- Example: Remove CJK range from a font that covers everything
Available script ranges (30 sets in 10 groups):
| Group | Ranges |
|---|---|
| Latin | Basic Latin, Extended Latin, Vietnamese |
| European | Cyrillic, Greek, Armenian, Georgian |
| Semitic | Arabic, Hebrew |
| N. Indic | Devanagari, Bengali, Gujarati, Gurmukhi |
| S. Indic | Tamil, Telugu, Kannada, Malayalam |
| SE Asian | Thai, Lao, Myanmar, Khmer |
| E. Asian | Hiragana, Katakana |
| Other | Sinhala, Tibetan |
| Symbols (1) | Digits, Punctuation, Currency, Math |
| Symbols (2) | Arrows, Box Drawing |
Output: Saves a new .ttf file with the suffix _subset. Reports original size, subset size, and reduction percentage.
Practical scenarios:
| Scenario | Mode | Configuration |
|---|---|---|
| Mobile game, English only | Keep | Basic Latin + Digits + Punctuation |
| European app, no Asian scripts | Remove | Devanagari, Bengali, Tamil, Thai, CJK, etc. |
| Localized to Arabic + English | Keep | Basic Latin + Arabic + Digits + Punctuation |
| Remove unused emoji from Noto | Remove | Custom text with emoji codepoints |
UniText features an extensible markup system based on Modifiers and Parse Rules.
The system separates what to parse from what to do:
- Parse Rule (
IParseRule) — finds patterns in text and produces ranges - Modifier (
BaseModifier) — applies a visual or structural effect to those ranges
This separation means:
- One modifier can work with multiple parse rules
- One parse rule can trigger different modifiers
- You can create custom rules and modifiers independently
Example: BoldModifier can work with any rule that detects "bold" intent:
| Parse Rule | Syntax | Modifier |
|---|---|---|
| BoldParseRule (built-in) | <b>bold</b> |
BoldModifier |
| Your MarkdownBoldRule | **bold** |
BoldModifier |
| Your BBCodeRule | [b]bold[/b] |
BoldModifier |
| Tag | Modifier | Parse Rule | Example |
|---|---|---|---|
<b> |
BoldModifier | BoldParseRule | <b>bold</b> |
<i> |
ItalicModifier | ItalicParseRule | <i>italic</i> |
<u> |
UnderlineModifier | UnderlineParseRule | <u>underline</u> |
<s> |
StrikethroughModifier | StrikethroughParseRule | <s>strike</s> |
<color> |
ColorModifier | ColorParseRule | <color=#FF0000>red</color> |
<size> |
SizeModifier | SizeParseRule | <size=24>large</size> |
<gradient> |
GradientModifier | GradientParseRule | <gradient=rainbow>text</gradient> |
<cspace> |
LetterSpacingModifier | CSpaceParseRule | <cspace=5>wider</cspace> |
<line-height> |
LineHeightModifier | LineHeightParseRule | <line-height=1.5>text</line-height> |
<line-spacing> |
LineHeightModifier | LineSpacingParseRule | <line-spacing=10>text</line-spacing> |
<upper> |
UppercaseModifier | UppercaseParseRule | <upper>text</upper> |
<ellipsis> |
EllipsisModifier | EllipsisTagRule | <ellipsis=1>long text</ellipsis> |
<li> |
ListModifier | (tag-based) | <li>bullet item</li> |
<link> |
LinkModifier | LinkTagParseRule | <link=url>click</link> |
<obj> |
ObjModifier | ObjParseRule | <obj=icon/> |
| Parse Rule | Syntax | Modifier |
|---|---|---|
| MarkdownLinkParseRule | [text](url) |
LinkModifier |
| MarkdownListParseRule | - item, * item, 1. item |
ListModifier |
| RawUrlParseRule | Auto-detects https://... URLs |
LinkModifier |
| Parse Rule | Purpose | Modifier |
|---|---|---|
| RangeRule | Apply modifier to specific ranges without markup | Any |
| StringParseRule | Match literal string patterns | Any |
| CompositeParseRule | Combine multiple rules into one | Any |
Color:
- Hex:
#RGB,#RRGGBB,#RRGGBBAA - Named (20 colors): white, black, red, green, blue, yellow, cyan, magenta, orange, purple, gray, lime, brown, pink, navy, teal, olive, maroon, silver, gold
Size:
- Absolute:
<size=24>— 24 pixels - Percentage:
<size=150%>— 150% of base size - Relative:
<size=+10>/<size=-5>— offset from base
Gradient:
- Default:
<gradient=name>— horizontal (0 degrees) - Angled:
<gradient=name,45>— rotated (0=right, 90=up) - Logical:
<gradient=name,L>— by character index, not visual position
Gradients are defined in the UniTextGradients asset (Project Settings > UniText > Gradients).
Letter spacing:
- Pixels:
<cspace=5>— 5px extra spacing - Em units:
<cspace=0.1em>— 0.1 em extra spacing
Ellipsis (text truncation):
<ellipsis=1>— truncate end (default):Hello Wo...<ellipsis=0>— truncate start:...o World<ellipsis=0.5>— truncate middle:Hel...rld- Any float 0-1 for fine-grained control
- Expand Mod Registers list on the UniText component
- Click + to add an entry
- Select a Rule (e.g., ColorParseRule)
- Select a Modifier (e.g., ColorModifier)
Each entry is a Rule+Modifier pair. Tags from the Rule are parsed in text, and the Modifier applies the effect to matched ranges.
uniText.RegisterModifier(new ModRegister
{
Rule = new ColorParseRule(),
Modifier = new ColorModifier()
});Remove at runtime:
bool removed = uniText.UnregisterModifier(modRegister);
// Or remove all:
uniText.ClearModifiers();Problem: You have 50 UniText components that all need the same set of modifiers (bold, italic, color, links). Setting up each one manually is tedious and error-prone.
Solution: ModRegisterConfig is a ScriptableObject that stores a reusable list of Rule+Modifier pairs.
- Assets > Create > UniText > Mod Register Config
- Add your modifier pairs:
MyModConfig.asset
├── [0] BoldModifier + BoldParseRule
├── [1] ItalicModifier + ItalicParseRule
├── [2] ColorModifier + ColorParseRule
├── [3] LinkModifier + LinkTagParseRule
└── [4] UnderlineModifier + UnderlineParseRule
- On each UniText component, add this config to the Mod Register Configs list
- Single source of truth — change the config, all components update
- No duplication — define modifiers once, reference everywhere
- Combinable — a component can have multiple configs plus its own local ModRegisters. They all work together
- Version control friendly — one asset to track rather than per-component settings
| Feature | Local Mod Registers | ModRegisterConfig |
|---|---|---|
| Scope | Per-component | Shared across components |
| Edit location | UniText Inspector | Config asset Inspector |
| Use case | Component-specific markup | Project-wide standard markup |
A component's effective set of modifiers = its local Mod Registers + all Mod Register Configs.
RangeRule lets you apply a modifier to specific text ranges programmatically, without any tags in the text itself.
To apply a modifier to the entire text (e.g., make everything a specific color), use the range "..":
var rangeRule = new RangeRule();
rangeRule.data.Add(new RangeRule.Data
{
range = "..", // ".." means the full text range
parameter = "#FF0000" // parameter passed to the modifier
});
uniText.RegisterModifier(new ModRegister
{
Rule = rangeRule,
Modifier = new ColorModifier() // entire text becomes red
});RangeRule uses C#-style range notation:
| Range | Meaning |
|---|---|
".." |
Entire text (start to end) |
"0..10" |
Codepoints 0 through 9 |
"5.." |
From codepoint 5 to end |
"..5" |
From start to codepoint 4 |
"2..^3" |
From codepoint 2 to 3 from end |
"^5.." |
Last 5 codepoints |
var rangeRule = new RangeRule();
rangeRule.data.Add(new RangeRule.Data { range = "0..5", parameter = "#FF0000" });
rangeRule.data.Add(new RangeRule.Data { range = "10..20", parameter = "#00FF00" });
uniText.RegisterModifier(new ModRegister
{
Rule = rangeRule,
Modifier = new ColorModifier()
});
// Codepoints 0-4 are red, 10-19 are green| Scenario | Range | Modifier |
|---|---|---|
| Bold the entire text | ".." |
BoldModifier |
| Highlight first word (5 chars) | "0..5" |
ColorModifier with color parameter |
| Underline last 10 chars | "^10.." |
UnderlineModifier |
| Apply size to specific range | "3..8" |
SizeModifier with size parameter |
StringParseRule matches literal string patterns in text (no XML/HTML syntax):
var emojiRule = new StringParseRule();
emojiRule.patterns = new[] { ":)", ":(", ":D" };
emojiRule.hasReplacement = true;
emojiRule.replacement = "😊";
uniText.RegisterModifier(new ModRegister
{
Rule = emojiRule,
Modifier = new EmptyModifier() // no visual effect, just replacement
});
// ":)" in text gets replaced with "😊"CompositeParseRule groups multiple rules into one. It tries child rules in order and returns the first match:
var composite = new CompositeParseRule();
composite.rules.Add(new LinkTagParseRule()); // <link=url>text</link>
composite.rules.Add(new MarkdownLinkParseRule()); // [text](url)
composite.rules.Add(new RawUrlParseRule()); // auto-detect https://...
uniText.RegisterModifier(new ModRegister
{
Rule = composite,
Modifier = new LinkModifier()
});
// All three link syntaxes work with a single modifierParse rules have a Priority property that controls matching order (higher = matched first):
| Priority | Use Case | Example |
|---|---|---|
| Positive (e.g., 10) | Explicit markup should match before anything else | Custom rules |
| 0 (default) | Standard tag-based and markdown rules | BoldParseRule, MarkdownLinkParseRule |
| Negative (e.g., -100) | Auto-detection, should only match if nothing else did | RawUrlParseRule (-100) |
This prevents conflicts: <link=url>https://example.com</link> won't be double-matched by both LinkTagParseRule and RawUrlParseRule.
Implement IParseRule to create your own markup syntax:
public interface IParseRule
{
int Priority => 0;
int TryMatch(string text, int index, PooledList<ParsedRange> results);
void Finalize(string text, PooledList<ParsedRange> results) { }
void Reset() { }
}Simplest approach — extend TagParseRule:
If your syntax follows the <tag>content</tag> pattern, just extend TagParseRule — all parsing logic is handled for you:
[Serializable]
public sealed class MyCustomTagRule : TagParseRule
{
protected override string TagName => "highlight";
protected override bool HasParameter => true;
// Now <highlight=yellow>text</highlight> works automatically
}UniText has three modifier base classes for different use cases:
For modifiers that transform codepoints before rendering (like uppercase):
[Serializable]
public class LowercaseModifier : BaseModifier
{
protected override void OnEnable() { }
protected override void OnDisable() { }
protected override void OnDestroy() { }
protected override void OnApply(int start, int end, string parameter)
{
var codepoints = buffers.codepoints.data;
var count = buffers.codepoints.count;
var clampedEnd = Math.Min(end, count);
for (var i = start; i < clampedEnd; i++)
codepoints[i] = char.ToLowerInvariant((char)codepoints[i]);
}
}For modifiers that change glyph appearance during mesh generation (color, underline, etc.):
[Serializable]
public class HighlightModifier : GlyphModifier<byte>
{
[SerializeField] private Color highlightColor = Color.yellow;
protected override string AttributeKey => "highlight";
protected override Action GetOnGlyphCallback() => OnGlyph;
protected override void DoApply(int start, int end, string parameter)
{
var buffer = attribute.buffer.data;
buffer.SetFlagRange(start, Math.Min(end, buffers.codepoints.count));
}
private void OnGlyph()
{
var gen = UniTextMeshGenerator.Current;
if (!attribute.buffer.data.HasFlag(gen.currentCluster))
return;
var colors = gen.Colors;
var baseIdx = gen.vertexCount - 4;
colors[baseIdx] = colors[baseIdx + 1] =
colors[baseIdx + 2] = colors[baseIdx + 3] = highlightColor;
}
}For clickable/hoverable text regions:
[Serializable]
public class HashtagModifier : InteractiveModifier
{
public override string RangeType => "hashtag";
public override int Priority => 50;
public event Action<string> HashtagClicked;
protected override void OnApply(int start, int end, string parameter)
{
AddRange(start, end, parameter); // Register clickable region
}
protected override void HandleRangeClicked(InteractiveRange range, TextHitResult hit)
{
HashtagClicked?.Invoke(range.data);
}
protected override void HandleRangeEntered(InteractiveRange range, TextHitResult hit) { }
protected override void HandleRangeExited(InteractiveRange range) { }
}SetOwner(uniText) <- attached to component
|
Prepare() <- lazy init on first Apply (allocate buffers)
|
PrepareForParallel() <- cache main-thread-only values before worker threads
|
Apply(start, end, param) <- called per matched range (calls OnApply)
|
OnDisable() <- text changed, unsubscribe from events
|
OnDestroy() <- component destroyed, release all resources
- No
new T[]at runtime — useUniTextArrayPool<T>.Rent/Returnorbuffers.GetOrCreateAttributeData<T>() - Subscribe in OnEnable, unsubscribe in OnDisable — prevents stale callbacks
- Use
PrepareForParallel()for anything that calls Unity API (Material.GetFloat(), etc.) - Modifiers are fully encapsulated — external code doesn't need to know about them. If a modifier adds geometry, it calls UniTextMeshGenerator methods internally
UniText provides built-in support for clickable regions, hover detection, and visual feedback.
// Any text click
uniText.TextClicked += hit => Debug.Log($"Clicked cluster: {hit.cluster}");
// Interactive range events (links, custom ranges)
uniText.RangeClicked += hit => Debug.Log($"Clicked: {hit.range.data}");
uniText.RangeEntered += hit => Debug.Log($"Hover enter: {hit.range.data}");
uniText.RangeExited += hit => Debug.Log($"Hover exit: {hit.range.data}");
// Continuous hover tracking
uniText.HoverChanged += hit => Debug.Log($"Hover at cluster: {hit.cluster}");For custom interaction logic:
// Local space
TextHitResult hit = uniText.HitTest(localPosition);
// Screen space
TextHitResult hit = uniText.HitTestScreen(screenPosition, eventCamera);
// Get visual bounds for a cluster range
var bounds = new List<Rect>();
uniText.GetRangeBounds(startCluster, endCluster, bounds);The Highlighter property controls visual feedback. The built-in DefaultTextHighlighter provides click and hover animations:
if (uniText.Highlighter is DefaultTextHighlighter highlighter)
{
highlighter.ClickColor = new Color(1, 0, 0, 0.5f);
highlighter.HoverColor = new Color(0, 0, 1, 0.1f);
highlighter.FadeDuration = 0.5f;
}
// Disable highlighting
uniText.Highlighter = null;Implement your own by extending TextHighlighter and overriding OnRangeClicked, OnRangeEntered, OnRangeExited, Update.
UniText automatically handles:
- RTL scripts (Arabic, Hebrew) — text flows right-to-left
- BiDi mixing — "Hello עולם World" renders correctly
- Complex shaping — Arabic ligatures, Indic conjuncts, etc. (via HarfBuzz)
- Auto (default) — detects from first strong directional character
- LeftToRight — force left-to-right
- RightToLeft — force right-to-left
uniText.BaseDirection = TextDirection.Auto;
uniText.Text = "مرحبا بالعالم"; // Renders right-to-leftEmoji work automatically — the system emoji font is detected and used:
uniText.Text = "Hello! 👋 Great job! 🎉";| Platform | Emoji Font |
|---|---|
| Windows | Segoe UI Emoji |
| macOS | Apple Color Emoji |
| iOS | Core Text (native API) |
| Android | NotoColorEmoji (via fonts.xml) |
| Linux | NotoColorEmoji / Symbola |
| WebGL | Browser Canvas 2D |
Emoji are rendered as color bitmaps in a separate atlas. The emoji font is checked first for emoji-presentation codepoints, then falls back to the regular font stack.
| Property | Type | Default | Description |
|---|---|---|---|
Text |
string | "" |
Text content with optional markup |
FontStack |
UniTextFontStack | — | Font collection with fallback chain |
Appearance |
UniTextAppearance | — | Material configuration |
FontSize |
float | 36 | Base font size in points |
color |
Color | white | Base text color |
BaseDirection |
TextDirection | Auto | LTR, RTL, or Auto |
WordWrap |
bool | true | Enable/disable word wrapping |
HorizontalAlignment |
HorizontalAlignment | Left | Left, Center, Right |
VerticalAlignment |
VerticalAlignment | Top | Top, Middle, Bottom |
AutoSize |
bool | false | Auto-fit text to container |
MinFontSize |
float | 10 | Auto-size minimum |
MaxFontSize |
float | 72 | Auto-size maximum |
Highlighter |
TextHighlighter | DefaultTextHighlighter | Interaction visual feedback |
| Property | Type | Description |
|---|---|---|
CleanText |
string | Text with all markup stripped |
CurrentFontSize |
float | Effective font size (after auto-sizing) |
ResultSize |
Vector2 | Computed text dimensions |
ResultGlyphs |
ReadOnlySpan<PositionedGlyph> | All positioned glyphs after layout |
| Event | Type | Description |
|---|---|---|
TextClicked |
Action<TextHitResult> | Any text click |
RangeClicked |
Action<InteractiveRangeHit> | Interactive range clicked |
RangeEntered |
Action<InteractiveRangeHit> | Pointer enters interactive range |
RangeExited |
Action<InteractiveRangeHit> | Pointer exits interactive range |
HoverChanged |
Action<TextHitResult> | Pointer moved over text |
Rebuilding |
Action | Before text rebuild |
RectHeightChanged |
Action | RectTransform height changed |
public class Example : MonoBehaviour
{
[SerializeField] private UniText uniText;
void Start()
{
uniText.Text = "Hello, World!";
uniText.FontSize = 24;
uniText.HorizontalAlignment = HorizontalAlignment.Center;
}
}private LinkModifier linkModifier;
void Start()
{
linkModifier = new LinkModifier();
linkModifier.AutoOpenUrl = false;
uniText.RegisterModifier(new ModRegister
{
Modifier = linkModifier,
Rule = new LinkTagParseRule()
});
uniText.Text = "Visit <link=https://example.com>our website</link> for more info.";
linkModifier.LinkClicked += url => Application.OpenURL(url);
linkModifier.LinkEntered += url => Debug.Log($"Hovering: {url}");
linkModifier.LinkExited += () => Debug.Log("Left link");
}// Markdown-style links
uniText.RegisterModifier(new ModRegister
{
Modifier = new LinkModifier(),
Rule = new MarkdownLinkParseRule()
});
uniText.Text = "Visit [our website](https://example.com) for details.";
// Auto-detect raw URLs
uniText.RegisterModifier(new ModRegister
{
Modifier = new LinkModifier(),
Rule = new RawUrlParseRule()
});
uniText.Text = "Check https://example.com for updates.";// Requires: ObjModifier + ObjParseRule registered
// ObjModifier must have InlineObject named "coin" with RectTransform prefab
uniText.Text = "You earned <obj=coin/> 100 gold!";// With MarkdownListParseRule + ListModifier registered:
uniText.Text = "Shopping list:\n- Apples\n- Bananas\n- Oranges";
// Ordered list:
uniText.Text = "Steps:\n1. Open app\n2. Click button\n3. Done";var rangeRule = new RangeRule();
rangeRule.data.Add(new RangeRule.Data { range = "..", parameter = "#FF6600" });
uniText.RegisterModifier(new ModRegister
{
Rule = rangeRule,
Modifier = new ColorModifier()
});
uniText.Text = "This entire text is orange.";uniText.Text = "Hello! 👋 Great job! 🎉";