williamandClaude Sonnet 5 9fb22be1ae
Build and deploy / test-python (push) Failing after 1m5s
Build and deploy / test-js (push) Successful in 51s
Build and deploy / lint-python (push) Failing after 1m2s
Build and deploy / lint-js (push) Failing after 1m4s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Build and deploy / sonarqube (push) Failing after 1m0s
Quiz reellement interactif en Mode Apercu (voir maquette document-formation-web.html)
Le quiz affichait jusqu'ici la meme carte resume en edition comme en
Apercu. Ajoute un vrai questionnaire jouable, visible UNIQUEMENT en
Mode Apercu (masque en edition via CSS, jamais les deux a la fois) :
options de reponse cliquables, marquage correct/incorrect immediat,
score qui accumule les points de chaque question repondue
correctement, progression "Question suivante", et un ecran de
resultat final (score obtenu / total des points possibles) avec
"Recommencer le quiz" - structure et identite visuelle calquees sur
docs/plan/maquettes/document-formation-web.html (cartes en degrade,
options A/B/C/D, feedback vert/orange), adaptees aux tokens --doc-*
deja en place (theme clair/sombre inclus, nouvelles variables
--doc-quiz-success-*/--doc-quiz-danger-*).

Cote rendu (document_engine/rendering/render_document_element.py),
_render_quiz ajoute desormais le questionnaire (fonction privee
_render_quiz_player) des qu'au moins une question existe : les
questions sont embarquees en JSON dans un attribut data-quiz-config
(jamais un <script> par element), echappees pour l'HTML - aucun
aller-retour serveur pendant qu'on joue, tout le deroulé (reponse/
score/suivant/resultat) est gere par
static/document/js/document-editor.js. pointer-events, desactive sur
tout element en Apercu pour empecher la selection/le glisser-deposer
pendant le test, est reactive specifiquement dans le questionnaire
pour qu'il reste reellement cliquable.

