The Grind: Prologue

Short Description: This is a prologue to a visual novel with an interactive narrative. Created by myself using the engine Ren’Py and brush painting black ink and water on rice paper.  

THE PROJECT

My project is a prologue to a visual novel, called The Grind, about spongey people that live in a world where it’s always nighttime. They have little light, most of which is provided by a giant manmade ‘star’ of fire in a globe near the center of the land where the more wealthy reside. The story follows a resilient ink grinder that provides ink to those who need it, for ink is the sustenance the sponge people require to survive. Black ink is banned because consuming it would turn the people dark, making them harder to see in the lack of light, causing disruptions. The ink grinder’s journey begins when the user makes a choice at the end of the prologue that determines which one of three narratives arches the novel will continue with. Here’s an image of the main menu.


INSPIRATION & THOUGHTS

I was inspired to make some type of graphic or visual novel back in sophomore year, when I read Yuumei’s Knite. I love both storytelling and creating art, so finding a combination really attracted me; it was more interactive than a regular comic book, interactivity being something I value in terms of connectivity, and the artwork supported the story and showed what the author was imagining – in this way I found the medium more intimate than, say, a movie or TV show. Because the author was laying out her words and drawing the related imagery straight from her imagination as opposed to finding actors that ‘best suit’ a character or a location that ‘best suits’ an imagined setting – never quite getting there. At the time, I felt that I wasn’t capable of producing good enough work and it would take me a lot of time when I had other classes to focus on. So I decided back then to leave the project for another time, and eventually came the time to do a capstone; the perfect time to make a graphic/visual novel of my own.

I chose to create a visual novel over a graphic novel; a distinction that’s lost to many people. A graphic novel is similar to (but not the same as ) a comic book, whereas a visual novel is a lot more interactive, incorporating decision making, branching narratives, and sometimes also other roles – for example playing an instrument. Knite is actually a flash comic. It took me some research to find what I really wanted to make – before, I’d just kind of lump the terms graphic/visual/kinetic together without really making a distinction, and even then I had trouble deciding whether I should include branching narratives to my visual novel. Soon, it became clear to me that branches were essential, especially as they contribute towards interactivity. Something that allows others to interact with it, experiment, find different paths, would lend itself to transportation: really being immersed in the story, the world, and even, if deep enough, affecting somebody’s views in the real world. Different paths, I believe, give readers the opportunity to explore and find out more about characters and viewpoints and thought processes, it gives you more insight into the storyworld, which hightens the impression of multiple dimensions, giving it more depth.

Of course, this was my first attempt at a project like this, and with a limited time to complete it, I couldn’t take it as deep as I might have liked and I still needed hands-on experience on what makes a visual novel successful; researching existing successes and their commonalities could only get one so far. Initially my plan was to create a novel, which of course would have taken a huge amount of time to make (especially if I was doing this individually), so it changed to a short story, which was still too time consuming, until I finally thought of creating a prologue. Still a lot of work. Usually, visual novels are team projects. I had to look up whether I doing something like this myself was even plausible. But a prologue would also allow me to have the opportunity to continue the project in the future, if I were to write/create the actual novel. So, my process, which stayed quite the same as I’d already planned back when I proposed my capstone, consisted of three parts: the story, the artwork and the code to put everything together.


THE STORY

I had trouble deciding what kind of story to write about, because I wished to create my artwork in ink with Chinese brush painting methods in a contemporary style – my currently preferred medium – and I wanted the story and art to mesh/flow together well. I also researched writing for visual novels because it’s not something I’d done before. Eventually, that indecisiveness lasted until I attended the first class of Professor David Perry’s Speculative Fictions course at the beginning of this semester (which I’d partially chosen to help me with capstone – goal achieved). He asked us to do a writing exercise, which forced me to just write something. And what I wrote turned out to be really suitable for my project; it incorporated the key component of my artwork into the story itself: the ink.

As I drafted my story, it became apparent to me that I’d have to change my plan from a short story to a prologue for what could be a larger visual novel due to time constraints. And because I was going to incorporate branching narratives in my story, I had to figure out what kind of branches I’d have. It seemed so complicated; there could be so many possibilities, yet they were hard to formulate. Once I bounced ideas off of a friend one night, which helped immensely, I figured out where the prologue would go.

Here is the structure of the story, showing the branches.

It seems slow-going, perhaps, but that’s because it is a prologue. There needs to be a satisfactory introduction to get readers accustomed to a very different (story)world, and having researched visual novels, I know that there cannot be branches all over the place or too soon; that would take you out of the story as well as put pressure on the author. If the readers had the ability to make narrative-altering decisions every few paces, the author would need to take them all into account and form new storylines that fit with the general narrative that runs throughout the VN – which puts into danger the integrity and cohesiveness of the whole thing. It begins turning into a different system more reliant on user input (called continuous interaction, allowing users to interact with the system at any point, as opposed to round-based interaction, where users are more limited and can only interact at certain points. I discuss this in my research paper. Citation: Endrass, Birgit, Christoph Klimmt, Gregor Mehlmann, Elisabeth André, Christian Roth. “Designing User-Character Dialog in Interactive Narratives: An Exploratory Experiment”. IEEE Transactions on Computational Intelligence and AI in Games, vol. 6, no. 2, 01 Jan. 2014, p. 166-173.)

Here’s the story draft.

The Grind: Prologue Draft

The ink grinder introduces the world to the reader a little

I live where it’s always nighttime. It’s not completely dark here; there’s always moonlight. I grind colored ink for those that want it – it’s nutritional and helps you keep your form. Unless it’s black ink you’re going for. Banned because it makes you hard to see in the darkness. Causes all sorts of disruptions. If you asked me whether I provide black ink, I’d tell you “no”. Fool.
Everybody wants to stay safe. But making ink isn’t too much of a cozy job. I have to leave, travel where there’s barely any light at all. None of that manmade everlasting fire “star” over in the central ring.
Well, we need to survive. So some of us have to get the job done. Being all spongey has its downsides though. Makes it a bit of a pain to hunt down colors. But I’m more absorbent than some, so I can last longer without ink out there. Makes for a good, if dangerous, living. The government gives me longer trips now, ‘cause who else will find the ingredients for black ink?   But enough about that, I need to head out – into the town this time, not the darkness. Were you hoping I’d go?
[User answers, “Yes”: Well, you’ll just have to wait to see what it’s like out there.]
[User answers, “No”: Where’s your sense of curiosity? I gotta work on how I tell my stories if you’re not interested.]

The ink grinder goes out to the black market and meets somebody in the same business as him

My bag’s always half-packed. I take out the essentials, restock them if I need to before setting out again. Less effort spent that way – I am careful about it though. I guess I don’t want to die anytime soon. Let me take a draught of my ink mix before I leave the house. Hm… which one shall I take?
[User answers, “Purple”: Red and blue, huh… stamina and common sense are always good to have with you.]
[User answers, “Green”: Joy and common sense… No wonder yellow and blue can be tricky to grind up properly.]
[User answers, “Orange”: It’s a healthy combination, red and yellow. Gives you your strength and keeps you somewhat joyful.]
Alright, let’s go. I enjoy walking through the village, I really do. Fresh scent of ink any day. Maybe that’s why I do what I do.
We’ve got to go down here. The entrance isn’t well known to the public, obviously – would make it harder to run a black market, wouldn’t it? Let’s see… My table should be this way. I’ll set up.
“Where’d you get all that?” There’s somebody looking at my table. “I don’t manage to collect nearly as much…”

They strike up conversation, which goes one of three ways depending on which option(s) the reader chooses:

“One doesn’t give up their secrets so easily,” I say. It’s a bit wrong, I suppose. But we can’t offer information up whenever we’re asked; if we all know the good spots in the darkness, even if it is a big world, the ink will run out before we know it, and how else are we supposed to make a living? Hence the difference in rates…
He looks around, then leans in close and whispers, “Who’re you selling to?”

They get into an argument because the ink grinder provides black ink for the government, which the stranger is against

[User answers, “Why would I tell you?”]
He looks at me for a while. “You’d better not be saying you’re the governments pet or something.”
“I didn’t say anything.” I felt a bit irritated at this stranger asking questions.
He’s really looking at me up close. “The people who usually don’t say anything are the pets.”
I stared at him, realizing my mistake. I shouldn’t have gotten annoyed. Stress of the job, y’know. The thing is, the general custom, shall we say, here in the black market is that everybody is fairly open about who they’re selling to or why they’re buying. People are quite divided, picking sides.

The conversation remains neutral as they discuss the problem of the ill people, for which the ink grinder also provides black ink

[User answers, “For the sick.”]
He nods solemnly. “It’s awful how the government won’t provide the buy even for the ill, huh…”
“Do you sell to them, too?”
“Sometimes… My rates are a little higher, y’know, it’s hard out there.”
“Hmm… but the ill tend to be poor and they can’t afford too high a price.”
“I try to keep it reasonable, I can’t stand seeing them feel all miserable.”
“You seem to have a good heart in you.”

They get along well and the stranger invites him for drinks at a bar, where he will reveal something about the organization that wants to overthrow the government by luring creatures in from the darkness so that the poor may have more light

