Theatre Script Builder
mars 2025 → juin 2025

Theatre Script Builder est un outil d'écriture pour le spectacle vivant : composer un script de théâtre complet, avec ses dialogues mais aussi ses éclairages, ses sons, ses images et ses déplacements d'acteurs, puis l'exporter en PDF pour les répétitions.
Le projet vient d'une UE de communication et de gestion d'équipe du master, où l'on devait mener un projet collectif de théâtre. La pièce ne s'est finalement pas jouée, mais on a travaillé le texte et fait des répétitions, et j'en ai profité pour construire l'outil qui nous manquait. C'est un de mes premiers projets vraiment complexes, et je l'ai poussé loin avant de m'arrêter, en butant sur un stack que je découvrais presque entièrement.
Un script de théâtre n'est pas qu'un texte
Un script de théâtre est une partition. Il mêle du texte à lire et à dire, des indications techniques et des mouvements, le tout dans un ordre précis. C'est le point de départ, et c'est ce qui a guidé toute la modélisation.
Un script contient des éléments de natures très différentes :
| Élément | Ce qu'il porte |
|---|---|
| Dialogue | Un texte, attaché à un personnage |
| Narration | Un texte lu, éventuellement attribué à un personnage |
| Éclairage | Une position sur scène, une couleur, un état allumé/éteint |
| Son | Un fichier, une URL ou une vidéo YouTube, avec timecode, durée et marqueur d'arrêt |
| Image | Une image projetée, avec légende et dimensions |
| Mise en scène | Un élément de décor (un rideau), sa position, une description |
| Mouvement | Un déplacement d'acteur, d'un point vers un autre |
Chacun a ses propres champs, mais tous doivent vivre dans la même liste ordonnée, parce que sur scène, tout se déroule dans un ordre unique. Une indication d'éclairage s'insère entre deux répliques, un son se déclenche pendant un mouvement.
La solution retenue est une entité ScriptItem qui porte l'ordre et le type, associée à une table spécialisée par nature d'élément. La séquence est homogène, les données ne le sont pas. C'est ce qui permet d'insérer n'importe quel type d'élément à n'importe quelle position sans que le modèle proteste.
Les personnages ajoutent une nuance à laquelle je n'aurais pas pensé seul : chacun a un nom réel et un nom de scène. En répétition on appelle les gens par leur vrai nom, mais le script, lui, parle des personnages. L'outil affiche les deux, côte à côte, pour que tout le monde s'y retrouve.
Réordonner, encore et encore
Écrire un script, c'est surtout déplacer des choses. L'interface repose donc sur le glisser-déposer, avec dnd-kit, choisi pour son accessibilité : le réordonnancement fonctionne aussi au clavier, ce qui compte pour un outil qu'on utilise longtemps.
C'est simple sur dix éléments. Ça l'est beaucoup moins sur cinq cents. Le script de test de notre pièce en comptait près de sept cents, et c'est à cette échelle que les choses se compliquent : chaque déplacement doit renuméroter les positions et se refléter à l'écran sans tout ralentir. J'ai fini par mémoriser le rendu des éléments et regrouper les mises à jour de position, mais c'est le genre de problème que je n'avais pas anticipé en commençant.
La sauvegarde, mon vrai mur
C'est sur la persistance que j'ai le plus appris, en découvrant tout en même temps : l'App Router de Next.js, les Server Actions, Prisma, une base Postgres serverless sur Neon.
Le principe est que l'on modifie un script librement, puis qu'on enregistre, avec un indicateur qui signale les changements en attente. Un store Zustand tient l'état côté client, les Server Actions écrivent en base. Sur le papier c'est net ; en pratique j'ai passé beaucoup de temps sur les cas limites, et surtout sur le volume. Enregistrer un gros script déclenchait des transactions si longues qu'il a fallu pousser leur délai d'expiration à plusieurs minutes.
Une partie du problème venait d'un choix que je ferais autrement aujourd'hui : les images et les sons importés étaient stockés directement en base, encodés en base64. Pratique au début, parce que tout tient dans une seule table, mais chaque élément média pèse lourd et alourdit toutes les opérations autour. Sur un script chargé en images, la base gonfle vite.
Fait pour être utilisé à plusieurs, et vite
Le projet était collectif, et l'outil devait suivre. Deux exigences ont guidé l'interface. D'abord la rapidité : en répétition, on modifie un script en permanence, donc ajouter un élément, le déplacer ou le corriger devait se faire sans y penser. Ensuite le partage : un script n'appartient pas à une seule personne. Il n'y a pas de comptes, chaque script vit sur son URL, que toute l'équipe pouvait ouvrir.
L'export et l'import en JSON jouaient un double rôle, sauvegarde et échange. On exporte un script, on en garde une copie, on le réimporte ailleurs. Sur un projet où le fichier représente des heures de travail collectif, pouvoir en faire une sauvegarde qu'on maîtrise comptait autant que le reste.
L'export PDF
L'export PDF n'était pas un bonus, c'était la finalité. En répétition, personne ne travaille devant un écran : on a le script sur papier, annoté, corné. Tant que l'outil ne produisait pas un document imprimable propre, il ne servait pas à grand-chose.
L'export génère un PDF côté client avec react-pdf, en composant le document comme une interface React. La difficulté n'est pas technique mais typographique. Un script de théâtre a des conventions de mise en page : la position du nom du personnage, l'indentation des didascalies, la manière dont les indications techniques se distinguent du texte dit. Reproduire ces conventions demande d'abord de les comprendre, ce qui m'a obligé à regarder comment de vrais scripts sont mis en page.
Ce que j'en retire
C'est le projet qui m'a fait passer un cap. Avant, j'avais surtout écrit des scripts et des petits outils ; là, j'ai monté une vraie application full-stack, avec une base de données, une interface riche et un stack que je ne connaissais pas. J'ai beaucoup galéré, sur la sauvegarde, sur le tri, sur les gros volumes, et ces galères sont exactement ce qui m'a fait progresser.
Il m'a aussi appris à écouter un métier que je ne connaissais pas. Les décisions qui comptent ici, l'ordre unique, la distinction entre le technique et le dit, le nom réel à côté du nom de scène, l'export sur papier, ne viennent pas de considérations d'ingénierie. Elles viennent de la façon dont on travaille en répétition.
Le projet s'arrête au stade du prototype, la pièce ne s'étant pas montée, mais il a servi pendant qu'on répétait, et c'est celui sur lequel j'ai le plus appris en tant que développeur à ce moment-là.