Utiliser Loreline avec TypeScript

Loreline inclut des définitions de types TypeScript complètes, offrant un accès typé à l'ensemble de l'API. Ce guide montre comment configurer un projet TypeScript, charger un script .lor, et gérer les dialogues, les choix et la fin du script avec des gestionnaires typés.

Installer la bibliothèque

Installez via npm :

npm install loreline

Le package inclut loreline.js (module ES) et loreline.d.ts (définitions de types). Aucun package @types séparé n'est nécessaire.

Vous pouvez aussi télécharger loreline-js.zip depuis la page des releases GitHub. L'archive contient js/loreline.js et js/loreline.d.ts. Copiez-les dans votre projet.

Configuration du projet

Créez un projet ESM avec TypeScript. Votre package.json doit inclure :

{
  "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"
  }
}

Et un tsconfig.json :

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ES2020",
    "moduleResolution": "node",
    "strict": true,
    "esModuleInterop": true,
    "outDir": "dist"
  },
  "include": ["src"]
}

Utiliser tsx permet d'exécuter TypeScript directement sans étape de compilation. Vous pouvez aussi compiler avec tsc et exécuter la sortie avec Node.js si vous préférez.

Charger un script

Importez les types et classes depuis le package loreline :

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() retourne Script | null. Utilisez l'assertion non-null ! quand vous êtes sûr que la source est valide, ou vérifiez null explicitement.

Si votre script n'a pas d'instructions import, vous pouvez omettre le gestionnaire de fichiers :

const script: Script = Loreline.parse(content)!;

Gérer les dialogues

Utilisez le type DialogueHandler pour votre callback. Le gestionnaire reçoit l'interpréteur, un identifiant de personnage (ou null pour du texte narratif), le texte du dialogue, les tags et un callback pour avancer :

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();
};

Gérer les choix

Utilisez le type ChoiceHandler. Chaque option a des champs text, tags et enabled :

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); // sélectionner la première option
};

Gérer la fin du script

Utilisez le type FinishHandler :

import { FinishHandler } from "loreline";

const onFinish: FinishHandler = (interpreter) => {
  console.log("--- Fin ---");
};

Exemple complet

Voici une application Node.js complète qui charge et exécute un script Loreline avec des annotations de types complètes :

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("Échec de l'analyse du 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("--- Fin ---");
};

const interp: Interpreter = Loreline.play(script, onDialogue, onChoice, onFinish);

Exécutez avec :

npm run start

Aller plus loin

Pour un exemple navigateur abouti avec animations, défilement fluide et sortie stylisée, téléchargez loreline-web.zip depuis la page des releases GitHub.