Ren'Py basics

By Allison Parrish

Ren’Py is an authoring system for interactive narratives, originally intended to facilitate the development of visual novels. It has an easy-to-use scripting language that also provides access to the full Python programming language that the system uses under the hood. Ren’Py supports builds for major desktop and mobile platforms and in recent versions even supports HTML5 export. Nifty!

This tutorial goes over the basics of how Ren’Py works, with a focus on the aspects of the scripting language most related (in my opinion) to creating dialogue and branching narratives.

Launcher and project structure

To begin, download Ren’Py and uncompress the files to a convenient location. Start the Ren’Py Launcher application appropriate for your platform. Once the Launcher starts, click Create New Project and follow the prompts.

Creating a new project creates a folder with boilerplate code and assets. The options in the “Open Directory” section of the Launcher will show this folder in your operating system’s file browser.

Code for your project should go in a file called script.npy. You can edit this with any text editor. Double-clicking on the file in the Launcher (under “Edit File”) will open the file in your default text editor.

To run your game, click Launch Project. While the game is running, press Shift+D to open a menu that shows various helpful debug scripts.

Something to note about Ren’Py: It’s Python-based, which means that whitespace matters. Indentation marks blocks of code. (In other programming languages, you’d do this same work with curly brackets.)

Labels and text

One of the main ways to organize your Ren’Py games is through the use of labels. Labels group a sequence of statements that can be jumped to (see below). The only required label in your Ren’Py game is start. The game begins at this label.

The following example shows Ren’Py doing the thing that Ren’Py does best: display text to the screen and wait for the user’s confirmation.

label start:
    narrator "Hello, world!"
    narrator "This is a test."

(Indentation is how Ren’Py groups statements, so make sure to get the indentation right.)

The syntax to display text is <character> string. The word narrator denotes a special built-in character used to show text without attribution. Because this is so common, Ren’Py just lets you leave this out:

label start:
    "Hello, world!"
    "This is a test."

Displaying another attribution:

label start:
    "Mortimer" "Hello, world!"
    "Horatio" "This is a test."

Absent any other statements to control the flow of the game, labels will flow from one to the next:

label start:
    "This is a test."
    "Nice."

label farmyard:
    "Let's go to a farmyard!"

label forest:
    "Now we're deep in a forest."

The jump statement moves execution to the named label:

label start:
    "This is a test."
    jump forest

label farmyard:
    "Let's go to a farmyard!"

label forest:
    "Now we're deep in a forest."

(Jumping between labels isn’t terribly useful on its own, but is very powerful when combined with menus; see below.)

By the way, game execution stops when the end of the script is reached, or when the return statement is used:

label start:
    "This is a test."
    jump forest

label farmyard:
    "Let's go to a farmyard!"
    return

label forest:
    "Now we're deep in a forest."
    jump farmyard

More on labels.

Also, you can add comments to your code with #:

# here's where it all begins!
label start:
    narrator "Hello, world!"
    narrator "This is a test." # so it is!

Aside from showing text and waiting for confirmation, the other main user interface element that Ren’Py provides is the menu. A menu presents a number of options and lets the user pick among them. Here’s an example:

label start:
    menu:
        "Breakfast":
            "Delicious bacon and eggs!"
        "Brunch":
            "Bacon and eggs and mimosas!"
        "Lunch":
            "Soup and salad special..."
    "I hope you enjoyed your meal!"

The menu: keyword introduces a sequence of options, each indented once. When the user picks an option, the statements indented beneath that option’s text are executed. Execution then resumes at the statement after the menu block.

Menus are especially effective when used in combination with the jump statement, which causes the game to start executing statements starting at the named label. This allows you to create simple structures of branching narrative:

label start:
    "Welcome to the hall... of choices"
    "Alexandra" "Choose, but choose wisely."
    menu:
        "Cheese and crackers":
            "Ah yes, fancy appetizers! Nothing better."
            "Alexandra" "A wonderful choice."
            jump cheese
        "Fast food burger":
            "Sometimes you've got to treat yourself."
            "Alexandra" "I'm loving it!"
            jump burger

label cheese:
    "Alexandra" "Enjoy your brie!"
    return

label burger:
    "Alexandra" "I'm such a huge Shake Shack fan!"
    return

State and conditionals

Statements beginning with dollar signs ($) are interpreted as Python code. You don’t need to be a Python wizard to use Ren’Py! But there are a few common patterns that it’s useful to be familiar with. One of the main ways to use Python code in your game is to is to set or modify variables, allowing you to keep track of game state. The default keyword at the beginning of your script sets the default value for these variables. Variables set this way are global and can be used in other labels. The following example presents a menu to the user and sets variables based on their choice:

default tomato = 0
default funicular = 0
label start:
    "Alexandra" "Tomato or funicular?"
    menu:
        "Tomato":
            $ tomato = 1
            "You eye the tomato. Its ripeness beckons you."
        "Funicular":
            $ funicular = 1
            "You've always wanted to ride one of these!"
        "Neither":
            "You're not sure how to decide among such riches. You hesitate."
    if tomato == 1:
        "Alexandra" "Ah yes, my favorite fruit!"
    elif funicular == 1:
        "Alexandra" "Enjoy your time on the mountain!"
    else:
        "Alexandra" "Hmph. You should be more decisive."

