Creating Worlds and Stories

Posted by Chris Rosser on Sun 13 April 2014
Hello! This site is archived and no longer maintained. For Chris' main site go to

Earlier I posted about my ideas and requirements to create a story manager within my world-building app. In this post I'm going to introduce the two first-draft scripts to first create the world and then create stories within that world.

But first I want to talk about my world template.

Template Directory

In my post, One Directory to Rule them All I outlined the directory structure I was planning to adopt. I've made a few refinements to this structure and created a skeleton version in my world directory titled _template. The directory tree with my refinements exploded is outlined below:

- _tools
+ characters
+ organisations
+ stories
+ articles
+ countries
+ religions

This template directory forms the backbone of the world-building project's structure. It gets duplicated as part of the create_world script and includes all the scripts and tools I've bundled with the world template.

The cool thing about this approach is that I can create multiple world templates if I choose: so for example I could have separate templates for:

  • Classic, single-world fantasy settings
  • Multi-world fantasy settings
  • Sci-fi settings
  • Historical fiction settings

There's no limit to what you could do; each template can have customised scripts, directory structures and starter documents to suit the way you want to work and the way you want to structure your setting.

The other benefit is that I've designed the workflow so that I only need to edit scripts in the master template because I've created a script refresh_tools that, when called from the world, will pull a fresh copy of everything in the _template/_tools directory.

Creating Worlds

create_world is a simple, top-level script that asks you some basic information about your world and then copies a customised version or your chosen template.

I've written the script in PHP because I'm planning to refactor all scripts into a console application built on Silex. However this script is so basic, it would be trivial to convert it to Python (for Mac OS X and Linux) or VBScript (to run from a Windows shell).

Let's look at the basics.

First the script asks you for the title of your world:

echo 'Enter the world title:' . PHP_EOL;
$title = trim(fread(STDIN, 200));
$title_slug = trim(strtolower(preg_replace('/[^a-zA-Z0-9-]+/', '-', $title)), '-');

The first line asks you to name your world. Then on the second line, what you type is passed to the variable, $title, which is trimmed of white space. Finally on the third line, we make a slug from the title, replacing spaces with hyphens and making the slug lower case. The title slug is what the new directory will be named.

Next the script asks you to specify the world template:

echo "Enter the world template. Leave blank for default" . PHP_EOL;
$template = trim(fread(STDIN, 200));

if ($template == "")
    $template = "_template";

} else {
    $template = trim(strtolower(preg_replace('/[^a-zA-Z0-9-]+/', '-', $template)), '-');


The first two lines use the same logic as in the previous code block and need for further description.

The next lines are a simple IF statement that changes the value of the $template variable depending on what choice you made initially. If it's blank (i.e. "") then the value becomes the name of the default template directory "_template" otherwise it takes the name of whatever you pass to it.

Next I use another IF statement to check if the template you nominated exists. If it doesn't exist, the script stops with a basic error message.

If all is good, I use a recursive copy function, copy_world_template(), to copy the template directory to a new directed named the world's title slug.

if (!is_dir($template))
    die(">>> Error, template location not found! Have you entered the name correctly?" . PHP_EOL);
} else
    copy_world_template($template, $title_slug);

    //fix permissions
    chmod($title_slug . "/_tools/create_story", 0774);
    chmod($title_slug . "/_tools/", 0774);
    chmod($title_slug . "/_tools/refresh_tools", 0774);

    echo "Your world has been created in: " . $title_slug . PHP_EOL;


Once the new directory is created, the script adds the correct file permissions to our tools to make them executable on a Unix-based system.

The script then informs us that all is well and the world has been created and names the new directory. The world directory can now be opened in your File Browser of choice or navigated from the command line.

With the basic world directory laid out, we can now create stories!

Creating Stories

create_story is a bit more complicated than create_world because we are adding more information about out stories and using that information to populate json and markdown documents.

At time of writing the script asks for:

  • The title of the story, and like the create_world tool it creates a title slug that will be the directory name
  • A one-sentence summary of the script, corresponding to Stage One of the Snowflake Method
  • The names of your story's protagonist and antagonist

This information is all requested, set and cleaned using the same logic as the world title and need no further description.

In the next day or so, I'll amend the script so that is also asks for the story's central thematic subject and a list of all major themes.

Next, the script takes this information and dumps it into two variables, one formatted as json and the other as markdown:

$summary_content_json =HEREDOC_OPEN_TAG
    "title" : "$title",
    "summary" : "$summary",
    "protagonist" : "$protagonist",
    "antagonist" : "$antagonist"

$summary_content_md = HEREDOC_OPEN_TAG

# $title #


## One-paragraph description ##

Enter your one one-paragraph summary here as defined by Snowflake Method Stage 2

## One-page synopsis ##
Enter your one one-page summary here as defined by Snowflake Method Stage 4


Note that the one-paragraph and one-page summaries should be completed after the file is created because completing these stages of Snowflake require a bit of quiet reflection.

Then the script uses an IF statement to test if the story already exists; if it does the process is aborted. If it isn't, the script generates a story directory.

Then we start take our story data and put it into our plan documents:

file_put_contents(__DIR__ . "/../stories/" . $title_slug . "/plan/summary.json", $summary_content_json);
file_put_contents(__DIR__ . "/../stories/" . $title_slug . "/plan/", $summary_content_md);

Then we encode our protagonist and antagonist into a json array and dump the content into our book's characters.json file:

$characters = array(
    $protagonist => array(
        "name" => "$protagonist",
        "type" => "protagonist",
        "alignment" => "protagonist",
        "biography" => "$protagonist_biography"

    $antagonist => array(
        "name" => "$antagonist",
        "type" => "antagonist",
        "alignment" => "antagonist",
        "biography" => "$antagonist_biography"

//put the characters
file_put_contents(__DIR__ . "/../stories/" . $title_slug . "/plan/characters.json" , json_encode($characters, JSON_PRETTY_PRINT));

Finally the script tells up that our story's been created.

Concluding Remarks

These scripts are still first draft so I'm not prepared to release them yet. There's more features I want to add for example: themes and the thematic subject. I also need to tie it into scenes.csv file and the world characters once I figure out what I'm going to record.

Wow you read this far! This site is archived and no longer maintained. For Chris' main site go to