Communitygithub.com

Opus Visual Motion Engine

Pipeline disciplinée pour graphismes animés : vidéo/UI générée par code, seek(t) déterministe, QA automatisé du rendu, export MP4 — fonctionne même avec les modèles textuels uniquement.

Qu'est-ce que Opus Visual Motion Engine ?

Opus Visual Motion Engine est un pipeline complet et rigoureux pour la création de livrables visuels animés (vidéos, motion design, UI, etc.) à partir de code. Il est conçu pour fonctionner de manière déterministe et fiable, même avec des modèles d'IA qui ne peuvent pas voir les images, en se concentrant sur des contraintes de qualité avant et après le rendu plutôt que sur le jugement esthétique. Le pipeline suit un processus en sept étapes : planification, construction à partir d'un template, rendu temporel déterministe via une fonction `render(t)`, QA automatisé (vérification de collisions, contraste, déterminisme, etc.), et export MP4. Il prend en charge l'audio en extrayant les données (battements, onsets, RMS) pour synchroniser parfaitement les animations. Les plateformes supportées incluent les navigateurs modernes (prévisualisation) et Node.js pour le QA headless. Ce skill est utile pour tout développeur ou concepteur souhaitant produire des animations de haute qualité, reproductibles, sans dépendre de la capacité du modèle à interpréter visuellement le résultat.

Compatible avec✓Claude Code~Codex CLI~Cursor
npx skills add Lob0Garou/opus-visual-motion-engine

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Que fait Opus Visual Motion Engine ?

Un pipeline discipliné pour les livrables visuels : planifier → construire à partir du template → rendre → QA → corriger → exporter. La qualité provient des contrôles appliqués avant et après le rendu, pas du goût. Suivez les étapes dans l'ordre. Ne sautez pas une étape parce que la tâche "a l'air simple".

Les chemins ci-dessous sont relatifs au répertoire de cette compétence (la base skill_resources qui vous a été donnée). Appelez-la $SKILL.

0. Lire d'abord (inconditionnel)

Avant d'écrire du code, lisez les références qui correspondent au livrable. Elles sont faisant autorité pour leur sujet :

LivrableLire
vidéo, motion graphique, explainer, vidéo produitreferences/video-generation.md, references/motion-design.md, references/javascript-animation.md
typographie cinétique / pièce axée sur le textel'ensemble vidéo ci-dessus + references/typography.md
page d'atterrissage, tableau de bord, maquette, UIreferences/visual-design.md, references/typography.md
diagramme, schéma, datavizreferences/visual-design.md §4
décisions de cadrage / camérareferences/cinematography.md
durées et easingreferences/animation-primitives.md
musique ou voix à synchroniserSKILL.md §10 + references/video-generation.md §6