[User answers, “Oh, for whoever wants it, y’know…”]
He gives me a speculative look and asks, “You mean you’d be open to selling to anyone then?”
Curious. “Are you buying?”
“I might. Well?”
“It depends. I can’t just give to any old thief.”
“Well, I’m not any old thief, that’s for sure. Smashed my damn light one time, the punk.”
“Ah, no… they take forever to fix, don’t they?”
“That’s right. Had to handle the fire, wait for officials to show up, then for the repairmen. You ever been in that situation?”
“No… I have a little more luck.”
“Luck, eh… Is that how you collected so much?”
“I’m not revealing anything.”
“Well, I’m a little more interested in buying now. But seeing as everyone wants to know who’s buying from them… How about we meet at a bar later? I’ll tell you a little something I can’t go shouting around here.”


THE ARTWORK

To make the illustrations, I had decided to go with Chinese traditional brush painting methods in a contemporary art style. One of the things I found attractive about visual novels is that they are so flexible; you can really create whatever you want, for example educational materials. Usually, visual novels have artwork in the style of manga/anime, but I wanted to take advantage of the flexibility and do something really different, perhaps even encourage more people to do so. It would make for a larger audience, attracting those that don’t like the manga/anime style. So, my own style used ink and water on rice paper, provided to me by Professor Barbara Edelstein as I’d been taking her fine art classes. I used two different brushes, a comparatively thicker shuǐ mò brush and a thin gōng bǐ brush. I cut the rice paper into A5 size panels and would sometimes sketch lightly in pencil what I was going to draw; once you put something down in ink, it’s difficult to correct it. I added splashes of colored paint for the ink pot panel (second picture below).

My workstation in the art studio had these materials on it: my brushes, a brush holder, a container of water, an ink dish, ink bottle, rice paper, A5 size normal paper template to measure out the rice paper, ruler, scissors, eraser, pencil, laptop with my story pulled up, phone and earphones. It was a lot of stuff. As the creation of all the art panels for the story overlapped with putting the story and art together with code, I would pull up the project on my laptop and go through the panels, creating the illustrations for them one by one. Here are some pictures of my workstation on various days.

When it was time to start adding the illustrations to the project, I would edit the pictures I took of them using BeFunky, an online photo editor. It took some time to figure out how to resize the pictures, I experimented a lot, and eventually I went for cropping the edges, then resizing to 1280 x 914 pixels. This worked best when the pictures were added to Ren’Py. After I figured out how to edit the first image, the rest of them were done much faster.


THE CODE

Before starting the project, I’d looked up ways to put things together and came across the visual novel engine Ren’Py. I chose to use it over other options such as CloudNovel, Adobe Flash, or even PowerPoint, as was suggested in class, because it really provided the general format of a visual novel as well as a lot of flexibility for formatting and adding features the way I’d like to.

When a new project is created in the Ren’Py launcher, shown below, it provides you with four different code files. These are titled script, which is totally blank, options, gui, and screens.

I went through The Question game in the launcher, the Ren’Py quickstart to get familiarized with the engine, initially, then briefly through the tutorial in the launcher. Then I set to work writing my script code, after encouragement from Professor’s Clay Shirky and Scott Fitzgerald to start working on a draft version of my project so that I would get more familiar with using Ren’Py and prevent the chances of encountering problems later. Gradually, after writing out the story text with the appropriate ‘jumps’ when something branched and getting started on the artwork, I started adding to the draft version, declaring more background images as I created the art panels, as well as transitions.

I would go to Lemma Soft Forums whenever I would run into an issue I needed help with, a haven for people making visual novels.

In the end, I also added music – Puzzles by Tomohito Nishiura for Professor Layton and the Curious Village. I’d had the Professor Layton games in mind since the beginning because I felt like the calm, mysterious vibe was very fitting for my project. One of the main things that keeps the readers going is the mystery of what’s going to happen in the story.

This is the script code:

#Declare images used by this game.
image bg intro = "IntroResized.jpg"
image bg grindingink = "GrindingInkResized.jpg"
image bg thievery = "ThieveryResized.jpg"
image bg blackink = "BlackInkResized.jpg"
image bg borderwall = "BorderWallResized.jpg"
image bg themap = "TheMapResized.jpg"
image bg forest = "ForestResized.jpg"
image bg inkgrinder = "InkGrinderResized.jpg"
image bg govink = "GovInkResized.jpg"
image bg outsidetown = "OutsideTownResized.jpg"
image bg yes = "YesResized.jpg"
image bg no = "NoResized.jpg"
image bg inkpots = "InkPotsResized.jpg"
image bg setout = "SetOutResized.jpg"
image bg entrance = "EntranceResized.jpg"
image bg blackmarket = "BlackMarketResized.jpg"
image bg igbm = "IGBMResized.jpg"
image bg stranger = "StrangerResized.jpg"

#Define characters used by this game.
define g = Character('INK GRINDER', color="#990033")
define s = Character('STRANGER', color="#7c4c44")

#The game starts here.
label start:

    scene bg intro
    with fade
    play music "ProfessorLaytonPuzzlesSuperExtended.mp3"

    g "I live where it’s always nighttime. It’s not completely dark here; there’s always moonlight."

    scene bg grindingink
    with fade

    "I grind colored ink for those that want it – it’s nutritional and helps you keep your form."

    scene bg thievery
    with fade

    "Unless it’s black ink you’re going for. Banned because it makes you hard to see in the darkness. Causes all sorts of disruptions."

    scene bg blackink
    with fade

    "If you asked me whether I provide black ink, I’d tell you \“no\”. Fool."

    scene bg borderwall
    with fade

    "Everybody wants to stay safe. But making ink isn’t too much of a cozy job. I have to leave, travel where there’s barely any light at all."

    scene bg themap
    with fade

    "None of that manmade everlasting fire \“star\” over in the central ring."

    scene bg inkgrinder
    with fade

    "Well, we need to survive. So some of us have to get the job done. Being all spongey has its downsides though."

    scene bg forest
    with fade

    "Makes it a bit of a pain to hunt down colors. But I’m more absorbent than some, so I can last longer without ink out there. Makes for a good, if dangerous, living."

    scene bg govink
    with fade

    "The government gives me longer trips now, ‘cause who else will find the ingredients for black ink?"

    scene bg outsidetown
    with fade

    "But enough about that, I need to head out – into the town this time, not the darkness. Were you hoping I’d go?"

    menu:

        "Yes":
            jump yes

        "No":
            jump no

label yes:

    scene bg yes
    with fade

    "Well, you’ll just have to wait to see what it’s like out there."
    jump blackmarket

label no:

    scene bg no
    with fade

    "Where’s your sense of curiosity? I gotta work on how I tell my stories if you’re not interested."
    jump blackmarket

label blackmarket:

    "My bag’s always half-packed. I take out the essentials, restock them if I need to before setting out again. Less effort spent that way – I am careful about it though. I guess I don’t want to die anytime soon."

    scene bg inkpots
    with fade

    "Let me take a draught of my ink mix before I leave the house. Hm… which one shall I take?"

    menu:

        "Purple":
            jump purple

        "Green":
            jump green

        "Orange":
            jump orange

label purple:

    scene bg grindingink
    with fade

    "Red and blue, huh… stamina and common sense are always good to have with you."
    jump village

label green:

    scene bg grindingink
    with fade

    "Joy and common sense… No wonder yellow and blue can be tricky to grind up properly."
    jump village

label orange:

    scene bg grindingink
    with fade

    "It’s a healthy combination, red and yellow. Gives you your strength and keeps you somewhat joyful."
    jump village

label village:

    scene bg setout
    with fade

    "Alright, let’s go. I enjoy walking through the village, I really do. Fresh scent of ink any day. Maybe that’s why I do what I do."

    scene bg entrance
    with fade

    "We’ve got to go down here. The entrance isn’t well known to the public, obviously – would make it harder to run a black market, wouldn’t it?"

    scene bg blackmarket
    with fade

    "Let’s see… My table should be this way. I’ll set up."

    scene bg stranger
    with fade

    s "\"Where’d you get all that? I don’t manage to collect nearly as much…\""

    scene bg igbm
    with fade

    g "\"One doesn’t give up their secrets so easily.\""

    "It’s a bit wrong, I suppose. But we can’t offer information up whenever we’re asked; if we all know the good spots in the darkness, even if it is a big world, the ink will run out before we know it, and how else are we supposed to make a living? Hence the difference in rates…"

    scene bg stranger
    with fade

    s "\"Who’re you selling to?\""

    menu:

        "\"Why would I tell you?\"":
            jump argument

        "\"For the sick.\"":
            jump neutral

        "\"Oh, for whoever wants it, y'know...\"":
            jump getalong

label argument:

    s "\"You’d better not be saying you’re the government's pet or something.\""

    scene bg igbm
    with fade

    g "\"I didn’t {i}say{/i} anything.\""

    "I feel a bit irritated at this stranger asking questions. And he’s really looking at me up close."

    scene bg stranger
    with fade

    s "\"The people who usually don’t say anything are the pets.\""

    "I stare at him, realizing my mistake. I shouldn’t have gotten annoyed. Stress of the job, y’know. The thing is, the general custom, shall we say, here in the black market is that everybody is fairly open about who they’re selling to or why they’re buying. People are quite divided, picking sides."

    return

