Independent Game Creator and Installation Designer

Menu

Campfire Tales Development Diary – Part 1

“Campfire Tales” is my upcoming project that utilizes procedural generation, room-scale environmental effects, and performance elements to make a unique storytelling experience that can’t be found anywhere else. This week: I discuss the origins of the project and my research into tools for procedural text generation.

Campfire Tales

Introduction

When I was growing up, I learned the alphabet by playing a storytelling game with my dad we called the “Alphabet Game.” He would tell me a story at bedtime where he would periodically pause because the main character encountered a “blank,” where the blank would start with the next letter of the alphabet. This led to lots of stories with alligators or apples going on boating adventures with cobras. I adapted this storytelling game later in life with friends on camping trips, where you would go around in a circle and each time a new blank occurs, the next person would then become the storyteller. It’s the kind of experience that in either case is impossible without some kind of improvisation, and dialogue between audience and orator. Because it has been such a formative and integral part of my growth as a storyteller, my hope for “Campfire Tales” was to be able to replicate this experience for others, and to find out how I could enhance the experience using computational wizardry.

To make this hope a reality, I set out to develop three major components of the experience: a central program that utilizes procedurally generated content to tell stories with audience interaction, optional room-scale environmental effects driven by the central program to facilitate new types of generative expressions, and introducing performers to direct the player experience in a public performance. To reach as wide an audience as possible, I planned to release “Campfire Tales” on the web so that people could interact with, save, and share their own stories while being encouraged to act them out live with their friends in a similar way to the version being publicly exhibited. Through repeated play, we create our own digital oral traditions as players, performers, and storytellers.

Why Procedural Generation?

Because the player interaction that I want to provide generally consists of a single word during transitions between story beats, and that kind of input can be replicated in code by saving player text input as a variable, I need a way to tell stories that include the possibility for improvisation as a result of that user interaction in order for it to feel meaningful. The solution was to utilize Procedural Narrative Generation, defined as “any automatic process that creates a narrative over time, where that narrative is not determined before the process begins” by Chris Martens and Rogelio Cardona-Rivera in their essential 2017 Game Developers Conference talk on the subject [source]. To do so, I would need to find the right tool that would allow me to generate text that could exist as a part of a larger narrative, respond to user interaction in a meaningful way, allow me to use the content generated to drive a microcontroller or other external electronic hardware component.

Improv

Improv is a “model-backed generative text grammar tool for javascript” by Bruno Dias that “can generate random, procedurally generated text recursively.” It was used to create the details for the randomly generated elements (like descriptions for planets, characters, pathways, and events) in his 2017 game Voyageur. Improv works by creating javascript “grammar” objects from a possibility space with a deeply nested structure consisting of phrases and objects that can be tagged or filtered. A recursive function will read through this structure (which contains a set of terminal and non-terminal values) to return a generated text string that can used in the game.

What sets Improv apart from other solutions is the ability to create a model, or “object that holds data about the text,” through the reincorporation of tags that can be filtered to ensure more predictable or authored generation[source]. In his PROCJAM tutorial, Bruno provides an example that would allow developers to generate types of ships that are named specifically because they are either military or civilian [source].

Rant

From the Rant website: “Rant is a free, all-purpose procedural text generation language developed for .NET. It has been refined over several years of development to include a dizzying array of features designed to handle everything from the most rudimentary of string generation tasks to dynamic game dialogue generation, code templating, automatic formatting, poetry, and much more.”

At first glance, Rant appears to have quite a lot of the functionality for text generation that I’m looking for, as well as documentation specifically for writers in established projects. At the time of this writing, I had issues integrating Rant into the latest version of Unity, and the .NET platform doesn’t have the same kind of flexibility with external components that I’m looking for.

Tracery

From the Tracery website: “Tracery is a super-simple tool and language to generate text, by GalaxyKate. It’s been used by middle school students, humanities professors, indie game developers, professional bot makers, and lots of regular people, too. Give it a try today!”

Tracery, like Improv, uses a recursive function to generate text from an authored set of possibilities. While it lacks native support for data modeling and filtering, it is extremely well documented and has been used in a number of projects that served as an inspiration for this game. It has also been ported to other languages (such as ruby and python) and there is even an integration into Twine [source][source]!

RitaJS

From the RitaJS website: “Designed to support the creation of new works of computational literature, the RiTa† library provides tools for artists and writers working with natural language in programmable media. The library is designed to be simple while still enabling a range of powerful features, from grammar and Markov-based generation to text-mining, to feature-analysis (part-of-speech, phonemes, stresses, etc). All RiTa functions are heuristic and do not require training data, thus making the core library quite compact. RiTa can also be integrated with its own user-customisable lexicon, or with the WordNet database. RiTa is implemented in both Java and JavaScript, is free/libre and open-source, and runs in a number of popular programming environments including Android, Processing, Node, and p5.js.”

At first glance, RitaJS appears to have all the functionality that I need to get things up and running, with the added bonus of having feature analysis to allow me to parse and modify generated text based on english grammar structures. I used RitaJS during my research to create a basic MadLibs Generator that replaces specific particles of speech with words selected from its built in lexicon. Code for this Prototype can be found here [source].

Deciding on Which Platform(s) to Use

Ultimately, I settled on using Tracery as the library for grammar generation based on the simplified nature of its grammar structure. Whereas Improv has the ability to filter text so that I would be less likely to create impossible scenarios, the fact that objects within its grammar generation require tagging meant that it would be a nightmare for users to interact with the program. I didn’t want people to have to type more than one thing per interaction, and it would be especially disruptive to live performances if people had to wait while someone typed in “animal” and “extinct” every time that they wanted to enter the word “dinosaur.” Tracery was powerful enough for my purposes, and allowed me to use a JSON data structure to create and save modified grammars as people played.

I began working on Campfire Tales using Javascript, Tracery, Processing, RitaJS and NodeJS so that I could extend and update the project as needed during development with additional packages for functionality. This environment allows for deployment to the web to reach a greater potential audience than I likely could using Unity (which meant that Rant was unsuitable). Additionally, I could use Processing for visual effects and for serial communication to drive an external electronic component (like an Arduino for example) and RitaJS to parse text intelligently if I wanted to implement changes to already generated stories over time (like replacing key words with synonyms from the built-in lexicon to create a sense of evolutionary growth).

Upcoming

Next week, I’ll be detailing my process for developing early technical prototypes for the game and fire effects. Stay tuned!