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.
Moving a whole project across. Usually a day's work.
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.
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.
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.
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.
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.
Wiring up a string table and adding locales as you go.
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.
直 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.
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.
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%.
Dialogue typewriters, damage numbers, tween sequences.
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.
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.
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.
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.
Settling the fallback list and the memory budget — on mobile especially.
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.
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.
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.
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.
First-frame hitches, the memory budget, the release checklist.
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.
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.
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.
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.
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.
A CanvasScaler above 1, a camera that gets close, or signage in world space.
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.
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.
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.
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.