diff --git a/devTools/sugarcube.d.ts b/devTools/sugarcube.d.ts
index 740be661787f88418b8d299271e4c0fdbe6ec15e..e24730b925d5e1512cd86b7d6cba86169c7ed0c5 100644
--- a/devTools/sugarcube.d.ts
+++ b/devTools/sugarcube.d.ts
@@ -1,4 +1,4 @@
-declare namespace SugarCube {
+declare namespace SugarCubeLib {
 
 	type navigationOverride = (passageName: string) => any;
 	type saveObjectHander = (save: SaveObject) => void;
@@ -62,7 +62,7 @@ declare namespace SugarCube {
 			 * dialog to load the autosave, or a function, which causes the autosave to be loaded if its return value is truthy.
 
 			 NOTE: If the autosave cannot be loaded, for any reason, then the start passage is loaded instead.
-			 * @since v2.0.0
+			 * @since 2.0.0
 			 */
 			autoload: boolean | string | Function;
 
@@ -76,14 +76,14 @@ declare namespace SugarCube {
 			 * property to disallow saving on the start passage. Or, if you use the start passage as real part of your story and
 			 * allow the player to reenter it, rather than just as the initial landing/cover page, then you might wish to only
 			 * disallow saving on the start passage the very first time it's displayed (at story startup).
-			 * @since v2.0.0
+			 * @since 2.0.0
 			 */
 			autosave: boolean | string | string[];
 
 			/**
 			 * Sets the story ID associated with saves.
 			 * @default slugified story title
-			 * @since v2.0.0
+			 * @since 2.0.0
 			 * @example
 			 *  Config.saves.id = "a-big-huge-story-part-1";
 			 */
@@ -94,7 +94,7 @@ declare namespace SugarCube {
 			 * requested. If its return value is falsy, the save is disallowed. If its return value is truthy, the save is
 			 * allowed to continue unperturbed.
 			 * @default undefined
-			 * @since v2.0.0
+			 * @since 2.0.0
 			 * @example
 			 * Config.saves.isAllowed = function () {
 			 * // code
@@ -108,7 +108,7 @@ declare namespace SugarCube {
 			 * exception containing an error message; the message will be displayed to the player and loading of the save will
 			 * be terminated.
 			 * @default undefined
-			 * @since v2.0.0
+			 * @since 2.0.0
 			 * @example
 			 * Config.saves.onLoad = function (save) {
 			 * // code
@@ -122,7 +122,7 @@ declare namespace SugarCube {
 			 *
 			 * NOTE: See the save objects section of the Save API for information on the format of a save.
 			 * @default undefined
-			 * @since v2.0.0
+			 * @since 2.0.0
 			 * @example
 			 * Config.saves.onSave = function (save) {
 			 * // code
@@ -133,7 +133,7 @@ declare namespace SugarCube {
 			/**
 			 * Sets the maximum number of available save slots.
 			 * @default 8
-			 * @since v2.0.0
+			 * @since 2.0.0
 			 * @example
 			 * Config.saves.slots = 4;
 			 */
@@ -144,7 +144,7 @@ declare namespace SugarCube {
 			 *
 			 * NOTE: This completely optional property is only for developer use, it is ignored by SugarCube.
 			 *
-			 * @since v2.0.0
+			 * @since 2.0.0
 			 * @example
 			 * // As an integer
 			 * Config.saves.version = 3;
@@ -1285,714 +1285,753 @@ declare namespace SugarCube {
 		setVar(varName: string, value: any): boolean;
 	};
 
+	declare interface Wikifier {
+		createExternalLink(destination: string, url: string, text: string): HTMLElement;
+		createInternalLink(destination: string, passage: string, text: string, callback: () => void): HTMLElement;
+		evalExpression(code: string, output: any): any;
+		evalStatements(code: string, output: any): any;
+		/**
+		 * @see State.getVar
+		 */
+		getValue(varName: string): any;
+		/**
+		 * @see Story.has
+		 * @param link link
+		 */
+		isExternalLink(link: string): boolean;
+		parse(text: string): any;
+		/**
+		 * @see State.setVar
+		 */
+		setValue(varName: string, value: any): boolean;
+		wikifyEval(text: string): string;
+	};
+
 	declare interface ISugarCube {
 		Config: Config;
+		Macro: Macro;
 		State: State;
+		Story: Story;
+		/**
+		 * Player settings object, set up by the author/developer. See Setting API for more information.
+		 * @since 2.0.0
+		 */
+		settings: any;
+		/**
+		 * Object that authors/developers may use to set up various bits of static data.
+		 *
+		 * Generally, you would use this for data that does not change and should not be stored
+		 * within story variables, which would make it part of the history.
+		 * @since 2.0.0
+		 * */
+		setup: any;
+
+		Wikifier: Wikifier;
 	};
 }
 
-declare var SugarCube: SugarCube.ISugarCube;
-
-declare var Config: SugarCube.Config;
-declare var Macro: SugarCube.Macro;
-declare var State: SugarCube.State;
-declare var Story: SugarCube.Story;
-declare var setup: any;
-
-
-/**
- * Executed before the modification of the state history.
- * @since 2.0.0
- */
-declare var prehistory: Record<string, SugarCube.DisplayTaskFunction>;
-
-/**
- * Executed before the rendering of the incoming passage.
- * @since 2.0.0
- */
-declare var predisplay: Record<string, SugarCube.DisplayTaskFunction>;
-
-/**
- * Executed before the rendering of the incoming passage.
- * @since 2.0.0
- */
-declare var prerender: Record<string, SugarCube.RenderTaskFunction>;
-
-/**
- * Executed after the rendering of the incoming passage.
- * @since 2.0.0
- */
-declare var postrender: Record<string, SugarCube.RenderTaskFunction>;
-
-/**
- * Executed after the display (i.e. output) of the incoming passage.
- * @since 2.0.0
- */
-declare var postdisplay: Record<string, SugarCube.DisplayTaskFunction>;
-
-/**
- * A prototype-less generic object whose properties and values are defined by the Setting.addToggle(),
- * Setting.addList(), and Setting.addRange() methods.
- *
- * Normally, the values of its properties are automatically managed by their associated Settings dialog
- * control. If necessary, however, you may manually change their values—n.b. you'll need to call the
- * Setting.save() after having done so.
- * @since 2.0.0
- */
-declare var settings: any;
-
-
-// SugarCube functions
-
-/**
- * Returns a deep copy of the given value.
- *
- * @param original The object to 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 objects will need a .clone() method to be properly supported
- * by the cone() function—when called on such an object, it will simply defer to the local method.
- *
- * @since 2.0.0
- *
- * @example
- * // 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
- */
-declare function clone(original: any): any;
-
-/**
- * Returns a random value from its given arguments.
- *
- * @param list 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>.flatten() method may be used to flatten the nested arrays prior to passing them to
- * either().
- * @since 2.0.0
- * @example
- * // 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")
- */
-declare function either(...list: any): any;
-
-/**
- * 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).
- * @param passageNames The title(s) of the passage(s) to search for. May be a list or an array of passages.
- * @since 2.7.0
- * @example
- * <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>>
- */
-declare function hasVisited(...passageNames: string | string[]): boolean;
-
-/**
- * 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).
- * @param passageNames The title(s) of the passage(s) to search for. May be a list or an array of passages.
- * @since 2.0.0
- * @example
- * <<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>>
- */
-declare function lastVisited(...passageNames: string | string[]): number;
-
-/**
- * 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 the script is loaded before before it is needed.
- *
- * NOTE: A script section (Twine 2: the Story JavaScript; Twine 1/Twee: a script-tagged passage) is normally the best place
- * to call importScripts().
- *
- * @param urls The URLs of the external scripts to import. Loose URLs are imported concurrently, arrays of URLs are imported
- *  sequentially.
- *
- * @since 2.16.0
- *
- * @example 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"
- *   ]
- * );
- *
- * @example 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);
- * });
- *
- * @example <caption>Saving the returned Promise object for later use</caption>
- * // 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);
- * });
- */
-declare function importScripts(...urls: string | string[]): Promise;
-
-/**
- * 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 the stylesheet is loaded before it is needed.
- *
- * NOTE: A script section (Twine 2: the Story JavaScript; Twine 1/Twee: a script-tagged passage) is normally the best place
- * to call importStyles().
- * @param urls The URLs of the external stylesheets to import. Loose URLs are imported concurrently, arrays of URLs are imported sequentially.
- * @since 2.16.0
- * @example <caption>Basic usage</caption>
- * // 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"
- * 	 ]
- * );
- *
- * @example <caption>Basic usage with the returned Promise object</caption>
- * // 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);
- * });
- */
-declare function importStyles(...urls: string | string[]): Promise;
-
-/**
- * Returns the title of the active (present) passage.
- * @since 2.0.0
- * @example
- * <<if passage() is "Café">>…the current passage is the Café passage…<</if>>
- */
-declare function passage(): string;
-
-/**
- * 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.
- * @since 2.0.0
- * @example
- * <<if previous() is "Café">>…the most recent non-active passage is the Café passage…<</if>>
- * @example
- * // Commonly used as part of a link to return to the most recent non-active passage
- * [[Return|previous()]]
- */
-declare function previous(): string;
-
-/**
- * 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 randomness, however, when the seedable PRNG has been enabled,
- * via State.initPRNG(), it uses the seeded PRNG instead.
- * @param min The lower bound of the random number (inclusive). If omitted, will default to 0.
- * @param max The upper bound of the random number (inclusive).
- * @since 2.0.0
- * @example
- * random(5) // Returns a number in the range 0–5
- * random(1, 6) // Returns a number in the range 1–6
- */
-declare function random(min?: number, max: number): number;
-
-/**
- * Returns a pseudo-random real 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 uses Math.random() as its source of randomness, however, when the seedable PRNG has been enabled,
- * via State.initPRNG(), it uses the seeded PRNG instead.
- * @param min The lower bound of the random number (inclusive). If omitted, will default to 0.0.
- * @param max The upper bound of the random number (exclusive).
- * @since 2.0.0
- * @example
- * 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…
- */
-declare function randomFloat(min?: number, max: number): number;
-
-/**
- * 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.
- * @param idOrElement The ID of the element or the element itself.
- * @param passages 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.
- * @param defaultText The default text to use if no passages are found.
- *
- * @since 2.0.0
- *
- * 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.
- * @example
- * // Using an ID; given an existing element on the page: <div id="my-display"></div>
- * setPageElement("my-display", "MyPassage");
- * @example
- * // Using an element; given a reference to an existing element: myElement
- * setPageElement(myElement, "MyPassage");
- */
-declare function setPageElement(
-	idOrElement: string | HTMLElement,
-	passages: string | string[],
-	defaultText?: string): HTMLElement | null;
-
-/**
- * Returns a new array consisting of all of the tags of the given passages.
- * @param passages The passages from which to collect tags. May be a list or an array of passages. If omitted, will default
- * to the current passage.
- * @since 2.0.0
- * @example
- * <<if tags().includes("forest")>>…the current passage is part of the forest…<</if>>
- * <<if tags("Lonely Glade").includes("forest")>>…the Lonely Glade passage is part of the forest…<</if>>
- */
-declare function tags(...passages?: string | string[]): string[];
-
-/**
- * Returns a reference to the current temporary variables store (equivalent to: State.temporary). This is only really useful
- * within pure JavaScript code, as within TwineScript you may simply access temporary variables natively.
- * @since 2.19.0
- * @example
- * // Given: _selection is 'Zagnut Bar'
- * if (temporary().selection === 'Zagnut Bar') {
- *   // Do something...
- * }
- */
-declare function temporary(): object;
-
-/**
- * Returns the number of milliseconds which have passed since the current passage was rendered to the page.
- * @since 2.0.0
- * @example
- * // Links which 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]]?
- */
-declare function time(): number;
-
-/**
- * Returns the number of passages that the player has visited.
- * @since 2.0.0
- * @example
- * << print "This is turn #" + turns() >>
- */
-declare function turns(): number;
-
-/**
- * Returns a reference to the active(present) story variables store(equivalent to: State.variables).This is only really
- * useful within pure JavaScript code, as within TwineScript you may simply access story variables natively.
- * @since 2.0.0
- * @example
- * // Given: $hasGoldenKey is true
- * if (variables().hasGoldenKey) {
- *    //Do something
- * }
- */
-declare function variables(): object;
-
-/**
- * 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.
- * @param passages 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.
- * @since 2.0.0
- * @example
- * <<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>>
- */
-declare function visited(...passages?: string | string[]): number;
-
-/**
- * Returns the number of passages within the story history which are tagged with all of the given tags.
- * @param tags The tags to search for. May be a list or an array of tags.
- * @since 2.0.0
- * @example
- * <<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>>
- */
-declare function visitedTags(...tags: string | string[]): number;
-
-declare interface Array<T> {
+declare global {
+	declare var SugarCube: SugarCubeLib.ISugarCube;
+
+	declare let setup = SugarCube.setup;
 	/**
-	 * Concatenates one or more unique members to the end of the base array and returns the result as a new array. Does not modify the original.
-	 * @param members The members to concatenate. Members which are arrays will be merged—i.e. their members will be concatenated, rather than the array itself.
-	 * @since SugarCube 2.21.0
-	 * @example
-	 * // Given: $fruits1 = ["Apples", "Oranges"], $fruits2 = ["Pears", "Plums"]
-	 * $fruits1.concatUnique($fruits2)            → Returns ["Apples", "Oranges", "Pears", "Plums"]
-	 * $fruits1.concatUnique($fruits2, $fruits2)  → Returns ["Apples", "Oranges", "Pears", "Plums"]
-	 * $fruits1.concatUnique("Pears")             → Returns ["Apples", "Oranges", "Pears"]
-	 * $fruits1.concatUnique("Pears", "Pears")    → Returns ["Apples", "Oranges", "Pears"]
-	 * $fruits1.concatUnique($fruits2, "Pears")   → Returns ["Apples", "Oranges", "Pears", "Plums"]
+	 * A prototype-less generic object whose properties and values are defined by the Setting.addToggle(),
+	 * Setting.addList(), and Setting.addRange() methods.
+	 *
+	 * Normally, the values of its properties are automatically managed by their associated Settings dialog
+	 * control. If necessary, however, you may manually change their values—n.b. you'll need to call the
+	 * Setting.save() after having done so.
+	 * @since 2.0.0
 	 */
-	concatUnique(...members: any): T[];
-
+	declare let settings = SugarCube.settings;
+	declare let Config = SugarCube.Config;
+	declare let Macro = SugarCube.Macro;
+	declare let State = SugarCube.State;
+	declare let Story = SugarCube.Story;
+	declare let Wikifier = SugarCube.Wikifier;
 	/**
-	 * Returns the number of times that the given member was found within the array, starting the search at position.
-	 * @param needle The member to count.
-	 * @param position The zero-based index at which to begin searching for needle. If omitted, will default to 0.
-	 * @since SugarCube 2.0.0
-	 * @example
-	 * // Given: $fruits = ["Apples", "Oranges", "Plums", "Oranges"]
-	 * $fruits.count("Oranges")     → Returns 2
-	 * $fruits.count("Oranges", 2)  → Returns 1
+	 * Executed before the modification of the state history.
+	 * @since 2.0.0
 	 */
-	count(needle: any, position?: number): number;
-
+	declare let prehistory: Record<string, SugarCube.DisplayTaskFunction>;
 	/**
-	 * Removes all instances of the given members from the array and returns a new array containing the removed members.
-	 * @param needles The members to remove. May be a list of members or an array.
-	 * @returns new array
-	 * @since SugarCube 2.5.0
-	 * @example
-	 * // Given: $fruits = ["Apples", "Oranges", "Plums", "Oranges"]
-	 * $fruits.delete("Oranges")          → Returns ["Oranges", "Oranges"]; $fruits ["Apples", "Plums"]
-	 * $fruits.delete("Apples", "Plums")  → Returns ["Apples", "Plums"]; $fruits ["Oranges", "Oranges"]
+	 * Executed before the rendering of the incoming passage.
+	 * @since 2.0.0
 	 */
-	delete(...needles: any): T[];
+	declare let predisplay: Record<string, SugarCube.DisplayTaskFunction>;
 
 	/**
-	 * Removes all of the members at the given indices from the array and returns a new array containing the removed
-	 *  members.
-	 * @param indices The indices of the members to remove.
-	 * @sine SugarCube 2.5.0
-	 * @example
-	 * // Given: $fruits = ["Apples", "Oranges", "Plums", "Oranges"]
-	 * $fruits.deleteAt(2)     → Returns ["Plums"]; $fruits ["Apples", "Oranges", "Oranges"]
-	 * $fruits.deleteAt(1, 3)  → Returns ["Oranges", "Oranges"]; $fruits ["Apples", "Plums"]
-	 * $fruits.deleteAt(0, 2)  → Returns ["Apples", "Plums"]; $fruits ["Oranges", "Oranges"]
+	 * Executed before the rendering of the incoming passage.
+	 * @since 2.0.0
 	 */
-	deleteAt(...indices: number | number[]): T[];
+	declare let prerender: Record<string, SugarCube.RenderTaskFunction>;
 
 	/**
-	 * Removes all of the members that pass the test implemented by the given predicate function from the array and returns
-	 * a new array containing the removed members.
-	 * @param predicate The function used to test each member. It is called with three arguments:
-	 * value: The member being processed.
-	 * index: (optional, integer) The index of member being processed.
-	 * array: (optional, array) The array being processed.
-	 * @param thisArg The value to use as this when executing predicate.
-	 * @example
-	 * // Given: $fruits = ["Apples", "Apricots", "Oranges"]
-	 * $fruits.deleteWith(function (val) {
-	 *    return val === "Apricots";
-	 * }) // Returns ["Apricots"];
-	 * // and now $fruits is ["Apples", "Oranges"]
-	 *
-	 * $fruits.deleteWith(function (val) {
-	 * 	return val.startsWith("Ap");
-	 * }) // Returns ["Apples", "Apricots"];
-	 * // and now $fruits is ["Oranges"]
-	 *
-	 * // Given: $fruits = [{ name : "Apples" }, { name : "Apricots" }, { name : "Oranges" }]
-	 * $fruits.deleteWith(function (val) {
-	 *     return val.name === "Apricots";
-	 * }) // Returns [{ name : "Apricots" }]; $fruits [{ name : "Apples" }, { name : "Oranges" }]
-	 *
-	 * $fruits.deleteWith(function (val) {
-	 *     return val.name.startsWith("Ap");
-	 * }) // Returns [{ name : "Apples" }, { name : "Apricots" }];
-	 * // and now $fruits is [{ name : "Oranges" }]
+	 * Executed after the rendering of the incoming passage.
+	 * @since 2.0.0
 	 */
-	deleteWith(predicate: (value: T, index?: number, array?: T[]) => boolean, thisArg?: T[]): T[];
+	declare let postrender: Record<string, SugarCube.RenderTaskFunction>;
 
 	/**
-	 * Returns the first member from the array. Does not modify the original.
-	 * @since SugarCube 2.2.7.0
-	 * @example
-	 * // Given: $pies = ["Blueberry", "Cherry", "Cream", "Pecan", "Pumpkin"]
-	 * $pies.first() // Returns "Blueberry"
+	 * Executed after the display (i.e. output) of the incoming passage.
+	 * @since 2.0.0
 	 */
-	first(): T;
+	declare let postdisplay: Record<string, SugarCube.DisplayTaskFunction>;
+
+	// SugarCube functions
 
 	/**
-	 * Returns a new array consisting of the flattened source array (i.e. flat map reduce). Does not modify the original.
-	 * @since SugarCube 2.0.0
+	 * Returns a deep copy of the given value.
+	 *
+	 * @param original The object to 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 objects will need a .clone() method to be properly supported
+	 * by the cone() function—when called on such an object, it will simply defer to the local method.
+	 *
+	 * @since 2.0.0
+	 *
 	 * @example
-	 * // Given: $npa = [["Alfa", "Bravo"], [["Charlie", "Delta"], ["Echo"]], "Foxtrot"]
-	 * $npa.flatten() //  Returns ["Alfa", "Bravo", "Charlie", "Delta", "Echo", "Foxtrot"]
+	 * // 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
 	 */
-	flatten(): T[];
+	declare function clone(original: any): any;
 
 	/**
-	 * Returns whether all of the given members were found within the array.
-	 * @param needles The members to find. May be a list of members or an array.
-	 * @since SugarCube 2.10.0
-	 * @example
-	 * // Given: $pies = ["Blueberry", "Cherry", "Cream", "Pecan", "Pumpkin"]
-	 * <<if $pies.includesAll("Cherry", "Pecan")>>…found Cherry and Pecan pies…<</if>>
+	 * Returns a random value from its given arguments.
+	 *
+	 * @param list 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>.flatten() method may be used to flatten the nested arrays prior to passing them to
+	 * either().
+	 * @since 2.0.0
 	 * @example
-	 * // Given: $search = ["Blueberry", "Pumpkin"]
-	 * <<if $pies.includesAll($search)>>…found Blueberry and Pumpkin pies…<</if>>
+	 * // 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")
 	 */
-	includesAll(...needles: T | T[]): boolean;
+	declare function either(...list: any): any;
 
 	/**
-	 * Returns whether any of the given members were found within the array.
-	 * @param needles The members to find. May be a list of members or an array.
-	 * @since SugarCube 2.10.0
-	 * @example
-	 * // Given: $pies = ["Blueberry", "Cherry", "Cream", "Pecan", "Pumpkin"]
-	 * <<if $pies.includesAny("Cherry", "Pecan")>>…found Cherry or Pecan pie…<</if>>
+	 * 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).
+	 * @param passageNames The title(s) of the passage(s) to search for. May be a list or an array of passages.
+	 * @since 2.7.0
 	 * @example
-	 * // Given: $search = ["Blueberry", "Pumpkin"]
-	 * <<if $pies.includesAny($search)>>…found Blueberry or Pumpkin pie…<</if>>
+	 * <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>>
 	 */
-	includesAny(...needles: T | T[]): boolean;
+	declare function hasVisited(...passageNames: string | string[]): boolean;
 
 	/**
-	 * Returns the last member from the array. Does not modify the original.
-	 * @since SugarCube 2.27.0
+	 * 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).
+	 * @param passageNames The title(s) of the passage(s) to search for. May be a list or an array of passages.
+	 * @since 2.0.0
 	 * @example
-	 * // Given: $pies = ["Blueberry", "Cherry", "Cream", "Pecan", "Pumpkin"]
-	 * $pies.last() // Returns "Pumpkin"
+	 * <<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>>
 	 */
-	last(): T;
+	declare function lastVisited(...passageNames: string | string[]): number;
 
 	/**
-	 * Removes and returns a random member from the array.
-	 * @since SugarCube 2.0.0
-	 * @example
-	 * // Given: $pies = ["Blueberry", "Cherry", "Cream", "Pecan", "Pumpkin"]
-	 * $pies.pluck() // Removes and returns a random pie from the array
+	 * 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 the script is loaded before before it is needed.
+	 *
+	 * NOTE: A script section (Twine 2: the Story JavaScript; Twine 1/Twee: a script-tagged passage) is normally the best place
+	 * to call importScripts().
+	 *
+	 * @param urls The URLs of the external scripts to import. Loose URLs are imported concurrently, arrays of URLs are imported
+	 *  sequentially.
+	 *
+	 * @since 2.16.0
+	 *
+	 * @example 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"
+	 *   ]
+	 * );
+	 *
+	 * @example 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);
+	 * });
+	 *
+	 * @example <caption>Saving the returned Promise object for later use</caption>
+	 * // 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);
+	 * });
 	 */
-	pluck(): T;
+	declare function importScripts(...urls: string | string[]): Promise;
 
 	/**
-	 * Randomly removes the given number of members from the base array and returns the removed members as a new array.
-	 * @param want The number of members to pluck.
-	 * @since SugarCube 2.20.0
-	 * @example
-	 * // Given: $pies = ["Blueberry", "Cherry", "Cream", "Pecan", "Pumpkin"]
-	 * $pies.pluckMany(3) // Removes three random pies from the array and returns them as a new array
+	 * 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 the stylesheet is loaded before it is needed.
+	 *
+	 * NOTE: A script section (Twine 2: the Story JavaScript; Twine 1/Twee: a script-tagged passage) is normally the best place
+	 * to call importStyles().
+	 * @param urls The URLs of the external stylesheets to import. Loose URLs are imported concurrently, arrays of URLs are imported sequentially.
+	 * @since 2.16.0
+	 * @example <caption>Basic usage</caption>
+	 * // 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"
+	 * 	 ]
+	 * );
+	 *
+	 * @example <caption>Basic usage with the returned Promise object</caption>
+	 * // 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);
+	 * });
 	 */
-	pluckMany(want?: number): T[];
+	declare function importStyles(...urls: string | string[]): Promise;
 
 	/**
-	 * Appends one or more unique members to the end of the base array and returns its new length.
-	 * @param members The members to append.
-	 * @since 2.21.0
+	 * Returns the title of the active (present) passage.
+	 * @since 2.0.0
 	 * @example
-	 * // Given: $fruits = ["Apples", "Oranges"]
-	 * $fruits.pushUnique("Apples") // Returns 2; $fruits ["Apples", "Oranges"]
-	 * $fruits.pushUnique("Plums", "Plums") // Returns 3; $fruits ["Apples", "Oranges", "Plums"]
+	 * <<if passage() is "Café">>…the current passage is the Café passage…<</if>>
 	 */
-	pushUnique(...members): number;
+	declare function passage(): string;
 
 	/**
-	 * Returns a random member from the array. Does not modify the original.
-	 * @since SugarCube 2.0.0
+	 * 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.
+	 * @since 2.0.0
+	 * @example
+	 * <<if previous() is "Café">>…the most recent non-active passage is the Café passage…<</if>>
 	 * @example
-	 * // Given: $pies = ["Blueberry", "Cherry", "Cream", "Pecan", "Pumpkin"]
-	 * $pies.random() // Returns a random pie from the array
+	 * // Commonly used as part of a link to return to the most recent non-active passage
+	 * [[Return|previous()]]
 	 */
-	random(): T;
+	declare function previous(): string;
 
 	/**
-	 * Randomly selects the given number of unique members from the array and returns the selected members as a new array.
-	 * Does not modify the original.
-	 * @param want The number of members to select.
-	 * @since SugarCube 2.20.0
+	 * 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 randomness, however, when the seedable PRNG has been enabled,
+	 * via State.initPRNG(), it uses the seeded PRNG instead.
+	 * @param min The lower bound of the random number (inclusive). If omitted, will default to 0.
+	 * @param max The upper bound of the random number (inclusive).
+	 * @since 2.0.0
 	 * @example
-	 * // Given: $pies = ["Blueberry", "Cherry", "Cream", "Pecan", "Pumpkin"]
-	 * $pies.randomMany(3) // Returns a new array containing three unique random pies from the array
+	 * random(5) // Returns a number in the range 0–5
+	 * random(1, 6) // Returns a number in the range 1–6
 	 */
-	randomMany(want?: number): T[];
+	declare function random(min?: number, max: number): number;
 
 	/**
-	 * Randomly shuffles the array.
-	 * @since SugarCube 2.0.0
+	 * Returns a pseudo-random real 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 uses Math.random() as its source of randomness, however, when the seedable PRNG has been enabled,
+	 * via State.initPRNG(), it uses the seeded PRNG instead.
+	 * @param min The lower bound of the random number (inclusive). If omitted, will default to 0.0.
+	 * @param max The upper bound of the random number (exclusive).
+	 * @since 2.0.0
 	 * @example
-	 * // Given: $pies = ["Blueberry", "Cherry", "Cream", "Pecan", "Pumpkin"]
-	 * $pies.shuffle() // Randomizes the order of the pies in the array
+	 * 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…
 	 */
-	shuffle(): T[];
-
+	declare function randomFloat(min?: number, max: number): number;
 
 	/**
-	 * Prepends one or more unique members to the beginning of the base array and returns its new length.
-	 * @param members The members to append.
-	 * @since SugarCube 2.21.0
+	 * 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.
+	 * @param idOrElement The ID of the element or the element itself.
+	 * @param passages 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.
+	 * @param defaultText The default text to use if no passages are found.
+	 *
+	 * @since 2.0.0
+	 *
+	 * 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.
+	 * @example
+	 * // Using an ID; given an existing element on the page: <div id="my-display"></div>
+	 * setPageElement("my-display", "MyPassage");
 	 * @example
-	 * // Given: $fruits = ["Oranges", "Plums"]
-	 * $fruits.unshiftUnique("Oranges") // Returns 2; $fruits ["Oranges", "Plums"]
-	 * $fruits.unshiftUnique("Apples", "Apples") // Returns 3; $fruits ["Apples", "Oranges", "Plums"]
+	 * // Using an element; given a reference to an existing element: myElement
+	 * setPageElement(myElement, "MyPassage");
 	 */
-	unshiftUnique(...members?: T): number;
-
-	// deprecated members
+	declare function setPageElement(
+		idOrElement: string | HTMLElement,
+		passages: string | string[],
+		defaultText?: string): HTMLElement | null;
 
 	/**
-	 *
-	 * @param needle
-	 * @param position
-	 * @deprecated in favor of <Array>.includes().
+	 * Returns a new array consisting of all of the tags of the given passages.
+	 * @param passages The passages from which to collect tags. May be a list or an array of passages. If omitted, will default
+	 * to the current passage.
+	 * @since 2.0.0
+	 * @example
+	 * <<if tags().includes("forest")>>…the current passage is part of the forest…<</if>>
+	 * <<if tags("Lonely Glade").includes("forest")>>…the Lonely Glade passage is part of the forest…<</if>>
 	 */
-	contains(needle: any, position?: number): boolean;
+	declare function tags(...passages?: string | string[]): string[];
 
 	/**
-	 *
-	 * @param needle
-	 * @deprecated in favor of <Array>.includesAll().
+	 * Returns a reference to the current temporary variables store (equivalent to: State.temporary). This is only really useful
+	 * within pure JavaScript code, as within TwineScript you may simply access temporary variables natively.
+	 * @since 2.19.0
+	 * @example
+	 * // Given: _selection is 'Zagnut Bar'
+	 * if (temporary().selection === 'Zagnut Bar') {
+	 *   // Do something...
+	 * }
 	 */
-	containsAll(...needle): boolean;
+	declare function temporary(): object;
 
 	/**
-	 *
-	 * @param needle
-	 * @deprecated in favor of <Array>.includesAny().
+	 * Returns the number of milliseconds which have passed since the current passage was rendered to the page.
+	 * @since 2.0.0
+	 * @example
+	 * // Links which 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]]?
 	 */
-	containsAny(...needle): boolean;
+	declare function time(): number;
 
 	/**
-	 *
-	 * @param array
-	 * @deprecated
+	 * Returns the number of passages that the player has visited.
+	 * @since 2.0.0
+	 * @example
+	 * << print "This is turn #" + turns() >>
 	 */
-	random(array: []): any;
-}
-
+	declare function turns(): number;
 
-interface JSON {
 	/**
-	 * Returns the given code string, and optional data chunk, wrapped within the JSON deserialization revive wrapper.
-	 * Intended to allow authors to easily wrap their custom object types (a.k.a. classes) revival code and associated data
-	 * within the revive wrapper, which should be returned from an object instance's .toJSON() method, so that the instance
-	 * may be properly revived upon deserialization.
-	 * @param codeString The revival code string to wrap.
-	 * @param reviveData he data which should be made available to the evaluated revival code during deserialization via the
-	 * special $ReviveData$ variable. WARNING: Attempting to pass the value of an object instance's this directly as the
-	 * reviveData parameter will trigger out of control recursion in the serializer, so a clone of the instance's own data
-	 * must be passed instead.
-	 * @since SugarCube 2.9.0
+	 * Returns a reference to the active(present) story variables store(equivalent to: State.variables).This is only really
+	 * useful within pure JavaScript code, as within TwineScript you may simply access story variables natively.
+	 * @since 2.0.0
 	 * @example
-	 * JSON.reviveWrapper( <valid JavaScript code string> ); // -> Without data chunk
-	 * JSON.reviveWrapper( <valid JavaScript code string> , myOwnData); // -> With data chunk
-	 * // E.g. Assume that you're attempting to revive an instance of a custom class named
-	 * //      `Character`, which is assigned to a story variable named `$pc`.  The call
-	 * //      to `JSON.reviveWrapper()` might look something like the following.
-	 * var ownData = {};
-	 * Object.keys(this).forEach(function (pn) { ownData[pn] = clone(this[pn]); }, this);
-	 * return JSON.reviveWrapper('new Character($ReviveData$)', ownData);
+	 * // Given: $hasGoldenKey is true
+	 * if (variables().hasGoldenKey) {
+	 *    //Do something
+	 * }
 	 */
-	reviveWrapper(codeString: strin, reviveData?: any): [];
-}
+	declare function variables(): object;
 
-interface Math {
 	/**
-	 * Returns the given number clamped to the specified bounds. Does not modify the original.
-	 * @param num The number to clamp. May be an actual number or a numerical string.
-	 * @param min The lower bound of the number.
-	 * @param max The upper bound of the number.
-	 * @since SugarCube 2.0.0
+	 * 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.
+	 * @param passages 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.
+	 * @since 2.0.0
 	 * @example
-	 * Math.clamp($stat, 0, 200) // Clamps $stat to the bounds 0–200 and returns the new value
-	 * Math.clamp($stat, 1, 6.6) // Clamps $stat to the bounds 1–6.6 and returns the new value
+	 * <<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>>
 	 */
-	static clamp(num: number | string, min: number, max: number): number;
+	declare function visited(...passages?: string | string[]): number;
 
 	/**
-	 * Returns the whole(integer) part of the given number by removing its fractional part, if any. Does not modify the
-	 * original.
-	 * @param num The number to truncate to an integer.
-	 * @since SugarCube 2.0.0
+	 * Returns the number of passages within the story history which are tagged with all of the given tags.
+	 * @param tags The tags to search for. May be a list or an array of tags.
+	 * @since 2.0.0
 	 * @example
-	 * Math.trunc(12.7) // Returns 12
-	 * Math.trunc(-12.7) // Returns -12
+	 * <<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>>
 	 */
-	static trunc(num: number): number;
+	declare function visitedTags(...tags: string | string[]): number;
+
+	declare interface Array<T> {
+		/**
+		 * Concatenates one or more unique members to the end of the base array and returns the result as a new array. Does not modify the original.
+		 * @param members The members to concatenate. Members which are arrays will be merged—i.e. their members will be concatenated, rather than the array itself.
+		 * @since SugarCube 2.21.0
+		 * @example
+		 * // Given: $fruits1 = ["Apples", "Oranges"], $fruits2 = ["Pears", "Plums"]
+		 * $fruits1.concatUnique($fruits2)            → Returns ["Apples", "Oranges", "Pears", "Plums"]
+		 * $fruits1.concatUnique($fruits2, $fruits2)  → Returns ["Apples", "Oranges", "Pears", "Plums"]
+		 * $fruits1.concatUnique("Pears")             → Returns ["Apples", "Oranges", "Pears"]
+		 * $fruits1.concatUnique("Pears", "Pears")    → Returns ["Apples", "Oranges", "Pears"]
+		 * $fruits1.concatUnique($fruits2, "Pears")   → Returns ["Apples", "Oranges", "Pears", "Plums"]
+		 */
+		concatUnique(...members: any): T[];
+
+		/**
+		 * Returns the number of times that the given member was found within the array, starting the search at position.
+		 * @param needle The member to count.
+		 * @param position The zero-based index at which to begin searching for needle. If omitted, will default to 0.
+		 * @since SugarCube 2.0.0
+		 * @example
+		 * // Given: $fruits = ["Apples", "Oranges", "Plums", "Oranges"]
+		 * $fruits.count("Oranges")     → Returns 2
+		 * $fruits.count("Oranges", 2)  → Returns 1
+		 */
+		count(needle: any, position?: number): number;
+
+		/**
+		 * Removes all instances of the given members from the array and returns a new array containing the removed members.
+		 * @param needles The members to remove. May be a list of members or an array.
+		 * @returns new array
+		 * @since SugarCube 2.5.0
+		 * @example
+		 * // Given: $fruits = ["Apples", "Oranges", "Plums", "Oranges"]
+		 * $fruits.delete("Oranges")          → Returns ["Oranges", "Oranges"]; $fruits ["Apples", "Plums"]
+		 * $fruits.delete("Apples", "Plums")  → Returns ["Apples", "Plums"]; $fruits ["Oranges", "Oranges"]
+		 */
+		delete(...needles: any): T[];
+
+		/**
+		 * Removes all of the members at the given indices from the array and returns a new array containing the removed
+		 *  members.
+		 * @param indices The indices of the members to remove.
+		 * @sine SugarCube 2.5.0
+		 * @example
+		 * // Given: $fruits = ["Apples", "Oranges", "Plums", "Oranges"]
+		 * $fruits.deleteAt(2)     → Returns ["Plums"]; $fruits ["Apples", "Oranges", "Oranges"]
+		 * $fruits.deleteAt(1, 3)  → Returns ["Oranges", "Oranges"]; $fruits ["Apples", "Plums"]
+		 * $fruits.deleteAt(0, 2)  → Returns ["Apples", "Plums"]; $fruits ["Oranges", "Oranges"]
+		 */
+		deleteAt(...indices: number | number[]): T[];
+
+		/**
+		 * Removes all of the members that pass the test implemented by the given predicate function from the array and returns
+		 * a new array containing the removed members.
+		 * @param predicate The function used to test each member. It is called with three arguments:
+		 * value: The member being processed.
+		 * index: (optional, integer) The index of member being processed.
+		 * array: (optional, array) The array being processed.
+		 * @param thisArg The value to use as this when executing predicate.
+		 * @example
+		 * // Given: $fruits = ["Apples", "Apricots", "Oranges"]
+		 * $fruits.deleteWith(function (val) {
+		 *    return val === "Apricots";
+		 * }) // Returns ["Apricots"];
+		 * // and now $fruits is ["Apples", "Oranges"]
+		 *
+		 * $fruits.deleteWith(function (val) {
+		 * 	return val.startsWith("Ap");
+		 * }) // Returns ["Apples", "Apricots"];
+		 * // and now $fruits is ["Oranges"]
+		 *
+		 * // Given: $fruits = [{ name : "Apples" }, { name : "Apricots" }, { name : "Oranges" }]
+		 * $fruits.deleteWith(function (val) {
+		 *     return val.name === "Apricots";
+		 * }) // Returns [{ name : "Apricots" }]; $fruits [{ name : "Apples" }, { name : "Oranges" }]
+		 *
+		 * $fruits.deleteWith(function (val) {
+		 *     return val.name.startsWith("Ap");
+		 * }) // Returns [{ name : "Apples" }, { name : "Apricots" }];
+		 * // and now $fruits is [{ name : "Oranges" }]
+		 */
+		deleteWith(predicate: (value: T, index?: number, array?: T[]) => boolean, thisArg?: T[]): T[];
+
+		/**
+		 * Returns the first member from the array. Does not modify the original.
+		 * @since SugarCube 2.2.7.0
+		 * @example
+		 * // Given: $pies = ["Blueberry", "Cherry", "Cream", "Pecan", "Pumpkin"]
+		 * $pies.first() // Returns "Blueberry"
+		 */
+		first(): T;
+
+		/**
+		 * Returns a new array consisting of the flattened source array (i.e. flat map reduce). Does not modify the original.
+		 * @since SugarCube 2.0.0
+		 * @example
+		 * // Given: $npa = [["Alfa", "Bravo"], [["Charlie", "Delta"], ["Echo"]], "Foxtrot"]
+		 * $npa.flatten() //  Returns ["Alfa", "Bravo", "Charlie", "Delta", "Echo", "Foxtrot"]
+		 */
+		flatten(): T[];
+
+		/**
+		 * Returns whether all of the given members were found within the array.
+		 * @param needles The members to find. May be a list of members or an array.
+		 * @since SugarCube 2.10.0
+		 * @example
+		 * // Given: $pies = ["Blueberry", "Cherry", "Cream", "Pecan", "Pumpkin"]
+		 * <<if $pies.includesAll("Cherry", "Pecan")>>…found Cherry and Pecan pies…<</if>>
+		 * @example
+		 * // Given: $search = ["Blueberry", "Pumpkin"]
+		 * <<if $pies.includesAll($search)>>…found Blueberry and Pumpkin pies…<</if>>
+		 */
+		includesAll(...needles: T | T[]): boolean;
+
+		/**
+		 * Returns whether any of the given members were found within the array.
+		 * @param needles The members to find. May be a list of members or an array.
+		 * @since SugarCube 2.10.0
+		 * @example
+		 * // Given: $pies = ["Blueberry", "Cherry", "Cream", "Pecan", "Pumpkin"]
+		 * <<if $pies.includesAny("Cherry", "Pecan")>>…found Cherry or Pecan pie…<</if>>
+		 * @example
+		 * // Given: $search = ["Blueberry", "Pumpkin"]
+		 * <<if $pies.includesAny($search)>>…found Blueberry or Pumpkin pie…<</if>>
+		 */
+		includesAny(...needles: T | T[]): boolean;
+
+		/**
+		 * Returns the last member from the array. Does not modify the original.
+		 * @since SugarCube 2.27.0
+		 * @example
+		 * // Given: $pies = ["Blueberry", "Cherry", "Cream", "Pecan", "Pumpkin"]
+		 * $pies.last() // Returns "Pumpkin"
+		 */
+		last(): T;
+
+		/**
+		 * Removes and returns a random member from the array.
+		 * @since SugarCube 2.0.0
+		 * @example
+		 * // Given: $pies = ["Blueberry", "Cherry", "Cream", "Pecan", "Pumpkin"]
+		 * $pies.pluck() // Removes and returns a random pie from the array
+		 */
+		pluck(): T;
+
+		/**
+		 * Randomly removes the given number of members from the base array and returns the removed members as a new array.
+		 * @param want The number of members to pluck.
+		 * @since SugarCube 2.20.0
+		 * @example
+		 * // Given: $pies = ["Blueberry", "Cherry", "Cream", "Pecan", "Pumpkin"]
+		 * $pies.pluckMany(3) // Removes three random pies from the array and returns them as a new array
+		 */
+		pluckMany(want?: number): T[];
+
+		/**
+		 * Appends one or more unique members to the end of the base array and returns its new length.
+		 * @param members The members to append.
+		 * @since 2.21.0
+		 * @example
+		 * // Given: $fruits = ["Apples", "Oranges"]
+		 * $fruits.pushUnique("Apples") // Returns 2; $fruits ["Apples", "Oranges"]
+		 * $fruits.pushUnique("Plums", "Plums") // Returns 3; $fruits ["Apples", "Oranges", "Plums"]
+		 */
+		pushUnique(...members): number;
+
+		/**
+		 * Returns a random member from the array. Does not modify the original.
+		 * @since SugarCube 2.0.0
+		 * @example
+		 * // Given: $pies = ["Blueberry", "Cherry", "Cream", "Pecan", "Pumpkin"]
+		 * $pies.random() // Returns a random pie from the array
+		 */
+		random(): T;
+
+		/**
+		 * Randomly selects the given number of unique members from the array and returns the selected members as a new array.
+		 * Does not modify the original.
+		 * @param want The number of members to select.
+		 * @since SugarCube 2.20.0
+		 * @example
+		 * // Given: $pies = ["Blueberry", "Cherry", "Cream", "Pecan", "Pumpkin"]
+		 * $pies.randomMany(3) // Returns a new array containing three unique random pies from the array
+		 */
+		randomMany(want?: number): T[];
+
+		/**
+		 * Randomly shuffles the array.
+		 * @since SugarCube 2.0.0
+		 * @example
+		 * // Given: $pies = ["Blueberry", "Cherry", "Cream", "Pecan", "Pumpkin"]
+		 * $pies.shuffle() // Randomizes the order of the pies in the array
+		 */
+		shuffle(): T[];
+
+
+		/**
+		 * Prepends one or more unique members to the beginning of the base array and returns its new length.
+		 * @param members The members to append.
+		 * @since SugarCube 2.21.0
+		 * @example
+		 * // Given: $fruits = ["Oranges", "Plums"]
+		 * $fruits.unshiftUnique("Oranges") // Returns 2; $fruits ["Oranges", "Plums"]
+		 * $fruits.unshiftUnique("Apples", "Apples") // Returns 3; $fruits ["Apples", "Oranges", "Plums"]
+		 */
+		unshiftUnique(...members?: T): number;
+
+		// deprecated members
+
+		/**
+		 *
+		 * @param needle
+		 * @param position
+		 * @deprecated in favor of <Array>.includes().
+		 */
+		contains(needle: any, position?: number): boolean;
+
+		/**
+		 *
+		 * @param needle
+		 * @deprecated in favor of <Array>.includesAll().
+		 */
+		containsAll(...needle): boolean;
+
+		/**
+		 *
+		 * @param needle
+		 * @deprecated in favor of <Array>.includesAny().
+		 */
+		containsAny(...needle): boolean;
+
+		/**
+		 *
+		 * @param array
+		 * @deprecated
+		 */
+		random(array: []): any;
+	}
+
+
+	interface JSON {
+		/**
+		 * Returns the given code string, and optional data chunk, wrapped within the JSON deserialization revive wrapper.
+		 * Intended to allow authors to easily wrap their custom object types (a.k.a. classes) revival code and associated data
+		 * within the revive wrapper, which should be returned from an object instance's .toJSON() method, so that the instance
+		 * may be properly revived upon deserialization.
+		 * @param codeString The revival code string to wrap.
+		 * @param reviveData he data which should be made available to the evaluated revival code during deserialization via the
+		 * special $ReviveData$ variable. WARNING: Attempting to pass the value of an object instance's this directly as the
+		 * reviveData parameter will trigger out of control recursion in the serializer, so a clone of the instance's own data
+		 * must be passed instead.
+		 * @since SugarCube 2.9.0
+		 * @example
+		 * JSON.reviveWrapper( <valid JavaScript code string> ); // -> Without data chunk
+		 * JSON.reviveWrapper( <valid JavaScript code string> , myOwnData); // -> With data chunk
+		 * // E.g. Assume that you're attempting to revive an instance of a custom class named
+		 * //      `Character`, which is assigned to a story variable named `$pc`.  The call
+		 * //      to `JSON.reviveWrapper()` might look something like the following.
+		 * var ownData = {};
+		 * Object.keys(this).forEach(function (pn) { ownData[pn] = clone(this[pn]); }, this);
+		 * return JSON.reviveWrapper('new Character($ReviveData$)', ownData);
+		 */
+		reviveWrapper(codeString: strin, reviveData?: any): [];
+	}
+
+	interface Math {
+		/**
+		 * Returns the given number clamped to the specified bounds. Does not modify the original.
+		 * @param num The number to clamp. May be an actual number or a numerical string.
+		 * @param min The lower bound of the number.
+		 * @param max The upper bound of the number.
+		 * @since SugarCube 2.0.0
+		 * @example
+		 * Math.clamp($stat, 0, 200) // Clamps $stat to the bounds 0–200 and returns the new value
+		 * Math.clamp($stat, 1, 6.6) // Clamps $stat to the bounds 1–6.6 and returns the new value
+		 */
+		static clamp(num: number | string, min: number, max: number): number;
+
+		/**
+		 * Returns the whole(integer) part of the given number by removing its fractional part, if any. Does not modify the
+		 * original.
+		 * @param num The number to truncate to an integer.
+		 * @since SugarCube 2.0.0
+		 * @example
+		 * Math.trunc(12.7) // Returns 12
+		 * Math.trunc(-12.7) // Returns -12
+		 */
+		static trunc(num: number): number;
+	}
 }
+
+export { };