label neutral:

    s "\"It’s awful how the government won’t provide the buy even for the ill, huh...\""

    scene bg igbm
    with fade

    g "\"Do you sell to them, too?\""

    scene bg stranger
    with fade

    s "\"Sometimes… My rates are a little higher, y’know, it’s hard out there.\""

    scene bg igbm
    with fade

    g "\"Hmm… but the ill tend to be poor and they can’t afford too high a price.\""

    scene bg stranger
    with fade

    s "\"I try to keep it reasonable, I can’t stand seeing them feel all miserable.\""

    scene bg igbm
    with fade

    g "\"You seem to have a good heart in you.\""

    return

label getalong:

    s "\"You mean you’d be open to selling to anyone then?\""

    scene bg igbm
    with fade

    g "Curious. \"Are you buying?\""

    scene bg stranger
    with fade

    s "\"I might. Well?\""

    scene bg igbm
    with fade

    g "\"It depends. I can’t just give to any old thief.\""

    scene bg stranger
    with fade

    s "\"Well, I’m not any old thief, that’s for sure. Smashed my damn light one time, the punk.\""

    scene bg igbm
    with fade

    g "\"Ah, no… they take forever to fix, don’t they?\""

    scene bg stranger
    with fade

    s "\"That’s right. Had to handle the fire, wait for officials to show up, then for the repairmen. You             ever been in that situation?\""

    scene bg igbm
    with fade

    g "\"No… I have a little more luck.\""

    scene bg stranger
    with fade

    s "\"Luck, eh… Is that how you collected so much?\""

    scene bg igbm
    with fade

    g "\"I’m not revealing anything.\""

    scene bg stranger
    with fade

    s "\"Well, I’m a little more interested in buying now. But seeing as everyone wants to know who’s buying from them… How about we meet at a bar later? I’ll tell you a little something I can’t go shouting around here.\""

return

Besides the script file, the other three were already filled in with the basics – as well as advanced options that were commented out. I went through them and edited what I needed to. In the GUI file, I set the text sizes for dialogue and menus and choices, changed the font, changed the main menu and game menu background images, and edited the choice menus for in-game decisions. I removed some unnecessary elements of the GUI that clashed with the rest of it, such as default images that popped up for various menus. I set the width and height of the game to 1280 x 914 pixels to match the resized artwork. I went for purply colors to go with the constant nighttime theme of the story.

This is the GUI code:

################################################################################
## Initialization
################################################################################

## The init offset statement causes the init code in this file to run before
## init code in any other file.
init offset = -2

## Calling gui.init resets the styles to sensible default values, and sets the
## width and height of the game.
init python:
    gui.init(1280, 914)



################################################################################
## GUI Configuration Variables
################################################################################


## Colors ######################################################################
##
## The colors of text in the interface.

## An accent color used throughout the interface to label and highlight text.
define gui.accent_color = '#942580'

## The color used for a text button when it is neither selected nor hovered.
define gui.idle_color = '#942580'

## The small color is used for small text, which needs to be brighter/darker to
## achieve the same effect.
define gui.idle_small_color = '#53478a'

## The color that is used for buttons and bars that are hovered.
define gui.hover_color = '#5c5c5c'

## The color used for a text button when it is selected but not focused. A
## button is selected if it is the current screen or preference value.
define gui.selected_color = '#5c5c5c'

## The color used for a text button when it cannot be selected.
define gui.insensitive_color = '#5c5c5c'

## Colors used for the portions of bars that are not filled in. These are not
## used directly, but are used when re-generating bar image files.
define gui.muted_color = '#a366a3'
define gui.hover_muted_color = '#c199c1'

## The colors used for dialogue and menu choice text.
define gui.text_color = '#53478a'
define gui.interface_text_color = '#009999'


## Fonts and Font Sizes ########################################################

## The font used for in-game text.
define gui.text_font = "AQuietSleep.ttf"

## The font used for character names.
define gui.name_text_font = "AQuietSleep.ttf"

## The font used for out-of-game text.
define gui.interface_text_font = "AQuietSleep.ttf"

## The size of normal dialogue text.
define gui.text_size = 26

## The size of character names.
define gui.name_text_size = 28

## The size of text in the game's user interface.
define gui.interface_text_size = 34

## The size of labels in the game's user interface.
define gui.label_text_size = 28

## The size of text on the notify screen.
define gui.notify_text_size = 16

## The size of the game's title.
define gui.title_text_size = 160


## Main and Game Menus #########################################################

## The images used for the main and game menus.
define gui.main_menu_background = "gui/main_menu_test.jpg"
define gui.game_menu_background = "gui/game_menu_test.jpg"

## Should we show the name and version of the game?
define gui.show_name = True


## Dialogue ####################################################################
##
## These variables control how dialogue is displayed on the screen one line at a
## time.

## The height of the textbox containing dialogue.
define gui.textbox_height = 185

## The placement of the textbox vertically on the screen. 0.0 is the top, 0.5 is
## center, and 1.0 is the bottom.
define gui.textbox_yalign = 1.0


## The placement of the speaking character's name, relative to the textbox.
## These can be a whole number of pixels from the left or top, or 0.5 to center.
define gui.name_xpos = 240
define gui.name_ypos = 0

## The horizontal alignment of the character's name. This can be 0.0 for left-
## aligned, 0.5 for centered, and 1.0 for right-aligned.
define gui.name_xalign = 0.0

## The width, height, and borders of the box containing the character's name, or
## None to automatically size it.
define gui.namebox_width = None
define gui.namebox_height = None

## The borders of the box containing the character's name, in left, top, right,
## bottom order.
define gui.namebox_borders = Borders(5, 5, 5, 5)

## If True, the background of the namebox will be tiled, if False, the
## background if the namebox will be scaled.
define gui.namebox_tile = False


## The placement of dialogue relative to the textbox. These can be a whole
## number of pixels relative to the left or top side of the textbox, or 0.5 to
## center.
define gui.dialogue_xpos = 268
define gui.dialogue_ypos = 50

## The maximum width of dialogue text, in pixels.
define gui.dialogue_width = 744

## The horizontal alignment of the dialogue text. This can be 0.0 for left-
## aligned, 0.5 for centered, and 1.0 for right-aligned.
define gui.dialogue_text_xalign = 0.0


## Buttons #####################################################################
##
## These variables, along with the image files in gui/button, control aspects of
## how buttons are displayed.

## The width and height of a button, in pixels. If None, Ren'Py computes a size.
define gui.button_width = None
define gui.button_height = 36

## The borders on each side of the button, in left, top, right, bottom order.
define gui.button_borders = Borders(4, 4, 4, 4)

## If True, the background image will be tiled. If False, the background image
## will be linearly scaled.
define gui.button_tile = False

## The font used by the button.
define gui.button_text_font = gui.interface_text_font

## The size of the text used by the button.
define gui.button_text_size = gui.interface_text_size

## The color of button text in various states.
define gui.button_text_idle_color = gui.idle_color
define gui.button_text_hover_color = gui.hover_color
define gui.button_text_selected_color = gui.selected_color
define gui.button_text_insensitive_color = gui.insensitive_color

## The horizontal alignment of the button text. (0.0 is left, 0.5 is center, 1.0
## is right).
define gui.button_text_xalign = 0.0


## These variables override settings for different kinds of buttons. Please see
## the gui documentation for the kinds of buttons available, and what each is
## used for.
##
## These customizations are used by the default interface:

define gui.radio_button_borders = Borders(25, 4, 4, 4)

define gui.check_button_borders = Borders(25, 4, 4, 4)

define gui.confirm_button_text_xalign = 0.5

define gui.page_button_borders = Borders(10, 4, 10, 4)

define gui.quick_button_borders = Borders(10, 4, 10, 0)
define gui.quick_button_text_size = 14
define gui.quick_button_text_idle_color = gui.idle_small_color
define gui.quick_button_text_selected_color = gui.accent_color

## You can also add your own customizations, by adding properly-named variables.
## For example, you can uncomment the following line to set the width of a
## navigation button.

# define gui.navigation_button_width = 250


## Choice Buttons ##############################################################
##
## Choice buttons are used in the in-game menus.

define gui.choice_button_width = 790
define gui.choice_button_height = None
define gui.choice_button_tile = False
define gui.choice_button_borders = Borders(100, 5, 100, 5)
define gui.choice_button_text_font = gui.text_font
define gui.choice_button_text_size = gui.text_size
define gui.choice_button_text_xalign = 0.5
define gui.choice_button_text_idle_color = "#53478a"
define gui.choice_button_text_hover_color = "#ffffff"


## File Slot Buttons ###########################################################
##
## A file slot button is a special kind of button. It contains a thumbnail
## image, and text describing the contents of the save slot. A save slot uses
## image files in gui/button, like the other kinds of buttons.

## The save slot button.
define gui.slot_button_width = 276
define gui.slot_button_height = 206
define gui.slot_button_borders = Borders(10, 10, 10, 10)
define gui.slot_button_text_size = 14
define gui.slot_button_text_xalign = 0.5
define gui.slot_button_text_idle_color = gui.idle_small_color

## The width and height of thumbnails used by the save slots.
define config.thumbnail_width = 256
define config.thumbnail_height = 144

## The number of columns and rows in the grid of save slots.
define gui.file_slot_cols = 3
define gui.file_slot_rows = 2


## Positioning and Spacing #####################################################
##
## These variables control the positioning and spacing of various user interface
## elements.

## The position of the left side of the navigation buttons, relative to the left
## side of the screen.
define gui.navigation_xpos = 40

## The vertical position of the skip indicator.
define gui.skip_ypos = 10

