# Textmeshpro

> 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.

- **Type:** Skill
- **Install:** `agentstack add skill-xeldaralz-everything-claude-unity-textmeshpro`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [XeldarAlz](https://agentstack.voostack.com/s/xeldaralz)
- **Installs:** 0
- **Category:** [AI & ML](https://agentstack.voostack.com/c/ai-and-ml)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [XeldarAlz](https://github.com/XeldarAlz)
- **Source:** https://github.com/XeldarAlz/everything-claude-unity/tree/main/.claude/skills/third-party/textmeshpro
- **Website:** https://github.com/XeldarAlz/everything-claude-unity#readme

## Install

```sh
agentstack add skill-xeldaralz-everything-claude-unity-textmeshpro
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## 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` |

```csharp
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)
4. 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

```csharp
[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

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

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

## Code Access Patterns

### Setting Text Efficiently

```csharp
[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

```csharp
_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

```csharp
// 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.

```csharp
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.

```csharp
// 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

```csharp
// 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

```csharp
// 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.

- **Author:** [XeldarAlz](https://github.com/XeldarAlz)
- **Source:** [XeldarAlz/everything-claude-unity](https://github.com/XeldarAlz/everything-claude-unity)
- **License:** MIT
- **Homepage:** https://github.com/XeldarAlz/everything-claude-unity#readme

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

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-xeldaralz-everything-claude-unity-textmeshpro
- Seller: https://agentstack.voostack.com/s/xeldaralz
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
