TextMeshDOTS
April 28, 2026 ยท View on GitHub
TextMeshDOTS renders world space text similar to TextMeshPro. It is a standalone text package for DOTS,
forked from Dreaming381's Latios Framework/Calligraphics.

Font Support Powered by Harfbuzz, TextMeshDOTS is currently able to load regular and variable TrueType and OpenType fonts, as well as TrueType Collection fonts. Fonts can either be included as an asset, or searched at runtime among the system fonts available on a given target platform (Windows, Linux, MacOS etc). Selection of font
family members (variants) that differ in properties such as regular/italic, font weight (normal, bold, thin, etc), font width (normal, condensed, expanded etc), slant, optical size etc is done per TextRenderer via rich text tags defining the desired font family and variant properties. If
no matching font variant for the defined properties can be found, TextMeshDOTS falls back to the font family, and is able to simulate bold and italic. In case a font does not contain a user provided unicode character or emoji, TextMeshDOTS is (for performance reasons) currently not searching for a fall back font that does contain the desired character - so be sure the selected font contains the characters or emoji you need.

Rich Text: TextMeshDOTS supports many rich text tags like TextMeshPro and TextCore (see section below for details). User selectable opentype features can be enabled using rich text tags such as <sub> (subscript), <sup> (superscript), <frac> (fractions), <smcp> (smallcaps).
Color Emoji :-) TextMeshDOTS is as of version 0.9.0 capable to render COLR v0 and v1 emoji fonts. Version 0.9.7 added support for PNG and SVG based emoji fonts (and any kind of other bitmaps that come with fonts), thanks to new harfbuzz internal rasterizer (that also happens to be 4-5x faster).
Slug base GPU renderer Eric Lengyel kindly donated his slug algorithm to the public. Using his approach, no textures are needed. Instead the font bezier curves are sampled directly on the GPU. The result is ""infinite" detail when zooming in. Rendering cost is higher compared to the texture approach (unless you use the "massive" texture setting). Harfbuzz was very quick to implement a GPU based renderer in version 14.2.0, so it was straight forward to add this option also to TextMeshDOTS as of version 0.9.9.
Technical Foundation
Unity DOTS: TextMeshDOTS leverages the Unity Entities package, BURST, and jobs to generate all data required for rendering, and Unity Entities Graphics for rendering.
Font Resource Management Prior to version 0.9.0, TextMeshDOTS used for each font a static atlas textures, borrowed from the Unity TextCore FontAsset. As of version 0.9.0, TextMeshDOTS generates all required glyph data and font textures dynamically using the Harfbuzz library, was however limited to one 4k atlas texture per font. Handling multiple fonts remained challenging, which prompted Dreaming381 to vastly simplify resource management by storing all SDF and color bitmaps in global atlas texture arrays. Dreaming381 also implemented a GPU resident representation of the glyph vertex data.
These GPU resident buffers are automatically and incrementally updated when changes occur. As of version 0.9.9, the optional slug based renderer does not use texture arrays, and rather uses a linear buffer containing the font data the slug shader needs to render the font directly from outlines.
Shader Support
There are two different versions. The included HDRP and URP ShaderGraph shader are based on a number of custom function nodes to provide modularity for decoding the GPU resident vertex data, sampling of the SDF or bitmap texture array, adding up to three outlines to SDF glyphs, as well as colorizing/texturing SDF glyphs and outlines. Different shader variants are provided, with the most complex shader providing feature parity to the TextMeshPro 4.0 SRP shader. The modularity of the
shader design enables users to expand on the provided examples and define their own custom shader. For a given text label (TextRenderer) that makes use of different fonts and emoji, TextMeshDOTS needs as of version 0.9.5 just one entity and one material. The alternative slug rendering mode does not (yet) support face textures or outlines (but is very crisp!).
Autoring workflow
Setup of Materials, Rendering Mode, Fonts
- Import Shader Open the package manager, select "Samples", and import either the URP or HDRP shader. The resources will be imported to the folder
Assets/Samples/TextMeshDOTS/Version/Sample Name. You can move them anywhere you like. Generate a material as usual (right click on desired shader --> Create --> Material). For the slug based GPU rendering mode, use a shader that contains the word "Slug".

