Workflows

Recommended
ways of working

Six situations you run into with OneText, and what we recommend in each. You do not have to read in order — take the section that matches what you are doing right now.

01

Moving over from TextMesh Pro

Moving a whole project across. Usually a day's work.

Rewrite the scripts first, convert the components second.

The Hub's onboarding tab lays its buttons out in that order too. A field still declared as a TMP type will not accept a OneTextLabel, and it will not complain either. Convert the scenes first and those fields quietly empty out. The migration reads its own writes back and tells you which field on which object, but keeping the order means it never happens.

Turn the report's by-hand list into tickets.

Some things are deliberately not carried across. TMP's margins do not exist in OneText, so you inset the rect yourself; onEndEdit listeners and a dropdown's multiSelect and placeholder have no counterpart. Unsupported markup prints on screen as literal text, and the ScrollRect and Linked overflow modes do not come over. Run it from the command line and it exits 1 while anything is outstanding, so CI can hold the line.

Eyeball one converted outline and shadow.

TMP's shader multiplies each effect slider by a ratio computed per font asset, so the same 0.25 is a different thickness on a different asset. The migration folds those ratios in, but whether one OneText reach and one TMP gradient unit are the same distance has not been confirmed yet. Putting one label beside a TMP screenshot takes a minute.

Fill placeholder fonts with a single .ttf.

A TMP asset that shipped its baked atlas without the source font file becomes a placeholder. Search the report for PlaceholdersCreated and it names the file each one is waiting for; drop it in through the font asset inspector's Choose the font file button and every label pointing at that asset is fixed with it. Until then the text draws in the project default font, and the warning appears once per font.

Using DOTween? Turn the define on in the Hub.

The Asset Store build of DOTween carries no package manifest to detect, so there is no way to work it out automatically. There is a button in the Hub, and it has to be on per build target group.

02

Shipping in several languages

Wiring up a string table and adding locales as you go.

Put whole-label decoration on the component's Decoration.

The inspector's decoration table edits that field. Wrap it round the text as tags instead and a Localize String Event takes the tags out with the string it replaces, so a label somebody styled carefully arrives as plain text in every language. Labels already wrapped in tags can be moved onto the component with one click in the inspector. Colour, effects, links and ruby on part of a sentence are a different matter: those belong to the translated text, so the translator carries the tags along with it.

Tag CJK fonts with a language, and labels with a locale.

直 is one codepoint whose correct shape differs between Japanese and Chinese. Without a tag, whichever font comes first in the fallback list wins. The font asset says which language a font is for and the label says who is reading it — you need both. The tag is used for Han, kana and Hangul only, because a Japanese font has Latin letters too, and letting the tag decide every character would drag digits and punctuation into CJK shapes as well. Matching is by prefix, so a zh tag covers a zh-Hans label and zh-Hant does not.

Put Doctor in CI.

Characters your project fonts do not have are drawn from the device's own operating-system fonts. That is on by default because it beats showing the reader a box, but those characters look different from device to device and do not appear at all on the web. Doctor reports a character caught by a system font as a warning and a character nothing has as an error, and exits 1 when there are errors.

Adding Thai, Lao, Khmer or Burmese? Install the word lists.

These scripts have no spaces, so breaking a line needs a dictionary. The built-in starter list handles about a tenth of real text. Install them once from the Hub's Dictionaries tab and it copies them out of the package, registers them for the build, and re-measures coverage on the spot. Doctor warns below 90%.

03

Animating text

Dialogue typewriters, damage numbers, tween sequences.

Drive the counter, not the text, for a typewriter.

Set Text once and move MaxVisibleGraphemes or CharactersPerSecond. Assigning a longer prefix each frame re-shapes the whole string, cuts clusters in half at UTF-16 boundaries, and — above all — assigning Text rewinds a reveal that is already running. On a label with a typewriter that means a reset every frame and nothing on screen. This package's own DOText moves the counter too, and switches the built-in typewriter off before it starts.

Choose per-frame properties by what they redraw.

Text, FontSize, Wrap, LineSpacing, Language and the auto-size bounds lay the text out again. Precise, Quality, Decoration, ScrollOffset and alignment rebuild the quads only. Tag effects like wave, and the reveal, write vertices and nothing else. For a pulse, DOScale beats FontSize: tweening the size is a re-layout every frame plus a walk through the atlas buckets, and it shows no change at all while AutoSize is on.

