Files
Ange-Marie MAURIN - A2M Systèmes e231e643cd refactor(studio): l'interface passe dans studio/ui, studio/ devient l'ensemble host + ui
Studio regroupe l'exécutable hôte (C++, à venir dans studio/host) et l'interface web (TypeScript, studio/ui). Chemins mis à jour dans les scripts, .gitignore et la documentation ; paquet renommé @sequa/studio-ui.
2026-11-06 22:24:27 +01:00

9.0 KiB

SEQUA Studio

SEQUA signifie Simulate Environments, Quantify Uncertainty, Adapt : simuler des environnements, quantifier l'incertitude liée à leur représentation et aux traitements, puis adapter les méthodes de calcul et de rendu au contexte. SEQUA Engine réunit quatre couches : Studio (la création), Core (la source de vérité : projet, simulation déterministe, rejeu, intentions, orchestrateur de rendu, confiance), SEQUA 3D (le contrat de données et la synchronisation vers les moteurs) et des moteurs 3D interchangeables (Godot, puis Unreal, à terme un moteur maison). SEQUA possède le projet et pilote les moteurs ; il n'est pas un plugin d'un autre moteur.

Rôle de Studio

Studio est le cœur et le visage du produit : c'est là que l'auteur exprime son intention, règle le ressenti, compose les modes de jeu et compare des variantes. Studio est une application web TypeScript indépendante de tout moteur ; il ne parle au Core que par un protocole (WebSocket et schéma partagé, Protobuf ou FlatBuffers — format non encore choisi). Son conteneur (navigateur, webview système, CEF) est un détail remplaçable.

L'interface est une vue d'un modèle d'état sérialisable : elle ne porte aucune logique produit. Les interactions produisent des événements, l'état évolue uniquement par une fonction pure de réduction, puis la vue est réaffichée.

État actuel

