Communitygithub.com

jeffersonmendo/remotion-tryslides

Structure le balisage Remotion pour l'interactivité

Qu'est-ce que remotion-tryslides ?

Cette compétence permet aux utilisateurs de Remotion Studio de rendre leurs compositions vidéo interactives en structurant le balisage d'une manière spécifique. Elle permet de sélectionner des éléments en cliquant, de les glisser-déposer, de les redimensionner, de les faire pivoter, d'éditer les styles CSS et de modifier les images clés et les valeurs d'easing directement dans le Studio. La compétence guide sur l'utilisation de composants interactifs comme `Track`, `Interactive.create()`, et les compositions connectées, ainsi que sur la gestion du timing, des schémas de propriétés et des animations avec `interpolate()`. Elle s'applique à tout projet utilisant Remotion et est cruciale pour les développeurs qui souhaitent créer des vidéos programmatiques avec une interface utilisateur riche et modifiable sans quitter le Studio.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/jeffersonmendo/remotion-tryslides/tree/HEAD/.agents/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

remotion-tryslides preview

Documentation

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

  • Permettre la sélection des é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'easing éditables

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

Préférer les composants interactifs avec leurs propres timelines

Construisez de nouvelles compositions avec Track, des compositions connectées, et Interactive.create().

Définissez layout explicitement à 'absolute-fill' pour les scènes ou 'none' pour les éléments délimités. Enregistrez la même scène exportée et les composants d'élément réutilisables avec Composition.

Commencez par l'exemple complet Track + compositions connectées. Il inclut l'élément, la scène, la timeline parente, et les enregistrements racine.

import {Track, useVideoConfig} from 'remotion';
import {Chapter} from './Chapter';

export const MyVideo = () => {
  const {fps} = useVideoConfig();

  return (
    <Track name="Chapitres">
      <Chapter
        name="Ouverture"
        durationInFrames={3 * fps}
        title="Introduction"
      />
      <Chapter
        name="Fonctionnalité"
        from={3 * fps}
        durationInFrames={4 * fps}
        title="Nouvelles fonctionnalités"
      />
    </Track>
  );
};

Placez les styles d'arrière-plan et d'alignement sur chaque instance de scène, comme montré dans l'exemple complet. Gardez les conteneurs de mise en page uniquement comme HTML simple.

Choisir les champs du schéma

Chaque clé dans le schéma est une propriété que le Studio peut lire et éditer au niveau de l'appel. Les propriétés 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 pourKeyframable
stringChaînes de caractères, comme un titre, une invite ou un extrait de codeNon
numberNombres, avec optionnellement min, max, step, integerOui
booleanInterrupteurs On/OffOui (maintien)
colorChaînes de couleur CSSOui
enumUn choix entre variants, chacun avec son propre schéma imbriquéOpt-in (maintien)
arrayListes de nombres, couleurs, énumérations et plusNon
assetSources médias, avec assetType optionnelNon
font-familyFamille de police CSSNon
font-weightGraisse de policeOui
translate, scale, rotation-css, rotation-degrees, transform-originTransformationsOui
uv-coordinateUn point normalisé [x, y] sur l'élémentOui
svg-pathDonnées de chemin SVGOui
remotion-captionsDonnées Caption[]Non
hiddenUne valeur cachée des contrôles—

Chaque champ a besoin d'une default et devrait 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'accent. N'ajoutez pas de champs pour style.translate, style.scale, style.rotate, style.transformOrigin et style.opacity : Interactive.create() les ajoute automatiquement.

Pour rendre les propriétés CSS de la racine modifiables par instance, étalez 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;

Sont également disponibles : Interactive.borderSchema, et Interactive.captionsSchema pour les composants qui acceptent des légendes. Pour les composants qui acceptent des enfants React.ReactNode, ajoutez ...Interactive.childrenSchema. Il fournit des contrôles pour le contenu des enfants et peut évoluer pour prendre en charge un contenu plus riche. Actuellement, il utilise un champ chaîne étiqueté "Texte" avec une valeur par défaut de ''. Si un composant nécessite des enfants uniquement sous forme de chaîne, déclarez un champ children explicite avec type: 'string' à la place. Interactive.textSchema contrôle les styles typographiques ; childrenSchema contrôle le contenu. Le fragment enfants n'est pas inclus dans baseSchema et n'est pas automatiquement ajouté aux composants personnalisés. Le balisage imbriqué et les enfants calculés sont actuellement en lecture seule. text-content est un alias obsolète pour le type de champ string. Voir InteractivitySchema pour toutes les options.

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

Enregistrez les scènes et les éléments réutilisables en tant que compositions autonomes. Le Studio appelle ces compositions connectées : elles peuvent être ouvertes dans leur propre timeline tout en partageant la même implémentation de composant avec la vidéo parent.

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 parent.

