Using Loreline with TypeScript
Loreline ships with full TypeScript type definitions, giving you type-safe access to the entire API. This guide shows how to set up a TypeScript project, load a .lor script, and handle dialogue, choices, and script completion with typed handlers.
Installing the library
Install via npm:
npm install loreline
The package includes loreline.js (ES module) and loreline.d.ts (type definitions). No separate @types package is needed.
You can also download loreline-js.zip from the GitHub releases page. It contains js/loreline.js and js/loreline.d.ts. Copy them into your project.
Project setup
Create an ESM project with TypeScript. Your package.json should include:
{
"type": "module",
"scripts": {
"start": "tsx src/main.ts"
},
"dependencies": {
"loreline": "^0.5.0",
"tsx": "^4.21.0",
"typescript": "^5.0.0"
},
"devDependencies": {
"@types/node": "^25.0.0"
}
}
And a tsconfig.json:
{
"compilerOptions": {
"target": "ES2020",
"module": "ES2020",
"moduleResolution": "node",
"strict": true,
"esModuleInterop": true,
"outDir": "dist"
},
"include": ["src"]
}
Using tsx lets you run TypeScript directly without a build step. You can also compile with tsc and run the output with Node.js if you prefer.
Loading a script
Import types and classes from the loreline package:
import { Loreline, Script } from "loreline";
import { readFileSync } from "fs";
const content: string = readFileSync("story/CoffeeShop.lor", "utf-8");
function handleFile(path: string, callback: (content: string) => void): void {
callback(readFileSync("story/" + path, "utf-8"));
}
const script: Script = Loreline.parse(content, "CoffeeShop.lor", handleFile)!;
Loreline.parse() returns Script | null. Use the non-null assertion ! when you are sure the source is valid, or check for null explicitly.
If your script has no import statements, you can omit the file handler:
const script: Script = Loreline.parse(content)!;
Handling dialogue
Use the DialogueHandler type for your callback. The handler receives the interpreter, a character identifier (or null for narrative text), the dialogue text, tags, and an advance callback:
import { DialogueHandler } from "loreline";
const onDialogue: DialogueHandler = (interpreter, character, text, tags, advance) => {
if (character) {
const name = interpreter.getCharacterField(character, "name");
console.log(`${name || character}: ${text}`);
} else {
console.log(text);
}
advance();
};
Handling choices
Use the ChoiceHandler type. Each option has text, tags, and enabled fields:
import { ChoiceHandler } from "loreline";
const onChoice: ChoiceHandler = (interpreter, options, select) => {
for (let i = 0; i < options.length; i++) {
if (options[i].enabled) {
console.log(` [${i + 1}] ${options[i].text}`);
}
}
select(0); // select first option
};
Handling script completion
Use the FinishHandler type:
import { FinishHandler } from "loreline";
const onFinish: FinishHandler = (interpreter) => {
console.log("--- The End ---");
};
Complete example
Here is a complete Node.js application that loads and plays a Loreline script with full type annotations:
import { readFileSync } from "fs";
import {
Loreline, Script, Interpreter,
DialogueHandler, ChoiceHandler, FinishHandler
} from "loreline";
const storyDir = "story/";
const content: string = readFileSync(storyDir + "CoffeeShop.lor", "utf-8");
function handleFile(path: string, callback: (content: string) => void): void {
try {
callback(readFileSync(storyDir + path, "utf-8"));
} catch {
callback("");
}
}
const script: Script | null = Loreline.parse(content, "CoffeeShop.lor", handleFile);
if (!script) {
console.error("Failed to parse script");
process.exit(1);
}
const onDialogue: DialogueHandler = (interp, character, text, tags, advance) => {
if (character) {
const name = interp.getCharacterField(character, "name");
console.log(`${name || character}: ${text}`);
} else {
console.log(text);
}
console.log();
advance();
};
const onChoice: ChoiceHandler = (interp, options, select) => {
for (let i = 0; i < options.length; i++) {
if (options[i].enabled) {
console.log(` [${i + 1}] ${options[i].text}`);
}
}
select(0);
};
const onFinish: FinishHandler = (interp) => {
console.log("--- The End ---");
};
const interp: Interpreter = Loreline.play(script, onDialogue, onChoice, onFinish);
Run it with:
npm run start
Going further
For a polished browser-based example with animations, smooth scrolling, and styled output, download loreline-web.zip from the GitHub releases page.