## The vertical position of the notify screen.
define gui.notify_ypos = 45

## The spacing between menu choices.
define gui.choice_spacing = 22

## Buttons in the navigation section of the main and game menus.
define gui.navigation_spacing = 4

## Controls the amount of spacing between preferences.
define gui.pref_spacing = 10

## Controls the amount of spacing between preference buttons.
define gui.pref_button_spacing = 0

## The spacing between file page buttons.
define gui.page_spacing = 0

## The spacing between file slots.
define gui.slot_spacing = 10

## The position of the main menu text.
define gui.main_menu_text_xalign = 1.0


## Frames ######################################################################
##
## These variables control the look of frames that can contain user interface
## components when an overlay or window is not present.

## Generic frames that are introduced by player code.
define gui.frame_borders = Borders(4, 4, 4, 4)

## The frame that is used as part of the confirm screen.
define gui.confirm_frame_borders = Borders(40, 40, 40, 40)

## The frame that is used as part of the skip screen.
define gui.skip_frame_borders = Borders(16, 5, 50, 5)

## The frame that is used as part of the notify screen.
define gui.notify_frame_borders = Borders(16, 5, 40, 5)

## Should frame backgrounds be tiled?
define gui.frame_tile = False


## Bars, Scrollbars, and Sliders ###############################################
##
## These control the look and size of bars, scrollbars, and sliders.
##
## The default GUI only uses sliders and vertical scrollbars. All of the other
## bars are only used in creator-written code.

## The height of horizontal bars, scrollbars, and sliders. The width of vertical
## bars, scrollbars, and sliders.
define gui.bar_size = 36
define gui.scrollbar_size = 12
define gui.slider_size = 30

## True if bar images should be tiled. False if they should be linearly scaled.
define gui.bar_tile = False
define gui.scrollbar_tile = False
define gui.slider_tile = False

## Horizontal borders.
define gui.bar_borders = Borders(4, 4, 4, 4)
define gui.scrollbar_borders = Borders(4, 4, 4, 4)
define gui.slider_borders = Borders(4, 4, 4, 4)

## Vertical borders.
define gui.vbar_borders = Borders(4, 4, 4, 4)
define gui.vscrollbar_borders = Borders(4, 4, 4, 4)
define gui.vslider_borders = Borders(4, 4, 4, 4)

## What to do with unscrollable scrollbars in the gui. "hide" hides them, while
## None shows them.
define gui.unscrollable = "hide"


## History #####################################################################
##
## The history screen displays dialogue that the player has already dismissed.

## The number of blocks of dialogue history Ren'Py will keep.
define config.history_length = 250

## The height of a history screen entry, or None to make the height variable at
## the cost of performance.
define gui.history_height = 140

## The position, width, and alignment of the label giving the name of the
## speaking character.
define gui.history_name_xpos = 150
define gui.history_name_ypos = 0
define gui.history_name_width = 150
define gui.history_name_xalign = 1.0

## The position, width, and alignment of the dialogue text.
define gui.history_text_xpos = 170
define gui.history_text_ypos = 5
define gui.history_text_width = 740
define gui.history_text_xalign = 0.0


## NVL-Mode ####################################################################
##
## The NVL-mode screen displays the dialogue spoken by NVL-mode characters.

## The borders of the background of the NVL-mode background window.
define gui.nvl_borders = Borders(0, 10, 0, 20)

## The height of an NVL-mode entry. Set this to None to have the entries
## dynamically adjust height.
define gui.nvl_height = 115

## The spacing between NVL-mode entries when gui.nvl_height is None, and between
## NVL-mode entries and an NVL-mode menu.
define gui.nvl_spacing = 10

## The position, width, and alignment of the label giving the name of the
## speaking character.
define gui.nvl_name_xpos = 430
define gui.nvl_name_ypos = 0
define gui.nvl_name_width = 150
define gui.nvl_name_xalign = 1.0

## The position, width, and alignment of the dialogue text.
define gui.nvl_text_xpos = 450
define gui.nvl_text_ypos = 8
define gui.nvl_text_width = 590
define gui.nvl_text_xalign = 0.0

## The position, width, and alignment of nvl_thought text (the text said by the
## nvl_narrator character.)
define gui.nvl_thought_xpos = 240
define gui.nvl_thought_ypos = 0
define gui.nvl_thought_width = 780
define gui.nvl_thought_xalign = 0.0

## The position of nvl menu_buttons.
define gui.nvl_button_xpos = 450
define gui.nvl_button_xalign = 0.0

## Localization ################################################################

## This controls where a line break is permitted. The default is suitable
## for most languages. A list of available values can be found at https://
## www.renpy.org/doc/html/style_properties.html#style-property-language

define gui.language = "unicode"


################################################################################
## Mobile devices
################################################################################

init python:

    ## This increases the size of the quick buttons to make them easier to touch
    ## on tablets and phones.
    if renpy.variant("touch"):

        gui.quick_button_borders = Borders(40, 14, 40, 0)

    ## This changes the size and spacing of various GUI elements to ensure they
    ## are easily visible on phones.
    if renpy.variant("small"):

        ## Font sizes.
        gui.text_size = 30
        gui.name_text_size = 36
        gui.notify_text_size = 25
        gui.interface_text_size = 36
        gui.button_text_size = 34
        gui.label_text_size = 36

        ## Adjust the location of the textbox.
        gui.textbox_height = 240
        gui.name_xpos = 80
        gui.text_xpos = 90
        gui.text_width = 1100

        ## Change the size and spacing of items in the game menu.
        gui.choice_button_width = 1240

        gui.navigation_spacing = 20
        gui.pref_button_spacing = 10

        gui.history_height = 190
        gui.history_text_width = 690

        ## File button layout.
        gui.file_slot_cols = 2
        gui.file_slot_rows = 2

        ## NVL-mode.
        gui.nvl_height = 170

        gui.nvl_name_width = 305
        gui.nvl_name_xpos = 325

        gui.nvl_text_width = 915
        gui.nvl_text_xpos = 345
        gui.nvl_text_ypos = 5

        gui.nvl_thought_width = 1240
        gui.nvl_thought_xpos = 20

        gui.nvl_button_width = 1240
        gui.nvl_button_xpos = 20

        ## Quick buttons.
        gui.quick_button_text_size = 20

In the options code, I commented out the ‘version’ number because it didn’t matter for now. I also added text for the ‘About’ menu, and first experimented adding sound here.

This is the options code:

## This file contains options that can be changed to customize your game.
##
## Lines beginning with two '#' marks are comments, and you shouldn't uncomment
## them. Lines beginning with a single '#' mark are commented-out code, and you
## may want to uncomment them when appropriate.


## Basics ######################################################################

## config.mouse = { 'default' : [ ('pointinghand.jpg', 0, 0)] }

## A human-readable name of the game. This is used to set the default window
## title, and shows up in the interface and error reports.
##
## The _() surrounding the string marks it as eligible for translation.

define config.name = _("The Grind")


## Determines if the title given above is shown on the main menu screen. Set
## this to False to hide the title.

define gui.show_name = True


## The version of the game.

## define config.version = "1.0"


## Text that is placed on the game's about screen. To insert a blank line
## between paragraphs, write \n\n.

define gui.about = _("This is a prologue to a larger visual novel that may be produced later on. This was made by Ferwa Razzaq, an Interactive Media Arts student at NYU Shanghai. April 2017")


## A short name for the game used for executables and directories in the built
## distribution. This must be ASCII-only, and must not contain spaces, colons,
## or semicolons.

define build.name = "TheGrind"


## Sounds and music ############################################################

## These three variables control which mixers are shown to the player by
## default. Setting one of these to False will hide the appropriate mixer.

define config.has_sound = True
define config.has_music = True
define config.has_voice = True


## To allow the user to play a test sound on the sound or voice channel,
## uncomment a line below and use it to set a sample sound to play.

# define config.sample_sound = "sample-sound.ogg"
# define config.sample_voice = "sample-voice.ogg"


## Uncomment the following line to set an audio file that will be played while
## the player is at the main menu. This file will continue playing into the
## game, until it is stopped or another file is played.

## define config.main_menu_music = "ProfessorLaytonPuzzlesSuperExtended.mp3"


## Transitions #################################################################
##
## These variables set transitions that are used when certain events occur.
## Each variable should be set to a transition, or None to indicate that no
## transition should be used.

## Entering or exiting the game menu.

define config.enter_transition = dissolve
define config.exit_transition = dissolve


## A transition that is used after a game has been loaded.

define config.after_load_transition = None


## Used when entering the main menu after the game has ended.

define config.end_game_transition = fade


## A variable to set the transition used when the game starts does not exist.
## Instead, use a with statement after showing the initial scene.


## Window management ###########################################################
##
## This controls when the dialogue window is displayed. If "show", it is always
## displayed. If "hide", it is only displayed when dialogue is present. If
## "auto", the window is hidden before scene statements and shown again once
## dialogue is displayed.
##
## After the game has started, this can be changed with the "window show",
## "window hide", and "window auto" statements.

define config.window = "auto"


## Transitions used to show and hide the dialogue window

define config.window_show_transition = Dissolve(.2)
define config.window_hide_transition = Dissolve(.2)


## Preference defaults #########################################################

## Controls the default text speed. The default, 0, is infinite, while any other
## number is the number of characters per second to type out.

default preferences.text_cps = 0


