Aller au contenu

Transcendance

Python Django JavaScript HTML5 Canvas PostgreSQL Docker Nginx

Projet final du tronc commun de l'école 42 : créer une application web complète permettant de jouer au Pong en local.


Présentation

Une application web full-stack pour jouer au Pong en local : 1 contre 1, 4 joueurs, tournoi, interface multi-langue avec gestion des comptes utilisateurs.


Contexte

Transcendance est le dernier projet du tronc commun 42. L'objectif était de concevoir une application web full-stack fonctionnelle, déployable via Docker, intégrant un jeu Pong jouable en local sur un même navigateur. Le projet combinait développement back-end (API REST), front-end (rendu Canvas), gestion d'utilisateurs, base de données relationnelle et conteneurisation, le tout en solo.


Mon rôle

Développeur full-stack solo sur l'ensemble du projet :

  • Back-end : Django 4.2, modélisation PostgreSQL, API REST (Django REST Framework), authentification, gestion des profils et des scores
  • Front-end : moteur de jeu Pong en vanilla JavaScript sur <canvas> HTML5, gestion des entrées clavier et tactile, IA adverse
  • Infra : Docker Compose (3 conteneurs), configuration Nginx avec SSL/TLS, migrations Django

Architecture

Architecture de Transcendance

Schéma de l'architecture de Transcendance

Les requêtes HTTP entrent par Nginx, qui termine le SSL et les transmet à gunicorn ; Django aiguille vers les apps pong et utilisateurs, interroge PostgreSQL et renvoie un HTML rendu côté serveur, pendant que le moteur de jeu s'exécute en JavaScript sur le canvas du navigateur.

Étape Rôle Dans le code
Navigateur L'utilisateur charge /pong/ ; le moteur de jeu démarre sur le canvas pong.js, router.js, HTML5 Canvas
Nginx Reverse proxy, terminaison SSL/TLS, service des fichiers statiques nginx/nginx.conf (port 8080)
Gunicorn Serveur WSGI qui exécute Django conteneur web, proxy_pass http://web:8000
Django Routage des URLs, vues, API REST, auth de session apps pong + utilisateurs, viewsets DRF
PostgreSQL Persistance des profils, scores, duels, tournois modèle Player + ArrayField

Deux apps Django : utilisateurs (inscription, connexion, déconnexion) et pong (jeu, profil, amis, scores).

Côté client, un routeur JavaScript (router.js) récupère le HTML par fetch() et applique la langue : un fonctionnement type SPA sans framework.


Technologies

Back-end
Python 3.12
Langage principal du back-end.
Django 4.2
Framework web : ORM, auth, templates, admin.
Django REST Framework
API REST avec serializers et viewsets.
Front-end
JavaScript vanilla
Moteur de jeu, gestion DOM, appels API fetch().
HTML5 Canvas
Rendu du terrain de jeu, raquettes, balle, score.
Bootstrap 5
Composants UI : modals, boutons, formulaires.
Base de données
PostgreSQL 15
Stockage des profils, scores, duels, tournois, amis.
ArrayField (psycopg2)
Tableaux d'historique sans jointures - duels, positions de tournoi.
Infra & DevOps
Docker Compose
Orchestration de 3 conteneurs avec volumes et migrations.
Nginx
Reverse proxy SSL, proxy_pass, fichiers statiques.
Makefile
Commandes make create, make re, make fclean, make psql…
Déploiement
SSL/TLS
Certificats auto-signés, TLSv1.2/1.3.
Gunicorn
Serveur WSGI production derrière Nginx.
Migrations Django
makemigrations + migrate via Makefile.

Fonctionnalités

  • Mode Solo : partie contre l'IA, premier à 3 points
  • 1v1 local : deux joueurs, un clavier (W/S vs flèches)
  • 4 joueurs : quadra sur canvas carré, 4 palettes colorées avec murs d'angles
  • Tournoi 4 : bracket saisi par l'utilisateur, demi-finales + finale
  • Multi-langue : FR, EN, ES - toute l'interface traduite via balises lang="" et routeur JS
  • Profil & avatar : création, modification du mot de passe, suppression de compte
  • Système d'amis : ajout par nickname, liste persistante, statut en ligne
  • Scores & historique : wins/loses, détail par duel (adversaire, score, date), positions de tournoi

Problème | Solution

Problème Solution
Le jeu devait être jouable de 320px (mobile) à 1440px+ sans distortion Calcul dynamique des dimensions Canvas avec 5 paliers de window.innerWidth, normalisation de toutes les positions par canvas.height / 1000
La balle accélérait indéfiniment après chaque rebond, rendant le jeu ingérable Conservation de la vitesse totale via Pythagore : speed = √(12² − speedy²) à chaque collision - la vitesse reste constante quelle que soit l'angle
Une IA qui suit simplement la balle est trop facile à battre L'IA prédit le point d'intersection y de la trajectoire au niveau de sa raquette, puis ajoute un bruit aléatoire (±10px) pour une difficulté imparfaite mais crédible

Résultats

  • 4 modes de jeu fonctionnels (solo, 1v1, 4 joueurs, tournoi)
  • 3 langues complètes (FR, EN, ES)
  • Déploiement Docker en une commande (make create)
  • API REST complète : 5 viewsets DRF pour scores, tournois, profils, langues, statuts

Lancement

make create        # docker compose up --build + migrations + superuser
make psql          # accès au shell PostgreSQL
make fclean        # arrêt total + purge des volumes et images

Ce que j'ai appris

Transcendance m'a appris que la plupart des projets "temps réel" en 42 ne le sont pas vraiment.

La vraie difficulté n'est pas le networking, mais la gestion de l'état côté client : qui possède la balle, quand le tour change, comment un score se propage au back-end.

J'ai aussi compris pourquoi Docker n'est pas qu'un outil de déploiement mais une contrainte d'architecture : séparer web, base et proxy m'a forcé à penser les interfaces entre composants avant d'écrire la première ligne de code.


Lien

Voir le code