Frontend public pour l'association MO5, construit avec SolidJS. Ce projet gère la partie publique du site (billeterie, événements publics, mini-jeu).
Note : Ce projet est le frontend public. Pour le backend, voir Ocelot. Pour l'interface d'administration, voir Solid.
Liquid est le frontend public du système MO5. Il s'adresse à tous les visiteurs du site de l'association, sans authentification requise.
- Accessibilité : Site public accessible à tous
- Billeterie : Achat de billets pour les expositions
- Information : Présentation de l'association et des événements
- Divertissement : Mini-jeu pixel art intégré
- Billeterie publique pour les expositions
- Affichage des événements publics
- Mini-jeu pixel art intégré
- Informations pratiques sur l'association
L'authentification, la gestion des membres, les cotisations et l'administration sont gérées par d'autres applications (voir Architecture).
- Node.js 22+ : Télécharger Node.js
- Sur Windows : Télécharger l'installateur
.msidepuis le site officiel - Sur macOS : Utiliser Homebrew (
brew install node@22) ou télécharger l'installateur - Sur Linux : Utiliser le gestionnaire de paquets de votre distribution
- Vérifier l'installation :
node --version(doit afficher v22.x.x ou supérieur)
- Sur Windows : Télécharger l'installateur
- Yarn : Installer après Node.js avec
npm install -g yarn - Backend Ocelot : Le backend doit être lancé séparément (voir Ocelot)
- Rendez-vous sur nodejs.org
- Téléchargez la version LTS (Long Term Support) recommandée (22.x ou supérieur)
- Lancez l'installateur et suivez les instructions
- Vérifiez l'installation en ouvrant un terminal :
node --version npm --version
npm install -g yarnVérifiez l'installation :
yarn --version# Cloner le projet
git clone <repository-url>
cd liquid
# Installer les dépendances
yarn install
# Configurer les variables d'environnement
cp env.example .env
# Éditer .env avec l'URL du backend Ocelotyarn devL'application sera accessible sur http://localhost:5173 (ou le port indiqué dans la console).
Le mini-jeu est accessible via la route /game une fois l'application lancée.
Le système MO5 est composé de trois applications distinctes :
-
Liquid (ce projet) : Frontend public
- Billeterie publique
- Affichage des événements
- Mini-jeu
- Informations pratiques
-
Ocelot : Backend API
- Authentification Discord OAuth2
- Gestion des paiements (SumUp)
- Base de données PostgreSQL
- API REST pour les applications frontend
-
Solid : Interface d'administration
- Gestion des membres
- Gestion des événements
- Gestion des cotisations
- Outils administratifs
src/
├── features/ # Features métier
│ ├── ticketing/ # Billeterie publique
│ ├── events/ # Affichage des événements publics
│ ├── mini-game/ # Mini-jeu pixel art
│ └── lang-selector/ # Sélecteur de langue
├── routes/ # Routes de l'application
│ ├── [lang]/ # Routes avec paramètre de langue
│ └── index.tsx # Redirection initiale
├── ui/ # Composants réutilisables
├── utils/ # Utilitaires
│ └── get-browser-lang.ts # Détection langue navigateur
└── types/ # Types TypeScript globaux
Le frontend communique avec Ocelot via des appels API REST. L'authentification est gérée par Ocelot via Discord OAuth2.
Le site supporte plusieurs langues (français et anglais) avec une gestion basée sur les routes.
Les routes sont organisées avec un paramètre de langue dans l'URL :
/ → Redirection automatique vers /fr ou /en
/[lang] → Page d'accueil (ex: /fr, /en)
/[lang]/game → Mini-jeu (ex: /fr/game, /en/game)
/[lang]/ticket → Billeterie (ex: /fr/ticket, /en/ticket)
-
À la première visite (
/) :- La langue est détectée automatiquement depuis les préférences du navigateur (
navigator.language) - Redirection vers
/frou/enselon la langue détectée - Par défaut :
/frsi la langue du navigateur n'est pas l'anglais
- La langue est détectée automatiquement depuis les préférences du navigateur (
-
Navigation :
- La langue est stockée dans le localStorage après sélection
- Le sélecteur de langue dans le header permet de changer de langue
- Le changement de langue met à jour l'URL et le localStorage
src/routes/[lang]/: Routes avec paramètre de languesrc/routes/index.tsx: Redirection initiale basée sur la langue du navigateursrc/features/lang-selector/: Composant et logique de sélection de languesrc/utils/get-browser-lang.ts: Utilitaire pour détecter la langue du navigateur
# Lancer tous les tests
yarn test
# Tests en mode watch
yarn test --watch
# Tests avec interface UI
yarn test:ui
# Tests avec couverture
yarn test:coverageLe projet utilise Tailwind CSS v4 avec des couleurs personnalisées définies dans src/app.css :
@theme {
--color-bg: #f2f2f2;
--color-primary: #4088cf;
--color-secondary: #e84855;
--color-discord: #5468ff;
/* ... */
}yarn dev # Développement
yarn build # Build de production
yarn start # Serveur de production
yarn lint # Linting
yarn test # Tests
yarn test:ui # Tests avec UI
yarn test:coverage # Tests avec couverturedocs/: Documentation techniquedocs/features/: Documentation des featuresdocs/architecture/: Architecture et tech stack
Le projet inclut un mini-jeu développé avec MelonJS, un moteur de jeu JavaScript pour jeux 2D en pixel art.
Les fichiers sources du jeu se trouvent dans les dossiers suivants :
src/features/mini-game/: Code source principal du mini-jeumini-game.tsx: Composant React/SolidJS minimal qui gère le conteneur du jeugame.init.ts: Initialisation centralisée de MelonJS (logique principale du jeu)entities/player.ts: Logique du joueur (mouvement, collisions, animations)entities/HUD.ts: Interface utilisateur du jeuscreens/start.ts: Écran de démarrage et chargement des niveauxscreens/loading.ts: Écran de chargement personnaliséressources.ts: Liste des ressources à charger (sprites, sons, niveaux)game-state.ts: État global du jeumini-game.types.ts: Types TypeScript pour le jeu
-
public/game/entities/: Sprites du joueurlulu.aseprite: Fichier source Aseprite du personnagelulu.png: Sprite sheet exportéelulu.json: Métadonnées des animations (frame tags, durées)
-
public/game/tiles/: Tilesets et niveauxtileset.png: Tileset principal (8x8 pixels par tile)tileset.tsx/tileset.json: Définitions du tilesetstart.tmx: Niveau de départ (format Tiled)start.aseprite: Fichier source Aseprite du niveaustart.png: Image exportée du niveau- Autres niveaux :
home.tmx,interlude.tmx,final.tmx, etc.
-
public/game/sounds/: Sons et effets sonoresjump.mp3: Son de sautspike.mp3: Son de chute/impact- Autres sons :
hurt.mp3,explosion.mp3, etc.
-
public/game/fnt/: Polices bitmapPressStart2P.*: Police pixel art pour l'interface
Le code du jeu a été structuré pour éviter les problèmes de nettoyage et de réinitialisation avec MelonJS :
Pourquoi garder le jeu en vie ?
MelonJS est une bibliothèque complexe qui gère de nombreux états internes (game loop, ressources, événements, etc.). Lors du changement de page ou du démontage du composant, tenter de nettoyer complètement MelonJS peut causer :
- Erreurs de référence :
Cannot read properties of undefined (reading 'length') - Fuites mémoire : Références circulaires non résolues
- Problèmes de réinitialisation : Conflits lors de la réinitialisation après nettoyage
Solution adoptée :
- Initialisation unique : Le jeu est initialisé une seule fois dans
game.init.tsavec un gardegameInitialized - Pas de nettoyage agressif : Le composant
mini-game.tsxne nettoie pas MelonJS lors du démontage - Réutilisation : Si le composant est remonté, MelonJS réutilise l'instance existante au lieu de créer une nouvelle
- Séparation des responsabilités :
mini-game.tsx: Gère uniquement le conteneur DOM et la propinitgame.init.ts: Contient toute la logique d'initialisation MelonJS (une seule fois)
Cette approche garantit une stabilité maximale et évite les bugs liés au cycle de vie des composants React/SolidJS.
src/features/mini-game/
├── mini-game.tsx # Composant minimal (conteneur + prop init)
├── game.init.ts # Initialisation MelonJS (singleton)
├── game-state.ts # État global partagé
├── ressources.ts # Définition des ressources
├── mini-game.types.ts # Types TypeScript
├── entities/
│ ├── player.ts # Logique du joueur
│ └── HUD.ts # Interface utilisateur
└── screens/
├── start.ts # Écran de jeu
└── loading.ts # Écran de chargement
Pour modifier les assets du jeu, vous aurez besoin de :
-
Aseprite (recommandé) : aseprite.org
- Pour éditer les sprites du joueur (
lulu.aseprite) - Pour créer/modifier les tilesets
- Export en PNG avec métadonnées JSON pour les animations
- Alternative gratuite : Piskel (en ligne)
- Pour éditer les sprites du joueur (
-
Tiled Map Editor : mapeditor.org
- Pour créer et éditer les niveaux (fichiers
.tmx) - Format utilisé : TMX (Tiled Map XML)
- Les tilesets doivent être configurés dans Tiled
- Pour créer et éditer les niveaux (fichiers
-
Éditeur de texte : Pour modifier les fichiers JSON de configuration
- Les animations sont définies dans
lulu.json - Les ressources sont listées dans
ressources.ts
- Les animations sont définies dans
-
Modifier les sprites :
- Ouvrir
public/game/entities/lulu.asepritedans Aseprite - Modifier les animations (stand, walk, jump, grounded)
- Exporter en PNG et JSON depuis Aseprite
- Les frame tags définissent les animations dans
lulu.json
- Ouvrir
-
Créer/modifier un niveau :
- Ouvrir
public/game/tiles/start.tmxdans Tiled - Utiliser le tileset
tileset.png(8x8 pixels) - Dessiner le niveau avec les tiles
- Sauvegarder en
.tmx - Exporter l'image de prévisualisation si nécessaire
- Ouvrir
-
Ajouter des ressources :
- Ajouter les fichiers dans
public/game/ - Déclarer les ressources dans
src/features/mini-game/ressources.ts - Format :
{ name: 'nom', type: 'image|json|audio|tmx', src: 'chemin' }
- Ajouter les fichiers dans
-
Tester les modifications :
- Lancer
yarn dev - Accéder à
/gamedans le navigateur - Les ressources sont rechargées automatiquement en développement
- Note : Si vous modifiez
game.init.ts, vous devrez peut-être recharger complètement la page (F5) car l'initialisation est en singleton
- Lancer
- Sprites : Format PNG avec sprite sheet (toutes les frames sur une image)
- Animations : Définies dans JSON avec frame tags et durées personnalisées
- Niveaux : Format TMX (Tiled Map XML) avec tilesets PNG
- Sons : Format MP3/OGG pour compatibilité navigateur
Si vous devez forcer une réinitialisation complète du jeu (par exemple après des modifications majeures dans game.init.ts), vous pouvez :
- Recharger complètement la page (F5 ou Ctrl+R)
- Modifier temporairement
game.init.tspour réinitialiser le garde :// Dans game.init.ts, ligne 8 let gameInitialized = false // Forcer la réinitialisation
- Les logs de MelonJS apparaissent dans la console du navigateur
- Utilisez les DevTools pour inspecter le canvas et les ressources chargées
- En cas d'erreur, vérifiez que
game.init.tsn'a été appelé qu'une seule fois
- ⏳ Ticketing : Billeterie publique pour expositions (intégration avec Ocelot)
- ⏳ Public Events : Affichage public des événements
- ✅ Mini-jeu : Jeu pixel art intégré
- ⏳ Informations pratiques : Horaires, accès, contact
- ⏳ Galerie : Photos des expositions
- ⏳ Actualités : Blog/actualités de l'association
Note : Les fonctionnalités d'authentification, de gestion des membres, d'administration et de cotisations sont gérées par les autres applications du système MO5.
- Billeterie pour les expositions
- Événements publics à venir
- Informations sur l'association
- Mini-jeu pixel art
- Authentification Discord OAuth2
- API REST pour les applications frontend
- Gestion des paiements (SumUp)
- Base de données PostgreSQL
- Voir : github.com/Asso-MO5/ocelot
- Gestion des événements (création, modification)
- Gestion des membres et rôles
- Gestion des cotisations
- Rapports et statistiques
- Voir : github.com/Asso-MO5/solid
- Authentification gérée par Ocelot (Discord OAuth2)
- API sécurisée avec validation et CORS
- Cookies HTTP-only pour les sessions
- Communication HTTPS en production
- Fork le projet
- Créer une branche feature (
git checkout -b feature/nouvelle-feature) - Commit les changements (
git commit -m 'Ajouter nouvelle feature') - Push vers la branche (
git push origin feature/nouvelle-feature) - Ouvrir une Pull Request
Ce projet est sous licence MIT.
MO5 Liquid - Frontend public pour l'association MO5 🏛️
Repositories liés :