Quick answer: Set the effect’s resource_name to the BBCode tag, add the effect resource to the label’s custom_effects array, and enable bbcode_enabled. All three are required.
A custom shake RichTextEffect script overrides _process_custom_fx to wiggle each character. Using [shake]Hello[/shake] in the label’s text shows the text statically — no wiggle. The script logic works (you can call it manually) but the BBCode tag doesn’t dispatch.
The Three Wiring Points
For a custom effect to trigger from BBCode:
- Define the effect resource with a
resource_namethat matches the BBCode tag. - Add an instance of that effect to the RichTextLabel’s
custom_effectsarray. - Enable the label’s
bbcode_enabled.
Skipping any one silently breaks dispatch.
Step 1: Effect Definition
# shake_effect.gd
@tool
class_name ShakeEffect extends RichTextEffect
var bbcode = "shake" # the BBCode tag name
func _process_custom_fx(char_fx: CharFXTransform) -> bool:
var mag = float(char_fx.env.get("mag", 2.0))
char_fx.offset += Vector2(randf_range(-mag, mag), randf_range(-mag, mag))
return true
Note var bbcode = "shake" rather than resource_name. In Godot 4, the RichTextEffect base class uses this convention.
Step 2: Add to custom_effects
In the editor, select the RichTextLabel:
- Inspector → Custom Effects.
- Click Add Element → New ShakeEffect.
- Save.
Or programmatically:
$RichTextLabel.install_effect(ShakeEffect.new())
Step 3: Enable BBCode
Set bbcode_enabled = true in the Inspector. Without it, the label treats [shake] as literal text, not a tag.
Using Parameters
$RichTextLabel.text = "Hello [shake mag=4]world[/shake]!"
The effect receives mag=4 via char_fx.env. Read as char_fx.env.get("mag", default). Allows tuning per-instance from the text itself.
Verifying
Run the scene. The text inside [shake] tags should wiggle on every render frame; the text outside should stay static. If everything is static, BBCode isn’t parsing — check the enable flag. If text inside the tag renders but doesn’t wiggle, the effect isn’t installed — check custom_effects.
“Three checkpoints. Get all three right and the tag fires; miss one and your effect is invisible.”
Add a small “effect test” debug label at startup that exercises every custom effect — catches wiring regressions immediately.