studio

FolioTier 1

characters

How speakers lower into Folio. A cast member is a stable handle (`say emma:`), like a Ren'Py `Character()` variable - rename-safe. A bare quoted name (`say "Storyteller":`, optionally `#color`) is a one-off custom speaker, like a Ren'Py string-speaker line. A bare string with no speaker is `narrate`.

Folio gives you three ways to attach a voice to a line of dialogue. A cast member is a name you define once in your project's cast - when you write say emma:, Folio resolves the display name, color, and portrait from that single definition, so renaming a character later touches one place rather than every line she speaks. A bare quoted name lets you put a speaker on screen without a cast entry, useful for one-off voices, environmental speakers, or anything whose identity matters for only a handful of lines.

Narrate drops the nameplate entirely. It is not a shorthand for a character named Narrator - it signals the structural absence of any speaker, and the engine presents it differently as a result.

The choice between a cast member and a quoted name is a question of reuse and ownership. If a speaker appears more than a handful of times, or if other parts of your script need to reference or react to their identity, define them as a cast member. A quoted name with a color is convenient for a background voice that surfaces once, but that color lives only inside that say line - there is no shared definition to update if your palette changes. Avoid using quoted names as a workaround for cast members you intend to reuse; the short-term convenience becomes maintenance debt once the character recurs.

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.

Cast handle or quoted name

A cast member is referenced by a stable handle - say emma: "..." - which is rename-safe: renaming the character never touches the line. A quoted name (say "Storyteller": "...") is a one-off custom speaker that is not in the cast.

say "Emma": "I missed you."
say "Storyteller": "And so the day began."

Two reasons for the flattening: (a) Forge and the 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, Forge, and the importer honest about whether a line is character speech (namebox, character-coloured text, voice-line auto-attachment once the voice verb ships) 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 presentation work, not character-definition work. The presentation layer exposes one per-character hook today - the namebox can follow the speaker's own colour; a richer styling system may return later, but it isn't part of the v1 surface.

Importer translation

This describes the deprecated V1 Ren'Py importer, which is no longer offered when you create a project. A Vizno Ren'Py project runs your Ren'Py source as it is.

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!" (color= is dropped; set the name color on the cast member, which the player uses wherever that character speaks) | | 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 migration report flags it inline on the affected scene - Folio's flat-namespace model can't carry the collision automatically, so the creator resolves it in the editor (typically by renaming one).

See also

  • say - character-attributed dialogue
  • narrate - narrator lines