## The default auto-forward delay. Larger numbers lead to longer waits, with 0
## to 30 being the valid range.

default preferences.afm_time = 15


## Save directory ##############################################################
##
## Controls the platform-specific place Ren'Py will place the save files for
## this game. The save files will be placed in:
##
## Windows: %APPDATA\RenPy\
##
## Macintosh: $HOME/Library/RenPy/
##
## Linux: $HOME/.renpy/
##
## This generally should not be changed, and if it is, should always be a
## literal string, not an expression.

define config.save_directory = "TheGrind-1489760294"


## Icon ########################################################################
##
## The icon displayed on the taskbar or dock.

define config.window_icon = "gui/window_icon.png"


## Build configuration #########################################################
##
## This section controls how Ren'Py turns your project into distribution files.

init python:

    ## The following functions take file patterns. File patterns are case-
    ## insensitive, and matched against the path relative to the base directory,
    ## with and without a leading /. If multiple patterns match, the first is
    ## used.
    ##
    ## In a pattern:
    ##
    ## / is the directory separator.
    ##
    ## * matches all characters, except the directory separator.
    ##
    ## ** matches all characters, including the directory separator.
    ##
    ## For example, "*.txt" matches txt files in the base directory, "game/
    ## **.ogg" matches ogg files in the game directory or any of its
    ## subdirectories, and "**.psd" matches psd files anywhere in the project.

    ## Classify files as None to exclude them from the built distributions.

    build.classify('**~', None)
    build.classify('**.bak', None)
    build.classify('**/.**', None)
    build.classify('**/#**', None)
    build.classify('**/thumbs.db', None)

    ## To archive files, classify them as 'archive'.

    # build.classify('game/**.png', 'archive')
    # build.classify('game/**.jpg', 'archive')

    ## Files matching documentation patterns are duplicated in a mac app build,
    ## so they appear in both the app and the zip file.

    build.documentation('*.html')
    build.documentation('*.txt')

## A Google Play license key is required to download expansion files and perform
## in-app purchases. It can be found on the "Services & APIs" page of the Google
## Play developer console.

# define build.google_play_key = "..."


## The username and project name associated with an itch.io project, separated
## by a slash.

# define build.itch_project = "renpytom/test-project"

In the screens code, I edited the position of the title on the main menu and made sure things were aligned properly.

And this is the screens code:

################################################################################
## Initialization
################################################################################

init offset = -1


################################################################################
## Styles
################################################################################

style default:
    properties gui.text_properties()
    language gui.language

style input:
    properties gui.text_properties("input", accent=True)
    adjust_spacing False

style hyperlink_text:
    properties gui.text_properties("hyperlink", accent=True)
    hover_underline True

style gui_text:
    properties gui.text_properties("interface")


style button:
    properties gui.button_properties("button")

style button_text is gui_text:
    properties gui.text_properties("button")
    yalign 0.5


style label_text is gui_text:
    properties gui.text_properties("label", accent=True)

style prompt_text is gui_text:
    properties gui.text_properties("prompt")


style bar:
    ysize gui.bar_size
    left_bar Frame("gui/bar/left.png", gui.bar_borders, tile=gui.bar_tile)
    right_bar Frame("gui/bar/right.png", gui.bar_borders, tile=gui.bar_tile)

style vbar:
    xsize gui.bar_size
    top_bar Frame("gui/bar/top.png", gui.vbar_borders, tile=gui.bar_tile)
    bottom_bar Frame("gui/bar/bottom.png", gui.vbar_borders, tile=gui.bar_tile)

style scrollbar:
    ysize gui.scrollbar_size
    base_bar Frame("gui/scrollbar/horizontal_[prefix_]bar.png", gui.scrollbar_borders, tile=gui.scrollbar_tile)
    thumb Frame("gui/scrollbar/horizontal_[prefix_]thumb.png", gui.scrollbar_borders, tile=gui.scrollbar_tile)

style vscrollbar:
    xsize gui.scrollbar_size
    base_bar Frame("gui/scrollbar/vertical_[prefix_]bar.png", gui.vscrollbar_borders, tile=gui.scrollbar_tile)
    thumb Frame("gui/scrollbar/vertical_[prefix_]thumb.png", gui.vscrollbar_borders, tile=gui.scrollbar_tile)

style slider:
    ysize gui.slider_size
    base_bar Frame("gui/slider/horizontal_[prefix_]bar.png", gui.slider_borders, tile=gui.slider_tile)
    thumb "gui/slider/horizontal_[prefix_]thumb.png"

style vslider:
    xsize gui.slider_size
    base_bar Frame("gui/slider/vertical_[prefix_]bar.png", gui.vslider_borders, tile=gui.slider_tile)
    thumb "gui/slider/vertical_[prefix_]thumb.png"


style frame:
    padding gui.frame_borders.padding
    background Frame("gui/frame.png", gui.frame_borders, tile=gui.frame_tile)



################################################################################
## In-game screens
################################################################################


## Say screen ##################################################################
##
## The say screen is used to display dialogue to the player. It takes two
## parameters, who and what, which are the name of the speaking character and
## the text to be displayed, respectively. (The who parameter can be None if no
## name is given.)
##
## This screen must create a text displayable with id "what", as Ren'Py uses
## this to manage text display. It can also create displayables with id "who"
## and id "window" to apply style properties.
##
## https://www.renpy.org/doc/html/screen_special.html#say

screen say(who, what):
    style_prefix "say"

    window:
        id "window"

        if who is not None:

            window:
                style "namebox"
                text who id "who"

        text what id "what"


    ## If there's a side image, display it above the text. Do not display on the
    ## phone variant - there's no room.
    if not renpy.variant("small"):
        add SideImage() xalign 0.0 yalign 1.0


style window is default
style say_label is default
style say_dialogue is default
style say_thought is say_dialogue

style namebox is default
style namebox_label is say_label


style window:
    xalign 0.5
    xfill True
    yalign gui.textbox_yalign
    ysize gui.textbox_height

    background Image("gui/textbox.png", xalign=0.5, yalign=1.0)

style namebox:
    xpos gui.name_xpos
    xanchor gui.name_xalign
    xsize gui.namebox_width
    ypos gui.name_ypos
    ysize gui.namebox_height

    background Frame("gui/namebox.png", gui.namebox_borders, tile=gui.namebox_tile, xalign=gui.name_xalign)
    padding gui.namebox_borders.padding

style say_label:
    properties gui.text_properties("name", accent=True)
    xalign gui.name_xalign
    yalign 0.5

style say_dialogue:
    properties gui.text_properties("dialogue")

    xpos gui.dialogue_xpos
    xsize gui.dialogue_width
    ypos gui.dialogue_ypos


## Input screen ################################################################
##
## This screen is used to display renpy.input. The prompt parameter is used to
## pass a text prompt in.
##
## This screen must create an input displayable with id "input" to accept the
## various input parameters.
##
## http://www.renpy.org/doc/html/screen_special.html#input

screen input(prompt):
    style_prefix "input"

    window:

        vbox:
            xalign gui.dialogue_text_xalign
            xpos gui.dialogue_xpos
            xsize gui.dialogue_width
            ypos gui.dialogue_ypos

            text prompt style "input_prompt"
            input id "input"

style input_prompt is default

style input_prompt:
    xalign gui.dialogue_text_xalign
    properties gui.text_properties("input_prompt")

style input:
    xalign gui.dialogue_text_xalign
    xmaximum gui.dialogue_width


## Choice screen ###############################################################
##
## This screen is used to display the in-game choices presented by the menu
## statement. The one parameter, items, is a list of objects, each with caption
## and action fields.
##
## http://www.renpy.org/doc/html/screen_special.html#choice

screen choice(items):
    style_prefix "choice"

    vbox:
        for i in items:
            textbutton i.caption action i.action


## When this is true, menu captions will be spoken by the narrator. When false,
## menu captions will be displayed as empty buttons.
define config.narrator_menu = True


style choice_vbox is vbox
style choice_button is button
style choice_button_text is button_text

style choice_vbox:
    xalign 0.5
    ypos 270
    yanchor 0.5

    spacing gui.choice_spacing

style choice_button is default:
    properties gui.button_properties("choice_button")

style choice_button_text is default:
    properties gui.button_text_properties("choice_button")


## Quick Menu screen ###########################################################
##
## The quick menu is displayed in-game to provide easy access to the out-of-game
## menus.

screen quick_menu():

    ## Ensure this appears on top of other screens.
    zorder 100

    if quick_menu:

        hbox:
            style_prefix "quick"

            xalign 0.5
            yalign 1.0

            textbutton _("Back") action Rollback()
            textbutton _("History") action ShowMenu('history')
            textbutton _("Skip") action Skip() alternate Skip(fast=True, confirm=True)
            textbutton _("Auto") action Preference("auto-forward", "toggle")
            textbutton _("Save") action ShowMenu('save')
            textbutton _("Q.Save") action QuickSave()
            textbutton _("Q.Load") action QuickLoad()
            textbutton _("Prefs") action ShowMenu('preferences')


## This code ensures that the quick_menu screen is displayed in-game, whenever
## the player has not explicitly hidden the interface.
init python:
    config.overlay_screens.append("quick_menu")

default quick_menu = True

style quick_button is default
style quick_button_text is button_text

style quick_button:
    properties gui.button_properties("quick_button")

style quick_button_text:
    properties gui.button_text_properties("quick_button")


