Today I would like to share some info about a topic that's rather close to my heart: Visual novel accessibility! I want to try and provide an overview on the subject and give some useful pointers for devs who want to make their games playable for a larger audience.
These following points are in no particular order (so they're not prioritized or anything) and you'll find that even if you are a solo-dev like me, you can include most of them on a zero budget – They only take time to implement!
Readability, text size and fonts
The main thing players do in a visual novel is read. This means that dialogue and narration text should be easy on the eyes and offer enough light-dark contrast to be pleasant to read. The way I see it, your text box is the most important piece of UI in a visual novel, since it's what players will be looking at most. This isn't the place to get overly elaborate with patterns or flashy fonts – Try to find a solution that matches your game's vibe while being functional and practical.
Renpy comes with a neat accessibility menu built-in, which you can open up by pressing A in the game, and it can be used to bump up text size or change the font, but I recommend picking a well-readable solution right out of the box. If you want to go beyond that, you can also add font, size and text spacing options to your game's Option menu, in fact a template for this can be found right here!
Colour blindness and UI design
I was surprised to read how many people experience some kind of colour blindness – around 8% of the male population, with red-green colour blindness being the most common one. You can keep this in mind by checking your UI through a colourblindness filter. I'm personally very fond of Colour Oracle, since it's simple and lightweight and covers the three main types of colourblindness, along with a handy option to switch to grayscale so you can check your light-and-dark contrasts.
Another tip about UI design that I got from a fellow game dev was to include an extra visual cue to make it very clear when a toggle-able option (like a radio button or checkbox-style button) is selected. In the case of Invisible Seams, I included a little pin like this:
One of my favourite Renpy features is the support for self-voicing. It means that players can press V while they're in the game to toggle automatic system-voicing, the specific sound of which will depend on their operating system (or alternative, Shift-C to activate Clipboard Voicing, a function some unique screenreaders make use of). Building on this feature, most visual novels can be made accessible to blind and vision-impaired players! I heavily recommend these articles by The Blind Nerd, since she goes into lovely detail describing her experience with visual novels specifically and includes advice on how to improve them: Article 1, Article 2
Here's a run-down of how I applied these principles for Invisible Seams:
Adding alt text on UI
By default, the self-voicing feature will read out the text on a text button just fine. If you have a custom image button, or you want to make the purpose of a button extra clear for screenreader-users, you will have to manually supply alt text, which can look something like this:
textbutton _("Test") action [Play("sound", config.sample_sound)] alt "Play test sound"
Ideally, someone should be able to navigate the interface without looking at the screen, using only their keyboard and the audio cues from the self-voicing.
Image descriptions on silent CGs
Sometimes you want to linger on a pretty cinematic illustration for a moment, or until the player has pressed a button and the story moves on. Someone who can't see the image is missing important context in this case. Using Renpy's “alt” character, we can add extra text that will only be read out when self-voicing is active. I recommend not just giving a plain description of the visuals, but making it feel interconnected with the rest of the narration, if possible. Focus on what is happening, and what emotional significance it can provide.
For example, when Jasper makes his first appearance in the game, I included this bit of alt description for him, which is logically part of Moth's POV narration:
alt "The young man's features are deceivingly juvenile, but his cold eyes are calculating and judgmental."
My hope was that this could give a more vibrant, organic impression of him, moreso than if I were to describe all his visual traits like his height, hair colour or clothing in great detail.
Optimizing dialogue for screen-readers
Sometimes I like to include fancy little flourishes in my dialogue, like “Gh- Uuuh, stuttering”, words that are “a liiiittle drawn out to indicate tempooo or hesitation”, or a little tilde to indicate that a line is said playfully or gently~
These details can trip up the self-voicing though, so I always do at least one pass in which I listen to the script with self-voicing on, mark the lines that can't be read smoothly and provide alternative lines in the code. It looks something like this:
jasper "Hey, I didn't say any of this to be nice!"
jasper "Wuh- Hey, I didn't say any of this to be nice!"
You may also want to do this for lines that are just ellipses, for extra convenience:
"I pause and stare at him, my mouth agape."
Screenshake and flashing lights
Some people experience motion sickness when a game makes use of screenshake or rumble, especially when it is frequent or used in longer sequences. Creating an option to toggle screenshake is deceivingly easy, I recommend TheoMinutes code for this, which is included and well-commented as part of his excellent Renpy accessibility add-on!
If your game includes transitions with flashing lights, such as flashbulbs, lightning or Ace Attorney-esque screen flashes, I heavily recommend including an option to disable these too, so that players with photosensitive epilepsy can play your game safely.
A note on mini games
If you're including minigames to spice up your gameplay, such as sequences with drag-and-drop components or arcade-style games, consider if these are absolutely mandatory for the full story experience or if you want to include an option to skip them, or offer some alternative, for players who can't get through them or simply don't like them. I'm personally much more likely to enjoy arcade-style minigames if they are an optional bonus, not when they are a mandatory challenge to overcome in order to proceed.
If your game was originally written in English, offering translations is one way to reach a larger playerbase! I assume that the most effective choices would be to offer Spanish, French, Chinese or Russian translations. Now, I didn't do this for Invisible Seams, because I don't have the budget to pay translators for their hard work, but I did offer a German translation, since it's my first language and I felt like giving it a go. It was honestly a really fun and interesting experience, and I talked a little more about the process in this Tumblr post!
Especially when it's not very obvious from the game's genre and overall marketing, it's good to let your players know what's coming by including notes in the description of the game on Itch (or whichever platform you use). Common things to include content warnings for are blood/gore, sexual content, drug use and jump scares. How sensitive you want to get with these is up to you – I personally also like to include whether a game is safe to stream on Twitch, in case a Let's Player wants to give it a go.
Most of your players will be on Windows, but for Renpy at least, it's fairly easy to include Linux and (unnotarized) Mac builds as well. Also, let's talk about Android – hoo boy! I was surprised to find that almost 30% of the downloads for Lovewood were for Android.
You'll most likely have to tweak your game's interface for small touch screens to make it easily playable on mobile devices, but if it's not too much effort, there are most likely a lot of players out there who would like to play your game on their phone or tablet.
Engine choices – Performance requirements
Okay, this is where my dramatic backstory comes in – For most of my life, I've been playing games on ancient garbage PCs. I'm talking graphic cards that stopped getting driver support 12 years ago. As a result, I couldn't play a lot of games until I upgraded to a more performant machine, and I reckoned that some folks out there may be in the same boat as me.
Your choice of engine, and even the version of the engine, can determine how smoothly your game runs on certain hardware. When Renpy had its big update from 7.3 to 7.4, it added a lot of cool features, but since it meant switching to a model-based renderer, it also required slightly beefier hardware, and games made with 7.4 simply wouldn't run on my old PC. This is why I've stuck with Renpy 7.3 for all the builds of Lovewood and Invisible Seams except for the Android builds – It means I have to do without certain features and need to invest a bit of extra effort, but my hope is that it makes my games a bit more playable for peeps who have an old computer and are simply looking for a nice pretty VN game to play (because anything more graphically elaborate than Sims 2 would set their PC on fire).
Optimizing for disc space
Nowadays disc space is pretty cheap and easily available, thank goodness, but I still find it resourceful to optimize your games a little. It reduces download times for players with a slow internet connection or may save them a bit of space on their phone if they're playing on mobile. Some simple steps I took to significantly reduce the required disc space for my VNs:
For audio files, stick with OGGs instead of WAV or MP3 files.
Optimize image files, for example by running PNGs through a program like PNGoo.
When you compile the final builds of your Renpy game, make sure that your work PSD files aren't included.
I'm sure that there are many more points that could be added to this list. If there's something you'd like to add on, feel absolutely free to do so in the comments! For now, I hope I could give some helpful input on the subject.
Thank you so much for reading, and take care out there!
This is an awesome article, thanks a lot for writing it! Especially performance requirements are something that I feel like people seem to dismiss sometimes. Like 32 bit not being supported in RenPy 8 anymore ;_;
There's by the way an interesting dilemma of optimizing disc space vs. performance requirements in Titanfall that might interest you. Since uncompressed audio labors the CPU less, they decided to go for uncompressed audio to make it playable on weaker hardware. On the other hand that meant that instead of 3-6 GB, the audio ended up taking up 35 GB, which was bad for people with small hard drives.
One note regarding audio that I'd like to add is that using opus instead of ogg decreases the audio file size by even more. The trade-off is that opus labors the CPU slightly more than ogg. The CPU labor increase is usually irrelevant for most VNs made in RenPy, though, unless the game already has features that labor the CPU a lot.
Yes, that's a great point! A bit sad to hear that Renpy 8 is fully 64-bit now T_T
It's super fascinating when concerns of accessibility lead to tradeoffs like in the case of the uncompressed audio. I guess if I had made the game, I would have tried to offer two versions so that players can make an informed choice on which will suit their hardware best? But I'm sure they considered that and there were other technical obstacles in the way. It may explain why a lot of high-fidelity modern games are so huge, now that I think about it.
Oooooh this is really good! Thank you for sharing :D I believe I didn't use these in my code because they were added in Renpy 7.4, and my games still use Renpy 7.3. That means it's a great new feature that devs can make use of!