Communitygithub.com

Parcha-ai/build

Créez des compositions vidéo, des animations, des cartons-titres, des incrustations, des sous-titres, des voix off, des visuels réactifs à l'audio et des transitions de scène en HyperFrames HTML.

Qu'est-ce que build ?

Cette compétence permet de construire des compositions vidéo complètes en utilisant HyperFrames, un framework où l'HTML est la source de vérité pour la vidéo. Elle est utile pour les développeurs et créateurs de contenu qui souhaitent produire des animations synchronisées, des sous-titres liés à l'audio, des voix off (text-to-speech), des animations réactives à la musique (beat sync, glow, pulse) et des transitions de scène. Elle prend en charge les plates-formes HyperFrames et les workflows de production vidéo. Son fonctionnement repose sur la définition de la structure, du timing et de l'animation via des attributs `data-*` dans l'HTML, l'utilisation de GSAP pour les animations et le respect de règles strictes (pas de `Math.random()`, pas de boucles infinies, etc.) pour garantir un rendu déterministe et fiable. Pour les commandes CLI (init, lint, preview, render, transcribe, tts), se référer à la compétence hyperframes-cli.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Parcha-ai/build/tree/HEAD/.agents/skills/hyperframes

Demander à votre IA préférée

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

Aperçu

Depuis le README du skill

Documentation

HyperFrames

L'HTML est la source de vérité pour la vidéo. Une composition est un fichier HTML avec des attributs data-* pour le timing, une timeline GSAP pour l'animation, et du CSS pour l'apparence. Le framework gère la visibilité des clips, la lecture des médias et la synchronisation de la timeline.

Approche

Avant d'écrire l'HTML, réfléchissez à un niveau élevé :

  1. Quoi — que doit vivre le spectateur ? Identifiez l'arc narratif, les moments clés et les battements émotionnels.
  2. Structure — combien de compositions, lesquelles sont des sous-compositions vs. en ligne, quelles pistes transportent quoi (vidéo, audio, incrustations, sous-titres).
  3. Timing — quels clips déterminent la durée, où se situent les transitions, quel est le rythme.
  4. Disposition — construisez d'abord l'état final. Voir "Disposition avant animation" ci-dessous.
  5. Animer — ajoutez ensuite le mouvement en utilisant les règles ci-dessous.

Pour les petites modifications (corriger une couleur, ajuster le timing, ajouter un élément), passez directement aux règles.

Lorsqu'aucun visual-style.md ou directive d'animation n'est fourni, suivez house-style.md pour les paramètres de mouvement par défaut, le dimensionnement et les palettes de couleurs.

Disposition avant animation

Positionnez chaque élément là où il doit être à son moment le plus visible — l'image où il est complètement entré, correctement placé, et pas encore en train de sortir. Écrivez cela sous forme de HTML+CSS statique d'abord. Pas encore de GSAP.

Pourquoi c'est important : Si vous positionnez les éléments à leur état de départ animé (hors écran, mis à l'échelle à 0, opacité 0) et que vous les animez jusqu'à l'endroit où ils devraient atterrir, vous devinez la disposition finale. Les chevauchements sont invisibles jusqu'à ce que la vidéo soit rendue. En construisant d'abord l'état final, vous pouvez voir et corriger les problèmes de disposition avant d'ajouter du mouvement.

Le processus

  1. Identifiez l'image héroïque pour chaque scène — le moment où le plus d'éléments sont simultanément visibles. C'est la disposition que vous construisez.
  2. Écrivez du CSS statique pour cette image. Le conteneur .scene-content DOIT remplir toute la scène en utilisant width: 100%; height: 100%; padding: Npx; avec display: flex; flex-direction: column; gap: Npx; box-sizing: border-box. Utilisez le padding pour pousser le contenu vers l'intérieur — JAMAIS position: absolute; top: Npx sur un conteneur de contenu. Les conteneurs de contenu en position absolue débordent lorsque le contenu est plus haut que l'espace restant. Réservez position: absolute uniquement pour les éléments décoratifs.
  3. Ajoutez les entrées avec gsap.from() — animez DEPUIS hors écran/invisible VERS la position CSS. La position CSS est la vérité de référence ; l'animation décrit le voyage pour y arriver.
  4. Ajoutez les sorties avec gsap.to() — animez VERS hors écran/invisible DEPUIS la position CSS.

Exemple

