FolioTier 1
choice
Player decision - present a list of options that branch the story.
choice is how you hand the story to the player. It draws a list of buttons, and picking one can jump to a new scene, quietly record a decision and keep going, or play out a short scene-local aside before returning to the same thread. It's the one construct where the reader, not the script, decides what happens next.
Reach for it any time you want a fork - a real branch to a different scene, a flavor pick that doesn't change the route but should still feel like a choice, or a menu that mixes both in one list. Give it a prompt and speaker when the choice should read as a beat of dialogue a character is asking; leave the prompt off for a bare, wordless menu when the options speak for themselves.
An option is either a router or a scene: pair it with a scene target to leave, or give it an indented body to do work in place, but never both - if a body option needs to leave, end that body with a jump instead of also writing an arrow.
Use the if guard for anything the player shouldn't be able to pick yet - a locked door, a line that only makes sense if they learned something earlier. Guarded options that fail their condition just don't render, so don't count on the player noticing an absence; if the missing option matters, telegraph it elsewhere in the scene.
Speaker on the header only makes sense next to a prompt - it's naming who's asking the question, not labeling the menu. If you want the options themselves to carry character voice, put that in the labels, since only the prompt gets a nameplate.
Bodies can nest a when chain or another choice, which is the main way to build a short branching aside without leaving the scene - just remember every path back has to either fall through to the statements after the choice or jump out explicitly.
Parameters
| Parameter | Kind | Required | Default | Notes |
|---|---|---|---|---|
| prompt | string | no | - | Optional prompt rendered above the option list. Omit for a bare option list (the canonical 'silent menu' shape - Ren'Py creators sometimes use this as a quick branch). |
| speaker | string | no | - | Optional speaker display name shown on the nameplate while the prompt is up, so the question reads like a line of dialogue - `choice "Penny" "Wanna go with me?":` (Ren'Py's `penny "Wanna go with me?"` as the menu caption). Two quoted strings on the header are speaker then prompt; a single string is always the prompt. It is a display name (a cast character's name colors the plate), not a cast handle, and it needs a prompt beside it. The choice inspector's Prompt speaker field writes it. |
| option label (per child line) | string | yes | - | Each child line is `option "<label>"` followed by an optional `-> <scene-target>`. The label is the button text the player sees. With a scene target, picking the option jumps the story to that scene; without one, the option records the pick and execution advances to the next step in the same scene (the Folio shape for a decorative Ren'Py menu whose branches are `pass`). |
| option body (trailing `:` + indented lines) | identifier | no | - | An option ending in `:` opens an indented body of Folio statements that play only when the reader picks it; afterwards the story continues below the choice in the same scene. A body option can't also route with `->` - end the body with a `jump` to leave the scene instead. Bodies nest (a `when` chain or another `choice` is legal inside). |
| option guard (`if <cond>` tail per option) | expression | no | - | Optional per-option `if <cond>` tail (after the scene target if one is present) hides the option when the condition is false. The condition is a Folio expression (`flag`, `not flag`, `count >= 3`, `a and b`, etc.). Hidden options never render in the player; they don't count against the visible option list and the player never sees them. |
Canonical example
choice "What do you do?":
option "Go inside" -> living-room
option "Stay on the porch" -> porch-wait if mood >= 3
option "Glance around":
narrate "The porch light hums. Nothing moves."
set looked = true
option "Leave" -> endmenu:
"What do you do?"
"Go inside":
jump living_room
"Stay on the porch" if mood >= 3:
jump porch_wait
"Glance around":
"The porch light hums. Nothing moves."
$ looked = True
"Leave":
returnchoice is Folio's menu - the branching primitive. The header line
opens the block (choice ["speaker"] [prompt]: - a single string is the
prompt; a leading second string names who asks it, so choice "Penny" "Coming?": shows Penny's nameplate while the question is up, the way a
Ren'Py penny "Coming?" menu caption does); each indented option
line is one button. Two shapes are supported per option: with -> <target>
the option routes the story to that scene; without it the option
records the pick and execution advances inline to the next step in
the same scene.
Notes
Options are rendered in source order. Each option line can carry an
if <cond> tail (after the scene target if one is present) so the
option only appears when the condition is true - that's the supported
way to do a conditional choice. The condition follows the same Folio
guard grammar used everywhere else (bare identifier, not <ident>, comparison, and / or). Hidden options never render in
the player. Don't try to wrap option lines in an outer if; the
parser doesn't support nesting choice options inside other block
constructs.
choice "Pick one":
option "Always visible" -> a
option "Only after first run" -> b if visited
option "High mood only" -> c if mood >= 3
Authoring in the inspector
The Forge inspector exposes the option's guard as a third field below
the label + jump target ("Show only when…"). The field accepts the
same Folio expression grammar as the text script - typing parses live
and flags unknown variables against the project's set declarations
plus seeded variables. A guarded option renders an if <cond> chip
on its timeline row so guards are visible without opening the
inspector. Use the inline clear link beside the field to remove a
guard entirely.
Target-less (inline-advance) options
An option line without -> <target> records the player's pick and
then advances to the next step in the same scene - no scene jump, no
episode end. This is the Folio shape for a decorative Ren'Py menu:
a menu: whose if/elif branches are pass, where the menu exists
to give the player a moment of agency but the next line of dialogue
plays regardless of which option was picked.
choice "":
option "I'm just looking around"
option "Your bra is showing a little"
say p: "Get out of my room right now!"
Inline-advance options accept the same do <effects> and if <cond>
tails as routing options; they just omit the -> clause.
Importer behaviour
The importer maps Ren'Py's menu: to choice: 1:1 for the simple
shape above, including Ren'Py's "text" if <cond>: guarded options
(the condition lowers from Ren'Py syntax - True → true, False →
false - when the shape is a bare identifier, negated identifier, or
a comparison with a bool/numeric literal). Menus with embedded code
(Python in option bodies, non-jump actions, set between options)
lower into a choice plus a small per-option scene that runs the body
before the routing. The read-only migration report shows the original
menu: on the left and the choice it became on the right, per
scene.
The decorative-choice pattern (call screen my_menu(...) followed by
an if/elif chain whose every branch is pass) lowers to inline
target-less options.
See also
jump- direct routing without a player decisionwhen- conditional block; branch by pairing a bodyjumpwith anelse:branchscene-flow-option ->and the rest of the routing vocabulary