FolioTier 1
characters
How named speakers, narrators, and Ren'Py character aliases lower into Folio.
Reference page — characters aren't a verb. This page collects the
rules that govern how say references a speaker and how the importer
flattens Ren'Py's character indirection.
Display name is the identifier
Folio has no define e = Character("Emma") step. The character's
display name is the only handle — say "Emma": "..." references the
character by what the player sees. No short-form alias, no
intermediate object, no Python class.
say "Emma": "I missed you."
say "Storyteller": "And so the day began."
Two reasons for the flattening: (a) the node editor and migration report read cleaner when the speaker is the literal name a creator would say out loud, and (b) Folio's import target is the result of a project's character system, not its source — Vizno owns the future, not the round-trip back to Ren'Py.
Narrator
A line without a speaker is narrate, not a
say with an empty character. The split keeps the runtime,
node editor, and importer honest about whether a line is character
speech (namebox, character-coloured text, voice-line auto-attachment
in Phase 6) or narration (no namebox, full-width prose).
narrate "The lights faded."
If a creator wants a named narrator — "the storyteller", "the dungeon
master" — they write it as a regular character: say "Storyteller": "...". The runtime treats them as a character; the render style
distinction stays clean.
Per-character styling
Per-character text styling (colours, fonts, side-of-screen positioning) is theme work, not character-definition work. The theme JSON5 declares named styles; a character picks a style by display name. The styling layer lands in Phase 2; until then, the runtime renders every character with the default theme.
Importer translation
Ren'Py Character() definitions are flattened at import time:
| Ren'Py | Folio |
|---|---|
| define e = Character("Emma")e "Hello!" | say "Emma": "Hello!" |
| define e = Character("Emma", color="#ff8")e "Hello!" | say "Emma": "Hello!" (colour migrates to theme JSON5 in Phase 2) |
| e "Hello," (what="...") | say "Emma": "Hello," (inline what= extensions normalize to plain text) |
| bare "Hello!" | narrate "Hello!" |
If two Ren'Py characters share a display name, the importer flags it in the migration report — Folio's flat-namespace model can't carry the collision automatically, and the author resolves it (typically by renaming one).