Story Editor — Guide d'utilisation
Le Story Editor est un plugin Godot intégré au projet. Il affiche un graphe visuel de toutes les scènes narratives définies dans les fichiers JSON, directement dans l'éditeur Godot — sans modifier le jeu en dehors des actions d'édition explicites.
Activation
- Dans Godot, ouvrir Projet → Paramètres du projet → Plugins
- Activer Story Editor
- Un onglet Story Editor apparaît en bas de l'éditeur (panneau inférieur, à côté de la console)
Prise en main
Une fois activé, voici les quatre actions de base pour démarrer :
- Cliquez sur Refresh — le graphe charge toutes les scènes des fichiers JSON du projet
- Cliquez sur un nœud — son contenu s'affiche dans le panneau de détail à droite ; les champs sont éditables directement
- Clic droit sur le fond du graphe — crée une nouvelle scène (ID, contact, fichier cible)
- Glissez un port de sortie vers un port d'entrée — connecte deux scènes (
next)
Tout ce qui suit dans ce document détaille ces actions et les fonctionnalités avancées.
Interface
+--------------------------------------------------------------------------------------+
| [Refresh] [Reformater…] [Contacts] [Paramètres] [↩] [↪] 2/5 : scene_03 |
| [🚩 Flags] [📊 Analyser] [🗗] [fr v] [Tous v] [Chercher...________] [<-] [->] |
+-------------------------------------------+------------------------------------------+
| | scene_04 |
| [> ch1_intro] --> [scene_01] --------> | Contact [Maeve v] |
| | | |
| [! orpheline] [X scene_02] | Messages ---------------------- |
| | |
| [~ scene_03] - - - trigger - - - -> | Bonjour ! [x] |
| | +-------------------------+ |
| | | Je t'ecris depuis le | |
| | | train. | |
| | +-------------------------+ |
| | pause [medium v] |
| | requires [-- v] |
| | |
| | Choix ------------------- |
| | C'est du spam -> [-- v] [x] |
| | Je vous recois-> [-- v] [x] |
| | [+ choix] |
+-------------------------------------------+------------------------------------------+
La toolbar est une seule rangée horizontale ; elle est représentée sur deux lignes ici pour la lisibilité.
Légende du graphe : [> id] = scène de départ · [! id] = isolée · [X id] = fin de parcours · [~ id] = saisie libre · - - -> = connexion trigger

