diff --git a/package.json b/package.json
index d0bb28b8..f9c66a02 100644
--- a/package.json
+++ b/package.json
@@ -13,7 +13,8 @@
"lint:test": "eslint ./test/**/*.test.js --fix",
"build:web": "webpack",
"build:bin": "esbuild ./src/extwee.js --bundle --platform=node --target=node12 --outfile=out.js && pkg -t node18-macos-x64 out.js --output ./build/extwee && rm out.js",
- "all": "npm run lint && npm run lint:test && npm run test"
+ "gen-types": "npx -p typescript tsc src/**/*.js --declaration --allowJs --emitDeclarationOnly --outDir types",
+ "all": "npm run lint && npm run lint:test && npm run test && npm run gen-types"
},
"keywords": [
"twine",
diff --git a/types/IFID/generate.d.ts b/types/IFID/generate.d.ts
new file mode 100644
index 00000000..d83b027d
--- /dev/null
+++ b/types/IFID/generate.d.ts
@@ -0,0 +1,14 @@
+/**
+ * Generates an Interactive Fiction Identification (IFID) based the Treaty of Babel.
+ *
+ * For Twine works, the IFID is a UUID (v4) in uppercase.
+ * @see Treaty of Babel ({@link https://babel.ifarchive.org/babel_rev11.html#the-ifid-for-an-html-story-file})
+ * @function generate
+ * @description Generates a new IFID.
+ * @returns {string} IFID
+ * @example
+ * const ifid = generate();
+ * console.log(ifid);
+ * // => 'A1B2C3D4-E5F6-G7H8-I9J0-K1L2M3N4O5P6'
+ */
+export function generate(): string;
diff --git a/types/JSON/parse.d.ts b/types/JSON/parse.d.ts
new file mode 100644
index 00000000..3ae6cd9a
--- /dev/null
+++ b/types/JSON/parse.d.ts
@@ -0,0 +1,51 @@
+/**
+ * Parse JSON representation into Story.
+ * @see {@link https://github.com/iftechfoundation/twine-specs/blob/master/twine-2-jsonoutput-doc.md Twine 2 JSON Specification}
+ * @function parse
+ * @param {string} jsonString - JSON string to convert to Story.
+ * @throws {Error} - Invalid JSON!
+ * @returns {Story} Story object.
+ * @example
+ * const jsonString = `{
+ * "name": "My Story",
+ * "start": "First Passage",
+ * "ifid": "A1B2C3D4-E5F6-G7H8-I9J0-K1L2M3N4O5P6",
+ * "format": "SugarCube",
+ * "formatVersion": "2.31.0",
+ * "creator": "Twine",
+ * "creatorVersion": "2.3.9",
+ * "zoom": 1,
+ * "passages": [
+ * {
+ * "name": "First Passage",
+ * "tags": "",
+ * "metadata": "",
+ * "text": "This is the first passage."
+ * },
+ * ]
+ * }`;
+ * const story = parse(jsonString);
+ * console.log(story);
+ * // => Story {
+ * // name: 'My Story',
+ * // start: 'First Passage',
+ * // IFID: 'A1B2C3D4-E5F6-G7H8-I9J0-K1L2M3N4O5P6',
+ * // format: 'SugarCube',
+ * // formatVersion: '2.31.0',
+ * // creator: 'Twine',
+ * // creatorVersion: '2.3.9',
+ * // zoom: 1,
+ * // tagColors: {},
+ * // metadata: {},
+ * // passages: [
+ * // Passage {
+ * // name: 'First Passage',
+ * // tags: '',
+ * // metadata: '',
+ * // text: 'This is the first passage.'
+ * // }
+ * // ]
+ * // }
+ */
+export function parse(jsonString: string): Story;
+import { Story } from '../Story.js';
diff --git a/types/Passage.d.ts b/types/Passage.d.ts
new file mode 100644
index 00000000..e24b0d26
--- /dev/null
+++ b/types/Passage.d.ts
@@ -0,0 +1,117 @@
+/**
+ * Passage class.
+ * @class
+ * @classdesc Represents a passage in a Twine story.
+ * @property {string} name - Name of the passage.
+ * @property {Array} tags - Tags for the passage.
+ * @property {object} metadata - Metadata for the passage.
+ * @property {string} text - Text content of the passage.
+ * @method {string} toTwee - Return a Twee representation.
+ * @method {string} toJSON - Return JSON representation.
+ * @method {string} toTwine2HTML - Return Twine 2 HTML representation.
+ * @method {string} toTwine1HTML - Return Twine 1 HTML representation.
+ * @example
+ * const p = new Passage('Start', 'This is the start of the story.');
+ * console.log(p.toTwee());
+ * // :: Start
+ * // This is the start of the story.
+ * //
+ * console.log(p.toJSON());
+ * // {"name":"Start","tags":[],"metadata":{},"text":"This is the start of the story."}
+ * console.log(p.toTwine2HTML());
+ * // This is the start of the story.
+ * console.log(p.toTwine1HTML());
+ * //
This is the start of the story.
+ * @example
+ * const p = new Passage('Start', 'This is the start of the story.', ['start', 'beginning'], {position: '10,10', size: '100,100'});
+ * console.log(p.toTwee());
+ * // :: Start [start beginning] {"position":"10,10","size":"100,100"}
+ * // This is the start of the story.
+ * //
+ * console.log(p.toJSON());
+ * // {"name":"Start","tags":["start","beginning"],"metadata":{"position":"10,10","size":"100,100"},"text":"This is the start of the story."}
+ * console.log(p.toTwine2HTML());
+ * // This is the start of the story.
+ * console.log(p.toTwine1HTML());
+ * // This is the start of the story.
+ */
+export default class Passage {
+ /**
+ * Create a passage.
+ * @param {string} name - Name
+ * @param {string} text - Content
+ * @param {Array} tags - Tags
+ * @param {object} metadata - Metadata
+ */
+ constructor(name?: string, text?: string, tags?: any[], metadata?: object);
+ /**
+ * @param {string} s - Name to replace
+ * @throws {Error} Name must be a String!
+ */
+ set name(s: string);
+ /**
+ * Name
+ * @returns {string} Name
+ */
+ get name(): string;
+ /**
+ * @param {Array} t - Replacement array
+ * @throws {Error} Tags must be an array!
+ */
+ set tags(t: any[]);
+ /**
+ * Tags
+ * @returns {Array} Tags
+ */
+ get tags(): any[];
+ /**
+ * @param {object} m - Replacement object
+ * @throws {Error} Metadata must be an object literal!
+ */
+ set metadata(m: any);
+ /**
+ * Metadata
+ * @returns {object} Metadata
+ */
+ get metadata(): any;
+ /**
+ * @param {string} t - Replacement text
+ * @throws {Error} Text should be a String!
+ */
+ set text(t: string);
+ /**
+ * Text
+ * @returns {string} Text
+ */
+ get text(): string;
+ /**
+ * Return a Twee representation.
+ *
+ * See: https://github.com/iftechfoundation/twine-specs/blob/master/twee-3-specification.md
+ *
+ * @method toTwee
+ * @returns {string} String form of passage.
+ */
+ toTwee(): string;
+ /**
+ * Return JSON representation.
+ * @method toJSON
+ * @returns {string} JSON string.
+ */
+ toJSON(): string;
+ /**
+ * Return Twine 2 HTML representation.
+ * (Default Passage ID is 1.)
+ * @method toTwine2HTML
+ * @param {number} pid - Passage ID (PID) to record in HTML.
+ * @returns {string} Twine 2 HTML string.
+ */
+ toTwine2HTML(pid?: number): string;
+ /**
+ * Return Twine 1 HTML representation.
+ * @method toTwine1HTML
+ * @returns {string} Twine 1 HTML string.
+ */
+ toTwine1HTML(): string;
+ #private;
+}
diff --git a/types/Story.d.ts b/types/Story.d.ts
new file mode 100644
index 00000000..207fdc7b
--- /dev/null
+++ b/types/Story.d.ts
@@ -0,0 +1,230 @@
+/**
+ * Story class.
+ * @class
+ * @classdesc Represents a Twine story.
+ * @property {string} name - Name of the story.
+ * @property {string} IFID - Interactive Fiction ID (IFID) of Story.
+ * @property {string} start - Name of start passage.
+ * @property {string} format - Story format of Story.
+ * @property {string} formatVersion - Story format version of Story.
+ * @property {number} zoom - Zoom level.
+ * @property {Array} passages - Array of Passage objects. @see {@link Passage}
+ * @property {string} creator - Program used to create Story.
+ * @property {string} creatorVersion - Version used to create Story.
+ * @property {object} metadata - Metadata of Story.
+ * @property {object} tagColors - Tag Colors
+ * @method {number} addPassage - Add a passage to the story and returns the new length of the passages array.
+ * @method {number} removePassageByName - Remove a passage from the story by name and returns the new length of the passages array.
+ * @method {Array} getPassagesByTag - Find passages by tag.
+ * @method {Array} getPassageByName - Find passage by name.
+ * @method {number} size - Size (number of passages).
+ * @method {string} toJSON - Export Story as JSON representation.
+ * @method {string} toTwee - Return Twee representation.
+ * @method {string} toTwine2HTML - Return Twine 2 HTML representation.
+ * @method {string} toTwine1HTML - Return Twine 1 HTML representation.
+ * @example
+ * const story = new Story('My Story');
+ * story.IFID = '12345678-1234-5678-1234-567812345678';
+ * story.start = 'Start';
+ * story.format = 'SugarCube';
+ * story.formatVersion = '2.31.0';
+ * story.zoom = 1;
+ * story.creator = 'extwee';
+ * story.creatorVersion = '2.2.1';
+ */
+export class Story {
+ /**
+ * Creates a story.
+ * @param {string} name - Name of the story.
+ */
+ constructor(name?: string);
+ /**
+ * @param {string} a - Replacement story name
+ */
+ set name(a: string);
+ /**
+ * Each story has a name
+ * @returns {string} Name
+ */
+ get name(): string;
+ /**
+ * @param {object} a - Replacement tag colors
+ */
+ set tagColors(a: any);
+ /**
+ * Tag Colors object (each property is a tag and its color)
+ * @returns {object} tag colors array
+ */
+ get tagColors(): any;
+ /**
+ * @param {string} i - Replacement IFID.
+ */
+ set IFID(i: string);
+ /**
+ * Interactive Fiction ID (IFID) of Story.
+ * @returns {string} IFID
+ */
+ get IFID(): string;
+ /**
+ * @param {string} s - Replacement start
+ */
+ set start(s: string);
+ /**
+ * Name of start passage.
+ * @returns {string} start
+ */
+ get start(): string;
+ /**
+ * @param {string} f - Replacement format version
+ */
+ set formatVersion(f: string);
+ /**
+ * Story format version of Story.
+ * @returns {string} story format version
+ */
+ get formatVersion(): string;
+ /**
+ * @param {object} o - Replacement metadata
+ */
+ set metadata(o: any);
+ /**
+ * Metadata of Story.
+ * @returns {object} metadata of story
+ */
+ get metadata(): any;
+ /**
+ * @param {string} f - Replacement format
+ */
+ set format(f: string);
+ /**
+ * Story format of Story.
+ * @returns {string} format
+ */
+ get format(): string;
+ /**
+ * @param {string} c - Creator Program of Story
+ */
+ set creator(c: string);
+ /**
+ * Program used to create Story.
+ * @returns {string} Creator Program
+ */
+ get creator(): string;
+ /**
+ * @param {string} c - Version of creator program
+ */
+ set creatorVersion(c: string);
+ /**
+ * Version used to create Story.
+ * @returns {string} Version
+ */
+ get creatorVersion(): string;
+ /**
+ * @param {number} n - Replacement zoom level
+ */
+ set zoom(n: number);
+ /**
+ * Zoom level.
+ * @returns {number} Zoom level
+ */
+ get zoom(): number;
+ /**
+ * Set passages in Story.
+ * @param {Array} p - Replacement passages
+ * @property {Array} passages - Passages
+ * @throws {Error} Passages must be an Array!
+ * @throws {Error} Passages must be an Array of Passage objects!
+ */
+ set passages(p: any[]);
+ /**
+ * Passages in Story.
+ * @returns {Array} Passages
+ * @property {Array} passages - Passages
+ */
+ get passages(): any[];
+ /**
+ * Add a passage to the story.
+ * Passing `StoryData` will override story metadata and `StoryTitle` will override story name.
+ * @method addPassage
+ * @param {Passage} p - Passage to add to Story.
+ * @returns {number} Return new length of passages array.
+ */
+ addPassage(p: Passage): number;
+ /**
+ * Remove a passage from the story by name.
+ * @method removePassageByName
+ * @param {string} name - Passage name to remove.
+ * @returns {number} Return new length of passages array.
+ */
+ removePassageByName(name: string): number;
+ /**
+ * Find passages by tag.
+ * @method getPassagesByTag
+ * @param {string} t - Passage name to search for
+ * @returns {Array} Return array of passages
+ */
+ getPassagesByTag(t: string): any[];
+ /**
+ * Find passage by name.
+ * @method getPassageByName
+ * @param {string} name - Passage name to search for
+ * @returns {Passage | null} Return passage or null
+ */
+ getPassageByName(name: string): Passage | null;
+ /**
+ * Size (number of passages).
+ * @method size
+ * @returns {number} Return number of passages
+ */
+ size(): number;
+ /**
+ * Export Story as JSON representation.
+ * @method toJSON
+ * @returns {string} JSON string.
+ */
+ toJSON(): string;
+ /**
+ * Return Twee representation.
+ *
+ * See: Twee 3 Specification
+ * (https://github.com/iftechfoundation/twine-specs/blob/master/twee-3-specification.md)
+ *
+ * @method toTwee
+ * @returns {string} Twee String
+ */
+ toTwee(): string;
+ /**
+ * Return Twine 2 HTML.
+ *
+ * See: Twine 2 HTML Output
+ * (https://github.com/iftechfoundation/twine-specs/blob/master/twine-2-htmloutput-spec.md)
+ *
+ * The only required attributes are `name` and `ifid` of the `` element. All others are optional.
+ *
+ * The `` element may have any number of optional attributes, which are:
+ * - `startnode`: (integer) Optional. The PID of the starting passage.
+ * - `creator`: (string) Optional. The name of the program that created the story.
+ * - `creator-version`: (string) Optional. The version of the program that created the story.
+ * - `zoom`: (decimal) Optional. The zoom level of the story.
+ * - `format`: (string) Optional. The format of the story.
+ * - `format-version`: (string) Optional. The version of the format of the story.
+ *
+ * @method toTwine2HTML
+ * @returns {string} Twine 2 HTML string
+ */
+ toTwine2HTML(): string;
+ /**
+ * Return Twine 1 HTML.
+ *
+ * See: Twine 1 HTML Output
+ * (https://github.com/iftechfoundation/twine-specs/blob/master/twine-1-htmloutput-doc.md)
+ *
+ * @method toTwine1HTML
+ * @returns {string} Twine 1 HTML string.
+ */
+ toTwine1HTML(): string;
+ #private;
+}
+export const creatorName: "extwee";
+export const creatorVersion: "2.2.2";
+import Passage from './Passage.js';
diff --git a/types/StoryFormat.d.ts b/types/StoryFormat.d.ts
new file mode 100644
index 00000000..9a0ef49a
--- /dev/null
+++ b/types/StoryFormat.d.ts
@@ -0,0 +1,121 @@
+/**
+ * StoryFormat representing a Twine 2 story format.
+ *
+ * This class has type checking on all of its properties.
+ * If a property is set to a value of the wrong type, a TypeError will be thrown.
+ *
+ * @see {@link https://github.com/iftechfoundation/twine-specs/blob/master/twine-2-storyformats-spec.md Twine 2 Story Formats Specification}
+ *
+ * @class
+ * @classdesc A class representing a Twine 2 story format.
+ * @property {string} name - The name of the story format.
+ * @property {string} version - The semantic version of the story format.
+ * @property {string} description - The description of the story format.
+ * @property {string} author - The author of the story format.
+ * @property {string} image - The image of the story format.
+ * @property {string} url - The URL of the story format.
+ * @property {string} license - The license of the story format.
+ * @property {boolean} proofing - The proofing of the story format.
+ * @property {string} source - The source of the story format.
+ * @example
+ * const sf = new StoryFormat();
+ * sf.name = 'New';
+ * sf.version = '1.0.0';
+ * sf.description = 'New';
+ * sf.author = 'New';
+ * sf.image = 'New';
+ * sf.url = 'New';
+ * sf.license = 'New';
+ * sf.proofing = true;
+ * sf.source = 'New';
+ */
+export default class StoryFormat {
+ /**
+ * @param {string} n - Replacement name.
+ */
+ set name(n: string);
+ /**
+ * Name
+ * @returns {string} Name.
+ */
+ get name(): string;
+ /**
+ * @param {string} n - Replacement version.
+ */
+ set version(n: string);
+ /**
+ * Version.
+ * @returns {string} Version.
+ */
+ get version(): string;
+ /**
+ * @param {string} d - Replacement description.
+ */
+ set description(d: string);
+ /**
+ * Description.
+ * @returns {string} Description.
+ */
+ get description(): string;
+ /**
+ * @param {string} a - Replacement author.
+ */
+ set author(a: string);
+ /**
+ * Author.
+ * @returns {string} Author.
+ */
+ get author(): string;
+ /**
+ * @param {string} i - Replacement image.
+ */
+ set image(i: string);
+ /**
+ * Image.
+ * @returns {string} Image.
+ */
+ get image(): string;
+ /**
+ * @param {string} u - Replacement URL.
+ */
+ set url(u: string);
+ /**
+ * URL.
+ * @returns {string} URL.
+ */
+ get url(): string;
+ /**
+ * @param {string} l - Replacement license.
+ */
+ set license(l: string);
+ /**
+ * License.
+ * @returns {string} License.
+ */
+ get license(): string;
+ /**
+ * @param {boolean} p - Replacement proofing.
+ */
+ set proofing(p: boolean);
+ /**
+ * Proofing.
+ * @returns {boolean} Proofing.
+ */
+ get proofing(): boolean;
+ /**
+ * @param {string} s - Replacement source.
+ */
+ set source(s: string);
+ /**
+ * Source.
+ * @returns {string} Source.
+ */
+ get source(): string;
+ /**
+ * Produces a string representation of the story format object.
+ * @method toString
+ * @returns {string} - A string representation of the story format.
+ */
+ toString(): string;
+ #private;
+}
diff --git a/types/StoryFormat/parse.d.ts b/types/StoryFormat/parse.d.ts
new file mode 100644
index 00000000..e06b2f62
--- /dev/null
+++ b/types/StoryFormat/parse.d.ts
@@ -0,0 +1,50 @@
+/**
+ * Parses story format content into a {@link StoryFormat} object.
+ *
+ * Story formats are generally JSONP files containing a JSON object with the following properties:
+ * - name: (string) Optional. (Omitting the name will lead to an Untitled Story Format.)
+ * - version: (string) Required, and semantic version-style formatting (x.y.z, e.g., 1.2.1) of the version is also required.
+ * - author: (string) Optional.
+ * - description: (string) Optional.
+ * - image: (string) Optional.
+ * - url: (string) Optional.
+ * - license: (string) Optional.
+ * - proofing: (boolean) Optional (defaults to false).
+ * - source: (string) Required.
+ *
+ * If existing properties do not match their expected type, a warning will be produced and incoming value will be ignored.
+ *
+ * This function does "soft parsing." It will not throw an error if a specific property is missing or malformed.
+ * @see {@link https://github.com/iftechfoundation/twine-specs/blob/master/twine-2-storyformats-spec.md Twine 2 Story Formats Specification}
+ * @function parse
+ * @param {string} contents - JSONP content.
+ * @throws {Error} - Unable to find Twine 2 JSON chunk!
+ * @throws {Error} - Unable to parse Twine 2 JSON chunk!
+ * @returns {StoryFormat} StoryFormat object.
+ * @example
+ * const contents = `{
+ * "name": "My Story Format",
+ * "version": "1.0.0",
+ * "author": "Twine",
+ * "description": "A story format.",
+ * "image": "icon.svg",
+ * "url": "https://example.com",
+ * "license": "MIT",
+ * "proofing": false,
+ * "source": ""
+ * }`;
+ * const storyFormat = parse(contents);
+ * console.log(storyFormat);
+ * // => StoryFormat {
+ * // name: 'My Story Format',
+ * // version: '1.0.0',
+ * // description: 'A story format.',
+ * // image: 'icon.svg',
+ * // url: 'https://example.com',
+ * // license: 'MIT',
+ * // proofing: false,
+ * // source: ''
+ * // }
+ */
+export function parse(contents: string): StoryFormat;
+import StoryFormat from '../StoryFormat.js';
diff --git a/types/TWS/parse.d.ts b/types/TWS/parse.d.ts
new file mode 100644
index 00000000..83ed71a6
--- /dev/null
+++ b/types/TWS/parse.d.ts
@@ -0,0 +1,10 @@
+/**
+ * Parse TWS file (as Buffer) into Story.
+ * Unless it throws an error, it will return a Story object.
+ * @see {@link https://github.com/iftechfoundation/twine-specs/blob/master/twine-1-htmloutput-doc.md Twine 1 HTML Documentation}
+ * @function parse
+ * @param {Buffer} binaryFileContents - File contents to parse as Buffer.
+ * @returns {Story} Story object.
+ */
+export function parse(binaryFileContents: Buffer): Story;
+import { Story } from '../Story.js';
diff --git a/types/Twee/parse.d.ts b/types/Twee/parse.d.ts
new file mode 100644
index 00000000..25c1139d
--- /dev/null
+++ b/types/Twee/parse.d.ts
@@ -0,0 +1,9 @@
+/**
+ * Parses Twee 3 text into a Story object.
+ * @see {@link https://github.com/iftechfoundation/twine-specs/blob/master/twee-3-specification.md Twee 3 Specification}
+ * @function parse
+ * @param {string} fileContents - File contents to parse
+ * @returns {Story} story
+ */
+export function parse(fileContents: string): Story;
+import { Story } from '../Story.js';
diff --git a/types/Twine1HTML/compile.d.ts b/types/Twine1HTML/compile.d.ts
new file mode 100644
index 00000000..7580efd1
--- /dev/null
+++ b/types/Twine1HTML/compile.d.ts
@@ -0,0 +1,19 @@
+/**
+ * Write a combination of Story object, `engine.js` (from Twine 1), `header.html`, and optional `code.js`.
+ * @see {@link https://github.com/iftechfoundation/twine-specs/blob/master/twine-1-htmloutput-doc.md Twine 1 HTML Documentation}
+ * @function compile
+ * @param {Story} story - Story object to write.
+ * @param {string} engine - Source of `engine.js` file from Twine 1.
+ * @param {string} header - `header.html` content for Twine 1 story format.
+ * @param {string} name - Name of the story format (needed for `code.js` inclusion).
+ * @param {string} codeJS - `code.js` content with additional JavaScript.
+ * @param {object} config - Limited configuration object acting in place of `StorySettings`.
+ * @param {string} config.jquery - jQuery source.
+ * @param {string} config.modernizr - Modernizr source.
+ * @returns {string} Twine 1 HTML.
+ */
+export function compile(story: Story, engine?: string, header?: string, name?: string, codeJS?: string, config?: {
+ jquery: string;
+ modernizr: string;
+}): string;
+import { Story } from '../Story.js';
diff --git a/types/Twine1HTML/parse.d.ts b/types/Twine1HTML/parse.d.ts
new file mode 100644
index 00000000..4063433c
--- /dev/null
+++ b/types/Twine1HTML/parse.d.ts
@@ -0,0 +1,9 @@
+/**
+ * Parses Twine 1 HTML into a Story object.
+ * @see {@link https://github.com/iftechfoundation/twine-specs/blob/master/twine-1-htmloutput-doc.md Twine 1 HTML Documentation}
+ * @function parse
+ * @param {string} content - Twine 1 HTML content to parse.
+ * @returns {Story} Story object
+ */
+export function parse(content: string): Story;
+import { Story } from '../Story.js';
diff --git a/types/Twine2ArchiveHTML/compile.d.ts b/types/Twine2ArchiveHTML/compile.d.ts
new file mode 100644
index 00000000..31cc9341
--- /dev/null
+++ b/types/Twine2ArchiveHTML/compile.d.ts
@@ -0,0 +1,14 @@
+/**
+ * Write array of Story objects into Twine 2 Archive HTML.
+ * @see {@link https://github.com/iftechfoundation/twine-specs/blob/master/twine-2-archive-spec.md Twine 2 Archive Specification}
+ * @function compile
+ * @param {Array} stories - Array of Story objects.
+ * @returns {string} Twine 2 Archive HTML.
+ * @example
+ * const story1 = new Story();
+ * const story2 = new Story();
+ * const stories = [story1, story2];
+ * console.log(compile(stories));
+ * // => '\n\n\n\n'
+ */
+export function compile(stories: any[]): string;
diff --git a/types/Twine2ArchiveHTML/parse.d.ts b/types/Twine2ArchiveHTML/parse.d.ts
new file mode 100644
index 00000000..91df37f3
--- /dev/null
+++ b/types/Twine2ArchiveHTML/parse.d.ts
@@ -0,0 +1,36 @@
+/**
+ * Parse Twine 2 Archive HTML and returns an array of story objects.
+ * @see {@link https://github.com/iftechfoundation/twine-specs/blob/master/twine-2-archive-spec.md Twine 2 Archive Specification}
+ * @function parse
+ * @param {string} content - Content to parse for Twine 2 HTML elements.
+ * @throws {TypeError} - Content is not a string!
+ * @returns {Array} Array of stories found in content.
+ * @example
+ * const content = '';
+ * console.log(parse(content));
+ * // => [
+ * // Story {
+ * // name: 'Untitled',
+ * // startnode: '1',
+ * // creator: 'Twine',
+ * // creatorVersion: '2.3.9',
+ * // ifid: 'A1B2C3D4-E5F6-G7H8-I9J0-K1L2M3N4O5P6',
+ * // zoom: '1',
+ * // format: 'Harlowe',
+ * // formatVersion: '3.1.0',
+ * // options: '',
+ * // hidden: '',
+ * // passages: [
+ * // Passage {
+ * // pid: '1',
+ * // name: 'Untitled Passage',
+ * // tags: '',
+ * // position: '0,0',
+ * // size: '100,100',
+ * // text: ''
+ * // }
+ * // ]
+ * // }
+ * // ]
+ */
+export function parse(content: string): any[];
diff --git a/types/Twine2HTML/compile.d.ts b/types/Twine2HTML/compile.d.ts
new file mode 100644
index 00000000..c296d092
--- /dev/null
+++ b/types/Twine2HTML/compile.d.ts
@@ -0,0 +1,14 @@
+/**
+ * Write a combination of Story + StoryFormat into Twine 2 HTML file.
+ * @see {@link https://github.com/iftechfoundation/twine-specs/blob/master/twine-2-htmloutput-spec.md Twine 2 HTML Output Specification}
+ * @function compile
+ * @param {Story} story - Story object to write.
+ * @param {StoryFormat} storyFormat - StoryFormat to write.
+ * @returns {string} Twine 2 HTML based on StoryFormat and Story.
+ * @throws {Error} If story is not instance of Story.
+ * @throws {Error} If storyFormat is not instance of StoryFormat.
+ * @throws {Error} If storyFormat.source is empty string.
+ */
+export function compile(story: Story, storyFormat: StoryFormat): string;
+import { Story } from '../Story.js';
+import StoryFormat from '../StoryFormat.js';
diff --git a/types/Twine2HTML/parse.d.ts b/types/Twine2HTML/parse.d.ts
new file mode 100644
index 00000000..8159e440
--- /dev/null
+++ b/types/Twine2HTML/parse.d.ts
@@ -0,0 +1,20 @@
+/**
+ * Parse Twine 2 HTML into Story object.
+ *
+ * See: Twine 2 HTML Output Specification
+ * (https://github.com/iftechfoundation/twine-specs/blob/master/twine-2-htmloutput-spec.md)
+ *
+ * Produces warnings for:
+ * - Missing name attribute on `` element.
+ * - Missing IFID attribute on `` element.
+ * - Malformed IFID attribute on `` element.
+ * @function parse
+ * @param {string} content - Twine 2 HTML content to parse.
+ * @returns {Story} Story object based on Twine 2 HTML content.
+ * @throws {TypeError} Content is not a string.
+ * @throws {Error} Not Twine 2 HTML content!
+ * @throws {Error} Cannot parse passage data without name!
+ * @throws {Error} Passages are required to have PID!
+ */
+export function parse(content: string): Story;
+import { Story } from '../Story.js';