/* scene-content remplit la scène, le padding positionne le contenu */
.scene-content {
  display: flex;
  flex-direction: column;
  justify-content: center;
  width: 100%;
  height: 100%;
  padding: 120px 160px;
  gap: 24px;
  box-sizing: border-box;
}
.title {
  font-size: 120px;
}
.subtitle {
  font-size: 42px;
}
/* Le conteneur remplit n'importe quelle taille de scène (1920x1080, 1080x1920, etc.).
   Le padding positionne le contenu. Flex + gap gère l'espacement. */

MAUVAIS — dimensions codées en dur et positionnement absolu :

.scene-content {
  position: absolute;
  top: 200px;
  left: 160px;
  width: 1920px;
  height: 1080px;
  display: flex; /* ... */
}
// Étape 3 : Animez VERS ces positions
tl.from(".title", { y: 60, opacity: 0, duration: 0.6, ease: "power3.out" }, 0);
tl.from(".subtitle", { y: 40, opacity: 0, duration: 0.5, ease: "power3.out" }, 0.2);
tl.from(".logo", { scale: 0.8, opacity: 0, duration: 0.4, ease: "power2.out" }, 0.3);

// Étape 4 : Animez DEPUIS ces positions
tl.to(".title", { y: -40, opacity: 0, duration: 0.4, ease: "power2.in" }, 3);
tl.to(".subtitle", { y: -30, opacity: 0, duration: 0.3, ease: "power2.in" }, 3.1);
tl.to(".logo", { scale: 0.9, opacity: 0, duration: 0.3, ease: "power2.in" }, 3.2);

Lorsque des éléments partagent de l'espace dans le temps

Si l'élément A sort avant que l'élément B n'entre dans la même zone, les deux doivent avoir des positions CSS correctes pour leurs images héroïques respectives. L'ordre de la timeline garantit qu'ils ne coexistent jamais visuellement — mais si vous sautez l'étape de disposition, vous ne détecterez pas le cas où ils se chevauchent accidentellement en raison d'une erreur de timing.

Ce qui est considéré comme un chevauchement intentionnel

Les effets en couches (lueur derrière le texte, éléments d'ombre, motifs d'arrière-plan) et les conceptions empilées en z (piles de cartes, couches de profondeur) sont intentionnels. L'étape de disposition consiste à détecter les chevauchements non intentionnels — deux titres atterrissant l'un sur l'autre, une statistique couvrant une étiquette, un contenu débordant du cadre.

Attributs de données

Tous les clips

AttributRequisValeurs
idOuiIdentifiant unique
data-startOuiSecondes ou référence d'ID de clip ("el-1", "intro + 2")
data-durationRequis pour img/div/compositionsSecondes. La vidéo/audio par défaut correspond à la durée du média.
data-track-indexOuiEntier. Les clips d'une même piste ne peuvent pas se chevaucher.
data-media-startNonDécalage de coupe dans la source (secondes)
data-volumeNon0-1 (par défaut 1)

data-track-index n'affecte pas la superposition visuelle — utilisez CSS z-index.

Clips de composition

AttributRequisValeurs
data-composition-idOuiID de composition unique
data-startOuiHeure de début (composition racine : utilisez "0")
data-durationOuiPrioritaire sur la durée de la timeline GSAP
data-width / data-heightOuiDimensions en pixels (1920x1080 ou 1080x1920)
data-composition-srcNonChemin vers un fichier HTML externe

Structure de composition

Les sous-compositions chargées via data-composition-src utilisent un wrapper <template>. Les compositions autonomes (le main index.html) n'utilisent PAS <template> — elles placent la div data-composition-id directement dans <body>. Utiliser <template> sur un fichier autonome cache tout le contenu du navigateur et casse le rendu.

Structure de sous-composition :

<template id="my-comp-template">
  <div data-composition-id="my-comp" data-width="1920" data-height="1080">
    <!-- contenu -->
    <style>
      [data-composition-id="my-comp"] {
        /* styles encapsulés */
      }
    </style>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js"></script>
    <script>
      window.__timelines = window.__timelines || {};
      const tl = gsap.timeline({ paused: true });
      // animations…
      window.__timelines["my-comp"] = tl;
    </script>
  </div>
</template>

Chargement dans la racine : <div id="el-1" data-composition-id="my-comp" data-composition-src="compositions/my-comp.html" data-start="0" data-duration="10" data-track-index="1"></div>

Vidéo et audio

La vidéo doit être muted playsinline. L'audio est toujours un élément <audio> séparé :

<video
  id="el-v"
  data-start="0"
  data-duration="30"
  data-track-index="0"
  src="video.mp4"
  muted
  playsinline
></video>
<audio
  id="el-a"
  data-start="0"
  data-duration="30"
  data-track-index="2"
  src="video.mp4"
  data-volume="1"
></audio>

