Enhancing Undum Hypertext Fiction with Vorple


Introduction to Vorple

Vorple is a user interface library for interactive literature. Its goal is to let online hypertext fiction and parser interactive fiction systems break out of their sandboxes and let story authors use the full scale of the vast possibilities of technologies that are commonly used in the World Wide Web.

An author might use Vorple just to theme their story with one of the provided custom themes, or make a multimedia spectacle with pictures, video, sound effects and interactive elements, or anything in between.

A web developer might ask if we really need Yet Another JavaScript Library. There are many general-purpose libraries, like jQuery which Vorple uses extensively, but there are none made specifically for this purpose. Libraries for "normal" web sites work usually by modifying the page elements directly, which is the best choice when you are building on top of an existing structure, but interactive fiction is different in that the content is continuously being pushed from an engine that runs the story.

The project's headquarters are at www.vorple-if.com where you'll find all the official material and downloads. JavaScript developers who want to dig into the innards of the system can find the source code at GitHub.

The library and all official material are open source and free for anyone to use for any purpose. (Mandatory footnote: Do still read all the licenses if you want to use it commercially or as a part of a closed system. Some third party themes, for example, are subject to slightly more restrictive licenses.)

Introduction to Undum

Undum is a JavaScript framework for creating works of hypertext and CYOA games. It is completely browser-based and provides beautiful visual design and smooth interaction out of the box. Undum is created and maintained by I D Millington.

Undum is programmed purely in JavaScript, the native language of all modern web browsers. The framework is very loose, providing only the basic functionality, which makes it easy to add more elements if so needed.

Here are some examples of stories authored with Undum:

As mentioned before, it's relatively easy to modify Undum's functionality and The Matter of the Monster, Leaks and Almost Goodbye all use this possibility to add more features to the stories. The official Undum tutorial uses only the basic features, as do Cavity of Time, The Play and Living Will.

As a contrast to "vanilla" Undum stories, Starborn is a story that uses Vorple to add multimedia features and e.g. an interactive map.

How to read this manual

This manual does not teach how to write hypertext fiction with Undum. At the moment the tutorial game at undum.com is the best way to learn the basics. From now on we'll assume that the reader knows at least how to create situations and actions and the difference between Situation and SimpleSituation.

Here's how the rest of this manual is structured:

The manual does not try to be a comprehensive reference. When looking for information about a certain feature, these are the primary learning resources:

Different coding practices

If you have followed the official Undum tutorial you'll notice that this manual uses slightly different conventions to structure the code.

The official tutorial builds the situations in a single block:

undum.game.situations = { 
    start: new undum.SimpleSituation( "..." ), 
    foo: new undum.SimpleSituation( "..." ),
    bar: new undum.SimpleSituation( "..." )

This manual, and the accompanying examples, create one situation at a time independent of each other.

    undum.game.situations.start = new undum.SimpleSituation( "..." );
    undum.game.situations.foo = new undum.SimpleSituation( "..." );
    undum.game.situations.bar = new undum.SimpleSituation( "..." );

There's a small caveat associated with the latter method: Undum allows hyphens in situation names. If a situation's name contains a hyphen, it must be created using again a slightly different syntax:

    undum.game.situations[ "end-scene" ] = new undum.SimpleSituation( "..." );

Both approaches are functionally equal. The reason why this manual takes a different approach is mainly because by creating the situations independently there's no need to include a complete story for each code snippet, and secondarily because it reduces the amount of required punctuation and therefore reduces the possibility of mistakes.

Another difference is that long lines of text are split to multiple lines by concatenating smaller strings instead of using backslashes at the end of lines. That is, the Undum tutorial does this:

"<p>Now we're almost at the end of the road. But so\
far you have moved through this tutorial linearly - from one\
situation to the next, without any choice. Undum is designed to\
support narratives that branch and merge.</p>"

...but we do this instead:

"<p>Now we're almost at the end of the road. But so "
+ "far you have moved through this tutorial linearly - from one "
+ "situation to the next, without any choice. Undum is designed to "
+ "support narratives that branch and merge.</p>"

Again there's no practical difference, but since Vorple functions must be concatenated with + characters it's simpler to use the same method with normal text as well.

Quick start for the impatient

People have different ways of learning new things. For those who learn best by getting their hands dirty from the start and not by reading a book from cover to cover, here's how to pick the important parts:

Getting started

Starting a new project

The download page at vorple-if.com has ready made packages for different themes. Choose a theme that pleases your eye the most, download the package and unpack.

Each theme package has at least these files and directories:

The media folder and its subfolders are meant for story-specific multimedia files.

You can verify that everything works ok by opening the index.html file with your browser. You should see an extremely minimal but functioning Undum story.

Go through the index.html file and replace the placeholder texts like story title and description. (You can also do this at any point later.)

vorple.game.en.js is an empty story file. If you want to call it something else, rename it to whatever you wish and change the filename in index.html so that it gets loaded properly.

Finally, open vorple.game.en.js and go through it, there are more instructions there on how to complete the story's basic setup.

As with vanilla Undum, if you don't have a local webserver installed on your computer it's best to use Firefox when developing the stories. Other browsers might disable features as a security measure when local web pages contain JavaScript.

Migrating an existing project

If you already have an existing Undum project where you want to use Vorple, download any theme package from the download page. You only need the library files so if you don't want to change your existing theme it doesn't matter which package you download. Unpack it and copy the library directory lib/ to the same directory where the story's HTML file is.

If you want to change the layout as well, skip the rest of this chapter and read Migrating to a new theme for further instructions.

Modify your existing main HTML file (usually storyname.en.html) and add Vorple's libraries and resources after the line that loads Undum. In the standard Undum template the line is almost at the end of the file.

<!-- Find this line... -->
<script type="text/javascript" src="media/js/undum.js"></script>

<!-- ...and add these lines below it: -->
<script type="text/javascript" src="lib/jquery.qtip.min.js"></script>
<script type="text/javascript" src="lib/soundmanager.min.js"></script>
<script type="text/javascript" src="lib/vorple.min.js"></script>

<!-- Make sure those lines come before the line that loads your story file,
        for example: -->
<script type="text/javascript"

If you plan for the story to feature sounds or music, see chapter Mute controls for instructions on how to add the controls to the layout.

Vorple is designed to be fully compatible with stories created for standard Undum. If you have a story that works with vanilla Undum but not with Vorple, please file a bug report.

Migrating to a new theme

If you want to start using one of the Vorple-provided themes, download the theme package, unpack it and copy your storyname.game.en.js story file to its main directory. The theme's index.html file becomes the new main HTML file.

You'll need to manually edit index.html to match the contents of your old HTML file (titles, descriptions, other custom content you've added). At the same time when you go through index.html, check if the theme requires other attention as well. Special instructions will be given as comments where necessary.

Before you can start using Vorple's features, you have to make the following changes to the story file:

Without these additions some of Vorple's features might not work correctly or at all. Refer to the vorple.game.en.js file for an example.

Developing with Vorple

Initializing the library

Always remember to initialize Vorple. Some features won't work or work incorrectly if the library isn't initialized.

Some of Vorple's features are initialized by calling vorple.core.init()API. undum.game.init() is a good place to do so. The Undum engine must be given as the first parameter to the initialization function. The engine is the undum.game.init()'s second parameter, system.

