blogs by Gio

Atom feed Recent posts

gaming 20 Absolutely True Things about Sonic ‘06

  • Posted in gaming

Sonic ‘06 is infamously bad. It’s glitchy, it’s a meme, et cetera. But actually, it turns out that it’s really bad. It’s a bad game. I played it. I played so much of it. I own the DLC. It’s honestly hard to describe. So here’s a description.

I’m trying not to include general shoddiness here, which there is a lot of. Also, I’m not numbering them. This isn’t Buzzfeed.

There is “Very Hard” mode DLC. You could pay money for it. This shipped after the game released and they knew about the issues. Sega’s reaction after shipping Sonic ‘06 was to try to charge people for more Sonic ‘06.

In addition to the hard mode DLC, there is DLC for an extra story called “TEAM ATTACK AMIGO”, where you play through a number of stages as side characters. Like End Of The World, you have to finish the whole gauntlet in one go with one pool of lives.

Apparently the game basically loads the whole overworld into memory any time the item layout changes or anything needs to be repositioned, even though really everything is in memory that should be there. This leads to hell situations like the box counting minigame. Oh god, the box counting minigame.

rp ja, es kawaii

  • Posted in rp

Sometimes steam will give you a coupon for a random game that isn’t very popular. And so this is how my evening went:

-33% off My Cute Fuhrer

📣 The Sarah Z Video Fallout

  • Posted in fandom

One of your questions was whether I thought Gio was a stalker. It’s my personal take that he probably does not technically qualify as one, but I also don’t think it’s a simple “no” either, given his antagonistic fixation toward people at WP, and his persistent invasiveness has made the women at WP uncomfortable.

Suffice to say for now, I don’t trust him, I will never speak to him, and probably no one from WP ever will either.

After the backer update came out, I took at look at Gio’s revisions to his article, and unsurprisingly, he just rearranged all the new facts so that he could draw all the same basic negative conclusions he’d already drawn.

I think this would be a bizarre conclusion to reach for anyone who was looking at that update objectively, and just indicates that the facts never really mattered because he had already made up his mind.

The only explanation is what everyone at WP suspected all along.
He’s a troll.

*record scratch*

*freeze frame*

You’re probably wondering how I got into this situation.

It all started on 4/13/2021. That’s right, I’m writing a story about me this time. It’s my blog, after all. First I wrote a history, then reported on a rumor, and now it’s time to tell a thriller.

⚖ YouTube broke links and other life lessons

This morning YouTube sent out an announcement that, in one month, they’re going to break all the links to all unlisted videos posted prior to 2017. This is a bad thing. There’s a whole lot bad here, actually.

Edit: Looks like Google is applying similar changes to Google Drive, too, meaning this doesn’t just apply to videos, but to any publicly shared file link using Google Drive. As of next month, every public Google Drive link will stop working unless the files are individually exempted from the new security updates, meaning any unmaintained public files will become permanently inaccessible. Everything in this article still applies, the situation is just much worse than I thought.

The Basics🔗

YouTube has three kinds of videos: Public, Unlisted, and Private. Public videos are the standard videos that show up in searches. Private videos are protected, and can only be seen by specific YouTube accounts you explicitly invite. Unlisted videos are simply unlisted: anyone with the link can view, but the video doesn’t turn up automatically in search results.

Unlisted videos are obviously great, for a lot of reasons. You can just upload videos to YouTube and share them with relevant communities — embed them on your pages, maybe — without worrying about all the baggage of YouTube as a Platform.

What Google is trying to do here is roll out improvements they made to the unlisted URL generation system to make it harder for bots and scrapers to index videos people meant to be semi-private. This is a good thing. The way they’re doing it breaks every link to the vast majority of unlisted videos, including shared links and webpage embeds. This is a tremendously bad thing. I am not the first to notice this.


Someone shared this story in a chat room I’m in and said “see, this is why YouTube needs a competitor, so they won’t just be able to do stuff like this.” I don’t think that’s quite right, actually.

YouTube doesn’t need a competitor so much as people need to unlearn the lies corporations have fed them about technology.

See, YouTube isn’t an all-purpose video hosting site. YouTube is a site for sharing videos socially and generating engagement to maximize ad revenue. It’s not a place for serious archival. So if you lose an important video because it was only uploaded to youtube, yes, youtube shouldn’t have made that change, but ultimately, the uploader also directly contributed to the problem.