################################################################################
## Main and Game Menu Screens
################################################################################

## Navigation screen ###########################################################
##
## This screen is included in the main and game menus, and provides navigation
## to other menus, and to start the game.

screen navigation():

    vbox:
        style_prefix "navigation"

        xpos gui.navigation_xpos
        yalign 0.5

        spacing gui.navigation_spacing

        if main_menu:

            textbutton _("Start") action Start()

        else:

            textbutton _("History") action ShowMenu("history")

            textbutton _("Save") action ShowMenu("save")

        textbutton _("Load") action ShowMenu("load")

        textbutton _("Preferences") action ShowMenu("preferences")

        if _in_replay:

            textbutton _("End Replay") action EndReplay(confirm=True)

        elif not main_menu:

            textbutton _("Main Menu") action MainMenu()

        textbutton _("About") action ShowMenu("about")

        if renpy.variant("pc"):

            ## Help isn't necessary or relevant to mobile devices.
            textbutton _("Help") action ShowMenu("help")

            ## The quit button is banned on iOS and unnecessary on Android.
            textbutton _("Quit") action Quit(confirm=not main_menu)


style navigation_button is gui_button
style navigation_button_text is gui_button_text

style navigation_button:
    size_group "navigation"
    properties gui.button_properties("navigation_button")

style navigation_button_text:
    properties gui.button_text_properties("navigation_button")


## Main Menu screen ############################################################
##
## Used to display the main menu when Ren'Py starts.
##
## http://www.renpy.org/doc/html/screen_special.html#main-menu

screen main_menu():

    ## This ensures that any other menu screen is replaced.
    tag menu

    style_prefix "main_menu"

    add gui.main_menu_background

    ## This empty frame darkens the main menu.
    frame:
        pass

    ## The use statement includes another screen inside this one. The actual
    ## contents of the main menu are in the navigation screen.
    use navigation

    if gui.show_name:

        vbox:
            text "[config.name!t]":
                style "main_menu_title"

            text "[config.version]":
                style "main_menu_version"


style main_menu_frame is empty
style main_menu_vbox is vbox
style main_menu_text is gui_text
style main_menu_title is main_menu_text
style main_menu_version is main_menu_text

style main_menu_frame:
    xsize 280
    yfill True

    ## background "gui/overlay/main_menu.png"

style main_menu_vbox:
    xalign 0.87
    xoffset -20
    xmaximum 800
    yalign 0.18
    yoffset -20

style main_menu_text:
    properties gui.text_properties("main_menu", accent=True)

style main_menu_title:
    properties gui.text_properties("title")

style main_menu_version:
    properties gui.text_properties("version")


## Game Menu screen ############################################################
##
## This lays out the basic common structure of a game menu screen. It's called
## with the screen title, and displays the background, title, and navigation.
##
## The scroll parameter can be None, or one of "viewport" or "vpgrid". When
## this screen is intended to be used with one or more children, which are
## transcluded (placed) inside it.

screen game_menu(title, scroll=None):

    style_prefix "game_menu"

    if main_menu:
        add gui.main_menu_background
    else:
        add gui.game_menu_background

    frame:
        style "game_menu_outer_frame"

        hbox:

            ## Reserve space for the navigation section.
            frame:
                style "game_menu_navigation_frame"

            frame:
                style "game_menu_content_frame"

                if scroll == "viewport":

                    viewport:
                        scrollbars "vertical"
                        mousewheel True
                        draggable True

                        side_yfill True

                        vbox:
                            transclude

                elif scroll == "vpgrid":

                    vpgrid:
                        cols 1
                        yinitial 1.0

                        scrollbars "vertical"
                        mousewheel True
                        draggable True

                        side_yfill True

                        transclude

                else:

                    transclude

    use navigation

    textbutton _("Return"):
        style "return_button"

        action Return()

    label title

    if main_menu:
        key "game_menu" action ShowMenu("main_menu")


style game_menu_outer_frame is empty
style game_menu_navigation_frame is empty
style game_menu_content_frame is empty
style game_menu_viewport is gui_viewport
style game_menu_side is gui_side
style game_menu_scrollbar is gui_vscrollbar

style game_menu_label is gui_label
style game_menu_label_text is gui_label_text

style return_button is navigation_button
style return_button_text is navigation_button_text

style game_menu_outer_frame:
    bottom_padding 30
    top_padding 120

    ## background "gui/overlay/game_menu.png"

style game_menu_navigation_frame:
    xsize 280
    yfill True

style game_menu_content_frame:
    left_margin 40
    right_margin 20
    top_margin 10

style game_menu_viewport:
    xsize 920

style game_menu_vscrollbar:
    unscrollable gui.unscrollable

style game_menu_side:
    spacing 10

style game_menu_label:
    xpos 50
    ysize 120

style game_menu_label_text:
    size gui.title_text_size
    color gui.accent_color
    yalign 0.5

style return_button:
    xpos gui.navigation_xpos
    yalign 1.0
    yoffset -30


## About screen ################################################################
##
## This screen gives credit and copyright information about the game and Ren'Py.
##
## There's nothing special about this screen, and hence it also serves as an
## example of how to make a custom screen.

screen about():

    tag menu

    ## This use statement includes the game_menu screen inside this one. The
    ## vbox child is then included inside the viewport inside the game_menu
    ## screen.
    use game_menu(_("About"), scroll="viewport"):

        style_prefix "about"

        vbox:

            label "[config.name!t]"
            text _("Version [config.version!t]\n")

            ## gui.about is usually set in options.rpy.
            if gui.about:
                text "[gui.about!t]\n"

            text _("Made with {a=https://www.renpy.org/}Ren'Py{/a} [renpy.version_only].\n\n[renpy.license!t]")


## This is redefined in options.rpy to add text to the about screen.
define gui.about = ""


style about_label is gui_label
style about_label_text is gui_label_text
style about_text is gui_text

style about_label_text:
    size gui.label_text_size


## Load and Save screens #######################################################
##
## These screens are responsible for letting the player save the game and load
## it again. Since they share nearly everything in common, both are implemented
## in terms of a third screen, file_slots.
##
## https://www.renpy.org/doc/html/screen_special.html#save https://
## www.renpy.org/doc/html/screen_special.html#load

screen save():

    tag menu

    use file_slots(_("Save"))


screen load():

    tag menu

    use file_slots(_("Load"))


screen file_slots(title):

    default page_name_value = FilePageNameInputValue(pattern=_("Page {}"), auto=_("Automatic saves"), quick=_("Quick saves"))

    use game_menu(title):

        fixed:

            ## This ensures the input will get the enter event before any of the
            ## buttons do.
            order_reverse True

            ## The page name, which can be edited by clicking on a button.
            button:
                style "page_label"

                key_events True
                xalign 0.5
                action page_name_value.Toggle()

                input:
                    style "page_label_text"
                    value page_name_value

            ## The grid of file slots.
            grid gui.file_slot_cols gui.file_slot_rows:
                style_prefix "slot"

                xalign 0.5
                yalign 0.5

                spacing gui.slot_spacing

                for i in range(gui.file_slot_cols * gui.file_slot_rows):

                    $ slot = i + 1

                    button:
                        action FileAction(slot)

                        has vbox

                        add FileScreenshot(slot) xalign 0.5

                        text FileTime(slot, format=_("{#file_time}%A, %B %d %Y, %H:%M"), empty=_("empty slot")):
                            style "slot_time_text"

                        text FileSaveName(slot):
                            style "slot_name_text"

                        key "save_delete" action FileDelete(slot)

            ## Buttons to access other pages.
            hbox:
                style_prefix "page"

                xalign 0.5
                yalign 1.0

                spacing gui.page_spacing

                textbutton _("") action FilePageNext()


style page_label is gui_label
style page_label_text is gui_label_text
style page_button is gui_button
style page_button_text is gui_button_text

style slot_button is gui_button
style slot_button_text is gui_button_text
style slot_time_text is slot_button_text
style slot_name_text is slot_button_text

style page_label:
    xpadding 50
    ypadding 3

style page_label_text:
    text_align 0.5
    layout "subtitle"
    hover_color gui.hover_color

style page_button:
    properties gui.button_properties("page_button")

style page_button_text:
    properties gui.button_text_properties("page_button")

style slot_button:
    properties gui.button_properties("slot_button")

style slot_button_text:
    properties gui.button_text_properties("slot_button")


## Preferences screen ##########################################################
##
## The preferences screen allows the player to configure the game to better suit
## themselves.
##
## https://www.renpy.org/doc/html/screen_special.html#preferences