Contrat de timeline

  • Toutes les timelines commencent { paused: true } — le lecteur contrôle la lecture
  • Enregistrez chaque timeline : window.__timelines["<composition-id>"] = tl
  • Le framework imbrique automatiquement les sous-timelines — ne les ajoutez PAS manuellement
  • La durée provient de data-duration, pas de la longueur de la timeline GSAP
  • Ne créez jamais d'animations vides pour définir la durée

Règles (non-négociables)

Déterministe : Pas de Math.random(), Date.now() ou logique basée sur le temps. Utilisez un PRNG ensemencé si vous avez besoin de valeurs pseudo-aléatoires (par exemple, mulberry32).

GSAP : Animez uniquement les propriétés visuelles (opacity, x, y, scale, rotation, color, backgroundColor, borderRadius, transformations). N'animez PAS visibility, display, et n'appelez pas video.play()/audio.play().

Conflits d'animation : N'animez jamais la même propriété sur le même élément à partir de plusieurs timelines simultanément.

Pas de repeat: -1 : Les timelines à répétition infinie cassent le moteur de capture. Calculez le nombre exact de répétitions à partir de la durée de la composition : repeat: Math.ceil(duration / cycleDuration) - 1.

Construction synchrone des timelines : Ne construisez jamais de timelines à l'intérieur d'async/await, setTimeout ou Promesses. Le moteur de capture lit window.__timelines de manière synchrone après le chargement de la page. Les polices sont intégrées par le compilateur, elles sont donc disponibles immédiatement — pas besoin d'attendre le chargement des polices.

Ne jamais faire :

  1. Oublier l'enregistrement de window.__timelines
  2. Utiliser la vidéo pour l'audio — toujours vidéo muette + <audio> séparé
  3. Nicher une vidéo dans une div temporisée — utilisez un wrapper non temporisé
  4. Utiliser data-layer (utilisez data-track-index) ou data-end (utilisez data-duration)
  5. Animer les dimensions d'un élément vidéo — animez une div wrapper
  6. Appeler play/pause/seek sur les médias — le framework possède la lecture
  7. Créer un conteneur de niveau supérieur sans data-composition-id
  8. Utiliser repeat: -1 sur n'importe quelle timeline ou animation — toujours des répétitions finies
  9. Construire des timelines de manière asynchrone (dans async, setTimeout, Promise)
  10. Utiliser gsap.set() sur des éléments de clip de scènes ultérieures — ils n'existent pas dans le DOM au chargement de la page. Utilisez tl.set(selector, vars, timePosition) à l'intérieur de la timeline au moment ou après l'heure data-start du clip à la place.
  11. Utiliser <br> dans le texte du contenu — les sauts de ligne forcés ne tiennent pas compte de la largeur de police réellement rendue. Le texte qui s'enroule naturellement + un <br> produit un saut supplémentaire indésirable, provoquant un chevauchement. Laissez plutôt le texte s'enrouler via max-width. Exception : les titres d'affichage courts où chaque mot est délibérément sur sa propre ligne (par exemple, "THE\nIMMORTAL\nGAME" à 130 px).

Transitions de scène (non-négociables)

Chaque composition multi-scène DOIT suivre TOUTES ces règles. En violer une seule rend la composition cassée.

  1. Utilisez TOUJOURS des transitions entre les scènes. Pas de coupures brutales. Aucune exception.
  2. Utilisez TOUJOURS des animations d'entrée sur chaque scène. Chaque élément s'anime ENTRANT via gsap.from(). Aucun élément ne peut apparaître complètement formé. Si une scène a 5 éléments, elle a besoin de 5 animations d'entrée.
  3. N'utilisez JAMAIS d'animations de sortie sauf sur la scène finale. Cela signifie : PAS de gsap.to() qui anime l'opacité à 0, le y hors écran, l'échelle à 0, ou toute autre animation de "sortie" avant qu'une transition ne se déclenche. La transition EST la sortie. Le contenu de la scène sortante DOIT être complètement visible au moment où la transition commence.
  4. Scène finale uniquement : La dernière scène peut estomper les éléments (par exemple, fondu au noir). C'est la SEULE scène où gsap.to(..., { opacity: 0 }) est autorisé.

MAUVAIS — animation de sortie avant la transition :

// INTERDIT — cela vide la scène avant que la transition ne puisse l'utiliser
tl.to("#s1-title", { opacity: 0, y: -40, duration: 0.4 }, 6.5);
tl.to("#s1-subtitle", { opacity: 0, duration: 0.3 }, 6.7);
// la transition se déclenche sur une image vide

BON — entrée uniquement, la transition gère la sortie :

