Rich Text & BBCode
BBCode tags, meta clickable links, and RichTextEffect shaders define formatted text systems.
Available Scripts
[richtextrainboweffect.gd](scripts/richtextrainboweffect.gd)
Expert custom RichTextEffect that rotates colors over time.
[richtextglitcheffect.gd](scripts/richtextglitcheffect.gd)
Professional horror-style glitch effects with spatial jitter and alpha flickering.
[richtexttypewritercontroller.gd](scripts/richtexttypewritercontroller.gd)
Dialogue manager that parses sequential event tags ([pause], [speed]) during animations.
[richtextmetadispatch.gd](scripts/richtextmetadispatch.gd)
Advanced handling for multi-prefix URLs in meta-clicks (items, quests, NPCs).
[richtextimagescaler.gd](scripts/richtextimagescaler.gd)
Utility to dynamically scale [img] tags to match runtime font sizes.
[richtexthoverreactive.gd](scripts/richtexthoverreactive.gd)
Signals and logic for making text spans reactive to mouse hover (SFX/Cursors).
[richtextbbcodesanitizer.gd](scripts/richtextbbcodesanitizer.gd)
Security utility to prevent BBCode injection in public chat interfaces.
[richtextgradientgenerator.gd](scripts/richtextgradientgenerator.gd)
Generator for multi-stop linear gradients using granular character-level tagging.
[richtextautoscroller.gd](scripts/richtextautoscroller.gd)
Smooth vertical auto-scrolling logic for credits, news feeds, and logs.
[richtextsyntaxhighlighter.gd](scripts/richtextsyntaxhighlighter.gd)
Simple regex-based syntax highlighting pattern for code blocks in UI.
NEVER Do (Expert UI Rules)
Formatting & Rendering
- NEVER use complex BBCode in tight loops — Parsing a 10,000 character string with 500 tags every frame will tank performance. Cache your formatted strings.
- NEVER forget to register Custom Effects — Writing the script isn't enough. You MUST add the instance to
RichTextLabel.customeffects list via Inspector or installeffect().
- NEVER use absolute pixel sizes in [img] —
[img width=128] fails on higher resolutions. Use richtextimage_scaler.gd to sync with line height.
Click & Hover UX
- NEVER use [url] without visual feedback — If the text doesn't change color on hover or the cursor doesn't change, players won't know it's clickable. Use
richtexthover_reactive.gd.
- NEVER hardcode layout logic into strings; strictly use BBCode Tables and Alignment Tags to ensure text structures remain flexible.
- NEVER animate text typewriter effects by modifying the
text or bbcode string frame-by-frame; strictly use visibleratio or visiblecharacters to avoid expensive parsing overhead and flickering.
- NEVER use standard bitmap fonts for large titles or dynamic UI; strictly use MSDF (Multichannel Signed Distance Field) fonts to ensure perfectly crisp outlines and scaling at any resolution.
- NEVER perform heavy logic inside
meta_clicked — This signal is on the Main Thread. Use it to emit a command and handle processing asynchronously if needed.
Dialogue & Narrative
- NEVER use
visibleratio for pausing typewriter — visibleratio is unreliable for per-character logic. Use visiblecharacters and explicit character indexing (richtexttypewritercontroller.gd).
- NEVER allow unfiltered user input in Chat Labels — A user could type
[img]hugeimagepath[/img] or [color=transparent] to break your UI. MANDATORY: pipe every user-generated string through [richtextbbcodesanitizer.gd](scripts/richtextbbcodesanitizer.gd) before assigning text.
$RichTextLabel.bbcode_enabled = true
$RichTextLabel.text = "[b]Bold[/b] and [i]italic[/i] text"
Reveal API Decision
| Need |
API |
MANDATORY |
| Simple fade / whole-line reveal |
visible_ratio + Tween |
Inline ok (see pattern below) |
Pause / speed / event tags ([pause], [speed]) |
visible_characters + indexer |
[richtexttypewritercontroller.gd](scripts/richtexttypewritercontroller.gd) |
NEVER use visible_ratio when you need per-character pause/speed tags.
Non-Obvious Tags & Effects
Skip cataloging [b] / [i] / [u] / [color] — see docs. Prefer these when non-obvious:
[url=payload]…[/url] + metaclicked — prefer [richtextmetadispatch.gd](scripts/richtextmeta_dispatch.gd)
[img] sizing — use widthunit / heightunit + RichTextLabel.ImageUnit (see [migration-notes.md](references/migration-notes.md)); scale with [richtextimagescaler.gd](scripts/richtextimagescaler.gd)
- Custom effects — register via
customeffects / installeffect(); examples: [richtextrainboweffect.gd](scripts/richtextrainboweffect.gd), [richtextglitcheffect.gd](scripts/richtextglitcheffect.gd)
User-Generated Rich Text
MANDATORY: [richtextbbcodesanitizer.gd](scripts/richtextbbcodesanitizer.gd) on any chat, lobby, or player-typed path before RichTextLabel.text = ….
Handle Link Clicks
Prefer [richtextmetadispatch.gd](scripts/richtextmetadispatch.gd). Minimal hook:
func _ready() -> void:
$RichTextLabel.meta_clicked.connect(_on_meta_clicked)
func _on_meta_clicked(meta: Variant) -> void:
# Emit a command; do not run heavy game logic here
pass
Expert Text Patterns
1. Rich-Text-MSDF-Outline (SDF)
Enable crisp, high-resolution outlines and scaling by enabling MSDF on font resources and using theme overrides.
# msdf_styler.gd
func _ready():
# Crisp outlines regardless of screen scale
label.add_theme_color_override("font_outline_color", Color.BLACK)
label.add_theme_constant_override("outline_size", 4)
2. Animated-Text-Reveal
Simple fade — tween visible_ratio (keeps BBCode effects; no string rewrite):
func reveal_fade(label: RichTextLabel, new_text: String, duration: float) -> void:
label.text = new_text
label.visible_ratio = 0.0
create_tween().tween_property(label, "visible_ratio", 1.0, duration)
Pause/speed tags — MANDATORY [richtexttypewritercontroller.gd](scripts/richtexttypewritercontroller.gd) using visiblecharacters (not visibleratio).
3. Custom-BBCode-Effect (RichTextEffect)
Define custom visual tags (like [relic]) by extending RichTextEffect for unique gameplay-themed text animations.
# relic_effect.gd
@tool
extends RichTextEffect
var bbcode = "relic"
func _process_custom_fx(char_fx: CharFXTransform):
# Retrieve param: [relic color=#ff00ff]
var color = char_fx.env.get("color", Color.GOLD)
# Apply sinusoidal floating
char_fx.offset.y += sin(char_fx.elapsed_time * 5.0) * 2.0
char_fx.color = color
return true
Deep recipes (on demand)
LLM-ignorance rule: if a general agent would not know it before reading, it lives here or in scripts/ — never delete, only move.
| Topic |
Reference |
| Tag catalog + 4.7 img units |
[bbcode-tag-catalog.md](references/bbcode-tag-catalog.md) |
Reference
Progressive disclosure: open Official Documentation links only when researching a specific API; load Related Skills when routing to a peer domain — do not preload the whole lattice.
Official Documentation
- BBCode in RichTextLabel — tag syntax, built-in effects, images, and
[url] meta for dialogue and formatted UI copy.
- RichTextLabel —
bbcodeenabled, visiblecharacters / visibleratio, metaclicked, and customeffects / install_effect().
- RichTextEffect — subclass contract for custom BBCode effects (
bbcode id + processcustomfx).
- CharFXTransform — per-glyph color, offset, and
env params used by rainbow/glitch/custom effects.
- Using fonts — MSDF / dynamic fonts so titles and BBCode scale crisply across resolutions.
- GUI skinning — theme color/constant overrides (outline, fonts) without baking styles into BBCode strings.
- Size and anchors — responsive dialogue boxes and log panels so rich text layouts survive resolution changes.
- GUI containers — keep buttons/icons in containers; use RichTextLabel for body text only.
- Custom mouse cursor — pointer feedback when hovering
[url] / meta spans.
- Internationalizing games —
tr() / CSV keys so BBCode templates stay localization-ready.
- Signals — wire
metaclicked / hover signals without stuffing game logic into the label.
- Tween — tween
visibleratio / visible_characters for typewriter reveals without re-parsing BBCode every frame.
Related Skills
Prerequisites
Complements
- godot-ui-theming — theme type variations and font/outline overrides that BBCode should reference, not hardcode.
- godot-tweening — lifecycle-safe tweens for typewriter
visible_ratio and auto-scroll polish.
- godot-input-handling — skip/advance and cursor changes that pair with meta hover without fighting Control focus.
- godot-dialogue-system — line runners and event tags that feed RichTextLabel typewriter controllers.
- godot-shaders-basics — when CharFX alone is not enough and you need canvas-item shaders around text panels.
Downstream / consumers
Master
- godot-master — library router and mirrored module entry for cross-skill discovery.