Sign in Home
Features
The AI FAQ
Library
Overview Themes Interactive components Workflows Workflow components
Download
Changelog

What changed, straight from the code

This isn't a marketing page: it's the actual CHANGELOG.md shipped inside the downloadable zip, read automatically on every visit — never retyped by hand, so it never drifts out of sync.

Current version : v1.4.0 Download this version

[1.1.2] - 2026-08-13
Ajouté (2026-08-10 — mise à jour automatique depuis slydeforge.com, charte SlydeForge riche, aide F1)
  • Retour utilisateur — « ajouter à l'ouverture un contrôle si c'est bien la dernière version installée et sinon proposer d'installer automatiquement la nouvelle version » : nouveau services/update_service.py::check_site (vérification publique via https://www.slydeforge.com/api/version-check.php, distincte du contrôle GHE interne existant) — si une version plus récente est publiée, une popup au démarrage propose de télécharger et d'installer automatiquement la mise à jour (réutilise le flux d'application depuis un .zip déjà existant : confirmation avec notes de version, progression en direct, proposition de redémarrage).
  • Retour utilisateur — « Les couleurs sont un peu flashy [...] intègre les éléments graphiques ci-joint. Gérer une image de fond moderne et [...] compléter avec 3/4 layouts [...] configurer les icônes + images » : la charte SlydeForge passe d'une simple palette à une charte riche complète (examples/themes/slydeforge.json, chargée comme Prisme) — palette assourdie (moins saturée que les couleurs vives du site), image de fond dégradée générée, 4 types de slides prêts à l'emploi (Couverture, Contenu, Multi-format, Clôture) intégrant les vrais éléments graphiques fournis (logo, icônes des 3 fonctionnalités clés).
  • Retour utilisateur (capture) — « le design [du nouveau projet vierge] fait vraiment basique [...] pas vraiment aligné avec le design moderne du site » : nouveau core/presets.py::sample_deck_from_charte — le deck de démonstration d'un nouveau projet vierge est désormais construit à partir des VRAIS gabarits de la charte SlydeForge (Couverture → Multi-format → Clôture, avec image de fond/icônes/logo) plutôt que d'une structure générique à bandeaux de couleur plate. Cette charte est en outre désormais toujours utilisée pour un nouveau projet vierge, indépendamment de la charte par défaut personnalisable de l'utilisateur.
  • Retour utilisateur — « ajouter la touche F1 pour ouvrir l'aide » : raccourci standard ajouté sur Aide > Guide utilisateur….
  • 4 nouvelles rubriques dans docs/guide-utilisateur.md : lancement du diaporama, mode présentateur (avec lecture vocale automatique), génération de vidéo, éditeur de workflow.
Corrigé (2026-08-10 — suppression de tag indécouvrable)
  • Retour utilisateur (capture) — « Je ne vois pas comment supprimer complètement un tag à partir de la liste de tags » : root cause — les boutons renommer/supprimer d'un tag (ui/tag_dialog.py) utilisaient des glyphes de police Unicode (✎/✕) invisibles sur la machine de l'utilisateur (rendu peu fiable selon les polices installées), rendant la suppression totalement indécouvrable bien que fonctionnelle. Remplacés par de vraies icônes vectorielles (ui/icons.py), même règle déjà appliquée ailleurs dans l'application.
  • Retour utilisateur — « si [un tag est] déjà utilisé il faut demander lister les projets concernés et demander confirmation » : la confirmation de suppression d'un tag liste désormais les projets concernés (nom, jusqu'à 15 affichés) plutôt qu'un simple message générique.
