Studio

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

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 (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

Folio
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" -> end
Ren'Py
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; 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 - Truetrue, Falsefalse - 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 decision
  • when - conditional block; branch by pairing a body jump with an else: branch
  • scene-flow - option -> and the rest of the routing vocabulary