Communitygithub.com

3bkader-gpt/remotion-tiktok-gym-editor

Structurez le balisage Remotion pour le rendre interactif

Qu'est-ce que remotion-tiktok-gym-editor ?

Cette compétence permet aux développeurs utilisant Remotion Studio de structurer leur balisage afin de le rendre pleinement interactif : sélection par clic, glisser-déposer, redimensionnement, rotation, édition des styles CSS, et modification des images clés et des courbes d'interpolation. Elle est conçue pour les agents IA comme Claude Code, Cursor ou Codex, et s'applique à la création de compositions vidéo dynamiques avec Remotion. La compétence explique comment utiliser `Interactive.create()`, `Track`, les compositions connectées, et les composants interactifs. Elle détaille les types de schémas à utiliser pour chaque champ (string, number, boolean, color, enum, array, asset, etc.), avec leurs possibilités de keyframing. Elle insiste sur l'importance de donner à chaque élément éditable son propre nœud JSX, de préférer le texte en ligne, d'attribuer des noms descriptifs aux éléments, de garder les styles CSS en ligne, d'utiliser `interpolate()` pour les animations, et de maintenir les chemins SVG éditables avec `Interactive.Path`. L'objectif est d'optimiser l'interactivité dans le Studio Remotion tout en évitant les structures trop complexes qui griseraient les contrôles.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/3bkader-gpt/remotion-tiktok-gym-editor/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-tiktok-gym-editor preview

Documentation

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

  • Permettre de sélectionner 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'interpolation modifiables

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

Préférez 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 les mêmes composants exportés de scène et d'élément réutilisable 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="Chapters">
      <Chapter
        name="Opening"
        durationInFrames={3 * fps}
        title="Introduction"
      />
      <Chapter
        name="Feature"
        from={3 * fps}
        durationInFrames={4 * fps}
        title="New features"
      />
    </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 en HTML simple.

Choisissez les champs du schéma

Chaque clé dans le schéma est une propriété que le Studio peut lire et éditer à l'endroit 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.

TypeUtilisationImages clés possibles
stringChaînes de caractères, comme un titre, une invite ou un extrait de codeNon
numberNombres, avec min, max, step, integer optionnelsOui
booleanInterrupteurs marche/arrêtOui (maintien)
colorChaînes de couleur CSSOui
enumUn choix entre variants, chacun avec son propre schéma imbriquéOptionnel (maintien)
arrayListes de nombres, couleurs, énumérations et plusNon
assetSources médiatiques, avec assetType optionnelNon
font-familyFamille de police CSSNon
font-weightGraisse de policeOui
translate, scale, rotation-css, rotation-degrees, transform-originTransformationsOui
uv-coordinateUn point [x, y] normalisé 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 nécessite une default et doit avoir une description, que le Studio affiche comme libellé. 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 : Interactive.create() les ajoute automatiquement.

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. 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 de chaîne de caractères étiqueté "Text" avec une valeur par défaut de ''. Si un composant nécessite des enfants uniquement sous forme de chaîne de caractères, 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 ni 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.

Enregistrez 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 les appelle 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 parente.

Définissez les styles requis et chargez les polices à l'intérieur du composant afin 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: 'A new 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 parente. Voir compositions connectées pour les détails d'enregistrement et d'extraction.

Placez le minutage directement sur le composant

Évitez un <Sequence> séparé autour d'un composant qui accepte déjà des propriétés de minutage. 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="Opening scene"
  from={30}
  durationInFrames={90}
  style={{opacity: 0.9}}
  title="A new perspective"
/>

Pour partager le minutage de scène, 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.

Donnez à chaque élément modifiable individuellement 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 de 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édia 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="Scenes">
  <Introduction name="Introduction" durationInFrames={90} />
  <Demo name="Demo" 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. Cela est approprié pour une sortie répétée contrôlée intentionnellement comme un seul modèle, comme des barres de visualisation ou des particules. Ce n'est pas approprié lorsque les instances ont besoin d'ID ou de noms, propriétés, métadonnées, minutage, ordre, suppression ou 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="Greeting card"
  style={{fontSize: 80, padding: 24}}
>
  Hello
</Interactive.Div>

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

Préférez 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.

// 👍 Le texte fixe reste modifiable
<Interactive.Div name="Title">
  Remotion Best Practices
</Interactive.Div>

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

Donnez 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="Hero title" style={{fontSize: 80}}>
    Launch day
  </Interactive.Div>
  <Img name="Avatar" src="https://remotion.media/image.jpeg" />
  <Video name="Background" src="https://remotion.media/video.mp4" />
  <Interactive.Div name="Title">
    Launch day
  </Interactive.Div>
</>

Gardez tous les styles CSS en ligne

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

<Interactive.Div
  style={{
    fontSize: 80,
    color: 'red',
  }}
>
  Hello World!
</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 calculs ne sont pas pris en charge
  }}
>
  Hello World!
</Interactive.Div>

Animez avec interpolate()

Écrivez les animations comme des appels interpolate() en ligne sur la propriété qui change. La plage de sortie, l'interpolation, 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 keyframées
<Interactive.Div
  name="Product card"
  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="Product card"
  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, ni des constantes
    scale: interpolate(anyVariable, [0, 30], [0, 1]) // ❌ Peut seulement interpréter la variable `frame`.
  }}
/>

Gardez 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 Studio :

bunx remotion add @remotion/paths

Si la géométrie est destinée à être statique, placez 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 avec inl

...

Individual skills in this repo

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

Skills associés