Communitygithub.com

AlexGit92s/Remotion2.0

Structurez le balisage Remotion pour l'interactivité

Qu'est-ce que Remotion2.0 ?

Cette compétence définit les bonnes pratiques pour structurer le balisage Remotion afin que le Studio Remotion puisse le reconnaître et le rendre interactif — permettant la sélection par clic, le glisser-déposer, le redimensionnement, la rotation et l'édition des styles CSS, des images clés et des fonctions d'accélération. Elle s'applique aux agents utilisant Remotion (comme Claude Code, Cursor, Codex) pour générer ou éditer du code de composition vidéo. La compétence explique comment utiliser `Interactive.withSchema({wrapInSequence: true})` pour des composants personnalisés avec leurs propres chronologies, comment exposer les propriétés éditables dans un `InteractivitySchema`, et comment enregistrer les composants réutilisables en tant que compositions connectées. Elle détaille également la gestion du timing directement sur les composants, l'attribution d'un nœud JSX distinct à chaque élément modifiable, l'utilisation de `Interactive` pour les éléments HTML/SVG, les styles CSS en ligne, l'animation avec `interpolate()` et l'ajout de noms descriptifs aux éléments interactifs.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/AlexGit92s/Remotion2.0/tree/HEAD/.claude/skills/remotion-interactivity

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

Remotion2.0 preview
Remotion2.0 preview

Documentation

En écrivant le balisage Remotion d'une manière spécifique, le Studio Remotion peut reconnaître la structure du code et le rendre interactif :

  • Permettre la sélection d'éléments en cliquant dessus
  • Permettre le glisser-déposer, le redimensionnement et la rotation
  • Éditer les styles CSS
  • Rendre les images clés et les valeurs d'accélération modifiables

Si le balisage est trop complexe pour que le Studio puisse le rendre interactif, les valeurs deviennent grisées.

Privilégier les composants interactifs avec leurs propres chronologies

Utilisez Interactive.withSchema({wrapInSequence: true}) pour les scènes personnalisées, les cartes, les titres et autres composants visuels dont les props doivent être modifiables par instance. Exposez les contrôles de contenu et d'apparence significatifs dans un InteractivitySchema. Conservez les détails d'implémentation décoratifs à l'intérieur du composant.

Le composant doit accepter style et le transmettre à une racine visuelle. Conservez une racine partagée lorsque les transformations, le recadrage ou l'opacité doivent affecter toutes ses couches. Aplatissez les emballages internes redondants lorsque leurs styles peuvent être déplacés sur un élément existant sans modifier la mise en page ou l'animation.

import type React from 'react';
import {Interactive, type InteractivitySchema} from 'remotion';

type LowerThirdProps = {
  readonly children: string;
  readonly accentColor: string;
  readonly style?: React.CSSProperties;
};

const LowerThirdInner: React.FC<LowerThirdProps> = ({
  children,
  accentColor,
  style,
}) => {
  return (
    <Interactive.Div
      style={{
        position: 'absolute',
        left: 80,
        bottom: 80,
        display: 'flex',
        alignItems: 'center',
        gap: 20,
        backgroundColor: 'white',
        borderRadius: 16,
        padding: '20px 32px',
        color: 'black',
        fontFamily: 'Helvetica, Arial, sans-serif',
        fontSize: 48,
        fontWeight: 600,
        ...style,
      }}
    >
      <div
        style={{
          width: 8,
          alignSelf: 'stretch',
          borderRadius: 4,
          backgroundColor: accentColor,
        }}
      />
      {children}
    </Interactive.Div>
  );
};

const lowerThirdSchema = {
  children: {type: 'text-content', default: '', description: 'Texte'},
  accentColor: {
    type: 'color',
    default: '#0b84f3',
    description: 'Couleur d'accentuation',
  },
} as const satisfies InteractivitySchema;

export const LowerThird = Interactive.withSchema({
  Component: LowerThirdInner,
  componentName: '<LowerThird>',
  schema: lowerThirdSchema,
  wrapInSequence: true,
});

Transmettre le style injecté à l'intérieur du composant est obligatoire ; conservez les styles éditables en ligne sur le site d'appel du composant.

Choisir les champs du schéma

Chaque clé du schéma est une prop que le Studio peut lire et éditer sur le site d'appel. Les props qui ne sont pas dans le schéma fonctionnent toujours, mais ne sont pas modifiables dans le Studio. Les clés peuvent utiliser la notation par points, comme style.color.

TypeUtilisation pourImages clés
text-contentTexte, comme un titreNon
numberNombres, avec min, max, step, integer optionnelsOui
booleanInterrupteurs on/offOui (maintien)
colorChaînes de couleur CSSOui
enumUn choix entre variants, chacun avec son propre schéma imbriquéSur option (maintien)
arrayListes de nombres, couleurs, énumérations, etc.Non
assetSources multimédia, avec assetType optionnelNon
font-familyFamille de police CSSNon
font-weightÉpaisseur de policeOui
translate, scale, rotation-css, rotation-degrees, transform-originTransformations CSSOui
uv-coordinateUn point normalisé [x, y] sur l'élémentOui
svg-pathDonnées de chemin SVGOui
remotion-captionsDonnées Caption[]Non
hiddenUne valeur conservée hors des contrôles—

Chaque champ a besoin d'une default et doit avoir une description, que le Studio affiche comme étiquette. Définissez keyframable: false pour afficher un contrôle statique.

Exposez le contenu et l'apparence par instance, comme le texte et une couleur d'accentuation. N'ajoutez pas de champs pour style.translate, style.scale, style.rotate, style.transformOrigin et style.opacity : wrapInSequence: true les ajoute déjà.

Pour rendre les propriétés CSS de la racine modifiables par instance, étendez les fragments de schéma intégrés :

const cardSchema = {
  ...Interactive.textSchema, // style.color, style.fontSize, style.fontWeight, ...
  ...Interactive.backgroundSchema, // style.backgroundColor
  ...Interactive.borderRadiusSchema, // style.borderRadius, ...
} as const satisfies InteractivitySchema;

Également disponibles : Interactive.borderSchema et Interactive.captionsSchema pour les composants qui acceptent des légendes. Voir InteractivitySchema pour toutes les options.

Enregistrer les composants réutilisables en tant que compositions connectées

Enregistrez les scènes et composants réutilisables substantiels avec leurs propres couches ou animation en tant que compositions autonomes. Le Studio les appelle compositions connectées : elles peuvent être ouvertes dans leur propre chronologie tout en partageant la même implémentation de composant que la vidéo parente.

Définissez les styles requis et chargez les polices à l'intérieur du composant pour qu'il fonctionne sans son parent. Voir l'indépendance parentale.

Enregistrez la même référence de composant exporté que le parent rend. Pour l'exemple ci-dessus, utilisez component={LowerThird}, pas LowerThirdInner ou un emballage en ligne. Avec wrapInSequence: true, aucun <Sequence> supplémentaire n'est nécessaire pour la connexion.

import {Composition} from 'remotion';
import {LowerThird} from './LowerThird';

export const RemotionRoot = () => (
  <Composition
    id="LowerThird"
    component={LowerThird}
    width={1280}
    height={720}
    fps={30}
    durationInFrames={30}
    defaultProps={{
      children: 'Jane Doe, Conceptrice de produits',
      accentColor: '#0b84f3',
    }}
  />
);

Choisissez un ID unique, des valeurs par défaut en ligne représentatives, et des dimensions, fps et durée adaptés à l'aperçu du composant. Les valeurs par défaut d'enregistrement ne copient pas automatiquement les props d'une instance parente. Voir les compositions connectées pour les détails d'enregistrement et d'extraction.

Placer le timing directement sur le composant

Évitez un <Sequence> séparé autour d'un composant qui accepte déjà des props de timing. Les composants interactifs intégrés et les composants personnalisés créés avec wrapInSequence: true peuvent recevoir name, from, durationInFrames, trimBefore, playbackRate et premountFor directement.

<LowerThird
  name="Tiers inférieur"
  from={30}
  durationInFrames={90}
  accentColor="#0b84f3"
>
  Jane Doe, Conceptrice de produits
</LowerThird>

Lors de la suppression d'une séquence redondante, déplacez son timing et son nom vers l'enfant. Conservez tout timing enfant existant ; ne remplacez pas et n'appliquez pas deux fois les décalages. Un appel useCurrentFrame() à l'intérieur du composant lit son image locale, tandis qu'une expression de style sur le site d'appel utilise toujours l'image de l'appelant. Conservez cette distinction lors du déplacement des styles d'animation.

Conservez un <Sequence> lorsqu'il fournit un timing partagé pour plusieurs frères, remplace les dimensions pour useVideoConfig(), ou encapsule un composant qui ne gère pas le timing. Conservez <Series.Sequence> pour la mise en page consécutive et <TransitionSeries.Sequence> pour les transitions ; les props from directes ne remplacent pas ces comportements.

