Ava

Un jeu de cartes parti d’un prototype en JavaScript vanilla, migré progressivement vers React 19 et Symfony : comptes, classement ELO, replays, 1v1 en ligne et version mobile, sans jamais casser le jeu en cours de route.

Le point de départ


Le prototype tenait dans un monolithe vanilla JS. D’un côté, engine.js (environ 3 600 lignes) portait les règles et l’état, et ai.js (environ 800 lignes) l’adversaire. De l’autre, app.js faisait le rendu à la main dans le DOM. 
Tout l’état vivait dans un seul objet global mutable, window.AVA.state, et le CSS s’empilait version après version, avec beaucoup de doublons et de !important.

Le jeu fonctionnait, mais chaque évolution devenait risquée, et l'utilisation du localstorage donnait l'illusion d'une persistance des données mais il n'y avait aucun vrai backend ni BDD en place.

Une migration progressive vers React


Plutôt que de tout réécrire, j’ai d’abord porté l’interface en gardant le moteur intact. 
Toute l’UI a été réécrite en composants React avec Vite, le style est passé en SCSS, et les règles CSS mortes ont été supprimées.

Ensuite, j’ai découpé engine.js en un fichier par fonctionnalité (combat, mouvement, économie, pioche, objets, tutoriel, IA), puis migré la logique métier fonction par fonction vers des hooks : useCombat, useMovement, useDrawPhase, useIncome… 
Zustand gère l’état partagé de l’interface : aide, tooltips, ELO.


Comptes, classement et sauvegardes


Côté back-end, une API Symfony gère les éditions, les cartes et les utilisateurs, avec une authentification JWT. Les parties sauvegardées, les replays et l’ELO (calculé par mode et par édition, avec des grades) sont stockés en base. Le localStorage a été abandonné : tout ce qui doit durer passe par le serveur.

Le 1v1 en ligne


Deux joueurs créent un salon, s’invitent depuis leur liste d’amis et peuvent reprendre une partie interrompue. L’arène est synchronisée en tour par tour, avec une phase de défense, et un minuteur déclare forfait le joueur qui dépasse son temps. 
Mercure gère le lobby, les invitations et les notifications. 

Le mobile


La volonté principale était de garder des écrans sans sur toute l'application. 
L’arène et les mains sont réagencées, les actions passent dans un dock, et le combat s’ouvre dans une modale. 
J’ai refait l’architecture CSS par zones (arène, phases, banque, pioche, dock), et l’accueil comme l’arène tiennent maintenant sur un écran mobile sans scroll.

Méthodologie


Le projet étant plus complexe qu’un simple site, le suivi passe par un Trello, avec une liste de tickets par type de besoin (fonctionnel, UX/UI, responsive, données…). Le client crée ses tickets directement dans la bonne section et suit leur avancement.

Les cahiers des charges détaillés sont rédigés dans des Google Docs partagés, tout comme un point quotidien qui résume l’avancement. Des visios régulières permettent de tester ensemble les nouveautés et d’arbitrer les priorités.

Où en est le projet


Le jeu propose un mode solo contre l’IA, un tutoriel, deux éditions (médiévale et antique), le suivi ELO, les sauvegardes, les replays et le 1v1 en ligne, qui est le mode par défaut.

Le projet est toujours en cours de développement.

Boite à outils du projet:

  • React
  • Javascript
  • Zustand
  • Symfony
  • Mercure
  • Mysql
  • Sass

On discute ?