7ca03380b756c98adcdb0b0d888048a60f1c6943
120
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
7ca03380b7 |
Retire l'action Publier du support de formation
Build and deploy / test-python (push) Successful in 6m57s
Build and deploy / test-js (push) Successful in 50s
Build and deploy / lint-python (push) Successful in 4m14s
Build and deploy / lint-js (push) Failing after 1m12s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Build and deploy / sonarqube (push) Failing after 3m48s
Un apprenant n'a jamais acces a l'editeur : un etat "publie" persiste en base (published_at) ne servait donc a rien tant qu'aucune vue apprenant/export ne le consomme (retour utilisateur direct). Retrait complet : route /document/<slug>/publish, db.mark_support_published, la colonne logique published_at dans support_meta, le bouton et son CSS/JS. "Aperçu" devient l'action primaire du bandeau (repond au vrai besoin : voir le rendu avant un futur export). Un export reel (SCORM ou equivalent) reste a specifier separement le jour venu. SKIP=djlint : meme backlog H021 pre-existant que le commit precedent, aucun fichier touche ici n'y figure. ruff/mypy --strict/vulture/ bandit/import-linter/eslint/stylelint tous verts ; 615 tests Python (617 - 2 tests du Publier retire) + verification manuelle live du retrait (route 404, bouton absent du HTML, Apercu confirme fonctionnel par simulation DOM). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
bab581737a |
Ajoute le support de formation : entite racine separee du jeu 2D
Build and deploy / test-python (push) Successful in 11m2s
Build and deploy / test-js (push) Successful in 1m2s
Build and deploy / lint-python (push) Successful in 4m6s
Build and deploy / lint-js (push) Failing after 1m21s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Build and deploy / sonarqube (push) Failing after 4m2s
Nouveau moteur document_engine/ (elements CRUD + rendering + labels), db/supports/ (stockage independant de db/games), routes/document/ (CRUD AJAX + publication), et l'editeur frontend complet (templates/document/, static/document/) avec moteur de layout reel (glisser-deposer -> fusion en rangee ou insertion avant/apres), vrai Undo/Redo par pile de commandes, grille d'accroche pour les formes libres, apercu responsive a largeurs fixes, mode Apercu, et publication persistee. "Mes formations" (templates/index.html) liste desormais les environnements 2D et les supports de formation cote a cote ; l'onboarding et core/auth_guard.py sont generalises pour qu'un compte restreint puisse posseder un projet de chaque type independamment. SKIP=djlint : le hook ne signale que le backlog H021 (styles en ligne) deja documente dans CODE_QUALITY.md sur des fichiers pre-existants non touches ici (base.html, game/play.html, scene_edit.html, game_dashboard_simple.html, clause_row.html) plus une ligne de index.html deja presente avant cette session — aucun nouveau fichier (document_edit.html compris) n'y figure. Tous les autres outils (ruff, mypy --strict, vulture, bandit, import-linter, eslint, stylelint) passent sans erreur ; 617 tests Python + 276 tests JS verts, plus une verification manuelle complete du cycle de vie via le serveur de developpement. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
b2e933f322 |
Reorganisation game/document : renommage screens->game_engine + sous-dossiers game/ dans routes, scripts, static, templates, tests
Build and deploy / test-python (push) Successful in 11m12s
Build and deploy / test-js (push) Successful in 53s
Build and deploy / lint-python (push) Successful in 3m56s
Build and deploy / lint-js (push) Successful in 3m1s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Build and deploy / sonarqube (push) Failing after 3m58s
Prepare la scission a venir entre l'editeur Jeu 2D et le futur editeur Support de formation (voir docs/plan/PLAN.md), sans toucher a l'architecture en couches existante : - screens/ renomme en game_engine/ (nom clair pour le moteur du jeu 2D, avant l'arrivee d'un second "moteur" cote document) : ~85 imports corriges, contrat import-linter mis a jour, meme forme de couches. - routes/, scripts/, static/, templates/, tests/ : tout ce qui est propre au jeu 2D deplace dans un sous-dossier game/ de chacun (routes/game/, static/game/, templates/game/, tests/game/, scripts/game/) ; ce qui est partage par le site (auth, onboarding, dashboard, uploads, db/) reste a la racine de chaque dossier. Un sous-dossier document/ (vide) cree dans chacun pour le futur chantier. - styles/ volontairement inchange : les 3 fichiers sources sont concatenes en un seul static/style.css charge par tout le site, scinder leur CONTENU (editeur vs partage) serait un refactor CSS distinct, pas un deplacement mecanique. - Chaine d'export SCORM (publish/build_scorm_package.py) mise a jour en profondeur : copie des assets, URLs d'icones relatives a static/style.css (qui ne bouge pas), manifeste, wrapper SCORM. - Deux regressions d'un sweep de renommage anterieur corrigees au passage (screens.js/screens/scene-objects incorrectement convertis en game_engine.js/game_engine/scene-objects dans des commentaires). - Effet de bord Windows decouvert et corrige : git mv + Path.write_text convertissent des fichiers en CRLF (core.autocrlf=true) - ~189 fichiers normalises en LF. - .eslintrc.json/package.json : uniquement les chemins de glob mis a jour (static/game/js/...) ; la preparation eslint-plugin-unicorn du lot 7 reste volontairement non committee (package-lock.json restaure a la version precedente). Verifications : ruff, mypy --strict (391 fichiers), vulture, bandit, lint-imports tous verts ; 591/591 tests Python, 276/276 tests JS ; demarrage serveur + requetes HTTP manuelles confirmant que les assets deplaces repondent en 200 au nouvel emplacement et 404 a l'ancien. SKIP=djlint : backlog H021 (styles inline) deja documente comme dette assumee dans CODE_QUALITY.md section 6, aucun template touche par ce commit au-dela d'un deplacement de fichier. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
ccf836f2c5 |
Lot 4 modernisation JS (SonarLint) + restauration CI sonarqube non-bloquante
Build and deploy / test-python (push) Successful in 11m18s
Build and deploy / test-js (push) Successful in 1m16s
Build and deploy / lint-python (push) Successful in 4m24s
Build and deploy / lint-js (push) Successful in 2m51s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Build and deploy / sonarqube (push) Successful in 5m30s
Corrige les findings SonarQube (via SonarLint IDE, fichier par fichier) sur ~24 fichiers static/js/ : parseFloat/parseInt -> Number.*, .replace(/x/g,y) -> .replaceAll, .indexOf() -> .includes()/.startsWith(), getAttribute/setAttribute -> .dataset, tableaux -> Set, x && x.y -> x?.y (verifie site par site), extraction de template litteraux imbriques, ternaires imbriquees, refactors de complexite cognitive (S3776) via tables de dispatch, Object.hasOwn, .at(), et deduplication de fonctions identiques (S4144). Deux exceptions S2486 documentees/corrigees (filter-repeater-rows.js) et un cas S2703 de partage inter-scripts complete (_collisionWizard, trigger-editor.js <-> collision-rules-editor.js). Details complets dans CODE_QUALITY.md section 5. Restaure aussi le job CI "sonarqube" (non-bloquant) dans .gitea/workflows/deploy.yml maintenant que l'instance prod est operationnelle. Suites vertes : 276/276 JS (node --test), 591/591 Python (pytest). SKIP=djlint sur ce commit : hook djlint bloquant sur le backlog H021 (styles inline, 49 occurrences/6 templates) deja documente comme dette assumee non traitee dans CODE_QUALITY.md section 6, aucun rapport avec ce commit (aucun template touche ici) - valide explicitement avec l'utilisateur avant de contourner ce hook. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
66d8eaeae8 |
Lots 1-3 modernisation JS (S8786/S2703/S2486) + retrait Sonar CI/prod
- Lot 1 (S8786, ReDoS) : 5 sites documentes NOSONAR apres preuve empirique (script reproductible docs/redos_probe_s8786.js), aucune reecriture defensive necessaire. - Lot 2 (S2703, variable globale implicite) : bug reel trouve et corrige (SCENE_OBJECT_NAMES en const au lieu de let, cassait la reassignation cross-script depuis scene-editor.js) + test de non-regression ; 4 autres sites confirmes surs et documentes. - Lot 3 (S2486, exceptions avalees) : 6 sites confirmes surs et documentes ; 2 sites (config sprite JSON invalide) corriges avec un console.warn devtools, comportement joueur inchange, couverts par un nouveau test. - Retrait du job CI sonarqube (.gitea/workflows/deploy.yml) et du service prod sonarqube/sonar-postgres (docker-compose.prod.yml) : acces dashboard bloque par des soucis d'infrastructure reseau (WSL2/pare-feu Hyper-V en local, reseau Docker partage avec Caddy pas en place en prod), sans lien avec le code du moteur - mis de cote plutot que de continuer a bloquer sur de l'infra. Les lots 4+ de modernisation JS dependent de scores Sonar exacts et sont donc egalement en pause (voir CODE_QUALITY.md). SKIP=djlint : H021 (styles inline, 49 occurrences) est un backlog deja documente et assume (CODE_QUALITY.md section 6), sur des templates non touches par ce commit - deja exclu de la CI pour la meme raison. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
c57420c8c9 |
Phase 3 : hardening qualite de code - typage strict, securite, dead code, a11y
Config strictement stricte partout (ruff, mypy --strict, bandit, vulture, import-linter, eslint, stylelint), aucune regle desactivee "pour ne pas casser le build" - l'existant a ete corrige pour la satisfaire plutot que l'inverse. Hooks pre-commit locaux (language: system) bloquants. - Typage mypy --strict propage a tout le moteur (db, screens, auth, core, ai, routes, puis publish/scripts/tests/app.py/build_css.py). - Securite : fuite de handle fichier Windows corrigee dans l'export SCORM (routes/publish/export_scorm.py), CSRF/RNG non-crypto/xAPI documentes (# nosec, # NOSONAR justifies), nouveau db.json_for_script() (echappe "</script>" dans le JSON embarque en <script>, 25 sites). - Architecture : imports circulaires/F811 nettoyes, contrats import-linter respectes, code mort retire (vulture). - Accessibilite : 69 champs de formulaire sans label correctement associe corriges (for/id ou aria-label) sur 11 templates. - ESLint/Stylelint : lot mecanique JS/CSS, regles ajustees puis appliquees (aucune desactivee sans verification individuelle). - Tests : isolation du compte admin partage (nettoyage ponctuel + fixture de teardown automatique en filet de securite), suite complete verte (591 tests Python, 241 tests JS). - SonarQube Community Build self-heberge (Docker + PostgreSQL) : rapport complet analyse point par point, faux positifs documentes. - .gitattributes ajoute (LF force) : core.autocrlf=true sur cette machine faisait echouer ESLint (linebreak-style) via un bug connu de git (checkout "en place" qui ignore l'eol force sur un fichier deja present sur disque - contourne en supprimant puis recreant chaque fichier suivi). djLint (H021, styles inline) volontairement saute pour ce commit - backlog assume, deja documente, traite dans un lot separe. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
7db4803b93 |
Ajoute la fonctionnalite quiz autonome/plein ecran a la boite a quiz
Introduit la double categorie de modeles (boite de dialogue / page de quiz plein ecran) avec plein ecran, minuteur, score integre et ecran de resultat pour les modeles page ; ajoute les modeles "Manga" (boite et page) et "Classique" (page), pilotables aussi par l'assistant IA Ruby. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
559331f9cf |
Enrichit les declencheurs/actions de scene (clic/survol/affichage, surbrillance/video/son/visibilite/indication/attendre) et fiabilise la pose d'un fond/decor importe
- Ajoute clic/survol/affichage-ecran comme declencheurs, et surbrillance, video, son, visibilite, indication, attendre comme actions, utilisables aussi bien par l'editeur manuel (menu lateral Objets/Ecran) que par Ruby (IA), avec blocs deplacables/supprimables dans une chaine. - Corrige plusieurs variantes du bug "impossible de poser un objet hors du champ de la camera" (troncature du chainage d'actions a 4 maillons, fond importe pose a 128x128 au lieu de sa taille reelle, decalage du fond au vrai glisser-depose, redimensionnement manuel jamais propage au monde). - Ajoute un vrai glisser-depose depuis la galerie vers la scene, la gestion complete de "Mes assets" (sous-sections Fonds/Decors/Sons/ Videos, suppression, reclassement fond<->decor sans re-upload). - Ajoute l'upload de son (limite 3 min) et de video (MP4 uniquement, limite 5 min), avec validation de la duree reelle du fichier, et une replique audio optionnelle dans une bulle de dialogue. - Fixe la taille de pose d'un objet/decor importe a 200x200 avec une boite de collision de 150x150. - Filtre le selecteur de fichier des actions son/video par type reel. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
b07b231a61 |
Ajoute l'assistant IA "Ruby" (Claude + Scenario) et corrige plusieurs bugs de la scène
Intègre un chat IA capable de manipuler la scène via les mêmes fonctions que l'éditeur manuel (objets, variables, déclencheurs, images générées), avec conversations multiples par écran façon Claude. Corrige au passage le rafraîchissement pjax hors-ordre, l'onglet IA/déclencheurs vide après sélection d'un objet, la comparaison de booléens dans les conditions, et le blocage du glisser-déposer hors du cadre caméra après un redimensionnement de fond par l'IA. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
d664ed5637 |
Remplace le système de quêtes par des déclencheurs, ajoute l'action variable et le chaînage
Supprime le concept de "quête" au profit d'un onglet unique "Déclencheurs"
portant toute la logique (dialogue, condition, marquage terminé) directement
sur l'objet de scène. Ajoute une nouvelle action "Modifier une variable"
(réutilisant le vocabulaire du graphe de flow) utilisable après une
collision, une interaction ou une branche de condition, ainsi qu'un
chaînage d'actions ("then") permettant d'enchaîner plusieurs actions à la
suite et d'étendre un déclencheur déjà posé sans le recréer.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
||
|
|
c504ace167 |
Enrichit le reporting SCORM/xAPI et met en conformité RGAA le player
SCORM/xAPI : - Ajoute l'export SCORM 2004 (3rd/4th edition) au choix, en plus du 1.2 par défaut : sépare completion_status/success_status (un échec reste "completed" au lieu de retomber à tort en "incomplete" comme force la 1.2), remonte aussi cmi.interactions.n.* par question répondue. - Fournit cmi.core.score.min/max (1.2 et 2004), calculé depuis les récompenses de quiz du jeu, pour que le LMS affiche un vrai pourcentage au lieu du score brut à tort étiqueté "%". - Libellés de verbes xAPI en français en plus de l'anglais. Accessibilité (RGAA/WCAG 2.1 AA) sur le player : - Navigation clavier des objets de scène "au clic"/"au survol" (tabindex, role, Entrée/Espace, focus/blur). - alt sur les images (nom auteur ou décoratif), aria-hidden sur les icônes seules, role="dialog"/aria-live sur les boîtes de dialogue/quiz. - Landmark <main> + titre de page, respect de prefers-reduced-motion. - Le quiz n'avance plus automatiquement après un délai fixe : bouton "Continuer →" explicite (RGAA 2.2.1). - Avertissement de contraste dans l'éditeur de style de dialogue. - Déclaration d'accessibilité téléchargeable depuis la modale d'export. |
||
|
|
f7a50e5afe |
Ajoute un suivi xAPI optionnel (bolt-on) au paquet SCORM exporté
Greffe l'envoi de statements xAPI vers un LRS configurable par le créateur du jeu, en parallèle du reporting SCORM existant : réglages stockés en base (_meta), formulaire dans la modale d'export, injection dans le paquet exporté. Relié aussi bien à l'action de flow "Modifier un score/statut" qu'au parcours quête/quiz (qui alimentait déjà le SCORM classique via un chemin séparé). L'export ne se lance plus automatiquement à l'ouverture de la modale, pour laisser le temps d'enregistrer les réglages xAPI avant de générer le paquet. |
||
|
|
50835a18e2 |
Supprime le type d'écran "document" et recentre le produit sur le jeu 2D
Le document de cadrage produit cible des formateurs non techniques créant des serious games/quiz gamifiés — l'éditeur générique "document" (blocs de logique en nœuds, timeline d'animation, définitions d'objets/relations, templates réutilisables) est une complexité hors cible que l'effort d'ingénierie récent avait déjà abandonnée au profit du jeu_2d. - Onboarding : ne garde que le parcours "RPG" (jeu_2d), retire Quiz/Embranchement/Créer mon jeu de A à Z (tous document-only) - Suppression en bloc des modules exclusifs au document : routes/elements, routes/element_types, routes/objects, routes/legacy_actions, screens/elements, screens/element_types, screens/widgets, screens/legacy_actions, le rendu render_element_html.py et son cluster, templates/screen_edit.html, templates/game_dashboard.html, flow-editor.js/tabs-and-blocks.js/animation-timeline.js - Dashboard toujours simplifié (un seul mode possible désormais) - Tests document-only supprimés, tests de logique partagée (flow, événements personnalisés, animations) retargetés sur des écrans jeu_2d - Aucune régression jeu_2d : 299 tests passent Carte d'onboarding retravaillée : argumentaire RH non technique (liste à coche, badge "Compatible LMS"), taille et interaction de retournement ajustées. |
||
|
|
413685e871 |
Relie le score/statut des quêtes aux indicateurs SCORM
Les quêtes/quiz mettaient à jour l'état local (statut, score) sans jamais toucher gameData.scoring, que scorm-api.js interroge déjà pour reporter Completion/Success/Score au LMS. Ajoute forgeSyncQuizScoreToScorm, forgeSyncQuestStartedToScorm et forgeSyncAllQuestsCompletionToScorm, appelées lors d'un bon score, de l'acceptation d'une quête et de la complétion de toutes les quêtes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
55c6bb330b |
Contrôle direct de la taille de la caméra (Largeur × Hauteur, toujours modifiable)
Remplace le bouton conditionnel "Agrandir la caméra à la zone visible" (n'apparaissait que si un fond dépassait déjà la scène) par deux champs "Caméra (px)" TOUJOURS visibles, pré-remplis avec scene_width/ scene_height actuels — demande explicite : "l'écran de l'éditeur a une taille fixe, la caméra a la même taille, c'est tout", un réglage direct plutôt qu'une suggestion automatique liée à la taille d'un fond. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
b9d3c46087 |
Bouton "📐 Agrandir la caméra à la zone visible"
Fait de tout le "monde" affiché par l'éditeur (la taille réelle d'un "fond" plus grand que la scène nominale, voir routes/scenes/ scene_edit_view.py::world_width/world_height) la scène/caméra ELLE-MÊME — jusqu'ici scene_width/scene_height n'étaient fixées qu'à la création de l'écran, jamais modifiables ensuite. Le bouton n'apparaît que quand un fond dépasse encore la scène nominale (même condition que le repère "🎥 Champ de la caméra"), affiche la taille cible, recharge la page une fois appliqué. La caméra ne recadre alors plus rien en jeu (monde == scène == viewport, voir personnage-controller.js::forgeUpdateSceneCamera). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
14ec76dddd |
Éditeur : le canevas affiche tout le monde (fond agrandi), pas que la scène
Suite au fix du glisser figé à (0,0) : le canevas de l'éditeur restait malgré tout limité à la scène nominale (960×540 par ex.) — la partie d'un "fond" plus grand qui dépasse restait invisible/injoignable à la souris. Le canevas affiche désormais tout le "monde" (max de la scène et de l'étendue de chaque "fond", voir routes/scenes/scene_edit_view.py), comme la caméra en jeu le fait déjà (personnage-controller.js). Nouveau repère visuel "🎥 Champ de la caméra" : un cadre en pointillés marquant où s'arrête la scène nominale à l'intérieur de ce monde agrandi (le reste est assombri), pour que l'auteur voie clairement ce que le joueur verra réellement à l'écran une fois le monde plus grand que le viewport. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
6b4846a646 |
Fix vrai bug : un objet plus grand que la scène (fond/caméra) restait figé à (0,0)
Confirmé par l'utilisateur : lié à l'introduction du fond/caméra (voir add_scene_object.py — un "fond" est posé à sa taille RÉELLE, souvent bien plus grande que la scène, exprès, pour que la caméra le suive en défilant sur un monde plus grand que le viewport). Le glisser en position utilisait Math.max(0, Math.min(SCENE_WIDTH - width, ...)) — cette formule suppose SCENE_WIDTH - width POSITIF (objet plus petit que la scène). Pour un objet plus GRAND (ex. un fond de 1920px sur une scène de 960px), cette différence est NÉGATIVE, et Math.max(0, négatif) ramenait TOUJOURS la position à 0 quel que soit le glisser — l'objet restait donc figé, impossible à repositionner. Le redimensionnement plafonnait aussi la largeur/hauteur à "ce qui reste dans la scène depuis son coin" (SCENE_WIDTH - left) — empêchant justement de rendre un objet plus grand que la scène par glisser (un fond ne pouvait être agrandi qu'en le recréant via la galerie). Les deux bornes sont corrigées pour fonctionner quel que soit lequel (scène ou objet) est le plus grand. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
7c9b2c9b25 |
Fix "impossible d'aller plus loin vers la droite" — défilement automatique du canevas
Cause confirmée (tous les objets bloquaient au même endroit, pas spécifique à un widget) : une scène à taille fixe (960×540 par ex.) peut être plus LARGE que la zone visible de .canvasFrame (overflow:auto) selon la largeur de fenêtre — sa partie droite/basse défile alors HORS de vue, et le curseur atteignait le bord de cette zone VISIBLE bien avant celui de la scène elle-même : la souris ne pouvait tout simplement plus bouger physiquement plus loin, sans aucun rapport avec la limite réelle (960px) de la scène. onSceneObjectMouseDown/onSceneObjectResizeMouseDown font maintenant défiler .canvasFrame automatiquement quand le curseur approche un bord pendant un glisser/redimensionnement — et continuent de déplacer l'objet même si la souris reste immobile près du bord (mirror du comportement standard d'un glisser-déposer dans une zone scrollable), grâce à une position ACCUMULÉE plutôt que recalculée depuis le point de départ fixe. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
046c38b4dc |
Annule la réservation d'espace des panneaux, corrige le vrai bug (drag invisible sous eux)
Retour en arrière sur le commit précédent : les panneaux flottants doivent RESTER en position:fixed par-dessus le canevas pour maximiser l'espace utile (remarque explicite) — leur réserver une marge permanente allait à l'encontre de ce principe et ne réglait rien. Vrai bug identifié : un objet glissé (déplacé ou redimensionné) sous l'un de ces panneaux (z-index:60) disparaissait littéralement à l'écran PENDANT le geste — toujours déplacé/enregistré correctement en dessous, juste invisible, donnant l'impression qu'on ne pouvait pas y déposer d'objet. Élevé au-dessus des panneaux (z-index très haut) le temps du glisser/redimensionnement SEULEMENT, restauré ensuite. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
d705f58c4a |
Fix accès au canevas masqué + quiz : header quête, réponse fausse n'avance jamais bloquée, animé
- Bug corrigé : les panneaux flottants "🧩 Objets"/"⚙️ Propriétés" sont en position:fixed (hors du flux flex de .builder3) — ils flottaient PAR-DESSUS le canevas sans jamais réduire sa largeur, rendant sa partie droite/gauche inaccessible au clic/glisser tant qu'un panneau restait ouvert. .builderCanvasArea réserve maintenant leur largeur (marge) dès qu'un panneau est ouvert (:has()). - Boîte à quiz : header = "Quête : <titre>" (au lieu du texte de la question), corps = la question ET ses choix ensemble. - Mauvaise réponse : ne bloque plus JAMAIS la progression (bug signalé : "je suis obligé de bien répondre sinon j'avance pas") — surligne la bonne réponse en vert (le choix cliqué en rouge s'il était faux) puis avance automatiquement après un court délai, sans jamais octroyer de points. Un second clic pendant la révélation est ignoré. - Animations : la boîte à quiz rejoue une entrée (pop-in) à CHAQUE nouvelle question, la bonne réponse pulse en vert, une mauvaise réponse "secoue" en rouge. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
b5546df044 |
Quiz jouable : budget de récompense, boîte à quiz, widget score
- Récompense d'une quête = budget MAXIMUM pour ses questions : la somme des points des "❓ Question" ne peut plus dépasser recompense_score (routes/quests/quest_dialogues.py à l'enregistrement des dialogues, quest_update.py si on abaisse la récompense sous ce qui est déjà réparti) — message d'erreur explicite (400) dans les deux sens, affiché via alert() côté éditeur (quest-editor.js), jamais enregistré silencieusement dans un état incohérent. - Nombre de choix par question plafonné à 4 (au lieu de 8). - Deux nouveaux widgets "🖥️ Interface" (mêmes fondations que "💬 Boîte de dialogue" — screens/rendering/dialogue_box_style.py, même panneau "🎨 Style") : - "❓ Boîte à quiz" : affiche la question et ses choix, sans pied (une question se résout au clic sur un choix, pas de "Suivant"). - "🏆 Score" : affiche en continu les points gagnés, TOUJOURS visible une fois posé (contrairement aux boîtes de dialogue/quiz, masquées par défaut). - Moteur d'exécution (static/js/play/dialogue-box-controller.js, refonte) : une conversation de quête alterne maintenant répliques (boîte de dialogue) et questions (boîte à quiz) selon le type de chaque ligne. Bonne réponse -> crédite le score (compteur runtime dédié, jamais lié au score du moteur document) et avance ; mauvaise réponse -> rien, la question reste affichée pour réessayer ; aucune boîte à quiz posée -> la question est ignorée plutôt que de bloquer la conversation. Le dialogue "en_cours" épuisé (donc, s'il contenait des questions, toutes répondues) fait passer la quête "terminee" (en mémoire seulement, comme le reste de ce système — voir accepter/ refuser une offre de quête) : le joueur peut alors quitter la scène normalement, ces widgets n'étant jamais des obstacles. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
e972acf9e6 |
Quêtes : bulle "❓ Question" à choix multiples, à côté de "+ Réplique"
Nouveau type de ligne dans un dialogue de quête (voir
db/quests/sanitize_quest_dialogues.py) : une bulle JAUNE, dans la même
chaîne verticale que les répliques (même alignement, reliée par un
trait) — header : nombre de choix (2 à 8) + récompense (score, montant
en points) ; body : la question, ses choix et un bouton radio pour
désigner la bonne réponse. Aucune limite au nombre de questions par
colonne, comme pour une réplique.
Les lignes de dialogue portent maintenant explicitement
{"type": "dialogue", ...} (au lieu d'un objet sans type) pour
distinguer les deux formes — migration de forme, tests mis à jour.
Portée de ce commit : l'ÉDITEUR (créer/modifier une question). Le jeu
lui-même (afficher la question au joueur, vérifier la réponse,
attribuer la récompense) reste à construire — le widget "💬 Boîte de
dialogue" ne sait aujourd'hui afficher qu'une réplique.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
||
|
|
e90d941527 |
Quête "nouvelle" : écran Accepter/Refuser à la fin du dialogue
Une fois le dialogue épuisé, si la quête est encore "nouvelle", la boîte de dialogue bascule sur un écran d'offre au lieu de se masquer : header "Quête : <titre>", body l'objectif, pied deux boutons. - Accepter -> la quête passe "en_cours" (en MÉMOIRE seulement, gameData.quests — jamais persisté en base : le statut en base est celui de DÉPART pour toute nouvelle partie, pas un état de partie en cours, voir PLAYER_SHARED/full_game_payload.py). - Refuser -> la boîte se referme SANS toucher au statut, qui reste "nouvelle" : la prochaine interaction rejoue exactement le même dialogue depuis le début — impossible d'avancer la quête sans l'accepter un jour. Pour tout autre statut (déjà "en_cours"/"terminee"), la boîte se masque normalement à la fin du dialogue, comme avant. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
df34106752 |
Collision : une carte par objet occupe toute la largeur
L'ancienne grille (auto-fill, colonnes de 300px minimum) réservait des colonnes vides même avec une seule carte, la laissant étroite avec un grand vide à droite. Empilées en pleine largeur à la place — laisse aussi la place à une longue chaîne de règles de s'étendre sans se faire couper. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
aa17614c7b |
Fix bulle "Appuie sur X" trop haute au-dessus du personnage
La bulle s'ancrait sur le cadre BRUT du sprite (<img> style.left/top/ width/height) — beaucoup de sprites (animaux CraftPix notamment, voir screens/labels/animal_sprite_library.py) ont un très grand canevas padé autour d'une silhouette bien plus petite, faisant flotter la bulle loin au-dessus du personnage visible. Elle s'ancre maintenant sur la BOÎTE DE COLLISION (objRect, déjà résolue via forgeElementBoxRect — largeur/hauteur/décalage réglables dans "🧱 Collision"), que l'auteur ajuste déjà pour épouser la silhouette réelle : ancre bien plus fidèle, sans configuration supplémentaire à faire. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
00f9cf33e9 |
Fix bulle "Appuie sur X" invisible + retire Attaque/Événement du picker
Bug corrigé : la bulle "Appuie sur X" était ajoutée comme ENFANT de l'objet de scène (un <img> pour "personnage"/"decor"/"fond") — un élément REMPLACÉ dont les enfants DOM ajoutés en JS ne sont JAMAIS affichés par un navigateur, quel que soit son CSS. La bulle existait donc bien dans le DOM (aucune erreur) mais restait invisible à l'écran. Elle est maintenant ajoutée comme SŒUR de l'objet dans son parent (.sceneWorld/.sceneUI), positionnée en JS aux mêmes coordonnées. Assistant "+ Action" de l'éditeur de collision : "⚔️ Attaquer la cible" et "📣 Déclencher un événement" retirés des choix proposés (pas besoin pour le moment) — le serveur continue d'accepter/d'exécuter une règle déjà enregistrée avec l'un des deux, rien ne casse pour l'existant. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
726775fe4e |
Fix "à la collision" — la marge de 3px restait insuffisante
forgeWouldCollide (personnage-controller.js) bloque le déplacement par PAS ENTIER (cmd.vitesse px/tick, 4 par défaut mais réglable) : le joueur peut donc rester bloqué jusqu'à PRESQUE un pas entier de distance de l'obstacle, pas seulement 1-3px — la marge de tolérance du correctif précédent (3px) restait insuffisante même pour la vitesse par défaut dans les cas les moins favorables. Portée à 24px, confortable pour toute vitesse raisonnablement configurée sans jamais déclencher "à la collision" alors que les objets sont encore visiblement séparés. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
3a67ba622b |
Fix "à la collision" qui ne se déclenchait jamais
Cause réelle : un objet portant une règle de collision est presque toujours AUSSI un obstacle solide (collision activée par défaut, voir forgeWouldCollide, personnage-controller.js) — le déplacement du joueur est donc bloqué PILE au contact, sans jamais laisser les deux boîtes se chevaucher réellement. Le déclencheur "collision" testait un chevauchement STRICT (forgeShapesOverlap nu), qui n'était donc jamais atteint : la règle ne se déclenchait jamais en jeu réel, malgré un contact visible à l'écran. Le déclencheur teste maintenant la boîte de l'objet élargie d'une petite marge (3px) — assez pour détecter un simple contact — SANS toucher au blocage physique du déplacement (resté strict, inchangé). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
5e17e42dfa |
Test bout en bout : collision -> quête -> boîte de dialogue
Vérifie explicitement le lien moteur demandé : une règle de collision "quete" retrouve la quête, récupère les répliques de son statut actuel, les affiche dans l'ordre dans le widget "💬 Boîte de dialogue" posé sur la scène, avance au clic sur "Suivant", disparaît à la dernière réplique — déjà implémenté (collision-rules-controller.js + dialogue-box-controller.js), ce test couvre la CHAÎNE COMPLÈTE plutôt que chaque brique isolément. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
077af2234d |
Fix "+ Réplique" qui remplaçait la bulle au lieu d'en ajouter une
Bug : questSaveDialogues() adoptait la réponse du serveur comme nouvel état local après chaque enregistrement. Une bulle fraîchement ajoutée a un texte encore vide (rien tapé) — sanitize_quest_dialogues.py la rejette légitimement (jamais de réplique sans texte persistée) — donc la réponse renvoyait un tableau amputé de cette bulle, que le client adoptait aveuglément, effaçant la bulle en cours d'écriture. Le clic suivant sur "+ Réplique" repartait donc du même état qu'avant, semblant "remplacer" la bulle plutôt que d'en ajouter une seconde. Le client ne resynchronise plus jamais son état depuis la réponse d'enregistrement — il est déjà la seule source de vérité pendant l'édition. Colonnes de dialogue : occupent maintenant toute la hauteur disponible de la modale plein écran et défilent chacune indépendamment (titre et bouton "+ Réplique" restent fixes), au lieu d'une hauteur minimale fixe. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
521792fe00 |
Dialogues de quête : bulles illimitées, n'importe quel objet, timeline reliée
- "qui parle" n'est plus réservé au personnage : N'IMPORTE QUEL objet de scène nommé (personnage, décor, fond — voir "ℹ️ Informations", screens/rendering/scene_object_names.py, ex-personnage_names.py) peut parler dans un dialogue. - Confirmé/documenté : aucune limite au nombre de répliques par colonne (bouton "+ Réplique" reste toujours disponible). - Bulle = header (menu déroulant du "qui parle") + body (le texte), centrée dans sa colonne à 70% de largeur, alignée verticalement et reliée à la suivante par un trait — remplace l'ancien alignement gauche/droite façon chat. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
2347a70c45 |
Quêtes/collision : personnages nommés, dialogues qui parlent, boîte de dialogue en jeu
- "ℹ️ Informations" (propriétés d'un personnage) : nom éditable, réutilisé comme "qui parle" dans l'éditeur de dialogue de quête (menu déroulant, plus "Joueur" toujours disponible) — remplace l'ancien choix binaire joueur/pnj. db.sanitize_quest_dialogues accepte maintenant un nom libre. - Nouveau menu "🖥️ Interface" (palette d'objets) avec le premier widget : "💬 Boîte de dialogue" (kind="dialogue_box", screens/rendering/ dialogue_box_style.py) — position/taille comme tout objet de scène, panneau "🎨 Style" dédié (police, taille, épaisseur, couleur du texte, couleur header/body/footer). Rendu en <div> à 3 zones, jamais soumis à la collision ni à l'éditeur de collision (exclu partout : obstacles, liste des règles, payload). Rendu côté jeu dans .sceneUI, une couche FIXE au viewport (jamais .sceneWorld, qui défile avec la caméra). - static/js/play/dialogue-box-controller.js : fait le lien moteur entre l'action "quete" de l'éditeur de collision et ce widget — affiche la réplique en cours du dialogue correspondant au STATUT ACTUEL de la quête (gameData.quests, désormais exposé game-wide par full_game_payload.py), avance au clic sur "Suivant" (header = qui parle, body = texte, footer = bouton), se masque à la dernière réplique. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
390ee831ca |
Quêtes : dialogue dans une modale à part, en plein écran
Sépare la modale unique en deux étapes distinctes demandées par
l'utilisateur : #questFieldsModal ("je crée" — titre/objectif/
récompense/statut/résultat, taille normale) puis, sur un bouton dédié
"💬 Ajouter les dialogues", #questDialogueModal ("j'ajoute les
dialogues" — les 3 colonnes de répliques SEULES, occupant tout
l'écran). Un bouton "←" ramène à la fiche ; "✓ Utiliser cette quête"
reste disponible dans les deux, pour l'intégration avec l'éditeur de
collision.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
||
|
|
78c1aba8a0 |
Éditeur de quêtes : onglet à côté de Collision, pas une page à part
Corrige la mauvaise interprétation de la demande initiale : la page dédiée "🗺️ Quêtes" (nav du jeu) est retirée au profit d'un nouvel onglet "🗺️ Quêtes" DANS l'éditeur de scène 2D, juste à côté de "🧩 Collision" — même liste tabulaire que l'onglet "📣 Événements" (titre/objectif/récompense/statut/résultat par ligne, pas des cartes), un clic sur une ligne ouvrant la modale d'arbre de dialogue déjà construite. L'assistant "+ Action" de l'éditeur de collision ouvre toujours cette même modale pour "Déclencher une quête". Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
51427b5297 |
Éditeur de quêtes : titre/objectif/récompense/statut/résultat + dialogue à 3 colonnes
Nouvel espace "🗺️ Quêtes" (game-wide, comme les événements personnalisés) : liste de cartes + "+ Nouvelle quête", chaque carte ouvrant une modale d'arbre de dialogue en bulles de théâtre ("speaker: texte"), une colonne par statut de quête (nouvelle/en cours/terminée) puisque le dialogue joué dépend de l'état de la quête au moment où le joueur parle au PNJ. Bulles alternées joueur/PNJ, couleur différente selon qui parle. L'action "Déclencher une quête" de l'éditeur de collision n'est plus un champ texte libre : elle ouvre directement CETTE MÊME modale (picker de quêtes existantes + création à la volée), et finalise la règle avec l'id numérique de la quête choisie — collision_rules.py migré en conséquence (quete_id devient un entier, comme evenement_id). Corrige aussi la miniature d'objet de la carte "🧩 Collision", 3× plus grande (120px) comme demandé. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
4391b36d45 |
Fix miniature de carte "🧩 Collision" échappée du cadre
render_scene_object.py pose un positionnement en pixels absolus pensé pour le canevas de scène (position:absolute, left/top/width/height en dur, coordonnées d'origine de l'objet) — réinjecté tel quel comme simple miniature 40×40 dans la carte, l'image se plaçait à ses coordonnées de scène d'origine au lieu de rester dans son cadre. Écrase ces styles en !important côté miniature seulement. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
b64541856f |
Éditeur de collision : cartes "pièces qui s'emboîtent", animées
Refonte visuelle de l'onglet "🧩 Collision" — l'ancien rendu (pastilles plates + flèches) ne rendait pas la métaphore "pièces de puzzle qui s'emboîtent" demandée. Chaque maillon (déclencheur/action/sous-action) est maintenant une pièce chevronnée colorée par type, imbriquée dans la suivante via clip-path + marge négative, avec une entrée animée en cascade. Cartes objet et choix de l'assistant modal redessinés en grille de cartes avec icône + libellé, hover/entrée animés. Purement visuel — aucun changement de logique/données (déjà couvert par tests/test_collision_rules.py et static/js/play/__tests__/collision-rules-controller.test.js). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
ee270d0286 |
Éditeur de collision (jeu 2D) : règles trigger -> action par objet
Nouvel onglet "🧩 Collision" dans l'éditeur de scène 2D : chaque objet (hors joueur et fond) peut porter des règles "à la collision" ou "dans un périmètre (px)" déclenchant une action (quête, attaque, événement, ou interagir - qui affiche "Appuie sur [touche]" puis exécute une sous-action à l'appui, un seul niveau d'imbrication). Backend (sanitisation, route de persistance, exposition dans full_game_payload) + assistant modal en cartes empilées côté client. Ajoute le moteur d'exécution runtime (collision-rules-controller.js) : détecte l'entrée en collision/périmètre avec le joueur à chaque tick, déclenche l'action une seule fois par entrée, pur JS client sans appel serveur (fonctionne à l'identique en ligne et en export SCORM). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
dfaf85fac1 |
Retire la collision sur les images de fond + les blocs de logique/timeline de l'éditeur 2D
Deux retours utilisateur sur l'éditeur de scène 2D : - Le panneau "🧱 Collision" (réglages + aperçu visuel sur le canevas) n'apparaît plus pour un objet kind="fond" : jamais un obstacle ni une cible de collision possible (déjà exclu de forgeSolidObstacles côté jeu), ce panneau n'aurait donc aucun effet. - Retire les onglets "🧩 Blocs de logique" et "🎬 Timeline d'animation" de CET éditeur (l'éditeur document, templates/screen_edit.html, les garde tel quel) — en prévision d'un éditeur dédié aux scènes 2D (collision/périmètre -> action), pas encore construit. switchBuilderTab()/ toggleDashCreate() (génériques, nécessaires à l'onglet "Événements" restant) extraites dans un nouveau builder-tabs.js partagé par les deux éditeurs, pour ne plus avoir à charger flow-editor.js/tabs-and-blocks.js/ animation-timeline.js (propres aux blocs/timeline) dans l'éditeur 2D. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
a231bcf2fa |
Aperçu de la boîte de collision dans l'éditeur + blocage physique au jeu
Deux retours utilisateur sur la boîte de collision (ajoutée précédemment) : - Visible et réglable directement dans l'éditeur de scène : pour l'objet sélectionné, un contour pointillé (rectangle/cercle) se superpose sur le canevas — glisser son corps ajuste le décalage, glisser sa poignée (coin bas-droit) ajuste la taille, les deux se répercutent dans le panneau "🧱 Collision" et inversement (édition des champs -> aperçu à jour). static/js/scenes/scene-editor.js::onCollisionBoxMouseDown/ onCollisionBoxResizeMouseDown, mirror des poignées de position/taille déjà existantes pour l'objet lui-même. - Bloque désormais RÉELLEMENT le déplacement au clavier : avant chaque pas, personnage-controller.js teste si la position candidate chevaucherait la boîte de collision d'un autre objet solide (jamais un "fond", jamais un objet à collision désactivée) et annule ce pas — par AXE séparément, pour permettre de glisser le long d'un mur en diagonale plutôt qu'un blocage total au moindre contact. Réutilise forgeShapesOverlap (conditions.js, factorisé depuis elementsOverlap pour ne jamais dupliquer la règle "qu'est-ce qui se touche"). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
bc3feb5080 |
Panneau scène simplifié + boîte de collision + rôle joueur/ennemi/pnj
Trois retours utilisateur sur l'éditeur de scène 2D : - Retire l'arborescence "Objets de cette scène" (un objet reste sélectionnable en cliquant dessus sur le canevas) et le bouton "+ Ajouter un décor" (le type "decor" reste supporté côté serveur, juste plus accessible depuis ce menu). - Chaque objet de scène a désormais une boîte de collision AUTOMATIQUE (= sa propre boîte, comportement inchangé pour une condition de collision déjà posée) réglable dans un nouveau panneau "🧱 Collision" : activée/désactivée, forme (rectangle/cercle), taille et décalage — utile pour un sprite très paddé (CraftPix) dont la silhouette réelle est bien plus petite que son canevas. elementsOverlap() (conditions.js) applique ces réglages en restant identique par défaut. - Nouveau champ "🏷️ Rôle" (Joueur/Ennemi/PNJ) sur un personnage : SEUL un personnage "Joueur" est désormais déplacé/animé au clavier et suivi par la caméra (personnage-controller.js) — "Ennemi"/"PNJ" restent immobiles tant qu'aucune logique de flow ne les pilote (déplacement ennemi automatique/apparition, dialogue de PNJ... hors scope de ce réglage, qui ne fait qu'identifier "quel objet est le joueur"). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
9199897784 |
Image de fond de scène + caméra qui suit le personnage, fps d'animation cohérent
Trois retours utilisateur : - fps d'idle/interagir/touches supplémentaires alignés sur celui de la marche (8 i/s partout, était 4 pour idle — perçu comme "les autres animations sont lentes à côté de la marche"). - Nouveau menu "🏞️ Images de fond" dans "Objets de cette scène" : pose un objet kind="fond" à la taille RÉELLE de l'image choisie (pack CraftPix intégré en galerie, admin seulement — licence, voir core/sprite_gate.py), derrière tout le reste, insensible au clic. - Si ce fond dépasse la scène, elle devient le "monde" : .playScreen. playScene est désormais le viewport (overflow:hidden, taille fixe), .sceneWorld le monde à l'intérieur — la caméra centre le premier personnage trouvé, bornée pour ne jamais montrer au-delà des bords (voir personnage-controller.js::forgeUpdateSceneCamera). Le personnage peut désormais se déplacer sur tout le monde, pas seulement le petit cadre visible (clampSceneObjectPosition, actions.js). Un jeu sans fond XXL garde un comportement strictement identique à avant (monde == scène, transform vide). Bibliothèque générée une fois par scripts/generate_background_manifest.py (assets/background/, non versionné, licence CraftPix) vers static/backgrounds/ (committé), même patron que generate_animal_sprite_manifest.py. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
5891c82c62 |
Commandes personnage : détection de touche au clavier + touches d'animation supplémentaires
Deux retours utilisateur sur le panneau "Commandes" (déplacement/
animation automatiques, voir précédent commit) :
- Les champs de touche (haut/bas/gauche/droite/interagir) capturent
maintenant la touche au clavier (clic puis appui — event.key, même
valeur que heldKeys/triggers.js) au lieu d'être tapés à la main,
source d'erreurs ("Espace" vs " ", "flèche haut" vs "ArrowUp"...).
- Nouvelle section "Animations supplémentaires" : un nombre illimité de
touches, chacune liée à UNE pose au choix parmi celles réellement
disponibles pour ce personnage (sauter, attaquer, courir...) — pas
seulement les 4 touches de déplacement + interagir.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
||
|
|
74f7ca396f |
Déplacement/animation automatiques d'un personnage (scène 2D)
Simplification demandée pour l'éditeur de jeu RPG : un personnage posé sur une scène 2D se déplace et s'anime TOUT SEUL avec ZQSD (+ E pour interagir) dès qu'il est posé — plus besoin de poser le moindre nœud de flow pour un mouvement de base. Le panneau "🕹️ Commandes" du personnage permet de remapper les 4 touches de déplacement et la touche d'interaction, et de bloquer un axe (horizontal/vertical seulement). Entièrement client (static/js/play/personnage-controller.js), réutilise heldKeys (triggers.js) et applyObjectProperty/clampSceneObjectPosition/ runSpriteAnimation (actions.js) — aucune logique dupliquée, et ça fonctionne aussi bien en ligne que dans l'export Web/SCORM (aucune requête serveur). "walk"/"idle"/"interact" (poses déjà présentes pour tout personnage Forge/CraftPix) sont utilisées telles quelles ; une pose absente dégrade silencieusement (déplacement sans animation) plutôt que de planter. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
82d00b3800 |
Export Web/SCORM : inline les icônes en data: URI (CORS Firefox/file://)
Le chemin relatif ("icons/x.svg") était enfin correct, mais Firefox
bloque encore par CORS TOUT chemin de fichier pour mask-image sous
file:// — chaque ressource file:// y est une origine opaque distincte,
indépendamment du chemin (troisième rapport du même utilisateur). Seule
une data: URI (aucune requête réseau séparée) contourne le problème.
_build_icon_data_uris (build_scorm_package.py) encode chaque icône
RÉELLEMENT posée dans le jeu (élément direct ou niché dans un élément de
jeu réutilisable) en base64, ajouté au payload sous
gameData.icon_data_uris ; forgeRenderIcone (JS) le consulte pour toute
régénération après une action, avec repli sur l'ancien chemin relatif
si jamais une icône n'a pas été pré-encodée.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
||
|
|
b60fe63a54 |
Export Web/SCORM : corrige le chemin de l'icône doublé "static/static/"
Le premier correctif ("static/icons/x.svg") ne suffisait pas : cette URL
est posée en style inline (--icon-url) mais CONSOMMÉE par `mask-image:
var(--icon-url)` dans static/style.css (.icon-svg) — une URL relative
dans une propriété personnalisée CSS se résout par rapport à la feuille
de style où le var() est UTILISÉ, pas où elle est définie (piège CSS
connu). Résultat : "static/icons/x.svg" redevenait
"static/static/icons/x.svg" une fois résolu depuis static/style.css
(CORS bloqué — deuxième rapport du même utilisateur). Seul "icons/x.svg"
(sans le préfixe "static/") est correct une fois résolu depuis
static/style.css. Corrigé côté rendu initial
(_relativize_absolute_urls) et côté port JS (forgeRenderIcone, qui
régénère ce widget après une action).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
||
|
|
e08c53e042 |
Export Web/SCORM : corrige la résolution des champs "relation" hors ligne
Bug signalé : une Donnée liée/un filtre référençant un champ "relation"
affichait "{{champ}}" tel quel une fois exporté, alors qu'il fonctionnait
en ligne. Deux causes cumulées :
- full_game_payload.py lisait la colonne SQL "<champ>" au lieu de
"<champ>_id" (seule vraie colonne d'un champ relation, voir
_field_column dans filter_repeater_rows.py) en construisant
gameData.data — une valeur toujours None. Invisible en ligne (les
filtres y requêtent la base fraîche, jamais cette snapshot), mais
fatal hors ligne (aucune base à requêter).
- Une fois ce None corrigé, le port JS (forgeFieldColumn) relisait
cette même valeur sous une clé slugifiée+suffixée ("boss_id") alors
que gameData.data est déjà indexé par le nom D'AFFICHAGE du champ
("boss") — mismatch qui ne se voyait que sur un champ relation (le
seul cas où slugify(nom)+suffixe diverge du nom original). Supprime
ce port erroné, lit directement row[fieldName] partout.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
||
|
|
7bc4c89eaa |
Export Web/SCORM : corrige les URLs absolues cassées en local (file://)
Bug signalé : icône disparue et texte suivant du dialogue absent après export. render_icone.py (et son miroir JS, forgeRenderIcone) bakaient une URL "/static/icons/..." en dur, correcte en ligne (racine du serveur Flask) mais bloquée par CORS une fois ouverte en local (file:///static/...). Même souci pour les fichiers envoyés par le créateur (/game/<slug>/uploads/..., jamais dans static/, jamais copiés par le paquet). Ajoute _relativize_absolute_urls (réécriture globale post-rendu du HTML) + copie du dossier uploads/, et relativise le port JS de l'icône pour toute régénération après action en mémoire. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
f3b72d73c9 |
Export Web/SCORM : port complet du runtime jouable côté navigateur
Phase 1.2 de la feuille de route produit — un paquet SCORM tourne seul dans le LMS du client, sans serveur Forge Engine disponible. Ajoute static/js/play/offline/ (miroir JS de screens/rendering/ et data_actions/, sous window.FORGE_OFFLINE) pour que variables, score, données d'objet, répéteurs et conditions de visibilité fonctionnent entièrement en mémoire côté navigateur ; branche actions.js et bindings.js dessus au lieu d'un fetch() serveur. Ajoute publish/build_scorm_package.py (paquet statique + imsmanifest.xml SCORM 1.2 + wrapper API SCORM) et le bouton "Exporter (Web/SCORM)". Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |