Text
Ren'Py contains several ways of displaying text. The say
and menu statements are primarily concerned with the
display of text to the user. The user interface often contains text,
displayed using the text, textbutton,
and label screen language statements. These
functions, along with others, create Text()
displayables, and
show them on the screen.
The Text displayable is responsible for managing the process of showing the text to the user. The text displayable performs actions in the following order:
Translating text.
Interpolating data into the text.
Styling the text using styles and text tags.
Laying out the styled text.
Drawing the text to the screen.
This chapter discusses the process of text display in Ren'Py.
Escape Characters
There are three special characters that can control the way Ren'Py displays text. A creator needs to be aware of these characters to ensure that their writing is not accidentally misinterpreted by the engine.
- (backslash)
The backslash character is used to introduce when writing a Ren'Py or Python string. Some common escape codes are:
- \" (backslash-doublequote)
Includes a doublequote in a double-quoted string.
- \' (backslash-quote)
Includes a single quote in a single-quoted string.
- \ (backslash-space)
Includes an additional space in a Ren'Py string. By default, Ren'Py script text collapses adjacent whitespace into a single space character.
- \n (backslash-n)
Includes a newline character in the text.
- \\ (backslash-backslash)
Includes a backslash character in the text.
- \% (backslash-percent)
Includes a protected percent character in the text. It's also possible to write it as %% : both protections will result in a single % character being written in the end.
- [ (left bracket)
The left bracket is used to introduce interpolation of a value into the text. To include a single left bracket in your text, double it – write
[[
.- { (left brace)
The left brace is used to introduce a text tag. To include a left brace in your text, double it – write
{{
.- 【 (left lenticular bracket)
The left lenticular bracket is used to to introduce ruby/furigana text. To include a left lenticular bracket in your text, double it – write
【【
.
Interpolating Data
Ren'Py supports interpolating data into the text string before it is
displayed. For example, if the player's name is stored in the
playername
variable, one could write a line of dialogue like:
g "Welcome to the Nekomimi Institute, [playername]!"
Ren'Py will search for variables in the following order:
When used in a screen, screen-local variables.
Variables found in the
interpolate
namespace.Variables found in the global namespace.
Ren'Py isn't limited to interpolating simple variables. It can also interpolate any valid Python expression. So it's possible to have:
g "My first name is [player.names[0]]."
It's possible to apply formatting when displaying numbers. This will display a floating point number to two decimal places:
g "I like you [100.0 * points / max_points:.2] percent!"
Ren'Py's string formatting is taken from the PEP 3101 string formatting syntax. Ren'Py uses [ to introduce string interpolation because { was taken by text tags.
Along with the !s
and !r
conversion flags supported by Python, Ren'Py
supports several more flags. The !q
conversion flag ensures that
text tags are properly quoted, so that displaying a string will not
introduce unwanted formatting constructs. For example:
g "Don't pull a fast one on me, [playername!q]."
The !t
flag will translate the interpolated string:
if points > 5:
$ mood = _("happy")
else:
$ mood = _("annoyed")
g "I'm [mood!t] to see you."
The !i
flag will make additional interpolate for the interpolated string:
define earned_points_info = _("[points]{image=points.png} earned points")
g "I'm happy to see you you have [earned_points_info!ti]."
This should be used to substitute the text that has a substitution inside. It's often useful in screen language, see Const Text.
The !u
flag forces the text to uppercase and the !l
flag forces the
text to lowercase. The !c
flag acts only on the first character,
capitalizing it. These flags may be combined, for example using !cl
would
capitalize the first character, and force the remaining text to lowercase.
It should be noted that:
the order in which the flags are given does not change the result :
!cl
will do just the same as!lc
.Supplementarly exclamation marks will be ignored, and will not circumvent the previous rule :
!l!c
will do the same as!c!l
or!cl
.
The transformations are done in the following order:
r
/s
(repr or str)t
(translate)i
(recursive interpolation)q
(quoting)u
(uppercase)l
(lowercase)c
(capitalize)
Non-English Languages
The default font for Ren'Py contains characters for English and many other languages. For size reasons, it doesn't contain the characters required to render other languages, including Chinese, Japanese, and Korean. In order to support these languages, a project must first change the fonts it uses.
Ren'Py should then support most world languages without further configuration. However, Korean can be written with or without spacing between words. Ren'Py has a special mode to support Korean with spaces, which can be enabled by setting:
define gui.language = "korean-with-spaces"
This can be changed from the default of "unicode" in gui.rpy.
Japanese has multiple rules for line breaking. We recommend starting with "japanese-normal", and moving to "japanese-loose" or "japanese-strict" for more or less break opportunities, respectively.
define gui.language = "japanese-loose"
Ideographic languages provide a large number of opportunities for line breaking. To enable a faster but less-accurate line-breaking algorithm, use:
define gui.language = "greedy"
The faster line-breaking algorithm is not be necessary unless the game is displaying huge amounts of text, such as in NVL-mode.
The line breaking algorithms can be further configured using the
renpy.language_tailor()
function.
Vertical Text
When the vertical
style property is set, Ren'Py will produce
vertically oriented text. The text is written top-to-bottom,
right-to-left.
There are two text tags that interact with vertical text.
- horiz
Includes horizontally-oriented text inside vertical text.
- vert
Includes vertically-oriented text inside horizontal text. (This will not rotate the text to the vertical orientation.)
Note
If the font does not contain vertical text spacing information, Ren'Py will attempt to synthesize this information from horizontal text information. The spacing may not remain constant between Ren'Py releases.
Ruby Text
Ruby text (also known as furigana or interlinear annotations) is a way of placing small text above a character or word. There are several steps required for your game to support ruby text.
First, you must set up styles for the ruby text. The following style changes are required:
One of the
line_leading
orruby_line_leading
properties must be used to leave enough vertical space for the ruby text.A new named style must be created. The properties of this style, such as
size
should be set in a fashion appropriate for ruby text.The
yoffset
of the new style should be set, in order to move the ruby text above the baseline.The
ruby_style
field of the text's style should be set to the newly-created style, for both dialogue and history window text.
For example:
style ruby_style is default:
size 12
yoffset -20
style say_dialogue:
ruby_line_leading 12
ruby_style style.ruby_style
style history_text:
ruby_line_leading 12
ruby_style style.ruby_style
(Use style.style_name
to refer to a style for this purpose.)
Once Ren'Py has been configured, ruby text can be included in two way.
Lenticular brackets. Ruby text can be written by enclosing it full-width lenticular brackets (【】), with the full-width or half-width vertical line character (| or |) separating the bottom text from the top text. For example:
e "Ruby can be used for furigana (【東|とう】 【京|きょう】)."
e "It's also used for translations (【東京|Tokyo】)."
Ruby text will only trigger if a vertical line is present. The left lenticular bracket can be quoted by doubling it. Lenticular ruby text may not contain other text tags.
The {rt} and {rb} text tags. The {rt} tag is used to mark one or more characters to be displayed as ruby text. If the ruby text is preceded by text enclosed in the {rb} tag, the ruby text is centered over that text. Otherwise, it is centered over the preceding character.
For example:
e "Ruby can be used for furigana (東{rt}とう{/rt} 京{rt}きょう{/rt})."
e "It's also used for translations ({rb}東京{/rb}{rt}Tokyo{/rt})."
It's the creator's responsibility to ensure that ruby text does not leave the boundaries of the text. It may be necessary to add leading or spaces to the left and right of the text to prevent these errors from occurring.
Ren'Py also supports alternate ruby text, which is a second kind of
ruby top text. This is introduced with the {art} text tag (instead of {rt}),
and the altruby_style
property (instead of ruby_style
).
Fonts
Ren'Py supports TrueType/OpenType fonts and collections, and Image-Based fonts.
A TrueType or OpenType font is specified by giving the name of the font file. The file must be present in the game directory or one of the archive files.
Ren'Py also supports TrueType/OpenType collections that define more than one font. When accessing a collection, use the 0-based font index, followed by an at-sign and the file name. For example, "0@font.ttc" is the first font in a collection, "1@font.ttc" the second, and so on.
When looking for a font files, if the file is not found, Ren'Py will search
in the game/fonts
directory. For example, when looking for "test.ttf", Ren'Py
will first search for game/test.ttf
, and then for game/fonts/test.ttf
.
Font Replacement
The config.font_replacement_map
variable is used to map
fonts. The combination of font filename, boldness, and italics is
mapped to a similar combination. This allows a font with proper
italics to be used instead of the automatically-generated italics.
Once such mapping would be to replace the italic version of the Deja Vu Sans font with the official oblique version (You'll need to download the oblique font from the web):
init python:
config.font_replacement_map["DejaVuSans.ttf", False, True] = ("DejaVuSans-Oblique.ttf", False, False)
This mapping can improve the look of italic text.
Font names and aliases
The config.font_name_map
variable is used to give names
or aliases to fonts. This allows two things : first, to make dialogues
using the {font}
tag shorter and easier to use, and second, to
enable Font Groups to be used by these tags.
define config.font_name_map["jap"] = "electroharmonix.ttf"
define config.font_name_map["tjap"] = FontGroup().add("OrthodoxHerbertarian.ttf", "A", "Z").add("electroharmonix.ttf", None, None)
label yamato:
e "Sorry, what does {font=jap}Black holes and revelations{/font} mean ?"
y "You pronounce it {font=tjap}Black Holes And Revelations{/font}." # the capital letters appear in OrthodoxHerbertarian
Image-Based Fonts
Image based fonts can be registered by calling one of the following registration functions. Registering an image-based font requires the specification of a name, size, boldness, italicness, and underline. When all of these properties match the registered font, the registered font is used.
As BMFont is the most complete of the three image font formats Ren'Py supports, it's the one recommended for new projects. An example of BMFont use is:
init python:
renpy.register_bmfont("bmfont", 22, filename="bmfont.fnt")
define ebf = Character('Eileen', what_font="bmfont", what_size=22)
label demo_bmfont:
ebf "Finally, Ren'Py supports BMFonts."
Font Groups
When creating a multilingual game, it may not be possible to find a single font that covers every writing system the game use while projecting the the mood the creator intends. To support this, Ren'Py supports font groups that can take characters from two or more fonts and combine them into a single font.
To create a font group, create a FontGroup
object and call the .add
method
on it once or more. A FontGroup can be used wherever a font name can be
used. The add method takes the start and end of a range of Unicode character
points, and the first range to cover a point is used.
For example:
style default:
font FontGroup().add("english.ttf", 0x0020, 0x007f).add("japanese.ttf", 0x0000, 0xffff)
Note that while FontGroups can be given a name using config.font_name_map
,
a FontGroup only takes filepaths as fonts, and does not recognize names or aliases
defined using that variable.
Text Displayables
Text can also be used as a displayable, which allows you to apply transforms to text, displaying it as if it was an image and moving it around the screen.
Text Utility Functions
Slow Text Concerns
Ren'Py allows the creator or user to indicate that text should be displayed slowly. In this case, Ren'Py will render the text to a texture, and then draw rectangles from the texture to the screen.
Unfortunately, this means that it's possible to get rendering
artifacts when characters overlap. To minimize these rendering
artifacts, ensure that the line_leading
and
line_spacing
properties are large enough that lines do not
overlap. If the bottoms of characters on the first line are clipped,
especially if line_spacing is negative, consider increasing
line_overlap_split
.
Horizontal artifacts are also possible when characters are kerned together, but these artifacts are less severe, as they exist for only a single frame.
Artifacts aren't a problem for static text, like the text in menus and other parts of the user interface.
Text Overflow Logging
Ren'Py can log cases where text expands outside of the area allocated for it. To enable text overflow logging, the following steps are necessary.
Set the
config.debug_text_overflow
variable to true.Set the
xmaximum
andymaximum
style properties on either the Text displayable, or a container enclosing it.Run the game.
Whenever text is displayed that overflows the available area, Ren'Py will log an error to the text_overflow.txt file.
Variable Fonts
Ren'Py has support for OpenType variable fonts. These fonts may support multiple axes, such as weight and width, and based on the value of these axes, the display of the font can change. Variable fonts may also have named instances, which provide different values for the axes. For example, the "bold" named instance will likely provide the bold version of a font, while "regular" will be a more normal version.
Variable fonts require the use of the harfbuzz text shaper, controlled by
the shaper
style property. Once this is set, the instance
property selects a named instance, while the axis
property sets
the value of one or more axes.
These can also be set in the gui system. For example one can use:
define gui.text_font = "nunito.ttf"
define gui.text_instance = "light"
define gui.text_axis = {"width" : 125}
Will start with the light instance, and make it wide.
If no instance is given, Ren'Py will default to "regular" for non-bold text, and "bold" for bold text.
There are two text tags that support the use of variable fonts.
- instance
The instance tag changes the instance that is being used. For example:
"This is {instance=heavy}heavy{/instance} text."
When the instance tag is used, the axis properties are overriden.
- axis
The axis tag changes the value of one or more axes. For example:
"This is {axis:width=125}wide{/axis} text."
The axis tag can be used multiple times, and the values will be combined.
"This is {axis:width=125}{axis:weight=200}wide and bold{/axis}{/axis} text."
The value of on the right side of the equals is expected to be a floating point number.
To get the available instances and axes of a font, use the renpy.variable_font_info()
function. This function is intended to be called from the console. To access it, hit
shift+O to open the console, and then type:
renpy.variable_font_info("nunito.ttf")
This will display information for the nunito.ttf font.