Comme je joue souvent à du jeu de rôle, j’ai l’occasion de créer des overlays où NodeCG tient une place centrale.

L’overlay ne se limite alors pas à afficher quelques informations à l’écran : il peut aller chercher des données dans différents services, réagir à ce qui se passe pendant la partie, piloter des animations et même interagir directement avec OBS.

Personnages, statistiques, jets de dés, décors, NodeCG gère beaucoup de choses

L’idée générale est toujours la même : récupérer une information quelque part, la faire transiter par NodeCG, puis faire réagir l’overlay en conséquence.

Récupérer et gérer les données

FoundryVTT

En général, nous jouons avec FoundryVTT, une plateforme permettant de jouer à des jeux de rôle à distance.

Chaque joueur et joueuse possède son propre personnage, avec sa feuille de statistiques, son équipement, ses compétences, etc. FoundryVTT permet également de gérer les jets de dés directement depuis l’interface.

Cela donne beaucoup d’informations intéressantes à afficher sur un overlay : les statistiques des personnages, leur état actuel, les jets de dés qui viennent d’être effectués, leur résultat, et ainsi de suite.

Le problème : récupérer les données

Le problème est que Foundry VTT ne propose pas d’API externe simple permettant de récupérer directement toutes ces informations depuis NodeCG.

J’ai longtemps expérimenté pour trouver une solution satisfaisante. Au tout début, je récupérais les informations des logs (la galère), maintenant le processus est un peu différent.

L’idée générale est assez simple : faire transiter les données de Foundry VTT jusqu’à NodeCG, puis les rendre accessibles au reste de l’application.

  1. Foundry VTT prépare les données

J’ai crée un module perso que j’ai intégré dans FoundryVTT. Son rôle est de rassembler les données dont j’ai besoin et de les envoyer dans le système de socket de Foundry.

Sur Foundry, le socket permet à différentes parties de l’application (serveur, navigateur…) de s’échanger des messages en temps réel.

Par exemple, lorsqu’un personnage est modifié, mon module envoie ses nouvelles données avec un type permettant de savoir de quel événement il s’agit :

game.socket.emit("module.foundryvtt-to-nodecg", {
type: "characterUpdate",
data: characterData
});
  1. NodeCG reçoit les événements

De l’autre côté, l’extension NodeCG écoute ce socket. Lorsqu’un message arrive, elle regarde son type et transmet les données au reste de l’application via un événement interne.

socket.on("module.foundryvtt-to-nodecg", (data) => {
if (data.type === "characterUpdate") {
foundryEmitter.emit("character-update", data.data);
}
});

Cette étape sert essentiellement de pont entre Foundry VTT et mon extension : Foundry envoie les données, NodeCG les récupère et les transmet sous une forme plus pratique à manipuler.

  1. Les données sont stockées dans le Replicant

Il ne reste ensuite qu’à stocker les données dans le Replicant.

Lorsqu’un personnage est mis à jour, je vérifie s’il existe déjà dans la liste : s’il n’existe pas, je l’ajoute, sinon je remplace ses données par la nouvelle version.

foundryEmitter.on("character-update", (character) => {
const characters = foundryRep.value.characters;
const index = characters.findIndex(c => c.id === character.id);
if (index === -1) {
characters.push(character);
} else {
characters[index] = character;
}
foundryRep.value.characters = characters; // Je stocke les données dans le Replicant
});

Une alternative : récupérer les données depuis Google Sheets

FoundryVTT n’est pas la seule source de données que j’ai utilisée.

Pour l’un de nos jeux de rôle, nous utilisions une feuille Google Sheets pour gérer les personnages, les jets de dés et certaines informations de la partie.

J’avais donc développé un script permettant à NodeCG de récupérer automatiquement les données de la feuille via une API, à partir de l’URL.

Quand on lance les dés sur le Spreasheet, l'overlay s'active 🎲

Au final, la source peut changer, mais l’interface fournie aux graphics reste la même.

Une limite cependant : le nombre d’appels à l’API est limité par Google Spreadsheets, donc je me limite à un appel toutes les deux secondes.

Des Replicants et des Messages

À ce stade, je rencontre principalement deux types d’informations : les données qui décrivent l’état de la partie, comme les statistiques des personnages, et les événements ponctuels, comme les jets de dés.

Ces deux types de données ne sont pas gérés de la même manière.

Comme expliqué dans le guide, il faut simplement retenir une distinction :

Concrètement ici :

Si le dashboard est ouvert après le début de la partie ou rechargé, il doit pouvoir récupérer immédiatement les informations actuelles des personnages.

En revanche, il n’a pas besoin de recevoir les jets de dés qui ont eu lieu cinq minutes auparavant.

Controler l’overlay

Gérer des cartes de jeu de rôle

Pour certains projets, j’ai également eu besoin d’afficher et de manipuler des cartes.

