Commit Graph
4 Commits
Author SHA1 Message Date
williamandClaude Sonnet 5 9e076f8cf9 Refonte : vrai widget "Personnage" visuel (remplace l'UI de la Phase 7)
Build and deploy / test-python (push) Successful in 1m26s
Build and deploy / test-js (push) Successful in 6s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
L'utilisateur a testé la Phase 7 (sprites pilotés via un menu déroulant
+ zone de texte dans la logique de flow) et l'a rejetée à raison : ce
n'est pas comme ça qu'un moteur de jeu (Phaser, Unity) gère un
personnage. Cette refonte remplace tout le flux d'AUTEURING par un vrai
widget visuel — le moteur d'exécution de la Phase 7 (runSpriteAnimation,
activeSpriteAnimations, orientation, kind="sprite" de la Timeline) reste
inchangé.

Nouveau widget "personnage" (screens/widgets/registry.py) :
- Rendu serveur dédié (special_render, screens/rendering/render_personnage.py)
  qui affiche la pose "idle" dès le HTML généré — jamais une image
  cassée à configurer après coup.
- Toutes ses données (source Forge ou sprites propres au créateur, quel
  personnage/quelles animations) vivent dans une seule clé JSON
  _personnage_data (screens/rendering/personnage_data.py), sans aucune
  migration de schéma (même patron que c_clause_list).
- Nouvelle échappatoire "custom_panel", symétrique à "special_render" mais
  pour le panneau de propriétés : ce widget affiche une galerie/un import
  de sprites sur-mesure plutôt que les contrôles génériques.

Galerie visuelle de personnages Forge (VRAIES miniatures, pas un emoji) :
- Panneau gauche "🎭 Personnages" : pose un personnage déjà configuré,
  animé immédiatement.
- Panneau droit (propriétés) : change le personnage Forge de l'élément
  sélectionné, ou importe les animations d'un sprite personnalisé.
- static/js/screen_edit/personnage-preview.js : lance l'aperçu animé de
  CHAQUE personnage du canevas dès le chargement de la page et après
  toute sauvegarde — le cœur de la demande ("je dois voir ça bouger").

Sélecteur d'animation à miniatures (nœud de flow "Jouer une animation" et
clip de Timeline "sprite") : remplace le menu déroulant/la zone de texte
par une grille de vraies miniatures, scopée aux SEULES animations du
personnage réellement ciblé (ELEMENT_ANIMATIONS_MAP, résolu côté serveur
à partir des propriétés de cet élément précis) — jamais un catalogue
global. Le format stocké sur le nœud/le clip ({frames, fps, loop}) est
inchangé, seule l'UI d'édition change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-30 20:26:39 +02:00
williamandClaude Sonnet 5 d2c2f20b65 Phase 7 : personnage animé par sprites (poses/images successives)
Build and deploy / test-python (push) Successful in 1m26s
Build and deploy / test-js (push) Successful in 6s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Ajoute une nouvelle action de flow "jouer_animation_sprite" qui joue une
séquence de PNG sur un élément image (cycle en boucle type marche, ou
une fois type saut) — réutilise target_element_id (déjà whitelisté) et
data_value en JSON {frames, fps, loop}, exactement le patron déjà établi
par "jouer_son" (Phase 6) et "alea" (Phase 2) : aucune nouvelle colonne,
aucune migration de schéma.

Ajoute une propriété d'élément "orientation" (Modifier un élément) pour
retourner un personnage en miroir (gauche/droite/bascule) sans nécessiter
une 2e feuille de sprites "vue de dos" — même patron que "surbrillance"/
"désactivé".

Étend aussi la Timeline d'animation existante (kind="sprite", aux côtés
de "animate_css"/"custom") pour qu'un personnage puisse animer tout seul
dès l'affichage de l'écran (ex. idle en boucle perpétuelle), pas
seulement en réaction à un événement — réutilise la colonne générique
custom_keyframes (JSON) et le réglage iteration_count déjà là pour la
boucle, aucune migration non plus. Les deux entrées (action de flow et
clip de timeline) partagent le même moteur côté client
(runSpriteAnimation()/activeSpriteAnimations dans static/js/play/
actions.js, indexé par nœud DOM plutôt que par id d'élément pour
supporter plusieurs instances d'un même écran-modèle animées
indépendamment).

Une bibliothèque de sprites Forge (2 personnages Kenney CC0, sous-
ensemble curé idle/marche/saut copié dans static/characters/) est
proposée dans l'éditeur, mais un créateur peut tout aussi bien utiliser
ses propres sprites uploadés (même route d'upload générique que le son
de la Phase 6).

Périmètre volontairement limité à ce qui a été demandé : pas d'avatar
modulable en couches (assemblage cheveux/haut/bas par le joueur),
écarté du plan initial à la demande de l'utilisateur.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-30 19:18:07 +02:00
williamandClaude Sonnet 5 76331f9285 Phase 6 : son (musique de fond par écran + action "Jouer un son")
Build and deploy / test-python (push) Successful in 1m27s
Build and deploy / test-js (push) Successful in 6s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Ajoute deux mécanismes distincts, à la demande de l'utilisateur qui a
précisé qu'un son doit pouvoir être attaché à une SCÈNE (pas seulement
joué ponctuellement par une action de flow, comme prévu initialement) :