If YouTube had more competition, they would be competing over who could drive the most engagement, not who could be the most responsible archivists. That is not their business. (I would argue it was Dropbox’s business, but what can you do but never do business with them again. Edit: oh, hey, it was also Google Drive’s explicit job to make public links work too!)

Please don't host your stuff on Discord🔗

The mistake of hosting important content exclusively on Youtube reminds me of another one of my pet peeves: hosting important content exclusively on Discord.

Discord is a web-based chat client. If you send someone an attachment on Discord, you can copy a link to that attachment. If you posted the attachment somewhere public, currently, that link will work for anyone. Some people see this and decide to abuse this mechanic to host important files on Discord. This is terrible.

Discord isn’t a durable hosting site. It isn’t meant to be a durable hosting site. It isn’t advertised as a durable hosting site. It happens to temporarily work as a filehost due to a quirk in the authentication api. Any file you put on discord can be a dead link in a matter of weeks.

Also — and I can’t believe this is actually a thing I have to bring up — discord doesn’t let you take backups.

If your disaster recovery plan includes “boy, I hope Jim selected the latest version of the documentation and copy-pasted it into a text document he saved somewhere, before a compromised discord bot wiped all our data” you don’t have a recovery plan.

You need a service where a clear part of the user/service arrangement is the ability to upload files you can reference directly with static links. You also need something without a greased-wheels moderation system. That means NOT Twitter, Discord, Dropbox (anymore), etc.

The only safe place to host images is a dedicated file host like pCloud. Discord makes no commitment to keep your images up and hotlinkable. This is something that costs money, which is why a lot of people don’t want to do it properly.

If you’re technically competent you can cut out some of the middleware and set up your own hosting box. Grab a cheap box off digitalocean or aws and spin up a general purpose webserver for file hosting. I have other recommendations on my recommendations page.

Final thoughts🔗

If you create digital content, and don’t want to lose it overnight:

  • Save local copies of things you care about. Hard copies. Not just on the cloud, not just on Discord, hard copies. On physical media you have physical access to. Buy a hard drive.
  • Use sharing sites like YouTube/Twitter/Imgur to distribute and promote your work, but have a fallback site somewhere more reliable. Fallbacks are going to be less flashy and do less promotional work for you, but they’ll keep your work from going up in smoke.

If you consume digital content, and are worried about losing access to unlisted videos:

  • Save local copies of things you care about. Hard copies. Not just on the cloud, not just on Discord, hard copies. On physical media you have physical access to. Buy a hard drive.
  • There is a one-page form your favourite creators can fill out to have all your unlisted videos exempted from the new changes. If you lose access to an unlisted video, it’s because the creator was irresponsible. Several times.

⚖ Twitter Blue is a late-stage symptom

Twitter Blue! $5/mo for Premium Twitter. It’s the latest thing that simply everyone.

News articles about twitter blue

I have an issue with it, but over a very fundamental point, and one Twitter shares with a lot of other platforms. So here’s why it’s bad that Twitter decided to put accessibility features behind a paywall, and it isn’t the obvious.

Client/Server architecture in 5 seconds🔗

All web services, Twitter included, aren’t just one big magic thing. You can model how web apps work as two broad categories: the client and the server. The client handles all your input and output: posts you make, posts you see, things you can do. The server handles most of the real logic: what information gets sent to the client, how posts are stored, who is allowed to log in as what accounts, etc.

📣 Trouble a-brewin’ at Redbubble

  • Posted in fandom

Homestuck is once again lit up over fan merch. Homestuck and fan merch have a long and troubled history, but this latest incident is between artists, Redbubble, and Viz media. Here are my thoughts on that!

In late May 2021, artists who sold Homestuck merch on Redbubble got this email:

Dear [name],

Thank you for submitting your fan art for Homestuck and/or Hiveswap as part of Redbubble’s Fan Art Partner Program.

At this time, our partnership with the rights holder VIZ Media has come to an end. When a partnership expires, we are required to remove officially approved artworks from the marketplace. This means that your Homestuck and/or Hiveswap designs will be removed from Redbubble soon.

Here are a couple of things to keep in mind:

  • It is important to know that licensors do not allow previously approved designs once sold on Redbubble to be sold on any other platform, even after the program ends.
  • Because this removal is not in response to a complaint, your account will not be negatively impacted.

Partnerships come and go, but don’t worry. We’re looking forward to partnering with more awesome brands in the future.

Check out our Current Brand Partnerships list to see all the properties that are actively accepting submissions. For additional information, we recommend checking out the Fan Art Partner Program FAQ.