- Selection of Rendering Mode TextMeshDOTS offers two rendering modes (1) Texture based and (2) slug based GPU rasterization. Mixing both modes would make the GPU resource handling significantly more complex and error prone. The GPU rendering mode can be enabled via Project Setting -> TextMeshDOTS -> GPU Rendering Slug. This generates a
TextMeshDOTSSettings.assetin the project asset folder. In this mode, allTextRenderermaterial need use the TMD_Color_Slug_URP or TMD_Color_Slug_HDRP shader. The slug rendering mode does not support face textures or outlines (but is very crisp!). If you need that, or have performance concerns then use the normal CPU based rasterization / texture based rendering.

- Prepare Fonts Please note that pretty much any font such as "Arial" in Windows actually consists of multiple font files (e.g. one for
regular, one forbold, one foritalic, one forbold italic. There can be many more to provide variations of font width (regular, condensed, expanded etc), font weight (bold, semibold, black etc), italic, different optical design sizes etc. You need all of these files to enable TextMeshDOTS to automatically select the right font when you apply differentFontStyles. In TrueType Collection fonts, a number of pre-defined variants are stored within just onettcfile. Variable fonts are similar to TrueType Collection fonts, however the files are much smaller because the variants are mathematically defined via parameters influencing the shape of the bezier curves. TextMeshDOTS can simulate bold and italic when those variants are missing, however this should be the exception and not the default.- To use
System Fonts(fonts that can be found on target device at runtime), drop thettfttcandotffiles into a folder of your choice underAssets. Click on the font asset and uncheckInclude Font Datato ensure the file is not included in your build. You might wonder why to even add such fonts to your project: this is only needed to extract some data to be able to correctly identify the desired fonts at runtime on the target device. - To use
Embedded Fonts, create underAssetsa subfolder calledStreamingAssets. Drag and drop allttfttcandotffiles you intend to use there. You can organize fonts in further subfolders as you wish. - Create a
FontCollectionAssetscriptable object:Any folder under Assets --> Right click --> Create --> TextMeshDOTS --> FontCollectionAsset - Drag and drop the fonts prepared in the first 2 steps into the respective lists
- Click
Process!

- To use
Baking: Subscenes, Config Singletons, TextRenderer entities
- Config Singletons
FontCollectionSingleton. This singleton provides all the data needed to load the fonts and populate the global font tables used by TextMeshDOTS.- Add empty
GameObject, addFontCollectioncomponent to it - Drag and drop the
FontCollectionAssetinto the provided field
- Add empty
TextColorGradientSingleton (optional): This singleton provides the required data to select color gradients via rich text tags.- Add empty
GameObject, andTextColorGradientcomponent to it - Add any number gradients to the list. You need to name the gradients to be able to select them via the rich text tag <gradient=name of gradient> For horizontal gradients, specify at least the top left & right color. For vertical gradients at least top & bottom-left. Otherwise specify all corners.
- Add empty
- TextRenderer
- Add empty
GameObject, addTextRenderercomponent to it. Add optional tag components in case you like to be able to use anEntityQueryto process a givenTextRendererin systems that change the label (e.g. to display damage status on a character) - Font Collection Asset Drag & drop
FontCollectionAssetinto this field. Without it you cannot select any fonts and this TextRenderer will not render. - Default Font Select a the base font family to be used by this
TextRenderer. You can override this using rich text tags. - Layout Options Select Font styles, size, color, max line width, word/line/paragraph spacing, word wrap, orthographic mode
- you can change font styles also using rich text tags such as <b> (bold), <i> (italic). The <font> rich text tag can be used to explicitly select a different font family.
- Language enter BCP 47 conform tags to set the language of this text. This ensures correct text shaping by harfbuzz (conversion of unicode characters into glyphs)
- Font Texture Size: Ignored when using the Slug based GPU render mode, which renders "infinite" detail directly from the bezier curves. Otherwise select here the sampling size for rasterizing glyphs
- Normal: 96px SDF (8bit), 128px color bitmaps (32bit)
- Big: 128px SDF (16bit), 512px color bitmaps (32bit)
- Massive (WARNING): 256px SDF (16bit), 2048px color bitmaps (32bit)
- a few hundred glyphs will fill all your GPU memory!
- Material Use material of your choice (generated in the first step) into the respective field. Ensure the material is compatible with the selected render mode (Slug or texture).
- Text Type in some text or rich text. If you followed all the steps above, you should now see the text as you type.
- Add empty

Runtime workflows
Changing text at runtime
Text is stored in the CalliString DynamicBuffer. Query for that buffer and change it. Identify TextRenderer of your choice via EntityQuery by adding optional tag components.
Spawning of TextRenderer at runtime
- Runtime spawned
TextRendererneed a material registered with Entity Graphics. In order to do that, you need to bake aTMD Runtime Material: add an emptyGameObject, addTMD Runtime Materialcomponent to it. Drop one of the materials you generated in first step of the authoring workflow (see above) into the material field. - Write a runtime
TextRendererspawner. You can follow the approach found in the package folderTextMeshDOTS\RuntimeSpawner\RuntimeTextRendererSpawner.cs(enable auto creation of this system to see a demo of runtime spawning once you enter play mode). The general workflow for runtime spawning is as follows:- Create the
TextRendererarchetype viaTextRendererUtility.GetTextRendererArchetype()orTextRendererUtility.GetDepthSortedTextRendererArchetype() - query for singleton with the
IComponentsRuntimeFontMaterialandRuntimeLanguagein order to retrieveMaterialMeshInfoand runtime languageBlobAssetReference<LanguageBlob> - create
TextBaseConfigurationviaTextRendererUtility.GetTextBaseConfiguration() - use
EntityManagerorEntityCommandBufferto create entity of theTextRendererarchetype - use
AddComponent(Entity e, in ComponentTypeSet componentTypeSet)overload to add any number of additionalIComponent - set all component data
- Create the
Optional runtime font instantiation workflow
In case you like to load fonts while your app is running, you can use the approach found in the package folder TextMeshDOTS\RuntimeSpawner\RuntimeFontSpawner.cs. You will notice, that you need to manually fill out a lot of information in the FontLoadDescription struct for every font you intend to use. This information can be extracted utilizing the FontUtility Scriptable Object.
- Right click in a folder, then
Create --> TextMeshDOTS --> Font Utility. Click on the lock icon (top right) to lock this view in the inspector) - Navigate to your font files. Drag and drop the fonts from
StreamingAssets(or from anywhere else in your project in case you intend to useSystem Fonts) into the font field. The font file will be parsed to extract the information from all available faces (or predefined variable profiles) in the font file. Use this information to build aFontLoadDescriptionin your runtime spawner. See the provided example in TextMeshDOTS\RuntimeSpawner\FontLoadDescription.cs. - I know this is cumbersome, and in order to improve the workflow I would love to hear about your concrete use cases that would require dynamic loading of fonts at runtime.

