AgentStack
SKILL verified MIT Self-run

Textmeshpro

skill-xeldaralz-everything-claude-unity-textmeshpro · by XeldarAlz

TextMeshPro text rendering — font asset creation, material presets, rich text tags, dynamic font fallback, sprite assets in text. Use for all text rendering in Unity.

No reviews yet
0 installs
15 views
0.0% view→install

Install

$ agentstack add skill-xeldaralz-everything-claude-unity-textmeshpro

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Textmeshpro? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

TextMeshPro — Advanced Text Rendering for Unity

TextMeshPro (TMP) is Unity's standard text solution, replacing the legacy Text component. It uses Signed Distance Field (SDF) rendering for resolution-independent, crisp text with support for rich text, outlines, shadows, and inline sprites.

Component Types

| Component | Use Case | Namespace | |-----------|----------|-----------| | TextMeshProUGUI | Canvas UI text (most common) | TMPro | | TextMeshPro | World-space 3D text (signs, name plates) | TMPro |

using TMPro;

[SerializeField] private TextMeshProUGUI _uiText;     // Canvas text
[SerializeField] private TextMeshPro _worldText;       // 3D world text

Font Asset Creation

Font assets are created from TTF/OTF font files via the Font Asset Creator window.

Steps

  1. Window > TextMeshPro > Font Asset Creator
  2. Set Source Font File to your TTF/OTF font
  3. Configure settings:
  • Sampling Point Size: Auto or specific (e.g., 64)
  • Padding: 5-9 (higher = better outlines/shadows but larger atlas)
  • Packing Method: Optimum
  • Atlas Resolution: 512x512 for small character sets, 2048x2048+ for CJK
  • Character Set: ASCII for English, Unicode Range for specific sets, Custom Characters for exact glyphs
  • Render Mode: SDFAA (default, best quality)
  1. Click Generate Font Atlas, then Save

SDF Rendering Modes

| Mode | Quality | Use Case | |------|---------|----------| | SDFAA | Best | Default for most fonts | | SDF | Good | Slightly faster rendering | | SDFAA_HINTED | Best + hinting | Small text sizes, pixel-perfect | | Raster | Bitmap | Pixel art fonts only |

Material Presets

Material presets add visual effects (outline, shadow, glow) without modifying the base font asset.

Creating a Material Preset

  1. Select the font asset in Project window
  2. In Inspector, click the material field to see the base material
  3. Right-click the font asset > Create > Material Preset
  4. Adjust properties on the new material:
  • Face: Color, softness, dilate
  • Outline: Color, thickness
  • Underlay (shadow): Color, offset, dilate, softness
  • Lighting: Bevel for 3D effect
  • Glow: Inner/outer glow

Applying Material Presets in Code

[SerializeField] private Material _damageMaterial;  // Red outline preset
[SerializeField] private Material _defaultMaterial;

public void ShowDamageText()
{
    _uiText.fontSharedMaterial = _damageMaterial;
}

public void ResetTextAppearance()
{
    _uiText.fontSharedMaterial = _defaultMaterial;
}

Important: Use fontSharedMaterial (shared, no allocation) instead of fontMaterial (creates instance, allocates).

Rich Text Tags

TMP supports extensive rich text markup within text strings.

Basic Formatting

Bold text
Italic text
Underline
Strikethrough
Highlighted
Superscript
Subscript

Color and Size

Red
Named red
Semi-transparent red
Larger text
Relative larger
Relative smaller

Alignment and Spacing

Centered text
Left aligned
Right aligned
Character spacing
Taller lines
Indented text
Text with margin
Monospaced

Inline Sprites

Coins:  x 100
Health: 
  (by index in sprite asset)

Links

Click here to open the store.
Visit our site.

Other Tags

Different font
Gradient text
Rotated
Vertical offset
Constrained width
No line break here
Page break (for multi-page)

Dynamic Font Fallback

Chain font assets so missing characters fall through to other fonts. Essential for multi-language support.

Setup

  1. Select your primary font asset
  2. In Inspector, expand Fallback Font Asset List
  3. Add fallback fonts in priority order:
  • Primary: LatinFont (English, European)
  • Fallback 1: CJKFont (Chinese, Japanese, Korean)
  • Fallback 2: ArabicFont
  • Fallback 3: EmojiFont

TMP automatically searches fallback fonts when a glyph is not found in the primary font.

Global Fallback (TMP Settings)

  1. Edit > Project Settings > TextMesh Pro > Settings
  2. Add fonts to Fallback Font Assets list
  3. These apply to ALL TMP text components as a last resort

Sprite Assets

Embed icons, emojis, or custom images inline with text.

Creating a Sprite Asset

  1. Create a sprite sheet texture (atlas of icons)
  2. Right-click texture > Create > TextMeshPro > Sprite Asset
  3. Define sprite regions in the Sprite Asset inspector
  4. Name each sprite for easy reference

Usage

// In text strings
_uiText.text = "Gold:  500";

// With tinting (inherits text color)
_uiText.text = "";

Code Access Patterns

Setting Text Efficiently

[SerializeField] private TextMeshProUGUI _scoreText;
[SerializeField] private TextMeshProUGUI _timerText;

// GOOD — SetText with format args avoids string allocation
_scoreText.SetText("Score: {0}", score);
_timerText.SetText("{0}:{1:00}", minutes, seconds);

