Utiliser Loreline avec JavaScript

Loreline fournit un module JavaScript qui fonctionne à la fois dans le navigateur et dans Node.js. Ce guide montre comment configurer un projet, charger un script .lor, et gérer les dialogues, les choix et la fin du script.

Installer la bibliothèque

Installez via npm :

npm install loreline

Cela fournit loreline.js (module ES) et loreline.d.ts (types TypeScript).

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 et importez-les directement.

Charger un script

Utilisez Loreline.parse() pour analyser une chaîne .lor. Le troisième argument est un gestionnaire de fichiers pour résoudre les instructions import dans votre script :

import { Loreline } from 'loreline';

const response = await fetch('story/CoffeeShop.lor');
const content = await response.text();

function handleFile(path, callback) {
  fetch('story/' + path)
    .then(r => r.ok ? r.text() : '')
    .then(data => callback(data))
    .catch(() => callback(''));
}

Loreline.parse(content, 'CoffeeShop.lor', handleFile, function(script) {
  // Script analysé avec succès, prêt à jouer
  Loreline.play(script, onDialogue, onChoice, onFinish);
});

Quand le gestionnaire de fichiers est asynchrone (comme fetch), parse() retourne null et délivre le script analysé via le quatrième argument (callback). Si votre gestionnaire de fichiers est synchrone (par ex. dans Node.js avec fs.readFileSync), parse() retourne le script directement :

import { Loreline } from 'loreline';
import { readFileSync } from 'fs';

const content = readFileSync('story/CoffeeShop.lor', 'utf-8');

function handleFile(path, callback) {
  callback(readFileSync('story/' + path, 'utf-8'));
}

const script = Loreline.parse(content, 'CoffeeShop.lor', handleFile);
Loreline.play(script, onDialogue, onChoice, onFinish);

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

const script = Loreline.parse(content);

Gérer les dialogues

Le gestionnaire de dialogue reçoit l'interpréteur, un identifiant de personnage (ou null pour du texte narratif), le texte du dialogue, les tags éventuels, et un callback pour faire avancer le script :

function onDialogue(interpreter, character, text, tags, callback) {
  if (character) {
    // Résoudre le nom d'affichage depuis la définition du personnage
    var name = interpreter.getCharacterField(character, 'name');
    console.log((name || character) + ' : ' + text);
  } else {
    // Texte narratif (pas de personnage)
    console.log(text);
  }
  callback();
}

Dans une interface navigateur, vous ajouteriez typiquement le texte au DOM et appelleriez callback() après un délai pour laisser le joueur lire.

Gérer les choix

Le gestionnaire de choix reçoit une liste d'options. Chaque option a un champ text et un champ enabled. Appelez le callback avec l'index du choix sélectionné :

function onChoice(interpreter, options, callback) {
  options.forEach(function(opt, i) {
    if (opt.enabled) {
      console.log('  [' + (i + 1) + '] ' + opt.text);
    }
  });

  // Dans une vraie application, vous afficheriez des boutons et appelleriez callback(index) au clic
  callback(0); // sélectionner la première option
}

Gérer la fin du script

Le gestionnaire de fin est appelé quand le script atteint sa fin :

function onFinish(interpreter) {
  console.log('--- Fin ---');
}

Exemple complet

Voici un exemple complet pour navigateur qui charge et joue un script Loreline :

import { Loreline } from 'loreline';

var output = document.getElementById('output');

function handleFile(path, callback) {
  fetch('story/' + path)
    .then(function(r) { return r.ok ? r.text() : ''; })
    .then(function(data) { callback(data); })
    .catch(function() { callback(''); });
}

function onDialogue(interpreter, character, text, tags, callback) {
  var line = document.createElement('p');
  if (character) {
    var name = interpreter.getCharacterField(character, 'name');
    line.innerHTML = '<strong>' + (name || character) + ' :</strong> ' + text;
  } else {
    line.textContent = text;
  }
  output.appendChild(line);
  setTimeout(callback, 600);
}

function onChoice(interpreter, options, callback) {
  var container = document.createElement('div');
  options.forEach(function(opt, i) {
    if (!opt.enabled) return;
    var btn = document.createElement('button');
    btn.textContent = opt.text;
    btn.addEventListener('click', function() {
      container.remove();
      callback(i);
    });
    container.appendChild(btn);
  });
  output.appendChild(container);
}

function onFinish(interpreter) {
  var p = document.createElement('p');
  p.textContent = '--- Fin ---';
  output.appendChild(p);
}

fetch('story/CoffeeShop.lor')
  .then(function(r) { return r.text(); })
  .then(function(content) {
    Loreline.parse(content, 'CoffeeShop.lor', handleFile, function(script) {
      Loreline.play(script, onDialogue, onChoice, onFinish);
    });
  });

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.