Enrichit les declencheurs/actions de scene (clic/survol/affichage, surbrillance/video/son/visibilite/indication/attendre) et fiabilise la pose d'un fond/decor importe
Build and deploy / test-python (push) Successful in 10m59s
Build and deploy / test-js (push) Successful in 1m27s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped

- 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>
This commit is contained in:
william
2026-09-12 00:28:46 +02:00
co-authored by Claude Sonnet 5
parent b07b231a61
commit 559331f9cf
67 changed files with 4739 additions and 306 deletions
+56
View File
@@ -23,6 +23,62 @@ def test_jeu2d_game_dispatches_to_scene_editor(client, tmp_game_slug_cleanup):
assert "Personnages" in html
def test_scene_edit_view_splits_my_assets_into_fond_decor_sons_videos_subsections(client, tmp_game_slug_cleanup):
"""Demande explicite : "des sous-menu pour voir, utiliser ou
supprimer des son, image et video", PUIS "un bouton d'import séparé
pour les images de fond et les objets" — "Mes assets" doit séparer
Fonds/Décors/Sons/Vidéos (voir auth/user_asset_kind.py,
auth/create_user_asset.py::scene_kind), chacun avec son bouton de
suppression ; le sélecteur de fichier des actions "son"/"vidéo"
(USER_ASSETS_OPTIONS), lui, voit TOUJOURS tout, peu importe le type."""
import auth
slug, screen_id = _create_jeu2d_game(client, tmp_game_slug_cleanup)
with client.session_transaction() as sess:
user_id = sess["user_id"]
fond_id = auth.create_user_asset(user_id, "ciel.png", original_name="ciel.png", source="upload", scene_kind="fond")
decor_id = auth.create_user_asset(user_id, "photo.png", original_name="photo.png", source="upload", scene_kind="decor")
audio_id = auth.create_user_asset(user_id, "bip.mp3", original_name="bip.mp3", source="upload")
video_id = auth.create_user_asset(user_id, "clip.mp4", original_name="clip.mp4", source="upload")
html = client.get(f"/game/{slug}/screens/{screen_id}/edit").get_data(as_text=True)
m = re.search(r"var USER_ASSETS_OPTIONS = (\[.*?\]);", html)
names = [o["name"] for o in json.loads(m.group(1))]
assert set(names) == {"ciel.png", "photo.png", "bip.mp3", "clip.mp4"}
fond_section = html.split('<summary>Fonds</summary>', 1)[1].split("</details>", 1)[0]
decor_section = html.split('<summary>Décors/objets</summary>', 1)[1].split("</details>", 1)[0]
sons_section = html.split('<summary>Sons</summary>', 1)[1].split("</details>", 1)[0]
videos_section = html.split('<summary>Vidéos</summary>', 1)[1].split("</details>", 1)[0]
assert "ciel.png" in fond_section and "photo.png" not in fond_section
assert "addSceneObject('fond', null, null, {})".format(fond_id) in fond_section
assert "photo.png" in decor_section and "ciel.png" not in decor_section
assert "addSceneObject('decor', null, null, {})".format(decor_id) in decor_section
assert "bip.mp3" in sons_section and "photo.png" not in sons_section
assert "clip.mp4" in videos_section and "photo.png" not in videos_section
# Un bouton de suppression pour chacun (demande explicite).
for asset_id in (fond_id, decor_id, audio_id, video_id):
assert "deleteUserAsset({},".format(asset_id) in html
def test_scene_edit_view_defaults_a_legacy_image_without_scene_kind_to_decor(client, tmp_game_slug_cleanup):
"""Une image importée AVANT l'ajout de scene_kind (NULL en base) doit
rester utilisable — comportement inchangé : "decor", jamais perdue
dans un vide entre les deux sous-sections."""
import auth
slug, screen_id = _create_jeu2d_game(client, tmp_game_slug_cleanup)
with client.session_transaction() as sess:
user_id = sess["user_id"]
auth.create_user_asset(user_id, "ancienne.png", original_name="ancienne.png", source="upload")
html = client.get(f"/game/{slug}/screens/{screen_id}/edit").get_data(as_text=True)
decor_section = html.split('<summary>Décors/objets</summary>', 1)[1].split("</details>", 1)[0]
fond_section = html.split('<summary>Fonds</summary>', 1)[1].split("</details>", 1)[0]
assert "ancienne.png" in decor_section
assert "ancienne.png" not in fond_section
def test_scene_edit_view_renders_with_a_personnage_object_selected(client, tmp_game_slug_cleanup):
slug, screen_id = _create_jeu2d_game(client, tmp_game_slug_cleanup)
resp = client.post(