undum.game.init = function( character, system ) {
    // other Undum initialization
    // ...
    vorple.core.init( system );

Using the library functions

Vorple adds enhancements to Undum's basic functionality (with the core module) and extends its capabilities (with the Undum module). The setup and usage of these features are covered in the respective module chapters.

To help write the HTML contents of an Undum story, the HTML module has helper functions that create HTML tags. For example, here's the (abbreviated) starting situation from the Undum tutorial game:

start: new undum.SimpleSituation(
    "<h1>Starting Out with Undum</h1>\
    <img src='media/games/tutorial/woodcut1.png' class='float_right'>\
    <p>Welcome to the Undum tutorial. Undum is a tool for writing\
    hypertext interactive fiction. It has some unique features\
    and a visual design that encourages narrative games.</p>\
    <p class='transient'>For now, lets move on with the tutorial.\
    <a href='rooms'>Click this link</a> to move on.</p>"

Using Vorple's HTML helpers it would be written like this:

undum.situations.start = new undum.SimpleSituation(
    vorple.html.tag( "h1", "Starting Out with Undum" )
    + vorple.media.image( 'woodcut1.png', { classes: 'float_right' } )
    + vorple.html.p(
        "Welcome to the Undum tutorial. Undum is a tool for writing "
        + "hypertext interactive fiction. It has some unique features "
        + "and a visual design that encourages narrative games."
       ) + vorple.html.p(
        "For now, lets move on with the tutorial. "
        + vorple.html.link( "rooms", "Click this link" )
        + " to move on.", { classes: 'transient' } 
See the Different coding practices chapter for an explanation why the long lines are split differently in the above examples.

Using the helpers reduces the chance of typos and missing end tags and they make the code more structured and readable (although your mileage may vary).

Other functions that don't create story text but do something else like play sounds or create tooltips are called inside functions.

undum.situations.maze = new undum.SimpleSituation( function() {
    vorple.media.playMusic({ mp3: "background.mp3", oga: "background.ogg" });
    return vorple.html.p( "You are in a maze of twisty passages, all alike." );

The exact syntax is described in each feature's documentation in this manual and in the API.

Reading the API

Vorple's modules and functions are documented in detail in the API. The API is included in the zip package and a link to the online version is in the main menu of the Vorple project website.

Functions mentioned in this manual have a link appended to them that takes you to the corresponding place in the API: vorple.core.init()API

In the API you'll find a list of modules in the left hand side of the page. Clicking on a module's name opens a page that details the fields (variables) and methods (functions) included in the module.

Here's an example documentation of vorple.core.requireRelease()API:

An example from the API

The first line tells that this method:

The following paragraph describes the use and behavior of the method.

Next there's a description of accepted parameters. The accepted type or types are inside the square brackets. The parameter's name corresponds to the name shown in the first line and the text "optional" means that this parameter can be left out. If the parameter defaults to some value if it's left out, it's also shown here.

A screenshot from the API of a parameter with a default value

Finally there's the description of the return value (if any). There might also be links to other parts of the API or to external resources.

At the top of the page there's a link to the source code of the module. If reading the manual and the API still leaves you wondering what a function does or how it's used, you can always look at its source code and try to figure it out from there.

Remember that Vorple uses the jQuery library that has its own api. Other included libraries have their own documentation, but the API has links to them when necessary.

Of functions and strings

We need to go through some JavaScript theory for this one. Let's say we want to make a situation where we show "Hello world!" to the reader. There are three ways to do it:

// SimpleSituation with a string argument
new undum.SimpleSituation( "<p>Hello world!</p>" );

// SimpleSituation with a function argument
new undum.SimpleSituation( function() {
    return "<p>Hello world!</p>"; 

// Situation
new undum.Situation({
    enter: function( character, system, from ) {
        system.write( "<p>Hello world!</p>" );

The end result is always the same, words "Hello world!" displayed on the screen. The difference is that the first method uses a string argument which is evaluated on initialization and the two others use functions whose contents are evaluated when they are called.

What does this fancy tech jargon mean and why is it important? Let's look at a practical example where we want to play a sound effect when the reader enters a situation:

// This won't work:
new undum.SimpleSituation( 
    "<p>You hear a loud bang.</p>"
    + vorple.media.playSound({ mp3: "gunshot.mp3" })

// Do this instead:
new undum.SimpleSituation( function() {
    vorple.media.playSound({ mp3: "gunshot.mp3" });
    return "<p>You hear a loud bang.</p>";

What happens with the first (incorrect) method is that the string contents are evaluated when the story loads and therefore you hear the sound effect right away, not when the reader enters the situation. In the latter version the sound playing function call is inside a function that's called only when the situation is entered so the sound plays at the correct time.

Vorple's functions can be divided into two categories: active functions that do something the moment they're called, and passive functions that return a string of HTML code.

The following modules or functions are always passive and therefore safe to use in undum.SimpleSituation as a string argument:

For everything else it's safer to use them in functions only.




Cookies are small snippets of text web pages can save to the user's computer. Cookies can be used to identify a returning user or save data across sessions.

Cookies can be set using the vorple.cookie.write()API method and read with vorple.cookie.read()API. Cookies can be deleted using vorple.cookie.remove()API. A cookie has text content and a name that's used to identify the cookie.

vorple.cookie.write( 'greeting', 'Hello!' );  // sets a cookie called "greeting"
vorple.cookie.read( 'greeting' );             // returns "Hello!"
vorple.cookie.remove( 'greeting' );           // removes the cookie

The cookie's contents can be updated by overwriting it with vorple.cookie.write().

By default cookies are set to expire in one year. The expiration period can be set using an expires option while writing the cookie, as a number of days the cookie is valid or as a JavaScript Date object:

vorple.cookie.write( 'greeting', 'Hello!', { expires: 7 } );
There's no guarantee that the user's browser keeps the cookies for the full duration of the expiration period, or that the browser accepts them at all. You shouldn't rely on cookies alone for important features.

The specification says that a browser should accept at least 20 cookies per web site, each with maximum content length of 4096 bytes (characters). Most browsers allow much more than this, but it's safest to stay within these boundaries. Some browsers also limit the total length of all cookies per web site to 4096 bytes or some other value.



The core module has mainly helper functions for other modules and general settings and features.


vorple.core.settings contains two variables: vorple.core.settings.confirmWindowClose (default false) and vorple.core.settings.debug (default false).

vorple.core.settings.confirmWindowClose defines whether or not the browser should alert the reader that they're leaving the page when they close the browser window or try to navigate to another page. The purpose is to prevent the reader from accidentally leaving the page and inadvertently erasing their progress at the same time.

Firefox versions 4 and up disregard the custom message and always show the browser's default message in the confirmation dialog.

If the variable is set to true a default message will be used: "You are about to leave the story. Any unsaved progress will be lost. Are you sure you want to continue?" If the variable is a string, it will be used as the message: vorple.core.settings.confirmWindowClose = "Are you sure you want to leave the game?"

The variable vorple.core.settings.debug can be set to true while developing the story. The flag can be used to add code used for debugging so that they don't accidentally appear in the released version of the story: if( vorple.core.settings.debug ) { ... }

Setting the debug flag disables confirmWindowClose so that you don't have to dismiss the confirmation dialog every time you reload the page.

The setting variables can be set at the beginning of the story file so that they're immediately active.

Version numbers

vorple.core.version and vorple.core.release contain the Vorple library's version numbers. Release is incremented every time a new release is made, and version increments when the new release includes a major feature or a significant rewrite of existing features. The full version number is displayed as version.release, for example version 2 release 15 is denoted as 2.15.

A plugin or another library can require a certain release of the Vorple library by calling vorple.core.requireRelease()API. An error is thrown if the library is not recent enough. The release number will always increment between releases, even when the version number increments, so it's safe to check only the release number.

If the page layout contains an element with class vorple-version, the contents of the element are replaced by the Vorple's version number in the version.release format. The default Vorple themes have this in the page footer:

Powered by <a href="http://undum.com">Undum</a>
and    <a href="http://vorple-if.com">Vorple 
<span class="vorple-version"></span></a>.

In the page itself it will look like this:

Powered by Undum and Vorple 2.15.

Initialization event

vorple.core.init()API triggers a init.vorple event that can be used to add custom initialization methods:

$( document ).on( 'init.vorple', function() {
    // custom initialization here

This is mostly useful for plugins. Individual stories can just add any initialization they need to undum.game.init() which runs at the time Undum has been initialized.


In all HTML module functions that create HTML tags you can add tag attributes as the last parameter. The attributes are given as an object that has the attributes' names as keys and contents as values:

        id: "foo",
        classes: "bar",
        title: "baz"
// → <p id="foo" class="bar" title="baz">Test</p> 

Note how the class attribute must be named classes because "class" is a reserved word in JavaScript.


vorple.html.p()API wraps given contents inside <p> tags. The following are equal:

// the "pure" Undum method
new undum.SimpleSituation( "<p>Hello World!</p>" );

// with the HTML helper
new undum.SimpleSituation( vorple.html.p( "Hello World!" ) );

// with a custom class
vorple.html.p( "Hello World!", { classes: "transient" } );
// → <p class="transient">Hello World!</p>

Links can be added with vorple.html.link()API. The first parameter is the link target, the second parameter the contents, and the third the <a> tag options.

vorple.html.link( "./book", "Open the book", { classes: 'unique' } );
// → <a href="./book" class="unique">Open the book</a>

The parameters can be given as a single object that has keys for at least the url and the contents:

    url: "./book", 
    content: "Open the book", 
    options: { classes: 'unique' } 

If an array of multiple links is given as the first parameter, a choice popup is created. A choice popup is a list of choices that appears when the main link is clicked.

The popup is hidden when any of the choices are selected or if the reader clicks on outside the popup.

        url: "http://vorple-if.com",
        content: 'Vorple'
        url: "http://undum.com",
        content: 'Undum'
    'useful links'


vorple.html.quote()API can be used to wrap contents inside quotes. The reason you might want to use this helper instead of just writing the quotes is that this way you can't forget to add the closing quote and you don't have to escape the quotes as in the example below.

// vanilla Undum
new undum.SimpleSituation( "<p>\"Hello,\" she said.</p>" );

// HTML helper
new undum.SimpleSituation(
    vorple.html.p( vorple.html.quote( "Hello," ) + " she said." )

Double quotes (") are used by default but another character or characters can be given as the second parameter, or an array with two members where the first member is the opening quote and the second character the closing quote. If you assign a character to the vorple.html.defaults.quotemarks variable, it's used as a default from there on.

vorple.html.quote( "Hello", "'" );                         // → 'Hello'
vorple.html.quote( "Hello", [ "&laquo;", "&raquo;" ] );  // → «Hello»

(Character entity references were used to create the arrow quotes.)

Other tags

You can add any HTML tags using vorple.html.tag()API. The first parameter is the tag's name, the second is the contents inside the tag and the third parameter the options and attributes.

    "Hello World!",
        classes: "transient",
        title: "Greeting"
// → <div class="transient" title="greeting">Hello World!</div>  

The end tag is added automatically if text content is given, and the tag is self-closed if the content is not a string.

vorple.html.tag( "br" );       // → <br />
vorple.html.tag( "div", "" );  // → <div></div>
vorple.html.tag(               // → <hr class="wide" />
    { classes: "wide" }

If you want to make sure the end tag is always added, use endTag: "always" option:

    { endTag: "always" }
Instead of the generic vorple.html.tag() use



vorple.media.image()API creates an <img> tag. The first parameter is the picture's file name and the second optional parameter an object with tag attribute options.

vorple.media.image( 'pic.png', { classes: 'once', title: 'A nice picture' } );
// result: <img src="media/image/pic.png" class="once" title="A nice picture" />

Unless an absolute path to the file is given (/other/folder/pic.png or http://example.com/pic.png), a path specified by vorple.media.defaults.imagePath is used. The default is the media/image/ directory that comes pre-made in all theme packages. It can be changed by assigning a new path to the variable.

vorple.media.image( 'pic.png' );    // → media/image/pic.png

vorple.media.defaults.imagePath = '/resources/pics/';
vorple.media.image( 'pic.png' );    // → /resources/pics/pic.png

Preloading images

By default the web browser loads images included in the story only when they are first encountered. The reader might see the image appear on the page slightly after the text, or they might see the image slowly loading, depending on their Internet connection and the size of the image.

This can be countered by preloading the image files. vorple.media.preloadImage()API makes the browser load the images beforehand so that they can be displayed immediately when the story actually needs them. Multiple images can be given to the function as an array at the same time.

vorple.media.preloadImage([ 'image1.png', 'image2.jpg' ]);

undum.game.init() is a good place to preload the images. The default image path is assumed, just like with vorple.media.image().

The downside is that preloading consumes bandwith unnecessarily if the reader doesn't actually come to the point in the story where the image is needed. You might consider preloading images only at some point during the story, for example one situation before the one that shows the image or at the point when the reader enters a branch in the story that leads to the situation that has the image.

Sound effects

The sounds are played automatically with sound down if the reader has muted sounds. The same applies to music.

Audio and local video files are played using the SoundManager 2 library.

Sound effects can be played by using vorple.media.playSound()API. Mp3 files are probably the best supported, but OGG files should work as well.

vorple.media.playSound( "sound.mp3" );

Audio files are loaded from the project's media/audio directory unless other path is given, just like with images. The default path is stored in vorple.media.defaults.audioPath.

vorple.media.stopSounds()API stops all currently playing sounds. If you need to stop or pause a single sound, you have to manipulate the player object directly. vorple.media.playSound() returns the sound objects id. If you assign the return value to a variable, you can use vorple.media.stopSound()API to stop the sound, or us any SoundManager methods to manipulate the sound.

iOS devices (iPhone, iPad, iPod) support only one sound playing simultaneously. If you specifically target these devices, it's best to use either background music or sound effects, but not both. Otherwise any sound effect will stop the background music.


For music these functions can be used:

They work identically to vorple.media.playSound() and vorple.media.stopSounds(). There's also vorple.media.stopAll()API that will stop both sound effects and music.

The default directory for music files is media/music. It can be changed by assigning the new directory to vorple.media.defaults.musicPath.

Why not just play background music the same way you'd play sound effects? There are a couple of key differences:

Another difference is that music is set to loop automatically (the same track starts again right after it has ended). If looping is not desired it can be disabled with a loop: false option:

vorple.media.playMusic( "filename.mp3", { loop: false } );

Conversely the same option set to true can be passed to vorple.media.playSound() to make sound effects looping.

Volume, fading out and callbacks

The default volume for sound effects and music is 80, with 100 being the maximum. It can be changed with the volume option.

All functions that stop sounds, including the vorple.media.playMusic() when it stops the previous music, have an option to fade the sound out gradually instead of stopping it abruptly.

The fade out speed is given as a number between 1 and 100, where higher number means faster fade out. The volume is decreased every 50 milliseconds (0.05 seconds) and the number tells how much the volume is decreased each time until it reaches zero. With fade out speed 5 it takes 80 / 5 * 50 = 800 milliseconds (0.8 seconds) for a sound to fade out from the default volume.

Passing a fade out speed of 100 will stop the sound immediately without fading. vorple.media.stopSound() and vorple.media.stopSounds() have 100 as the default. vorple.media.stopAll(), vorple.media.stopMusic() and vorple.media.playMusic() have 5.

Functions that stop sounds also have an option to pass a callback function that's executed when the sound has actually stopped, i.e. when the fade out has completed.

Here's an example of stopping background music with slow fade out and showing a notification when the fade out is completed.

	function() { 
		vorple.notify.show( 'The music has stopped!' ); 

YouTube videos

YouTube videos can be embedded with vorple.embed.youtube()API. The function takes as the first parameter the id of the video to embed and as the second parameter the options.

heightinteger390Height of the video player
widthinteger640Width of the video player
parametersobjectsee belowYouTube embedding parameters

All available embedding parameters are listed in the YouTube API documentation. Default parameters are:

autoplay: '1',
controls: '0',
disablekb: '1', 
modestbranding: '1',
rel: '0' 

That is, start playing the video immediately, hide controls, disable keyboard controls, hide YouTube logos and don't show related videos at the end.

When the story is being reloaded from a save position, the video player is embedded but parameters.autoplay is set to 0 so that it won't start playing automatically.

An example of usage where we show a video in an Undum situation:

undum.game.situations.livingroom = new undum.SimpleSituation(
        "You find yourself in a living room where a film has just "
        + "started playing on the DVD player." 
    ) + vorple.html.p(
                width: '500',
                height: '280',
                parameters: {
                    controls: '1',     // allow the user to control the video 
                    loop: '1'        // start again from the beginning when playback ends

Mute controls

Themes included with Vorple already have the mute checkboxes in the HTML files, but by default they are not displayed. Remove the <!-- --> tags around the checkboxes to enable them.

If the story uses audio, it's polite to offer the reader a possibility to mute sounds. If you put the following piece of code into the story's HTML file, that is, checkboxes with class mute and value sound, music or all, Vorple will automatically make them function as you'd expect.

    <input type="checkbox" id="muteMusic" class="mute" value="music" /> 
    <label for="muteMusic">Mute music</label>
    <input type="checkbox" id="muteSound" class="mute" value="sound" /> 
    <label for="muteSound">Mute sound effects</label>
    <input type="checkbox" id="muteAll" class="mute" value="all" /> 
    <label for="muteAll">Mute all</label>

If you want to use the opposite scheme where a checked box means that sounds are enabled, you can use the "unmute" class instead. The functionality is identical but reversed.

    <input type="checkbox" id="unmuteMusic" class="unmute" value="music" /> 
    <label for="unmuteMusic">Music</label>
    <input type="checkbox" id="unmuteSound" class="unmute" value="sound" /> 
    <label for="unmuteSound">Sound effects</label>
    <input type="checkbox" id="unmuteAll" class="unmute" value="all" /> 
    <label for="unmuteAll">All sounds</label>

The mute status is written to a browser cookie every time it changes. In other words if the reader mutes audio, the preference is automatically remembered the next time they load the story.

To toggle the mute state manually you can use vorple.media.mute()API to mute or unmute sounds, music or videos, or vorple.media.muteAll()API to mute or unmute all sounds. vorple.media.muteAll() is a shortcut for vorple.media.mute({ sound: true, music: true }).

vorple.media.mute() uses an object that describes what elements to mute or unmute:

vorple.media.mute( { music: true } );                // mute music
vorple.media.mute( { music: true, sound: false } );    // mute music and unmute sound

vorple.media.muteAll() is used by giving the mute status as a parameter:

vorple.media.muteAll( true );    // mute everything
vorple.media.muteAll( false );    // unmute everything
Local videos respect the mute sound option. Embedded YouTube videos are always played with the sound on.

The mute checkboxes are automatically toggled to reflect the current mute status even when the muting is done manually.

Mute status can be toggled with vorple.media.toggleMute()API. It will unmute muted media and vice versa. The return value is true if the new status of the media is muted and false if it's now unmuted.

Here's an example of a button that toggles sounds on and off and changes its own text to reflect the current status from "Sounds on" to "Sounds off".

<button onclick="$( this ).html( vorple.media.toggleMute( 'sound' ) ? 'Sounds off' : 'Sounds on' );">
    Sounds on


Native audio and video support in web browsers is still far from standard. Some browsers can play only MP3 files, some only OGG files, some both, some neither. SoundManager uses primarily a Flash player and tries to use the browser's native playback capabilities if Flash player isn't available.

YouTube videos always require Flash (with some exceptions; iOS browsers (iPhone, iPod, iPad) can launch YouTube videos in a separate player).

Mobile Safari (iPhone, iPad, iPod) supports only one sound channel. If you start a new sound while another is playing, the other sound will be stopped. If you target mobile devices, it's best to disable either background music or sound effects (if you have them), otherwise any sound effect during the story will make background music stop abruptly.


Vorple uses the noty library to create notifications. They can be used to e.g. inform the reader of important events or acknowledge their actions.

Notifications are created using vorple.notify.show()API with the content of the notification as the first parameter. The notification's behavior can be altered with options given as the second parameter. All the available options can be found on noty's web site.

	'Note this!',
		speed: 2000,  // animations take 2 seconds (2000 ms)
		closeOnSelfClick: false  // don't close the notification on click

The notification's position can be given with the layout option. The available positions are the four corners of the screen (topLeft, topRight, bottomLeft and bottomRight), as a wide bar on the top or the bottom of the screen (top or bottom), in the center on top (topCenter), or in the middle of the screen (center). The default is bottom right. (Click on the positions above to test notifications.)

Multiple notifications in the four corners of the screen are displayed simultaneously. In every other position the notifications are put into a common queue and displayed sequentially. The queue can be emptied with vorple.notify.clearQueue()API.

The oldest notification can be dismissed with vorple.notify.close()API and all notifications dismissed with vorple.notify.closeAll()API, which will also empty the queue.

In the noty library the default duration of notifications is 5 seconds (5000 ms), but Vorple's default is that the notifications are automatically hidden after seven seconds. The average reading speed is about three words per second so 7 seconds is good for messages of about 20 words. In addition to the default location (bottom right) this is the only change to noty's defaults.

vorple.notify.defaults contains the story-specific defaults.

vorple.notify.defaults.textAlign = 'left';
vorple.notify.defaults.timeout = false;

vorple.notify.show( "This notification's text is aligned left " 
    + "and it must be clicked to dismiss." ); 

Click here to display the above notification.


Creating tooltips

Vorple comes bundled with the qTip2 tooltip library.

To add a tooltip to every link in the game, we'll add the vorple.tooltip.enable( 'a' )API to undum.game.init():

vorple.tooltip.enable( 'a' );

As simple as that! Now every link that has the title attribute will show the contents of the title as a tooltip when the mouse is put over them.

<a href="foo" title="This is the tooltip's text!">Link</a>

Or using the HTML module:

    { title: "This is the tooltip's content!" }

The parameter is a jQuery selector. If you need to add tooltips more accurately or to other elements, refer to the jQuery documentation.

All qTip2 options are supported. The documentation is at http://craigsworks.com/projects/qtip2/docs/ (look under "Options").

Manually triggered tooltips

Sometimes we might want to display a tooltip in response to an unrelated event or as part of the story's plot. vorple.tooltip.show()API creates a tooltip and shows it after a delay, then hides it again after another delay.

    'Tooltip content', 
        delay: 1000,    // 1 second
        duration: 5000    // 5 seconds

The first parameter is the element's jQuery selector, the second the text to be displayed in the tooltip, and the third is the options, including the delay before showing the tooltip and the duration how long the tooltip is displayed in milliseconds. The defaults for the delay and duration are 3000 milliseconds and 10000 milliseconds respectively.


Disposable links

Undum's once-links disable themselves after they've been clicked, but the effect is temporary. If the reader encounters the same link later, it's active again.

Disposable links are similar to once-links, but the effect is permanent: after the reader has clicked on a disposable link, it will never be shown during the same story again. (Links with the same target (href-attribute) are considered being the same link.)

There are two ways to define disposable links: either give them as a list, or specify that all links should be disposable and list only the exceptions.

The disposable link list should be assigned as an array to vorple.undum.settings.disposableLinks:

vorple.undum.settings.disposableLinks = [ 'discard', 'these', 'links' ];

To use the latter method and specify that all links should be disposable, set vorple.undum.settings.allDisposable to true and, if necessary, list the exceptions as an array in vorple.undum.settings.disposableExceptions.

vorple.undum.settings.allDisposable = true;
vorple.undum.settings.disposableExceptions = [ 'non-disposable', 'links' ];

If vorple.undum.settings.allDisposable is true, vorple.undum.settings.disposableLinks will be ignored.

Disposing a link will dispose of both actions and situations with the same name, so it's generally best to always use unique action and situation names.

Disposable links don't make a difference between situations and actions. Links to actions should be listed without the ./ prefix.

Disposable links can be defined anywhere in the story file. Using undum.game.init() is recommended.

A link's status can be checked with vorple.undum.isDisposed()API which will return true if the link has been disposed.

Disposing links manually

Links can be disposed manually by calling vorple.undum.dispose()API. The function can dispose any number of links at the same time, given either as separate arguments or as an array.

vorple.undum.dispose( 'name' );
vorple.undum.dispose( 'first', 'second', 'third' );
vorple.undum.dispose( [ 'first', 'second', 'third' ] );

You can dispose even links that are not in the vorple.undum.settings.disposableLinks list.

Reactivating disposed links

To reactivate a link call vorple.undum.reactivate()API. You can reactivate one or multiple links at the same time, just like with vorple.undum.dispose().

vorple.undum.reactivate( 'name' );
vorple.undum.reactivate( 'first', 'second', 'third' );
vorple.undum.reactivate( [ 'first', 'second', 'third' ] );

Reactivation applies only to future links. Any inactive links currently visible on the screen will not be activated. Reactivated links are not automatically removed from the list of disposable links, so clicking on them later will again dispose of them.

Unique links

If a link has class unique applied to it, all other instances of the same link will be automatically disabled. This can be used to make sure that only one instance of a link will be visible at the same time.

Here's a <a href="name" class="unique">link</a> 
and <a href="name">another</a>
but only the former one will be active because it's marked as unique
and the latter links to the same place.

Or, using Vorple's HTML helpers:

vorple.html.link( 'name', 'link', { classes: 'unique' } );
// → <a href="name" class="unique">link</a>

doClick() and doLink() exposures

undum.doClick() and undum.doLink() are exposed as vorple.undum.doClick()API and vorple.undum.doLink()API. This lets the author use them outside Undum's own methods, when the undum object is not available.

Complete examples

The examples can be downloaded separately from the download page.

One With Everything

The example story One With Everything uses all standard Vorple features. It's not really a story or a game by itself, but if you want to see a real-life code example of any of the features you can probably find it in the story's source code.

Down the Rabbit-Hole

Down the Rabbit-Hole showcases Vorple's features. It doesn't include every feature like One With Everything does and it uses some more advanced techniques to e.g. show custom popup windows.


Starborn is an Undum/Vorple adaptation of an Inform 7 keyword-based story. The adaptation adds background music, an interactive map, clickable buttons and other eye candy. Some of the features are straight-up Vorple, some are custom-made for the story.