studio
FolioTier 1
choice
Player decision - present a list of options that branch the story.
Use choice to pause the story and let the reader pick an option. Give each option an indented body for the steps that follow that pick; when the body finishes, the story continues below the choice. End a body with jump when that branch should leave the scene. An existing option with a scene target routes there directly, while an empty option simply advances to the next step.
A prompt tells the reader what they are deciding. Add a speaker before the prompt when a character asks the question, or omit the prompt when the option labels carry the moment. Use an option condition to make a response depend on earlier decisions. False conditions hide the option by default; append else disabled when the reader should see a possibility they cannot pick yet.
In Forge, select an option and choose Always available, Disable when, or Hide when under Availability. Conditional modes reveal visual checks: a true check disables or hides the option, and false leaves it available. Formula checks handle complex expressions; use the Script editor to edit a complete condition as Folio text. Clear rule restores Always available. The timeline shows only if and the positive availability condition, without a disabled suffix, and the choice inspector options list has no condition badges. Disabled options stay editable; their Stage buttons remain unpickable.
Keep option access in its compact Lock section. Edit access opens Price & lock; Back returns to the option's text, actions, and availability controls. The root Choice has no access lock. The timeline places a small lock beside paid, pass-only, and members-only option names and shows no monetization prices. An unlocked option can still lead to a separately gated scene or episode.
A disabled option uses the Theme's disabled text color on the idle button fill and skin. It shows no price or membership chip and cannot be selected with a pointer or keyboard. Its effects and nested steps do not run. If every option is hidden or disabled, playback skips the choice, so keep a pickable route when this decision must stop the story.
Write else disabled directly after the option's if condition, before any do effects and before the colon that opens a body. It is an error without a condition. An option may have either a body or an arrow target; use a jump inside the body when it needs to route. Bodies can contain another choice or a when chain.
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 hides the option when false by default. Append `else disabled` to keep it visible but unpickable instead. Conditions are Folio expressions (`flag`, `not flag`, `count >= 3`, `a and b`). A choice with nothing pickable is skipped, including an all-disabled list. |
| else disabled (after an option condition) | identifier | no | - | Only directly after `if <cond>`: `option "Vault" if has_key else disabled:`. While false, the option uses the Theme's disabled text on the idle fill and skin, with no price chip or input response. Without a condition the clause is an error. Clearing the condition restores Hide; unsupported imported guards stay hidden. |
Canonical example
choice "What do you do?":
option "Go inside" -> living-room
option "Stay on the porch" -> porch-wait if mood >= 3 else disabled
option "Glance around":
narrate "The porch light hums. Nothing moves."
set looked = true
option "Leave" -> enddefine config.menu_include_disabled = True
menu:
"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; with two strings, the first 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. An option ending in : opens its own indented
steps, then continues below the choice. End those steps with a jump
to leave the scene. An option with -> <target> routes directly to
that scene; an option without a target or body simply records the
pick and advances below the choice. A body and an arrow cannot share
the same option.
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 by default. Append
else disabled directly after the condition to keep the option
visible but unpickable while false. 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 else disabled
Disabled options use the Theme's disabled text color on the idle fill
and button skin. They show no price or membership chips and do not
respond to clicks, hover, focus, or keyboard selection. Their do
effects and nested steps do not run. When every option is hidden or
disabled, playback skips the choice and continues below it. Keep at
least one pickable option if the reader must make a decision here.
else disabled needs an immediately preceding if <cond>; it is
not a standalone option setting. Place any do effects after it.
Option effects (do)
An option line can carry a do <effects> tail - a comma-separated
list applied the moment the reader picks it. Four forms are accepted:
var += <number> and var -= <number> adjust a counter, var = <literal> writes a number, true / false, or a quoted string, and
var = <var> + <number> (plus -, *, /) writes the result of the
arithmetic. An unquoted bare word on the right reads that variable, so
quote a string value. Anything else - a function call, a string in
arithmetic - is a parse error rather than a silently dead effect.
choice "Answer her":
option "Tell the truth" -> a do trust += 1
option "Lie" -> b do trust -= 1, lies = lies + 1
option "Say nothing" do mood = "quiet"
Authoring in the inspector
Select an option in Forge's timeline and use Availability. Choose Always available, Disable when, or Hide when. Conditional modes reveal checks built with the variable picker. A true check disables or hides the option; false leaves it available. Formula checks handle more complex expressions, and the Script editor exposes the full condition as Folio text. Clear rule restores Always available.
The timeline's condition chip shows only if <condition>, including
for disabled options. The choice inspector's options list has no
condition badges. Folio still writes else disabled for disabled options.
Disabled options stay editable in the timeline and Inspector; seek
to a nested event to preview their body. Their Stage buttons remain
unpickable. New options start with an empty body that you fill from
the timeline's Add a step well. Existing routed options expose
their jump target for editing; clearing it gives the option its own body.
The option inspector keeps a compact Lock section. Use Edit access to open Price & lock, then Back to return to the option's text, actions, and availability controls. Access belongs to the individual option. The root Choice inspector shows its prompt and option list, with no root access lock.
In the timeline, paid, pass-only, and members-only options show a small lock immediately beside their names. Free options show no lock, and timeline rows show no monetization prices. Unlocking an option does not unlock an independently gated destination scene or episode.
Target-less (inline-advance) options
An option line without -> <target> or an indented body 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>, if <cond>,
and else disabled tails as routing and body options; they just omit
the -> clause. Forge writes an empty body as option "Label":,
which advances inline too.
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 to true, False to
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.
Ren'Py's config.menu_include_disabled = True imports supported
option conditions with else disabled. A later source-order
$ config.menu_include_disabled = False restores hiding for later
menus. An unsupported imported condition stays hidden for repair;
it does not become a disabled button. Imported menus with nothing
pickable are skipped too.
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