I hope you continue developing this title.
happybloke
Creator of
Recent community posts
Actually, I went ahead and had a conversation with some AI so it could output a super generic guide to probably better explain what I'm talking about, in full, and in order, and with descriptive variables wrapped in square brackets. I was just steam of consciousness typing my last reply. 😅 This should *actually* help you do this. I read it over and I think it's right.
1. class_name — making a script globally available
When you put class_name [YourEffectName] at the top of a GDScript file, Godot registers it project-wide. Every other script can use [YourEffectName] by name with no import needed.
class_name [YourEffectName] extends RichTextEffect # Now any script in the project can write: # [YourEffectName].new()
Without class_name you'd have to use load("res://[path/to/your/file].gd").new() every time. class_name skips all of that.
2. RichTextEffect — what it is and how Godot uses it
Godot's RichTextLabel node has a built-in system for per-character visual effects. You plug in any number of effects and Godot calls them automatically every frame for every character.
To create one, extend RichTextEffect and implement one function:
extends RichTextEffect var bbcode = "[your_tag]" # the tag this effect listens for func _process_custom_fx(char_fx: CharFXTransform) -> bool: # Godot calls this every frame for every character inside [[your_tag]]...[[/your_tag]] # char_fx gives you: index, color, offset, and more # whatever you do here IS what appears on screen return true
3. The bbcode variable — which characters get the effect
The bbcode variable tells Godot which tag to listen for. If you set it to "[your_tag]", only characters wrapped in [[your_tag]]...[[/your_tag]] get processed.
# In your effect script: var bbcode = "[your_tag]" # In your label text: label.text = "Normal text [[your_tag]]this gets the effect[[/your_tag]] normal again"
Setting bbcode = "" applies the effect to all characters with no tag needed. Built-in tags like [b], [color], [i] are unaffected — they run independently and stack fine.
4. custom_effects — registering effects on a label
custom_effects is a built-in array on every RichTextLabel. It ships empty. You fill it with instances of your effects and Godot runs all of them every frame.
# In [YourDialogueScript] or wherever you control the label: @onready var [your_label_variable]: RichTextLabel = $[YourPanelNode]/[YourLabelNode] func _ready() -> void: [your_label_variable].custom_effects = [ [YourFirstEffect].new(), [YourSecondEffect].new(), [YourThirdEffect].new() ]
All registered effects are active. Which ones actually do anything depends on whether the text contains their BBCode tag.
5. @onready — safely referencing child nodes
Node references can only be resolved once the scene tree is ready. @onready delays the assignment until that moment automatically.
# This is shorthand for assigning in _ready(): @onready var [your_label_variable]: RichTextLabel = $[YourPanelNode]/[YourLabelNode] # It's exactly equivalent to writing: var [your_label_variable]: RichTextLabel func _ready() -> void: [your_label_variable] = $[YourPanelNode]/[YourLabelNode]
The variable name ([your_label_variable]) is your choice. The node path ($[YourPanelNode]/[YourLabelNode]) must match the actual scene tree structure.
6. Combining multiple effects
Because each effect has its own BBCode tag, you can stack them freely on the same text:
[your_label_variable].text = "[[first_tag]][[second_tag]]both effects here[[/second_tag]] only first here[[/first_tag]]"
Godot runs each registered effect on each character. A character inside both tags gets both effects applied.
One file per effect is the right structure. Don't try to bundle multiple effects into one file — you can only declare one bbcode variable per class, and GDScript only allows one class_name per file.
7. The full plug-and-play setup
1
Create effect files — one per effect, each with class_name [YourEffectName], var bbcode = "[your_tag]", and _process_custom_fx().
2
Register them in [YourDialogueScript] — add all effects to [your_label_variable].custom_effects in _ready().
3
Use tags in text — wrap any text in [[your_tag]]..[[/your_tag]] and the effect runs automatically.
4
Adding a new effect — create the file, add one line to custom_effects. Nothing else needs to change.
8. What "boilerplate" means here
Boilerplate is reusable code that solves a general problem with no project-specific logic in it. A well-written [YourEffectName] qualifies — it knows nothing about your game, just how to transform characters visually. Drop it into any Godot project and it works.
A dialogue box script is boilerplate at its core (entry cycling, timing, dismiss fade) but often has project-specific parts on top (portrait modes, character-specific flags). Strip those out and the skeleton becomes reusable too.
Thanks! You'll want to start by looking into "CharFXTransform" in the Godot documentation. The "visible" boolean is what you want to play with. For the fade out part, just make it wait for the fade in process to finish before starting and repeat the logic except change opacity from 100 to 0, so the same thing but in reverse visually... To make it wiggle, you can actually offset each individual character with [var].offset = Vector2(X, Y), but you want to make sure you make X and Y something like X = sin(something)* amplitude and Y = sin(something)* amplitude. or cos. Basically you leverage that sin/cos is a wave, and multiply it by how wiggly you want it to be. Create this in a standalone .gd, give it a classname, be sure to include a declared variable called "bbcode" = "[sickradeffect]" then you can call your sick rad effect into code attached to dialogue box if and only if you wrap text in the inspector like this. "[sickradeffect]SICKRADEFFECTEXAMPLE[/sickradeffect]" That way sickradeffect only applies if and only if you wrap text in this. You're essentially adding something custom along side the ability to write out text like this "[b]THIS WOULD BE BOLD[/b]".
This is the way to do it to save yourself from typing it out over and over again in whatever project. Even cooler, you can create a permanent, personal library of text effects that to include in any project from the get go. If you haven't written anything like that yet, once you do, congrats, you've crafted your first personalized boilerplate code. Ideally each text effect that you design should be in a seperate .gd file, and should have a unique bbcode to prevent conflicts. In your dialogue box code include something like "text_label.custom_effects = [sickradeffect.new(), sickradeffect2.new(),...etc]",. "custom_effects" is a pre-existing array designed for you to fill it with....custom effects in the manner described here. And then make sure to @onready your label. I hope that helps!
Hey! Yeah thats how i felt right before i submitted mine 😴, glad I wasnt the only one!
I was honestly pulled into the narrative, but as feedback it *wasn't* the opening sequence that did it. it was the exposition with the maid who i assume is actually the daughter.
And I used to work directly with electricians. Let me assure you, when they were called out to fix something they often were given the best idea about who the client was by their manager as was possible. thinking on it more, it'd be more likely that the maid woudlve called it in to and talked to the electrician on duty for night calls directly, possibly even waking him up out of bed. I think pulling the maid in ASAP would be better. do what you will with that feedback, but always bear in mind players are right 90% of the time about when something doesnt feel good enough and wrong 90% of the time about how to fix it.
I accidentally jumped off the world.
Then on day three I just fell through the world while I was standing at the table. It was pretty funny in a way, I since everything disappeared I was like "wow, that fog really did thicken". It took me a few moments to realize I'd just glitched through the ground like that.
I was liking where the narrative was going, and I really liked the introduction sequence, but I didn't like the gameplay loop so much.