- Musique de fond par écran (nouveau champ background_music_url sur
  _screens, ALTER TABLE nullable) : réglée dans le panneau gauche de
  l'éditeur (URL ou envoi de fichier, réutilise la route d'upload
  générique existante), enregistrée en AJAX au même patron que le format
  d'aperçu (screen_set_aspect.py). Démarrée en boucle à l'affichage de
  l'écran et arrêtée au changement d'écran (runScreenBackgroundMusic(),
  appelée depuis showScreen() dans static/js/play/screens.js) — un seul
  Audio actif à la fois, jamais cumulé avec une musique restée d'un écran
  précédent.

- Action de flow "jouer_son" (aux côtés des actions existantes) : effet
  sonore ponctuel, non bouclé, déclenchable sur n'importe quel nœud
  Déclencheur. Réutilise data_value (déjà un champ texte générique sur
  le nœud action, comme pour "attendre") plutôt qu'une nouvelle colonne
  dédiée — fire-and-forget côté client (runActionNode), ne bloque jamais
  la suite du graphe.

Les deux réutilisent le même mécanisme d'upload de fichier déjà en place
ailleurs dans l'éditeur (ex. source d'une vidéo), sans nouvelle route.

Ceci complète les 6 phases du plan d'extension du moteur (état par
joueur, hasard/maths, clavier/minuteur, ajout de ligne, position/
collision, son) : Forge Engine peut désormais couvrir des jeux bien
au-delà du narratif/puzzle/quiz (action, arcade, jeux à contrainte de
temps).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-30 17:56:49 +02:00
williamandClaude Sonnet 5 fe807ba51e Phase -1 (suite) : découpe l'éditeur de screen_edit.html en modules JS
Même chantier que le commit précédent (moteur de jeu, play.html) —
templates/screen_edit.html était un unique fichier HTML+CSS+JS de 3312
lignes, tout l'éditeur (arborescence, panneaux flottants, canevas,
formulaire de propriétés, éditeur de flow à nœuds, blocs de logique,
timeline d'animation) vivant dans UN SEUL <script>.

Ce fichier est plus imbriqué que play.html : de nombreux appels
s'exécutent au niveau racine du script (pas seulement des déclarations
de fonctions), et JavaScript hoiste les déclarations `function` sur
TOUT le script — un appel au niveau racine peut donc référencer une
fonction déclarée PLUS LOIN dans le même fichier. Découper naïvement
casserait cet ordre implicite. Un audit dédié (analyse ligne par ligne
de chaque appel racine + son graphe d'appel transitif) a identifié 3
références "en avance" réelles, toutes regroupées dans la même zone
(initBuilderPanel()/toggleActionFields() → bindAspectButtons/
toggleElementPropertyValue/onDataDefinitionChange) — le découpage
respecte cette contrainte : chaque fichier est une TRANCHE SÉQUENTIELLE
de l'original (jamais une réorganisation), et cette zone spécifique
reste un seul fichier (panel-init.js) pour que le hoisting continue de
fonctionner exactement comme avant.

5 fichiers sous static/js/screen_edit/ :
- tree-panels.js — arborescence, menu contextuel, panneaux flottants
  gauche/droite, galerie d'icônes, modale de suppression/choix d'icône,
  glisser-déposer du canevas, panneau de propriétés (autosave).
- panel-init.js — (ré)initialisation du panneau central après chaque
  changement de sélection, filtres de répéteur/donnée liée, condition
  de visibilité, champs d'action du formulaire de nœud.
- flow-editor.js — éditeur de flow à nœuds (rendu du graphe, formulaire
  d'ajout de nœud, blocs de logique — currentBlockNodes/Edges).
- tabs-and-blocks.js — onglets du centre, panneaux flottants génériques
  (drag/resize/plein écran), modale d'un bloc de logique.
- animation-timeline.js — timeline d'animation (clips Animate.css/
  personnalisés).

Toutes les données injectées par Jinja (GAME_SLUG, SCREEN_ID,
DEFINITIONS_DATA, FLOW_NODES_INITIAL, ELEMENTS_LABELS, CUSTOM_EVENTS_MAP,
ANIM_CLIPS...) sont posées UNE FOIS par un petit <script> inline resté
dans le template, avant les <script src> — même patron que
static/js/play/. Le seul bout de logique resté inline est la toute
petite IIFE d'ouverture initiale (?tab=/?block=), qui dépend directement
de request.args et doit s'exécuter après que tous les fichiers soient
chargés.

tests/conftest.py : screen_edit_js_bundle() (même principe que
play_js_bundle(), Phase -1 précédente) — 4 tests qui vérifiaient la
présence de telle fonction/chaîne dans le HTML de l'éditeur (le JS y
était inline) sont mis à jour pour chercher dans ce bundle. Un des deux
échecs révélait un test déjà fragile (assert "Ligne cliquée" in html
vérifiait en réalité le TEXTE SOURCE d'un <script> inline, jamais du
HTML réellement rendu — ce texte ne peut plus s'y trouver une fois la
fonction qui le construit dynamiquement déplacée dans un fichier
externe) : corrigé pour vérifier le bundle JS + la disponibilité de la
route séparément.

Vérifié : 215 tests passent, syntaxe JS validée sur les 5 nouveaux
fichiers (node --check) et sur les <script> inline restants (rendus via
le client de test). Test manuel recommandé (édition complète d'une
scène : arborescence, propriétés, glisser-déposer, logique de flow,
blocs, timeline) avant de considérer ce découpage définitivement sans
risque — comme pour play.html, ce fichier n'a pas de harnais de test
DOM automatisé.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-30 14:38:57 +02:00