screen preferences():

    tag menu

    if renpy.mobile:
        $ cols = 2
    else:
        $ cols = 4

    use game_menu(_("Preferences"), scroll="viewport"):

        vbox:

            hbox:
                box_wrap True

                if renpy.variant("pc"):

                    vbox:
                        style_prefix "radio"
                        label _("Display")
                        textbutton _("Window") action Preference("display", "window")
                        textbutton _("Fullscreen") action Preference("display", "fullscreen")

                vbox:
                    style_prefix "radio"
                    label _("Rollback Side")
                    textbutton _("Disable") action Preference("rollback side", "disable")
                    textbutton _("Left") action Preference("rollback side", "left")
                    textbutton _("Right") action Preference("rollback side", "right")

                vbox:
                    style_prefix "check"
                    label _("Skip")
                    textbutton _("Unseen Text") action Preference("skip", "toggle")
                    textbutton _("After Choices") action Preference("after choices", "toggle")
                    textbutton _("Transitions") action InvertSelected(Preference("transitions", "toggle"))

                ## Additional vboxes of type "radio_pref" or "check_pref" can be
                ## added here, to add additional creator-defined preferences.

            null height (4 * gui.pref_spacing)

            hbox:
                style_prefix "slider"
                box_wrap True

                vbox:

                    label _("Text Speed")

                    bar value Preference("text speed")

                    label _("Auto-Forward Time")

                    bar value Preference("auto-forward time")

                vbox:

                    if config.has_music:
                        label _("Music Volume")

                        hbox:
                            bar value Preference("music volume")

                    if config.has_sound:

                        label _("Sound Volume")

                        hbox:
                            bar value Preference("sound volume")

                            if config.sample_sound:
                                textbutton _("Test") action Play("sound", config.sample_sound)


                    if config.has_voice:
                        label _("Voice Volume")

                        hbox:
                            bar value Preference("voice volume")

                            if config.sample_voice:
                                textbutton _("Test") action Play("voice", config.sample_voice)

                    if config.has_music or config.has_sound or config.has_voice:
                        null height gui.pref_spacing

                        textbutton _("Mute All"):
                            action Preference("all mute", "toggle")
                            style "mute_all_button"


style pref_label is gui_label
style pref_label_text is gui_label_text
style pref_vbox is vbox

style radio_label is pref_label
style radio_label_text is pref_label_text
style radio_button is gui_button
style radio_button_text is gui_button_text
style radio_vbox is pref_vbox

style check_label is pref_label
style check_label_text is pref_label_text
style check_button is gui_button
style check_button_text is gui_button_text
style check_vbox is pref_vbox

style slider_label is pref_label
style slider_label_text is pref_label_text
style slider_slider is gui_slider
style slider_button is gui_button
style slider_button_text is gui_button_text
style slider_pref_vbox is pref_vbox

style mute_all_button is check_button
style mute_all_button_text is check_button_text

style pref_label:
    top_margin gui.pref_spacing
    bottom_margin 2

style pref_label_text:
    yalign 1.0

style pref_vbox:
    xsize 225

style radio_vbox:
    spacing gui.pref_button_spacing

style radio_button:
    properties gui.button_properties("radio_button")
    foreground "gui/button/check_[prefix_]foreground.png"

style radio_button_text:
    properties gui.button_text_properties("radio_button")

style check_vbox:
    spacing gui.pref_button_spacing

style check_button:
    properties gui.button_properties("check_button")
    foreground "gui/button/check_[prefix_]foreground.png"

style check_button_text:
    properties gui.button_text_properties("check_button")

style slider_slider:
    xsize 350

style slider_button:
    properties gui.button_properties("slider_button")
    yalign 0.5
    left_margin 10

style slider_button_text:
    properties gui.button_text_properties("slider_button")

style slider_vbox:
    xsize 450


## History screen ##############################################################
##
## This is a screen that displays the dialogue history to the player. While
## there isn't anything special about this screen, it does have to access the
## dialogue history stored in _history_list.
##
## https://www.renpy.org/doc/html/history.html

screen history():

    tag menu

    ## Avoid predicting this screen, as it can be very large.
    predict False

    use game_menu(_("History"), scroll=("vpgrid" if gui.history_height else "viewport")):

        style_prefix "history"

        for h in _history_list:

            window:

                ## This lays things out properly if history_height is None.
                has fixed:
                    yfit True

                if h.who:

                    label h.who:
                        style "history_name"

                        ## Take the color of the who text from the Character, if
                        ## set.
                        if "color" in h.who_args:
                            text_color h.who_args["color"]

                text h.what

        if not _history_list:
            label _("The dialogue history is empty.")


style history_window is empty

style history_name is gui_label
style history_name_text is gui_label_text
style history_text is gui_text

style history_text is gui_text

style history_label is gui_label
style history_label_text is gui_label_text

style history_window:
    xfill True
    ysize gui.history_height

style history_name:
    xpos gui.history_name_xpos
    xanchor gui.history_name_xalign
    ypos gui.history_name_ypos
    xsize gui.history_name_width

style history_name_text:
    min_width gui.history_name_width
    text_align gui.history_name_xalign

style history_text:
    xpos gui.history_text_xpos
    ypos gui.history_text_ypos
    xanchor gui.history_text_xalign
    xsize gui.history_text_width
    min_width gui.history_text_width
    text_align gui.history_text_xalign
    layout ("subtitle" if gui.history_text_xalign else "tex")

style history_label:
    xfill True

style history_label_text:
    xalign 0.5


## Help screen #################################################################
##
## A screen that gives information about key and mouse bindings. It uses other
## screens (keyboard_help, mouse_help, and gamepad_help) to display the actual
## help.

screen help():

    tag menu

    default device = "keyboard"

    use game_menu(_("Help"), scroll="viewport"):

        style_prefix "help"

        vbox:
            spacing 15

            hbox:

                textbutton _("Keyboard") action SetScreenVariable("device", "keyboard")
                textbutton _("Mouse") action SetScreenVariable("device", "mouse")

                if GamepadExists():
                    textbutton _("Gamepad") action SetScreenVariable("device", "gamepad")

            if device == "keyboard":
                use keyboard_help
            elif device == "mouse":
                use mouse_help
            elif device == "gamepad":
                use gamepad_help


screen keyboard_help():

    hbox:
        label _("Enter")
        text _("Advances dialogue and activates the interface.")

    hbox:
        label _("Space")
        text _("Advances dialogue without selecting choices.")

    hbox:
        label _("Arrow Keys")
        text _("Navigate the interface.")

    hbox:
        label _("Escape")
        text _("Accesses the game menu.")

    hbox:
        label _("Ctrl")
        text _("Skips dialogue while held down.")

    hbox:
        label _("Tab")
        text _("Toggles dialogue skipping.")

    hbox:
        label _("Page Up")
        text _("Rolls back to earlier dialogue.")

    hbox:
        label _("Page Down")
        text _("Rolls forward to later dialogue.")

    hbox:
        label "H"
        text _("Hides the user interface.")

    hbox:
        label "S"
        text _("Takes a screenshot.")

    hbox:
        label "V"
        text _("Toggles assistive {a=https://www.renpy.org/l/voicing}self-voicing{/a}.")


screen mouse_help():

    hbox:
        label _("Left Click")
        text _("Advances dialogue and activates the interface.")

    hbox:
        label _("Middle Click")
        text _("Hides the user interface.")

    hbox:
        label _("Right Click")
        text _("Accesses the game menu.")

    hbox:
        label _("Mouse Wheel Up\nClick Rollback Side")
        text _("Rolls back to earlier dialogue.")

    hbox:
        label _("Mouse Wheel Down")
        text _("Rolls forward to later dialogue.")


screen gamepad_help():

    hbox:
        label _("Right Trigger\nA/Bottom Button")
        text _("Advances dialogue and activates the interface.")

    hbox:
        label _("Left Trigger\nLeft Shoulder")
        text _("Rolls back to earlier dialogue.")

    hbox:
        label _("Right Shoulder")
        text _("Rolls forward to later dialogue.")

    hbox:
        label _("D-Pad, Sticks")
        text _("Navigate the interface.")

    hbox:
        label _("Start, Guide")
        text _("Accesses the game menu.")

    hbox:
        label _("Y/Top Button")
        text _("Hides the user interface.")

    textbutton _("Calibrate") action GamepadCalibrate()


style help_button is gui_button
style help_button_text is gui_button_text
style help_label is gui_label
style help_label_text is gui_label_text
style help_text is gui_text

style help_button:
    properties gui.button_properties("help_button")
    xmargin 8

style help_button_text:
    properties gui.button_text_properties("help_button")

style help_label:
    xsize 250
    right_padding 20

style help_label_text:
    size gui.text_size
    xalign 1.0
    text_align 1.0



################################################################################
## Additional screens
################################################################################


## Confirm screen ##############################################################
##
## The confirm screen is called when Ren'Py wants to ask the player a yes or no
## question.
##
## http://www.renpy.org/doc/html/screen_special.html#confirm

screen confirm(message, yes_action, no_action):

    ## Ensure other screens do not get input while this screen is displayed.
    modal True

    zorder 200

    style_prefix "confirm"

    add "gui/overlay/confirm.png"

    frame:

        vbox:
            xalign .5
            yalign .5
            spacing 30

            label _(message):
                style "confirm_prompt"
                xalign 0.5

            hbox:
                xalign 0.5
                spacing 100

                textbutton _("Yes") action yes_action
                textbutton _("No") action no_action

    ## Right-click and escape answer "no".
    key "game_menu" action no_action


style confirm_frame is gui_frame
style confirm_prompt is gui_prompt
style confirm_prompt_text is gui_prompt_text
style confirm_button is gui_medium_button
style confirm_button_text is gui_medium_button_text

style confirm_frame:
    background Frame([ "gui/confirm_frame.png", "gui/frame.png"], gui.confirm_frame_borders, tile=gui.frame_tile)
    padding gui.confirm_frame_borders.padding
    xalign .5
    yalign .5

style confirm_prompt_text:
    text_align 0.5
    layout "subtitle"

style confirm_button:
    properties gui.button_properties("confirm_button")

style confirm_button_text:
    properties gui.button_text_properties("confirm_button")