Pour cela, j’ai utilisé Leaflet, une bibliothèque JavaScript open source permettant de créer des cartes interactives dans une page web.

Dans le dashboard NodeCG, j’avais une interface permettant à la personne qui contrôle le stream de :

L'overlay affiche la carte, le tout piloté par NodeCG 🗺️

Le dashboard d’interface d’administration de la carte.

Du côté des “graphics”, le principe est différent : l’écran du stream affiche simplement le résultat final.

Conceptuellement, cela fonctionne bien, mais il me faudrait beaucoup de temps pour terminer de développer le module et en faire quelque chose de propre.

Faire réagir l’ovelay

Animer les personnages quand quelqu’un parle

Un problème se pose lorsqu’on réalise un overlay de JDR sans webcam.

Sans webcams, comment indiquer à l’écran quelle personne (et son personnage) parle ?

L’idée était simple : faire légèrement bouger le personnage lorsqu’il parle, un peu comme un indicateur vocal.

Récupérer le statut vocal avec Mumble

Nous utilisons Mumble pour discuter en ligne pendant nos parties.

J’ai donc développé, là encore dans une extension NodeCG, un petit bot capable de se connecter au serveur Mumble grâce à la bibliothèque mumble-client

Le bot ne récupère pas la voix des participant·e·s. Il récupère uniquement leur statut : parle/ne parle pas

Un dashboard de NodeCG, pour se connecter sur un salon Mumble et détecter qui parle

Mon dasboard NodeCG permet de détecter qui parle

Il faut ensuite faire le lien entre ce statut vocal et les personnages affichés à l’écran. Pour cela, je maintiens une correspondance entre la personne sur Mumble et son personnage.

Sur Mumble : Pepe parle, sur l’overlay son personnage “Lafitte” s’anime

Lorsqu’une personne commence à parler, l’extension envoie donc un message aux éléments graphiques avec l’identifiant du personnage concerné.

Celui-ci active son animation. Lorsque la personne arrête de parler, l’animation est désactivée.

Sur l'overlay, la marionnette du personange s'agite quand le joueur ou la joueuse parle

Quand Pepe parle, Lafitte s'agite !

Un décor piloté par la météo

L’overlay est construit autour d’une sorte de petit théâtre de marionnettes.

Les personnages sont placés devant un décor et différents éléments graphiques peuvent être ajoutés ou retirés : nuages, torches, effets météorologiques, etc.

J’ai donc ajouté la possibilité de modifier le décor à la volée depuis le dashboard de NodeCG.

Une petite télécommande dans le dashboard

Le dashboard contient une interface permettant de contrôler les différents éléments du décor pendant la partie. Cela permet, par exemple, de modifier rapidement l’ambiance d’une scène sans devoir modifier manuellement les fichiers graphiques.

La télécommande permet de changer le décor

Mais je me suis demandé s’il était possible d’aller un peu plus loin et de laisser le décor réagir automatiquement. Pour pousser l’idée, j’ai connecté NodeCG à une API météo gratuite.

Imaginons par exemple un scénario dans lequel la météo d’une ville ou d’un village est complètement détraquée et change sans arrêt. Plutôt que de choisir moi-même la météo à afficher, j’ai testé un script qui récupère toutes les quelques minutes la météo d’un lieu choisi au hasard dans le monde.

Le décor réagit automatiquement au résultat :

La météo devient ainsi une source de données supplémentaire pour l’overlay. Ce qui était au départ un simple bouton dans le dashboard peut désormais être déclenché automatiquement par une information extérieure.

J’aime l’idée mais je n’ai pas encore eu le temps de bien la creuser : la météo réelle d’un lieu choisi au hasard peut directement influencer ce qui se passe dans le décor de l’overlay.

Ajouter des confettis (oui)

J’aime bien les confettis et pour cet overlay, je les utilise pour simuler entre autres certains effets magiques ou du sang.

Dans NodeCG, j’utilise la bibliothèque canvas-confetti pour pouvoir déclencher des effets de confettis directement dans les Graphics de l’overlay.

Ici, j’ai utilisé les confettis dans différentes situations :

Des effets de confettis quand les points de vie changent 🎊

Ici, quand le Replicant qui gère les données des personnages detecte une modification de la valeur “Points de vie” , il envoie un message avec la nouvelle valeur pour déclencher l’animation.

On peut même aller plus loin, ici le nombre de confettis depend du nombre de points de vie perdus (petit dégats = peu de confettis).

NodeCG comme colonne vertébrale de l’overlay

Tous ces exemples peuvent sembler assez différents : récupérer un jet de dés, détecter quelqu’un qui parle, changer une météo, afficher une carte, déclencher des confettis ou contrôler OBS.

Pourtant, le principe derrière ces fonctionnalités est toujours le même, NodeCG sert de colonne vertébrale entre les différentes sources d’information et les différents éléments du stream.