Studio

FolioTier 1

transition

Blend or fade into every change inside the block at once.

Use transition when a beat needs more than one stage change to happen under a single blend - a new background, sprites entering or leaving, maybe a music swap, all resolving together instead of as separate cuts. It replaces reaching for a `with` clause on each individual line; instead you gather every affected line into one indented block and the whole set crossfades or fades as one move.

Reach for it on real scene turns - a location swap, a time jump, a full cast change - where you want the eye to read the change as one continuous event rather than a stack of little cuts. dissolve reads as time passing within the same continuity; fade reads as a harder break, the kind you'd use for a chapter turn or a mood shift. Start with the bare form of either and only add a duration or color once the default pacing doesn't fit the moment.

The name is a closed set - dissolve, fade, and the fadein alias are it. There's no custom-transition escape hatch, so an unrecognized name is a hard error, not a fallback.

The body is stage changes only: bg, sprite lines, set, and audio, plus a when whose own branches are held to that same list. Dialogue, narrate, choice, pause, jump/call/return/end, video, paywall, and input all block the save if they land inside the block, and so does nesting another transition. A child line also can't carry its own with clause or a non-teleport move - the block is what plays it, so a per-line transition on top of the block's own is redundant and rejected.

An empty body is only legal on fade, where it reads as a blink; the same empty body on dissolve saves but warns, since there's nothing to blend into. Anything changed in the same beat but written outside the block simply cuts - so if a sprite move is supposed to be part of the blend, it has to live inside the indentation, not sit next to it.

wait defaults on, because a scene fading in with dialogue already popping over it usually reads wrong. Write wait=false deliberately, when you want the next line - typically dialogue - to run underneath the blend rather than after it finishes. That switch only exists on the transition header itself; the inline with clause on a single bg or sprite line never takes it.

When importing Ren'Py transitions, only the ones that are genuinely blends land here. vpunch and hpunch become @punch instead, and the directional/spatial family (pixellate, wipe, slide, iris, and similar) gets approximated down to a plain dissolve rather than preserved as its own effect.

Parameters

ParameterKindRequiredDefaultNotes
nameidentifieryes-The blend the block plays, written as a call on the header line. The set is closed: `dissolve` and `fade` are the only two names this verb spells, and anything else is a hard error that blocks the save - there is no custom-transition escape hatch. `dissolve` takes an optional crossfade duration - `transition dissolve(0.8):` is 0.8s, and any decimal is legal (`dissolve(0.83)`); bare `dissolve` = the 0.5s registry default. `fade` is `fade(seconds, color=#rrggbb)`; bare `fade` = the defaults (1s, black), split half out and half back in. `fadein` is a parse alias of `fade`. Legacy spellings like `dissolve-d8` no longer parse; write the call form. Imported Ren'Py transitions that map to a non-transition catalog entry arrive as that entry's own effect line, not as a transition: `vpunch`/`hpunch` become `@punch`, and the directional / spatial family (`pixellate`, `wipe*`, `slide*`, `iris*`, ...) approximates to a dissolve.
bodyidentifierno-The indented lines under the header - every change the one blend plays over, two spaces in, like a `when` body. A body holds stage changes only: `bg`, every `sprite` verb, `set`, audio (`music` / `sound` / stop / volume), and a `when` whose branches hold only those. Dialogue, `narrate`, `choice`, `pause`, `jump` / `call` / `return` / `end`, video, paywall, input, and another `transition` are errors that block the save. A child never carries its own ` with ...` clause or a non-teleport move - the block plays it. An empty body is legal on `fade` (a blink) and warns on `dissolve` (nothing to blend). Anything changed in the same beat but OUTSIDE the block cuts.
waitbooleannotrueWhether the story holds until the blend finishes. Default on - a scene change with text popping in mid-blend reads wrong - so it is only ever written as `wait=false` to let the next line run underneath. Spellable on a transition block header only; the inline ` with ...` clause on a `bg` or sprite line never takes it. In Forge this is the header inspector's "Hold here until this finishes" switch.

Canonical example

Folio
transition dissolve(0.8):
  bg bg-kitchen-morning
  sprite show emma
  sprite show noah
Ren'Py
scene bg kitchen_morning
show emma happy
show noah
with Dissolve(0.8)

transition is a container: a header carrying one blend and a trailing colon, then an indented body of the changes that blend plays over. It is the screenplay's DISSOLVE TO: / FADE TO: - the body is what you dissolve or fade to. A change carries its own transition; a transition block carries one transition for every change inside it.

Notes

One change does not need a block. Put the transition on the line itself - bg bg-kitchen-morning with dissolve(0.5), sprite show emma with fade - and it plays for that change alone. Reach for the block when a backdrop swap and the sprites around it have to land together, or when the whole frame should go through black.

What blends and what cuts. Only what is inside the body is in scope. A sprite shown on the line above the header, outside the block, cuts in at full opacity while the body blends around it. That is the point of the container: the scope is what you indented, not "whatever happened recently".

Dissolve is a cross-fade; fade goes through a color. dissolve holds the old frame and brings the new one up through it. fade splits its duration in half: out to the color over the first half, the body applies under the opaque wash, then back in over the second half - the whole frame, sprites included. An empty fade body is a blink; an empty dissolve body warns, because there is nothing to blend.

The block holds by default. The story waits out the blend before the next line, which is what a scene change should feel like. Write wait=false in the header call when the next line should start underneath it.

transition fade(1.2, color=#000000) if act_two:
  sprite hide emma
  bg bg-station-night

Coming from Ren'Py. A standalone with dissolve / with fade line imports as this block, wrapping the changes pending since the last interaction, which is Ren'Py's own rule. $ renpy.transition(x) wraps the changes that follow it instead. with None stays a cut. An inline with on a single statement stays that statement's own clause.

See also

  • bg - the backdrop verb, and the same inline with shorthand
  • sprite - the sprite verbs a body is mostly made of
  • @dissolve - the effect transition dissolve plays
  • @fade - the effect transition fade plays, and the out-and-hold line form