Expressions and packs
Lives in: characters/<id>/*.json
When one PNG per look is not enough, a pack lists stacked pictures (layers) for each expression. Same folder as the PNGs; often named default.json.
A small pack
{
"display_name": "Hana",
"default": [
{ "path": "base.png" },
{ "path": "mouth.png" }
],
"happy": {
"extends": "default",
"override": [{ "layer": 1, "path": "mouth_happy.png" }]
}
}
| Idea | Meaning |
|---|---|
| Expression key | default, happy, … — what [hana happy] and HANA [happy]: ask for |
| Layers | Stacked pictures (body, face, mouth…) drawn bottom → top |
"layer": 1 in override | Index into that stack (0 = first layer) |
extends | Copy another expression’s layers, then change them |
override | Replace layers by index |
add | Append extra layers |
This is layer reuse, not the same as panel "extends" — Reusing settings.
Unknown expression names fall back to default.
Pack root (not layers)
Keys at the top of the file describe the character, not one expression:
| Key | Effect |
|---|---|
display_name | Name shown on the name plate (usual case) |
display_name_key | Translation catalog key instead of a hard-coded string |
ui | Preferred panel / name-plate / draw plane — see Pack ui below |
drive | Live reactions while talking or focused — Talking and focus |
composition_transitions | How expression swaps fade — Expression fades |
<expression> | Layer list or extends / override / add object |
Reserved filenames (not packs): sprites.json, objects.json, metadata.json, profiles.json.
Pack ui
| Key | Effect |
|---|---|
draw_layer | "behind_panel" (usual) or "above_panel" — Places on stage |
default_panel_id | Preferred dialogue panel for this character — How text finds a panel |
default_panel_preset | Panel look preset name — How a panel looks |
default_labelplate_style_key | Name-plate look for this speaker — Name plate |
panel_slots | Portrait / art inside the box — Speaker art on the panel |
Layer keys
A layer is usually a picture; it can also be a flipbook — Motion and frames.
| Key | Effect |
|---|---|
path | Image in the character folder (__blank = empty slot) |
x / y | Offset in pixels |
w / h | Size override |
modulate / scale / opacity | Tint, size, alpha for that layer |
drive | Show only while a driver is on — e.g. "typing", "!typing", "focus" — Talking and focus |
frames + fps / loop / … | Flipbook instead of a single path |
Several pack files
Keep a simple default.json and a richer full.json (or similar). Switch with:
[char_pack hana full]
{ "type": "char_pack", "name": "hana", "pack": "full" }
Or set "pack": "full" on a single char command. char_pack alone does not redraw — the next show / expression change uses the new pack.
If the named pack is missing, the player tries default, then the first pack it finds.
Locale overlays
For a translated art set, add default_ja.json (or <pack>_<locale>.json) beside the base pack. The player picks the overlay that matches the active language when it exists.
Simple PNGs still work
If there is no pack, the player keeps using hana.png / hana_happy.png. Adding a pack is optional polish, not a rewrite of the script.
Story look (tint, shader, bind)
Separate from the pack file — on a char command (direction file or data):
| Want | Field |
|---|---|
| Tint / fade / size for this beat | modulate, opacity, scale (repeat on later commands if you want them to stick) |
| Effect on the character | shader / shader_params (or null to clear) — one shader over the whole slot, not per layer — Shaders |
| Follow a flag while on stage | bind for opacity, modulate, scale, shader:… — Reacting to flags live |
{
"type": "char",
"name": "hana",
"position": "left",
"opacity": 0.85,
"bind": {
"opacity": { "flag": "trust", "linear": [0, 0.3, 10, 1.0] }
}
}
Show/hide fades in the script ([hana left fade 0.4]) are stage enter/leave — expression-to-expression blends live in the pack — Expression fades.
Usually you need
| Want | Do |
|---|---|
| Body + mouth | Pack with two layers |
| Happy mouth only | "extends": "default" + override on the mouth index |
| Second wardrobe | Another *.json pack + char_pack |
| Name on the plate | display_name (and optional ui.default_labelplate_style_key) |
Full map
Pack keys at a glance: characters pack map. Full tables: Character pack detail.