## Skip indicator screen #######################################################
##
## The skip_indicator screen is displayed to indicate that skipping is in
## progress.
##
## https://www.renpy.org/doc/html/screen_special.html#skip-indicator

screen skip_indicator():

    zorder 100
    style_prefix "skip"

    frame:

        hbox:
            spacing 6

            text _("Skipping")

            text "▸" at delayed_blink(0.0, 1.0) style "skip_triangle"
            text "▸" at delayed_blink(0.2, 1.0) style "skip_triangle"
            text "▸" at delayed_blink(0.4, 1.0) style "skip_triangle"


## This transform is used to blink the arrows one after another.
transform delayed_blink(delay, cycle):
    alpha .5

    pause delay

    block:
        linear .2 alpha 1.0
        pause .2
        linear .2 alpha 0.5
        pause (cycle - .4)
        repeat


style skip_frame is empty
style skip_text is gui_text
style skip_triangle is skip_text

style skip_frame:
    ypos gui.skip_ypos
    background Frame("gui/skip.png", gui.skip_frame_borders, tile=gui.frame_tile)
    padding gui.skip_frame_borders.padding

style skip_text:
    size gui.notify_text_size

style skip_triangle:
    ## We have to use a font that has the BLACK RIGHT-POINTING SMALL TRIANGLE
    ## glyph in it.
    font "DejaVuSans.ttf"


## Notify screen ###############################################################
##
## The notify screen is used to show the player a message. (For example, when
## the game is quicksaved or a screenshot has been taken.)
##
## https://www.renpy.org/doc/html/screen_special.html#notify-screen

screen notify(message):

    zorder 100
    style_prefix "notify"

    frame at notify_appear:
        text message

    timer 3.25 action Hide('notify')


transform notify_appear:
    on show:
        alpha 0
        linear .25 alpha 1.0
    on hide:
        linear .5 alpha 0.0


style notify_frame is empty
style notify_text is gui_text

style notify_frame:
    ypos gui.notify_ypos

    background Frame("gui/notify.png", gui.notify_frame_borders, tile=gui.frame_tile)
    padding gui.notify_frame_borders.padding

style notify_text:
    properties gui.text_properties("notify")


## NVL screen ##################################################################
##
## This screen is used for NVL-mode dialogue and menus.
##
## http://www.renpy.org/doc/html/screen_special.html#nvl


screen nvl(dialogue, items=None):

    window:
        style "nvl_window"

        has vbox:
            spacing gui.nvl_spacing

        ## Displays dialogue in either a vpgrid or the vbox.
        if gui.nvl_height:

            vpgrid:
                cols 1
                yinitial 1.0

                use nvl_dialogue(dialogue)

        else:

            use nvl_dialogue(dialogue)

        ## Displays the menu, if given. The menu may be displayed incorrectly if
        ## config.narrator_menu is set to True, as it is above.
        for i in items:

            textbutton i.caption:
                action i.action
                style "nvl_button"

    add SideImage() xalign 0.0 yalign 1.0


screen nvl_dialogue(dialogue):

    for d in dialogue:

        window:
            id d.window_id

            fixed:
                yfit gui.nvl_height is None

                if d.who is not None:

                    text d.who:
                        id d.who_id

                text d.what:
                    id d.what_id


## This controls the maximum number of NVL-mode entries that can be displayed at
## once.
define config.nvl_list_length = 6

style nvl_window is default
style nvl_entry is default

style nvl_label is say_label
style nvl_dialogue is say_dialogue

style nvl_button is button
style nvl_button_text is button_text

style nvl_window:
    xfill True
    yfill True

    background "gui/nvl.png"
    padding gui.nvl_borders.padding

style nvl_entry:
    xfill True
    ysize gui.nvl_height

style nvl_label:
    xpos gui.nvl_name_xpos
    xanchor gui.nvl_name_xalign
    ypos gui.nvl_name_ypos
    yanchor 0.0
    xsize gui.nvl_name_width
    min_width gui.nvl_name_width
    text_align gui.nvl_name_xalign

style nvl_dialogue:
    xpos gui.nvl_text_xpos
    xanchor gui.nvl_text_xalign
    ypos gui.nvl_text_ypos
    xsize gui.nvl_text_width
    min_width gui.nvl_text_width
    text_align gui.nvl_text_xalign
    layout ("subtitle" if gui.nvl_text_xalign else "tex")

style nvl_thought:
    xpos gui.nvl_thought_xpos
    xanchor gui.nvl_thought_xalign
    ypos gui.nvl_thought_ypos
    xsize gui.nvl_thought_width
    min_width gui.nvl_thought_width
    text_align gui.nvl_thought_xalign
    layout ("subtitle" if gui.nvl_text_xalign else "tex")

style nvl_button:
    properties gui.button_properties("nvl_button")
    xpos gui.nvl_button_xpos
    xanchor gui.nvl_button_xalign

style nvl_button_text:
    properties gui.button_text_properties("nvl_button")



################################################################################
## Mobile Variants
################################################################################

style pref_vbox:
    variant "medium"
    xsize 450

## Since a mouse may not be present, we replace the quick menu with a version
## that uses fewer and bigger buttons that are easier to touch.
screen quick_menu():
    variant "touch"

    zorder 100

    hbox:
        style_prefix "quick"

        xalign 0.5
        yalign 1.0

        textbutton _("Back") action Rollback()
        textbutton _("Skip") action Skip() alternate Skip(fast=True, confirm=True)
        textbutton _("Auto") action Preference("auto-forward", "toggle")
        textbutton _("Menu") action ShowMenu()


style window:
    variant "small"
    background "gui/phone/textbox.png"

style nvl_window:
    variant "small"
    background "gui/phone/nvl.png"

style main_menu_frame:
    variant "small"
    background "gui/phone/overlay/main_menu.png"

style game_menu_outer_frame:
    variant "small"
    background "gui/phone/overlay/game_menu.png"

style game_menu_navigation_frame:
    variant "small"
    xsize 340

style game_menu_content_frame:
    variant "small"
    top_margin 0

style pref_vbox:
    variant "small"
    xsize 400

style slider_pref_vbox:
    variant "small"
    xsize None

style slider_pref_slider:
    variant "small"
    xsize 600

USER TESTING & ADJUSTMENTS

During user testing, people seemed pretty satisfied with the way the project was running. I was surprised to find that people liked the texture of the rice paper that came through when photographing the illustrations with my phone’s camera. I’d actually planned on scanning the illustrations at first, but captured a couple of them with my phone so that I could add them to my script code more quickly for user testing. After the user feedback, I decided to continue taking pictures of the illustrations with my phone. As mentioned before, I’d then edit them on BeFunky.

Another piece of feedback I was given was to adjust the text colors on the About, History and Preference menus in the game, because the text was showing up white, which was hard to read. Strangely enough, this took me a long time to figure out how to fix. Frustratingly, as these things go, the solution was a simple hex color change in the GUI code file.

Besides this, it was also brought to my attention that the confirmation boxes needed editing; for example, when going to the main menu, the game asks for confirmation about whether you really want to go there with yes or no options to answer with. Except there were no questions – just yes or no options. It turned out the problem was the white text as mentioned above – the text was there, it was just unreadable.

During user testing, Professor Anna Greenspan questioned whether the choices were coming in too late. I explained that in visual novels, there aren’t too many choices, nor they do they come too often, especially considering my project was only a prologue, for reasons I explained near the beginning of this post. Too many branches and choices affect the narrative. The classmates who were user testing at the time, Michael Chang and Shirley Huang, who both seemed to have some experience with visual novels as well, agreed that the pacing seemed fine. The first few choices don’t branch the story; they’re there to get the reader into the habit of making choices. Then there is a choice near the end of the story that splits it into three paths. Professor Greenspan questioned whether it was clear that the story takes different directions, and I think that if somebody actually goes through the whole story and repeats it with the paths I’ve set out properly, instead of simply skimming it, then it will be very clear that they are different.

During my capstone presentation, Professor Marianne Petite pointed out to me that the font detracted from the overall look of the project. I’d initially chosen the font Garamond because I liked the look of it with the rest of the work, but of course I took the feedback into account and considered it would be a good idea to change it. I then searched for and found an appropriate brush-style font called A Quiet Sleep on DaFont and replaced Garamond with that in my code.


PDF & PAPER & POWERPOINT

Here’s the PDF version of my project, with some new edits (click download anyway):
https://drive.google.com/file/d/0B11OZTl6J7J9aWRuNFNaaExtOFE/view?usp=sharing

Here’s my capstone research paper:
https://drive.google.com/file/d/0B11OZTl6J7J9VjFqMWthTmViQjA/view?usp=sharing

Here’s the PowerPoint of my capstone presentation:
https://docs.google.com/presentation/d/1Vd6URxhxDSxlRUzBAQCk1NIL9y0JzoUHfQW9RsdPOl4/edit?usp=sharing


ACKNOWLEDGMENTS

Ren’Py visual novel engine with its new project template and documentation.

Lemma Soft Forums for helping me find answers to issues I ran into or help I wanted to find.

Professor Layton and the Curious Village soundtrack Puzzles, composed by Tomohito Nishiura.

Thank you to Professor Barbara Edelstein for supplying me with rice paper!

Thanks to the IMA faculty that helped and gave me guidance while doing this project.

Leave a Reply

Your email address will not be published. Required fields are marked *