Recently I’ve revived TerrorText, a teletext based horror game I was working on in ren’py last year. I’ve ported it to Unreal so I can be a little more flexible with events.

The idea is that there’s a cursed section on the teletext, accessible only by going to page 666 at the right time. When I was a kid I thought there was something weirdly fascinating and mysterious about teletext, it seemed adult and unknown (because I couldn’t read particularly well I suppose), and I want to draw on this feeling to create a horror game.

The Shader

I started out with the look of the thing, because I generally find that motivating and it draws on my existing skillset.

I didn’t want to have to make every page individually, nor did I want to use an actual telextext character editor. I need to dynamically alter the UI and cutting things into modular pieces makes far more sense for that.

As such, I made a UI shader that pixelates a 2D image it takes in and rounds each color channel to 0 or 255 to create the limited color palette. This actually gives me one additional color than teletext had, but its an elegant solution and I’m more about the spirit of the thing than accuracy here.

The graph – simple stuff for such a cool effect!

I laid out a couple of quick rules that seem to get the best result: 75 shader resolution, 1024 original resolution with 28px text.

The final look!

Importing Text Content

As there would be a lot of text content in the project – teletext pages do not write themselves – I wanted an easy way to import, edit and update it. I wanted to have my friends contribute some writing to this, and I didn’t want to have to grab the repo or do anything in engine.

As such, I wrote a quick python script that takes in a folder of text documents and constructs a csv out of their contents. This is then imported into unreal as a datatable, containing the text’s ID, content, title and other information relevant to the flow of the game.

import os
import csv

CSV_PATH = "C:\\Users\\amyst\\Documents\\Unreal Projects\\Prototypes 4.25\\Source\\Terrortext\\Writing\\content.csv"
CONTENT_PATH = "C:\\Users\\amyst\\Documents\\Unreal Projects\\Prototypes 4.25\\Source\\Terrortext\\Writing\\Content"

def get_files():
    return [f for f in os.listdir(CONTENT_PATH)]

def make_csv():
    content = get_files()
    with open(CSV_PATH, "w") as c:
        writer = csv.writer(c, delimiter=",")
        writer.writerow(["ID", "Title", "Text"])
        for file in content:
            file = os.path.join(CONTENT_PATH, file)
            with open(file, 'r') as f:
                lines = f.readlines()
                contentLines = lines.copy()
                del contentLines[0]
                del contentLines[0]
                for line in contentLines:
                    line = line.replace("[","")
                    line = line.replace("]", "")
                    line = line.replace("'", "")
                writer.writerow([lines[0], lines[1], contentLines[0]])

if __name__ == '__main__':

When I get new content, all I have to do is run this script, and its straight into the game.

With art and writing content sorted, it was time to actually make something interactive! I set up various UI widgets and a main gameplay blueprint, with the channel number being set in the UI then using an event dispatcher to talk to the main blueprint and update what is being displayed.

The datatable holding the text also has an associated field for graphics, so for now everything is set via the channel number matching a number in the datatable.

Oddly enough, the longest part of this setup was creating a function that checks the number of characters in the channel number string and adds dashes to it. This feels a little superfluous, but is quite important so the player knows which number they are inputting.

Event System

On top of the UI work, I made an event manager blueprint, also connected to the event dispatcher ran when the player has input a channel number. This stores and checks things like the number of unique pages visited and in which order pages have been visited. I plan to control the flow of the narrative using these. The ideal is that because we’re not running off a series of if statements, utilising more abstract tracking instead, each player will have a completely different path through the experience.


With the basics in place, I grabbed a house kit off of the epic store and moved my UI widgets into 3d widget components of the main gameplay blueprint. Having some art in is good for atmosphere and, beyond needing something for the remote, I’m happy enough with this to keep it as is.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s