Tests : 3 nouveaux tests de rendu purs (sans Flask, dont un qui
verifie l'echappement HTML du texte d'une question contre une
injection). Verifie en live via une simulation DOM complete
(basculer Apercu, repondre correctement puis incorrectement,
verifier score/feedback/etat des options, passer a la question
suivante, voir l'ecran de resultat) - le script de diagnostic n'a pas
ete conserve dans le depot.

SKIP=djlint : backlog H021 pre-existant, aucun template touche ici.
ruff/mypy --strict/vulture/bandit/import-linter/eslint/stylelint tous
verts ; 48 tests cibles (document + onboarding) verifies frais.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-20 12:08:03 +02:00
2026-08-21 16:23:49 +02:00
2026-08-21 16:23:49 +02:00
2026-08-21 16:23:49 +02:00

Forge Engine

Éditeur no-code de serious games 2D pour la formation professionnelle, dans le navigateur. Créé pour un public non technique (formateurs, RH) : aucune ligne de code, aucun graphe de logique générique — un assistant pas à pas pour chaque mécanique de jeu.

Voir .claude/Forge_Engine_Cadrage.pdf (non versionné, document business interne) pour le positionnement produit complet et l'analyse de marché qui a guidé les choix ci-dessous.

Lancer le projet

pip install -r requirements.txt
python3 app.py

Le navigateur s'ouvre automatiquement sur http://127.0.0.1:5050.

Ce que permet Forge Engine aujourd'hui

Chaque jeu créé est un RPG 2D : une ou plusieurs scènes (des décors à taille fixe), sur lesquelles on pose des personnages, un fond, et des widgets d'interface — tout au glisser-déposer, sans jamais toucher à du HTML/CSS/JS.

  • Personnages : bibliothèque de sprites prêts à l'emploi (personnages Kenney CC0 + animaux CraftPix pour les comptes admin), animés automatiquement (idle, marche...). Un rôle — Joueur (déplacement au clavier, suivi par la caméra), PNJ ou Ennemi — se choisit explicitement par personnage ; un personnage fraîchement posé est toujours "PNJ" par défaut.
  • Collision (onglet dédié de l'éditeur de scène) : pour chaque objet de la scène (jamais le joueur lui-même), un assistant "+ Action" construit une règle "déclencheur → action" pièce par pièce (jamais un formulaire à plusieurs champs) — à la collision ou dans un périmètre, déclencher une quête, ou une interaction au clavier ("Appuie sur ...") qui elle-même déclenche une quête. Toute la liste se met à jour en AJAX (ajout/suppression d'objet, changement de rôle/nom), sans jamais recharger la page.
  • Quêtes & dialogues : chaque quête a un titre, un objectif, une récompense, un statut et un résultat ; son dialogue se rédige séparément (3 colonnes — Nouvelle / En cours / Terminée — pour faire varier ce que dit un PNJ selon l'avancement).
  • Widgets d'interface : Boîte de dialogue, Boîte à quiz, Score — posés comme n'importe quel objet de scène, gérés automatiquement par le moteur de jeu (jamais de logique à câbler), avec leur propre style (police, couleurs) réglable une fois posés.
  • Export SCORM 1.2 natif (routes/game/publish/export_scorm.py) : un paquet .zip autonome (imsmanifest.xml + runtime hors-ligne), prêt à déposer dans un LMS (Moodle, 360Learning...) — score et statut de la partie remontent automatiquement.

Onboarding

Un seul parcours de création à l'inscription : RPG. La carte de choix (templates/onboarding/onboarding_new.html) se retourne pour présenter l'argumentaire produit.

Ce qui a été délibérément retiré

Une première version du moteur exposait aussi un type d'écran "document" — un éditeur générique façon no-code (blocs de logique en nœuds, timeline d'animation, définitions d'objets/champs/relations façon base de données, templates réutilisables). Cette complexité ne correspond à aucun besoin du public cible (formateurs non techniques) et a été supprimée pour recentrer entièrement le produit sur le jeu 2D — voir l'historique Git pour le détail de ce retrait.

Ce qui manque encore pour une mise sur le marché (voir le cadrage)

Sur les 6 fonctionnalités listées comme bloquantes (condition d'achat) par le document de cadrage, seul l'export SCORM est construit. Restent à faire : support xAPI, intégration LTI 1.3, hébergement UE + RGPD (DPA), accessibilité RGAA/WCAG 2.2 AA. L'export HTML5 responsive existe déjà via le mode Jouer.

Structure du code

app.py                     point d'entrée : assemble core/ + routes/, lance le serveur

core/                       pièces transverses (instance Flask, filtres Jinja, CSRF, auth)
filters/                    filtres Jinja restants (colname)

routes/                     une route HTTP = un fichier, regroupées par domaine
  auth/                       inscription, connexion, 2FA, mot de passe
  onboarding/                 parcours de création guidé ("Quel jeu veux-tu créer ?")
  games/                      créer/renommer/supprimer un jeu, tableau de bord ("Mes écrans")
  uploads/                    envoi de fichiers (images/vidéos)
  assets/                     upload/suppression des assets utilisateur
  game/                       tout ce qui est propre à l'éditeur Jeu 2D — voir docs/plan/PLAN.md
    screens/                    écrans du jeu (liste, création, renommage, taille de scène...)
    scenes/                     objets de scène (personnage/décor/fond/widgets), rôle, collision, nom...
    custom_events/              événements personnalisés (déclenchés/écoutés depuis une scène)
    flow/, flow_blocks/         moteur de logique à nœuds (partagé, utilisé par les règles de collision)
    animations/                 clips d'animation (Animate.css + images-clés)
    global_vars/                variables globales du jeu
    publish/                    export SCORM
    play/, public_play/         mode jouable
    triggers/, ia/               déclencheurs cross-écran, chat assistant Ruby
  document/                   futur éditeur Support de formation — vide pour l'instant

db/                         couche données bas niveau (SQLite, un fichier .db par jeu)
  games/                      cycle de vie d'un jeu, catalogue d'onboarding
  definitions/, rows/          objets de données typés + leurs lignes (utilisés par le flow)
  quests/                      quêtes et leur dialogue
  custom_events/, global_vars/, scoring/

game_engine/                couche rendu — un fichier par fonction
  scenes/                      objets de scène : ajout, rendu, rôle, collision, commandes, dialogue...
  rendering/                   personnage (data/animations/rôle), collision, dialogue, quêtes
  flow/                        moteur de logique à nœuds (partagé)
  data_actions/                exécution d'une action de flow (modifier une donnée, un score...)
  animations/, custom_events/, labels/, payload/, screens_repo/

templates/                  pages HTML (Jinja2) — base.html, auth/, onboarding/, dashboard : partagées
  game/                       scene_edit.html, play.html : propres à l'éditeur Jeu 2D
  document/                   futur éditeur Support de formation — vide pour l'instant
static/                     CSS + JS partagés (style.css, pjax.js, csrf_fetch.js, branding/, vendor/)
  game/                       tout ce qui est propre à l'éditeur Jeu 2D
    js/                         scenes/ = éditeur de scène, play/ = moteur de jeu, screen_edit/, triggers/, ia/
    characters/, backgrounds/, icons/, quiz-templates/   assets du jeu (sprites, fonds, icônes, aperçus de modèles)
  document/                   futur éditeur Support de formation — vide pour l'instant
projects/                   un sous-dossier par jeu créé (généré à l'usage, non versionné)

tests/                      suite pytest — conftest.py, tests génériques (auth, db, IA) à la racine
  game/                       tests propres à l'éditeur Jeu 2D
  document/                   futur éditeur Support de formation — vide pour l'instant

Tests

pip install -r requirements-dev.txt
pytest

Notes techniques

  • Navigation sans rechargement : la plupart des actions de l'éditeur de scène (ajout/suppression d'objet, sélection, changement de rôle/nom, règles de collision) passent par des appels fetch() dédiés qui ne touchent que le fragment de page concerné. La navigation entre pages différentes (ex. "Mes écrans" ↔ une scène) passe par static/pjax.js (interception des clics/formulaires, remplacement de <main> + #pageChrome) plutôt qu'un rechargement complet — toute règle CSS dont dépend une page doit donc vivre dans static/style.css (chargé partout), jamais dans un <style> inline propre à cette seule page, qui ne serait pas repris lors d'une navigation pjax vers elle.
  • Serveur de développement en mode threaded=True (app.py) : une scène charge plusieurs images en parallèle (personnages, fond) — sans ce réglage, le serveur Werkzeug mono-thread les sert une par une.
S
Description
No description provided
Readme
1.6 GiB
Languages
Python 55.5%
JavaScript 35.5%
HTML 6.5%
CSS 2.4%