From unity-plugin
Provides expert Unity TextMeshPro guidance for SDF font assets, rich text formatting, material effects, dynamic/static fonts, localization, and UI text performance optimization.
npx claudepluginhub creator-hian/claude-code-plugins --plugin unity-pluginThis skill uses the workspace's default tool permissions.
TextMeshPro (TMPro) is Unity's advanced text rendering solution using Signed Distance Field (SDF) technology for resolution-independent, high-quality text with minimal performance overhead.
Imports and configures TextMesh Pro Essential Resources for Unity projects targeting Meta Quest and Horizon OS. Fixes pink/magenta TMP text, missing materials/fonts during UI setup.
Guides Unity UI development using UGUI (Canvas, RectTransform, layouts) and UI Toolkit (USS, UXML), covering system selection, anchoring, performance, and common patterns.
Unity 6 UI development guide. Use when building user interfaces, menus, HUD, buttons, or any UI elements. Covers UI Toolkit (recommended for new projects — USS, UXML, UI Builder, data binding), uGUI/Canvas (legacy runtime UI), and IMGUI. Based on Unity 6.3 LTS documentation.
Share bugs, ideas, or general feedback.
TextMeshPro (TMPro) is Unity's advanced text rendering solution using Signed Distance Field (SDF) technology for resolution-independent, high-quality text with minimal performance overhead.
Foundation Required: unity-csharp-fundamentals (TryGetComponent, FindAnyObjectByType), unity-ui (UI systems, Canvas, UGUI)
Core Topics:
using TMPro;
using UnityEngine;
public class TextController : MonoBehaviour
{
[SerializeField] private TMP_Text mDisplayText;
void Start()
{
mDisplayText.text = "Hello, World!";
mDisplayText.fontSize = 36;
mDisplayText.color = Color.white;
}
}
// TMP_Text - Base class, use for serialization (works with both)
[SerializeField] private TMP_Text mText;
// TextMeshProUGUI - Canvas UI text (most common)
[SerializeField] private TextMeshProUGUI mUiText;
// TextMeshPro - 3D world space text (MeshRenderer)
[SerializeField] private TextMeshPro mWorldText;
// Basic formatting
text.text = "<b>Bold</b> and <i>Italic</i>";
text.text = "<size=48>Large</size> and <size=24>Small</size>";
text.text = "<color=#FF0000>Red</color> text";
// Advanced formatting
text.text = "<mark=#FFFF00AA>Highlighted</mark>";
text.text = "H<sub>2</sub>O and E=mc<sup>2</sup>";
text.text = "<s>Strikethrough</s> and <u>Underline</u>";
// Sprite embedding
text.text = "Score: 100 <sprite=0>";
| Scenario | Component | Reason |
|---|---|---|
| UI Canvas text | TextMeshProUGUI | Canvas integration, auto-batching |
| 3D world labels | TextMeshPro | MeshRenderer, world-space |
| Serialized reference | TMP_Text | Works with both types |
| Input field | TMP_InputField | Built-in input handling |
| Dropdown | TMP_Dropdown | Built-in dropdown UI |
Static Font Asset:
- Pre-generated character set
- Best performance (no runtime generation)
- Use for: Known character sets, optimized builds
Dynamic Font Asset:
- Runtime character generation
- Flexible but slower initial render
- Use for: Localization, user input, unknown characters
Font Asset Creator (Window > TextMeshPro > Font Asset Creator)
Sampling Point Size: Use highest size that fits atlas (better quality)
Padding: 5-9 for normal use, higher for effects (outline, glow)
// BAD: Frequent text changes trigger mesh rebuild
void Update()
{
scoreText.text = $"Score: {score}"; // Rebuilds every frame
}
// GOOD: Update only when value changes
private int mLastScore = -1;
void Update()
{
if (score != mLastScore)
{
mLastScore = score;
scoreText.text = $"Score: {score}";
}
}
// BETTER: Use SetText for formatted updates (less allocation)
void UpdateScore(int score)
{
scoreText.SetText("Score: {0}", score);
}
// Use StringBuilder for complex text construction
private readonly StringBuilder mSb = new StringBuilder(256);
void BuildComplexText()
{
mSb.Clear();
mSb.Append("Player: ");
mSb.Append(playerName);
mSb.Append(" | Score: ");
mSb.Append(score);
displayText.SetText(mSb);
}
// Prefer SetText with parameters over string interpolation
text.SetText("{0}/{1}", currentHP, maxHP); // Less GC
// Instead of
text.text = $"{currentHP}/{maxHP}"; // More GC
// Apply material preset at runtime
[SerializeField] private Material mHighlightMaterial;
[SerializeField] private Material mNormalMaterial;
void Highlight(bool active)
{
mText.fontMaterial = active ? mHighlightMaterial : mNormalMaterial;
}
// Modify material properties
mText.fontMaterial.SetFloat(ShaderUtilities.ID_OutlineWidth, 0.2f);
mText.fontMaterial.SetColor(ShaderUtilities.ID_OutlineColor, Color.black);
Core TextMeshPro concepts:
Optimization techniques:
Advanced usage patterns:
// AVOID: Creating new materials per text instance
text.fontMaterial = new Material(text.fontMaterial); // Memory leak risk
// AVOID: Updating text in Update() without change check
void Update() { text.text = score.ToString(); } // Constant rebuild
// AVOID: Excessive rich text nesting
text.text = "<b><i><color=#FF0000><size=48>...</size></color></i></b>";
// AVOID: Dynamic fonts for static content
// Use pre-generated static font assets instead