
Apres avoir livre le premier jalon complet de Rainbow Journey (archive sous le tag v0-astra-tango), nous avons mene une seance d'audit approfondie sur le code reel. Lorsque l'on passe d'une demo statique a un jeu au clavier dense a 30 notes par seconde, les moindres inefficacites du chemin chaud deviennent des goulets d'etranglement majeurs.
Le Lot 1 a ete concu pour repondre a un imperatif fondamental du cadrage : garantir un traitement synchrone a latence minimale, un rendu 3D a 60 FPS sans hoquet garbage collector et une persistance robuste sans perte de donnees.
Voici le recit technique et les arbitrages d'architecture de cette etape.
1. Le diagnostic du chemin chaud : pourquoi React et Three.js souffraient
Sous le jeu musical, un flux d'attaques et de relachements produit des dizaines d'evenements par seconde. En analysant le cycle de vie d'un message MIDI, trois problemes majeurs sont apparus :
- Re-rendus React massifs a chaque octet : Chaque
note onetnote offappelaitnotify(), declenchant un cycle de reconciliation complet deJourneyet des 88 touches dePiano. Dans chaque touche,runtime.notesetait appele 88 fois par rendu, regenerant des aplatissements deMapet des allocations d'objets inutiles. - Pression GC dans la boucle Three.js (
World.tsx) : A chaque frame (60 fois par seconde), l'orientation des rubans clonait unVector3par segment (direction.clone().normalize()), generant plus de 1 000 allocations de vecteurs par frame. De plus,runtime.trails.filter().slice(-128)allouait un tableau temporaire parmi 2 048 traces a chaque rafraichissement d'image. - Persistance synchrone et journal sature : Lors d'un enregistrement, chaque glissement de curseur dans l'editeur generait des centaines d'evenements
settingscontenant tout l'objet de configuration (schemas Zod, 32 regles, 28 effets). Toutes les 5 secondes, unstructuredClonecomplet de la session etait valide et ecrit en ouvrant puis refermant une connexion IndexedDB a chaque appel.
2. Les solutions d'architecture implementees
Pour eliminer ces goulots sans casser la simplicite du code, nous avons decoupe le travail en paquets autonomes sans concurrence sur les fichiers.
A. Rendu 3D sans allocation (src/World.tsx)
- Vecteurs pre-alloues : Utilisation d'un vecteur d'orientation statique
directionUnitreinitialise via.copy().normalize(), supprimant totalement les instanciations deVector3dans la boucle d'animation. - Parcours arriere borne : Remplacement de l'allocation
.filter().slice(-128)par une boucle arriere directe dans le tableau circulaire des traces, collectant jusqu'a 128 elements actifs dans une structure pre-allouee. - Cache d'uniformes et de terrain : Les 12 couleurs de l'eau ne sont recalculees que lorsque les reglages de palette ou l'ancre changent, et le bruit de Perlin pour les arbres n'est appele que lorsque leur tranche de profondeur se renouvelle.
- Clamps capacitaires : Protection explicite de tous les compteurs d'instances (
InstancedMesh) pour eviter les debordements de memoire GPU.
B. Coalescence et caches paresseux (src/runtime.ts, src/ui.tsx)
- Notifications rAF batchees : Les evenements MIDI sont immediatement et synchroniquement routes vers le port physique et inscrits dans le journal, mais la notification des composants React (
notify()) est coalescee une fois par frame viarequestAnimationFrame. Pour les actions directes de l'utilisateur (Panic, arret d'enregistrement, changement de mode, deplacement de curseur),notifyNow()garantit une reactivite instantanee. - Cache par version de mutation : Les getters couteux
notes,nextetharmonysont memoises et invalides uniquement lorsquedataVersionchange. - Extraction et memoisation de
Key(React.memo) : Le piano virtuel pre-calcule unSetdes notes actives en $O(1)$ et delegue chaque touche a un composant memoise qui ne re-rend que si son statut (actif, fantome, autorise) change.
C. Theorie musicale enrichie et accords stabilises (src/music.ts)
- Intervalles composes (13 a 24 demi-tons) : Le rayon melodique configurable jusqu'a 24 demi-tons affichait auparavant des codes Tonal bruts (
15P,9M). Ils sont desormais traduits en francais pur : Neuvieme majeure, Onzieme juste, Double octave, avec indication du sens (ascendant / descendant). - Fenetre de stabilisation d'accord (40 ms) : Lors du jeu en arpege, le nom de l'accord ne clignote plus au passage de chaque note transitoire ; le moteur attend que le jeu se pose 40 ms pour emettre l'accord stabilise.
D. Stockage persistant et file in-flight + latest (src/session.ts, src/runtime.ts)
- Singleton IndexedDB : La connexion a la base locale
rainbowjourneyreste ouverte et partagee via une promesse singleton reutilisee. - Coalescence des reglages : Les deplacements successifs de curseurs sous 150 ms sans note MIDI intermediaire remplacent le dernier snapshot au lieu de gonfler le journal de centaines d'entrees redondantes.
- File de sauvegarde non bloquante : Le mecanisme
in-flight + latestgarantit qu'une sauvegarde automatique n'empile jamais de promesses concurrentes tout en assurant que le dernier snapshot d'arret est toujours ecrit.
E. Accessibilite complete et ecran de repli (src/Editor.tsx, src/Sessions.tsx, src/main.tsx)
- Navigation au clavier complet : La barre d'onglets de l'editeur implemente les roles ARIA
tablist/tabpanelavec navigation fluide aux fleches directionnelles gauche/droite. - Touche Escape & Restauration du focus : Les tiroirs et boites de dialogue se ferment proprement a la touche
Escapeet restituent le focus sur le bouton qui les a ouverts. - Piege de focus modal : La bibliotheque des parcours capture les tabulations pour eviter de perdre le focus derriere la modale.
- React ErrorBoundary : En cas d'exception inattendue, l'application ne presente plus d'ecran blanc muet mais un ecran de recuperation en ASCII avec reinitialisation controlee.
3. Bilan de la verification et des metriques
A l'issue de ce lot, tous les garde-fous de qualite ont ete executes et valides :
- Vitest : 25 tests unitaires et d'integration (4 suites) — 100% verts (contre 12 initialement).
- Playwright E2E : 8 scenarios complets sur navigateur Chromium reel avec GPU D3D11 — 100% verts (dont 4 tests d'accessibilite clavier natifs).
- TypeScript (
tsc -b) : 0 erreur. - ESLint : 0 avertissement.
- Production Build : Compile et minifie sans erreur.
- Securite : 0 vulnerabilite signalee par
npm audit. - CI : Workflow GitHub Actions operationnel.
4. Prochaine etape : Le test en temps reel collaboratif
Avant de coder les fonctionnalites du Lot 2 (modulation expressive des effets, historique de 4 attaques, stockage par blocs et projection des touches), la prochaine seance consistera a brancher le piano physique Bird DP1 pour une session d'improvisation collaborative en direct.
Nous mesurerons les sensations de jeu, la pertinence des suggestions et l'impact visuel des rubans pour calibrer ensemble les futurs developpements.