The if/elif/else structure at the end of this example is based on Python syntax (elif is Python’s way of writing else if).

These variables don’t have to be numbers; they can contain any Python data type. This example imagines a simple system for tracking character traits using a Python dictionary:

default traits = {'kind': 0, 'smart': 0, 'hungry': 0}
label start:
    "Alexandra" "How are you doing today?"
    menu:
        "I'm well. It's good to see you! How are you?":
            $ traits['kind'] += 1
        "I am operating within established parameters. You?":
            $ traits['smart'] += 1
        "I'm hungry. Very hungry.":
            $ traits['hungry'] += 1
    if traits['hungry'] > 0:
        "Alexandra" "You poor soul! Here, have some soup."
    else:
        "Alexandra" "I'm fine, thank you! Now, down to business."

A very helpful feature for debugging Ren’Py scripts is the console. Type Shift+O to open it. You can execute arbitrary Python commands in the console, but a particularly helpful thing to try out is to just type the name of the variable you’re using to keep track of game state and press Enter. You’ll see the value that is currently stored in the variable. (Type exit to close the console.)

Showing and hiding images

Visual novels are famously… well, visual. So let’s add some visual media to the game. Ren’Py has a few commands you can use to show images. The first is the show command, whose syntax looks like this:

show tag attribute1 attribute2 attribute3 ...

Ren’Py will load an image from the images folder in your project directory based on the tag and attributes that you supply to the show command. For example, the following:

show kitty smiling

… would load and display “kitty smiling.png” from your images folder. (Case is ignored when looking for files. Background art, discussed below, can also be supplied in JPEG format.)

Ren’Py will keep an image displayed with show on the screen until one of the following happens: (a) the show command is called again with the same tag (but different attributes); (b) the hide command is called with the image’s tag; (c) the scene command is called (see below).

I have supplied a file containing a few sample visual assets that you can download and put in your project’s images folder if you want to follow along with the examples below. (You can access your project’s images folder by clicking “images” under “Open directory” in the Ren’Py launcher.)

label start:
    show adelaide
    "Adelaide" "Hello."
    show adelaide glow
    "Adelaide" "HOW ARE YOU"
    hide adelaide
    "Adelaide vanishes in a glowing puff of smoke!"

Images are shown centered in the middle of the screen by default, with the bottom edge of the image aligned to the bottom of the screen. To adjust this, you can supply a position to the show command. The syntax looks like this:

show tag attribute1 attribute2 ... at <position>

… where <position> can be replaced with left, right or center. (The technical term for these positions in Ren’Py is transformations. The left, right, center and truecenter transformations are built-in, but you can program your own transformations as well.)

The hide command, as mentioned above, hides the image on screen with the given tag.

An alternative way to display an image is scene, which hides all other images currently on screen and the displays the specified image (following the filename conventions related above):

label start:
    scene bg orbit
    show adelaide
    "Adelaide" "Welp, it was good to see you! Have fun on the surface."
    scene bg surface
    "The great cratered surface of the planet stretches before you."

Ren’Py comes with a number of built in transition effects, which affect the way that images appear and disappear when you add them to the screen. A full list of built-in transition effects is available in the Ren’Py tutorial. Here’s an example, riffing on the short script above:

label start:
    scene bg orbit
    show adelaide
    "Adelaide" "Welp, it was good to see you! Have fun on the surface."
    scene bg surface
    with dissolve
    "The great cratered surface of the planet stretches before you."
    show adelaide
    with moveinleft
    "Adelaide" "Whoops, you forgot your glasses. Here you go! Bye!"
    hide adelaide
    with moveoutright

Ren’Py also provides easy commands for playing sounds and video. See the Music and Sound portion of the official tutorial, or the Movie section in the Ren’Py documentation.

Character objects

It’s common in Ren’Py to create Character objects for each character that speaks. For more detail about the many affordances of Character objects, see the Dialogue and Narration section from the Ren’Py documentation. For our purposes, making a Character object has two benefits:

  • They’re shorter to type than the character name/text format we’ve been using so far (i.e., "Adelaide" "Hello"), and let you change the name of the character without having to search and replace every instance of the character’s name throughout the game;
  • They let you easily change the color of the character’s name when their text is displayed.

Making Character objects looks like this:

define a = Character('Adelaide', color="#ff4040")
define b = Character('Bernardine', color="#00c000")
label start:
    show adelaide
    a "Hello."
    show bernardine
    b "Hi."

Text styles and interpolation

More information on text styles and interpolation.

define a = Character('Adelaide', color="#ff4040")
label start:
    scene bg orbit
    show adelaide at left
    a "How are {i}you{/i} feeling today?"
    menu:
        "Just rotten.":
            $ mood = "crummy"
        "Pretty great!":
            $ mood = "fine"
    a "Hmm, okay. It's good to know you're in a [mood] mood."
    a "A {b}very{/b} [mood] mood."

Customizing the style of your game

Detailed documentation on Ren’Py style.