code:
<!-- ***********************************************************************************************
	Template API
************************************************************************************************ -->
# `Template` API {#template-api}

<!-- *********************************************************************** -->

### `Template.size` → *number* {#template-api-getter-size}

Returns the number of existing templates.

#### History:

* `v2.29.0`: Introduced.

#### Examples:

```
if (Template.size === 0) {
	/* No templates exist. */
}
```

<!-- *********************************************************************** -->

### `Template.add(name , definition)` {#template-api-method-add}

Add new template(s).

#### History:

* `v2.29.0`: Introduced.

#### Parameters:

* **`name`:** (*string* | *Array<string>*) Name, or array of names, of the template(s) to add.  **NOTE:** Names must consist of characters from the basic Latin alphabet and start with a letter, which may be optionally followed by any number of letters, numbers, the underscore, or the hyphen.
* **`definition`:** (*function* | *string* | *Array<function | string>*) Definition of the template(s), which may be a: function, string, or an array of either.  **NOTE:** Each time array definitions are referenced, one of their member templates is randomly selected to be the output source.

#### Function templates:

Function templates should return a string, which may itself contain markup.  They are called with no arguments, but with their `this` set to a template (execution) context object that contains the following data properties:

* **`name`:** (*string*) The template's name.

#### String templates:

String templates consist solely of a string, which may itself contain markup.

#### Examples:

##### Basic usage

```
/* Define a function template named ?yolo. */
Template.add('yolo', function () {
	return either('YOLO', 'You Only Live Once');
});

/* Define a string template named ?nolf. */
Template.add('nolf', 'No One Lives Forever');

/* Define an array of string templates named ?alsoYolo. */
Template.add('alsoYolo', ['YOLO', 'You Only Live Once']);

/* Define an array of mixed string and function templates named ?cmyk. */
Template.add('cmyk', [
	'Cyan',
	function () {
		return either('Magenta', 'Yellow');
	},
	'Black'
]);
```

##### Using the context object (`this`)

```
/* Define a function template with two names, ?color and ?Color, whose output changes based on its name. */
Template.add(['color', 'Color'], function () {
	var color = either('red', 'green', 'blue');
	return this.name === 'Color' ? color.toUpperFirst() : color;
});
```

<!-- *********************************************************************** -->

### `Template.delete(name)` {#template-api-method-delete}

Remove existing template(s).

#### History:

* `v2.29.0`: Introduced.

#### Parameters:

* **`name`:** (*string* | *Array<string>*) Name, or array of names, of the template(s) to remove.

#### Examples:

```
/* Deletes the template ?yolo. */
Template.delete('yolo');

/* Deletes the templates ?yolo and ?nolf. */
Template.delete(['yolo', 'nolf']);
```

<!-- *********************************************************************** -->

### `Template.get(name)` → *function* | *string* | *Array<function | string>* {#template-api-method-get}

Return the named template definition, or `null` on failure.

#### History:

* `v2.29.0`: Introduced.

#### Parameters:

* **`name`:** (*string*) Name of the template whose definition should be returned.

#### Examples:

```
/* Returns the template ?yolo, or null if it doesn't exist. */
var yolo = Template.get('yolo');
```

<!-- *********************************************************************** -->

### `Template.has(name)` → *boolean* {#template-api-method-has}

Returns whether the named template exists.

#### History:

* `v2.29.0`: Introduced.

#### Parameters:

* **`name`:** (*string*) Name of the template to search for.

#### Examples:

```
if (Template.has('yolo')) {
	/* A ?yolo template exists. */
}
```


code:
<!-- ***********************************************************************************************
	UI API
************************************************************************************************ -->
# `UI` API {#ui-api}

<!-- *********************************************************************** -->

### `UI.alert(message [, options [, closeFn]])` {#ui-api-method-alert}

Opens the built-in alert dialog, displaying the given message to the player.

#### History:

* `v2.0.0`: Introduced.

#### Parameters:

* **`message`:** (*string*) The message to display to the player.
* **`options`:** (optional, *null* | *object*) The options object.  See [`Dialog.open()`](#dialog-api-method-open) for more information.
* **`closeFn`:** (optional, *null* | *function*) The function to execute whenever the dialog is closed.

#### Examples:

```
UI.alert("You smell of elderberries!");
```

<!-- *********************************************************************** -->

### `UI.jumpto([options [, closeFn]])` {#ui-api-method-jumpto}

Opens the built-in jump to dialog, which is populated via the [`bookmark` tag](#special-tag-bookmark).

#### History:

* `v2.0.0`: Introduced.

#### Parameters:

* **`options`:** (optional, *null* | *object*) The options object.  See [`Dialog.open()`](#dialog-api-method-open) for more information.
* **`closeFn`:** (optional, *null* | *function*) The function to execute whenever the dialog is closed.

#### Examples:

```
UI.jumpto();
```

<!-- *********************************************************************** -->

### `UI.restart([options])` {#ui-api-method-restart}

Opens the built-in restart dialog, prompting the player to restart the story.

#### History:

* `v2.0.0`: Introduced.

#### Parameters:

* **`options`:** (optional, *null* | *object*) The options object.  See [`Dialog.open()`](#dialog-api-method-open) for more information.

#### Examples:

```
UI.restart();
```

<!-- *********************************************************************** -->

### `UI.saves([options [, closeFn]])` {#ui-api-method-saves}

Opens the built-in saves dialog.

#### History:

* `v2.0.0`: Introduced.

#### Parameters:

* **`options`:** (optional, *null* | *object*) The options object.  See [`Dialog.open()`](#dialog-api-method-open) for more information.
* **`closeFn`:** (optional, *null* | *function*) The function to execute whenever the dialog is closed.

#### Examples:

```
UI.saves();
```

<!-- *********************************************************************** -->

### `UI.settings([options [, closeFn]])` {#ui-api-method-settings}

Opens the built-in settings dialog, which is populated from the [`Setting` API](#setting-api).

#### History:

* `v2.0.0`: Introduced.

#### Parameters:

* **`options`:** (optional, *null* | *object*) The options object.  See [`Dialog.open()`](#dialog-api-method-open) for more information.
* **`closeFn`:** (optional, *null* | *function*) The function to execute whenever the dialog is closed.

#### Examples:

```
UI.settings();
```

<!-- *********************************************************************** -->

### `UI.share([options [, closeFn]])` {#ui-api-method-share}

Opens the built-in share dialog, which is populated from the [`StoryShare` passage](#special-passage-storyshare).

#### History:

* `v2.0.0`: Introduced.

#### Parameters:

* **`options`:** (optional, *null* | *object*) The options object.  See [`Dialog.open()`](#dialog-api-method-open) for more information.
* **`closeFn`:** (optional, *null* | *function*) The function to execute whenever the dialog is closed.

#### Examples:

```
UI.share();
```


code:
# `UIBar` API {#uibar-api}

### `UIBar.destroy()` {#uibar-api-method-destroy}

Completely removes the UI bar and all of its associated styles and event handlers.

#### History:

* `v2.17.0`: Introduced.

#### Parameters: *none*

#### Examples:

```
UIBar.destroy();
```

### `UIBar.hide()` → *`UIBar` object* {#uibar-api-method-hide}

Hides the UI bar.  Returns a reference to the `UIBar` object for chaining.

Note:
This does not reclaim the space reserved for the UI bar.  Thus, a call to UIBar.stow() may also be necessary.  Alternatively, if you simply want the UI bar gone completely and permanently, either using UIBar.destroy() or the StoryInterface special passage may be a better choice.

#### History:

* `v2.29.0`: Introduced.

#### Parameters: *none*

#### Examples:

##### Basic usage

```
UIBar.hide();
```

##### With stow

```
UIBar.hide().stow();
```

### `UIBar.isHidden()` → *boolean* {#uibar-api-method-ishidden}

Returns whether the UI bar is currently hidden.

#### History:

* `v2.29.0`: Introduced.

#### Parameters: *none*

#### Examples:

```
if (UIBar.isHidden()) {
	/* code to execute if the UI bar is hidden… */
}

if (!UIBar.isHidden()) {
	/* code to execute if the UI bar is not hidden… */
}
```

### `UIBar.isStowed()` → *boolean* {#uibar-api-method-isstowed}

Returns whether the UI bar is currently stowed.

#### History:

* `v2.29.0`: Introduced.

#### Parameters: *none*

#### Examples:

```
if (UIBar.isStowed()) {
	/* code to execute if the UI bar is stowed… */
}

if (!UIBar.isStowed()) {
	/* code to execute if the UI bar is not stowed… */
}
```

### `UIBar.show()` → *`UIBar` object* {#uibar-api-method-show}

Shows the UI bar.  Returns a reference to the `UIBar` object for chaining.

#### History:

* `v2.29.0`: Introduced.

#### Parameters: *none*

#### Examples:

##### Basic usage

```
UIBar.show();
```

##### With unstow

```
UIBar.unstow().show();
```

### `UIBar.stow([noAnimation])` → *`UIBar` object* {#uibar-api-method-stow}

Stows the UI bar, so that it takes up less space.  Returns a reference to the `UIBar` object for chaining.

#### History:

* `v2.17.0`: Introduced.
* `v2.29.0`: Added returned `UIBar` chaining reference.

#### Parameters:

* **`noAnimation`:** (optional, *boolean*) Whether to skip the default animation.

#### Examples:

##### Basic usage

```
UIBar.stow();
```

##### With no animation

```
UIBar.stow(true);
```

### `UIBar.unstow([noAnimation])` → *`UIBar` object* {#uibar-api-method-unstow}

Unstows the UI bar, so that it is fully accessible again.  Returns a reference to the `UIBar` object for chaining.

#### History:

* `v2.17.0`: Introduced.
* `v2.29.0`: Added returned `UIBar` chaining reference.

#### Parameters:

* **`noAnimation`:** (optional, *boolean*) Whether to skip the default animation.

#### Examples:

##### Basic usage

```
UIBar.unstow();
```

##### With no animation

```
UIBar.unstow(true);
```

### `UIBar.update()` {#uibar-api-method-update}

Updates all sections of the UI bar that are populated by special passages—e.g., `StoryBanner`, `StoryCaption`, `StoryMenu`, etc.

Warning:
As all special passage populated sections are updated it is recommended that UIBar.update() be used sparingly.  Ideally, if you need to update UI bar content outside of the normal passage navigation update, then you should update only the specific areas you need to rather than the entire UI bar.

#### History:

* `v2.29.0`: Introduced.

#### Parameters: *none*

#### Examples:

```
UIBar.update();
```


code:
#!/usr/bin/env node
/***********************************************************************************************************************

	build-docs.js (v1.2.0, 2021-12-21)
		A Node.js-hosted build script for SugarCube's documentation.

	Copyright © 2020–2021 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.
	Use of this source code is governed by a BSD 2-clause "Simplified" License, which may be found in the LICENSE file.

***********************************************************************************************************************/
/* eslint-env node, es2021 */
'use strict';

/*******************************************************************************
	Configuration
*******************************************************************************/

const CONFIG = {
	// WARNING: The ordering within the following arrays is significant.
	md : {
		files : [
			// Table of Contents
			'table-of-contents.md',

			// Introduction
			'introduction.md',

			// Core
			'core/markup.md',
			'core/twinescript.md',
			'core/macros.md',
			'core/functions.md',
			'core/methods.md',
			'core/special-names.md',
			'core/css.md',
			'core/html.md',
			'core/events.md',

			// APIs
			'api/api-config.md',
			'api/api-dialog.md',
			'api/api-engine.md',
			'api/api-fullscreen.md',
			'api/api-loadscreen.md',
			'api/api-macro.md',
			'api/api-macrocontext.md',
			'api/api-passage.md',
			'api/api-save.md',
			'api/api-setting.md',
			'api/api-simpleaudio.md',
			'api/api-simpleaudio-audiotrack.md',
			'api/api-simpleaudio-audiorunner.md',
			'api/api-simpleaudio-audiolist.md',
			'api/api-state.md',
			'api/api-story.md',
			'api/api-template.md',
			'api/api-ui.md',
			'api/api-uibar.md',

			// Guides
			'guides/guide-state-sessions-and-saving.md',
			'guides/guide-tips.md',
			'guides/guide-media-passages.md',
			'guides/guide-harlowe-to-sugarcube.md',
			'guides/guide-test-mode.md',
			'guides/guide-typescript.md',
			'guides/guide-installation.md',
			'guides/guide-code-updates.md',
			'guides/guide-localization.md'
		]
	},
	js : {
		intro : {
			files : [
				'templates/js/intro-scdocs.js',
				'templates/js/intro-enhancement.js'
			],
			intro : 'templates/js/intro.js',
			outro : 'templates/js/outro.js'
		},
		nav : {
			files : [
				'templates/js/nav-enhancement.js'
			],
			intro : 'templates/js/intro.js',
			outro : 'templates/js/outro.js'
		}
	},
	css : {
		files : [
			'templates/css/core.css'
		]
	},
	html : {
		intro : 'templates/html/intro.html',
		outro : 'templates/html/outro.html'
	},
	build : {
		dest : 'build/index.html'
	}
};

/*******************************************************************************
	Main Script
*******************************************************************************/

// NOTICE!
//
// Where string replacements are done, we use the replacement function style to
// disable all special replacement patterns, since some of them may exist within
// the replacement strings—e.g., `$&` within the HTML or JavaScript sources.

const process = require('process');
process.env.BROWSERSLIST_CONFIG = '../.browserslistrc';

const {
	log,
	die,
	makePath,
	readFileContents,
	writeFileContents,
	concatFiles
} = require('../scripts/build-utils');
const _path = require('path');
const _opt  = require('node-getopt').create([
	['h', 'help',       'Print this help, then exit.'],
	['u', 'unminified', 'Suppress minification stages.']
])
	.bindHelp()
	.parseSystem();

// Build the documentation.
(async () => {
	console.log('Starting build...\n');

	// Set build constants.
	const BUILD_VERSION  = require('../package.json').version;
	const BUILD_DATETIME = new Date().toISOString().replace(/\.\d+Z$/, 'Z');
	const BUILD_DATE     = new Date().toISOString().slice(0, 10);

 	// Compile the JavaScript.
	log('compiling JavaScript...');
	const jsIntro = await compileJavaScript(CONFIG.js.intro);
	const jsNav   = await compileJavaScript(CONFIG.js.nav);

	// Compile the CSS.
	log('compiling CSS...');
	const css = compileStyles(CONFIG.css);

	// Compile the Markdown.
	log('compiling Markdown...');
	const markdown = compileMarkdown(CONFIG.md);

	// Assemble the basic document.
	log('assembling document...');
	let output = readFileContents(CONFIG.html.intro)
		+ markdown
		+ readFileContents(CONFIG.html.outro);

	// Add permalinks to ID-bearing headings.
	output = output.replace(
		/<([Hh]\d)>(.+?)\{#([^}]+)\}<\/\1>/g,
		(_, heading, text, id) => `<${heading} id="${id}"><a href="#${id}" class="permalink" title="Permanent link" aria-label="Permanent link"></a>\u00A0<span>${text}</span></${heading}>`
	);

	// Build the final document.
	const outfile = _path.normalize(CONFIG.build.dest);
	log(`building: "${outfile}"`);

	// Process the source replacement tokens. (First!)
	output = output.replace(/\{\{\.SCRIPT_CORE\}\}/, () => jsIntro);
	output = output.replace(/\{\{\.SCRIPT_NAV\}\}/, () => jsNav);
	output = output.replace(/\{\{\.STYLE_CORE\}\}/, () => css);

	// Process the build replacement tokens.
	output = output.replace(/\{\{\.VERSION\}\}/g, () => BUILD_VERSION);
	output = output.replace(/\{\{\.ISO_DATE\}\}/g, () => BUILD_DATETIME);
	output = output.replace(/\{\{\.DATE\}\}/g, () => BUILD_DATE);

	// Write the outfile.
	makePath(_path.dirname(outfile));
	writeFileContents(outfile, output);
})()
	.then(() => console.log('\nBuild complete!  (check the "build" directory)'))
	.catch(reason => console.log('\nERROR:', reason));

/*******************************************************************************
	Utility Functions
*******************************************************************************/
function compileMarkdown(sourceConfig) {
	const { execFileSync } = require('child_process');
	return concatFiles(sourceConfig.files, (contents /* , filename */) => {
		try {
			// TODO: Replace `cmark-gfm` with a JavaScript solution.
			return execFileSync('cmark-gfm', ['-t', 'html'], {
				input : contents
			});
		}
		catch (ex) {
			die(`markdown error: ${ex.message}`, ex);
		}
	});
}

function compileJavaScript(sourceConfig) {
	return (async source => {
		if (_opt.options.unminified) {
			return source;
		}

		// Minify the code with Terser.
		const { minify } = require('terser');
		const minified   = await minify(source, {
			compress : {
				keep_infinity : true // eslint-disable-line camelcase
			},
			mangle : true
		});

		if (minified.error) {
			const { message, line, col, pos } = minified.error;
			die(`JavaScript minification error: ${message}\n[@: ${line}/${col}/${pos}]`);
		}

		return minified.code;
	})(
		  readFileContents(sourceConfig.intro)
		+ concatFiles(sourceConfig.files)
		+ readFileContents(sourceConfig.outro)
	);
}

function compileStyles(sourceConfig) {
	const autoprefixer  = require('autoprefixer');
	const postcss       = require('postcss');
	const CleanCss      = require('clean-css');
	return concatFiles(sourceConfig.files, (contents, filename) => {
		const processed = postcss([autoprefixer]).process(contents, { from : filename });
		processed.warnings().forEach(mesg => console.warn(mesg.text));

		let css = processed.css;

		if (!_opt.options.unminified) {
			css = new CleanCss({
				level         : 1,
				compatibility : 'ie9'
			})
				.minify(css)
				.styles;
		}

		const fileSlug = _path.basename(filename, '.css').toLowerCase().replace(/[^0-9a-z]+/g, '-');

		return `<style id="style-${fileSlug}" type="text/css">${css}</style>`;
	});
}


code:
# CSS {#css}

## Passage Conversions {#css-passage-conversions}

IDs and classes automatically generated from passage names and tags are normalized to kebab case with all lowercase letters—which entails: removing characters that are not alphanumerics, underscores, hyphens, en-/em-dashes, or whitespace, then replacing any remaining non-alphanumeric characters with hyphens, one per group, and finally converting the result to lowercase.

### Passage Names

Passage names have `passage-` prepended to their converted forms and are converted both into IDs and classes depending on how the passage is used—an ID for the active passage, classes for included (via [`<<include>>`](#macros-macro-include)) passages.

For example, if the passage name was `Gone fishin'`, then:

* When the active passage, it would become the ID `passage-gone-fishin` (selector: `#passage-gone-fishin`).
* When included, it would become the class `passage-gone-fishin` (selector: `.passage-gone-fishin`).

### Passage Tags

When displaying a passage, its tags are:

1. Added to the active passage's container element, `<html>` element, and `<body>` element as a space separated list within the `data-tags` attribute.
2. Added to the active passage's container element and `<body>` element as classes.  The following special tags are excluded from this mapping:

			Twine 2:
			debug, nobr, passage, widget, and any tag starting with twine.

			Twine 1/Twee:
			debug, nobr, passage, script, stylesheet, widget, and any tag starting with twine.

For example, if the tag name was `Sector_42`, then it would become both the `data-tags` attribute member `Sector_42` (selector: `[data-tags~="Sector_42"]`) and the class `sector-42` (selector: `.sector-42`).

## Example Selectors {#css-example-selectors}

		Selector
		Description

		html

The document element.  The default font stack is set here.

The active passage's tags will be added to its data-tags attribute (see: Passage Conversions).

		body

The body of the page.  The default foreground and background colors are set here.

The active passage's tags will be added to its data-tags attribute and classes (see: Passage Conversions).

		#story
		Selects the story element.

		#passages
		Selects the element that contains passage elements.  All created passage elements will be children of this element.

		.passage

Selects the passage element.  Normally, there will be only one such passage per turn, however, during passage navigation there may briefly be two—the incoming (a.k.a. active) and outgoing passages.

The active passage's name will be added as its ID (see: Passage Conversions).

The active passage's tags will be added to its data-tags attribute and classes (see: Passage Conversions).

		.passage a
		Selects all <a> elements within the passage element.

		.passage a:hover
		Selects <a> elements within the passage element that are being hovered over.

		.passage a:active
		Selects <a> elements within the passage element that are being clicked on.

		.passage .link-broken
		Selects all internal link elements within the passage element whose passages do not exist within the story.

		.passage .link-disabled
		Selects all internal link elements within the passage element who have been disabled—e.g., already chosen <<choice>> macro links.

		.passage .link-external
		Selects all external link elements within the passage element—e.g., links to other pages and websites.

		.passage .link-internal
		Selects all internal link elements within the passage element—e.g., passage and macro links.

		.passage .link-visited1
		Selects all internal link elements within the passage element whose passages are within the in-play story history—i.e., passages the player has been to before.

		.passage .link-internal:not(.link-visited)1
		Selects all internal link elements within the passage element whose passages are not within the in-play story history—i.e., passages the player has never been to before.

The .link-visited class is not enabled by default, see the Config API's Config.addVisitedLinkClass property for more information.

## Warnings {#css-warnings}

### Multiple Stylesheets *(for Twine 1/Twee only)*

When using Twine 1/Twee, it is ***strongly*** recommended that you use only a single `stylesheet` tagged passage.  CSS styles cascade in order of load, so if you use multiple `stylesheet` tagged passages, then it is all too easy for your styles to be loaded in the wrong order, since Twine 1/Twee gives you no control over the order that multiple `stylesheet` tagged passages load.

### Tagged Stylesheets

SugarCube does not support the Twine 1.4+ vanilla story formats' tagged stylesheets.  In SugarCube, you would instead simply prefix the selectors of your styles with the appropriate tag-based selectors—e.g., either `[data-tags~="…"]` attribute selectors or class selectors.

For example, if some story passages were tagged with `forest`, then styles for those forest passages might look like this:

```
/* Using [data-tags~="…"] attribute selectors on <html> */
html[data-tags~="forest"] { background-image: url(forest-bg.jpg); }
html[data-tags~="forest"] .passage { color: darkgreen; }
html[data-tags~="forest"] a { color: green; }
html[data-tags~="forest"] a:hover { color: lime; }

/* Using [data-tags~="…"] attribute selectors on <body> */
body[data-tags~="forest"] { background-image: url(forest-bg.jpg); }
body[data-tags~="forest"] .passage { color: darkgreen; }
body[data-tags~="forest"] a { color: green; }
body[data-tags~="forest"] a:hover { color: lime; }

/* Using class selectors on <body> */
body.forest { background-image: url(forest-bg.jpg); }
body.forest .passage { color: darkgreen; }
body.forest a { color: green; }
body.forest a:hover { color: lime; }
```

## Built-in Stylesheets {#css-built-ins}

These are SugarCube's built-in stylesheets, in order of load/cascade.  The most interesting of which, from an end-user's standpoint, are 4–10.  The links go to the most recent release versions of each in SugarCube's [source code repository](https://github.com/tmedwards/sugarcube-2).

1. [normalize.css](https://raw.githubusercontent.com/tmedwards/sugarcube-2/master/src/vendor/normalize.css)
2. [init-screen.css](https://raw.githubusercontent.com/tmedwards/sugarcube-2/master/src/css/init-screen.css)
3. [font.css](https://raw.githubusercontent.com/tmedwards/sugarcube-2/master/src/css/font.css)
4. [core.css](https://raw.githubusercontent.com/tmedwards/sugarcube-2/master/src/css/core.css)
5. [core-display.css](https://raw.githubusercontent.com/tmedwards/sugarcube-2/master/src/css/core-display.css)
6. [core-passage.css](https://raw.githubusercontent.com/tmedwards/sugarcube-2/master/src/css/core-passage.css)
7. [core-macro.css](https://raw.githubusercontent.com/tmedwards/sugarcube-2/master/src/css/core-macro.css)
8. [ui-dialog.css](https://raw.githubusercontent.com/tmedwards/sugarcube-2/master/src/css/ui-dialog.css)
9. [ui.css](https://raw.githubusercontent.com/tmedwards/sugarcube-2/master/src/css/ui.css)
10. [ui-bar.css](https://raw.githubusercontent.com/tmedwards/sugarcube-2/master/src/css/ui-bar.css)
11. [ui-debug.css](https://raw.githubusercontent.com/tmedwards/sugarcube-2/master/src/css/ui-debug.css)


code:
# Events {#events}

Events are messages that are sent (a.k.a.: fired, triggered) to notify code that something has taken place, from player interactions to automated happenings.  Each event is represented by an object that has properties that may be used to get additional information about what happened.

This section offers a list of SugarCube-specific events, triggered at various points during story operation.

See Also:
For standard browser/DOM events, see the Event reference @MDN.

## `Dialog` Events {#events-dialog}

`Dialog` events allow the execution of JavaScript code at specific points during the opening and closing of dialogs.

See:
Dialog API.

### `:dialogclosed` event {#events-dialog-event-dialogclosed}

Global event triggered as the last step in closing the dialog when [`Dialog.close()`](#dialog-api-method-close) is called.

Warning:
You cannot obtain data about the closing dialog from the dialog itself—e.g., title or classes—when using the :dialogclosed event, as the dialog has already closed and been reset by the time the event is fired.  If you need that kind of information from the dialog itself, then you may use the :dialogclosing event instead.

#### History:

* `v2.29.0`: Introduced.

#### Event object properties: *none*

Note:
While there are no custom properties, the event is fired from the dialog's body, thus the target property will refer to its body element—i.e., #ui-dialog-body.

#### Examples:

```
/* Execute the handler function when the event triggers. */
$(document).on(':dialogclosed', function (ev) {
	/* JavaScript code */
});

/* Execute the handler function exactly once. */
$(document).one(':dialogclosed', function (ev) {
	/* JavaScript code */
});
```

### `:dialogclosing` event {#events-dialog-event-dialogclosing}

Global event triggered as the first step in closing the dialog when [`Dialog.close()`](#dialog-api-method-close) is called.

#### History:

* `v2.29.0`: Introduced.

#### Event object properties: *none*

Note:
While there are no custom properties, the event is fired from the dialog's body, thus the target property will refer to its body element—i.e., #ui-dialog-body.

#### Examples:

```
/* Execute the handler function when the event triggers. */
$(document).on(':dialogclosing', function (ev) {
	/* JavaScript code */
});

/* Execute the handler function exactly once. */
$(document).one(':dialogclosing', function (ev) {
	/* JavaScript code */
});
```

### `:dialogopened` event {#events-dialog-event-dialogopened}

Global event triggered as the last step in opening the dialog when [`Dialog.open()`](#dialog-api-method-open) is called.

#### History:

* `v2.29.0`: Introduced.

#### Event object properties: *none*

Note:
While there are no custom properties, the event is fired from the dialog's body, thus the target property will refer to its body element—i.e., #ui-dialog-body.

#### Examples:

```
/* Execute the handler function when the event triggers. */
$(document).on(':dialogopened', function (ev) {
	/* JavaScript code */
});

/* Execute the handler function exactly once. */
$(document).one(':dialogopened', function (ev) {
	/* JavaScript code */
});
```

### `:dialogopening` event {#events-dialog-event-dialogopening}

Global event triggered as the first step in opening the dialog when [`Dialog.open()`](#dialog-api-method-open) is called.

#### History:

* `v2.29.0`: Introduced.

#### Event object properties: *none*

Note:
While there are no custom properties, the event is fired from the dialog's body, thus the target property will refer to its body element—i.e., #ui-dialog-body.

#### Examples:

```
/* Execute the handler function when the event triggers. */
$(document).on(':dialogopening', function (ev) {
	/* JavaScript code */
});

/* Execute the handler function exactly once. */
$(document).one(':dialogopening', function (ev) {
	/* JavaScript code */
});
```

## Navigation Events {#events-navigation}

Navigation events allow the execution of JavaScript code at specific points during passage navigation.

In order of processing: *(for reference, this also shows tasks and various special passages)*

1. Passage init.  Happens before the modification of the state history.
	1. `:passageinit` event.
	2. `prehistory` tasks. *(deprecated)*
2. Passage start. Happens before the rendering of the incoming passage.
	1. `predisplay` tasks. *(deprecated)*
	2. [`PassageReady` special passage](#special-passage-passageready).
	3. `:passagestart` event.
	4. `prerender` tasks. *(deprecated)*
	5. [`PassageHeader` special passage](#special-passage-passageheader).
3. Passage render.  Happens after the rendering of the incoming passage.
	1. [`PassageFooter` special passage](#special-passage-passagefooter).
	2. `:passagerender` event.
	3. `postrender` tasks. *(deprecated)*
4. Passage display.  Happens after the display—i.e., output—of the incoming passage.
	1. [`PassageDone` special passage](#special-passage-passagedone).
	2. `:passagedisplay` event.
	3. `postdisplay` tasks. *(deprecated)*
5. UI bar special passages update.  Happens before the end of passage navigation.
	1. [`StoryBanner` special passage](#special-passage-storybanner).
	2. [`StoryDisplayTitle` special passage](#special-passage-storydisplaytitle).
	3. [`StorySubtitle` special passage](#special-passage-storysubtitle).
	4. [`StoryAuthor` special passage](#special-passage-storyauthor).
	5. [`StoryCaption` special passage](#special-passage-storycaption).
	6. [`StoryMenu` special passage](#special-passage-storymenu).
6. Passage end.  Happens at the end of passage navigation.
	1. `:passageend` event.

### `:passageinit` event {#events-navigation-event-passageinit}

Triggered before the modification of the state history.

#### History:

* `v2.20.0`: Introduced.

#### Event object properties:

* **`passage`:** (*`Passage` object*) The incoming passage object.  See the [`Passage` API](#passage-api) for more information.

#### Examples:

```
/* Execute the handler function each time the event triggers. */
$(document).on(':passageinit', function (ev) {
	/* JavaScript code */
});

/* Execute the handler function exactly once. */
$(document).one(':passageinit', function (ev) {
	/* JavaScript code */
});
```

### `:passagestart` event {#events-navigation-event-passagestart}

Triggered before the rendering of the incoming passage.

#### History:

* `v2.20.0`: Introduced.

#### Event object properties:

* **`content`:** (*`HTMLElement` object*) The, currently, empty element that will eventually hold the rendered content of the incoming passage.
* **`passage`:** (*`Passage` object*) The incoming passage object.  See the [`Passage` API](#passage-api) for more information.

#### Examples:

##### Basic usage

```
/* Execute the handler function each time the event triggers. */
$(document).on(':passagestart', function (ev) {
	/* JavaScript code */
});

/* Execute the handler function exactly once. */
$(document).one(':passagestart', function (ev) {
	/* JavaScript code */
});
```

##### Modifying the content buffer

```
/*
	Process the markup "In the //beginning//." and append the result
	to the incoming passage's element.
*/
$(document).on(':passagestart', function (ev) {
	$(ev.content).wiki("In the //beginning//.");
});
```

### `:passagerender` event {#events-navigation-event-passagerender}

Triggered after the rendering of the incoming passage.

#### History:

* `v2.20.0`: Introduced.

#### Event object properties:

* **`content`:** (*`HTMLElement` object*) The element holding the fully rendered content of the incoming passage.
* **`passage`:** (*`Passage` object*) The incoming passage object.  See the [`Passage` API](#passage-api) for more information.

#### Examples:

##### Basic usage

```
/* Execute the handler function each time the event triggers. */
$(document).on(':passagerender', function (ev) {
	/* JavaScript code */
});

/* Execute the handler function exactly once. */
$(document).one(':passagerender', function (ev) {
	/* JavaScript code */
});
```

##### Modifying the content buffer

```
/*
	Process the markup "At the //end// of some renderings." and append the result
	to the incoming passage's element.
*/
$(document).on(':passagerender', function (ev) {
	$(ev.content).wiki("At the //end// of some renderings.");
});
```

### `:passagedisplay` event {#events-navigation-event-passagedisplay}

Triggered after the display—i.e., output—of the incoming passage.

#### History:

* `v2.20.0`: Introduced.
* `v2.31.0`: Added `content` property to event object.

#### Event object properties:

* **`content`:** (*`HTMLElement` object*) The element holding the fully rendered content of the incoming passage.
* **`passage`:** (*`Passage` object*) The incoming passage object.  See the [`Passage` API](#passage-api) for more information.

#### Examples:

##### Basic usage

```
/* Execute the handler function each time the event triggers. */
$(document).on(':passagedisplay', function (ev) {
	/* JavaScript code */
});

/* Execute the handler function exactly once. */
$(document).one(':passagedisplay', function (ev) {
	/* JavaScript code */
});
```

##### Modifying the content buffer

```
/*
	Process the markup "It's //showtime//!" and append the result
	to the incoming passage's element.
*/
$(document).on(':passagedisplay', function (ev) {
	$(ev.content).wiki("It's //showtime//!");
});
```

### `:passageend` event {#events-navigation-event-passageend}

Triggered at the end of passage navigation.

#### History:

* `v2.20.0`: Introduced.
* `v2.31.0`: Added `content` property to event object.

#### Event object properties:

* **`content`:** (*`HTMLElement` object*) The element holding the fully rendered content of the incoming passage.
* **`passage`:** (*`Passage` object*) The incoming passage object.  See the [`Passage` API](#passage-api) for more information.

#### Examples:

##### Basic usage

```
/* Execute the handler function each time the event triggers. */
$(document).on(':passageend', function (ev) {
	/* JavaScript code */
});

/* Execute the handler function exactly once. */
$(document).one(':passageend', function (ev) {
	/* JavaScript code */
});
```

##### Modifying the content buffer

```
/*
	Process the markup "So long and //thanks for all the fish//!" and append the result
	to the incoming passage's element.
*/
$(document).on(':passageend', function (ev) {
	$(ev.content).wiki("So long and //thanks for all the fish//!");
});
```

### `prehistory` tasks {#events-navigation-task-prehistory}

Deprecated:
prehistory tasks have been deprecated and should no longer be used.  See the :passageinit event for its replacement.

#### History:

* `v2.0.0`: Introduced.
* `v2.31.0`: Deprecated.

### `predisplay` tasks {#events-navigation-task-predisplay}

Deprecated:
predisplay tasks have been deprecated and should no longer be used.  See the :passagestart event for its replacement.

#### History:

* `v2.0.0`: Introduced.
* `v2.31.0`: Deprecated.

### `prerender` tasks {#events-navigation-task-prerender}

Deprecated:
prerender tasks have been deprecated and should no longer be used.  See the :passagestart event for its replacement.

#### History:

* `v2.0.0`: Introduced.
* `v2.31.0`: Deprecated.

### `postrender` tasks {#events-navigation-task-postrender}

Deprecated:
postrender tasks have been deprecated and should no longer be used.  See the :passagerender event for its replacement.

#### History:

* `v2.0.0`: Introduced.
* `v2.31.0`: Deprecated.

### `postdisplay` tasks {#events-navigation-task-postdisplay}

Deprecated:
postdisplay tasks have been deprecated and should no longer be used.  See the :passagedisplay event for its replacement.

#### History:

* `v2.0.0`: Introduced.
* `v2.31.0`: Deprecated.

## `SimpleAudio` Events {#events-simpleaudio}

`SimpleAudio` events allow the execution of JavaScript code at specific points during audio playback.

See:
To add or remove event listeners to audio tracks managed by the SimpleAudio API see:

AudioTrack API methods: <AudioTrack>.off(), <AudioTrack>.on(), <AudioTrack>.one().

AudioRunner API methods: <AudioRunner>.off(), <AudioRunner>.on(), <AudioRunner>.one().

### `:faded` event {#events-simpleaudio-event-faded}

Track event triggered when a fade completes normally.

#### History:

* `v2.29.0`: Introduced.

#### Event object properties: *none*

#### Examples:

```
/* Execute the handler function when the event triggers for one track via <AudioTrack>. */
aTrack.on(':faded', function (ev) {
	/* JavaScript code */
});

/* Execute the handler function when the event triggers for multiple tracks via <AudioRunner>. */
someTracks.on(':faded', function (ev) {
	/* do something */
});
```

### `:fading` event {#events-simpleaudio-event-fading}

Track event triggered when a fade starts.

#### History:

* `v2.29.0`: Introduced.

#### Event object properties: *none*

#### Examples:

```
/* Execute the handler function when the event triggers for one track via <AudioTrack>. */
aTrack.on(':fading', function (ev) {
	/* JavaScript code */
});

/* Execute the handler function when the event triggers for multiple tracks via <AudioRunner>. */
someTracks.on(':fading', function (ev) {
	/* do something */
});
```

### `:stopped` event {#events-simpleaudio-event-stopped}

Track event triggered when playback is stopped after [`<AudioTrack>.stop()`](#audiotrack-api-prototype-method-stop) or [`<AudioRunner>.stop()`](#audiorunner-api-prototype-method-stop) is called—either manually or as part of another process.

See Also:
ended and pause for information on somewhat similar native events.

#### History:

* `v2.29.0`: Introduced.

#### Event object properties: *none*

#### Examples:

```
/* Execute the handler function when the event triggers for one track via <AudioTrack>. */
aTrack.on(':stopped', function (ev) {
	/* JavaScript code */
});

/* Execute the handler function when the event triggers for multiple tracks via <AudioRunner>. */
someTracks.on(':stopped', function (ev) {
	/* do something */
});
```

## System Events {#events-system}

System events allow the execution of JavaScript code at specific points during story startup and teardown.

### `:storyready` event {#events-system-event-storyready}

Global event triggered once just before the dismissal of the loading screen at startup.

#### History:

* `v2.31.0`: Introduced.

#### Event object properties: *none*

#### Examples:

```
/* Execute the handler function exactly once, since it's only fired once. */
$(document).one(':storyready', function (ev) {
	/* JavaScript code */
});
```

### `:enginerestart` event {#events-system-event-enginerestart}

Global event triggered once just before the page is reloaded when [`Engine.restart()`](#engine-api-method-restart) is called.

#### History:

* `v2.23.0`: Introduced.

#### Event object properties: *none*

#### Examples:

```
/* Execute the handler function when the event triggers. */
$(document).one(':enginerestart', function (ev) {
	/* JavaScript code */
});
```

## `<<type>>` Events {#events-type-macro}

`<<type>>` macro events allow the execution of JavaScript code at specific points during typing.

### `:typingcomplete` event {#events-type-macro-event-typingcomplete}

Global event triggered when all `<<type>>` macros within a passage have completed.

Note:
Injecting additional <<type>> macro invocations after a :typingcomplete event has been fired will cause another event to eventually be generated, since you're creating a new sequence of typing.

#### History:

* `v2.32.0`: Introduced.

#### Event object properties: *none*

#### Examples:

```
/* Execute the handler function when the event triggers. */
$(document).on(':typingcomplete', function (ev) {
	/* JavaScript code */
});
```

### `:typingstart` event {#events-type-macro-event-typingstart}

Local event triggered on the typing wrapper when the typing of a section starts.

#### History:

* `v2.32.0`: Introduced
* `v2.33.0`: Changed to a local event that bubbles up the DOM tree.

#### Event object properties: *none*

#### Examples:

```
/* Execute the handler function when the event triggers. */
$(document).on(':typingstart', function (ev) {
	/* JavaScript code */
});
```

### `:typingstop` event {#events-type-macro-event-typingstop}

Local event triggered on the typing wrapper when the typing of a section stops.

#### History:

* `v2.32.0`: Introduced
* `v2.33.0`: Changed to a local event that bubbles up the DOM tree.

#### Event object properties: *none*

#### Examples:

```
/* Execute the handler function when the event triggers. */
$(document).on(':typingstop', function (ev) {
	/* JavaScript code */
});
```


code:
# Functions {#functions}

### `clone(original)` → *any* {#functions-function-clone}

Returns a deep copy of the given value.

Note:
Only the primitives, generic objects, some JavaScript natives (specifically: Array, Date, Map, RegExp, and Set), and DOM node objects are supported by default.  Unsupported object types, either native or custom, will need to implement .clone() method to be properly supported by the clone() function—when called on such an object, it will simply defer to the local method; see the Non-generic object types (a.k.a. classes) guide for more information.

#### History:

* `v2.0.0`: Introduced.

#### Parameters:

* **`original`:** (*any*) The object to value.

#### Examples:

```
// Without clone(); given the generic object: $foo = { id : 1 }
<<set $bar to $foo>>
<<set $bar.id to 5>>
$foo.id  → Returns: 5
$bar.id  → Returns: 5

// With clone(); given the generic object: $foo = { id : 1 }
<<set $bar to clone($foo)>>
<<set $bar.id to 5>>
$foo.id  → Returns: 1
$bar.id  → Returns: 5
```

### `either(list…)` → *any* {#functions-function-either}

Returns a random value from its given arguments.

#### History:

* `v2.0.0`: Introduced.

#### Parameters:

* **`list`:** (*any*) The list of values to operate on.  May be any combination of singular values, actual arrays, or array-like objects.  All values will be concatenated into a single list for selection.  **NOTE:** Does not flatten nested arrays—if this is required, the [`<Array>.flat()`](#methods-array-prototype-method-flat) method may be used to flatten the nested arrays prior to passing them to `either()`.

#### Examples:

```
// Using singular values
either("Blueberry", "Cherry", "Pecan")  → Returns a random pie from the whole list

// Using arrays; given: $pies = ["Blueberry", "Cherry", "Pecan"]
either($pies)  → Returns a random pie from the whole array

// Using singular values and arrays; given: $letters = ["A", "B"]
either($letters, "C", "D")  → Returns a random value from the whole list—i.e., "A", "B", "C", "D"

// Using multiple arrays; given: $letters = ["A", "B"] & $numerals = ["1", "2"]
either($letters, $numerals)  → Returns a random value from the whole list—i.e., "A", "B", "1", "2"
```

### `forget(key)` {#functions-function-forget}

Removes the specified key, and its associated value, from the story metadata store.

See Also:
memorize(), recall().

#### History:

* `v2.29.0`: Introduced.

#### Parameters:

* **`key`:** (*string*) The key to remove.

#### Examples:

```
<<run forget('achievements')>>
```

### `hasVisited(passages…)` → *boolean* {#functions-function-hasvisited}

Returns whether the passage with the given title occurred within the story history.  If multiple passage titles are given, returns the logical-AND aggregate of the set—i.e., `true` if all were found, `false` if any were not found.

#### History:

* `v2.7.0`: Introduced.

#### Parameters:

* **`passages`:** (*string* | *Array<string>*) The title(s) of the passage(s) to search for.  May be a list or an array of passages.

#### Examples:

```
<<if hasVisited("Bar")>>…has been to the Bar…<</if>>
<<if not hasVisited("Bar")>>…has never been to the Bar…<</if>>
<<if hasVisited("Bar", "Café")>>…has been to both the Bar and Café<</if>>
<<if not hasVisited("Bar", "Café")>>…has never been to either the Bar, Café, or both…<</if>>
```

### `lastVisited(passages…)` → *integer* {#functions-function-lastvisited}

Returns the number of turns that have passed since the last instance of the passage with the given title occurred within the story history or `-1` if it does not exist.  If multiple passage titles are given, returns the lowest count (which can be `-1`).

#### History:

* `v2.0.0`: Introduced.

#### Parameters:

* **`passages`:** (*string* | *Array<string>*) The title(s) of the passage(s) to search for.  May be a list or an array of passages.

#### Examples:

```
<<if lastVisited("Bar") is -1>>…has never been to the Bar…<</if>>
<<if lastVisited("Bar") is 0>>…is currently in the Bar…<</if>>
<<if lastVisited("Bar") is 1>>…was in the Bar one turn ago…<</if>>
<<if lastVisited("Bar", "Café") is -1>>…has never been to the Bar, Café, or both…<</if>>
<<if lastVisited("Bar", "Café") is 2>>…has been to both the Bar and Café, most recently two turns ago…<</if>>
```

### `importScripts(urls…)` → *`Promise` object* {#functions-function-importscripts}

Load and integrate external JavaScript scripts.

Note:
Loading is done asynchronously at run time, so if the script must be available within a tight time frame, then you should use the Promise returned by the function to ensure that the script is loaded before it is needed.

Note:
Your project's JavaScript section (Twine 2: the Story JavaScript; Twine 1/Twee: a script-tagged passage) is normally the best place to call importScripts().

#### History:

* `v2.16.0`: Introduced.

#### Parameters:

* **`urls`:** (*string* | *Array<string>*) The URLs of the external scripts to import.  Loose URLs are imported concurrently, arrays of URLs are imported sequentially.

#### Examples:

##### Basic usage

```
// Import all scripts concurrently
importScripts(
	"https://somesite/a/path/a.js",
	"https://somesite/a/path/b.js",
	"https://somesite/a/path/c.js",
	"https://somesite/a/path/d.js"
);

// Import all scripts sequentially
importScripts([
	"https://somesite/a/path/a.js",
	"https://somesite/a/path/b.js",
	"https://somesite/a/path/c.js",
	"https://somesite/a/path/d.js"
]);

// Import scripts a.js, b.js, and the c.js/d.js group concurrently,
// while importing c.js and d.js sequentially relative to each other
importScripts(
	"https://somesite/a/path/a.js",
	"https://somesite/a/path/b.js",
	[
		"https://somesite/a/path/c.js",
		"https://somesite/a/path/d.js"
	]
);
```

##### Basic usage with the returned `Promise` object

```
// Import a script while using the returned Promise to ensure that
// the script has been fully loaded before executing dependent code
importScripts("https://somesite/a/path/a.js")
	.then(function () {
		// Code that depends on the script goes here.
	})
	.catch(function (err) {
		// There was an error loading the script, log it to the console.
		console.log(err);
	});
```

##### Saving the returned `Promise` object for later use

```
// Import a script while saving the returned Promise so it may be used later
setup.aScriptImport = importScripts("https://somesite/a/path/aScript.js");

// Use the returned Promise later on to ensure that the script has been fully
// loaded before executing dependent code
setup.aScriptImport
	.then(function () {
		// Code that depends on the script goes here.
	})
	.catch(function (err) {
		// There was an error loading the script, log it to the console.
		console.log(err);
	});
```

### `importStyles(urls…)` → *`Promise` object* {#functions-function-importstyles}

Load and integrate external CSS stylesheets.

Note:
Loading is done asynchronously at run time, so if the stylesheet must be available within a tight time frame, then you should use the Promise returned by the function to ensure that the stylesheet is loaded before it is needed.

Note:
Your project's JavaScript section (Twine 2: the Story JavaScript; Twine 1/Twee: a script-tagged passage) is normally the best place to call importStyles().

#### History:

* `v2.16.0`: Introduced.

#### Parameters:

* **`urls`:** (*string* | *Array<string>*) The URLs of the external stylesheets to import.  Loose URLs are imported concurrently, arrays of URLs are imported sequentially.

#### Examples:

##### Basic usage

```
// Import all stylesheets concurrently
importStyles(
	"https://somesite/a/path/a.css",
	"https://somesite/a/path/b.css",
	"https://somesite/a/path/c.css",
	"https://somesite/a/path/d.css"
);

// Import all stylesheets sequentially
importStyles([
	"https://somesite/a/path/a.css",
	"https://somesite/a/path/b.css",
	"https://somesite/a/path/c.css",
	"https://somesite/a/path/d.css"
]);

// Import stylesheets a.css, b.css, and the c.css/d.css group concurrently,
// while importing c.css and d.css sequentially relative to each other
importStyles(
	"https://somesite/a/path/a.css",
	"https://somesite/a/path/b.css",
	[
		"https://somesite/a/path/c.css",
		"https://somesite/a/path/d.css"
	]
);
```

##### Basic usage with the returned `Promise` object

```
// Grab a loading screen lock
var lsLockId = LoadScreen.lock();

// Import a stylesheet while using the returned Promise to ensure that the
// stylesheet has been fully loaded before unlocking the loading screen
importStyles("https://somesite/a/path/a.css")
	.then(function () {
		// The stylesheet has been loaded, release the loading screen lock.
		LoadScreen.unlock(lsLockId);
	})
	.catch(function (err) {
		// There was an error loading the stylesheet, log it to the console.
		console.log(err);
	});
```

### `memorize(key, value)` {#functions-function-memorize}

Sets the specified key and value within the story metadata store, which causes them to persist over story and browser restarts.  To update the value associated with a key, simply set it again.

Note:
The story metadata, like saves, is tied to the specific story it was generated with.  It is not a mechanism for moving data between stories.

Warning:
The story metadata store is not, and should not be used as, a replacement for saves.  Examples of good uses: achievement tracking, new game+ data, playthrough statistics, etc.

Warning:
This feature is largely incompatible with private browsing modes, which cause all in-browser storage mechanisms to either persist only for the lifetime of the browsing session or fail outright.

See Also:
forget(), recall().

#### History:

* `v2.29.0`: Introduced.

#### Parameters:

* **`key`:** (*string*) The key that should be set.
* **`value`:** (*any*) The value to set.

#### Examples:

```
// Sets 'achievements', with the given value, in the metadata store.
<<run memorize('achievements', { ateYellowSnow : true })>>

// Sets 'ngplus', with the given value, in the metadata store.
<<run memorize('ngplus', true)>>
```

### `passage()` → *string* {#functions-function-passage}

Returns the title of the active (present) passage.

#### History:

* `v2.0.0`: Introduced.

#### Parameters: *none*

#### Examples:

```
<<if passage() is "Café">>…the active passage is the Café passage…<</if>>
```

### `previous()` → *string* {#functions-function-previous}

Returns the title of the most recent previous passage whose title does not match that of the active passage or an empty string, if there is no such passage.

#### History:

* `v2.0.0`: Introduced.

#### Parameters: *none*

#### Examples:

```
<<if previous() is "Café">>…the most recent non-active passage is the Café passage…<</if>>

→ Commonly used as part of a link to return to the most recent non-active passage
[[Return|previous()]]
```

### `random([min ,] max)` → *integer* {#functions-function-random}

Returns a pseudo-random whole number (integer) within the range of the given bounds (inclusive)—i.e., [min, max].

Note:
By default, it uses Math.random() as its source of (non-deterministic) randomness, however, when the seedable PRNG has been enabled, via State.prng.init(), it uses that (deterministic) seeded PRNG instead.

#### History:

* `v2.0.0`: Introduced.

#### Parameters:

* **`min`:** (optional, *integer*) The lower bound of the random number (inclusive).  If omitted, will default to `0`.
* **`max`:** (*integer*) The upper bound of the random number (inclusive).

#### Examples:

```
random(5)     → Returns a number in the range 0–5
random(1, 6)  → Returns a number in the range 1–6
```

### `randomFloat([min ,] max)` → *float* {#functions-function-randomfloat}

Returns a pseudo-random decimal number (floating-point) within the range of the given bounds (inclusive for the minimum, exclusive for the maximum)—i.e., [min, max).

Note:
By default, it simply returns non-deterministic results from Math.random(), however, when the seedable PRNG has been enabled, via State.prng.init(), it returns deterministic results from the seeded PRNG instead.

#### History:

* `v2.0.0`: Introduced.

#### Parameters:

* **`min`:** (optional, *float*) The lower bound of the random number (inclusive).  If omitted, will default to `0.0`.
* **`max`:** (*float*) The upper bound of the random number (exclusive).

#### Examples:

```
randomFloat(5.0)       → Returns a number in the range 0.0–4.9999999…
randomFloat(1.0, 6.0)  → Returns a number in the range 1.0–5.9999999…
```

### `recall(key [, defaultValue])` → *any* {#functions-function-recall}

Returns the value associated with the specified key from the story metadata store or, if no such key exists, the specified default value, if any.

See Also:
forget(), memorize().

#### History:

* `v2.29.0`: Introduced.

#### Parameters:

* **`key`:** (*string*) The key whose value should be returned.
* **`defaultValue`:** (optional, *any*) The value to return if the key doesn't exist.

#### Examples:

```
// Set setup.achievements to the 'achievements' metadata or an empty generic object.
<<set setup.achievements to recall('achievements', {})>>

// Set setup.ngplus to the 'ngplus' metadata, with no default.
<<set setup.ngplus to recall('ngplus')>>
```

### `setPageElement(idOrElement , passages [, defaultText])` → *`HTMLElement` object* | *null* {#functions-function-setpageelement}

Renders the selected passage into the target element, replacing any existing content, and returns the element.  If no passages are found and default text is specified, it will be used instead.

#### History:

* `v2.0.0`: Introduced.

#### Parameters:

* **`idOrElement`:** (*string* | *`HTMLElement` object*) The ID of the element or the element itself.
* **`passages`:** (*string* | *Array<string>*) The name(s) of the passage(s) to search for.  May be a single passage or an array of passages.  If an array of passage names is specified, the first passage to be found is used.
* **`defaultText`:** (optional, *string*) The default text to use if no passages are found.

#### Examples:

Note:
As it is highly unlikely that either an array of passage names or default text will be needed in the vast majority of cases, only a few basic examples will be given.

```
// Using an ID; given an existing element on the page: <div id="my-display"></div>
setPageElement("my-display", "MyPassage");

// Using an element; given a reference to an existing element: myElement
setPageElement(myElement, "MyPassage");
```

### `tags([passages…])` → *Array<string>* {#functions-function-tags}

Returns a new array consisting of all of the tags of the given passages.

#### History:

* `v2.0.0`: Introduced.

#### Parameters:

* **`passages`:** (optional, *string* | *Array<string>*) The passages from which to collect tags.  May be a list or an array of passages.  If omitted, will default to the active (present) passage—included passages do not count for this purpose; e.g., passages pulled in via `<<include>>`, `PassageHeader`, etc.

#### Examples:

```
<<if tags().includes("forest")>>…the active passage is part of the forest…<</if>>
<<if tags("Lonely Glade").includes("forest")>>…the Lonely Glade passage is part of the forest…<</if>>
```

### `temporary()` → *object* {#functions-function-temporary}

Returns a reference to the current temporary variables store (equivalent to: [`State.temporary`](#state-api-getter-temporary)).  This is only really useful within pure JavaScript code, as within TwineScript you may simply access temporary variables natively.

#### History:

* `v2.19.0`: Introduced.

#### Parameters: *none*

#### Examples:

```
// Given: _selection is 'Zagnut Bar'
if (temporary().selection === 'Zagnut Bar') {
	/* Do something… */
}
```

### `time()` → *integer* {#functions-function-time}

Returns the number of milliseconds that have passed since the current passage was rendered to the page.

#### History:

* `v2.0.0`: Introduced.

#### Parameters: *none*

#### Examples:

```
→ Links that vary based on the time
In the darkness, something wicked this way comes.  Quickly!  Do you \
<<link "try to run back into the light">>
	<<if time() lt 5000>>
		/% The player clicked the link in under 5s, so they escape %/
		<<goto "Well lit passageway">>
	<<else>>
		/% Else, they're eaten by a grue %/
		<<goto "Eaten by a grue">>
	<</if>>
<</link>> \
or [[stand your ground|Eaten by a grue]]?
```

### `turns()` → *integer* {#functions-function-turns}

Returns the total number (count) of played turns currently in effect—i.e., the number of played moments up to the present moment; future (rewound/undone) moments are not included within the total.

#### History:

* `v2.0.0`: Introduced.

#### Parameters: *none*

#### Examples:

```
<<print "This is turn #" + turns()>>
```

### `variables()` → *object* {#functions-function-variables}

Returns a reference to the active (present) story variables store (equivalent to: [`State.variables`](#state-api-getter-variables)).  This is only really useful within pure JavaScript code, as within TwineScript you may simply access story variables natively.

#### History:

* `v2.0.0`: Introduced.

#### Parameters: *none*

#### Examples:

```
// Given: $hasGoldenKey is true
if (variables().hasGoldenKey) {
	/* Do something… */
}
```

### `visited([passages…])` → *integer* {#functions-function-visited}

Returns the number of times that the passage with the given title occurred within the story history.  If multiple passage titles are given, returns the lowest count.

#### History:

* `v2.0.0`: Introduced.

#### Parameters:

* **`passages`:** (optional, *string* | *Array<string>*) The title(s) of the passage(s) to search for.  May be a list or an array of passages.  If omitted, will default to the current passage.

#### Examples:

```
<<if visited() is 3>>…this is the third visit to the current passage…<</if>>
<<if visited("Bar")>>…has been to the Bar at least once…<</if>>
<<if visited("Café") is 1>>…has been to the Café exactly once…<</if>>
<<if visited("Bar", "Café") is 4>>…has been to both the Bar and Café at least four times…<</if>>
```

### `visitedTags(tags…)` → *integer* {#functions-function-visitedtags}

Returns the number of passages within the story history that are tagged with all of the given tags.

#### History:

* `v2.0.0`: Introduced.

#### Parameters:

* **`tags`:** (*string* | *Array<string>*) The tags to search for.  May be a list or an array of tags.

#### Examples:

```
<<if visitedTags("forest")>>…has been to some part of the forest at least once…<</if>>
<<if visitedTags("forest", "haunted") is 1>>…has been to the haunted part of the forest exactly once…<</if>>
<<if visitedTags("forest", "burned") is 3>>…has been to the burned part of the forest three times…<</if>>
```


code:
<!-- ***********************************************************************************************
	HTML
************************************************************************************************ -->
# <abbr title="HyperText Markup Language">HTML</abbr> {#html}

The hierarchy of the document body, including associated HTML IDs and class names is as follows.

#### Notes:

* Periods of ellipsis (`…`) signify data that is dynamically generated at run time.
* The `#story-title-separator` element is normally unused.
* The story menu, `#menu-story`, will only exist if the [`StoryMenu` special passage](#special-passage-storymenu) is used.
* The core menu item for the Settings dialog, `#menu-item-settings`, will only exist if the [`Setting` API](#setting-api) is used.
* The core menu item for the Share dialog, `#menu-item-share`, will only exist if the [`StoryShare` special passage](#special-passage-storyshare) is used.

```
<body class="…">
	<div id="init-screen"></div>
	<div id="ui-overlay" class="ui-close"></div>
	<div id="ui-dialog" tabindex="0" role="dialog" aria-labelledby="ui-dialog-title">
		<div id="ui-dialog-titlebar">
			<h1 id="ui-dialog-title"></h1>
			<button id="ui-dialog-close" class="ui-close" tabindex="0" aria-label="…"></button>
		</div>
		<div id="ui-dialog-body"></div>
	</div>
	<div id="ui-bar">
		<div id="ui-bar-tray">
			<button id="ui-bar-toggle" tabindex="0" title="…" aria-label="…"></button>
			<div id="ui-bar-history">
				<button id="history-backward" tabindex="0" title="…" aria-label="…">…</button>
				<button id="history-jumpto" tabindex="0" title="…" aria-label="…">…</button>
				<button id="history-forward" tabindex="0" title="…" aria-label="…">…</button>
			</div>
		</div>
		<div id="ui-bar-body">
			<header id="title" role="banner">
				<div id="story-banner"></div>
				<h1 id="story-title"></h1>
				<div id="story-subtitle"></div>
				<div id="story-title-separator"></div>
				<p id="story-author"></p>
			</header>
			<div id="story-caption"></div>
			<nav id="menu" role="navigation">
				<ul id="menu-story">…<ul>
				<ul id="menu-core">
					<li id="menu-item-saves"><a tabindex="0">…</a></li>
					<li id="menu-item-settings"><a tabindex="0">…</a></li>
					<li id="menu-item-restart"><a tabindex="0">…</a></li>
					<li id="menu-item-share"><a tabindex="0">…</a></li>
				</ul>
			</nav>
		</div>
	</div>
	<div id="story" role="main">
		<div id="passages">
			<div class="passage …" id="…" data-passage="…">
				<!-- The active (present) passage content -->
			</div>
		</div>
	</div>
	<!-- The story data chunk, which depends on the compiler release (see below) -->
	<script id="script-sugarcube" type="text/javascript"><!-- The main SugarCube module --></script>
</body>
```

#### Story data chunks:

Periods of ellipsis (`…`) signify data that is generated at compile time.

##### Twine 2 style data chunk

```
<tw-storydata name="…" startnode="…" creator="…" creator-version="…"
	ifid="…" zoom="…" format="…" format-version="…" options="…" hidden>
	<!-- Passage data nodes… -->
</tw-storydata>
```

##### Twine 1 style data chunk

```
<div id="store-area" data-size="…" hidden>
	<!-- Passage data nodes… -->
</div>
```