“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 detail the process of taking peer feedback and using it to iterate my design for the development of my second prototype.
Iterating Prototypes Based on Feedback
Research Methodology
Campfire Tales was built on a foundation of iterative design, and therefore required a significant amount of player feedback to inform and validate design choices and the project’s effectiveness in completing research goals [need to rewrite]. This was done with several rounds of feedback during its development using a mixed-method approach to gather information from peers, friends and family, professionals, and through a small set of public tests before release.
Qualitative feedback was gathered from my peers in the form of interviews and recorded responses during our weekly development and degree show planning meetings over the summer. Once development reaches a playable stage, a google form was created that is linked to the completion of the game that allows testers to input feedback in the form of short answer survey questions and questions based on a Likert scale to determine their response to various features in the game.
Feedback and Iteration
The first round of peer feedback on my original prototype raised significant concerns about what it was that made “campfire tales” special. In its earliest form, the user interaction doesn’t extend beyond an individual page. And while I had managed to implement my own version of a model using JSON, my classmates were genuinely concerned that I wouldn’t be able to deliver a compelling experience with a series of disconnected paragraphs. They were, however, excited by the possibility of generating special effects with the results of these generated sections.
At this point I realized that I really needed to double down on the development of the actual story generation itself, and to determine how to make the experience itself enjoyable. I started by researching aspects of oral traditions in performance, interactive dramaturgies, design for procedural narratives, and reading hundreds of campfire stories to learn what makes them work. I came across a fundamental structure for building these narratives as a series of beats that connect nodes in a possibility space.
My writing process was to create a set of possible events on index cards, and to map out how a player could get from start to finish while still allowing for the entry of their own characters. I would write short paragraphs with blanks (for generative text additions like adjectives) and special notes for saved variables that the player will have or should have named, and planned to use these when designing Tracery “grammars” in future iterations of the game.
I then diagrammed the entirety of how I imagined the user experience would be, to make sure that I had a clearer idea of all of the various game states and features that I would need to implement during development.
Game Flow Diagram

Diagram of all the anticipated screens and sequences in the game
My original vision for the entirety of the game works like this: When a player first starts the game, they would see a title screen indicating them to click to start the game (as well as introducing clicking as a valid interaction). They would then see a secondary title screen with three buttons to start a new story, load a saved story, or reach an options menu.
If the player chose to go to the options menu they could find a set of instructions, load a saved world model that included things that had been added by other players, and see a list of game credits (that for now includes myself and the creator of the public domain stock background image that I am using for the game).
If the player chose to start a new story, they would be given a series of screens with no more text than you would see on a teleprompter on each (so they could easily be read by a performer). Each screen would either give the option to click to continue or to enter some text that could be added to the game world and reincorporated into the story. When the story ends, the player is then given the option to save the story to replay it later or to restart.
If the player chose to load a saved story, either created themselves or someone else playing the game, the experience is similar to that of a new story except that players would have the option to add new elements or keep them the way that they were. This would allow players to keep the same structure as a favorite story, such as a sequence of events that they really enjoyed, but change certain elements to create a slightly different version that changes with the telling. This is much like the ritual action and gradual change of stories that I found occurred during my research on storytelling in oral traditions.
With this vision in mind, I set out to develop my second functional prototype of the game.
Second Technical Prototype (saving variables into existing grammars)
As mentioned previously, Tracery uses a recursive function to expand a data structure called a grammar to generate text. Generally, this allows the programmer to loop through text and save an individual result from multiple possibilities to generate different outputs each time the function is run using the same grammar as a source. This is done by creating a series of rules within the grammar for Tracery to follow. For example, if we wanted to write a very short story with a small amount of variation, we could create something like this:
var grammar = { story: “#beginning# there was an #adj# #character#”, beginning: [“Once upon a time”, “It was a dark and stormy night, and”, “A long time ago, in a galaxy far, far away”], adj: [“green”, “yellow”, “gigantic”, “evil”], character: [“squirrel”, “scientist”, “unicorn”] }
Expanding this grammar with a starting point uses Tracery’s functions to select an item from each rule that it encounters with the ‘#’ character. In this case, by starting with the story rule, Tracery would select a beginning then an adjective and a character and output one possible combination of these elements. This might result in our story being “Once upon a time there was an evil squirrel.”
What if we wanted to save a selection from one of the rules and keep it for the remainder of the generation? We could change the “story” rule to look like this:
story: “#beginning# there was an #adj# [hero:#character#]. #newSentence#”
And then add a new rule that calls back our hero character in a new sentence, like this:
newSentence: “The #hero# was awesome”
One possible outcome of this new grammar might be “It was a dark and stormy night, and there was an gigantic unicorn. The unicorn was awesome.”
What this doesn’t do is save the variable between multiple calls to expand the grammar. Nor does it allow us to incorporate new values (such as text entry or defined values) into the structure for further use. This is where we can use a combination of javascript variables and Tracery’s pushRules function to address this problem. To make my second prototype, I created a very simple short story with very little variation to test this functionality. In it, a person (whose name is generated by Tracery) meets a new friend (defined by the player) and they go to a place (also defined by the player) and have fun!
To make this work, I would need to run Tracery’s algorithms each time there was something new added to the story. To save a permanent addition to the grammar (so that the generated name is consistent for the remainder of the program) I wrote the grammar to look like this:
var grammar = { names: [“Molly”, “Billy”, “Yosuke”, “Amanda”] } var story = tracery.createGrammar(grammar); var hero = story.flatten(#names#); story.pushRules(“hero”, [hero]);
This code takes a grammar structure with one rule composed of a series of names that when “flattened” selects one of the names in the list and saves it to the variable “hero.” That variable is then pushed as a new rule to the grammar called “hero” and containing only one possibility (the previously saved name), thus making sure that the value is consistent for all future expansions.
This same method can be used when saving player input from a text box to push new rules to the grammar that can be called later. And because we can define the name ourselves, we can write rules that anticipate these rules being pushed later, even if they don’t exist when the program is first run. For example, I could use the same rule from our previous example
newSentence: “The #hero# was awesome”
which would result in a sentence like “The Amanda was awesome” once the algorithm is run using the newSentence rule.
Where my earlier prototype had values added directly to the arrays in the grammar themselves, and were saved for future iterations. Players were essentially adding words to an ever increasing list of monster names, and with each new addition they were decreasing the possibility that any of these would be recalled in future stories. While it’s great to have variety, it made it more difficult for the player to feel like they were having a direct influence on the story itself. This newer structure felt much more dynamic, and served as the basis for the playable and final versions of the game.
Lastly, I added a title screen and option to save the story as an image from the flow diagram I had made previously to test the player experience from start to finish. Doing so made me realize that I didn’t necessarily need to give players the option to share the actual data of their grammars with each other, nor did I need most of the additional screens and options from my flow diagram to create a compelling experience. Most importantly, peer feedback indicated that the pictures were very effective (especially when printed).
Upcoming
Next week, I’ll be delving into the academic reasoning for the project, and discussing why we should be making more generative performance pieces that can enhance our ability to improvise effectively and expand our roles as storytellers.