Deux bugs remontés en test manuel sur l'éditeur de scène (Phase A,
commit f0070fa) :
1. Décalage visuel à l'ajout d'un objet de scène (personnage/décor) :
render_scene_object.py positionne son <img> en absolu (left/top/
width/height en px), pensé pour être un enfant DIRECT de
.playScreen.playScene en mode jouable. Dans scene_edit.html, la même
balise est nichée dans .canvasElementInner, lui-même déjà positionné
par .canvasElement — l'image se repositionnait donc EN PLUS depuis
#canvas (son ancêtre positionné le plus proche), en double du
décalage déjà appliqué par le conteneur. Corrigé par une règle CSS
scoped à l'éditeur (.canvasElementInner > img) qui neutralise le
positionnement propre de l'image et la fait simplement remplir son
conteneur.
2. "FOREIGN KEY constraint failed" à l'ajout d'un clip de Timeline sur
un objet de scène : _animation_clips.element_id portait une VRAIE
contrainte FK vers _screen_elements depuis la création de la table.
animation-timeline.js est réutilisé TEL QUEL entre les deux éditeurs
(voir le plan "Fondations d'une plateforme multi-éditeurs") et
n'opère aucune distinction — pour un jeu jeu_2d, element_id désigne
en réalité un id de _scene_objects, absent de _screen_elements, d'où
l'échec de l'INSERT sous PRAGMA foreign_keys=ON. ensure_animation_schema
reconstruit maintenant la table (une fois, migration automatique à la
volée comme le reste du schéma) sans cette contrainte FK — même
patron que trigger_element_id/cond_element_a dans ensure_flow_schema.py.
Comme la suppression en cascade reposait jusqu'ici sur cette FK, un
nettoyage manuel des clips a été ajouté à la suppression d'un élément
(delete_element.py) et d'un objet de scène (delete_scene_object.py).
Nouveaux tests (tests/test_scene_edit_view.py, +4 cas) : ajout d'un
clip de Timeline sur un objet de scène via la route, nettoyage des
clips à la suppression d'un objet de scène et d'un élément DOM. Suite
complète : 312 tests passent (aucune régression).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Deuxième et dernier commit de la Phase A du plan "Fondations d'une
plateforme multi-éditeurs" (le premier, efa7d1d, posait le schéma et le
CRUD des objets de scène). Ce commit branche l'éditeur et le mode
jouable sur ces fondations, en réutilisant TEL QUEL tout ce qui est déjà
générique côté moteur de logique.
Éditeur (routes/scenes/, templates/scene_edit.html,
static/js/scenes/scene-editor.js) :
- routes/screens/screen_edit.py délègue à render_scene_edit() dès que
game_type == "jeu_2d" — même endpoint Flask "screen_edit" pour les
deux éditeurs, aucune route dupliquée.
- Nouveau template scene_edit.html : canevas à taille FIXE en pixels
(scene_width/scene_height) avec glisser-déposer/redimensionnement en
pixels (scene-editor.js, mirror pixel de tree-panels.js), galerie
personnages/décors. Les onglets "Blocs de logique"/"Timeline
d'animation"/"Événements" réutilisent tels quels flow-editor.js,
tabs-and-blocks.js et animation-timeline.js.
- flow-editor.js : nouveau flag FLOW_TARGETS_OBJECTS (false par défaut,
true dans scene_edit.html) qui fait écrire submitNodeForm() vers
trigger_object_id/target_object_id au lieu de trigger_element_id/
target_element_id, plus une branche "Modifier un objet de scène"
(position px, visibilité, orientation) et des gardes null partout
(le DOM de scene_edit.html n'a pas tous les champs de l'éditeur
document).
- blocks_view.py étend l'ensemble d'ids d'éléments concernés par un
bloc pour inclure aussi trigger_object_id/target_object_id.
Runtime jouable (templates/play.html, static/js/play/actions.js,
screens/payload/full_game_payload.py) :
- full_game_payload() construit les écrans d'un jeu jeu_2d à partir de
_scene_objects (render_scene_object) au lieu de _screen_elements, et
récupère les animations de personnage sur les objets de scène.
- play.html : #playFrame occupe tout le viewport pour une scène jeu_2d
(pas de ratio fluide) ; la scène se centre via .playScreen.playScene,
qui réutilise tel quel showScreen() (déjà indexé par id d'écran, pas
par forme DOM) — aucun fichier "scenes.js" séparé n'a été nécessaire.
- actions.js : jouer_animation_sprite retombe sur target_object_id si
target_element_id est absent ; nouvelle action modifier_objet_scene
avec applyObjectProperty() (positions en px, contrairement aux % de
applyElementProperty()).
Un bug de gabarit a été découvert et corrigé pendant la vérification :
le commentaire CSS de play.html contenait littéralement "{% for %}"
comme texte français, que Jinja interprétait comme une vraie balise et
faisait planter le rendu — reformulé. render_scene_object() n'était en
outre jamais appelé par la vue de l'éditeur (les objets de scène
s'affichaient sans image) — scene_edit_view.py attache maintenant
rendered_html à chaque objet avant de les passer au template.
Nouveaux tests (tests/test_scene_edit_view.py, 10 cas) : dispatch
document vs jeu_2d, rendu d'un personnage sélectionné, CRUD géométrie/
suppression d'objet, nœuds de flow ciblant un objet de scène (action et
condition de collision), payload et page /play pour un jeu jeu_2d,
présence des nouveaux helpers JS. Suite complète : 309 tests passent
(299 existants + 10 nouveaux, aucune régression). node --check et
node --test (13 tests JS) passent également.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Première brique du plan "Fondations d'une plateforme multi-éditeurs" —
l'utilisateur veut un éditeur dédié aux jeux 2D/serious games (scène à
coordonnées pixel fixes, objets en couches, collision, personnages
animés), distinct de l'éditeur générique actuel, sans dupliquer ce qui
peut être partagé (comptes, objets de données, moteur de logique de
flow, hébergement/publication).
- db/games/get_game_type.py (nouveau) : "document" (défaut, éditeur
actuel) ou "jeu_2d" (nouveau), stocké dans _meta comme
is_public_played — aucune migration pour les jeux déjà créés
(retombent sur "document"). Choisi obligatoirement à la création
(templates/index.html), jamais modifiable ensuite.
- screens/scenes/ (nouveau sous-module) : table _scene_objects (une
scène = des objets en pixels fixes, pas les % fluides de
_screen_elements — indispensable pour la collision/l'animation),
CRUD complet, rendu HTML. kind="personnage" réutilise TELLE QUELLE la
structure _personnage_data et les fonctions resolve_personnage_* déjà
écrites pour le widget "personnage" de l'éditeur document (Phase 8) —
même bibliothèque Forge, même moteur d'animation, juste une autre
table de stockage.
- screens/flow/ensure_flow_schema.py : += trigger_object_id/
target_object_id (ALTER TABLE sans contrainte FK, même patron que
cond_element_a) — le moteur de logique de flow (_flow_nodes/_flow_edges,
flow-engine.js) reste EXACTEMENT le même pour les deux éditeurs, seule
la palette de nœuds change (screens/scenes/flow_palette.py, nouveau :
sous-ensemble direct des triggers/actions existants, déjà génériques).
- screens/screens_repo/ensure_schema.py : += scene_width/scene_height
sur _screens (taille de scène fixe en pixels, sans effet sur un écran
"document").
Reste à faire (prochains commits) : route + template de l'éditeur de
scène, puis le rendu en mode jouable.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>