Yesterday I posted a proof of concept of a simple text-based adventure game built in Vue.js. While it was incredibly simple (and a bit broken, sorry), I made some progress in updating the engine today that I thought would be cool to share. Pretty much nothing visually changed, but I made some structural changes that I think will go a long way to improving the core game.

One of the first things I did was add support for command aliases. I already had this in terms of "w" being an alias for "west", but I wanted a generic structure for this I could update more easily. With that in mind, I added a simple aliases.json file:

	"look at|l at|l":"look"

Take a look at that last line. The use of pipe allows me to have multiple variations of an alias. I could have simply repeated them, but I liked this form. It felt more compact.

Next, I added a file called commands.json. It's only purpose was to serve as a definition of legal commands:

	"look *"

Again, the last line is important here. My game doesn't support "looking" yet, but I used the form look * as a way of supporting the ability to look at anything. Eventually my code will map "look X" to a result that says, "She wants to do command look with an arg X."

I then combined my three data files into one JSON file called data.json and simply fetched that on start. I did this via a utility script I'm going to show in a bit. Here is the new startup routine:

mounted() {
	console.log('Loading room data...');
	.then(res => res.json())
	.then(res => {
		this.aliases = this.prepareAliases(res.aliases);
		this.commands = res.commands;
		this.rooms = res.rooms; = this.rooms[this.initialRoom];
		this.loading = false;
		//nextTick required because line above changes the DOM
		this.$nextTick(() => {

The prepareAliases method simply handles taking those pipes and 'exploding' them out:

prepareAliases(s) {
	To make it easier for the author, I allow for X|Y, which I'll expand out at X:alias and Y:alias
	let aliases = {};
	for(let key in s) {
		if(key.indexOf('|') === -1) {
			aliases[key] = s[key];
		} else {
			let parts = key.split('|');
			parts.forEach(p => {
				aliases[p] = s[key];
	return aliases;

As the comment says, I want it to be easier for the author, or game developer. And that desire is what drove my final change. As I mentioned, I built a simple utility that would combine my JSON files into one. But I wanted to do something special for rooms. In the first version, rooms were defined in JSON. Here is an example:

	"description":"This is a rather boring room, but despite that, you feel the pull of a new adventure!",

While that isn't bad, the description field doesn't really work well for long descriptions. I can't use line breaks or quotes without escaping and what I really want is the ability to just write. So I came up with a new format:

You are in a rather simple room. Plain white walls surround you and nothing really
stands out of the ordinary. Despite that, you feel the pull of a new adventure and
steel yourself for what waits ahead!


I've got a simple description tag where I can put in anything I want. Exits are a line-delimited list of values where each line has a direction and destination. Finally, the name of the file is the "key" for the room. So this file would be

With that in place, I built this utility:

Simple Node script to read in a few JSON files (soon to be text too) 
and output a JSON output that can be saved into a file.
const fs = require('fs');

//let rooms = fs.readFileSync('./rooms.json', 'UTF-8');
let aliases = fs.readFileSync('./aliases.json', 'UTF-8');
let commands = fs.readFileSync('./commands.json', 'UTF-8');

let data = {};
//data.rooms = JSON.parse(rooms);
data.aliases = JSON.parse(aliases);
data.commands = JSON.parse(commands);
data.rooms = {};

now parse everything in rooms
let rooms = fs.readdirSync('./rooms');
let descRe = /<description>([\s\S]+)<\/description>/m;
let exitRe = /<exits>([\s\S]+)<\/exits>/m;

rooms.forEach(room => {
	let r = {};
	let roomContent = fs.readFileSync('./rooms/'+room,'UTF-8');
	let desc = roomContent.match(descRe);
	r.description = desc[1].trim();

	let exitStr = (roomContent.match(exitRe))[1].trim();
	let exitArr = exitStr.split(/\r\n/);

	r.exits = [];
	exitArr.forEach(e => {
		let [dir,loc] = e.split('|');
		r.exits.push({"dir":dir, "room":loc});

	let name = room.split('.')[0];
	data.rooms[name] = r;


And then ran: node util.js > data.json. And voila - done. You can view the code here ( and actually play it here (

Header photo by Jeremy Bishop on Unsplash