- Bouton Refresh : relit les fichiers JSON et reconstruit le graphe. À utiliser après chaque modification manuelle des fichiers de dialogue. Les actions d'édition depuis le graphe déclenchent un Refresh automatique.
- Bouton Reformater… : ouvre une fenêtre de sélection avant toute écriture. Elle indique précisément quels fichiers de
dialogues/seront reformattés, y compris les éventuels fallbacks de la langue active. Voir Reformater des fichiers JSON. - Bouton Contacts : ouvre le panneau Contacts — une fenêtre flottante pour gérer la liste des personnages.
- Bouton Paramètres : ouvre le panneau Paramètres — une fenêtre flottante pour les réglages globaux, les langues et l'écran de fin.
- Bouton 🚩 Flags : ouvre le panneau Flags — une fenêtre flottante listant tous les flags du projet avec leurs scènes d'origine et d'utilisation.
- Bouton 📊 Analyser : ouvre le panneau Analyser — une fenêtre flottante présentant une analyse complète du récit (accessibilité, flags inutilisés, boucles, personnages, durée indicative).
- Boutons ↩ / ↪ : annuler / rétablir la dernière action (équivalents à Ctrl+Z / Ctrl+Y).
- Bouton 🗗 : ouvre le Story Editor dans une fenêtre séparée — pratique sur un second écran. Un deuxième clic ramène la fenêtre existante au lieu d'en ouvrir une nouvelle. La fenêtre peut être mise en plein écran.
- Filtre contact : dropdown listant tous les contacts du projet. Sélectionner un contact grise toutes les scènes des autres contacts à 20 % d'opacité — les connexions restent visibles pour garder le contexte global. Choisir « Tous » rétablit l'affichage normal. Le filtre est conservé après un Refresh.
- Champ de recherche : saisir un texte et appuyer sur Entrée cherche d'abord dans les IDs de scène (exact → préfixe → sous-chaîne), puis dans le texte des messages et des choix. La recherche est insensible à la casse. Si plusieurs résultats correspondent, les boutons ← et → (ou les touches fléchées ← / → depuis le champ) permettent de naviguer entre eux ; le label de statut affiche
2 / 5 : scene_id. Échap efface le champ et masque les boutons. Ctrl+F depuis n'importe où dans le panneau remet le focus sur ce champ. - Graphe (zone principale) : nœuds déplaçables, zoomables à la molette, navigables en maintenant le clic molette ou en maintenant Espace + glisser. Une minimap en bas à droite donne une vue d'ensemble du graphe. Les positions des nœuds sont sauvegardées automatiquement et restaurées à chaque ouverture.
- Panneau de détail (droite) : cliquer sur un nœud affiche son contenu complet. Les textes des messages et des choix sont éditables directement.
Nœuds du graphe
Chaque scène JSON correspond à un nœud. Le nom affiché dans le titre du nœud est l'id de la scène.
Indicateurs visuels
| Indicateur | Signification |
|---|---|
| ▶ avant l'ID | Scène de départ (start_scene dans story.json) |
| ✎ après l'ID | Scène avec free_input (saisie libre du joueur) |
| 📝 après l'ID | Scène avec des notes internes (_notes) |
| Couleur de titre | Chaque contact a une couleur de barre de titre générée automatiquement depuis son ID — constante d'une session à l'autre |
| Texte en petit sous le titre | Aperçu tronqué (60 car.) du premier message de la scène |
| ⛔ Fin de parcours (rouge) | La scène n'a aucune sortie — probable oubli d'auteur |
| ⚠ Isolée (jaune) | Aucune scène ne pointe vers cette scène — elle ne sera jamais atteinte |
Types de connexions
Les flèches entre les nœuds sont colorées selon leur nature :
| Couleur | Type | Description |
|---|---|---|
| Gris clair | next ou choice |
Enchaînement normal ou choix du joueur |
| Orange | trigger |
Déclenchement automatique via trigger_after_scene |
| Violet | resume |
Reprise conditionnelle via resume_after_flag |
Ports
Chaque nœud a :
- Un port d'entrée (gauche) — reçoit les connexions des scènes précédentes
- Un port de sortie par connexion (droite) — une par next, une par choix (choices[])
Si une scène a des choix sans destination (next absent), chaque choix dispose de son propre port de sortie — visible sans fil, prêt à être connecté. Glisser depuis ce port vers une autre scène écrit le next dans le bon choix.
Si une scène n'a ni choix ni next, un port → ? est affiché : il permet de tirer une connexion vers une autre scène, ce qui ajoutera un next de scène.
Panneau de détail