Enregistrez la même référence de composant exportée que celle rendue par le parent. Pour l'exemple ci-dessus, utilisez component={Chapter}, pas ChapterInner ou un wrapper en ligne. Interactive.create() fournit la séquence, donc aucun <Sequence> supplémentaire n'est nécessaire pour la connexion.

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

export const RemotionRoot = () => (
  <Composition
    id="Chapter"
    component={Chapter}
    width={1280}
    height={720}
    fps={30}
    durationInFrames={90}
    defaultProps={{
      title: 'Une nouvelle perspective',
      style: {
        backgroundColor: '#111111',
        justifyContent: 'center',
        alignItems: 'center',
      },
    }}
  />
);

Choisissez un ID unique, des valeurs par défaut en ligne représentatives et des dimensions, fps et durée adaptés à la prévisualisation du composant. Les valeurs par défaut d'enregistrement ne copient pas automatiquement les propriétés d'une instance parent. Voir les compositions connectées pour les détails d'enregistrement et d'extraction.

Mettre le timing directement sur le composant

Évitez un <Sequence> séparé autour d'un composant qui accepte déjà les propriétés de timing. Les composants interactifs intégrés et les composants personnalisés créés avec Interactive.create() peuvent recevoir name, from, durationInFrames, trimBefore et playbackRate directement.

<Chapter
  name="Scène d'ouverture"
  from={30}
  durationInFrames={90}
  style={{opacity: 0.9}}
  title="Une nouvelle perspective"
/>

Pour le timing partagé des scènes, regroupez le contenu dans un composant créé avec Interactive.create() et chronométrez cette instance. Les racines gérées acceptent également width et height pour useVideoConfig().

Utilisez <Track> pour placer des éléments sur la même ligne de timeline du Studio. Utilisez <TransitionSeries> lorsque les scènes sont séquentielles.

Donner à chaque élément modifiable indépendant 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, calque ou séquence qui doit être modifiable individuellement, écrivez un nœud JSX séparé et conservez ses propriétés modifiables sur ce nœud. Cela s'applique à <Composition>, <Still>, les composants médias intégrés, <Sequence>, <TransitionSeries.Sequence> et les composants personnalisés.

Par exemple, créez une timeline modifiable comme ceci :

import { Track } from "remotion";

<Track name="Scènes">
  <Introduction name="Introduction" durationInFrames={90} />
  <Demo name="Démo" from={90} durationInFrames={150} />
</Track>

Un .map() ou une autre boucle programmatique créerait plusieurs éléments d'exécution à partir d'un seul nœud source JSX. C'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 ont besoin d'ID ou de noms, de propriétés, de métadonnées, de timing, d'ordre, de suppression ou de duplication indépendants dans le Studio.

Rendre un élément HTML interactif avec Interactive

Chaque élément HTML et SVG (sauf <Img>, il 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 les styles et les images clés dans le Studio. Soyez raisonnable, si un composant a de nombreux éléments, la timeline pourrait devenir désordonnée.

Préférer 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">
  Meilleures pratiques Remotion
</Interactive.Div>

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

Donner aux éléments interactifs un nom descriptif

Ajoutez une propriété name aux éléments pour les rendre facilement identifiables. Évitez les noms calculés, codez-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>
</>

Garder tous les styles CSS en ligne

La meilleure façon est de simplement passer un objet simple à style - pas de référence à des constantes, pas d'étalement d'objet, pas de calcul.

<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, // ❌ L'étalement n'est pas pris en charge
    color: RED, // ❌ La référence à des constantes n'est pas prise en charge
    scale: frame * 10 // ❌ Les calculs ne sont pas pris en charge
  }}
>
  Bonjour le monde !
</Interactive.Div>

Animer avec interpolate()

Écrivez les animations sous forme d'appels interpolate() en ligne sur la propriété qui change. La plage de sortie, l'easing, 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 nus comme durationInFrames, la multiplication avec 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 keyframées
<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 calculs 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 calculs avec des variables arbitraires, impossible d'utiliser des constantes
    scale: interpolate(anyVariable, [0, 30], [0, 1]) // ❌ Ne peut interpréter que la variable `frame`.
  }}
/>

Garder les chemins SVG modifiables avec Interactive.Path

Utilisez <Interactive.Path> de remotion au lieu de <path> à l'intérieur d'un SVG pour rendre le chemin visuellement modifiable.

Installez @remotion/paths pour l'interpolation de chemin et les images clés de chemin dans le Studio :

bunx remotion add @remotion/paths

Si la géométrie est destinée à être statique, mettez la chaîne du chemin directement dans la propriété d. Ne l'extrayez pas dans une constante.

import {Interactive} from 'remotion';

<Interactive.Svg width={300} height={300} viewBox="0 0 300 300">
  <Interactive.Path
    name="Triangle"
    d="M 40 40 L 260 40 L 150 260 Z"
    fill="#0b84f3"
  />
</Interactive.Svg>

Morphing de chemins en utilisant inl

…

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

Skills associés