Que fait anim-slides ?
Illustrations SVG animées pour diaporamas, à partir de diapositives existantes ou de documentation.
La sortie est toujours un fragment : un fichier HTML avec une balise <style> et un <svg>, sans scripts,
sans fichiers externes, thématisé par variables CSS, qui s'intègre dans n'importe quel diaporama.
references/fragment-contract.md est le contrat. Lisez-le avant de construire quoi que ce soit.
Quand l'utiliser
- Une diapositive contient une rangée de cartes textuelles, une liste à puces ou une capture d'écran, et le contenu représente un processus, un flux, une structure de dépendances, une chronologie, une comparaison, une architecture ou une série temporelle.
- Un document (Markdown, export Confluence, README, bloc Mermaid) décrit un processus ou des dépendances et l'utilisateur souhaite le voir affiché sous forme d'animation sur une diapositive ou une page.
- L'hôte est un diaporama HTML (frontend-slides, reveal.js, impress.js, Slidev, écrit à la main) ou une
page web simple. Un fichier
.pptxou une source Markdown est d'abord converti en diaporama HTML conçu par un skill de diaporama (étape 0) ; ce skill ajoute ensuite les illustrations.
Workflow
<skill-dir> ci-dessous est le dossier qui contient ce SKILL.md (Claude Code l'expose sous
$CLAUDE_SKILL_DIR ; dans d'autres environnements, utilisez le chemin à partir duquel vous avez chargé ce fichier). Les scripts nécessitent
Python 3.9+ et, pour le rendu, un binaire Chrome ou Chromium. anim/<name>/ est un dossier à côté du
diaporama de l'utilisateur.
0. Récupération
Obtenez d'abord un diaporama HTML. anim-slides ajoute des figures à un diaporama HTML ; il n'en conçoit pas un.
- La source est déjà un diaporama HTML (reveal.js, impress.js, tout
<section>ou.slidediaporama) : continuez. - La source est un fichier
.pptx, Markdown, remark, un document ou tout autre chose qui n'est pas un diaporama HTML : un skill de diaporama construit d'abord le diaporama HTML, pas anim-slides. Par ordre de préférence : (a) le propre skill de diaporama de l'utilisateur ou de l'organisation, s'il est installé ; (b)frontend-slides, lorsqu'il est installé (il convertit pptx et Markdown en un diaporama HTML conçu ; lorsqu'il propose des aperçus esthétiques, choisissez celui qui se rapproche le plus de la marque du diaporama source, sauf si l'utilisateur souhaite un nouveau look) ; (c) uniquement lorsqu'aucun skill de diaporama n'est installé,scripts/md_to_deck.pycomme solution de repli (voir la puce de repli ci-dessous), et dites à l'utilisateur en une phrase que sa sortie est un hôte simple, pas un design, et qu'elle ressemblera à un document jusqu'à ce qu'un skill de diaporama ou un designer le style. Dans les cas (a) et (b), le fichier.pptxoriginal reste la source pourextract_slides.pyetrender_deck.pyde triage (graphiques, figures, notes), mais l'intégration cible le diaporama produit par le skill, et l'apparence correspondante provient de la palette de ce diaporama viahost_theme.py. Demandez au skill de diaporama (ou faites-le juste après) d'envelopper le corps de chaque diapositive candidate dans un slot<div id="sN-slot">de taille fixe entre<!-- sN-body -->et<!-- /sN-body -->(l'identifiant et les noms de marqueurs quemd_to_deck.pyutilise, bien qu'ici le slot soit un frère vide du corps) :measure_slot.py --selector '#sN-slot'est alors exact, etintegrate_fragment.py --anchor/--replace-untilcible les marqueurs. Le lien de police propre au skill de diaporama (Google Fonts, Fontshare) est le chargement du diaporama, pas un ajouté par anim-slides ; conservez-le et intégrez-le lors de la remise avecbundle_deck.py --fetch.
Ensuite, décidez quel point d'entrée s'applique :
- Diaporama existant : exécutez
python3 <skill-dir>/scripts/extract_slides.py deck.pptx|deck.html|doc.md -o anim/outline.jsonetpython3 <skill-dir>/scripts/render_deck.py deck -o anim/render, puis regardez les planches de contactsheet-NN.png(12 diapositives numérotées chacune), pas page par page (lorsque le nombre d'images d'une diapositive dansoutline.jsondiffère des images dans son rendu, examinez les images de la mise en page de la diapositive : une photo de couverture sur la mise en page est facile à manquer) ; puis triez avecreferences/input-stage.mdet écrivez le tableau dansanim/triage.md: chaque diapositive, une décision et une raison, pas de sauts silencieux (3 à 8 illustrations pour 30 diapositives est normal ; sur un petit diaporama, chaque processus, structure, chronologie, comparaison ou diapositive de données en reçoit une). Ensuite, définissez l'apparence une fois pour l'ensemble du diaporama : match (les fragments prennent la palette et les polices de l'hôte, la valeur par défaut pour les diaporamas de marque ou d'entreprise) ou lean (les fragments conservent la palette épurée sur un fond sombre, pour les discours et les présentations).python3 <skill-dir>/scripts/host_theme.py deck.html --mode match -o anim/host-theme.cssdérive la colle de correspondance du CSS du diaporama (--mode leanécrit la colle épurée) ; comparez le bloc dérivé une fois avec les propres variables du diaporama (une couleur de texte atténuée, un arrière-plan secondaire) et corrigez manuellement là où la dérivation a choisi un mélange calculé ; rendez le premier fragment des deux manières (render-phases.sh --theme anim/host-theme.css ...) et montrez les deux images avant de construire le reste, sauf si l'utilisateur a déjà nommé une apparence. Seules les couleurs et les polices changent entre les deux : les règles de forme dereferences/style.mds'appliquent aux deux. Le contrôle estoncepour l'ensemble du diaporama, sauf si l'utilisateur demande un clic : la figure de chaque diapositive joue un passage calme lorsque la diapositive apparaît, puis se repose. Ne recommandez passtepde votre propre chef. Mentionnez-le en une ligne uniquement lorsqueoutline.jsonsignale desbuildssupérieurs à 0 (la source se construit déjà par clic : fragments reveal.js, animations PowerPoint par clic, sous-étapes impress.js, les propres étapes de construction du diaporama) : "votre diaporama se construit par clic ; les figures peuvent faire de même (step), dites-le si vous le souhaitez". Sousstep, l'entrée se dessine et chaque clic amène la phase suivante ; les phases sont les phases narrées du brief (3 à 5 par diapositive), le fichier fragment est le même, et le clic repose sur la propre navigation du diaporama. Step écoute uniquement les touches, donc un diaporama step est présenté avec le clavier ou un cliqueur (un diaporama qui navigue également par roue ou balayage, comme le fait frontend-slides, saute les phases lors d'un défilement). Écrivez Apparence et Contrôle dans l'en-tête deanim/triage.md. - Repli, aucun skill de diaporama installé (Markdown, remark, ou un pptx extrait en Markdown) :
python3 <skill-dir>/scripts/md_to_deck.py deck.md -o deck.htmlcrée un hôte simple et autonome pour l'intégration (une<section>par diapositive, portail.visible, mise en page d'impression, marqueurs<!-- sN-body -->autour du corps de chaque diapositive). Ce n'est pas un diaporama conçu : dites-le à l'utilisateur en une phrase. Récupérez d'abord les images référencées par le Markdown (chemins relatifs) dans le même dossier, sinon le diaporama affiche des espaces réservés ; puis extrayez de la source originale (le fichier.pptxs'il y en avait un) ou du Markdown. - Documentation : lisez la source, choisissez l'archétype avec le tableau dans
references/archetypes.md, extrayez une spécification (étape 1). - Demande de diapositive unique : allez directement à l'étape 1 pour cette diapositive. Demandez à l'utilisateur uniquement lorsque la source est ambiguë quant à l'ordre, la direction ou le regroupement. Sinon, énoncez l'hypothèse dans le brief et continuez.
1. Spécification
Écrivez anim/<name>/spec.yaml en suivant references/spec-format.md : nom, archétype, nœuds,
arêtes, groupes, phases avec marques de secondes, cycle (la durée du passage), contrôle (le choix du diaporama
lors de la récupération : once, un passage calme de 4 à 10 s lorsque la diapositive devient courante, se terminant sur
le cadre de repos ; step, le même passage coupé aux marques de phase pour que chaque clic amène
la phase suivante ; loop uniquement lorsque l'utilisateur demande une boucle continue). Le fichier fragment est le même
sous once et step ; les marques de phase deviennent data-anim-phases. Réutilisez les
propres mots de la source comme étiquettes. Gardez une spécification sous environ 12 nœuds ; sinon, divisez.
1b. Vérifier le pool
Lisez <skill-dir>/pool/index.yaml, puis $ANIM_POOL/index.yaml (ou listez $ANIM_POOL/*/) si
cette variable est définie, et cherchez une entrée avec le même archétype et une histoire ou des balises similaires.
- Correspondance proche : copiez le dossier dans
anim/<name>/, renommez le fragment et chaque préfixe en<name>, puis adaptez les étiquettes, les données, le timing et la viewBox à la spécification à l'étape 3 au lieu de l'échafaudage. Sonspec.yaml, s'il est présent, est un point de départ pour le vôtre. - Même archétype uniquement : échafaudez comme d'habitude et ouvrez le fragment du pool comme barre de qualité pour la densité, le mouvement et le cadre de repos.
- Rien ne correspond : construisez à partir de la spécification ; l'entrée la plus proche du pool vaut toujours un coup d'œil. Ne copiez jamais un fragment du pool inchangé dans un diaporama : son histoire est un exemple, pas celle de l'utilisateur.
2. Slot et brief
Mesurez la zone libre sur la diapositive : python3 <skill-dir>/scripts/measure_slot.py deck.html --slide N [--selector SEL] [--ignore .body]
affiche la zone en pixels de la scène, une viewBox correspondante et les indicateurs de vérificateur (references/layouts.md
explique la méthode manuelle). Sur une mise en page positionnée de manière absolue, la mesure sans --selector
renvoie des données inutilisables ; mesurez le div slot (--selector '#sN-slot', étape 0). Choisissez une viewBox avec le même rapport d'aspect,
et remplissez anim/<name>/brief.md à partir de references/brief-template.md. Le brief fixe
la viewBox et la taille rendue, la composition, les phases, le cadre de repos, les jetons de thème et la taille minimale du texte,
et nomme ce que le fragment remplace sur la diapositive (les pilules, le diagramme en boîte, la colonne de puces).
La qualité du fragment suit la qualité du brief.
3. Construction
python3 <skill-dir>/scripts/scaffold_from_spec.py anim/<name>/spec.yaml -o anim/<name>/<name>.html --rendered-width <px>
valide la spécification et écrit un squelette conforme au contrat (mise en page, phases, paquets, notes,
cadre de repos ; tailles de police relevées au minimum pour la largeur rendue), puis exécute le vérificateur dessus.
Le commentaire en haut de la sortie liste ce qui doit être affiné manuellement. Affinez-le en l'illustration que le brief décrit, en utilisant
references/archetypes.md pour la composition et le mouvement, references/motion-rules.md pour le timing et l'assouplissement, et
references/style.md pour l'apparence (lean : anneaux et lignes fines, pas de boîtes, un accent lumineux, sous-étiquettes mono, légendes simples). Pour plusieurs illustrations, construisez un
fragment à la fois à partir des briefs partagés, ou un sous-agent parallèle par fragment si l'environnement
les supporte ; l'intégration reste toujours dans le thread principal.
4. Vérification visuelle
python3 <skill-dir>/scripts/check_fragment.py anim/<name>/<name>.html --name <name> --rendered-width <px> --stage-width <largeur de scène du diaporama>doit réussir (préfixes, jetons, portails, taille du texte, contenu interdit).--stage-widthdéfinit le seuil de texte (18 px à 1920, 12 px à 1280) ;outline.jsonindique la scène.<skill-dir>/scripts/render-phases.sh anim/<name> <W> <H> 1.5 4 7 10 restrend les PNG de phase et une planche de contact avec la méthode pause et délai négatif, dans un dossier temporaire qu'il imprime (passez--out DIRpour choisir). Après intégration,render-phases.sh --page deck.html 1920 1080 restvérifie le cadre de repos de la page hôte ; sur une page multi-diapositives, ajoutez--slide N(ou#hash, ou un sélecteur CSS). Utilisez--no-scriptpour les images de marque temporelle ou de phase lorsque le propre script de la page bascule la classe de portail, jamais pourrest: dans les diaporamas frontend-slides,.visibleest à la fois le portail et la classe qui affiche la diapositive, le rendu du repos l'enlève, et la diapositive reste affichée uniquement parce que le script du diaporama définit également.active; sans script, le cadre de repos est vide. Ouvrez chaque PNG avec votre outil de visualisation d'images. Corrigez le rognage, les chevauchements, le texte illisible, les panneaux vides. Itérez au moins une fois.- Le cadre de repos doit être lisible comme une image fixe complète (l'export PDF n'affiche que cela).
python3 <skill-dir>/scripts/verify_facts.py anim/<name>/<name>.html --source anim/outline.json --slide <N>(ou--source doc.md) doit réussir : chaque nombre dans le fragment provient de la source ou est marqué comme illustratif ; lisez chaque AVERTISSEMENT et remplacez les formulations introuvables par les propres mots de la source ou supprimez-les. Règles dansreferences/accuracy.md. Une figure n'est pas terminée tant que cela ne réussit pas. Ne faites jamais confiance à--virtual-time-budget, et ne faites jamais confiance à la lecture de la source au lieu du PNG.
5. Intégration
python3 <skill-dir>/scripts/integrate_fragment.py deck.html anim/<name>/<name>.html --name <name> --anchor '<chaîne unique dans la diapositive>' [--replace-until '<chaîne>'] [--gate 'section.present'] [--control once|step] --backup
lève le style dans l'en-tête, insère le fragment entre les marqueurs <!-- anim:<name>:start --> et <!-- anim:<name>:end -->
(le style entre les marqueurs anim-style ; une réexécution remplace les deux copies), réécrit le portail pour le diaporama hôte, et préfixe toute
classe qui aurait échappé. Pour les pages simples, copiez <skill-dir>/scripts/snippets/observer.html dans la page.
--control définit le contrôle du diaporama sur le wrapper ; --control step met également
scripts/snippets/step-host.html (un petit script simple, sans bibliothèque) dans l'en-tête une fois et
définit son portail à partir de --gate. Le contrôle est un commutateur à l'échelle du diaporama lors de l'intégration : réexécutez avec
l'autre valeur pour le modifier, les fragments restent tels quels.
L'ancre et la chaîne jusqu'à sont conservées ; ce qui se trouve entre elles est remplacé. Le portail est le
marqueur "diapositive courante" de l'hôte : section.present pour reveal.js, .visible pour les pages simples
(scripts/snippets/observer.html) et pour les diaporamas de md_to_deck.py. Dans les diaporamas md_to_deck.py,
et dans les diaporamas de skills de diaporama avec les marqueurs de slot de l'étape 0, le fragment remplace le corps :
--anchor '<!-- sN-body -->' --replace-until '<!-- /sN-body -->'.
Vérifiez que les titres et le texte du corps de la diapositive s'affichent sans le script du diaporama et à l'impression.
Les animations d'entrée des skills de diaporama animent souvent leurs révélations uniquement sur la classe de diapositive courante
(frontend-slides affiche les éléments .reveal uniquement sous .slide.visible), donc les rendus de repos et les
PDF affichent des diapositives vides ; animez également ces révélations sur la classe active du diaporama (.slide.active)
et ajoutez une règle d'impression qui les affiche. (Le nom de classe .reveal correspond également à la détection reveal.js
dans les sélecteurs de diapositives de host_theme.py ; inoffensif jusqu'à présent, mais vérifiez quelles diapositives il a trouvées.)
Il ajoute également un garde d'impression afin que l'export PDF (le ?print-pdf de reveal marque chaque diapositive présente) affiche
les cadres de repos.
Gardez le diaporama de travail léger : les fragments sont du petit texte SVG et s'insèrent par marqueurs, mais ne
intégrez pas de polices, d'images, de bibliothèques ou de feuilles de style pendant que vous travaillez, et ne lisez jamais l'ensemble du diaporama
dans le contexte ; lisez des tranches autour de l'ancre (grep -n, sed -n) et laissez les scripts l'éditer.
Ouvrez ensuite le diaporama dans un vrai navigateur et regardez...