Supported rich text tags
<align=...> <allcaps>, <alpha=xx>, <b>, <color=...>, <cspace=xx>, <gradient=...> <font=...>, <font-weight=xxx>, <font-width=xxx.x>, <fraction>, <i>, <indent=xx> <lowercase>, <sub>, <sup>, <size=xx>, <space=000.00>, <mspace=xx.x>, <smallcaps>, <scale=xx.x>, <rotate=00>, <voffset=00>. Permitted size units are 'pt','px', 'em' and '%' or nothing (e.g. font-weight, font-width). Permitted values for named colors (<color=red>) are red, lightblue, blue, grey, black, green, white, orange, purple, yellow. String values (such as named colors or font names) are recognized with and without surrounding quotation marks. Hexadecimal colors are either specified using the color keyword <color=#005500>, or directly without the color keyword as <#005500>. Alpha values are specified via <alpha=#FF>.
Known issues
- <align> works only for left, center and right (not justified and flush)
- <sub> and <sup> are currently implemented using the font opentype feature. For most fonts, this only works for digits and a few characters. One could simulate <sub> and <sup> for all glyphs via scaling & offsetting, but this comes at the cost of glyphs that are optically too thin. The code for switching from one to the other is present and you could locally modify the package if you desire.
Special Thanks to the original authors and contributors
- Dreaming381 - not only has he created the amazing Latios Framework, including the Calligraphics text module, but has also been of tremendous support in figuring out how to create a standalone version of Calligraphics that uses Entity Graphics instead of the Kinematic rendering engine. Furthermore, Dreaming381 made the harfbuzz library accessible as plugin across platforms via the HarfbuzzUnity plugin for MacOS, Linux and Windows, and implemented the core systems for managing the texture arrays and glyph rendering.
- Sovogal โ significant contributions to the Calligraphics module of Latios Framework (including the name)