// GOOD — SetText with float formatting
_scoreText.SetText("DPS: {0:2}", damagePerSecond); // 2 decimal places

// OK for infrequent updates
_scoreText.text = $"Score: {score}";

// BAD for frequent updates — allocates every frame
void Update()
{
    _scoreText.text = "FPS: " + (1f / Time.deltaTime).ToString("F1"); // Allocates
}

// GOOD for frequent updates
void Update()
{
    _scoreText.SetText("FPS: {0:1}", 1f / Time.deltaTime); // Zero alloc
}

SetText Format Specifiers

_text.SetText("{0}", intValue);          // Integer
_text.SetText("{0:1}", floatValue);      // 1 decimal place
_text.SetText("{0:2}", floatValue);      // 2 decimal places
_text.SetText("{0:00}", intValue);       // Zero-padded (use string format for this)

Note: SetText format is NOT the same as string.Format. The number after : is decimal places, not format specifier.

Accessing Text Properties

// Font and style
_text.font = myFontAsset;
_text.fontSize = 36;
_text.fontStyle = FontStyles.Bold | FontStyles.Italic;
_text.characterSpacing = 2f;
_text.lineSpacing = 10f;
_text.wordSpacing = 5f;

// Color
_text.color = Color.white;
_text.faceColor = new Color32(255, 255, 255, 200); // Face color with alpha
_text.outlineColor = Color.black;
_text.outlineWidth = 0.2f;

// Alignment
_text.alignment = TextAlignmentOptions.Center;
_text.alignment = TextAlignmentOptions.TopLeft;

// Overflow
_text.overflowMode = TextOverflowModes.Ellipsis;
_text.overflowMode = TextOverflowModes.Truncate;
_text.enableWordWrapping = true;

// Sizing
_text.enableAutoSizing = true;
_text.fontSizeMin = 12;
_text.fontSizeMax = 48;

Link Handling

Detect and respond to clicks on `` tags.

using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;

public class LinkHandler : MonoBehaviour, IPointerClickHandler
{
    [SerializeField] private TextMeshProUGUI _text;

    public void OnPointerClick(PointerEventData eventData)
    {
        int linkIndex = TMP_TextUtilities.FindIntersectingLink(
            _text, eventData.position, null // null = main camera
        );

        if (linkIndex >= 0)
        {
            TMP_LinkInfo linkInfo = _text.textInfo.linkInfo[linkIndex];
            string linkId = linkInfo.GetLinkID();
            string linkText = linkInfo.GetLinkText();

            Debug.Log($"Clicked link: {linkId} ({linkText})");
            HandleLink(linkId);
        }
    }

    private void HandleLink(string linkId)
    {
        switch (linkId)
        {
            case "store":
                OpenStore();
                break;
            default:
                if (linkId.StartsWith("http"))
                    Application.OpenURL(linkId);
                break;
        }
    }
}

Performance Best Practices

Disable Raycast Target

Every TMP component with Raycast Target enabled participates in UI raycasting. Disable it when the text is not interactive.

// In inspector: uncheck "Raycast Target" on non-interactive text
// Or in code:
_text.raycastTarget = false;

Canvas Optimization

  • Place frequently updating text on a separate Canvas to avoid rebuilding the entire UI batch
  • Use Canvas.willRenderCanvases callback sparingly for text updates
  • Group static text together, dynamic text on a different Canvas

Avoid Per-Frame text Property Assignment

// BAD — triggers mesh rebuild every frame even if value has not changed
void Update()
{
    _scoreText.text = $"Score: {_score}";
}

// GOOD — only update when value changes
private int _lastDisplayedScore = -1;
void Update()
{
    if (_score != _lastDisplayedScore)
    {
        _lastDisplayedScore = _score;
        _scoreText.SetText("Score: {0}", _score);
    }
}

Text Info Access

// Access character, word, and line info after text is set
_text.ForceMeshUpdate(); // Ensure text info is current

TMP_TextInfo textInfo = _text.textInfo;
int charCount = textInfo.characterCount;
int wordCount = textInfo.wordCount;
int lineCount = textInfo.lineCount;

// Access individual character info
TMP_CharacterInfo charInfo = textInfo.characterInfo[0];
Vector3 bottomLeft = charInfo.bottomLeft;
Vector3 topRight = charInfo.topRight;
bool isVisible = charInfo.isVisible;

Localization Considerations

  • Use string keys and a localization system — never hardcode user-facing text
  • Set up font fallback chains to cover all target languages
  • CJK fonts need large atlases (4096x4096 or dynamic atlas)
  • Right-to-left languages (Arabic, Hebrew) require TMP's RTL support enabled
  • Test overflow and auto-sizing with the longest translation strings
  • Some languages expand 30-50% compared to English — design UI with flexible layouts

Common Issues

Missing Characters (Rectangles)

  • Character not in font atlas. Add to character set or use fallback fonts.

Blurry Text

  • Atlas resolution too low. Regenerate with higher resolution.
  • Padding too low for the outline/shadow being used.
  • Canvas Scaler reference resolution mismatch.

Text Not Updating

  • Call ForceMeshUpdate() if reading textInfo immediately after setting text.
  • Check that the component is enabled and the Canvas is active.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.