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.
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 :
SimulatedCoreConnectionn'ouvre aucune socket et reproduit la séquenceconnecting→connectedavec une version de Core fictive marquée comme simulée ; - connexion réelle optionnelle :
WebSocketCoreConnectionutilise l'API WebSocket native du navigateur, sans bibliothèque, et effectue la poignée de mainhello→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 }eterror{ code, message }; - la poignée de main réussit si la version majeure de
welcome.protocolVersionest celle de Studio et, tant que cette majeure vaut0(API instable selon semver), si la mineure est identique aussi ; un messageerror, 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 vraisequa-coresur 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.