TypeFlow Pro
Get this asset on HyperCodeStore — full C# source, instant download. More Unity editor tools with source on the same store.
Correct, animated Arabic / Hebrew / right-to-left text for TextMeshPro — plus a pure-C# OpenType engine for the scripts, fonts and effects TMP's atlas can't reach. No migration, no native binaries.
⚡ Arabic in 10 seconds
Add TypeFlow Text to a TMP object — correct joining and RTL order, instantly.
🎬 RTL-aware animation
A typewriter that reveals in logical reading order, plus 20 built-in behaviors, per-word appearances and dialogue actions.
🔥 Kiln engine
Pure-C# OpenType: GSUB/GPOS, variable fonts, color emoji, SDF/MSDF — no TextMeshPro.
✅ 100% conformance
Grapheme, word and sentence segmentation at 100% on the official Unicode suites.
🎨 Families & links
Font families with faux-bold/italic, clickable <link> regions, gradients.
⤓ Drop-in install
Import, run Setup, add a component. Remove it and you're back to vanilla TMP.
This guide covers both tiers. Tier-1 (TextMeshPro) topics come first; the pure-C# Kiln engine follows; shared concepts and reference are at the end.
Installation
Import once, run the Setup wizard, add a component.
In
Window → Package Manager → My Assets, download and import TypeFlow Pro. It lands at Assets/TypeFlowPro/.Window → TextMeshPro → Import TMP Essential Resources (needed for the Tier-1 TextMeshPro path).Tools → TypeFlow Pro → Setup — it verifies TMP and helps you build an Arabic-capable font atlas (it lists the presentation-form ranges to include).TypeFlow Text on a TMP object for the Tier-1 path, or Kiln Text for the standalone Tier-2 renderer.
Requirements
- Unity 2021.3 or newer (developed on Unity 6000.0).
- TextMeshPro (
com.unity.textmeshpro) for the Tier-1 path. - An Arabic-capable font with presentation forms for Tier-1 (e.g. Noto Naskh Arabic, Amiri, Cairo, Dubai). A bundled SIL OFL font (Amiri) is included for the demo.
What gets installed
Assets/TypeFlowPro/
Runtime/ // Unicode (BiDi, segmentation, layout), Fonts (shaping/render),
// Core (pipeline + TypeFlowText), Kiln (Tier-2), TypeFlow (animation)
Editor/ // Setup Wizard, Font Diagnostics, Conformance Runner, inspectors
Demos/ // bundled Amiri font + a guided, interactive showcase scene
// (every feature, page by page) you can open and play
Documentation/ // You are here
Tests/ // EditMode + PlayMode (run headless via Unity -runTests)Project
ITextPreprocessor — disable or remove the component and your text reverts to plain TextMeshPro. Nothing is rewritten on disk.Quick Start: Arabic on TextMeshPro
Correct, joined, right-to-left Arabic on your existing TMP objects — in about ten seconds.
A TextMeshPro - Text (UI) or TextMeshPro (3D), as usual. Assign an Arabic-capable font asset.
Add Component → TypeFlow Pro → TypeFlow Text.That's it — letters join, the line orders right-to-left, and mixed numbers/English are placed correctly.
Add TypeFlow Animator and enable the typewriter — it reveals in logical reading order, correct even for RTL.
BaseDirection.Auto uses the UAX #9 first-strong rule; set RightToLeft or LeftToRight for a fixed layout.Quick Start: Kiln Engine (Tier 2)
Render any font with its own OpenType tables — no TextMeshPro, no native code.
Drop a
.ttf/.otf into your project and rename the extension to .bytes (so Unity imports it as a TextAsset).Add Component → TypeFlow Pro → Kiln Text (Tier 2) on an empty GameObject (it adds a MeshFilter + MeshRenderer).Drag the
.bytes font into the Font slot and set the text. Kiln shapes it with the font's GSUB/GPOS, rasterizes glyphs to its SDF atlas, and draws with the KilnSDF shader.Set Max Width (> 0 enables word wrap) and the alignment. See Kiln Text for all fields.
How It Works (Tier 1)
A string becomes correct, animated RTL text in one preprocessing pass.
TfpTagParserstrips TypeFlow Pro's own animation tags (keeping TextMeshPro markup).ArabicShaperapplies logical-order contextual joining + lam-alef ligatures.Bidi.Resolvecomputes UAX #9 embedding levels and the visual order.- Mirroring (rule L4) produces the visual string and a VisualToSource cluster map.
- TextMeshPro renders the visual string with its own atlas and shaders.
TypeFlowAnimatorreveals/animates the TMP mesh, using the cluster map so the typewriter follows logical reading order (correct for RTL).
TMPro.ITextPreprocessor, so TMP calls it automatically before layout. There is no second mesh, no extra draw call, and no per-frame allocation in steady state.TypeFlow Text
TypeFlowPro.TypeFlowText — the Tier-1 component. Add it to any object with a TMP_Text.
| Member | Description |
|---|---|
BaseDirection BaseDirection | Paragraph direction: Auto (UAX #9 first-strong), LeftToRight, or RightToLeft. Setter re-processes. |
bool EnableArabicShaping | Toggle contextual joining + lam-alef ligatures. Setter re-processes. |
byte LastParagraphLevel | 0 = LTR, 1 = RTL of the last preprocess. |
ProcessedText LastProcessed | Visual string + cluster map of the last preprocess. |
ParsedText LastParsed | Stripped animation data of the last preprocess. |
event Action TextProcessed | Raised after each preprocess. |
string PreprocessText(string) | ITextPreprocessor entry point (called by TMP). |
void Refresh() | Force TMP to re-run preprocessing. |
Auto-flip alignment (so RTL text right-aligns automatically) is a serialized option on the component.
TypeFlow Animator
TypeFlowPro.TypeFlow.TypeFlowAnimator — the animation driver. Add it alongside TypeFlow Text.
Typewriter
Enable the typewriter to reveal text character-by-character. Because reveal follows the cluster map, Arabic appears right-to-left in the correct order, not backwards. Configure characters-per-second, play-on-enable, and a punctuation pause.
Control & events
| Member | Description |
|---|---|
Play() / Pause() / Skip() / Restart() (alias Replay()) | Typewriter control. |
SetTextAndPlay(string) | Set the label's text (TFP tags allowed) and restart the reveal from the top. |
Continue() | Release a <waitinput> hold so the typewriter resumes (call on player input). |
PlayOut() | Play the disappearance (exit) animation. |
SetTypewriterSound(AudioSource, AudioClip[], volume, pitchJitter, everyN) | Wire a per-character click sound at runtime (random clip + pitch jitter; skip whitespace). |
bool IsPlaying / IsComplete / IsWaitingForInput | Current state. |
float Progress / int VisibleCharacters | Reveal progress (0..1) and the count of revealed characters — for progress bars / gating. |
event Action<int> CharacterRevealed | Fires with the logical index as each character appears. |
event Action<int> WordRevealed | Fires with the word index as each whole word finishes revealing. |
event Action WaitingForInput | Fires once when the typewriter parks at a <waitinput>; call Continue() to resume. |
event Action<string> EventTriggered | Fires when a <event=name> tag is reached. |
event Action TypewriterCompleted | Fires when the reveal finishes. |
event Action HiddenOut | Fires when a PlayOut() disappearance finishes. |
var anim = GetComponent<TypeFlowAnimator>();
anim.WordRevealed += w => { /* sync a voice clip per word */ };
anim.EventTriggered += name => { /* react to <event=name> */ };
anim.WaitingForInput += () => ShowContinuePrompt(); // parked at <waitinput>
anim.TypewriterCompleted += () => AdvanceDialogue();
anim.SetTextAndPlay("Hello <wave>world</wave>!<waitinput> Ready?");
if (Input.GetMouseButtonDown(0)) anim.Continue(); // release the wait
progressBar.fillAmount = anim.Progress; // 0..1
anim.Skip(); // reveal everything nowC#
Common recipes
Dialogue box that waits for input. Use <waitinput> between sentences and call Continue() on a click; WaitingForInput tells you when to show a prompt.
anim.WaitingForInput += () => prompt.SetActive(true);
anim.SetTextAndPlay("Hello, traveler!<waitinput> The road is dangerous.<waitinput> Continue?");
void Update() {
if (anim.IsWaitingForInput && Input.GetMouseButtonDown(0)) {
prompt.SetActive(false);
anim.Continue();
}
}C#
Word-by-word voice / SFX sync. Reveal whole words and react per word.
anim.Reveal = TypeFlowAnimator.RevealUnit.Word;
anim.WordRevealed += wordIndex => PlayBlip(wordIndex);
anim.Restart();C#
Animate shaped Arabic. Behaviors work on the RTL-shaped glyphs — just tag the text; the typewriter still reveals in correct logical order.
arabicLabel.text = "<wave>مرحبا</wave> <rainbow>بالعالم</rainbow>";
// (TypeFlow Text handles shaping/BiDi; TypeFlow Animator animates the result)C#
Different entrance per word. Override the global entrance per span, optionally with its own timing.
label.text = "<appear=pop ease=back>Bounce</appear> <appear=scale dur=0.8>grow</appear> in!";Text
Auto-hide toast (show → hold → vanish). Reveal, then play the disappearance after a delay.
anim.Disappearance = EntranceStyle.FadeIn; // reversed for exit
anim.TypewriterCompleted += () => StartCoroutine(HideAfter(2f));
anim.HiddenOut += () => gameObject.SetActive(false);
anim.SetTextAndPlay("Saved!");
// IEnumerator HideAfter(float s){ yield return new WaitForSeconds(s); anim.PlayOut(); }C#
Animation Tags
Inline tags drive per-character motion. They are parsed before TMP sees the text; any other <...> markup passes through to TextMeshPro.
Hello <wave>world</wave>! <shake a=6 f=20>Danger</shake>
مرحبا <wave>بالعالم</wave>Text
Behavior tags — 20 built-in
| Tag | Effect | Channel |
|---|---|---|
<wave> | Vertical sine wave (travelling per-character). | Position |
<bob> | Vertical bob, all letters in unison. | Position |
<sway> | Horizontal sway, in unison. | Position |
<slide> | Horizontal travelling sway (per-character). | Position |
<float> | Slow elliptical drift. | Position |
<bounce> | Bounce (absolute-value sine). | Position |
<wobble> | Circular sway. | Position |
<wiggle> | Organic 2-D wander. | Position |
<shake> | Energetic multi-sine shake. | Position |
<jitter> | Per-step hashed noise. | Position |
<tremor> | Subtle high-frequency rumble. | Position |
<swing> | Rotate back & forth, in unison. | Rotation |
<dangle> | Travelling wave of rotation. | Rotation |
<pendulum> | Gentle phased swing. | Rotation |
<spin> | Continuous rotation (a ≈ deg/sec). | Rotation |
<pulse> | Scale in/out. | Scale |
<heartbeat> | Sharp scale pulse (a living throb). | Scale |
<rainbow> | Hue cycling. | Colour |
<fade> | Alpha pulses up & down. | Alpha |
<blink> | Alpha toggles on/off. | Alpha |
Close any behavior with its matching tag, e.g. <wave>…</wave>. Attributes: a = amplitude, f = frequency — e.g. <wave a=12 f=3>. Register your own tag in C# with TfpEffects.Register("name", …), or with no code via a Custom Effect ScriptableObject (Create ▸ TypeFlow Pro ▸ Custom Effect) on a TfpEffectRegistrar.
<wave><rainbow>hello</rainbow></wave> both waves and cycles colour. A global default effect (set on the component) applies to any untagged glyph and is replaced — not stacked — where you add an explicit tag.Appearance & disappearance tags
| Tag | Effect |
|---|---|
<appear=pop>…</appear> | Give this span its own entrance (fade, pop, scale, slideup/down/left/right, rotate), overriding the global entrance. |
<appear=pop dur=0.5 ease=back> | Optionally give that span its own duration (dur/d, seconds) and easing (ease/e: linear, back, bounce, elastic, sine, expo, cubic, … with in/out variants). Omit either to inherit the component's global timing. |
<disappear=down dur=0.8>…</disappear> | Give this span its own exit (with optional dur/ease too), played by PlayOut(). |
Pacing & dialogue tags
| Tag | Effect |
|---|---|
<speed=0.5>…</speed> | Change reveal speed for the span. |
<pause=0.4> | Hold the typewriter for N seconds. |
<waitfor=0.4> | Timed hold (same as pause). |
<waitinput> / <waitfor> | Halt the typewriter here until you call Continue() — perfect for dialogue boxes. Fires WaitingForInput. |
<event=name> | Fire TypeFlowAnimator.EventTriggered with name. |
// A dialogue box that waits for the player between sentences
text.text = "Hello, traveler!<waitinput> The road ahead is dangerous.<waitinput> Continue?";
anim.WaitingForInput += () => { /* show a 'press to continue' prompt */ };
// on player input: anim.Continue();C#
RTL, Alignment & Digits
The details that make mixed-direction text look right.
Bidirectional layout
The full UAX #9 algorithm (including directional isolates) orders mixed Arabic/Hebrew/Latin/number runs correctly. Numbers and Latin words embedded in an RTL line stay left-to-right within the right-to-left flow.
Alignment auto-flip
With auto-flip enabled, a paragraph that resolves to RTL right-aligns automatically, matching reader expectation without you toggling alignment per string.
Digit shaping
Optional contextual digit shaping maps ASCII digits to Arabic-Indic or Eastern Arabic-Indic (Persian) forms based on context, so "2026" can render with native digits where appropriate. Kashida justification and Persian/Urdu presentation forms are also supported.
**bold** and *italic* work in your dialogue strings.Kiln Text (Tier 2)
TypeFlowPro.Kiln.KilnText — a world-space text renderer that shapes and draws a font entirely in C#.
Kiln parses a font's own tables (TrueType glyf and CFF/Type2), applies GSUB and GPOS, rasterizes glyphs to an SDF atlas, and draws them with a MeshRenderer + the KilnSDF shader — no TextMeshPro and no native code.
| Field | Description |
|---|---|
| Font Asset | A .ttf/.otf imported as bytes (rename to .bytes). Or call SetFont(byte[]) at runtime. |
| Text | The string to render. Settable via the Text property. |
| Pixel Size / World Scale | Rasterization size and world-unit scale. |
| Color | Tint applied through the KilnSDF material. |
| Base Direction | Auto / LeftToRight / RightToLeft — mixed-BiDi glyphs are reordered with the UAX #9 L2 rule. |
| Script | "auto" (default) detects the script from the text and routes complex scripts (Devanagari, Thai, …) through the full reordering/feature shaper; Arabic/Hebrew/Latin use the Arabic shaper. Force a specific OpenType tag ("arab", "deva", "thai", …) if you need to. |
| Max Width | World-unit line width. 0 = single line; > 0 enables word wrap (full UAX #14 line breaking). |
| Line Height Multiplier / Alignment | Multi-line spacing and Left/Center/Right/Justify alignment. |
Complex scripts, color emoji & variable fonts
Feed Kiln the right font and it just works — the component detects the script and picks the shaper, composites COLR/CPAL color emoji as tinted SDF layers, and can interpolate a variable font's axes at runtime:
var kiln = GetComponent<KilnText>();
// Complex script: auto-detected, conjuncts/marks shaped from the font's GSUB/GPOS
kiln.SetFont(devanagariFont.bytes);
kiln.Text = "नमस्ते"; // the स्त conjunct forms (Script = "auto")
// Color emoji: load a COLR/CPAL v0 font and type emoji — rendered in full colour
kiln.SetFont(emojiFont.bytes);
kiln.Text = "🚀❤🎉";
// Variable font: drive a weight (or any) axis live
kiln.SetFont(interVariable.bytes);
if (kiln.HasVariableAxes) kiln.SetVariation("wght", 700f); // re-interpolates & re-rasterizesC#
Inline effects
Kiln understands the same inline effect tags as the Tier-1 style parser, applied to the glyphs it shapes:
| Tag | Effect |
|---|---|
<gradient=RRGGBB,RRGGBB>…</gradient> | Per-glyph vertical gradient (top colour, bottom colour) baked into the mesh vertex colours — works on shaped Arabic/complex text too. |
<outline=RRGGBB,width>…</outline> | Outline ring via the KilnSDF material (applied to the text run). |
<shadow=RRGGBB,dx,dy>…</shadow> | Drop shadow via the KilnSDF material (applied to the text run). |
Tags are stripped before shaping, so they never render as literal text. Example: <gradient=FF4040,FFD23E>سلام</gradient> renders joined Arabic with a red→gold vertical gradient on each letter.
Scripts & Fonts
What the engine shapes today, and the OpenType features behind it.
Contextual joining, ligatures, mark positioning, full BiDi.
Han/Kana rendered from the font's own tables.
Reordering + conjunct formation (e.g. नमस्ते).
Consonants + above/below marks, with dictionary word-breaking.
OpenType features supported
- GSUB: single, multiple, ligature, chaining-context, and extension lookups.
- GPOS: pair, mark-to-base, mark-to-mark, cursive, and extension lookups.
- Variable fonts:
fvaraxes +gvardeltas. - Color: COLR/CPAL color glyphs (e.g. emoji) composited as tinted SDF layers.
- Outlines: TrueType
glyf(incl. composites) and CFF/Type2; SDF + MSDF rasterization; multi-page atlas. - Fallback: automatic per-codepoint font fallback across a chain.
- Collections:
.ttcTrueType collections (by font index).
Families, Links & Effects
Rich-text building blocks that work across both tiers.
Font families
Create a Font Family asset (Assets → Create → TypeFlow Pro → Font Family) holding Regular / Bold / Italic / Bold-Italic faces plus optional fallbacks. <b>/<i> then pick the correct face, with CSS-style graceful degradation (faux-bold / faux-italic when a face is missing).
// Whole-text: set the right face + faux style for a bold/italic state
family.ApplyTo(myTmpText, bold: true, italic: false);
// Mixed text: rewrite <b>/<i> into per-run <font> spans
string markup = family.ToTmpMarkup("plain <b>bold</b> text");C#
Clickable links
The easiest path is the TypeFlow Clickable Text component (Add Component → TypeFlow Pro → TypeFlow Clickable Text) on any TextMeshPro label: set its Source to text with <link=id>…</link> markup and wire OnLinkClicked in the inspector. It strips the link tags (other markup like <color> passes through), pushes the clean text to the label, and hit-tests clicks and hover for you.
var clickable = label.gameObject.AddComponent<TfpClickableText>();
clickable.Source = "Visit the <link=home>home page</link>.";
clickable.OnLinkClicked.AddListener(id => { /* the user clicked link 'id' */ });
clickable.LinkHovered += id => { /* hovered link id, or null */ };C#
Under the hood it uses the pure-geometry primitives, which you can also call directly (e.g. for a Kiln layout):
string clean = LinkParser.Parse(source, out var links);
// boxes from TextMeshPro (or your Kiln layout):
var boxes = LinkHitTester.BoxesFromTextMeshPro(tmpText);
string id = LinkHitTester.GetLinkIdAt(localPoint, boxes, links);
if (id != null) { /* the user clicked link 'id' */ }C#
Inline effect tags
StyleTagParser parses <gradient=RRGGBB,RRGGBB>, <outline=RRGGBB,width> and <shadow=RRGGBB,dx,dy> into style spans. The KilnSDF shader supports outline + shadow; gradients apply via vertex colors.
Damage Numbers
Pooled, animated floating combat text — built on the same per-character engine as the rest of TypeFlow Pro, so it does things a generic popup system can't: per-digit entrances, live behaviors, and RTL Arabic-Indic / Persian numbers.
Spawn a number with one call. The first call lazily creates a persistent world-space manager; for full control, drop a TfpDamageNumberManager in your scene or assign your own to TfpDamageNumbers.Default.
using TypeFlowPro.CombatText;
// One-liner — a pooled popup floats up at a world point and fades out:
TfpDamageNumbers.Spawn(150, hitPoint);
// With a no-code style asset (Assets ▸ Create ▸ TypeFlow Pro ▸ Combat Text Style):
TfpDamageNumbers.Spawn(critDamage, hitPoint, critStyle);
// Your own manager — world or canvas, follow a moving enemy, combine rapid hits:
manager.Spawn(heal, enemy.position, healStyle, follow: enemy.transform);C#
The popup style asset
A TfpPopupStyle is a ScriptableObject that defines the whole look — no code. Hand it to Spawn. (Leave it out and the manager uses a sensible default.)
| Field group | What it controls |
|---|---|
Font, FontSize, FontStyle, Color | Rendering. ColorByValue + a ValueGradient make bigger hits glow hotter. |
Abbreviation, Decimals, ThousandsSeparator | Number formatting: metric abbreviation (1234567 → 1.2M), grouping, fixed decimals, plus a Prefix/Suffix. |
Digits | Western, ArabicIndic (٠-٩) or Persian (۰-۹) — combat text in the player's own numerals. |
Lifetime, Rise, RiseDistance, ArcHeight, Direction | How it travels: straight Up, a Directional drift, or a parabolic Arc (loot/XP toss). |
StartScale, ScaleEase, PopInFraction, EndScale | The pop-in (use an OutBack ease for overshoot) and an optional shrink as it dies. |
FadeInFraction, FadeOutFraction | The transparency in/out windows. |
ShakeAmplitude, ShakeFrequency, SpinDegrees | The classic crit shake and optional spin. |
PerCharacter, EntranceStyle, ContinuousEffect | Animate each digit independently with the TypeFlow engine — a staggered entrance plus a continuous behavior (Wave, Rainbow…). |
Combine, CombineRadius, CombineWindow | Merge rapid hits in the same spot into one rising total (DPS-meter feel) instead of overlapping popups. |
FaceCamera | Billboard world-space popups toward the camera. |
Components & API
| Member | Description |
|---|---|
TfpDamageNumbers.Spawn(value, worldPos, style?, follow?) | Static one-liner; routes to Default (auto-created, persistent, world-space). |
TfpDamageNumberManager | Pools and spawns popups. WorldSpace toggles 3D TextMeshPro (billboarded) vs canvas TextMeshProUGUI under a Container. Prewarm avoids first-hit hitches. |
TfpDamageNumber | One pooled popup. Drives a TMP_Text through its life; exposes Value, DisplayText, IsAlive. |
TfpPopupStyle | The no-code style asset (above). BuildFormat() / BuildMotion() compile its fields into the pure structs the runtime uses. |
TfpNumberFormat.Format(value, fmt) | Pure, culture-invariant value→string (abbreviation, grouping, decimals, prefix/suffix, digit substitution). Reusable on its own. |
TextMeshPro, billboarded). Set WorldSpace = false and a Container under a Canvas for HUD/screen-space popups instead — the same Spawn call drives both. It's all C#, AOT-safe, and pools every instance so steady combat allocates nothing.TfpPopupStyle built in a few lines.Two-Tier Architecture
One package, two ways to put correct text on screen.
| Tier 1 — TextMeshPro | Tier 2 — Kiln | |
|---|---|---|
| Renderer | TextMeshPro (its atlas + shaders) | Pure-C# OpenType engine + KilnSDF shader |
| Migration | None — add a component | New component (Kiln Text) |
| Best for | Arabic/Hebrew/RTL UI & animation | Scripts/fonts/effects TMP can't express |
| Native code | None | None |
| Animation engine | Yes (typewriter + behaviors) | Shares the same building blocks |
The two tiers share the same Unicode foundation (BiDi, segmentation, shaping) — a clip of Arabic text shapes identically whether TMP or Kiln renders it.
Unicode Conformance
Measured against the official Unicode test suites and enforced by regression-floored tests.
| Official suite | Result | What it proves |
|---|---|---|
| GraphemeBreakTest | 100% | User-perceived character boundaries (emoji ZWJ, etc.). |
| WordBreakTest | 100% | Word boundaries (incl. flag pairs, Hebrew quotes). |
| SentenceBreakTest | 100% | Sentence boundaries. |
| BidiCharacterTest | 99.97% | The bidirectional algorithm over 91,707 official cases. |
| LineBreakTest | 99.73% | UAX #14 line-break opportunities. |
Reproduce them yourself: run the UnicodeConformanceTests and BidiCharacterConformanceTests headlessly. Each test prints its pass rate and asserts a regression floor, so conformance can't silently slip.
Editor Tools
Under Tools → TypeFlow Pro.
Verifies TextMeshPro and helps build an Arabic-capable atlas, listing the required Unicode ranges.
Scans a TMP font asset and reports missing Arabic base/presentation glyphs.
Runs the bundled UAX #9 BiDi vectors and shows pass counts.
Scripting API
The stable public surface. Namespaces: TypeFlowPro, TypeFlowPro.Unicode.BiDi, TypeFlowPro.Fonts.Shaping, TypeFlowPro.TypeFlow.
Common usage
using TypeFlowPro;
using TypeFlowPro.Unicode.BiDi;
var tfp = GetComponent<TypeFlowText>();
tfp.BaseDirection = BaseDirection.Auto;
tfp.EnableArabicShaping = true;
tfp.Refresh();C#
Pipeline & BiDi (engine-level)
// One-shot processing without a component:
ProcessedText p = TypeFlowProcessor.Process(logical, ShapeSettings.Default);
// p.Visual, p.ParagraphLevel, p.VisualToSource, p.IsRightToLeft
// Raw bidirectional resolution:
BidiResult b = Bidi.Resolve(text, BaseDirection.Auto);
// b.ParagraphLevel, b.Levels, b.VisualToLogicalC#
Key types
| Type | Purpose |
|---|---|
TypeFlowProcessor.Process(string, ShapeSettings) | Logical → visual string + cluster map. |
Bidi.Resolve(string|int[], BaseDirection) | UAX #9 levels + visual order. |
ArabicShaper.Shape(int[]) | Contextual joining → glyphs + source map. |
TfpTagParser.Parse(string) | Clean text + animation spans/events/controls. |
KilnText.SetFont / Text / Script / SetVariation(tag,value) | Tier-2 renderer: load a font, set text, force/auto a script, drive a variable-font axis (HasVariableAxes / VariationAxes). |
TypeFlowProcessor.ProcessBatch(string[], ShapeSettings) | Shape many strings in parallel (multi-core, thread-safe, cache-free). |
KashidaJustifier.InsertKashidas(int[] cps, int count) | Distribute Arabic tatweel elongations at the best joints for kashida justification. |
FontFallback.SegmentRuns(int[] cps) | Resolve a mixed-script string into per-font runs across an ordered font chain. |
RevealScheduler / TextBehaviors / AnimationMap | Animation building blocks. |
FontFamily / FontFamilyResolver | Face selection + faux synthesis. |
TfpClickableText | Drop-in clickable/interactive text component (click + hover on <link> regions). |
LinkParser / LinkHitTester | Clickable-text parsing + hit-testing primitives (used by the component). |
Troubleshooting
The issues that come up most, and how to fix them.
Arabic shows as disconnected / boxed letters
The font atlas is missing Arabic presentation forms. Run Tools → TypeFlow Pro → Setup and rebuild the atlas with the presentation-form ranges it lists, using an Arabic-capable font (Noto Naskh Arabic, Amiri, Cairo, Dubai). Use Font Diagnostics to confirm the glyphs are present.
Arabic appears backwards
Make sure the TypeFlow Text component is actually on the object (the TMP field alone won't reorder). If direction detection is wrong for your data, set BaseDirection to RightToLeft explicitly instead of Auto.
Mixed numbers/English sit in the wrong place
That ordering is governed by the bidirectional algorithm and is usually correct per UAX #9. If a specific string looks wrong, check whether you intended a fixed paragraph direction — setting BaseDirection explicitly removes the first-strong ambiguity.
The typewriter reveals RTL text in the wrong order
Use TypeFlow Animator (not a generic typewriter asset). It reveals via the cluster map in logical reading order, which is correct for RTL. Generic per-glyph typewriters reveal in visual order and look backwards on Arabic.
Kiln Text renders nothing
Confirm the font is imported as bytes (extension renamed to .bytes so it's a TextAsset) and assigned to the Font slot, and that the GameObject has the MeshFilter + MeshRenderer the component requires. Check the Console for font-parse messages.
A complex script doesn't shape correctly in Kiln
Latin, Arabic, Hebrew, CJK, Devanagari and Thai are validated; Myanmar/Khmer cluster reordering is not yet modeled. Also confirm the font actually contains the GSUB/GPOS features for that script — Kiln shapes from the font's own tables.
FAQ
Quick answers to the questions that come up most.
Do I have to migrate off TextMeshPro?
No. TypeFlow Text is an ITextPreprocessor — add it to your existing TMP objects and they start rendering correct Arabic/RTL. Remove it and you're back to vanilla TextMeshPro, with nothing rewritten.
Does it use native plugins?
No. Everything is pure C#. It runs on every Unity target including WebGL and consoles, with no per-platform native libraries (both WebGL and Windows-IL2CPP builds are verified clean).
Which languages are supported?
Tier 1 (TextMeshPro): Arabic, Persian/Farsi, Urdu and other Arabic-script languages, plus Hebrew, with full BiDi for mixing them with Latin, numbers and punctuation. The Tier-2 Kiln engine additionally render-validates CJK, Devanagari (conjuncts) and Thai. Myanmar/Khmer cluster shaping is on the roadmap.
Does the typewriter work in Arabic?
Yes — it reveals in logical reading order using the cluster map, so Arabic appears right-to-left in the correct order, not backwards. This is a common bug in animation assets; TypeFlow Pro handles it.
Do rich-text tags (<color>, <b>) still work?
Yes. TextMeshPro tags pass through untouched; only TypeFlow Pro's own animation tags are consumed. (Deep interaction of arbitrary TMP markup inside reordered RTL runs continues to be hardened.)
What about performance?
Shaping is cached and only re-runs when the text changes; animation manipulates the existing TMP mesh with no per-frame allocations in steady state. No extra draw calls or materials. A multi-core batch API is included for processing many strings at once.
Does it work at runtime / in builds?
Yes. Both tiers run at runtime on any Unity build target. There is no editor-only dependency for rendering.
Support
Need help? We're here for you.
Get in Touch
Bug reports, feature requests, font/shaping questions — reach out and we'll get back to you.
✉ ragendom@gmail.comWe typically respond within 24–48 hours.
- Check the Troubleshooting section
- Run Font Diagnostics for missing-glyph issues
- Confirm the TypeFlow Text component is on the object
- Check the Console for parse/shaping messages
- Unity version (e.g.
6000.0.30f1) - TypeFlow Pro version (v4.0)
- Render pipeline (Built-in / URP / HDRP)
- The font you're using + a sample string
TypeFlow Pro v4.0 · Built for Unity 2021.3+ · Pure C#, no native binaries
Support: ragendom@gmail.com