Des exemples concrets se trouvent dans examples/*.md. Lisez celui qui se rapproche le plus du brief.

1. Planifier avant le code (écrire le plan)

Écrivez le plan dans votre réponse (ou dans un fichier PLAN.md à côté du résultat) avant de créer le HTML. Un plan qui n'existe que dans votre tête ne compte pas.

UI / page

  1. Message principal : une phrase. Que doit comprendre le spectateur en 3 secondes ?
  2. Direction nommée : un nom, 4 à 6 tokens hexadécimaux nommés avec leurs significations attribuées, polices avec rôles, traitement de forme. Dérivez-la du secteur du sujet, des matériaux et du langage. Un magasin de jouets et un tableau de bord fintech ne partagent jamais une direction.
  3. Hiérarchie : étiquetez chaque bloc PRIMARY / SECONDARY / TERTIARY. Seul PRIMARY obtient le geste audacieux.
  4. Progression des sections : une ligne par section, donnant son travail et comment elle passe la main à la suivante.
  5. Mathématiques pré-rendu : largeur du texte ≈ chars × 0.55 × font-size (sans) ou × 0.5 (serif) ; largeur de la boîte = max(title_chars × 8, subtitle_chars × 7) + 24 à 14px ; ajustement des lignes = Σlargeurs + écarts ≤ conteneur. Tracez chaque connecteur par rapport à chaque boîte. S'il en traverse une, tracez un chemin en forme de L.

Vidéo / motion graphique

  1. Message central : une phrase. S'il en faut deux, il y a deux vidéos.
  2. Temps forts : 3 à 7. Chaque temps fort répond à "que sait maintenant le spectateur ?"
  3. Fiche scène par temps fort : début/fin (s), composition, caméra, tailles de police, primitives (2–4), sortie. Utilisez le modèle dans references/motion-design.md §2.
  4. Moment signature : nommez l'UNIQUE image où le mécanisme est montré, pas étiqueté (par exemple, le bruit filtré en signal). Si l'histoire ne fonctionne qu'avec ses légendes, reconcevez le temps fort.
  5. Chronologie globale : horodatages absolus. La SORTIE d'une scène se termine avant que la scène suivante ne réclame l'espace. Définissez DURATION sur la vraie fin (10–20s par défaut ; 30–45s uniquement avec narration).

Une scène sans fiche n'a pas sa place dans la vidéo.

2. Construire à partir du modèle (vidéo)

Copiez assets/composition-template.html à côté du livrable et remplissez les blocs EDIT. Ne réécrivez pas les blocs ENGINE. Ils fournissent déjà :

  • une #stage 1920×1080 (changez STAGE_W/H pour 1080×1920 ou 1080×1080), adaptée à n'importe quelle fenêtre ;
  • window.DURATION, window.seek(t), window.render(t), window.SCENES : le contrat de capture/export (le QA capture chaque scène à partir de SCENES) ;
  • at(), ease.*, lerp, mulberry32 (PRNG ensemencé), et layer() pour la visibilité des scènes plus EXIT ;
  • les assistants audio audioAt(t, "rms"|"low"), since(t, list), hit(t, list, dur) qui lisent window.AUDIO (§10) et renvoient 0 sans lui ;
  • un lecteur de prévisualisation (espace, ←/→, Home/End) qui se désactive automatiquement en mode capture et mouvement réduit ;
  • des tokens de couleur dans les 3 couches requises (clair, protégé par prefers-color-scheme, [data-theme]).

Pour les pages, écrivez un fichier HTML unique normal suivant §6.

3. Temps déterministe (vidéo)

  • render(t) est le seul moteur d'état. Chaque position, opacité, taille, nombre et dashoffset est calculé à partir de t en secondes. seek(x) rend l'image identique, quel que soit ce qui a été rendu avant.
  • t est en secondes. Limitez t à [0, DURATION], jamais à [0, 1] : limiter les secondes à 0..1 fige silencieusement toute la chronologie.
  • Interdit : setTimeout, setInterval, animations/transitions CSS comme chronologie, Math.random() non ensemencé, Date.now() dans l'état. requestAnimationFrame ne peut avancer que l'horloge de lecture et appeler render(clock). Le modèle fait déjà cela.
  • Aléatoire : générez au moment de la construction à partir de mulberry32(seed), jamais à l'intérieur de render.
  • Le dessin SVG nécessite les trois : pathLength="1", stroke-dasharray="1", et stroke-dashoffset de 1 à 0. Sans dasharray, la ligne apparaît entièrement dessinée dès l'image 0.
  • Les spans inline-block de mots absorbent les espaces de fin. Mettez l'espacement dans margin-right.

4. Grammaire du mouvement

Cinq mouvements, chacun avec un seul travail. Si un mouvement n'est aucun de ceux-ci, supprimez-le.

  • ENTER : une séquence orchestrée par page ou scène, dans l'ordre de lecture, les frères et sœurs décalés de 60 à 120ms. Un fondu vers le haut sur chaque section est le signe révélateur de l'IA.
  • EMPHASIS : un élément à la fois : une augmentation d'échelle (≤1.2), une lueur ou un changement de couleur qui a du sens.
  • TRANSITION : un changement d'état. La partie modifiée bouge ; tout le reste reste immobile. 0.2–0.6s.
  • CAMERA : une échelle/translation au niveau de la scène, au maximum une fois par scène, 0.8–1.2s, jamais pendant une lecture de texte.
  • EXIT : 0.3–0.5s, entièrement terminé. Aucun élément ne survit à mi-état à travers une limite de scène, sauf un point d'ancrage de continuité délibéré qui persiste de manière identique ou morphose (le même objet changeant d'état, qui est la transition la plus forte disponible).

Les transitions ont une signification : coupe franche = changement de catégorie, morphose = même chose qui change, panoramique = traversée. Jamais un fondu enchaîné par défaut partout. Les durées et les easings se trouvent dans references/animation-primitives.md. Les voisins qui bougent ensemble reçoivent des durées différentes ou un décalage.

5. Décision de pile

SituationPile
micro-mouvement de pageTransitions CSS sur transform/opacity, 0.2–0.6s ; boucles ≤2s dans @media (prefers-reduced-motion: no-preference)
vidéo / motion graphique / typo cinétiquemodèle + vanilla render(t) (par défaut)
>6 pistes décalées ou orchestration de morphose SVGGSAP UMD épinglé, UNE chronologie maîtresse en pause, seek(t) → tl.seek(t)
graphiquesSVG en ligne (par défaut) ou Chart.js UMD avec animation:false, couleurs hex (le canvas ne peut pas lire les variables CSS)
art génératifp5.js avec randomSeed/noiseSeed
3D, uniquement quand la 3D est le messageThree.js UMD épinglé ; caméra scriptée dans render(t)

Utilisez la pile la plus simple qui atteint le résultat. Les scripts externes doivent être des versions épinglées exactes provenant de cdnjs.cloudflare.com ou cdn.jsdelivr.net. Tout le reste en ligne. Chaque police obtient une vraie pile de secours.

6. Base technique (non négociable)

  1. Un seul fichier .html avec CSS et JS en ligne, sous 16 Mo, images/données sous forme d'URI data:.
  2. Couleurs en tant que tokens :root ; couche sombre sous @media (prefers-color-scheme: dark) protégée par :root:not([data-theme="light"]) et répétée sous :root[data-theme="dark"] ; fond body explicite.
  3. meta viewport avec viewport-fit=cover ; remplissage env(safe-area-inset-*) ; height:100% sur html/body, jamais 100vh ; les blocs larges défilent à l'intérieur de leur propre overflow-x:auto ; les grilles utilisent minmax(0,1fr).
  4. Les nombres calculés affichés passent par Math.round, toFixed ou Intl.NumberFormat. Les compteurs arrivent exactement sur la valeur finale.
  5. Accessibilité : contraste ≥4.5:1 (≥3:1 pour un texte ≥24px), focus visible, prefers-reduced-motion respecté (le modèle montre l'image finale stabilisée).
  6. Typographie lisible : dans une image vidéo 1080p, aucun texte en dessous de 20px (H/54). Sur les pages mobiles, aucun texte de corps en dessous de 14px.
  7. Le stockage du navigateur ne contient jamais l'état de la chronologie. Là où le stockage est utilisé, enveloppez-le dans un try/catch.

7. Éviter le design générique de l'IA

Là où le brief laisse la liberté, ne la dépensez jamais sur ces valeurs par défaut (qa.mjs en signale plusieurs automatiquement) :

SigneCorrection
crème #F4F1EA-ish + police serif d'affichage + accent terre cuite #D97757-ishune palette tirée des propres matériaux du sujet
presque noir + un accent acide, utilisé indépendamment du sujetautorisé uniquement lorsque la direction le justifie par écrit
cartes arrondies identiques, un rayon partout, la même ombre doucetokens de rayon par hiérarchie ; carte uniquement pour les objets délimités
dégradés comme décoration, dégradés violets, glassmorphismeremplissages plats ; un dégradé max, uniquement pour une propriété physique continue
sourcils tout en majuscules suivis, chaînes méta avec point médian, "→" sur les lienscasse de phrase ; supprimez les étiquettes qui répètent le contenu
Inter / police système par défautpolices choisies pour ce sujet, avec une pile de secours
un seul mot accentué dans un titreautorisé UNIQUEMENT lorsque la couleur d'accent est un token sémantique utilisé pour la même signification ailleurs dans la pièce (par exemple, corail = bruit)
héro générique : titre + sous-titre + CTA + capture d'écranouvrez avec la chose la plus caractéristique dans l'univers du sujet
tout centré, même rythme de grille à chaque sectionun système d'alignement par section ; variez le rythme
tout anime en même temps, 300ms partoutla carte des durées + décalage (§4)

Dépensez l'audace à un endroit, puis retirez un accessoire.

8. Rendu + QA (obligatoire avant la livraison)

Exécutez le QA automatisé. Il rend le fichier sans tête et écrit les preuves plus un verdict. Il nécessite Node ≥18. La première exécution dans une copie fraîche de la compétence nécessite npm install dans $SKILL/scripts (sautez-le si scripts/node_modules existe).

node "$SKILL/scripts/qa.mjs" chemin/vers/livrable.html

Dans DSH sur Windows, exécutez-le avec l'outil pwsh en utilisant la même commande. Options : --step 0.25 (une grille plus fine pour les scènes rapides), --out <dir>, --mode page|video.

Mode vidéo (automatique quand DURATION + seek existent) capture une image à chaque pas et vérifie : les API interdites, le déterminisme sur les revisites dans le désordre, une chronologie figée, le silence, les étendues presque vides, une image de fin instable, les collisions de texte, le texte sur d'autres graphiques, le clipping, le contraste, la taille de police minimale, les lignes dash-offset qui ne se dessinent jamais, les boucles en mouvement réduit, les erreurs de console/page et les signes du modèle. Mode page rend le bureau 1440, le mobile 390 et le thème sombre, et vérifie les mêmes règles de mise en page plus le débordement horizontal mobile.

Les résultats atterrissent dans qa-<nom>/ : report.md (verdict et résultats), report.json (couverture d'encre par image et changement), contact-sheet.png (toutes les images sur une seule image), moments.png (l'entrée, le milieu et la fin de chaque scène, pris à partir de window.SCENES), key_000..100.png et frames/.

  • Passez le moment signature et tout point de synchronisation explicitement : --at 5.4,9.1.
  • La superposition délibérée (typographie cinétique empilée volontairement, un titre sur des images) va à l'intérieur d'un élément avec data-qa-allow-overlap. Cela ignore les vérifications de collision et de texte sur les graphiques pour cette sous-arborescence uniquement. Ne l'utilisez jamais pour faire taire une collision accidentelle.
  • Un avertissement font signifie que la police de première intention ne s'est pas chargée et que le texte est dans une police de secours. Corrigez-le avant de juger la mise en page, car toutes les largeurs sont erronées.

Code de sortie 0 = aucun ÉCHEC. L'ÉCHEC est bloquant. Chaque avertissement est soit corrigé, soit justifié en une ligne dans votre critique.

9. Boucle de critique

  1. Si votre modèle peut lire des images : ouvrez contact-sheet.png, puis toute key_*.png qui semble erronée. Jugez les pixels, pas vos intentions.
  2. Si votre modèle est textuel uniquement : utilisez report.md plus le tableau par image dans report.json. coverage < 0.015 signifie que l'image est vide. Une diff de 0 sur une scène signifie que rien ne bouge. Un pic dans diff marque une coupe. Vérifiez les horodatages de chaque fiche de scène par rapport à ces nombres.
  3. Répondez à chaque question avec une observation concrète, pas "✓" :
    • Composition : à chaque image clé, où l'œil atterrit-il en premier ? Est-ce le message ?
    • Hiérarchie : PRIMARY est-il indubitable ? Y a-t-il exactement une chose en mouvement qui compte par image ?
    • Mécanisme : le moment signature montre-t-il l'idée avec les légendes retirées ?
    • Continuité : toutes les transitions sont-elles propres, sans rien à mi-état à une limite et les ancres identiques ou en morphose ?
    • Timing : y a-t-il des décalages, pas de durées par défaut, et un temps de lecture ≥1.2s pour 8 mots ?
    • Typographie / contraste / densité : tailles selon le plan, ≤5 éléments concurrents par image, lisible en mode sombre ?
    • Narratif : un spectateur pourrait-il répéter le message central après un visionnage ?
  4. Corrigez → réexécutez qa.mjs → re-critiquez. Répétez jusqu'à ce que le QA réussisse et que la critique n'ait aucun élément ouvert.
  5. Question finale, répondue honnêtement : "Cela a-t-il l'air intentionnellement conçu, ou simplement généré ?" Si "généré" : nommez ce qui est générique, révisez le plan (§1) et reconstruisez. Un premier rendu n'est presque jamais le livrable. Attendez-vous à 2-3 générations.

10. Synchronisation audio (quand il y a de la musique ou une voix)

Ne devinez jamais le timing à l'oreille. Convertissez l'audio en données, et laissez render(t) les lire :

node "$SKILL/scripts/audio-data.mjs" music.mp3 --inject composition.html   # écrit window.AUDIO dans le HTML
  • AUDIO.beats (une grille uniformément espacée au tempo estimé), AUDIO.onsets (frappes, notes, syllabes), et par image AUDIO.rms / AUDIO.low (0..1 ; low est la bande de kick/basse < 150 Hz).
  • Pilotez le mouvement avec les assistants du modèle : hit(t, AUDIO.beats, 0.2) pour une impulsion de battement (EMPHASIS), audioAt(t, "low") pour une échelle réactive au kick, since(t, AUDIO.onsets) pour des révélations par frappe. Placez les coupes de scène sur les battements : choisissez les débuts de scène à partir de AUDIO.beats.
  • La synchronisation est exacte à l'image près par construction : une impulsion atterrit sur la première image à ou après son battement (≤1 image, ≤33 ms à 30 ips). Si l'audio commence plus tard que t=0, passez --offset <s>.
  • Les niveaux sont vérifiés avant que quiconque n'écoute. Les échantillons écrêtés sortent avec le code 1. Un pic d'échantillon au-dessus de −1 dBFS avertit, car l'encodage AAC va l'écrêter. La sonie en dehors de −18..−12 LUFS est signalée (les plateformes normalisent à environ −14).
  • --bpm remplace...

Skills associés