Squelette sans framework UI ni bibliothèque de composants :

  • projet Vite + TypeScript strict, tests Vitest ;
  • état minimal sérialisable (connection, protocolVersion, version du Core, raison de la dernière déconnexion, liste d'intentions vide) et réduction pure ;
  • interface sobre affichant le titre, le statut de connexion, le badge « Core simulé » ou « Core réel », la version du Core et la raison de la dernière déconnexion ;
  • connexion simulée par défaut : SimulatedCoreConnection n'ouvre aucune socket et reproduit la séquence connecting → connected avec une version de Core fictive marquée comme simulée ;
  • connexion réelle optionnelle : WebSocketCoreConnection utilise l'API WebSocket native du navigateur, sans bibliothèque, et effectue la poignée de main hello → welcome ;
  • messages JSON provisoires dans src/protocol/messages.ts, en attendant le schéma partagé (Protobuf ou FlatBuffers, fixé par une ADR) ;
  • faux Core de développement (tools/mock-core.mjs) pour tester le chemin WebSocket sans compiler le C++ (voir ci-dessous) ;
  • pas encore de reconnexion automatique.

Se connecter à un Core

Par défaut, Studio reste en mode simulé. Pour viser un Core réel, ajouter le paramètre d'URL core avec une URL ws:// ou wss:// :

http://localhost:5173/?core=ws://127.0.0.1:9100

Tout autre schéma (ou une URL invalide) est refusé : Studio reste en simulé et affiche la raison. Le vrai Core est l'exécutable sequa-core ; pour le développement sans le compiler, voir « Faux Core de développement » ci-dessous.

Le format des messages est provisoire et confiné à src/protocol/ :

  • enveloppe { "v": 1, "type": "...", "payload": { ... } } ;
  • client → Core : hello { protocolVersion, client: "sequa-studio" } ;
  • Core → client : welcome { protocolVersion, coreVersion } et error { code, message } ;
  • la poignée de main réussit si la version majeure de welcome.protocolVersion est celle de Studio et, tant que cette majeure vaut 0 (API instable selon semver), si la mineure est identique aussi ; un message error, un message indécodable, une version incompatible ou un délai de poignée de main dépassé (5 s par défaut) ferme le socket et affiche la raison.

Ce format sera remplacé par un schéma binaire généré depuis schema/ ; aucun autre module ne doit en dépendre.

Faux Core de développement

Pour tester le chemin WebSocket sans compiler le vrai Core (l'exécutable sequa-core), Studio fournit un faux serveur Core dans studio/ui/tools/mock-core.mjs :

  • SIMULÉ : ce serveur n'est pas le Core. Il imite uniquement le protocole WebSocket du vrai Core (hello → welcome / error, mêmes messages d'erreur, mêmes codes de fermeture 1002/1003/1008…) et ne fournit aucune donnée réelle ;
  • aucune dépendance : modules node: uniquement, implémentation minimale de la RFC 6455 (poignée de main, trames client masquées, ping → pong, close propre, trames fragmentées refusées) ;
  • écoute par défaut sur 127.0.0.1:9101 (jamais sur toutes les interfaces) et journalise chaque connexion et message.

Six scénarios couvrent des cas d'erreur difficiles à provoquer avec le vrai Core :

Scénario (--scenario) Comportement du faux Core Effet côté Studio
ok poignée de main normale : hello → welcome Core réel connecté, version 0.0.0-mock
incompatible répond welcome avec une version de protocole d'une autre mineure déconnexion : « Version de protocole incompatible »
error répond error { code: 'incompatible-protocol', … } puis ferme (1008), comme le vrai Core déconnexion avec la raison du Core
silent ne répond jamais délai de poignée de main dépassé (5 s)
garbage répond du texte non JSON « Message illisible pendant la poignée de main »
close ferme immédiatement (code 1011 + raison) déconnexion avec la raison de fermeture

Lancement autonome (arrêt : Ctrl+C) :

npm run mock-core                      # scénario ok sur ws://127.0.0.1:9101
npm run mock-core -- --scenario error --port 9200
node tools/mock-core.mjs --help

Ou lancement couplé à Studio (le faux Core démarre en arrière-plan et s'arrête avec Studio) :

.\scripts\studio.ps1 -MockCore                 # ouvre Studio sur le faux Core
.\scripts\studio.ps1 -MockCore -Scenario garbage
MOCK_CORE=garbage ./scripts/studio.sh          # équivalent Unix

Les tests d'intégration tests/mock-core.test.ts connectent la vraie WebSocketCoreConnection à chaque scénario sur un port libre, via l'API startMockCore({ port: 0, scenario }) exportée par tools/mock-core.mjs.

Avertissement : le faux Core est un outil de développement, marqué SIMULÉ dans ses messages et au démarrage. Le vrai Core reste l'exécutable sequa-core ; seul ce dernier fournit des données réelles. Le faux Core écoute sur 9101 et le vrai sequa-core sur 9100 : les deux peuvent tourner en même temps. Si le port 9101 est déjà occupé, le faux Core refuse de démarrer avec un message explicite.

Commandes

Prérequis : Node.js 24 recommandé (Vitest 5 accepte ^22.12, ^24 et >=26 ; Vite 8 accepte ^20.19 ou >=22.12).

npm ci          # installation reproductible depuis package-lock.json
npm run dev     # serveur de développement Vite
npm run check   # typecheck, tests, puis build de production

Autres scripts : npm run typecheck (tsc --noEmit), npm run test (vitest run), npm run build (vite build), npm run preview, npm run mock-core (node tools/mock-core.mjs, le faux Core de développement).

Structure

studio/
├── index.html
├── package.json
├── tsconfig.json
├── src/
│   ├── main.ts                 # montage dans #app, câblage connexion ↔ vue
│   ├── style.css               # thème sombre minimal
│   ├── model/state.ts          # StudioState, événements, état initial, reduce pure
│   ├── protocol/
│   │   ├── connection.ts       # interface CoreConnection + connexion SIMULÉE
│   │   ├── messages.ts         # messages JSON provisoires (encode/decode validants)
│   │   └── websocket.ts        # connexion WebSocket réelle (API native)
│   └── ui/app.ts               # rendu de l'état et actions de connexion
├── tools/
│   ├── mock-core.mjs           # FAUX Core de développement (SIMULÉ) : serveur WebSocket RFC 6455
│   └── mock-core.d.mts         # types publics du faux Core (contrat pour les tests)
└── tests/
    ├── state.test.ts
    ├── connection.test.ts
    ├── messages.test.ts
    ├── websocket.test.ts
    ├── mock-core.test.ts       # intégration : vraie WebSocket contre le faux Core
    └── node-net.d.ts           # déclarations minimales de node:net pour ces tests

Licences

SEQUA Studio est distribué sous Mozilla Public License 2.0 (MPL-2.0). Chaque fichier source porte son identifiant SPDX.

Dépendances directes de développement (versions et licences relevées dans node_modules/<paquet>/package.json après installation) :

Paquet Version Licence
vite 8.3.6 MIT
typescript 7.0.2 Apache-2.0
vitest 5.1.0 MIT

Ce sont les seules dépendances directes. Les paquets transitifs nécessaires à Vite, TypeScript et Vitest sont verrouillés par package-lock.json et restent des dépendances de développement, absentes du build de production en dehors des fichiers générés par Vite.