Image OG animée
Chaque fichier utilisé par cette compétence est livré dans son propre dossier, à côté de ce SKILL.md, et les chemins ici sont relatifs à ce dossier. Elle n'a besoin de rien provenant d'autres compétences ou d'autres dossiers, ne les cherchez donc pas. Sauf si l'utilisateur nomme un autre emplacement, enregistrez tout ce qu'elle produit dans out/og-image-animated/ sous le projet actuel.
La carte de partage statique animée en une courte et calme révélation :
- Carte vide : arrière-plan et lueur douce uniquement.
- La marque et le titre tombent du haut (fondu + glissement vers le bas).
- La fenêtre de l'application s'élève depuis le bas (fondu + glissement vers le haut) et se stabilise exactement là où elle se trouve sur la carte statique.
- Pause sur l'image finale, qui doit correspondre à l'image OG statique.
Exemples : references/pulse.gif (le résultat) et references/pulse-frames.png (quatre images : début, titre entré, application en ascension, finale).
Règles
- Partez de la carte statique. Si le projet n'a pas encore de composant de carte OG, construisez-le d'abord en suivant
references/static-card.md(produit réel, message du site actuel, données réalistes). L'animation n'ajoute que du mouvement : même balisage, même disposition finale, aucun nouveau contenu. - Un composant, deux modes. Ajoutez une propriété
animatedau composant de carte existant plutôt que de le copier, afin que le PNG statique et l'animation ne dérivent jamais l'un de l'autre. Sans la propriété, rien n'est animé. - Mouvement, pas d'effets. Uniquement
opacity+transform: translateY, une seule courbe d'assouplissement partagée (cubic-bezier(0.16, 1, 0.3, 1)). Pas de rebond, de flou, de pop d'échelle, de texte machine à écrire ou d'éléments rotatifs. - Court. Chronologie totale d'environ 2 à 2,5 s, puis une pause d'environ 1,5 s. Le titre doit être entièrement lisible vers 1,3 s.
- Animations CSS uniquement (keyframes +
animationavec remplissageboth), pas de tweens ni de minuteurs pilotés par JS à l'intérieur de la carte. Le séquenceur recherche les animations CSS via l'API Web Animations ; le mouvement piloté par JS ne serait pas capturé de manière déterministe.
Chronologie
| Élément | Keyframes | Durée | Délai |
|---|---|---|---|
| Marque | de opacity: 0; translateY(-48px) | 900ms | 100ms |
| Titre | de opacity: 0; translateY(-48px) | 1000ms | 250ms |
| Fenêtre de l'application | de opacity: 0; translateY(320px) | 1300ms | 700ms |
Ajustez les distances à la carte : l'application doit commencer principalement en dessous du bord inférieur (environ la moitié de la hauteur de la carte) et le titre environ à sa propre hauteur au-dessus de son emplacement de repos. S'il y a un panneau flottant, laissez-le arriver en dernier (+200ms après le début de la fenêtre).
Étapes
1. Découvrir
- Trouvez le composant de carte statique et sa route de rendu (par ex.
og-image.tsx,/og/<page>), et le PNG actuel danspublic/. - Notez les wrappers de la marque, du titre et de la fenêtre de l'application. Si la fenêtre utilise
zoompour s'adapter, animez un wrapper interne, pas l'élément zoomé, afin que les décalages restent corrects.
2. Ajouter le mode animé
Dans le composant de carte :
const KEYFRAMES = `
@keyframes og-drop { from { opacity: 0; transform: translateY(-48px); } to { opacity: 1; transform: none; } }
@keyframes og-rise { from { opacity: 0; transform: translateY(320px); } to { opacity: 1; transform: none; } }
`;
const EASE = 'cubic-bezier(0.16, 1, 0.3, 1)';
const enter = (name: string, ms: number, delay: number) => ({ animation: `${name} ${ms}ms ${EASE} ${delay}ms both` });
// <div data-og-frame …>{animated && <style>{KEYFRAMES}</style>} …
// marque : style={animated ? enter('og-drop', 900, 100) : undefined}
// titre : style={animated ? enter('og-drop', 1000, 250) : undefined}
// fenêtre : <div style={{ zoom }}><div className="h-full" style={animated ? enter('og-rise', 1300, 700) : undefined}>…
Placez les keyframes dans le composant (une balise <style>) ou le CSS global du projet ; avec Tailwind v4, les keyframes dans @theme ne sont émises que lorsqu'un jeton --animate-* correspondant est utilisé, donc préférez le composant ou le CSS simple.
3. Ajouter une route web qui la joue
Une route sœur de la route statique, par ex. /og/<page>-animated (noindex, sans chrome d'application) :
- Affiche
<Card animated />à l'intérieur du cadre 1200×630. - Rejoue pour prévisualisation : remonte la carte avec une
keychangeante toutes les ~4,5s. ?loop=0joue une fois (le séquenceur utilise ceci). Normalisez d'abord le paramètre de recherche en chaîne : les routeurs comme TanStack analysent?loop=0comme le nombre0, et une vérification manquée continue de remonter la carte pendant l'enregistrement.
Ouvrez-la dans le navigateur et regardez-la plusieurs fois. Vérifiez l'ordre d'entrée, qu'aucun flash n'apparaît avant le début de l'animation, et que l'état stabilisé correspond à la carte statique.
4. Enregistrer MP4 + GIF
Avec le serveur de développement en cours d'exécution :
node <ce dossier de compétence>/scripts/record.mjs \
--url "http://localhost:<port>/og/<page>-animated?loop=0" \
--out out/og-image-animated/og-<page>
Écrit og-<page>.mp4 (2400×1260, H.264, 30ips), og-<page>.gif (1200px de large, palette optimisée, boucle) et og-<page>.png (dernier cadre). Comment ça fonctionne : il met en pause chaque animation sur la page, lit la longueur de la chronologie, puis parcourt toutes les animations image par image et capture une zone fixe de [data-og-frame]. Le résultat est identique à chaque exécution, sans images perdues. Options : --fps, --hold, --lead, --scale, --formats mp4,gif,png, --selector.
Nécessite ffmpeg dans le PATH. Playwright s'installe dans le dossier scripts/ de cette compétence lors de la première exécution, avec son Chromium si aucun n'est trouvé.
Pièges :
- La page ne doit pas forcer une réduction de mouvement. De nombreuses feuilles de style globales raccourcissent les animations sous
prefers-reduced-motion; le séquenceur ne l'émule pas, et il échoue bruyamment s'il ne trouve aucune animation. - Les captures d'écran d'éléments attendent la "stabilité", qui ne survient jamais au milieu d'une animation. C'est pourquoi le script capture une région de la page.
- Assurez-vous que le port dessert bien cette application (un autre serveur local peut répondre sur
localhost).
5. Réviser
Extrayez une planche contact et examinez-la :
ffmpeg -y -loglevel error -i og-<page>.mp4 \
-vf "select='eq(n\,8)+eq(n\,22)+eq(n\,40)+eq(n\,<dernier>)',scale=1000:-1,tile=2x2" -frames:v 1 sheet.png
- Image ~0,25s : carte vide (lueur uniquement), pas de saut de disposition.
- ~0,7s : titre entré ou presque, application pas encore visible.
- ~1,3s : application en pleine ascension, titre entièrement lisible.
- Dernière image : identique en contenu au PNG statique.
Gardez le GIF raisonnablement petit (moins d'environ 3 Mo). S'il est plus gros, réduisez --fps (20–24) ou raccourcissez --hold.
Résultat
Informez l'utilisateur :
- de l'URL de la route de prévisualisation (boucle) et des fichiers écrits (MP4, GIF, PNG)
- de la commande de régénération
- de la chronologie (ce qui bouge, durées)
- que
og:imagedoit rester le PNG statique : les plateformes sociales ne lisent pas les images OG animées. Utilisez le MP4/GIF pour les publications, README, pages de lancement ouog:videolà où c'est pris en charge.