a231bcf2fabcd2cd1dfd464dad01fd786fd52822
18
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
76a50fa87a |
Onboarding guidé systématique + tableau de bord simplifié
Comportement SYSTÉMATIQUE à chaque création de jeu (admin compris), pas une formalité réservée à l'inscription : /onboarding (routes/onboarding/) devient le point d'entrée unique — 4 cartes retournables (survol = explication au dos), défilement horizontal animé vers le nom du jeu. Un admin y repasse à volonté (pas de project_slug dédié, jamais bloqué/ redirigé vers un projet précédent) ; un compte "user" n'en a plus qu'un créé d'office (routes/auth/register_2fa.py), guidé ici à la place. - db/games/game_type_catalog.py : catalogue des 4 types (Quiz/ Embranchement-escape game/RPG/Créer mon jeu de A à Z), _meta['onboarding_type'] décide du "kind" du premier écran créé et si le tableau de bord complet reste accessible. - routes/games/game_dashboard.py, templates/game_dashboard_simple.html : un type restreint (quiz/embranchement/rpg) voit désormais SON tableau de bord (même route que "custom"), rendu en version simplifiée — juste ses écrans en cartes avec un aperçu RÉEL du contenu (scène mise à l'échelle par container query CSS, adaptée à la largeur réelle de la carte). "+ Ajouter un écran" n'y propose pas de choix de type : imposé par le projet (routes/screens/screens_new.py), verrouillé aussi côté serveur. - core/auth_guard.py : plus de blocage de game_dashboard par type — la restriction se fait au rendu, pas à l'accès à la route. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
d5a59bdbd8 |
Fusion des deux moteurs : type d'écran par écran, plus par projet
"document" (écrans %) et "jeu_2d" (scène pixels) devient une propriété PAR ÉCRAN (_screens.kind, migration automatique idempotente dans ensure_schema.py, source = l'ancien game_type au niveau projet) plutôt qu'un choix figé pour tout le jeu — un même projet peut désormais mélanger écrans classiques et scènes 2D librement. - routes/screens/screen_edit.py : dispatch vers l'éditeur de scène selon screen["kind"] (l'écran demandé), plus game["game_type"]. - screens/payload/full_game_payload.py, templates/play.html, static/js/play/screens.js : le rendu jouable (payload, markup, bascule du mode plein-écran #playFrame) décide écran par écran, y compris en cours de partie (changer d'écran ne recharge pas la page). - screens/screens_repo/create_screen.py : nouveau paramètre kind. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
449c36fd5d |
Bibliothèque de sprites animaux CraftPix (1/3) : catalogue, galerie, accès admin
Premier commit d'une fonctionnalité découpée en plusieurs lots (voir le plan "Bibliothèque de sprites animaux CraftPix") : intègre 14 familles d'animaux (15 variantes de couleur chacune) comme personnages Forge sélectionnables, à côté des 6 Kenney existants — réservé au rôle admin, licence CraftPix oblige (interdiction contractuelle de rendre ces sprites utilisables par un compte "user" via l'application). - screens/labels/animal_sprite_library.py (nouveau) : charge un manifest JSON généré une fois (voir scripts/generate_animal_sprite_manifest.py, commit suivant) et construit ADMIN_SPRITE_LIBRARY, dans le même format que l'existant PUBLIC_SPRITE_LIBRARY (screens/labels/sprite_library.py, ex-SPRITE_LIBRARY, renommé pour distinguer les deux). screens.SPRITE_LIBRARY reste le catalogue FUSIONNÉ (utilisé par resolve_personnage_animations pour la résolution runtime, sans filtrage par rôle — voir le constat d'exploration : le payload de jeu et /jouer/<slug> ne vérifient déjà aucun rôle nulle part). - screens/labels/sprite_gallery.py (nouveau) : sprite_gallery_families() groupe la galerie par famille — un animal n'apparaît qu'une fois (sa variante "de base"), ses 15 couleurs se choisissent depuis le panneau de propriétés (render_variant_gallery, templates/screen_edit.html), répondant à la suggestion de l'utilisateur plutôt que d'encombrer la galerie d'ajout de 210 tuiles quasi identiques. - routes/screens/screen_edit.py, routes/scenes/scene_edit_view.py : la galerie passée au template est filtrée par rôle (PUBLIC_SPRITE_LIBRARY pour un compte "user", SPRITE_LIBRARY complet pour un admin) — même idiome que core/auth_guard.py. - core/sprite_gate.py (nouveau) + 4 routes d'écriture (element_add, element_set_personnage_data, scene_object_add, scene_object_personnage_data) : ferme la brèche d'un POST direct qui contournerait la galerie filtrée (403 si un compte non-admin tente d'assigner un personnage animal). - tests/conftest.py : nouvelles fixtures user_client/user_game (compte "user" non-admin avec un projet assigné) pour tester le filtrage par rôle de bout en bout. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
f0070faced |
Phase A (2/2) : éditeur de scène 2D — route, template, runtime jouable
Deuxième et dernier commit de la Phase A du plan "Fondations d'une
plateforme multi-éditeurs" (le premier,
|
||
|
|
9e076f8cf9 |
Refonte : vrai widget "Personnage" visuel (remplace l'UI de la Phase 7)
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> |
||
|
|
d2c2f20b65 |
Phase 7 : personnage animé par sprites (poses/images successives)
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>
|
||
|
|
76331f9285 |
Phase 6 : son (musique de fond par écran + action "Jouer un son")
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> |
||
|
|
92fbfbc9dd |
Phase 4 : ajout dynamique d'une ligne à l'exécution
Nouveau sentinel LAST_INSERTED_ROW_ID = -3 (screens/flow/constants.py), aux côtés de CLICKED_ROW_ID = -1 — même principe : un id de ligne n'existe qu'APRÈS l'insertion, jamais connu à la création du nœud. Permet d'enchaîner un nœud "Ajouter une ligne" (crée une ligne VIDE) puis un ou plusieurs nœuds "Modifier une donnée" déjà existants (ciblant "➕ Dernière ligne ajoutée" dans le sélecteur "Ligne concernée", partagé avec les conditions) pour renseigner ses champs — réutilise 100% du mécanisme actuel, aucun nouveau format de payload multi-champs. screens/data_actions/apply_add_row_action.py : db.get_definition + db.insert_row(slug, definition, {}, player_id) — la ligne appartient au joueur qui agit pour un objet per_player (Phase 1). Nouvelles routes (créateur ET publique, comme prévu dès la Phase 1) : POST /game/<slug>/flow/nodes/<id>/run-add-row et son miroir /jouer/<slug>/.../run-add-row — renvoient {"ok", "row_id"}. routes/flow/flow_node_run_data.py (+ son miroir public) : résout aussi LAST_INSERTED_ROW_ID (en plus de CLICKED_ROW_ID déjà en place) via last_inserted_row_id transmis par le client. static/js/play/actions.js : runActionNode branche "ajouter_ligne" -> fetch la nouvelle route, pose window.lastInsertedRowId, puis refreshRuntimeData() (un Répéteur lié affiche la nouvelle ligne au prochain rendu, confirmé par l'audit préalable — aucun ajustement du mécanisme de rafraîchissement nécessaire). La branche "modifier_donnee" transmet désormais aussi last_inserted_row_id, comme clicked_row_id. templates/screen_edit.html + static/js/screen_edit/flow-editor.js : nouveau type d'action "Ajouter une ligne à un objet" (juste un sélecteur d'objet, aucun champ à remplir — le rappel du fonctionnement enchaîné est affiché directement dans le formulaire) ; le sélecteur "Ligne concernée" (partagé Condition/Modifier une donnée) gagne l'option "➕ Dernière ligne ajoutée" à côté de "🖱️ Ligne cliquée". Vérifié : 259 tests passent (4 nouveaux, dont un bout-en-bout via HTTP qui enchaîne réellement les deux nœuds et vérifie le champ renseigné, et un qui verrouille l'isolation par joueur de la ligne créée), 13 tests node:test toujours au vert, syntaxe JS validée. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
1b7706b357 |
Ajoute les blocs de logique : organise le graphe de flow en sous-graphes nommés
Le graphe de logique d'une scène s'affichait jusqu'ici sur un seul canevas plat (toutes les scènes accumulant leurs nœuds sur la même grille), ce qui ne tient pas à l'échelle dès qu'une scène évolue au fil de l'avancée du joueur et accumule des centaines/milliers de nœuds. Ajoute les "Blocs de logique" : un bloc regroupe un sous-ensemble de nœuds/arêtes d'un écran sous un nom et une description (comme une fonction). L'onglet "Logique de la scène" devient une liste de blocs (nom, description tronquée à 3 phrases, éléments concernés, nombre de nœuds, bouton "Ouvrir"). Ouvrir un bloc affiche SON graphe dans une modale plein écran, redimensionnable et déplaçable (patron déjà mûr dans game_dashboard.html, porté tel quel : makeFloatPanelDraggable/ Resizable/Fullscreenable). Décision d'architecture : un bloc est un automate FERMÉ — impossible de relier un nœud d'un bloc à un nœud d'un autre bloc (rejeté côté serveur dans flow_edge_add.py). Toute communication entre deux blocs passe par le système d'événements personnalisés déjà en place (declencher_evenement / trigger_event="evenement"). Détails techniques : - Nouvelle colonne _flow_nodes.block_id (nullable, sans FK — même rationale que trigger_element_id/target_element_id, voir screens/elements/delete_element.py) et nouvelle table _flow_blocks (screens/flow/ensure_flow_schema.py, screens/flow/blocks/ensure_flow_blocks_schema.py). - Migration douce et automatique : les nœuds posés avant l'existence des blocs (block_id NULL) sont rattachés, à la première ouverture de l'onglet, à un "Bloc principal" auto-créé (screens/flow/blocks/ list_flow_blocks.py) — aucun script de migration séparé, aucune donnée perdue. - Suppression d'un bloc = cascade complète (bloc + tous ses nœuds/ arêtes), patron identique à screens/custom_events/delete_custom_event.py mais scopé à un seul bloc plutôt que game-wide. - Routes CRUD sous routes/flow_blocks/, montées comme routes/custom_events/. - templates/screen_edit.html : FLOW (global unique) renommé en ALL_FLOW (toutes les données de l'écran) ; un seul bloc ouvert à la fois (modale unique, à la Unity) — currentBlockNodes()/currentBlockEdges() filtrent ALL_FLOW par CURRENT_BLOCK_ID à chaque rendu, sans tenir de seconde copie à synchroniser manuellement. Vérifié : 215 tests passent (7 nouveaux dans tests/test_flow_blocks.py, dont un qui verrouille l'ordre d'appel list_flow_blocks()/ list_flow_nodes() dans screen_edit.py — la migration douce doit tourner AVANT le chargement des nœuds, sinon le compte de nœuds affiché juste après une migration est périmé), syntaxe JS validée (script de screen_edit.html rendu via le client de test puis node --check). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
2c59e54556 |
Simplifie les événements : notification pure, sans paramètre
Retour de l'utilisateur sur le premier jet : "Déclencher un événement" ne doit JAMAIS faire choisir un élément — c'est une notification pure, rien de plus. C'est à l'ÉCOUTEUR (déclencheur "Sur un événement personnalisé" → condition → action) de décider quoi faire ensuite, avec ses réglages habituels (cible fixe, "Ligne cliquée"...), jamais à l'événement de transporter un paramètre. Retire donc tout le mécanisme de transmission ajouté au tour précédent (has_element_param, target_element_from_event, EVENT_ROW_ID, window.lastEventParams) : - db/custom_events/ : _custom_events perd sa colonne has_element_param — un événement n'est plus qu'un nom + une description. - screens/flow/ : retire target_element_from_event (colonne ajoutée par ALTER TABLE, laissée inerte sur les bases déjà migrées — sans conséquence, plus jamais lue ni écrite) et la constante EVENT_ROW_ID. - routes/flow/flow_node_run_data.py : retire la résolution EVENT_ROW_ID, revient à sa forme d'origine (seul CLICKED_ROW_ID reste géré). - templates/screen_edit.html : le nœud Action "Déclencher un événement" n'a plus qu'un sélecteur d'événement — plus de champs élément/ligne. Le nœud Action "Modifier un élément" perd la case "Utiliser l'élément transmis par l'événement en cours". L'onglet Événements perd la case à cocher "Paramètre" (création et édition). - templates/play.html : window.dispatchGameEvent(eventId) ne prend plus que l'id de l'événement — scan global inchangé, mais ne pose plus aucun window.lastEventParams. modifier_element et readFieldValue reviennent à leur résolution d'origine (plus de branche event-aware). 208 tests au total (2 tests retirés, devenus sans objet : la persistance de target_element_from_event et la résolution serveur d'EVENT_ROW_ID). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
f436190f90 |
Ajoute les événements personnalisés (éditeur + exécution)
Deuxième moitié de la fonctionnalité "événements" (voir le commit précédent pour le backend) : un nouvel onglet "📣 Événements" dans screen_edit.html (scène ET modèle, même route) pour créer/modifier/ supprimer un événement (nom, description, "a un paramètre élément" oui/ non) et voir où il est déjà écouté/déclenché ; deux nouveaux types de nœud dans le graphe de logique ; exécution réelle côté client (play.html). - templates/screen_edit.html : - Onglet Événements : barre de création + tableau (patron form/name="..." + attribut `form="eventEditFormN"` déjà utilisé par l'onglet Variables du tableau de bord, pour éditer plusieurs champs d'une ligne sans emboîter un <form> dans un <tr>). Colonne "Utilisé par" avec liens directs vers les écrans/modèles concernés (list_custom_event_usages, déjà en place côté backend). - Nœud Déclencheur "Sur un événement personnalisé" : un simple sélecteur d'événement (trigger_custom_event_id) — ni élément ni écran, retrouvé par un scan global côté client (comme "À l'affichage de l'écran"). - Nœud Action "Déclencher un événement" : sélecteur d'événement (target_custom_event_id), avec élément/ligne concernés affichés seulement si l'événement a has_element_param (réutilise le sélecteur d'élément existant + "Ligne cliquée" pour la ligne, pas de définition d'objet ici donc pas de liste de lignes fixes possible). - Nœud Action "Modifier un élément" : nouvelle case "Utiliser l'élément transmis par l'événement en cours" (target_element_from_event) — v1, seule cette action l'expose (extensible plus tard sans nouveau changement de schéma). - nodeLabel()/submitNodeForm()/toggleFlowTriggerFields()/ toggleFlowActionFields() étendus en conséquence, CUSTOM_EVENTS_MAP (id -> nom/has_element_param) exposé côté JS pour le rendu des libellés et l'affichage conditionnel des champs paramètre. - templates/play.html : - window.dispatchGameEvent(eventId, elementId, rowId) : scan de gameData.flows (toutes scènes ET modèles à la fois, même principe que findTriggerNode()/runScreenShowTriggers()) pour trouver chaque écouteur, pose window.lastEventParams puis exécute son graphe (runFlowFrom) — au même titre que window.lastClickedRowId pour "Ligne cliquée". - runActionNode : nouvelle branche "declencher_evenement" (résout CLICKED_ROW_ID pour la ligne transmise, comme "Modifier une donnée") ; branche "modifier_element" étendue pour résoudre dynamiquement l'élément depuis window.lastEventParams quand target_element_from_event est actif. - readFieldValue (évaluation de condition) et l'appel serveur de "Modifier une donnée" (routes/flow/flow_node_run_data.py) résolvent désormais aussi EVENT_ROW_ID (-2), au même endroit que CLICKED_ROW_ID (-1) déjà en place. - routes/screens/screen_edit.py : passe custom_events/ custom_event_usages/custom_events_map_json au template (même patron que global_variables déjà threadé pour le sélecteur de variable dans le formulaire de Condition). Nouveaux tests dans tests/test_custom_events.py : forme exacte du payload runtime exposé au JS (types entiers, pas des chaînes — une comparaison stricte "===" échouerait silencieusement sinon), target_element_from_event bien persisté, résolution serveur d' EVENT_ROW_ID depuis le corps de la requête. 210 tests au total. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
5d6747770c |
Auto-héberge les polices Google Fonts et animate.css (fin des CDN)
Étape 1 de la fonctionnalité "Publier un jeu en exécutable autonome" : un jeu exporté devra fonctionner sans AUCUNE connexion internet, ce qui suppose d'abord que l'app elle-même n'ait plus aucune dépendance CDN — Bulma l'était déjà (refonte design system), il ne restait que Google Fonts et animate.css, chargés par templates/play.html ET templates/screen_edit.html (aperçu du canevas dans l'éditeur). GOOGLE_FONTS_LINK (screens/widgets/font_options.py) était une constante FIXE (4 polices, 2 graisses chacune, jamais dépendante du jeu en cours) : téléchargées une fois pour toutes (45 fichiers woff2, ~1.1 Mo au total avec la couverture cyrillique/vietnamienne incluse) dans static/vendor/fonts/, avec un fonts.css régénéré à partir du CSS officiel de Google Fonts mais pointant vers les fichiers locaux. Même chose pour animate.min.css 4.1.1 (static/vendor/animate.min.css). routes/play/game_play.py et routes/screens/screen_edit.py ne passent plus google_fonts_link aux templates (devenu inutile, les deux pages chargent directement les fichiers locaux) ; GOOGLE_FONTS_LINK est retiré de screens/widgets/font_options.py et screens/__init__.py (plus aucun appelant). tests/test_animations.py : les deux tests qui vérifiaient la présence du lien CDN vérifient maintenant la présence du fichier local (animate.min.css) — renommés en conséquence. 199 tests toujours verts. Reste à faire pour la fonctionnalité complète : empaquetage Python portable + serveur minimal + bouton "Publier". Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
d875557254 |
Fusionne les 4 pages de création dans le dashboard, retire le titre/BDD
Suite de la demande précédente : les 4 pages autrefois listées dans la barre de navigation n'existent plus en tant que pages séparées — tout vit désormais dans les onglets du tableau de bord (commit précédent) ou, pour la création d'un objet, dans un panneau déplaçable. - screens_list.html + sa route (screens_list) : supprimés (l'onglet "Écrans du jeu" du dashboard couvre déjà tout : créer, réordonner, éditer, supprimer). screen_new/screen_move/screen_delete redirigent maintenant vers le dashboard (tab=screens) au lieu de cette page. - element_types.html : supprimé, mais la route element_types est conservée (GET redirige vers le dashboard, POST — utilisé par la barre de création repliable de l'onglet "Éléments de jeu" — continue de fonctionner). element_type_edit/element_type_delete redirigent aussi vers le dashboard. - game_variables.html + sa route (game_variables) : supprimés (l'onglet "Variables" du dashboard couvre déjà tout). create_global_var/ global_var_edit/global_var_delete redirigent vers le dashboard (tab=variables) au lieu de cette page. - object_form.html : supprimé. La route object_new (POST) est conservée pour traiter la soumission du panneau — voir plus bas — mais ne rend plus de page pour un GET (redirige vers le dashboard). Nouveau panneau déplaçable "Nouvel objet" sur le dashboard (bouton "+ Nouvel objet" de l'onglet Objets) : réutilise .floatPanel/ .floatPanelHeader/.floatPanelBody (déjà utilisées dans l'éditeur d'écran) avec une nouvelle variante centrée (.floatPanel--center) et son propre glisser-déposer minimal (pas de position persistée, contrairement aux panneaux de l'éditeur d'écran — inutile pour un panneau ouvert ponctuellement). Contenu et script (object_form.js) repris tels quels de l'ancienne page. base.html : la barre de navigation du jeu n'a donc plus que 2 liens — "📊 Tableau de bord" (nouveau) et "▶️ Jouer" (toujours en dernier). game_dashboard.html : titre du jeu et chemin de la base de données retirés (redondants avec le nom déjà visible dans l'onglet du navigateur/la barre de nav). Les liens "crée-en un"/"gérer les variables" dans l'éditeur d'écran (screen_edit.html) pointent maintenant vers le dashboard avec le bon onglet (?tab=...), lu et appliqué au chargement de la page (switchDashTab() côté JS). 2 tests (test_screens_and_elements.py) mis à jour : ils vérifiaient le contenu des pages supprimées (element-types, screens) — adaptés pour vérifier la même chose sur le dashboard, qui porte maintenant cette information. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
9c9e3c5379 |
Le sélecteur de champ apparaît maintenant sur tout nouveau widget d'un élément de jeu lié à un objet
Le tour précédent exigeait que CHAQUE widget règle sa propre "Donnée
liée" (_data_definition_id) pour voir apparaître le sélecteur de champ -
mais un élément de jeu ("Mail card"...) créé avec un "Objet lié" (voir
element_types.html, bound_definition_id) a précisément pour but d'éviter
ce réglage widget par widget : ses {{champ}} sont censés venir de CET
objet, fourni plus tard par le Répéteur qui l'utilisera comme modèle de
ligne. D'où le bug remonté : un nouveau Titre/Texte posé dans un tel
élément de jeu n'affichait jamais le sélecteur.
Ajoute get_element_type_by_template_screen(slug, screen_id), pour
retrouver depuis l'éditeur d'un écran-modèle l'entrée du catalogue (et
donc l'objet lié) dont il est la recette. screen_edit.py le calcule pour
le panneau de propriétés et le passe à controls_with_values(), qui
l'utilise comme repli pour le champ "Contenu" SEULEMENT si ce widget n'a
pas déjà sa propre "Donnée liée" réglée (priorité conservée au réglage le
plus spécifique).
Ajoute tests/test_element_type_bound_field_picker.py (apparition sans
réglage supplémentaire, absence sans objet lié, priorité à la "Donnée
liée" du widget si réglée).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
||
|
|
c04bc0b926 |
Ajoute la condition de visibilité et les variables globales
Nouveau panneau "Condition de visibilité" disponible dans les propriétés
de TOUT élément (widget) : permet de masquer un élément en mode jouable
selon deux moyens, au choix -
- une variable globale (nom + type + valeur, une seule par jeu, stockée
dans une nouvelle table _global_variables) ;
- le champ d'un objet de données existant (même convention "état de
partie" - une seule ligne - déjà utilisée par la Jauge).
Une variable ne servant à rien si elle ne peut jamais changer en cours de
partie, ajoute aussi une nouvelle action de flow "Modifier une variable
globale" (parallèle à "Modifier une donnée"), avec sa propre route
d'exécution serveur et son sous-formulaire dans l'éditeur de logique de
scène. Une variable peut aussi se créer à la volée depuis le sélecteur du
panneau de visibilité, sans quitter les propriétés de l'élément.
La condition n'est évaluée qu'en mode jouable (/game/<slug>/play), jamais
dans l'éditeur, pour que l'élément reste toujours sélectionnable. Un
élément masqué se réévalue en direct après toute action "Modifier une
donnée/variable", via le même mécanisme de rafraîchissement déjà utilisé
par la Jauge et le Répéteur.
Corrige au passage deux bugs découverts en testant bout en bout : (1)
apply_ctx plantait sur le nouveau marqueur interne _forge_play_mode (un
booléen parmi les {{champ}} à substituer, qui attend des chaînes) ; (2)
_compare traitait toute valeur booléenne stockée en chaîne ("0" inclus,
donc toujours vraie en Python) comme vraie - correct pour les champs
d'objet (entiers SQLite) mais faux pour les variables globales (toujours
stockées en texte).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
||
|
|
cc0442ef5f |
Add a Font Awesome icon gallery to the properties panel, draggable onto the screen
New "Icône" widget (<i class="...">, color/size customizable exactly like any other widget) plus a curated set of ~250 verified Font Awesome 5 Free solid icon names (fontawesome_icons.py) — not the full ~1500-icon catalog, since an embedded list needs to be guaranteed accurate (a wrong class name silently renders as a blank glyph); any other valid FA5 class still works by typing it directly into the widget's "Icône" setting. The gallery lives in the (now always-visible) top of the right floating panel, searchable, with each tile both clickable and HTML5-draggable onto the canvas — either action posts to element_add with the chosen icon_class, which now seeds the new element's class instead of leaving it on the generic default. Available in the element-type template editor too, since it reuses screen_edit.html. Loads Font Awesome 5.15.4 (cdnjs) alongside the existing animate.css/Bulma links, in both the editor and /play. Verified end to end: gallery renders with real icon glyphs, clicking/simulated-drop creates a correctly-classed <i> element, and the actual /play route renders it with Font Awesome loaded. Full suite green (89). |
||
|
|
c9d3069f47 |
Fix Jauge always reading the object's most recent row
A Jauge could only target a whole object, not a specific record — three gauges pointing at the same "value" field (e.g. Réputation/ Trésorerie/Confiance in one "jauge" object) all silently showed the most recent row's value, with no way to tell them apart. Add "Enregistrement (ligne) à suivre" (row_id) so a Jauge targets one specific row, and "Champ contenant le nom" (champ_nom) to show a label above the bar — both as dropdowns populated from the object's actual fields/rows (previously "Champ numérique à afficher" was free text the user had to type correctly by hand). No regression: without row_id the widget still falls back to the latest row, exactly as before. Extract data_definition_options() (rows+fields for a definition) out of routes/screens/screen_edit.py so controls_with_values.py can reuse it server-side for the initial render; a small client-side handler (bindJaugeDefinitionSelect) repopulates the same selects live when the tracked object is changed without leaving the panel. Verified live with Playwright: picking "jauge" then "Confiance" then "value"/"name" in the panel renders an 80%-filled, green-leaning bar labelled "Confiance" on /play — not the 20%/50% of the other rows. |
||
|
|
3f4ebc4527 | first commit |