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>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
b07b231a61
commit
559331f9cf
+127
-1
@@ -608,6 +608,45 @@ body.builderBody > main.content{ flex:1 1 auto; min-height:0; overflow:hidden; d
|
||||
reconnaissable, contrairement à une icône. */
|
||||
.iconGallery.personnageGallery{ grid-template-columns:repeat(2, 1fr); gap:10px; max-height:420px; }
|
||||
.personnageThumb{ width:100%; height:100%; object-fit:contain; image-rendering:pixelated; }
|
||||
|
||||
/* "Mes assets" — sous-sections Images/Sons/Vidéos (demande explicite :
|
||||
"voir, utiliser ou supprimer des son, image et vidéo") : une tuile
|
||||
image garde son bouton de pose (clic/glisser-déposer, voir
|
||||
iconGalleryTile) avec un ✕ de suppression posé par dessus ; un son/une
|
||||
vidéo n'ont rien à "poser" — juste une rangée avec leur lecteur natif
|
||||
(aperçu direct, "voir"/"utiliser" au sens d'écouter/visionner avant de
|
||||
le choisir dans le sélecteur d'une action) et le même ✕. */
|
||||
.userAssetTileWrap{ position:relative; }
|
||||
.userAssetTileWrap .iconGalleryTile{ width:100%; height:100%; }
|
||||
.userAssetDeleteBtn{
|
||||
position:absolute; top:-6px; right:-6px; width:18px; height:18px; border-radius:50%;
|
||||
border:1px solid var(--border); background:#1a1d24; color:var(--muted, #8b95a7);
|
||||
font-size:10px; line-height:1; display:flex; align-items:center; justify-content:center; cursor:pointer;
|
||||
padding:0; z-index:2;
|
||||
}
|
||||
.userAssetDeleteBtn:hover{ background:#e0524d; color:#fff; border-color:#e0524d; }
|
||||
.userAssetRow{
|
||||
display:flex; flex-direction:column; gap:4px; padding:8px; margin-top:8px;
|
||||
background:var(--panel2); border:1px solid var(--border); border-radius:8px;
|
||||
}
|
||||
.userAssetRow:first-child{ margin-top:0; }
|
||||
.userAssetRow audio, .userAssetRow video{ width:100%; display:block; border-radius:4px; background:#000; }
|
||||
.userAssetRowFooter{ display:flex; align-items:center; justify-content:space-between; gap:8px; }
|
||||
.userAssetName{ font-size:11.5px; color:var(--text-dim); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; flex:1; }
|
||||
.userAssetRowFooter .userAssetDeleteBtn{ position:static; flex-shrink:0; }
|
||||
/* "→ Fond"/"→ Décor" (voir auth/update_user_asset_scene_kind.py) : bascule
|
||||
une image DÉJÀ importée entre "Fonds" et "Décors/objets" sans ré-upload
|
||||
— trouvé en diagnostiquant un "décalage" (une image importée par le
|
||||
mauvais bouton, ou avant la séparation fond/décor, restait bloquée dans
|
||||
la mauvaise section). Posé dans .userAssetRowFooter (déjà en
|
||||
position:static, voir ci-dessus), sous la vignette d'une image. */
|
||||
.userAssetTileWrap .userAssetRowFooter{ margin-top:4px; }
|
||||
.userAssetReclassifyBtn{
|
||||
flex:1; font-size:10.5px; padding:2px 4px; border-radius:4px;
|
||||
border:1px solid var(--border); background:var(--panel2); color:var(--text-dim);
|
||||
cursor:pointer; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
|
||||
}
|
||||
.userAssetReclassifyBtn:hover{ background:var(--panel3, var(--panel2)); color:var(--text); }
|
||||
.widgetBtnForm{ margin:0; }
|
||||
.widgetBtn{
|
||||
width:100%; display:flex; flex-direction:column; align-items:center; gap:4px;
|
||||
@@ -956,6 +995,41 @@ body.builderBody > main.content{ flex:1 1 auto; min-height:0; overflow:hidden; d
|
||||
white-space:nowrap; pointer-events:none; z-index:20;
|
||||
}
|
||||
|
||||
/* Bulle de l'action "indication" (voir forgeShowIndicationBubble,
|
||||
collision-rules-controller.js) — même patron que .collisionInteractBubble
|
||||
ci-dessus (sœur de l'objet, position calculée en JS), mais un texte
|
||||
LIBRE (pas juste une touche) qui peut passer à la ligne, et sa propre
|
||||
classe pour ne jamais interférer avec le cycle d'affichage de la bulle
|
||||
"Appuie sur X" (minuterie propre, pas liée à l'état "actif" d'un
|
||||
déclencheur "interagir"). */
|
||||
.collisionIndicationBubble{
|
||||
display:none; position:absolute; transform:translate(-50%, -100%); margin-top:-6px;
|
||||
background:#2a3a5a; color:#fff; border-radius:10px; padding:6px 12px; font-size:13px;
|
||||
max-width:220px; text-align:center; white-space:normal; pointer-events:none; z-index:20;
|
||||
box-shadow:0 2px 8px rgba(0,0,0,.3);
|
||||
}
|
||||
|
||||
/* Overlay de l'action "video" (voir forgeShowVideoOverlay,
|
||||
static/js/play/video-overlay.js) — posé une seule fois sur <body>,
|
||||
réutilisé pour chaque lecture. "plein_ecran" couvre toute la fenêtre de
|
||||
jeu ; "incrustation" reste une petite fenêtre en bas à droite, la scène
|
||||
restant visible autour. */
|
||||
.forgeVideoOverlay{
|
||||
display:none; position:fixed; z-index:1000; align-items:center; justify-content:center;
|
||||
}
|
||||
.forgeVideoOverlay-pleinEcran{
|
||||
inset:0; background:rgba(0,0,0,.92);
|
||||
}
|
||||
.forgeVideoOverlay-incrustation{
|
||||
right:24px; bottom:24px; left:auto; top:auto; width:min(40vw, 480px);
|
||||
}
|
||||
.forgeVideoOverlay .forgeVideoOverlayPlayer{ max-width:100%; max-height:80vh; display:block; }
|
||||
.forgeVideoOverlay-incrustation .forgeVideoOverlayPlayer{ width:100%; max-height:none; border-radius:8px; box-shadow:0 4px 20px rgba(0,0,0,.5); }
|
||||
.forgeVideoOverlay .forgeVideoOverlaySkip{
|
||||
position:absolute; top:12px; right:12px; background:rgba(0,0,0,.6); color:#fff; border:1px solid rgba(255,255,255,.4);
|
||||
border-radius:6px; padding:6px 12px; font-size:13px; cursor:pointer;
|
||||
}
|
||||
|
||||
/* ---- Reliquat de l'ancien onglet "🗺️ Quêtes" (retiré, voir onglet
|
||||
"Déclencheurs" et static/js/triggers/trigger-editor.js) — règles
|
||||
orphelines gardées telles quelles, aucune ne s'applique plus. ---- */
|
||||
@@ -1007,6 +1081,30 @@ body.builderBody > main.content{ flex:1 1 auto; min-height:0; overflow:hidden; d
|
||||
boutons Réplique/Question/Action TOUJOURS tout en bas — ils ajoutent
|
||||
dans le dialogue du déclencheur ACTIF (voir .questTriggerCol.active),
|
||||
jamais dans une liste séparée. */
|
||||
/* Onglet "Déclencheurs" — menu latéral gauche (demande explicite) pour
|
||||
choisir entre les déclencheurs D'OBJET ("🧩 Objets") et D'ÉCRAN ("🖥️
|
||||
Écran", voir screens/rendering/screen_triggers.py), plutôt que les
|
||||
empiler l'un sous l'autre — même patron visuel que .iaCol-left/
|
||||
.iaConversationItem (chat IA) pour rester cohérent avec le reste de
|
||||
l'éditeur.*/
|
||||
.triggersTabLayout{
|
||||
display:flex; width:100%; flex:1 1 auto; min-height:0;
|
||||
border:1px solid var(--border); border-radius:10px; overflow:hidden;
|
||||
}
|
||||
.triggersTabSidebar{
|
||||
flex:0 0 190px; border-right:1px solid var(--border); background:var(--panel2);
|
||||
display:flex; flex-direction:column; gap:4px; padding:10px;
|
||||
}
|
||||
.triggersTabSidebarItem{
|
||||
display:flex; align-items:center; gap:8px; width:100%; padding:10px 12px;
|
||||
border-radius:8px; border:1px solid transparent; background:transparent;
|
||||
color:var(--text-dim); text-align:left; cursor:pointer; font-size:13.5px; font-weight:600;
|
||||
}
|
||||
.triggersTabSidebarItem:hover{ background:var(--panel); }
|
||||
.triggersTabSidebarItem.active{ background:var(--panel); border-color:var(--accent); color:var(--text); }
|
||||
.triggersTabContent{ flex:1 1 auto; min-width:0; min-height:0; display:flex; flex-direction:column; }
|
||||
.triggersTabPane{ flex:1 1 auto; min-height:0; display:flex; flex-direction:column; padding:16px; }
|
||||
.triggersTabPaneIntro{ margin-bottom:10px; }
|
||||
.questDialogueColumns{ flex:1; min-height:0; display:flex; }
|
||||
.questDialogueColumn{
|
||||
width:90%; margin:0 auto; height:100%; min-height:0; display:flex; flex-direction:column; gap:8px;
|
||||
@@ -1068,11 +1166,28 @@ body.builderBody > main.content{ flex:1 1 auto; min-height:0; overflow:hidden; d
|
||||
le losange doit être plus grande"). */
|
||||
.questTriggerConnector.tall{ height:32px; width:3px; }
|
||||
.questTriggerConnector.tall::after{ border-width:7px; }
|
||||
.questTriggerPill{ width:100%; border-radius:100px; padding:8px 14px; font-size:12px; font-weight:700; text-align:center; }
|
||||
.questTriggerPill{ width:100%; border-radius:100px; padding:8px 14px; font-size:12px; font-weight:700; text-align:center; position:relative; }
|
||||
.questTriggerPill.trigger{ background:#f2994a; color:#1a1002; }
|
||||
.questTriggerPill.interagir{ background:#d4a72c; color:#1a1002; }
|
||||
.questTriggerPill.quete{ background:#9b59b6; color:#fff; }
|
||||
.questTriggerPill.none{ background:transparent; border:1.5px dashed var(--border); color:var(--muted, #8b95a7); }
|
||||
/* Contrôles ↑/↓/✕ par bloc étiquette+action (demande explicite : "que
|
||||
chaque bloc étiquette + action soit déplaçable ou supprimable par
|
||||
l'utilisateur et par l'IA aussi") — collés au bord droit de la
|
||||
pastille, discrets tant que la souris n'est pas dessus. */
|
||||
.questTriggerPillControls{
|
||||
position:absolute; right:8px; top:50%; transform:translateY(-50%);
|
||||
display:flex; gap:2px; opacity:.55;
|
||||
}
|
||||
.questTriggerPill:hover .questTriggerPillControls{ opacity:1; }
|
||||
.questTriggerPillCtrlBtn{
|
||||
width:20px; height:20px; border-radius:6px; border:none; background:rgba(0,0,0,.25);
|
||||
color:inherit; font-size:11px; line-height:1; cursor:pointer; display:flex; align-items:center; justify-content:center;
|
||||
}
|
||||
.questTriggerPillCtrlBtn:hover{ background:rgba(0,0,0,.45); }
|
||||
.questTriggerPillCtrlBtn:disabled{ opacity:.3; cursor:default; }
|
||||
.questTriggerPillCtrlBtn:disabled:hover{ background:rgba(0,0,0,.25); }
|
||||
.questTriggerPillCtrlBtn-delete:hover{ background:#e0524d; color:#fff; }
|
||||
|
||||
/* Rectangle "dialogue" — même largeur que le reste de la chaîne (100% de
|
||||
son conteneur, comme les pastilles, maquette validée : "le rectangle
|
||||
@@ -1307,6 +1422,17 @@ body.builderBody > main.content{ flex:1 1 auto; min-height:0; overflow:hidden; d
|
||||
flex-shrink:0; background:none; border:none; color:rgba(255,255,255,.75); cursor:pointer;
|
||||
font-size:11px; padding:0; transition:color .15s ease;
|
||||
}
|
||||
/* Voix off d'une réplique (demande explicite : "ajouter une réplique
|
||||
audio") — un sélecteur discret sous le texte, plus un aperçu <audio>
|
||||
natif SEULEMENT quand une voix off est choisie (voir
|
||||
triggerBubbleAudioControlHtml, static/js/triggers/trigger-editor.js). */
|
||||
.questBubbleAudioRow{ margin-top:6px; display:flex; flex-direction:column; gap:4px; }
|
||||
.questBubbleAudioSelect{
|
||||
font-size:11px; background:rgba(0,0,0,.2); color:#fff; border:1px solid rgba(255,255,255,.25);
|
||||
border-radius:4px; padding:2px 4px; max-width:100%;
|
||||
}
|
||||
.questBubbleAudioSelect option{ color:#111; }
|
||||
.questBubbleAudioPreview{ width:100%; height:28px; }
|
||||
.questBubbleDelete:hover{ color:#fff; }
|
||||
|
||||
.listRow.selected{ border-color:var(--accent); background:var(--panel2); }
|
||||
|
||||
Reference in New Issue
Block a user