Renommé (2026-08-10 — SlideForge devient SlydeForge)
  • Retour utilisateur — « renommer l'application SlydeForge avec un "y" [...] intégrer le nouveau set d'icônes/logo [...] créer une charte aux couleurs de ce nouveau logo et l'utiliser pour la présentation de base à l'ouverture » : renommage complet du produit à travers tout le code, les tests, la documentation et les scripts de packaging (108 fichiers). Dossier de données utilisateur %APPDATA%\SlydeForge avec migration automatique (une seule fois, best-effort élément par élément si un fichier est verrouillé) depuis l'ancien %APPDATA%\SlideForge — aucune donnée d'un utilisateur existant ne doit disparaître après la mise à jour.
  • Nouvelle icône applicative (assets/icon.svg réel, régénère assets/icon.ico/assets/icon.png via packaging/make_icon.py) et logotype (assets/branding/wordmark.png, affiché sur l'écran de démarrage).
  • Nouveau préréglage de charte « SlydeForge » (core/presets.py::theme_slydeforge) — couleurs extraites directement des tracés du logo (fond marine #141736, dégradé orange #FA6117/#E8421E, violet #6936DE). Devient la charte par défaut sur une installation neuve (jamais sur une installation existante ayant déjà un défaut explicite) — utilisée par la présentation affichée à l'ouverture de l'application.
  • Dossier racine renommé SlideForge → SlydeForge.
Ajouté (2026-08-10 — composants de workflow : dates, structure de génération imposée, connecteurs SharePoint/FTP/SFTP, trace détaillée)
  • Retour utilisateur — « pouvoir récupérer la date du jour, la formater et l'ajouter dans une variable pour l'intégrer dans un nom de fichier de sortie » : nouveau nœud core.current_date — démontré dans l'exemple bundlé (nom de fichier exporté désormais daté).
  • Retour utilisateur — « un composant pour paramétrer les layouts à utiliser par slide pour donner la logique sur la structure à respecter » : nouveau nœud core.layout_plan (sélection de charte + liste de slides layout | type de slide | titre) — son port plan court-circuite la planification automatique par IA de core.ai_generate_deck.
  • Retour utilisateur — « récupérer un fichier source depuis un SharePoint avec les authentifications de l'utilisateur » : nouveau connectors.sharepoint_source (Microsoft Graph, authentification par device code avec mise en cache locale — un seul geste ponctuel requis côté IT : inscription d'une application Azure AD cliente publique).
  • Retour utilisateur — « des composants pour gérer des accès de type FTP, SFTP [...] pour récupérer un fichier mais aussi déposer un fichier » : nouveaux connectors.file_download/connectors.file_upload (FTP/FTPS/SFTP).
  • Retour utilisateur — « rendre le log d'exécution plus verbeux [...] expliquer le traitement en entrée et en sortie » : chaque message de progression émis par une brique pendant son exécution est désormais capitalisé dans la trace de debug (groupe « Étapes » dépliable), pas seulement affiché en direct puis perdu.
  • Bouton ▶ Exécuter et menu contextuel (Supprimer le lien) sur les liens du canevas de workflow.
Ajouté (2026-08-08, retours sur la 5e vague, 9e round — tags d'animation synchronisés à la lecture vocale)
  • Retour utilisateur — « lorsqu'il y a une lecture autonome à partir de notes mais en plus qu'il y a une animation sur les objets d'un slide alors il fait l'animation des éléments de la slide que à la fin. Est-ce qu'il y aurait moyen d'intégrer dans les notes de la slide des tags que la voix ne prendrait pas encore mais que l'animation automatique en fonction de la lecture pourrait utiliser pour gérer l'animation » : nouveau core/notes_tags.py — marqueur [[anim]] insérable dans le texte des notes, jamais lu à voix haute (retiré avant toute synthèse ET avant tout export PPTX). En lecture autonome, ui/present_window.py découpe désormais les notes en segments à chaque tag et les synthétise/joue l'un après l'autre — l'étape d'animation suivante se déclenche exactement entre deux segments, plus seulement en toute fin de narration. Sans tag, comportement de lecture strictement inchangé.
  • Retour utilisateur — « il faudrait que la génération de notes puisse être informée de l'animation existante pour créer ces tags lorsqu'il génère les notes » : services/notes_suggest_service.py::suggest_notes connaît désormais le nombre réel d'étapes d'animation de la slide (ui/present_window.py::slide_step_count, déjà en place pour le lecteur) et insère automatiquement le bon nombre de tags aux endroits naturels — uniquement si la slide est réellement animée, jamais mentionné sinon.
  • Retour utilisateur — « un mode IA pour si une note existante retirer les tags s'ils existent et en proposer d'autres toujours basé sur les éléments de l'animation existante » : nouveau suggest_tags_for_notes — ne réécrit JAMAIS le texte, seulement où replacer les marqueurs par rapport à l'animation ACTUELLE. Nouveau bouton 🏷️ Retaguer (IA) à côté du champ Notes de la slide courante.
  • Retour utilisateur — « il faudrait également un mode pour revoir les tags des animations dans les notes de l'ensemble des slides [...] une assistance pour gérer les tags manuellement pour nous aider à les définir en fonction de la séquence de l'animation » : nouveau ui/tag_review_dialog.py (menu Présentation > Revoir les tags d'animation…) — liste de TOUTES les slides avec un badge (✓/⚠) comparant le nombre de tags posés au nombre réel d'étapes, et pour la slide sélectionnée : la séquence d'animation détaillée (« Étape 1 : Titre (fondu) »…), un éditeur où les tags sont directement visibles/modifiables, un bouton pour en insérer un au curseur, et le même retaguage IA que ci-dessus — combine en un seul endroit la revue globale et l'assistance manuelle demandées.
  • +53 tests (nouveaux fichiers tests/test_notes_tags.py — 16, tests/test_tag_review_dialog.py — 17 ; extension de tests/test_voice_reading.py — 6, tests/test_notes_suggest_service.py — 8, tests/test_slide_notes_ui.py — 4, tests/test_notes_import_export_roundtrip.py — 2).
Ajouté (2026-08-08, retours sur la 5e vague, 11e round — export vidéo de la présentation)
  • Retour utilisateur — « génération de vidéos basées sur les animations, transitions, notes et voix. Il faudra certainement une popup pour valider les paramètres nécessaires [...] et déterminer le dossier de destination (par défaut dossier output de appdata roaming) » : le moteur bas niveau existait déjà (rendu d'image par étape d'animation, ffmpeg) mais n'était relié à rien. Nouveau services/video_export.py::export_video — orchestre rendu d'image, synthèse vocale des notes et assemblage ffmpeg en une vraie vidéo MP4, VÉRIFIÉ de bout en bout avec un ffmpeg réel (vidéo+audio produits, durées correctes). La narration est synchronisée aux tags [[anim]] quand ils sont présents (chaque segment devient un clip audio séparé, l'étape d'animation se déclenche exactement à la frontière — réutilise le même mécanisme que la lecture autonome) ; sans tag, comportement historique déjà testé (un seul audio par slide, réparti également). Limite assumée pour cette 1ère version (même principe d'honnêteté que le lecteur live, cf. familles de transitions) : les transitions entre slides restent des coupes franches dans la vidéo, pas un fondu enchaîné ffmpeg — trop risqué à livrer sans vérification visuelle poussée dans le temps imparti.
  • Nouveau ui/video_export_dialog.py (menu Fichier > Exporter en vidéo…) — popup de paramètres : destination (pré-remplie avec prefs.exports_dir(), le dossier output déjà utilisé pour les exports PPTX/projet), résolution, statut ffmpeg, puis progression en direct (slide en cours) dans la même fenêtre.
  • Retour utilisateur — « s'il manque des librairie python ou autre à installer pour la génération de la vidéo il faudra assister l'utilisateur lambda pour que ça soit simple à faire » : ffmpeg n'est pas un paquet pip (contrairement à Edge/Piper) — nouveau services/video_installer.py, installation guidée en un clic via winget (gestionnaire officiel Windows, déjà présent par défaut) avec progression en direct (ui/video_install_dialog.py, même patron que l'installateur de moteurs de voix). Le binaire fraîchement installé est immédiatement détecté sans redémarrer SlydeForge.
  • +39 tests (nouveaux fichiers tests/test_video_installer.py — 7, tests/test_video_install_dialog.py — 7, tests/test_video_export_dialog.py — 12 ; extension de tests/test_video_export.py — 13).
Corrigé (2026-08-08, retours sur la 5e vague, 12e round — délais d'animation synchronisés, bouton Retaguer grisé sans animation)
  • Retour utilisateur — « les temps de pause de la voix sur les animations sur les objets sont un peu longues, est-ce que tu peux mieux les synchroniser avec le temps prévu de l'animation ? » : le délai entre deux étapes d'animation (lecture autonome ET export vidéo) était un délai FIXE (900 ms), sans rapport avec la durée réellement configurée de l'animation qui vient de se jouer. Nouveau ui/present_window.py::step_duration_ms — utilise désormais le duration_ms réel de l'animation déclenchée à cette étape (le plus long si plusieurs éléments apparaissent ensemble), avec un repli sur l'ancien délai fixe seulement si aucune durée n'est renseignée. Réutilisé aussi par services/video_export.py pour les étapes sans narration propre.
  • Retour utilisateur — « juste au-dessus de la zone de note il y a retaguer IA, mais s'il n'y a pas d'animation sur la slide ça ne sert à rien et le bouton peut être grisé » : le bouton 🏷️ Retaguer (IA) est désormais désactivé (avec une infobulle explicative) tant que la slide sélectionnée n'a aucune étape d'animation, au lieu d'attendre un clic pour l'apprendre.
  • +12 tests (extension de tests/test_present_window.py — 6, tests/test_voice_reading.py — 2, tests/test_video_export.py — 1, tests/test_slide_notes_ui.py — 3).
Corrigé (2026-08-08, retours sur la 5e vague, 8e round — touches Tab et Entrée en mode présentation)
  • Retour utilisateur — « la touche Tab du clavier ne permet pas de passer à la diapositive suivante » puis « ajoute la touche Entrée pour passer à la slide suivante » : root cause (Tab) — Qt intercepte Tab AVANT keyPressEvent pour déplacer le focus clavier entre widgets (comportement par défaut, même avec StrongFocus) ; PresentWindow.focusNextPrevChild refuse désormais explicitement ce déplacement de focus. Tab et Entrée avancent maintenant la diapositive au même titre que →/Espace/PageDown.
  • +3 tests (extension de tests/test_present_window.py).
Corrigé (2026-08-08, retours sur la 5e vague, 7e round — audio d'écoute périmé, installation Piper réellement simple, catalogue français élargi, message d'erreur figé, chrono auto)
  • Retour utilisateur (capture) — « lorsque je change de voix et que je fais écouter, je suis toujours sur l'ancienne voix [...] je dois fermer la popup et la réouvrir » : root cause — le fichier temporaire d'essai avait un nom FIXE par langue (slydeforge_voice_test_fr.mp3), si bien qu'un essai encore en cours pouvait écraser après coup le résultat d'un essai plus récent (et certains lecteurs média ne redétectent pas toujours un contenu changé sous un chemin identique). Chaque tentative écrit désormais dans un fichier au nom UNIQUE.
  • Retour utilisateur (capture) — « je ne peux toujours pas installer simplement piper [...] il faut que ça soit simple comme pour edge neutral » : root cause CONFIRMÉE en reproduisant le problème — pip install piper-tts réussit et rend le paquet Python importable, mais le script piper qu'il déclare n'atterrit pas toujours sur le PATH (installation utilisateur, dossier Scripts absent du PATH…) ; SlydeForge ne cherchait QUE ce script, jugeait donc Piper « non installé » à tort et tentait quand même une synthèse qui échouait avec le message brut d'installation. services/tts.py::_piper_command() retombe désormais sur python -m piper (l'interpréteur courant, où le paquet vient d'être installé) dès que le script n'est pas sur le PATH mais que le module l'est — un simple clic sur Installer… (déjà en place) devient enfin suffisant, à parité avec Edge.
  • Retour utilisateur — « pour les voix française de piper, tu ne trouves pas de voix avec plus haute qualité, même en canadien ou belge [...] merci de compléter la liste et de vraiment proposer les voix les plus haute qualité et appréciées » : catalogue Piper vérifié en DIRECT (index HuggingFace réel) — 7 voix françaises seulement, TOUTES en fr_FR, qualité maximale « medium » (jamais « high »), aucune voix canadienne/belge : une limitation réelle du projet Piper lui-même, pas un choix de SlydeForge, honnêtement non comblée par une invention. Côté Edge (qui, lui, propose vraiment ces variantes), le catalogue est complété avec des voix RÉELLES vérifiées via un appel direct à edge_tts.list_voices() : Canada (Sylvie, Antoine), Belgique (Charline, Gérard), Suisse (Ariane, Fabrice), et les deux nouvelles voix « Multilingual » (génération la plus récente et la plus naturelle d'Edge) — devenues le nouveau choix par défaut en français et en anglais.
  • Retour utilisateur (capture) — « lorsque je change de moteur de voix il conserve le message d'erreur du moteur précédent (ici je suis sur edge et je vois le message pour piper) » : le statut d'écoute (_tts_test_status) n'était vidé nulle part au changement de moteur — désormais réinitialisé dès que le moteur change.
  • Retour utilisateur — « en mode présentateur lorsque je clique sur lecture vocale il ne lance pas automatiquement le chrono » : même filet de sécurité que la toute première avance de slide — activer la lecture vocale démarre désormais le chronomètre s'il ne tournait pas déjà.
  • +11 tests (extension de tests/test_tts.py — 7, tests/test_voice_settings_dialog.py — 2, tests/test_voice_reading.py — 2 ; tests/test_tts_settings.py mis à jour pour la nouvelle valeur par défaut, sans test supplémentaire).
Ajouté (2026-08-08, retours sur la 5e vague, 6e round — suggestion IA de notes sur tout le deck, comparaison et édition avant validation)
  • Retour utilisateur — « je souhaite pouvoir générer des notes + proposition de temps sur l'ensemble les slides et s'il existe déjà des notes il faut pouvoir les comparer et les valider. Il faudrait même pouvoir éditer en live la version que l'on va conserver si on souhaite changer quelques éléments avant validation. » : la suggestion IA de notes (jusqu'ici mono-slide) fonctionne désormais sur une sélection de slides ou le deck entier — nouveau services/notes_suggest_service.py::suggest_notes_for_deck (un appel par slide, une slide sans rien à dire n'interrompt jamais les autres) et nouveau ui/notes_suggest_dialog.py::DeckNotesSuggestDialog : vue maître-détail avec, pour la slide sélectionnée, les notes ACTUELLES affichées en lecture seule au-dessus des notes PROPOSÉES, librement éditables avant validation — le texte réellement appliqué est celui laissé dans le champ au moment de valider, édité ou non. Chaque slide reste cochable/décochable individuellement. Le temps de lecture est estimé automatiquement pour toute slide qui n'en avait pas encore (même règle que la version mono-slide, jamais en écrasant un temps déjà réglé).
  • Accessible via clic droit sur une ou plusieurs slides (« Proposer des notes (IA)… », même portée que « Proposer des transitions (IA)… ») et via le menu Présentation > Proposer des notes pour tout le deck (IA)….
  • +30 tests (nouveaux fichiers tests/test_notes_suggest_ui.py — 11, tests/test_notes_suggest_dialog.py — 14 ; extension de tests/test_notes_suggest_service.py — 5).
Ajouté (2026-08-08, retours sur la 5e vague, 5e round — bibliothèque de voix recherchable par moteur)
  • Retour utilisateur — « comment est-ce qu'il est possible d'ajouter de nouvelle voix facilement ? Possible de proposer une bibliothèque et de rechercher à partir de critère (genre, âge, ...) une voix, la sélectionner et l'installer [...] il faut gérer un moteur de recherche différencié par moteur de voix car chacun va utiliser des bibliothèques (sources différentes) » : nouveau services/voice_library.py, avec une recherche RÉELLE propre à chaque moteur (pas un catalogue statique unique) — Edge interroge son catalogue LIVE de ~500 voix Microsoft (edge_tts.list_voices, filtrable langue/genre, rien à installer : une voix choisie est immédiatement utilisable) ; Piper interroge l'index HuggingFace rhasspy/piper-voices (filtrable par langue, un vrai téléchargement du modèle .onnx+.onnx.json dans le dossier des voix de SlydeForge est nécessaire avant utilisation) ; ElevenLabs interroge la bibliothèque partagée du compte configuré (filtrable langue/genre/âge, nécessite la clé d'API déjà renseignée). Chaque moteur expose les filtres qu'il sait RÉELLEMENT honorer (SUPPORTED_FILTERS) — l'âge, par exemple, n'existe que côté ElevenLabs, les autres filtres restent masqués plutôt que de proposer un choix qui ne ferait jamais rien.
  • Nouveau ui/voice_library_dialog.py (VoiceLibraryDialog) — recherche en arrière-plan (texte libre + filtres pertinents pour le moteur courant), liste de résultats avec statut « ⬇ à installer » le cas échéant, bouton Installer (Piper, avec progression en direct) ou Utiliser cette voix (sélection immédiate), double-clic pour aller plus vite. Ouvert via un nouveau bouton 📚 Bibliothèque… à côté de chaque combo de voix FR/EN dans ui/voice_settings_dialog.py.
  • +40 tests (nouveaux fichiers tests/test_voice_library.py — 24, tests/test_voice_library_dialog.py — 13 ; extension de tests/test_voice_settings_dialog.py — 3).
Ajouté (2026-08-08, retours sur la 5e vague, 4e round — cohérence lecture vocale, barre de progression, bandeau discret)
  • Retour utilisateur — « il faudrait que le bouton lecture/pause du mode présentation soit lié avec le mode audio lorsqu'il est activé pour garder une cohérence » : le bouton ▶/⏸ du chronomètre (console présentateur) pilote désormais AUSSI la narration en cours quand la lecture vocale est active — l'arrêter met en pause l'audio en train de jouer ET le minuteur d'enchaînement (entre étapes d'animation ou avant la slide suivante), en mémorisant le temps restant pour reprendre exactement où on s'était arrêté ; le redémarrer reprend l'audio (ou lance la synthèse restée en attente si elle s'est terminée pendant la pause) et relance le minuteur avec le temps qu'il restait. Changer manuellement de slide efface toujours une pause en cours (on repart en lecture, jamais sur une pause fantôme). ui/audio_player.py gagne pause()/resume()/is_paused() en plus de play_file()/stop()/is_playing().
  • Retour utilisateur — « il faudrait que l'on puisse avancer avec une barre de type slice sur le son » : ui/audio_player.py::AudioPlayer relaie désormais positionChanged/durationChanged (relais par slot Python, QMediaPlayer émettant en qlonglong incompatible avec une connexion signal-à-signal directe vers un Signal(int)) et expose position()/duration()/set_position(). Nouvelle barre de progression (QSlider) dans la console présentateur, connectée à ces signaux — un glisser en cours n'est jamais écrasé par une mise à jour de position entrante, le relâcher cherche dans l'audio via set_position().
  • Retour utilisateur — « je vois que tu indiques en haut de la slide le fait que la lecture automatique vocale est activée [...] il faudrait que ce soit plus fondu et que soit on puisse la fermer manuellement soit que au bout d'un certain temps elle se ferme tout de seule » : le bandeau de statut (ui/present_window.py::_show_voice_status) passe d'un fond plein contrasté à un fond translucide discret, se ferme au clic (curseur en pointeur) et disparaît automatiquement après 4,5s — ce n'est qu'une notification transitoire, jamais un indicateur d'état permanent.
  • +23 tests (extension de tests/test_audio_player.py — 10, tests/test_voice_reading.py — 9, tests/test_presenter_window.py — 4).
Corrigé (2026-08-07, retours sur la 5e vague, 3e round — combo voix, message d'écoute, raison des échecs de lot, langue de narration évolutive)
  • Retour utilisateur (capture) — « je vois que si je change de moteur, j'ai toujours la même voix proposée [...] j'imagine que d'un moteur à l'autre ça ne peut pas être les mêmes » : root cause — un libellé du catalogue de l'ANCIEN moteur (ex. « Français — Denise (femme, neutre et posée) », un libellé Edge) était à tort traité comme une valeur personnalisée tapée par l'utilisateur et réapparaissait tel quel une fois basculé sur un AUTRE moteur, faute de distinguer fiablement une vraie saisie libre d'un simple libellé de catalogue hérité (QComboBox.currentData() reste périmé après setEditText(), comportement Qt vérifié empiriquement — nouveau _is_free_typed, basé sur la comparaison texte affiché ↔ libellé de l'item courant, seul signal fiable). Bug plus profond trouvé au passage : le même problème faisait qu'une voix personnalisée TAPÉE À LA MAIN pouvait être silencieusement remplacée par la donnée périmée d'un item déjà sélectionné avant la frappe — corrigé de la même façon.
  • Retour utilisateur (capture) — « je vois encore ce type de message [...] lorsqu'un moteur de voix n'est pas encore installé [...] il faut pas afficher ce message (sauf si on tente la lecture) mais surtout afficher le bouton pour permettre l'installation » : cliquer « Écouter » sur un moteur non installé tentait la synthèse et affichait le texte BRUT et multi-paragraphe de l'erreur d'installation comme si c'était un crash (« Erreur inattendue : ... »). Vérifie désormais la disponibilité du moteur AVANT de tenter quoi que ce soit, et renvoie vers le bouton Installer… déjà présent plutôt que de dupliquer/aggraver le même message.
  • Retour utilisateur (2e signalement) — « pour la transition IA sur l'ensemble des slides j'ai maintenant une erreur, mais je ne comprends pas vraiment pourquoi [...] Même en relançant c'est pareil » : l'exception réelle était totalement avalée (except Exception: return None), impossible à diagnostiquer. Elle est désormais journalisée ET propagée jusqu'au message affiché à l'utilisateur (« Raison : ... »). Taille de lot réduite par prudence (8 → 5 slides par appel) pour limiter le risque de heurter une limite d'images/taille de requête propre à certains backends, en plus du budget de tokens déjà adapté.
  • Retour utilisateur — « comment est géré depuis le mode présentation le choix de la langue entre le français et l'anglais ? [...] il faudra pouvoir ajouter d'autres langues dans le futur [...] Le système doit être évolutif » : root cause de la question — deck["language"] (champ de schéma) n'était écrit NULLE PART dans l'application, donc toujours "fr" par défaut même pour un deck en anglais, sans le moindre moyen de le changer. Nouveau core/languages.py, registre UNIQUE (fr/en par défaut) dont dérivent désormais le stockage de voix (services/tts_settings.py, une clé voice_<code> générée par langue du registre, plus de binaire "fr" / "tout le reste") et un vrai sélecteur de langue dans la console présentateur, modifiable à chaud pendant la présentation. Ajouter une langue (italien, espagnol, allemand…) est désormais une seule ligne à ajouter au registre.
  • +34 tests (nouveau fichier tests/test_languages.py — 9 ; extension de tests/test_voice_settings_dialog.py — 10, tests/test_voice_reading.py — 8, tests/test_tts_settings.py — 3, tests/test_animation_suggest_service.py — 2, tests/test_animation_suggest_ui.py — 2).
Corrigé (2026-08-07, retours sur la 5e vague, 2e round — fenêtre Voix séparée, installateur guidé, transitions IA sur tout le deck, transitions visuellement distinctes)
  • Retour utilisateur — « peux-tu mettre la configuration de la voix dans une autre fenêtre que les autres éléments liés à l'IA ? » : la page Voix a quitté Paramètres > IA… pour un dialogue dédié (ui/voice_settings_dialog.py, nouvelle entrée Paramètres > Voix…) — ui/settings_dialog.py ne contient plus rien de lié à la voix.
  • Retour utilisateur — « si les moteurs de voix ne sont pas installés [...] c'est trop technique pour un utilisateur lambda, il faut lui demander confirmation et ouvrir une fenêtre qui va faire l'installation pour lui où il peut suivre l'avancement » : nouveau services/tts_installer.py (pip install du paquet du moteur, via l'interpréteur courant) + ui/tts_install_dialog.py — un bouton Installer… apparaît dès qu'un moteur installable (Edge/Piper) est sélectionné mais absent du poste ; confirmation demandée, puis fenêtre avec le journal d'installation affiché EN DIRECT (ligne de sortie pip par ligne de sortie), jamais une commande à copier-coller. ElevenLabs (clé d'API, pas un paquet) n'a pas de bouton d'installation — rien à automatiser.
  • Retour utilisateur (capture) — « bizarre les propositions de transitions de slides par IA ne m'a été proposé que sur les dernières slides. Pourquoi pas sur tout ? » : sur un deck de 15 slides découpé en 2 lots (8+7), le 1er lot avait échoué SANS que rien ne le signale — ses slides disparaissaient silencieusement du résultat. Un lot en échec est désormais RETENTÉ une fois avant abandon (un aléa isolé, ex. latence de démarrage du 1er appel réseau de la session, ne doit plus condamner tout un lot), et toute slide dont le lot échoue malgré tout est explicitement nommée dans un message dédié (« Analyse impossible pour N slide(s) : … ») plutôt que de disparaître sans explication.
  • Retour utilisateur — « lorsque je suis en mode présentation, j'ai l'impression que les transitions sont toujours identiques alors qu'elles sont paramétrées avec des valeurs différentes » : root cause — le lecteur live (ui/present_window.py::_animate_transition) ignorait totalement kind, toujours un simple fondu d'opacité quelle que soit la transition choisie parmi les 21 du catalogue. Chaque transition est désormais catégorisée dans l'une de 4 familles visuellement distinctes (core/animation_catalog.py::transition_family : none/cut = passage sec, fade/dissolve = fondu d'opacité inchangé, push/cover/pull/wipe/blinds/comb/strips/random_bar/split/checker = glissement horizontal, wedge/wheel/circle/diamond/plus/newsflash/zoom = zoom depuis le centre) — pas un rendu géométrique pixel-parfait par transition (hors de portée raisonnable pour l'aperçu écran ; l'export PPTX, lui, reste fidèle à chaque transition individuellement), mais la famille choisie se voit désormais vraiment.
  • +71 tests (nouveaux fichiers tests/test_voice_settings_dialog.py — 22, tests/test_tts_installer.py — 10, tests/test_tts_install_dialog.py — 7, tests/test_present_window_transitions.py — 16 ; extension de tests/test_animation_suggest_service.py — 4, tests/test_animation_suggest_ui.py — 5, tests/test_animation_catalog.py — 7).
Corrigé (2026-08-07, retours sur la 5e vague — console présentateur, notes IA, transitions IA sur tout le deck)
  • Retour utilisateur (captures) — « je vois bien le bouton pour lire la voix mais je ne vois pas le menu de paramétrage qui est mentionné » : root cause probable — le dialogue Paramètres (Backend + Images + Dictée + désormais Voix) dépasse facilement la hauteur de l'écran, sans le moindre moyen d'atteindre le bas (QVBoxLayout posé directement sur le QDialog, jamais défilable). Tout le contenu est maintenant dans un QScrollArea (boutons Enregistrer/Annuler restant, eux, toujours visibles hors du scroll). Nouvelle entrée de menu dédiée Paramètres > Voix…, qui ouvre ce même dialogue en faisant défiler directement jusqu'à cette section.
  • Retour utilisateur — « en mode présentateur si je clique sur le premier slide il faut démarrer automatiquement le chrono si j'ai oublié de le faire » : la toute première avance depuis le tout début de la présentation (clic, flèche, Espace, bouton Suivant) démarre l'horloge si elle ne tourne pas encore déjà — un oubli reste rattrapable, un démarrage manuel explicite au préalable reste respecté.
  • Retour utilisateur — « en mode présentateur lorsque je clique dans le slide alors l'outil de conception de SlydeForge passe au-dessus de la fenêtre de management pour le présentateur. C'est vraiment gênant. » : root cause — sous Windows, un top-level Qt « possédé » (parent Qt + Qt.Window) fait remonter son PROPRIÉTAIRE juste derrière lui à chaque activation (ex. un clic) ; le diaporama était possédé par la fenêtre principale (« l'outil de conception »), qui remontait donc au-dessus de la console présentateur (elle-même hors de cette chaîne de propriété). Le diaporama est désormais un top-level INDÉPENDANT (sans parent Qt) — sa fermeture à la sortie de SlydeForge est gérée explicitement puisqu'elle ne peut plus compter sur la suppression en cascade d'un parent.
  • Retour utilisateur — « si je suis en mode présentateur, que j'ai plusieurs écrans et que je sélectionne l'écran où se trouve la fenêtre de gestion de la présentation alors il faut mettre la fenêtre de gestion sur un autre écran [...] (sinon elle est cachée) » : choisir un écran de diffusion qui recouvrirait la console la relocalise désormais automatiquement sur un autre écran disponible — jamais cachée derrière le diaporama plein écran.
  • Retour utilisateur — « lorsque l'IA génère un texte de note pour une slide, il faudrait également qu'elle propose un temps de lecture si aucun temps n'est renseigné » : nouveau core/timing.py::estimate_reading_seconds (rythme oral ~130 mots/minute, même repère que le message « ~X min à l'oral » déjà affiché) — renseigné automatiquement UNIQUEMENT si la slide n'a encore aucun temps prévu, jamais en écrasant un réglage manuel existant.
  • Retour utilisateur — « j'ai voulu faire une analyse de transition IA sur l'ensemble des slides [15] et j'ai eu une erreur [...] Aucune transition n'a pu être proposée » : root cause — tout le deck partait en UN SEUL appel (15 images + 1 de contexte), avec un budget de tokens fixe (1200) bien trop court pour une réponse à 15 entrées JSON ; la réponse tronquée faisait échouer le parsing, et l'appel unique retombait entièrement à vide. propose_deck_transitions découpe désormais les gros lots (> 8 slides) en plusieurs appels bornés, chacun avec un budget de tokens proportionné à sa taille et sa propre image de contexte (la VRAIE slide de deck précédente, pour garder une continuité de style) — l'échec d'un lot n'efface plus plus les propositions déjà obtenues pour les autres.
  • +59 tests (nouveau fichier tests/test_presenter_bugfixes_2.py ; extension de tests/test_slide_notes_ui.py, tests/test_timing.py, tests/test_animation_suggest_service.py, tests/test_settings_dialog_voix.py).
Ajouté (2026-08-07, 5e vague — sélecteur d'écran multi-moniteur, Paramètres > Voix, lecture vocale automatique)
  • Retour utilisateur (poste à 3 écrans) — « il faut pouvoir sélectionner facilement l'écran sur lequel on souhaite diffuser la présentation [...] passer de l'un à l'autre facilement et que la diffusion s'adapte à la taille de l'écran automatiquement » : sélecteur d'écran fonctionnant pour N écrans (pas seulement une bascule entre 2) — combo « Écran de diffusion » dans la console présentateur (mis à jour à chaque navigation, un vidéoprojecteur peut être branché/débranché en cours de séance) et raccourci S côté diaporama (overlay listant tous les écrans détectés, avec leur résolution). Réutilise _move_window_to_screen (déjà corrigé pour le DPI) et redessine immédiatement la diapositive à la résolution du nouvel écran.
  • Retour utilisateur — « je ne vois pas le menu pour paramétrer les voix et je ne comprends pas comment on peut l'utiliser sur les slides. Je rappelle que pour les voix je souhaite un exemple en français + anglais de très haute qualité (niveau pro) » : services/tts.py existait déjà (Edge/Piper/ElevenLabs) mais sans AUCUNE interface pour le configurer — nouvelle page Voix dans Paramètres (moteur, voix FR/EN avec le catalogue Edge Neural par défaut — Denise/Henri en français, Aria/Guy en anglais —, vitesse, volume, clé ElevenLabs, avertissement de confidentialité pour les moteurs en ligne, bouton « 🔊 Écouter » par langue). Nouveau services/tts_settings.py (config persistée par utilisateur) et ui/audio_player.py (lecture audio partagée, wrapper QMediaPlayer/QAudioOutput). Usage sur les slides : bouton « 🔊 Lecture vocale » de la console présentateur, ou touche V pendant le diaporama — chaque diapositive est alors narrée depuis son champ Notes, puis ses étapes d'animation s'enchaînent automatiquement (rythme fixe) avant de passer à la suivante ; toute navigation manuelle relance la narration sur la nouvelle diapositive ; la fin du deck arrête proprement la lecture.
  • Bug réel corrigé en écrivant la page Voix : le combo de voix (éditable, pour permettre une valeur personnalisée) renvoyait le LIBELLÉ affiché (« Français — Henri (homme, chaleureux) ») au lieu de l'identifiant réel de la voix (fr-FR-HenriNeural) dès qu'une entrée du catalogue était sélectionnée via la liste déroulante — la synthèse aurait reçu un nom de voix inutilisable. currentData() est désormais utilisé en priorité, avec repli sur currentText() uniquement pour une valeur tapée à la main.
  • +76 tests (nouveaux fichiers tests/test_screen_picker.py, tests/test_tts_settings.py, tests/test_audio_player.py, tests/test_settings_dialog_voix.py, tests/test_voice_reading.py).
Corrigé (2026-08-07, retours sur la 4e vague — sélecteurs numériques, écrans, laser, chronomètre)
  • Retour utilisateur (captures) — « problème sur le sélectionneur de temps prévu sur une slide, idem sur les durées de transitions et animations » : les flèches +/- de ces champs étaient illisibles. Root cause : ils utilisaient un QSpinBox BRUT alors que ui/spin_widgets.py::IntSpinBox existe précisément pour ce bug (déjà signalé auparavant par capture — Fusion peint tout le contrôle en un bloc natif sans point d'interception QSS pour les flèches). Les 4 champs concernés (temps prévu d'une slide, durée de transition, durée d'animation dans les 2 dialogues, durée dans le panneau de propriétés) utilisent désormais IntSpinBox, plus un test garde-fou qui échoue si un QSpinBox brut est réintroduit ailleurs dans ui/.
  • Retour utilisateur — « le mode présentateur, l'écran avec la présentation ne respecte pas bien la taille de l'écran ça déborde sur un autre écran » : setGeometry(screen.geometry()) suivi de showFullScreen() ne suffit pas dès que les écrans n'ont pas le même facteur d'échelle (DPI) — la géométrie était posée dans l'échelle de l'écran d'origine puis réinterprétée sur la destination. La fenêtre est désormais rattachée à l'écran cible au niveau de sa QWindow native (setScreen) après être sortie du plein écran, avant d'y être remise.
  • Retour utilisateur — « le laser ne suit pas la souris » : mouseMoveEvent n'était jamais appelé — la diapositive est peinte dans un QLabel enfant qui couvre toute la fenêtre, et Qt ne délivre les déplacements sans bouton enfoncé qu'au widget survolé (qui n'avait pas le suivi de souris), sans jamais remonter au parent. Remplacé par un suivi par minuteur sur la position GLOBALE du curseur : indépendant du widget survolé, et insensible à l'ajout d'autres calques (notes, aide, grille).
  • Retour utilisateur — « le chrono se lance tout de suite il faudrait un bouton de démarrage » : boutons ▶ Démarrer / ⏸ Pause et ↺ Remise à zéro dans la console. Le chronomètre de la console et l'alerte de dépassement de l'écran public suivent désormais la MÊME horloge (source unique côté diaporama) — sans quoi ouvrir la console dix minutes avant de parler affichait une alerte de dépassement au public dès la première diapositive.
  • +20 tests (tests/test_presenter_bugfixes.py).
Ajouté / Corrigé (2026-08-07, 4e vague — catalogue d'animations enrichi, mode présentateur, minutage, retours d'assistant)
  • Retour utilisateur — « il n'existe que 2 types de transitions entre les slides, est-ce qu'il serait possible d'en proposer d'autres ? Idem est-ce que l'on peut proposer plus d'effet / animation sur un objet ? Il faut que l'IA ait accès à tout ce qui est possible » : nouveau core/animation_catalog.py, source unique des transitions et effets — 21 transitions (contre 3) et 19 effets d'entrée (contre 5), tous vérifiés comme exportables en OOXML de base ECMA-376 (aucun risque de fichier « à réparer »). Le schéma JSON, les combos de l'UI, l'export PPTX, le mode présentation et les prompts IA en dérivent désormais tous : ajouter un effet au catalogue suffit à le rendre proposable par l'IA, sans retoucher un seul prompt (c'est précisément la dérive entre ces 5 copies qui faisait que l'IA ne « voyait » que 2 transitions).
  • Retour utilisateur — « la proposition de transition entre les slides ne fonctionne pas [...] je fais l'action depuis la slide 7 et il me dit que c'est sur le slide 1 : Analyse des transitions possibles pour 1 slide(s)… / Aucune transition n'a pu être proposée » : deux causes distinctes corrigées. (1) Le libellé donnait un COMPTE (« pour 1 slide(s) »), lu comme un NUMÉRO — les slides concernées sont désormais nommées (« pour la slide 7 »). (2) Sur une seule slide, l'IA n'avait aucun contexte — or une transition décrit l'ENTRÉE sur la slide, donc l'enchaînement depuis la précédente : sans la voir, le modèle répondait « none », systématiquement filtré ensuite. La slide précédente est maintenant jointe comme image de contexte, et toute slide ciblée sans proposition exploitable retombe sur un fondu (décochable) plutôt que de disparaître silencieusement. Un échec RÉSEAU, lui, continue de ne rien inventer.
  • Retour utilisateur — « comment est-ce que je peux visualiser mes notes qd je suis en mode diaporama ? [...] Powerpoint affiche sur un autre écran ce type d'information [...] il faut pouvoir décider au lancement [...] et basculer d'un mode à l'autre facilement même en cours de diffusion » : nouveau ui/presenter_window.py::PresenterWindow — console du présentateur avec diapositive courante, diapositive suivante, notes, minuteur, position dans le deck, boutons de navigation et rappel permanent des raccourcis. Envoyée sur le 2e écran quand il y en a un (le diaporama part alors sur l'autre), proposée au lancement, et basculable à chaud par P. Les fonctions existantes mais invisibles (laser, grille, notes) sont désormais listées dans une aide à l'écran (H).
  • Retour utilisateur — « j'aimerais que l'on puisse définir par slide un temps limite et que si l'on dépasse [...] une alerte apparait discrètement [...] et passe en rouge si on dépasse [...] voir le décompte global et celui définit sur la slide courante » : nouveau core/timing.py (règle du temps global implémentée telle que formulée : somme des slides si TOUTES en ont un, sinon le total manuel, sinon aucun total), champ « Temps prévu » par slide à côté des notes, pastille d'alerte discrète en haut à droite de l'écran public (orange à l'approche, rouge et compte négatif en dépassement), et double décompte (global + slide courante) dans la console du présentateur. Nouveau services/timing_suggest_service.py pour challenger l'IA sur les temps : sans temps global elle estime librement chaque slide ; avec un temps global imposé elle ne donne que des POIDS relatifs et la répartition exacte est faite arithmétiquement (la somme retombe à la seconde près).
  • Retour utilisateur — « lorsque l'on utilise l'IA pour générer des notes il n'y a pas d'explication dans l'assistant SlydeForge sur ce qu'il se passe » : message explicite avant l'appel (nommant la slide) et après (nombre de mots, durée approximative à l'oral, et où le texte a été inséré).
  • Retour utilisateur — « lorsqu'il y a un nouvel évènement dans l'assistant [...] et que l'utilisateur n'a pas fait bougé manuellement la scrollbar récemment [...] alors il faut toujours montrer le dernier message » : défilement automatique vers le dernier message, suspendu uniquement si l'utilisateur vient de faire glisser l'ascenseur à la main (15 s de grâce) sans être revenu en bas, ou s'il a une sélection de texte en cours.
  • Retour utilisateur — « dans la popup de gestion des animations [...] il est difficile d'identifier l'élément [...] indiquer sur la slide le numéro de référence pour faire le lien visuel » : pastilles rondes numérotées posées sur les éléments animés du canevas pendant toute l'ouverture du dialogue, portant le même numéro que la ligne correspondante — et renumérotées en direct à chaque Monter/Descendre/Supprimer.
  • Retour utilisateur — « j'aurais aimé que lorsque je clique sur un objet voir le paramétrage de son animation dans la propriété de cet objet » : nouveau groupe « Animation » dans le panneau de propriétés (effet, déclencheur, durée + rappel du rang dans la séquence). L'ordre relatif (order) y est préservé et non réécrit, puisqu'il se règle au niveau de la slide entière.
  • Retour utilisateur — « pourquoi les notes ne sont pas ouvertes par défaut lorsque l'on ouvre l'application ? » : panneau Notes déplié d'emblée.
  • Bug préexistant trouvé en passant : un PowerPoint sans diapositive exploitable affichait « Import impossible : Deck non conforme au schéma : slides : [] should be non-empty » — la validation de schéma passait AVANT le test « aucune diapositive » dont le message clair était pourtant déjà écrit. Ordre corrigé. Ce chemin ouvrait un dialogue modal non neutralisé qui bloquait indéfiniment la suite de tests complète (jamais menée à terme jusqu'ici).
  • Retour utilisateur — « intégrer un système de lecture des notes automatique [...] charger des fichiers voix en indiquant la langue + infos techniques (vitesse, volume) [...] une voix de haute qualité et pro [...] un connecteur compatible avec elevenlabs.io [...] gestion des problèmes de phonétique, intonation [...] avec le moins d'effet robot possible » : nouveau services/tts.py, couche de synthèse vocale ENFICHABLE à trois moteurs — Edge Neural (voix neuronales gratuites, sans clé, fr-FR Denise/Henri et en-US Aria/Guy), Piper (neuronal 100 % LOCAL, pour les notes confidentielles) et un connecteur ElevenLabs (clé d'API). Toute dépendance est importée paresseusement : SlydeForge démarre et fonctionne normalement sans qu'aucun moteur ne soit installé, et chaque absence produit un message disant précisément quoi installer. Un avertissement de confidentialité (volontairement générique, ne nommant aucune organisation) précède l'usage d'un moteur en ligne et oriente vers l'alternative locale. Traitement phonétique : lexique de prononciation respectant les limites de mots et la casse (« ROI » l'indicateur est corrigé, « roi » le monarque ne l'est pas) et respirations ajoutées pour casser le débit plat des listes à puces.
  • Retour utilisateur — « être capable d'extraire la présentation dans un format vidéo où l'ensemble pourra être animé et lu (texte des notes) en automatique » : nouveau services/video_export.py — chaque ÉTAPE d'animation est rendue en image via exactement la même logique que le mode présentation (la vidéo montre ce que le public verrait, jamais un rendu parallèle qui pourrait diverger), la durée de chaque diapositive est le plus long entre son audio et son temps prévu (une phrase n'est jamais coupée), les diapositives masquées sont exclues. ffmpeg est DÉTECTÉ, jamais téléchargé automatiquement : son absence affiche la commande d'installation pour Windows/macOS/Linux.
  • Nouvelle documentation docs/VOIX.md : choix du moteur, avertissement de confidentialité, installation, où trouver des voix libres et gratuites (bibliothèque Piper, Common Voice, Coqui), où déposer les modèles, réglages vitesse/volume, conseils de prononciation et d'intonation, et installation de ffmpeg pour l'export vidéo.
  • +150 tests (nouveaux fichiers tests/test_animation_catalog.py, tests/test_chat_autoscroll.py, tests/test_properties_panel_animation.py, tests/test_canvas_animation_badges.py, tests/test_presenter_window.py, tests/test_timing.py, tests/test_timing_suggest_service.py, tests/test_slide_duration_ui.py, tests/test_tts.py, tests/test_video_export.py ; extension de tests/test_transitions_animations.py, tests/test_animation_suggest_service.py, tests/test_element_animations_dialog.py, tests/test_slide_notes_ui.py). Suite complète vérifiée verte (2047 tests, en deux moitiés — cf. note sur le crash natif d'infrastructure ci-dessous).
Corrigé (2026-08-07, 3e vague — retours après la 2e vague : chargement, IA notes, gestion manuelle des animations, badges, menu contextuel, slash)
  • Retour utilisateur — « je ne vois pas la barre de chargement à l'ouverture d'un projet » : root cause — un seul processEvents() juste après show() ne garantissait pas toujours que Windows ait eu le temps de composer/peindre la fenêtre avant que le chargement synchrone bloquant ne reprenne la main, et pour un projet qui se charge très vite l'overlay pouvait de toute façon apparaître puis disparaître en quelques millisecondes, trop rapide pour être perçu. ui/loading_overlay.py::LoadingOverlay : plusieurs passages de processEvents() + raise_()/activateWindow() + reste au-dessus de la fenêtre parente (WindowStaysOnTopHint), et une durée d'affichage MINIMALE (400ms, attente via une boucle d'évènements locale — jamais time.sleep(), qui gèlerait aussi le spinner). Même overlay réutilisé pour répondre à « lorsque je change de charte et qu'il y a beaucoup de slides ça met un temps de chargement, afficher une barre de progression » (_on_chat_theme_changed/_reapply_theme).
  • Retour utilisateur — « lorsque l'on fait suggérer IA pour les notes, il faudrait montrer que c'est en cours de traitement » : le bouton « ✨ Suggérer (IA) » se désactive et l'indicateur d'occupation du chat s'active pendant l'appel, se réactive à la fin (succès comme erreur).
  • Retour utilisateur — « comment gérer manuellement l'animation de plusieurs objets en une seule fois ? Comment modifier ou supprimer des animations sur des objets. Ça serait bien de pouvoir lister l'ensemble des animations des objets sur une slide. Ça permettrait de définir également l'ordre des animations sur chaque objet » : nouveau ui/element_animations_dialog.py::SlideAnimationsDialog (menu contextuel vignette > « Gérer les animations… ») — liste tabulaire de tous les éléments animés d'une slide (effet/déclencheur/durée modifiables), boutons Monter/Descendre/Supprimer. Nouveau champ element.animation.order (deck.schema.json) déterminant l'ordre de déclenchement "au clic", délibérément INDÉPENDANT de l'ordre des éléments dans le tableau (jamais mélangé avec le z-order) — repli sur la position dans le tableau si absent (comportement historique inchangé). Pris en compte à l'export PPTX (render/pptx_renderer.py) et dans le mode présentation (ui/present_window.py).
  • Retour utilisateur — « j'aimerais voir une icône sur les slides où il y a des animations et une autre icône lorsqu'il existe une transition entre 2 slides » : badges ronds superposés au coin haut-droit des vignettes de la bande (ui/slide_strip.py::_with_status_badges), et rappel dans l'info-bulle de la vignette.
  • Retour utilisateur — « réorganiser les fonctions disponibles depuis le menu contextuel d'une preview de slide afin de permettre une meilleure lecture et compréhension. Je pense qu'ajouter des icônes permettrait de faciliter la compréhension » : _build_context_menu regroupé en 5 blocs logiques (structure / édition / IA contenu-design / animations-transitions / visibilité-suppression), une icône par entrée (ui/icons.py : insert_slide, rename, ai_sparkle, transition, animations_list, eye, réutilisation de duplicate/delete).
  • Retour utilisateur — « lorsque je saisis "/" [...] je voudrais que ça soit sous forme d'un "like" [...] "/layout" [...] mais aussi "/no_layout" [...] "/slide" me permet d'avoir "/review_slide" » : ui/chat_panel.py — l'autocomplétion de 1er niveau filtre désormais par SOUS-CHAÎNE (n'importe où dans le nom de la commande) plutôt que par préfixe strict.
  • Retour utilisateur — « lorsque je fais "/image" je ne vois pas bien la suggestion de la liste des fonctions » (popup tronquée, barre de défilement horizontale) : ui/slash_command_popup.py calcule désormais sa largeur d'après le texte le plus long à afficher (bornée entre 280 et 560px), défilement horizontal désactivé.
  • +49 tests (nouveaux fichiers tests/test_element_animations_dialog.py, tests/test_manage_slide_animations.py, tests/test_slide_strip_badges_and_menu_icons.py, tests/test_slash_command_like_matching.py ; extension de tests/test_project_loading_overlay.py, tests/test_slide_notes_ui.py, tests/test_transitions_animations.py, tests/test_present_window.py).
Ajouté (2026-08-07, 2e vague — IA d'animation, audio, chargement, notes, panneaux repliables, mode présentation)
  • Retour utilisateur — « un outil IA qui permet de proposer de les créer automatiquement pour nous sur une slide pour l'animer [...] afficher des éléments en suivant une séquence, faire des effets sur des éléments pour les rendre plus vivant et interactifs [...] ou encore pour la transition d'une slide vers une autre [...] une analyse de l'ensemble des slides pour proposer une animation sur l'ensemble ou une sélection de slides [...] trouver un moyen visuel de proposer les différentes animations et que l'utilisateur puisse les valider avant de les appliquer » : nouveau services/animation_suggest_service.py — UN appel vision propose une séquence d'animations d'entrée par élément (déclencheurs variés : au clic / avec le précédent / après le précédent, jamais tout au clic par défaut) + une transition pour la slide (/suggest_animation, menu contextuel « Animer la slide (IA)… ») ; un second appel analyse une sélection de slides (ou tout le deck, nouveau menu « Présentation ») et propose une transition cohérente par slide (« Proposer des transitions (IA)… »). Présenté dans une liste À COCHER (ui/animation_suggest_dialog.py, tout coché par défaut, décochable ligne par ligne) — appliqué mécaniquement (jamais via patch IA, ce ne sont que des propriétés structurées transition/animation déjà en place).
  • Retour utilisateur — « on a l'insertion d'une vidéo, mais il faudrait également gérer un objet de type audio. Est-ce que le même objet peut gérer les 2 ? » : oui — nouveau champ kind ("video"/"audio") sur le type d'élément video existant, aperçu canevas distinct (carte haut-parleur + forme d'onde pour l'audio), menu Insérer > « Audio… ». L'export PPTX des deux passe par le même mécanisme (add_movie, python-pptx n'ayant aucun support natif de l'audio) — limitation de la librairie assumée et signalée à l'utilisateur, pas un choix d'architecture SlydeForge.
  • Retour utilisateur — « lorsque l'on ouvre un projet il faudrait une barre de chargement » : nouveau ui/loading_overlay.py::LoadingOverlay (spinner réutilisé du splash de démarrage), affiché pendant le chargement synchrone d'un projet existant.
  • Retour utilisateur — « il n'y a pas de zone pour pouvoir commenter les slides. Et il faudrait que l'IA propose également le texte que l'on pourrait dire sur une slide lors d'une présentation » : nouvelle zone Notes repliable sous le canevas, liée à deck.schema.json::slide.notes (déjà exportée en PPTX, désormais aussi RELUE à l'import — gap comblé au passage) + bouton « ✨ Suggérer (IA) » (services/notes_suggest_service.py, UN appel vision, texte au style oral inséré dans le champ, jamais appliqué sans relecture).
  • Retour utilisateur — « lorsque l'on replie complètement les volets avec l'assistant, les previews ou encore les propriétés il faudrait mettre une icône pour pouvoir les redéplier facilement. Et il faudrait également quand ils sont dépliés montrer par une icône dans la zone de redimensionnement que l'on peut élargir ou diminuer la zone avec la souris » : nouveau ui/collapsible_splitter.py — bouton chevron cliquable sur la poignée dès qu'un panneau (chat/vignettes/propriétés — jamais le canevas) est replié à 0, grip pointillés quand les deux côtés sont visibles.
  • Retour utilisateur — « un player pour pouvoir visualiser / diffuser une présentation en plein écran [...] afin de pouvoir faire une vraie présentation directement depuis SlydeForge [...] mais aussi pouvoir tester et valider les animations, effets de transitions [...] voir les commentaires, avoir un laser de présentation, naviguer entre les slides + les flèches [...] ou aller plus rapidement vers une slide » : nouveau ui/present_window.py::PresentWindow (menu Présentation > « Lancer le diaporama », F5) — navigation clavier complète (flèches/espace/PageUp/PageDown/Home/Fin), notes en surimpression (N), grille de vignettes pour sauter directement à une slide (G), pointeur laser (L). Transitions entre slides et animations d'entrée par élément RÉELLEMENT rejouées (fondu entre images pré-rendues — un élément pas encore déclenché a son opacité forcée à 0 pour ce rendu, réutilise la propriété opacité déjà en place). MVP mono-écran assumé : pas de fenêtre présentateur séparée sur un 2e moniteur.
  • +100 tests dans 9 nouveaux fichiers (tests/test_animation_suggest_service.py, tests/test_animation_suggest_dialogs.py, tests/test_animation_suggest_ui.py, tests/test_project_loading_overlay.py, tests/test_notes_import_export_roundtrip.py, tests/test_notes_suggest_service.py, tests/test_slide_notes_ui.py, tests/test_collapsible_splitter.py, tests/test_present_window.py) + extension de tests/test_insert_elements.py, tests/test_insert_video_ui.py, tests/test_insert_menu_icons_and_order.py.
Ajouté (2026-08-07, 9 évolutions — bibliothèque dans le chat, revue de slide IA, formes modernes, transitions/animations, vidéo, opacité, i18n)
  • Retour utilisateur — « pouvoir depuis les fonctions "/" appeler une icone ou image de la bibliothèque afin de demander de l'utiliser lors des échanges avec l'IA » : nouvelle commande /image du chat — ouvre le même sélecteur de bibliothèque que Insérer > Image… (images/icônes de charte + bibliothèque du projet), joint l'image choisie au PROCHAIN message envoyé à l'IA (multimodal, même mécanisme que les fichiers déjà joints), avec son nom rappelé dans le prompt. Affichée dans la MÊME liste de pièces jointes que les fichiers (icône dédiée, retrait individuel).
  • Retour utilisateur — « une fonction [...] sur la revue d'une slide pour challenger les couleurs, positions, taille des objets, police, taille de la police [...] et que l'IA propose une version plus élégante et plus pro de la slide courante », complété ensuite par « il faudrait aller un peu plus loin [...] gérer les icônes, utilisations de formes [...] maintenant qu'il y a un module pour la gestion des transitions et des effets » : nouvelle commande /review_slide + entrée « Revue de la slide (IA)… » dans le menu contextuel des vignettes (groupée avec « Suggérer des mises en forme… »). UN appel vision (services/slide_review_service.py) produit une critique/instruction — jugement esthétique général explicitement autorisé (contrairement au contrôle de lisibilité automatique existant), considère aussi l'ajout d'un accent décoratif ou une transition/animation adaptée — réinjectée dans le pipeline d'édition existant (aperçu avant/après, undo/version inclus).
  • Retour utilisateur — « est-ce que la suggestion de mise en forme pourrait intégrer des formes plus modernes (ex : hexagone, ronds de couleurs...) pour rendre le design plus moderne » : le wizard /suggest_design peut désormais proposer une zone decor (accent géométrique pur — hexagone, rond, bandeau…) en étape 1, avec sa vraie silhouette dans l'aperçu wireframe (plutôt qu'un rectangle grisé générique), traduite en un élément shape réel par le pipeline d'édition.
  • Retour utilisateur — « lorsque des changements sont proposés [...] est-ce qu'il pourrait y avoir une option (décochée par défaut) qui permette d'ajouter la nouvelle proposition juste après plutôt que de remplacer » : nouvelle case à cocher dans l'aperçu avant/après IA — la slide d'origine reste inchangée, la proposition est insérée comme une nouvelle slide juste après (id régénéré, même discipline que « Dupliquer »).
  • Retour utilisateur — « comment gérer le niveau de transparence d'une image ou un objet graphique, il faudrait que ce soit une propriété » : la propriété opacity du schéma (déjà rendue à l'écran) est désormais exposée dans le panneau de propriétés (tous types d'éléments) et exportée en PPTX (injection OOXML <a:alpha>/<a:alphaModFix>, même stratégie que l'ombre portée).
  • Retour utilisateur — « SlydeForge ne sait pas encore gérer toutes les transitions et animations [...] proposer une liste des évènements » : nouveau module transitions (fade/poussée par slide) + animations d'entrée (apparition/fondu/balayage/vol vers l'intérieur, déclenchées au clic/avec le précédent/après le précédent) sur les éléments — dialogues dédiés accessibles depuis les menus contextuels vignette/canevas. Export PPTX uniquement (injection OOXML <p:transition>/<p:timing>) ; aperçu écran volontairement statique. MVP assumé : le déclencheur "avec/après le précédent" est stocké mais pas encore distingué à l'export (tout élément animé devient un clic indépendant).
  • Retour utilisateur — « il n'est pas possible d'ajouter d'objets de type vidéos [...] il faudrait également répondre à ce besoin d'une présentation moderne » : nouveau type d'élément video (aperçu écran = affiche + icône lecture, export PPTX via add_movie — marqué EXPÉRIMENTAL par python-pptx lui-même, signalé à l'utilisateur).
  • Retour utilisateur — « dans le menu insérer, mettre des icônes [...] et revoir l'ordre des objets afin de proposer ce qui serait le plus logique » : icônes dessinées (cf. ui/icons.py) sur chaque entrée du menu Insérer, regroupées par nature (Contenu → Formes → Médias → Données → Structure) plutôt que rangées au fil de l'eau.
  • Retour utilisateur — « faire version multi langues (français / anglais) » : infrastructure i18n (QTranslator chargé au démarrage selon la préférence Paramètres > Langue, redémarrage requis) — périmètre MVP converti : ui/main_window.py (quasi-totalité des menus, via le helper commun _act()) + un sous-ensemble représentatif de ui/chat_panel.py. Le reste de l'application reste à convertir (cf. i18n/README.md).
  • +90 tests (nouveaux fichiers tests/test_image_attach_command.py, tests/test_slide_review_service.py, tests/test_review_slide_ui.py, tests/test_diff_preview_insert_after.py, tests/test_transitions_animations.py, tests/test_transition_animation_ui.py, tests/test_insert_video_ui.py, tests/test_insert_menu_icons_and_order.py, tests/test_i18n.py ; extension de tests/test_suggest_design_feature.py, tests/test_roundtrip_pptx.py, tests/test_properties_panel_border_shadow.py, tests/test_insert_elements.py, tests/test_settings_dialog.py).
Ajouté (2026-08-07, /suggest_design en 3 étapes — disposition, couleurs, tailles)
  • Retour utilisateur — « ça reste très basique, il propose bien et gère le positionnement, mais ne fait aucune suggestion à minima sur les couleurs. Il pourrait y avoir 2 phases, on sélectionne le positionnement et dans un deuxième temps les couleurs, puis 3ème temps les tailles de polices. À chaque étape l'IA prend en compte la réponse pour faire la proposition suivante » : /suggest_design devient un assistant en 3 étapes successives, chacune un appel IA qui voit les réponses précédentes (une seule conversation partagée, cf. services/design_suggest_service.py) : (1) disposition (inchangé), (2) un jeu de couleurs par zone — UNIQUEMENT des rôles de la palette de la charte, jamais une couleur inventée (retour utilisateur d'origine : « en respectant les conventions des couleurs du thème ») — prévisualisé sur le wireframe DÉJÀ choisi (mêmes zones, couleurs différentes par vignette, cf. render/wireframe.py::render_wireframe_image désormais capable de teinter chaque zone avec contraste de texte automatique) ; (3) un préréglage de taille de la charte (title/heading/subheading/body/caption) par zone TEXTUELLE de la disposition — une image/un graphique/un tableau/un logo gardent leur propre taille, jamais de police. Annuler l'étape 2 ou 3 SAUTE cette étape (poursuit avec la charte par défaut) plutôt que d'abandonner tout le travail déjà fait ; annuler l'étape 1 (disposition) abandonne l'ensemble, comme avant. Les 3 choix sont combinés en UNE instruction pour le pipeline d'édition existant, qui produit la vraie diapositive.
  • tests/test_suggest_design_feature.py réécrit pour les 3 étapes (42 tests : validation par étape, annulation partielle à chaque étape, magicien bout en bout).
  • Retour utilisateur — « dans la suggestion de design il doit y avoir une image ou plusieurs alors il faut dans le wizard demander de charger une photo, ou utiliser la bibliothèque ou par IA comme tu l'as déjà dans un sélectionneur. Faut juste bien donner le contexte de quelle image ça concerne lors de la sélection » : nouvelle étape "images" (entre la disposition et les couleurs) — pour CHAQUE zone "image" de la disposition retenue, ouvre le même dialogue unifié que Insérer > Image… (bibliothèque de charte/projet, recherche libre de droits, génération IA), avec un bandeau bleu rappelant PRÉCISÉMENT quelle zone est concernée (« Photo 1/2 pour la disposition « X » — zone Image en x=…%, y=…%, largeur=…%, hauteur=…% »), indispensable dès qu'il y a plusieurs photos à choisir à la suite. Jamais confié à l'IA : le patch d'édition ne peut pas transporter un contenu binaire réel, la ou les vraies photos choisies sont injectées directement dans le deck APRÈS le patch (services/design_suggest_service.py::apply_chosen_images), à la position exacte de leur zone ; l'IA est explicitement instruite de ne RIEN créer elle-même dans une zone déjà pourvue d'une photo (évite tout doublon). Fermer/annuler UNE sélection de photo laisse simplement cette zone sans image (l'IA réutilise une image déjà présente sur la diapositive si possible) plutôt que d'abandonner tout l'assistant — même discipline que les étapes couleurs/tailles.
  • +11 tests (extension de tests/test_suggest_design_feature.py, désormais 53 tests).