char
Shows, changes, moves, or hides a character.
{ "type": "char", "name": "hana", "expression": "happy", "position": "left", "transition": "fade", "duration": 0.4 }
In script.txt:
[hana happy left fade 0.4]
[hana] # default expression, current or auto-assigned slot
[hana hide]
Hana [happy]: Good morning. # implicit char command before the line
Usually you need
| Field | Type | Default | Effect |
|---|---|---|---|
name | string | — | Character folder under characters/. Empty or missing hides whoever is in the resolved slot |
expression | string | "default" | Expression key in the pack. Unknown keys fall back to default |
position | string | see slot resolution | Slot alias (left, center, right, …) |
show | bool | true | false hides the character in the resolved slot |
transition | transition kind | "instant" | Enter and leave |
duration | number ≥ 0 | 0 | Seconds when transition_duration is absent |
That is enough for most stories. Everything below is the full surface.
All fields
| Field | Type | Default | Effect |
|---|---|---|---|
name | string | — | Character folder under characters/. An empty or missing name hides whoever is in the resolved slot |
expression | string | "default" | Expression key in the pack. Unknown keys fall back to default |
pack | string | active pack | Pack file to read the expression from, without .json |
position | string | see below | Slot alias from the active layout profile |
show | bool | true | false hides the character in the resolved slot |
draw_layer | "behind_panel" | "above_panel" | pack, then slot, then behind_panel | Which plane the character draws on |
transition | transition kind | "instant" | Applies to both entering and leaving |
transition_in | transition kind | — | Overrides transition when appearing |
transition_out | transition kind | — | Overrides transition when hiding |
transition_duration | number ≥ 0 | 0 | Seconds. Takes priority over duration |
duration | number ≥ 0 | 0 | Seconds, when transition_duration is absent |
swap_mode | swap mode | from the pack | Forces how an expression change is blended |
modulate | HTML color | #ffffff | Tint |
opacity | number 0–1 | 1 | Alpha |
scale | number or [sx, sy] | 1 | Scale |
shader | string, null, or shader object | keep current | Shader for this character |
shader_params | object | {} | Uniform values, when shader is a plain name |
bind | object | — | Live property binding to flags |
interaction | object | — | Hooks fired when this command runs |
when | expression | — | Skip the whole command when the expression is falsy |
Transition kinds are instant, fade, slide_up, slide_down, slide_left, slide_right, or "" to mean “not specified”. Swap modes are auto, in_only, crossfade, out_in, cross_slide.
Which slot the character lands in
position takes a slot alias — whatever the active layout profile defines, such as left or center by default, or your own names in a custom profile. See Planes and slots.
Omit position and the engine resolves it:
- The character’s current slot, if they are already on screen.
- Otherwise the first free alias, in the profile’s
auto_selection_policyorder. - If every slot is taken, nothing happens and a warning is logged.
Showing a character also clears them from any other slot immediately, so the same character can never occupy two slots.
Visual fields are not sticky
modulate, opacity, and scale apply only to commands that mention them. Any char command that leaves one out clears the previous value for that slot.
[hana happy] # tinted
[hana sad] # tint is gone
Repeat the value on every command that should keep it, or move it into a pack drive rule instead.
The final look of a slot multiplies four sources in this order: the slot’s own modulate/scale from the layout profile, the command’s values, any matching pack drive rules, and finally bind. opacity and a bound opacity replace the alpha rather than multiplying it.
Transitions and expression changes
The command’s transition is used whenever the command names one, meaning a non-empty transition, transition_in, or transition_out, or any transition_duration or duration.
When the command says nothing about transitions:
- Changing expression on a character who is already on screen uses the pack’s
composition_transitionspolicy for that expression pair. - Anything else is instant.
swap_mode decides how the outgoing and incoming art overlap during an expression change. Without it, the pack policy chooses, and auto resolves to crossfade for a fade and in_only for a slide.
Shaders
shader value | Result |
|---|---|
| absent | Keeps whatever shader the slot already has |
null | Clears the shader |
"drop_shadow" | Loads shaders/drop_shadow.gdshader, with shader_params as uniforms |
{ "name": …, "params": …, "target": …, "pass": …, "margin": … } | Full shader object; use margin to grow the render area so effects are not clipped |
Binding to flags
bind drives a property from a flag while the character is on screen.
{
"type": "char",
"name": "hana",
"bind": {
"opacity": { "flag": "trust", "linear": [0, 0.3, 10, 1.0] },
"modulate": { "flag": "mood", "map": { "angry": "#ffbbbb" }, "default": "#ffffff" }
}
}
Bindable properties are opacity, modulate, scale, and shader:<uniform> for any uniform of the current shader. Full modes and surfaces: Binds.
Hooks
interaction.hooks fires when the command runs, not when the player clicks the character. Available events are on_show, on_hide, and on_change as a fallback for either. on_hide is chosen when show is false, otherwise on_show. Actions run in the gameplay UI context.
{ "type": "char", "name": "hana", "show": false,
"interaction": { "hooks": { "on_hide": { "type": "set_flag", "values": { "hana_gone": true } } } } }
Related
- Characters and composition — packs, drive,
char_pack/char_layout - Transitions — kinds, defaults, composition swap
- Binds — flag → property
- Planes and slots — slot aliases and layout profiles
- Shaders — per-slot shader object / clear
- Your first script — happy-path brackets
char_pack/char_layout