Donner à chaque élément modifiable son propre nœud JSX

Le Studio édite le nœud source JSX qui a créé un élément. Si plusieurs éléments d'exécution proviennent du même nœud JSX, ils partagent une seule cible d'édition source.

Pour chaque enregistrement de composition, clip, scène, couche ou séquence qui doit être modifiable individuellement, écrivez un nœud JSX séparé et conservez ses props modifiables sur ce nœud. Cela s'applique à <Composition>, <Still>, les composants multimédia intégrés, <Sequence>, <Series.Sequence>, <TransitionSeries.Sequence> et les composants personnalisés.

Par exemple, écrivez une chronologie modifiable comme ceci :

<Series>
  <Series.Sequence name="Introduction" durationInFrames={90}>
    <Introduction />
  </Series.Sequence>
  <Series.Sequence name="Démo" durationInFrames={150}>
    <Demo />
  </Series.Sequence>
</Series>

Un .map() ou une autre boucle programmatique créerait plusieurs éléments d'exécution à partir d'un seul nœud source JSX. Cela est approprié pour une sortie répétée qui est intentionnellement contrôlée comme un modèle unique, comme des barres de visualisation ou des particules. Ce n'est pas approprié lorsque les instances nécessitent des ID ou noms, props, métadonnées, timing, ordre, suppression ou duplication indépendants dans le Studio.

Rendre un élément HTML interactif en utilisant Interactive

Chaque élément HTML et SVG (sauf <Img>, qui est déjà interactif) comme <div> peut être rendu interactif en utilisant Interactive :

<Interactive.Div
  name="Carte de vœux"
  style={{fontSize: 80, padding: 24}}
>
  Bonjour
</Interactive.Div>

Cela permet de définir des styles et des images clés dans le Studio. Soyez raisonnable : si un composant a de nombreux éléments, la chronologie pourrait devenir désordonnée.

Privilégier le texte en ligne

Si le texte est fixe et utilisé une seule fois, écrivez-le directement à l'intérieur de l'élément interactif au lieu de l'extraire dans une constante.

// 👍 La copie fixe reste modifiable
<Interactive.Div name="Titre">
  Bonnes pratiques Remotion
</Interactive.Div>

Utilisez une prop ou une variable uniquement lorsque le texte est dynamique ou réutilisé.

Donner aux éléments interactifs un nom descriptif

Ajoutez une prop name aux éléments pour les rendre facilement identifiables. Évitez les noms calculés ; codifiez-les en dur.

<>
  <Interactive.Div name="Titre héros" style={{fontSize: 80}}>
    Jour de lancement
  </Interactive.Div>
  <Img name="Avatar" src="https://remotion.media/image.jpeg" />
  <Video name="Arrière-plan" src="https://remotion.media/video.mp4" />
  <Interactive.Div name="Titre">
    Jour de lancement
  </Interactive.Div>
</>

Conserver tous les styles CSS en ligne

La meilleure façon est de simplement passer un objet simple à style - sans référence à des constantes, sans décomposition d'objet, sans mathématiques.

<Interactive.Div
  style={{
    fontSize: 80,
    color: 'red',
  }}
>
  Bonjour le monde !
</Interactive.Div>
const baseStyle = useMemo(() => {
  return {
    fontSize: 12 // ❌ Les styles non en ligne ne sont pas pris en charge
  }
}, []);

<Interactive.Div
  style={{
    ...baseStyle, // ❌ La décomposition n'est pas prise en charge
    color: RED, // ❌ La référence à des constantes n'est pas prise en charge
    scale: frame * 10 // ❌ Les mathématiques ne sont pas prises en charge
  }}
>
  Bonjour le monde !
</Interactive.Div>

Animer en utilisant interpolate()

Écrivez les animations sous forme d'appels interpolate() en ligne sur la propriété qui change. La plage de sortie, l'accélération, l'extrapolation et la propriété output doivent utiliser des valeurs codées en dur.

La plage d'entrée peut également utiliser durationInFrames, fps, width et height déstructurés directement de useVideoConfig(). Les identifiants simples comme durationInFrames, la multiplication par un nombre comme 2 * fps ou fps * 2, et la soustraction d'un nombre comme durationInFrames - 1 sont pris en charge.

const {fps, durationInFrames} = useVideoConfig();