L'éditeur est une aide pratique pour écrire des scènes sans toucher au JSON. Il couvre la grande majorité des cas d'usage courants. Certaines fonctionnalités avancées (conditions structurées
and/or, médias, corrections différées, musique) restent accessibles uniquement via l'édition directe du fichier JSON — voir la section Ce que le JSON permet en plus en fin de document.
Cliquer sur un nœud ouvre le panneau de détail à droite. Tous les champs sont directement éditables et sauvegardés dès que le champ perd le focus (clic ailleurs ou Tab).
Niveau scène
| Champ | Interface |
|---|---|
_notes |
Zone de texte — notes internes sur la scène, ignorées par le moteur. Apparaissent en vert en haut du panneau. |
| Contact | Dropdown — tous les contacts du projet |
trigger_after_scene |
Dropdown de scènes — se déclenche quand la scène choisie vient d'être jouée |
resume_after_flag |
Dropdown de flags — attend en coulisse jusqu'à ce que ce flag soit activé |
resume_after_delay |
Texte libre — accepte 300 (secondes), "5m", "1h" |
free_input (var) |
Bouton + Saisie libre → champ texte pour le nom de variable |
free_input_placeholder |
Champ texte — texte indicatif dans le champ de saisie du joueur |
Par message
| Champ | Interface |
|---|---|
| Texte simple | Zone de texte multi-ligne + × pour supprimer |
| Texte tableau (bulles) | Chaque bulle éditable séparément + + bulle pour en ajouter |
requires_flag |
Dropdown de flags — masque le message si le flag n'est pas actif |
pause |
Dropdown — (aucune), short, medium, long |
effects |
Ligne par effet : dropdown op + dropdown cible + champ valeur + × ; + Effet pour ajouter |
Par choix
| Champ | Interface |
|---|---|
| Texte du bouton | Zone de texte multi-ligne + × pour supprimer |
message (bulle joueur) |
Absent : boutons + msg (une bulle) et + msgs [...] (plusieurs bulles successives) · Chaîne : champ texte éditable + × pour supprimer · Tableau : chaque bulle éditable séparément + + bulle pour en ajouter + × pour supprimer tout le tableau |
flag |
Champ texte — flag activé à la sélection |
requires_flag |
Dropdown de flags — masque ce choix si le flag n'est pas actif |
next |
Dropdown de scènes — scène jouée après ce choix |
effects |
Même interface que les effets de messages |
Effets (effects)
Chaque effet se compose de trois champs :
| Op | Cible | Valeur |
|---|---|---|
set |
Dropdown de variables | Valeur à affecter |
add |
Dropdown de variables | Valeur à ajouter |
sub |
Dropdown de variables | Valeur à soustraire |
rename |
Dropdown de contacts | Éditeur de nom inline : une ligne — pour un nom invariant (identique dans toutes les langues), ou une ligne par code langue. Cliquez + Langue pour ajouter des entrées localisées — l'entrée invariante est automatiquement convertie en première entrée de langue. Un code langue apparaît en orange si aucun fichier *.{code}.json correspondant n'existe dans dialogues/. |
set_status |
Dropdown de contacts | online / away / offline / network_issue |
Saisie libre vs Choix
free_input et choices sont mutuellement exclusifs : le moteur ignore les choix si une saisie libre est définie. L'éditeur le reflète : + Saisie libre est grisé si des choix existent, et + Choix est grisé si une saisie libre est active.
Édition depuis le graphe
Toutes les modifications sont écrites immédiatement dans le fichier JSON correspondant, puis le graphe est reconstruit automatiquement. Aucune confirmation n'est nécessaire sauf pour la suppression.
Créer une scène
Clic droit sur le fond du graphe (pas sur un nœud) → dialog de création :
- ID : identifiant unique de la scène (ex.
scene_10). Si l'ID existe déjà, la création est refusée. - Contact : liste déroulante de tous les contacts définis dans
story.json. - Fichier : si plusieurs fichiers JSON existent dans
dialogues/, un menu supplémentaire permet de choisir dans quel fichier écrire la scène.
La scène est ajoutée en fin de fichier avec un message vide { "text": "" }. Elle apparaît dans le graphe avec l'indicateur ⚠ Isolée jusqu'à ce qu'une connexion entrante soit créée.
Connecter deux scènes
Glisser depuis un port de sortie (cercle droit d'un nœud) vers le port d'entrée (cercle gauche) d'un autre nœud.
- Si le port de sortie correspond à un choix, le champ
nextde ce choix est renseigné dans le JSON. - Si le port de sortie correspond au
nextde scène (ou au port → ?), le champnextde la scène est renseigné. - Si le port avait déjà une destination, elle est remplacée par la nouvelle.
On ne peut pas connecter un port
triggerouresume— ces connexions sont en lecture seule (elles reflètent des champs du JSON mais ne peuvent pas être modifiées depuis le graphe).
Déconnecter ou supprimer une connexion
Clic droit sur le nœud source → le menu contextuel liste toutes les connexions sortantes actives :
Supprimer cette scène
Dupliquer cette scène
─────────────────────
Déconnecter : C'est du spam → scene_02
Déconnecter : Oui, je vous reçois → scene_02
Cliquer sur une entrée "Déconnecter" supprime le next correspondant dans le JSON (le choix ou le next de scène reste, mais sans destination).
Dupliquer une scène
Clic droit sur le nœud → Dupliquer cette scène — ou Ctrl+D avec le nœud sélectionné.
La scène est copiée dans le même fichier JSON avec un nouvel ID ({id}_copy, puis {id}_copy2… en cas de collision). Les messages, les choix et tous les textes sont copiés ; les liens sortants (next, trigger_after_scene, resume_after_flag, resume_after_delay, choices[].next) sont effacés pour éviter les connexions dupliquées. L'opération est annulable avec Ctrl+Z.
Supprimer une scène
Clic droit sur le nœud → Supprimer cette scène — ou Suppr avec le nœud sélectionné — → dialog de confirmation.
Sur confirmation :
- La scène est retirée du fichier JSON qui la contient.
- Tous les next et choices[].next qui pointaient vers cette scène sont supprimés dans tous les fichiers JSON du projet.
- Le graphe est reconstruit.
La suppression peut être annulée avec Ctrl+Z.
Raccourcis clavier
| Raccourci | Condition | Action |
|---|---|---|
| Ctrl+Z | — | Annule la dernière modification |
| Ctrl+Y | — | Rétablit la dernière modification annulée |
| Ctrl+F | — | Focus sur le champ de recherche |
| F | Aucun champ texte en focus | Recentre et ajuste le zoom sur l'ensemble du graphe |
| Suppr | Nœud sélectionné, aucun champ texte en focus | Ouvre la confirmation de suppression |
| Ctrl+D | Nœud sélectionné, aucun champ texte en focus | Duplique la scène sélectionnée |
| ← → | Champ de recherche en focus, ≥ 2 résultats | Résultat précédent / suivant |
| Échap | Champ de recherche en focus | Efface la recherche et relâche le focus |
Les actions couvertes par l'annulation : connexion / déconnexion de scènes, création / suppression de scènes, édition de n'importe quel champ du panneau de détail, Reformater…, renommage de contact, toutes les modifications dans le panneau Contacts.
Exception : l'ajout et la suppression de langues (section Langues du panneau Paramètres) ne sont pas annulables — ces opérations peuvent créer plusieurs fichiers, modifier story.json et ui.csv, puis déclencher un réimport Godot.
L'historique d'annulation est limité à la session courante de l'éditeur.
Panneau Paramètres
Cliquer sur le bouton Paramètres dans la toolbar ouvre une fenêtre flottante pour les réglages globaux du projet. Chaque modification est écrite immédiatement, sans bouton Enregistrer. Les champs globaux et les vitesses de frappe sont sauvegardés respectivement dans story.json et theme.json.
Champs globaux
| Champ | Interface |
|---|---|
title |
Texte libre — affiché dans les menus et la barre de titre de la fenêtre |
menu_music |
Champ texte + bouton … — ouvre l'explorateur de fichiers Godot filtré sur .ogg, .mp3, .wav. Chemin vers le fichier audio joué en boucle dans le menu principal. Laisser vide pour aucune musique. |
start_scene |
Dropdown de scènes — première scène jouée au lancement d'une nouvelle partie |
start_contact |
Dropdown de contacts — contact dont la conversation est affichée à l'écran au lancement ; si vide, le contact principal est utilisé |
Vitesse de frappe
Configure les délais de saisie dans theme.json. Les modifications prennent effet au prochain lancement du jeu.
| Champ | Interface |
|---|---|
| Contacts | SpinBox (0.01–0.50 s) — délai par caractère pour l'indicateur … affiché pendant qu'un contact "écrit". Défaut : 0.08 |
| Joueur | SpinBox (0.01–0.50 s) — délai par caractère lors de la frappe des réponses du joueur. Défaut : 0.05 |
Langues
La section Langues liste les colonnes déclarées dans translations/ui.csv. L'affichage est mis à jour immédiatement, sans attendre la génération des fichiers .translation par Godot.
| Élément | Rôle |
|---|---|
| Chip par langue + × | Chaque langue active est affichée avec un bouton ×. Celui-ci ouvre l'assistant de suppression décrit ci-dessous. Le bouton est grisé pour la dernière langue et pour la langue par défaut. |
| + Ajouter une langue… | Ouvre l'assistant de localisation complet décrit ci-dessous. Aucune écriture n'a lieu avant la confirmation finale. |
Assistant d'ajout de langue
L'assistant se déroule en deux étapes :
- Configuration — saisir un code de langue (
es,de,pt_BR…), choisir une langue source, puis décider s'il faut créer les dialogues localisés et préparer les champs localisés destory.json. - Vérification — contrôler le nombre de textes d'interface, de champs de projet et la liste exacte des fichiers qui seront créés avant de cliquer sur Ajouter la langue.
À la confirmation, l'assistant :
- ajoute une colonne à
translations/ui.csvet la préremplit depuis la langue source choisie ; - crée, si demandé, un fichier
nom.{langue}.jsonpour chaque dialogue disponible, en utilisant le fichier source localisé ou son fichier de fallback ; - prépare, si demandé, les
namesdes contacts, les textes dehistoryet les champs localisés de l'écran de fin dansstory.json; - demande à Godot de régénérer les ressources
.translation; - affiche un bilan et rappelle quels contenus copiés doivent maintenant être traduits.
Les fichiers localisés déjà présents ne sont jamais écrasés, même s'ils apparaissent entre l'aperçu et la confirmation. Les écritures sont transactionnelles et validées. En cas d'échec partiel, la langue n'est pas enregistrée dans ui.csv ; les fichiers déjà préparés sont conservés et l'assistant peut être relancé sans perte.
Si la création des dialogues est décochée, le moteur continue d'utiliser automatiquement les fichiers de la langue par défaut. L'assistant ne considère pas les textes copiés comme traduits : ils constituent uniquement une base de travail explicite.
La liste des langues proposée dans les paramètres du jeu est reconstruite automatiquement depuis
ui.csvau prochain lancement.
Assistant de suppression de langue
Le bouton × d'une langue non protégée propose deux portées avant toute écriture :
- Retirer uniquement du jeu supprime seulement sa colonne de
translations/ui.csv. Les dialogues et les valeurs localisées destory.jsonrestent intacts afin de pouvoir réactiver la langue plus tard. - Supprimer entièrement la langue supprime sa colonne de
ui.csv, ses entrées dans lesnames,historyet textes localisés de l'écran de fin, ainsi que tous les fichiers*.{langue}.jsoncorrespondants et la ressource.translationgénérée.
Une seconde étape affiche le nombre de valeurs localisées et la liste exacte des fichiers concernés. La confirmation finale est obligatoire pour appliquer la suppression.
Une suppression complète reste récupérable : chaque fichier retiré est renommé avec un suffixe .removed.{horodatage}, avec ses éventuels fichiers temporaires et sauvegardes. Il n'est donc plus détecté par le moteur, mais son contenu reste disponible localement. Ces archives sont exclues de Git. story.json utilise l'écriture transactionnelle habituelle et la colonne de ui.csv n'est supprimée qu'en dernier. En cas d'échec partiel, l'assistant peut être relancé.
La dernière langue ne peut jamais être supprimée. La langue par défaut est également protégée, car les fichiers JSON sans suffixe utilisent son contenu comme fallback. Pour la remplacer, il faut d'abord définir et préparer une autre langue par défaut.
Maintenance des fichiers de récupération
La section Maintenance des fichiers contient le bouton Nettoyer les fichiers de récupération…. Cet assistant permet de supprimer définitivement les anciennes récupérations lorsque le projet a été vérifié et fonctionne correctement.
Deux catégories peuvent être analysées séparément :
- les sauvegardes rotatives
.bak,.bak.2et.bak.3créées par les écritures sécurisées ; - les archives
.removed.*conservées après la suppression complète d'une langue.
L'assistant parcourt uniquement les fichiers du projet et affiche leur chemin, leur taille et la liste exacte des éléments sélectionnés. Chaque fichier peut être décoché avant la confirmation finale. Une sauvegarde .bak dont le fichier principal est absent ou invalide est automatiquement protégée, car elle peut constituer la dernière copie récupérable.
Le nettoyage est définitif et ne crée pas une nouvelle sauvegarde des fichiers supprimés. Les fichiers .tmp, les quarantaines .corrupt.*, .git, .godot, les dossiers d'export et les sauvegardes de parties situées dans user:// sont volontairement exclus.
Écran de fin
La section Écran de fin configure ce qui s'affiche après une scène marquée "end": true.
| Champ | Interface |
|---|---|
title |
Un champ par langue active — titre principal affiché en grand. Sauvegardé comme dict localisé si plusieurs langues, comme string si une seule. |
text |
Un champ par langue active — texte secondaire sous le titre (accroche, annonce de suite…). Même format que title. |
lien URL |
Texte libre — URL ouverte au clic (ex : page itch.io). Vide = aucun lien |
lien texte |
Texte libre — libellé affiché sur le lien. Vide = l'URL brute s'affiche |
glitch |
Case à cocher — active le scramble de texte sur le titre + scanlines animées + flicker |
show_stats |
Case à cocher — affiche le nombre de messages échangés pendant la session |
Pour marquer la scène finale, ajoutez "end": true directement dans le JSON de la scène (voir le guide auteur).
Panneau Contacts
Cliquer sur le bouton Contacts dans la toolbar ouvre une fenêtre flottante pour gérer la liste des personnages dans story.json. Chaque modification est écrite immédiatement, sans bouton Enregistrer.
Liste des contacts
Chaque contact est affiché sous forme de carte avec tous ses champs éditables :
| Champ | Interface |
|---|---|
id |
Texte libre — si modifié, toutes les références contact_id dans les fichiers de dialogue sont mises à jour automatiquement |
name |
Texte libre — nom affiché dans la liste de contacts et la barre de titre |
is_main |
Case à cocher — désigne le contact qui reçoit toutes les scènes sans contact_id explicite ; cocher un contact décoche automatiquement tous les autres |
avatar |
Champ texte + bouton … — cliquer sur … ouvre l'explorateur de fichiers Godot directement dans assets/avatars/. Le chemin peut aussi être saisi manuellement (ex : res://assets/avatars/maeve.png). Vide = initiale du nom sur fond coloré. Les formats acceptés sont PNG, JPG, JPEG et WEBP. |
status |
Dropdown — online, away, offline, network_issue |
pending_scene |
Dropdown de scènes — scène mise en attente pour ce contact au démarrage ; le joueur voit un choix en suspens dès l'ouverture de la conversation |
names |
Section « Noms localisés » — liste de paires code langue / nom. Bouton + Langue pour ajouter une entrée (un placeholder ?? apparaît en orange — le remplacer par le code réel). Le code langue est coloré en orange si aucun fichier de dialogue correspondant (*.{code}.json) n'est trouvé dans dialogues/. Voir la section names du guide auteur. |
history |
Liste de lignes — chaque entrée a une case → (envoyé par le joueur), un champ date YYYY-MM-DD (optionnel), un champ heure HH:MM, un bouton 📅 pour ouvrir le sélecteur visuel, et un champ texte par langue active. Si le projet a plusieurs langues (ex : fr et en), chaque ligne affiche autant de champs que de langues — préfixés par leur code. Si la date est vide, le message s'affiche comme un message du jour ; si elle est antérieure à aujourd'hui, l'horodatage affiché est JJ-MM-AAAA HH:MM (locale FR) ou AAAA-MM-JJ HH:MM (autres locales). |
- + Contact — ajoute une nouvelle carte contact
- × sur une carte — demande une confirmation avant de supprimer le contact de
story.json - + msg sur une carte — ajoute une entrée d'historique
- × sur une ligne d'historique — supprime l'entrée immédiatement
Renommer un
idest sans risque : le panneau scanne tous les fichiers de dialogue du projet et met à jour chaquecontact_idqui correspondait à l'ancienne valeur. Le champstart_contactglobal est aussi mis à jour si nécessaire.
Panneau Flags
Cliquer sur le bouton 🚩 Flags dans la toolbar ouvre une fenêtre flottante en lecture seule listant tous les flags utilisés dans le projet, dérivés en temps réel depuis les scènes chargées.
Pour chaque flag, trois catégories sont affichées (uniquement celles non vides) :
| Catégorie | Source dans le JSON |
|---|---|
| ✏️ Défini par | choices[].flag — scènes dont un choix active ce flag |
| ⏱ Attendu par | resume_after_flag — scènes qui attendent ce flag pour se déclencher |
| ? Requis par | requires_flag, condition (à tous les niveaux : scène, message, choix) — scènes qui consultent ce flag |
Cliquer sur un ID de scène dans la liste centre le graphe sur ce nœud et ouvre son panneau de détail.
Le panneau se met à jour automatiquement après chaque Refresh du graphe.
Panneau Analyser
Cliquer sur le bouton 📊 Analyser dans la toolbar ouvre une fenêtre flottante en lecture seule présentant une analyse du récit calculée en temps réel depuis les scènes chargées.
| Section | Contenu |
|---|---|
| Vue d'ensemble | Nombre de scènes, messages, choix, fins (sans continuation), scènes inaccessibles, boucles et flags inutilisés (avec indicateur coloré si > 0) |
| Accessibilité | Pourcentage de scènes accessibles depuis start_scene (parcours exhaustif depuis la scène de départ) ; liste cliquable des scènes inaccessibles |
| Flags inutilisés | Flags activés par choices[].flag mais jamais vérifiés dans requires_flag, condition ou resume_after_flag (section absente si tous les flags sont utilisés) |
| Boucles | Circuits fermés détectés par exploration des chemins — scènes où le joueur peut rester indéfiniment sans condition de sortie (section absente si aucune boucle) |
| Personnages | Nombre de messages par contact, trié par volume décroissant, avec pourcentage du total |
| Durée indicative | ≈ Xh YY ou ≈ N min — basé sur 200 mots/min en comptant toutes les branches (chemin complet inclus) |
Cliquer sur un ID de scène dans les sections Accessibilité ou Boucles centre le graphe sur ce nœud.
Le panneau se recalcule automatiquement à chaque ouverture (si déjà ouvert, cliquer à nouveau le bouton rafraîchit les données).
Ce que le JSON permet en plus
L'éditeur couvre la grande majorité des scénarios. Les fonctionnalités suivantes nécessitent encore une édition directe du fichier JSON :
| Fonctionnalité | Pourquoi JSON uniquement |
|---|---|
condition structurée (and/or/flag/var) |
Logique booléenne complexe, requires_flag couvre la majorité des cas |
media (image dans une bulle) |
Affiché en lecture seule dans l'éditeur (📷 nom du fichier) |
edit (corrections différées) |
Le texte corrigé (corrected_text) est éditable ; le type et le délai restent en lecture seule |
time (délai d'apparition d'un message) |
Cas avancé rare |
music |
Cas avancé rare |
Après une édition manuelle, le bouton Reformater… permet de remettre les fichiers voulus dans le format canonique décrit ci-dessous.
Format JSON produit par l'éditeur
L'éditeur écrit le JSON en respectant l'ordre sémantique des clés à trois niveaux :
Scène :
_notes → id → contact_id → trigger_after_scene → resume_after_flag → resume_after_delay → messages_in → free_input → free_input_placeholder → music → next → choices
Message :
text → edit → effects → media → pause → requires_flag → condition
Choix :
text → message → flag → requires_flag → condition → next → effects
Les messages, choix et tableaux de texte sont entièrement développés : chaque objet et chaque texte possède sa propre ligne. L'indentation utilise des tabulations.
Reformater des fichiers JSON
Le bouton Reformater… n'écrit rien immédiatement. Il ouvre d'abord une fenêtre compacte qui liste, par ordre alphabétique, tous les fichiers .json présents dans dialogues/.
- La langue actuellement éditée est indiquée en haut de la fenêtre.
- Les fichiers réellement utilisés pour cette langue sont présélectionnés.
- Lorsqu'un fichier localisé n'existe pas, le fichier de la langue par défaut utilisé à sa place est signalé comme Fallback et mis en évidence. Le reformatage ne crée pas de variante localisée manquante.
- Langue active rétablit cette présélection ; Tous les fichiers sélectionne toute la liste. Chaque fichier peut aussi être coché ou décoché individuellement.
- Le bouton de confirmation indique le nombre de fichiers concernés et reste désactivé tant que la sélection est vide.
Seuls les fichiers cochés au moment de la confirmation sont écrits. Le reformatage modifie uniquement la présentation du document — indentation, retours à la ligne et ordre canonique des clés — sans modifier les valeurs ni la logique narrative. Chaque écriture utilise le mécanisme sécurisé du moteur et conserve une copie de récupération. L'opération peut également être annulée avec Ctrl+Z dans le Story Editor.
Avec un grand nombre de langues ou de fichiers, seule la liste défile verticalement : les actions de sélection, de confirmation et d'annulation restent visibles. Le chemin complet et le détail d'un fallback sont disponibles dans l'infobulle de chaque fichier.
Localisation
Le plugin lit les fichiers de dialogue en appliquant la même logique de locale que le jeu :
- Il préfère acte1.fr.json si la langue système est fr, sinon acte1.json
- La langue lue correspond au réglage de la langue système de l'OS, pas au réglage dans le jeu
Prévisualiser une autre langue : le dropdown de locale dans la toolbar ([fr v] dans l'ASCII ci-dessus) permet de forcer la locale du plugin indépendamment de la langue système. Sélectionner en charge acte1.en.json à la place de acte1.json — pratique pour vérifier la version anglaise depuis un OS configuré en français. Le choix est perdu au redémarrage de Godot.
Architecture
Cette section s'adresse aux développeurs qui souhaitent modifier ou étendre le plugin. Elle n'est pas nécessaire pour écrire du contenu narratif.
Le plugin est dans addons/story_editor/ et ne touche à aucun fichier existant du projet hors des actions d'édition explicites.
| Fichier | Rôle |
|---|---|
plugin.cfg |
Manifest Godot (nom, version) |
plugin.gd |
EditorPlugin — ajoute/retire le panneau |
StoryEditorPanel.tscn |
Scène du panneau (HSplitContainer[GraphEdit, ScrollContainer]) + toolbar |
StoryEditorPanel.gd |
Logique principale : parsing, layout BFS, rendu, édition, écriture JSON ; ouvre les fenêtres Contacts et Paramètres ; possède l'undo/redo |
SceneDetailPanel.gd |
RefCounted — formulaire d'édition de scène (panneau droit) ; toutes les fonctions _populate_* et _add_* ; reçoit ses dépendances via des callables injectés par StoryEditorPanel |
StoryPanelBase.gd |
Classe de base partagée par ContactsPanel et StorySettingsPanel : lecture/écriture de story.json, callables undo/redo, helpers UI (_section, _line_edit, _dropdown, etc.) |
ContactsPanel.gd |
Panneau Contacts — liste des personnages uniquement ; étend StoryPanelBase |
StorySettingsPanel.gd |
Panneau Paramètres — réglages globaux, langues, écran de fin ; étend StoryPanelBase |
scene_parser.gd |
RefCounted autonome — lit story.json + dialogues/*.json avec support locale |
FlagsPanel.gd |
Panneau Flags — liste en lecture seule tous les flags du projet avec leurs scènes d'origine ; Control pur, non connecté à StoryPanelBase |
AnalysisPanel.gd |
Panneau Analyser — analyse en lecture seule : accessibilité par parcours depuis start_scene, détection de cycles, flags inutilisés, compte par contact, durée indicative ; Control pur |
json_utils.gd |
Helpers JSON statiques : expand() / compact() (sérialiseur sur mesure), ordered_scene/message/choice() (ordre stable des clés pour des diffs lisibles) |
scene_parser.gd est volontairement découplé de dialogue_loader.gd pour fonctionner dans le contexte éditeur (les autoloads du jeu ne sont pas disponibles dans un plugin @tool).
ContactsPanel.gd et StorySettingsPanel.gd étendent tous deux StoryPanelBase.gd et reçoivent quatre callables injectés par StoryEditorPanel : get_scene_ids, begin_mutation, end_mutation, snapshot_file. Les deux panneaux communiquent avec le panneau principal via les signaux story_modified et error_occurred. ContactsPanel émet en plus rename_contact_requested, dont les écritures dans les fichiers de dialogue sont déléguées à StoryEditorPanel (qui possède _write_json).
Les scènes sont écrites via _write_json() qui appelle JsonUtils.ordered_scene() (tri sémantique des clés, défini dans json_utils.gd) puis JsonUtils.expand() (sérialiseur sur mesure : expansion jusqu'à la profondeur 3, compact au-delà). story.json utilise le même sérialiseur dans ContactsPanel.