Thank you, Redbubble

This hit a lot of people, and hit them hard:


Unfortunately for Twitter and brevity this is actually the intersection of a couple different complicated issues, which I’ll try to summarize here.

Redbubble forcing predatory licensing on people🔗

Now, copyright law sucks for fanartists, but that doesn’t explain what happened here.

⚙ Positioning things in Ren’py

  • Posted in dev

As is common in Python, the mechanical process of displaying something on screen in Ren’py is at once easy to execute and deceptively complicated to execute correctly.

The Ren’py documentation does a fine job of defining the specifications of position properties, but intuitively understanding how to use those properties can still be hard because it doesn’t include much in the way of examples or elaboration, so here are some of those.

Your basic properties🔗

These names come directly from atl transform on the documentation. Note that these are generally parallel with the style properties of the same names.

📣 W.D. Gaster and fake depth

  • Posted in fandom

or, “W.D. Gaster undercuts Undertale’s cohesiveness as a work”

When I wrote The Raphael Parable, I updated it with a little ARG. “The ARG Update”, I called it. There were scattered clues, and a puzzle, and secret notes so the diligent scavenger could piece together what really happened. Except nothing did really happen. There wasn’t a story I wanted to tell, there wasn’t an interesting mystery to solve, there were just clues tied to more clues tied to an arbitrary ending. It was the trappings of mystery without any of the meaning.

Petscop, on the other hand, has a substantial depth to it because it keeps tying itself to reality. The viewer is given a real person recording themselves playing a game. It’s set in our world. The game itself seems to be intricately tied to real-world events; too. Disappearances, the player’s family, even the YouTube account managing the videos. Petscop tells a deep mystery story because the mystery is backed by a story: a death, an abuse, a revenge. There’s meat to the mystery.

Sans (Undertale) is a fun character. He’s spooky. He breaks an unbreakable log, he teleports, he’s figured out something about the timelines. Then there’s a fight with Sans, where he’s very tough and has a gun. Then he needed a backstory for his gun and science, and we got Gaster, who is almost those things. Gaster was a fun idea, though, so he got some extra Easter eggs. We get room_gaster, the gaster followers, Mysteryman, the wrong number song, and the sound test. He’s fun, and mysterious, and ended up carrying most of the mysterious lore bits of Undertale that were never quite explained.

So, who is W.D. Gaster? Who is the big backstory, the Secret, the man behind the True Lab? Nothing. He’s the previous royal scientist, but through some unknowable horror he got deleted from reality. “Shattered across time and space”, according to another character who doesn’t seem to exist. He’s cut content who was conceived of as cut content. He’s a mystery by definition. The only story he gets is one of omission, the vague cosmic horror of not existing:

Have you ever thought about a world where everything is exactly the same… Except you don’t exist? Everything functions perfectly without you… Ha, ha… The thought terrifies me.

-still not Gaster, because he isn’t there

Of course, the story I’m describing here is emergent, not one he was crafted around. This is the narrative that arises out of Gaster’s mechanical function of… well, not being there.

Treating Gaster as a solvable mystery is an explicitly absurd quest in futility. He is unfixable. The answer is missing.

But Undertale isn’t about mysteries, not really. Undertale wants you to move on from Undertale. Undertale shames the genocide completionist and teases the pacifist stickler.

Don't you have something better to do?

Undertale doesn’t want you to sit down at a corkboard and “solve” it. W.D. Gaster refuses to be solved. His whole character is defined by being missing, by not being in the game or even in the universe at all.

And yet.

And yet Gaster demands solution. There’s just too much riding on it. With every ounce of weight Undertale gives to its plot, with every secret detail it includes about Gaster, it demands you care about him. He designed the SOUL machine that kickstarts the whole plot of the game. He gives Sans the knowledge he needs to nudge the timelines toward safety. He is all the loose ends and plot holes wrapped up into one character who isn’t available to be interrogated.

This isn’t like with the genocide route, where the player is shamed for starting a rampage for the sake of it. This is a mystery the game created, a mystery the story revolves around. The player is demanded to consider it, to solve it, to work towards solutions. But in the end they’re denied a solution. There’s a missing piece, and there always will be.

In a parallel to the way Asriel wants you to keep playing the game to the point of self-destruction, Undertale wants you to keep solving its story to that same end. It’s perverted, sure, but when it comes to Gaster it’s something Undertale deliberately hooks you into doing, not an expectation the player unfairly imposes on the work.