// Animations d'entrée de la scène 1
tl.from("#s1-title", { y: 50, opacity: 0, duration: 0.7, ease: "power3.out" }, 0.3);
tl.from("#s1-subtitle", { y: 30, opacity: 0, duration: 0.5, ease: "power2.out" }, 0.6);
// PAS d'animations de sortie — la transition à 7,2 s gère le changement de scène
// Animations d'entrée de la scène 2
tl.from("#s2-heading", { x: -40, opacity: 0, duration: 0.6, ease: "expo.out" }, 8.0);

Garde-fous d'animation

  • Décalez la première animation de 0,1 à 0,3 s (pas t=0)
  • Variez les "ease" entre les animations d'entrée — utilisez au moins 3 "ease" différents par scène
  • Ne répétez pas un motif d'entrée dans une scène
  • Évitez les dégradés linéaires plein écran sur les arrière-plans sombres (crénelage H.264 — utilisez radial ou uni + lueur localisée)
  • Titres de 60 px ou plus, corps de 20 px ou plus, étiquettes de données de 16 px ou plus pour la vidéo rendue
  • font-variant-numeric: tabular-nums sur les colonnes de nombres

Lorsqu'aucun visual-style.md ou directive d'animation n'est fourni, suivez house-style.md pour les paramètres esthétiques par défaut.

Typographie et actifs

  • Polices : Écrivez simplement le font-family que vous voulez dans le CSS — le compilateur intègre les polices prises en charge automatiquement. Si une police n'est pas prise en charge, le compilateur avertit.
  • Ajoutez crossorigin="anonymous" aux médias externes
  • Pour le débordement de texte dynamique, utilisez window.__hyperframes.fitTextFontSize(text, { maxWidth, fontFamily, fontWeight })
  • Tous les fichiers résident à la racine du projet aux côtés de index.html ; les sous-compositions utilisent ../

Modification de compositions existantes

  • Lisez d'abord l'intégralité de la composition — faites correspondre les polices, couleurs et motifs d'animation existants
  • Ne modifiez que ce qui a été demandé
  • Préservez le timing des clips non liés

Liste de vérification de sortie

  • npx hyperframes lint et npx hyperframes validate passent tous les deux
  • Avertissements de contraste traités (voir Contrôles de qualité ci-dessous)
  • Chorégraphie d'animation vérifiée (voir Contrôles de qualité ci-dessous)

Contrôles de qualité

Contraste

hyperframes validate exécute un audit de contraste WCAG par défaut. Il cherche 5 horodatages, capture l'écran de la page, échantillonne les pixels d'arrière-plan derrière chaque élément de texte et calcule les rapports de contraste. Les échecs apparaissent sous forme d'avertissements :

⚠ Avertissements de contraste WCAG AA (3) :
  · .subtitle "secondary text" — 2,67:1 (besoin de 4,5:1, t=5,3s)

Si des avertissements apparaissent :

  • Sur les arrière-plans sombres : éclaircissez la couleur défaillante jusqu'à ce qu'elle dépasse 4,5:1 (texte normal) ou 3:1 (grand texte, 24 px+ ou 19 px+ en gras)
  • Sur les arrière-plans clairs : assombrissez-la
  • Restez dans la famille de la palette — n'inventez pas une nouvelle couleur, ajustez celle existante
  • Relancez hyperframes validate jusqu'à ce qu'il soit propre

Utilisez --no-contrast pour ignorer si vous itérez rapidement et que vous vérifierez plus tard.

Carte d'animation

Après avoir créé les animations, exécutez la carte d'animation pour vérifier la chorégraphie :

npx hyperframes animate-map main.html

Cela génère un résumé textuel de chaque animation avec son heure, sa durée, sa cible et sa propriété.

Arrière-plan du framework

HyperFrames anime les fichiers HTML en vidéos. Une composition est une page HTML qui utilise data-* pour le timing. Pendant le rendu, le framework :

  1. Charge la page dans un navigateur sans tête
  2. Joue la timeline GSAP de chaque composition
  3. Capture chaque image en tant qu'image
  4. Assemble les images dans une vidéo avec l'audio de la piste

Les compositions s'imbriquent : une composition racine peut charger d'autres fichiers HTML en tant qu'enfants, chacun avec sa propre timeline. Le framework aligne et entrelace chronologiquement les images de toutes les sous-compositions.

Pour chaque élément de la composition racine qui référence une composition enfant, le framework crée une timeline gsap qui est un segment de la timeline racine. Pour les sous-timelines, le framework projette les images sur l'intervalle de temps data-duration de la composition enfant dans la timeline racine.

Skills associés