Build per-character effects on ITextQuadModifier.

It addresses grapheme clusters, so ligatures do not throw it off. TMP-style code that edits textInfo.meshInfo directly still compiles, but the moment the text is laid out again what it wrote is thrown away — the position an index pointed at is no longer the same character.

Running on another clock? Turn Animate off and set AnimationTime yourself.

A pause menu is the usual reason. The typewriter runs regardless of Animate, because a label with no effect tags on it can still have a typewriter. A pooled dialogue label types itself out again when it is re-enabled.

04

Managing fonts and memory

Settling the fallback list and the memory budget — on mobile especially.

Put only fonts you actually use in the fallback list.

The first label to draw decompresses and parses every font on the list. The asset keeps the parsed face, so every label after that picks up the same one. It cannot be put off, because working out which font has which character means asking the parsed face. The decompression is paid once — 93 ms on a desktop, several times that on a phone. The memory is not: a CJK font nobody ever reaches goes on holding its full 15.7 MB for as long as the asset is loaded. Characters that turn up one at a time are better left to the system font tier.

Run the Hub's Pack smaller once before you ship.

Importing packs on the fast setting, because the smallest one freezes the editor for 30 seconds on a single Korean font. At release time those 30 seconds are worth spending: about 17 seconds per CJK font buys 12%. Nothing repacks for you and nothing reminds you, so put it on the checklist.

Call GetFontBytes only when you need it.

Every call copies the whole font file afresh. The kept array is the one HarfBuzz is reading, so a single byte written into it would break the font everywhere at once.

Built a FontStack yourself? Dispose the stack before its fonts.

Instanced bold and italic borrow the original face. Remove the regular one while the stack is alive and the bold points at a face that is gone. Set BoldWeight and ItalicSlant before the first render, too: they are read once, the first time a family's bold is asked for.

05

Getting ready to ship

First-frame hitches, the memory budget, the release checklist.

Record a play session for the prewarm charset instead of writing one.

Turn recording on in settings, play a round, then save the charset. A hand-written list misses translated strings and user input, and the density buckets the atlas really keys on are not the same as font sizes, so they are hard to guess.

If prewarm stopped early, read the report.

It stops at 85% full or at the first eviction and records what did not fit. Filling further would push out the glyphs it just added, which is the very thing prewarming is there to prevent. A charset bigger than the atlas means growing the atlas or cutting the charset.

Budget the atlas from DemandTiles.

The occupancy gauge reads 30% for ever on an atlas under pressure, because recycling keeps running. The demand figure counts each key once and tells you what size would not have stopped it. Even when it genuinely fills nothing is lost for good: eviction and compaction run and the meshes are rebuilt, and dropped glyphs come back next frame.

Do not move the SDF shader out of a Resources folder.

No code references that shader; it ships purely because it sits under Resources. Move it and you get a player where labels measure and wrap exactly as they do in the editor and draw no glyphs at all. The editor looks fine right to the end. Doctor catches this as an error.

Raise the layer count with the quality rung.

Each rung takes the square of itself in atlas area, and the memory is size times size times layers. Precise is a second atlas at four bytes a texel, which is why it is switched on per label.

06

When text gets magnified

A CanvasScaler above 1, a camera that gets close, or signage in world space.

On a scaled canvas, treat Quality as a floor.

The real magnification is measured every canvas pass, and a label re-bakes once it leaves a 10% band. Quality is the minimum for setups that measurement cannot see. The larger of the two wins and they do not multiply, so a label on a canvas scaled by three under the High rung uses 3x, not 6x.

To change labels you have already made, use the Project rung.

Project is the zero value, so every component already serialized reads back as “ask the project”. The project's answer is read at draw time, which means one field changes six thousand prefabs together. Per-label settings are for the exceptions.

Set world-text quality from how close the player gets.

A 30-point sign is 30 points at two metres and at twenty. The default is Medium because world text is usually walked up to; measured at 1x, the crossbar of an ‘A’ filled the view at under two texels thick. A prefab carries no session's measurement.

Density stops at 128 ppem.

Otherwise a perspective camera could raise it without end, and one 256-ppem Hangul glyph is 70,000 texels. Above that the baked tile is drawn magnified. Raise the cap only along with the atlas budget.