I’m forcefully reminded at this point about Folding Ideas’ excellent video The Stanley Parable, Dark Souls, and Intended Play, which makes this argument:

If there is crafted content on the other side of your misbehaviour, then it’s not actually misbehaviour.

If there is something that the game’s author simply flat-out, 100% did not want you to experience, did not want you to engage in, then it wouldn’t be there. Even when it comes to potential misbehavior using the rules of the system you’re placed within, externalities that they didn’t or couldn’t account for, like throwing garbage at NPCs, the only truly accurate sign that the authors don’t want you doing that is that nothing happens at all. This is because even a negative reaction, even the game pushing back against misbehaviour, is content.

The obvious example of subversively intended play is the genocide route — a joke he makes in the video — but I can’t help but think of the contrapositive alluded to in the quote above: if there is nothing, no content behind a path, then the game is making the strong, deliberate statement that it does not want you following that path. Gaster, a character defined by a lack of content, is then a whole degree of judgement further than the genocide route — maybe even the harshest a game can possibly discourage something. How viciously then must Undertale not want you to think about this?

But — for me, at least — this paradoxically creates a weird illusion of depth. The mystery being intricate, having scattered clues throughout the game, being tied to characters and mechanics I’ve learned to love through playing it… it all makes it feel important. Fun values and random events make the game feel “deeper”, like there’s a vast world you’re getting inconsistent glimpses into, and Gaster seems to be presented explicitly as a secret that takes digging to discover. Digging is explicitly encouraged with more content and tidbits and clues

And as you learn the puzzle is harder and harder to solve, as the clues become scattered so far throughout the game world and tied so deeply to the plot and characters, the “answer” feels more and more important. It’s an illusion. A trick. A sleight-of-hand. There’s no depth, no substance to it. Just signs and symbols of depth around an answer that isn’t. We know the answer isn’t deep or important because — by definition — there is not an answer at all.

I say it “undercuts Undertale’s cohesiveness as a work” because again, I think Undertale wants to be set down and for the player to be finished with it. But Gaster simultaneously hooks the dedicated player into an unfinishable puzzle.

The Gaster mystery is the kind of thing you have to seal away in a glass box, or else it doesn’t work. It’s a mystery you can’t treat as a mystery. It’s an ouroborus. Despite the act of eating and the concept of body length being things that demand concrete resolution, it’s not a resolvable thing. You can’t finish it, you can’t resolve it. You can only abstract it and understand it for what it is.

I love W.D. Gaster. The mystery of omission is incredibly tantalizing to me, on a deep level. I want to dive in, I want to solve this character. I want to look at the science, and find all the secret grey kids, and piece together every last crumb of the universe. I stayed up until midnight to get the survey program that turned out to be Deltarune, and I was disappointed when it did. I wanted more pieces of the puzzle, not more puzzle. W.D. Gaster is always the promise of more puzzle, but without the solution. The solution isn’t just missing, it’s impossible. The mystery itself is predicated on it not itself being solvable. I hate W.D. Gaster.

⚙ How we made Befriendus ludicrously accessible

  • Posted in dev

Befriendus; everybody’s favorite visual novel about making alien friends. It’s got trolls, yes, but it also has a slew of accessibility options. You can adjust everything: color, font, motion, even spelling. It’s clean, it’s easy, and it works. Here’s how we did it.

Befriendus in-game menu, with accessibility options

When I was designing the basic accessibility framework I had these principles in mind:

  • Accessible scripts must be easy to write; work should never be duplicated
    • Demanding people write multiple versions of work is bad design and encourages accessibility to eventually be dropped in favour of efficient production
  • Humans should never do postprocessing tasks
    • We’re writing software; a computer should do any and all mechanical work, not writers
  • Accessibility options should have as granular control as possible
    • Whenever possible, players should be able to select exactly what they need, not be forced to use something that doesn’t match their needs.
    • Options should be compatible with each other whenever possible
    • Just pushing out transcripts is not accessible design.

The best way to explain these is probably to explain what we ended up doing, and how each design choice was made carefully in accordance with those principles.


We knew from the moment we started putting together logic for character colours that we wanted an optional high-contrast mode. One of the first characters written was Mituna, whose light yellow text doesn’t show up super well against our grey textbox:

Mituna dialogue; yellow text with normal spelling

This is good enough for most cases, but we definitely need a way to turn colors off. Black-on-grey has much more contrast and pops nicely for the high-contrast folks:

Mituna dialogue; black text with normal spelling

This is handled by the Hemospectrum subsystem, a part of FSE.

Characters’ colours are defined with their characters are (mituna, name=Mituna, hemocolor=gold) and processed by the dialogue system when characters speak. Colours are defined semantically and handled correctly at the appropriate stage in the pipeline. (As opposed to some horrible hack, like binding a listener to the option and manually editing every character’s colour in storage every time it’s changed.)

Anytime a color (gold, orange, #f00, #a20000, whatever) needs to be resolved (in the dialogue box, mainly), it’s passed to the hemospectrum function, which resolves colour names and colour codes to universal colour codes.

The logic there is for name resolution, but we also use this entry point to handle contrast logic. Whenever this lookup is made we check if the high contrast user setting is enabled. If it is, we return either black or white, depending on the tone of the colour requested. Since all the colour logic was in one place already, it was easy to add extra logic here. This also gives us the tools to make contextual decisions further down the line — a very light color might pop better as light grey or white, for instance.

Typing Quirks🔗

Characters in the source material, Homestuck, have what are called “typing quirks”. Typing styles, basically. Characters type in different styles, ranging from semi-mundane style choices (lowercase, all caps) to incredibly elaborate (elaborate puns, ending every line with an emote, alphanumeric replacement). I could write a lot about how interesting these are and how they give characters a feeling of tone that the written word rarely conveys, but I’ll save that for another discussion. Brass tacks, we want our characters to do this, and that requires some work.

Now, to my eye, this looks like a build artifact. The “source code” is the script, and once the script is written there’s postprocessing replacement step that has to get done before we publish.

The alternative is for writers to write with quirks to begin with (WH1CH 1N 50M3 C4535 15 UNT3N4BL3) or to run a search-and-replace over the script every time they changed the script. From what I can tell, this is how Homestuck and pretty much every fanfic operate.

Fortunately for us, though, we’re running on a software engine! We can do better.

First, some groundwork. The main gameplay in Ren’py consists of dialogue in script files. Script text looks like this:

show !mituna at speaking

!mituna confused talk "she wouldnt leave without an ip adaptor that was the ONE thing i told her to bring"

!mituna idle frown talk "unless she was an idiot and just didnt. which i guess is unfortunately possible" (show_hashtags="#name of my autobiography: #\"unfortunately possible\"")

show !mituna idle

We don’t care about the stage directions here, let’s look at that dialogue:

On the first line of dialogue mituna is the character speaking, confused talk is his “pose” (the sprite displayed, if omitted it just uses the previous one), and the rest is the text that shows up in the dialogue box. When the story gets to this line, the character mituna says his line with a pose. (Remember that the character does the saying, this will come up later.)

The second line is pretty much the same thing, except you can see there’s some extra data called “show_hashtags” at the end. In Befriendus, the character dialogue boxes have an optional second line of text called hashtags, and this just tells the engine about that.

Here’s what that should look like:

Mituna dialogue; yellow text with normal spelling

But if you get Befriendus and play with all the default settings, here’s what you actually get:

Mituna dialogue; yellow text with quirky spelling

There’s some trickery going on here! Mituna’s text has its alphanumeric substitutions. Where did this happen?

Here’s the trick: all befriendus characters automatically modify their dialogue based on the currently set options. When the mituna character got the line, it changed the line to this:

"{quirk=mituna}unless she was an idiot and just didnt. which i guess is unfortunately possible{/quirk}"

That bit in brackets is a tag. Ren’py uses text tags as internal control commands for things like text speed or text style like boldness and italics, but it also lets you define your own tags to operate on the text. That’s what we’re doing here.

This notes that the quirk with the name mituna should be applied to the text if quirks are enabled, but it hasn’t actually done it yet. At the beginning of the route, when we first defined the mituna character in the first place, we added this line once:

init python:
    QuirkStore["mituna"] = [(c, "31073107"[i]) for i, c in enumerate("ELOTelot")]

The specifics of the right-hand side are the instructions for how to translate Mituna’s text and are black magic. What matters is we’ve told something called the QuirkStore how to apply the mituna quirk. Now every time text is rendered, as part of the engine’s default tag parsing (alongside bold, italics, links, etc…), the {quirk} tag checks whether quirks are enabled in options and applies them on-the-fly.

This lets us do some great stuff. We’re able to quirks anywhere we want (title screen tags, route titles, hashtags) without having to worry about extra cases: there’s no M*N problem since all the logic is handled in one place.

Keeping the semantic, pre-process copy of the text around has obvious benefits when it comes to translation or text-to-speech. Since the dialogue is stored correctly it’s easy for text-to-speech to read from the original text, rather than try to stumble through alphanumeric replacement or some other slurry.


I mentioned earlier that some quirks involve puns. While you could do this with regular expressions, (or write two copies of every script, yikes) we took a better approach and just piggybacked off the tags system again.

Here’s what Meenah’s dialogue looks like:

!meenah pissed "but HELLO we ended up getting busted {pun=halfwave}halfway{/pun} through and its only cuz of MY quick {pun=sinking}thinking{/pun} that we got here at all" (show_hashtags="#had to {pun=finprovise}improvise{/pun} like MAD")

!meenah snarky "{pun=betides}besides{/pun} i gave you my trolltag didnt i"

The {pun} tag is another Befriendus original. The text inside the tag is the original word, and the text after the = is the pun version. As with quirks, this lets the decision of what text to use be made at runtime, and globally. Tags hook into the global text system, so the pun and quirk systems are availible anc consistent anytime we display text.


I really can’t emphasize this enough: all the text features work together. You can toggle quirks independent of color, you can adjust puns independent of quirks, everything. Because everything is structured correctly, this is exceedingly easy to write for.


Unfortunately, “don’t duplicate work” has its limits, and animation is one of them. All our motion-intensive animations and flashing lights have to be written out twice; one full, one reduced. There’s a simple flag in the options menu that determines which one plays in the game.

While ATL has some support for conditionals, I haven’t found that to work consistently enough for our purposes, so we do have some icky logic mixed in with the script.

Here’s what Mituna’s flashing effect looks like:

You can see we tried to eliminate duplication as much as possible using subanimations here, and we even have a ConditionSwitch there at the end. But still, when we trigger the effect in-game, it looks like

if persistent.flash:
    show !psionicoverlay_flash #<- flash variant
    show !psionicoverlay_noflash
with dissolve
hide !mituna with easeouttop

Fortunately, there are only a few cases of this in the game.

Juicy Builtins🔗

Ren’py has plenty of built-in accessibility features that we make sure to expose to the player:

Renpy accessibility menu

As shown you can replace the fonts, adjust text size and spacing, and even turn on automatic text-to-speech.

This didn’t require any real work on our part, except for communicating to the player that this menu exists, which we do at the bottom of the options menu:

Befriendus in-game menu, with accessibility options

As mentioned previously, it was also important for voicing that we kept the original english script around instead of preprocessing the whole thing into quirks.


Ren’py also makes it easy for fans to make and distribute dialogue translations. All our hashtags, menu text, and dialogue use the translation system to make this as easy as possible. Things like pun and quirk tags also make it easier to translate non-words by exposing the intent behind them.


I can’t take any credit for this one either; Alien and Robin maintain incredibly detailed transcripts for all the routes and features on the game page using a web of google docs. I wrote a utility to pull transcripts from Friendsim, but we don’t use that because we have access to all the original scripts. This makes making transcripts for Befriendus is much easier than fan transcripts for, say, Pesterquest.

Alien and Robin actually maintain two distinct sets of transcripts. Alien makes traditional text transcripts of the routes (with colours and quirks) that are as close to gameplay as possible, while Robin makes transcripts that are as accessible as possible, with quirks and colours removed and with added text descriptions of effects, poses, and animations.

Unlike other accessibility features, these aren’t mix-and-match; any changes need to be manually propagated through all the transcripts. Transcripts, though, aren’t part of the prototyping cycle; they’re put together at the very end, sometimes even after the route releases.


We have a warnings page with individually spoiled content warnings for each route. There’s a large button for this on the main menu, so players who are interested won’t miss it. We also try to include appropriate content warnings without spoiling the route, which can be a tricky balance.

This isn’t a traditional accessibility feature, but it does make the game more accessible.

Well, that’s what we’ve done so far. There’s more game yet to go, though; if we add some other major accessibility feature I’ll try to remember to come back to add it here.

I don’t have any groundbreaking takeaways here that I didn’t give away in the first paragraphs. Design your engine in a way to prevent humans doing duplicate work; let the data do the lifting for you. If humans have to do everything twice, no they won’t. Give players control; let them tweak their experience precisely to their liking. If done well, it doesn’t have to be all-or-nothing. Accessibility is necessary, and it doesn’t have to be hard if it’s designed properly.