// 👍 Les valeurs en ligne peuvent être standardisées et animées par images clés
<Interactive.Div
  name="Carte produit"
  style={{
    color: 'white',
    fontSize: 80,
    scale: interpolate(frame, [0, fps], [0, 1], {
      easing: Easing.spring({damping: 200}),
      output: 'perceptual-scale',
      extrapolateLeft: 'clamp',
      extrapolateRight: 'clamp'
    }),
    rotate: interpolate(frame, [0, 1 * fps], ['0deg', '20deg'], {
      easing: Easing.spring({damping: 200}),
      extrapolateLeft: 'clamp',
      extrapolateRight: 'clamp'
    }),
    translate: interpolate(
      frame,
      [durationInFrames - 30, durationInFrames],
      ['0px 0px', '0px 120px'],
      {
        easing: Easing.spring({damping: 200}),
        output: 'perceptual-scale',
        extrapolateLeft: 'clamp',
        extrapolateRight: 'clamp'
      }
    ),
  }}
/>
const translateY = interpolate(frame, [0, 30], [0, 120]); // ❌ Les mathématiques doivent être directement dans le balisage

<Interactive.Div
  name="Carte produit"
  style={{
    translate: translateY, // ❌ Seuls les appels interpolate() en ligne sont pris en charge,
    rotate: interpolate(frame, [start, start + 10], [0, Math.PI]), // ❌ Impossible d'utiliser des mathématiques avec des variables arbitraires, impossible d'utiliser des constantes
    scale
  }}
/>

Types de propriétés de sortie pris en charge

Utilisez la propriété output sur interpolate() pour que le Studio connaisse l'unité :

Valeur de sortiePropriétés CSS typiquesLorsque l'intervalle de sortie...
'number' (défaut)opacity...contient des nombres (par exemple [0, 1])
'perceptual-scale'scale, translate...contient des nombres (par exemple [0, 1])
'degrees'rotate...contient des nombres ou unités deg
'length'Largeur, hauteur, margin, padding...contient des nombres ou unités px / %

'perceptual-scale' est particulièrement important pour les transformations : il garantit que l'échelle et la translation sont interpolées correctement sur le plan perceptuel. Utilisez-le pour scale, translate, translateX et translateY.

Ajouter des noms aux éléments pour les rendre faciles à trouver dans le Studio

Préfixez les noms avec un terme général et un terme spécifique, en utilisant la capitalisation.

<Interactive.Div name="Titre : Principale" /> // 👍
<Interactive.Div name="Titre : Secondaire" /> // 👍

Gardez les noms distinctifs même après avoir supprimé les préfixes.

<Interactive.Div name="Carte produit : Image" />
<Interactive.Div name="Carte produit : Étiquette" />
<Interactive.Div name="Carte produit : Fond" />

Utilisez le formatage pour que les noms soient visuellement décalés. Utilisez la même casse pour chaque élément.

Suivre les directives de balisage spécifiques au type

Les directives suivantes offrent une interactivité pour les types de composants courants.

Séquences et séries

L'empaquetage et le retrait des séquences doivent être en ligne.

<Sequence name="Logos" from={60} durationInFrames={30}>
  <Logo />
</Sequence>
<Series>
  <Series.Sequence name="Scène 1" durationInFrames={60}>
    <Scene1 />
  </Series.Sequence>
</Series>

Transitions

Utilisez TransitionSeries avec des séquences nommées distinctes pour chaque scène, pas un seul nœud avec un accessoire timeline.

<TransitionSeries>
  <TransitionSeries.Sequence name="Scène 1" durationInFrames={60}>
    <Scene1 />
  </TransitionSeries.Sequence>
  <TransitionSeries.Sequence name="Scène 2" durationInFrames={60}>
    <Scene2 />
  </TransitionSeries.Sequence>
</TransitionSeries>

Composants Iframe, Audio et Vidéo

Ajoutez toujours un nom à ces éléments interactifs intégrés.

<Interactive.Iframe
  name="Intégration"
  src="https://remotion.dev"
  style={{width: 1280, height: 720}}
/>

<Audio
  name="Bande son"
  src="https://example.com/audio.mp3"
  volume={0.5}
/>

<Video
  name="Clip B-Roll"
  src="https://example.com/video.mp4"
/>

Transparence alpha d'une vidéo / Images

L'élément <Img> est déjà interactif. N'utilisez pas Interactive.Img.

Pour le média avec transparence alpha :

<Img
  name="Image alpha"
  src="https://example.com/image.png"
  style={{opacity: 0.5}}
/>

Utilisez la prop name sur <Img> avec la même approche de nommage. Les images doivent avoir des noms descriptifs dans le même format que les autres éléments interactifs.

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

Skills associés