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

ParameterKindRequiredDefaultNotes
promptstringno-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).
speakerstringno-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)stringyes-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)identifierno-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)expressionno-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)identifierno-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

Folio
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" -> end
Ren'Py
define 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":
        return

choice 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 decision
  • when - conditional block; branch by pairing a body jump with an else: branch
  • scene-flow - option -> and the rest of the routing vocabulary