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.
| Type | Utilisation | Images clés possibles |
|---|---|---|
string | Chaînes de caractères, comme un titre, une invite ou un extrait de code | Non |
number | Nombres, avec min, max, step, integer optionnels | Oui |
boolean | Interrupteurs marche/arrêt | Oui (maintien) |
color | Chaînes de couleur CSS | Oui |
enum | Un choix entre variants, chacun avec son propre schéma imbriqué | Optionnel (maintien) |
array | Listes de nombres, couleurs, énumérations et plus | Non |
asset | Sources médiatiques, avec assetType optionnel | Non |
font-family | Famille de police CSS | Non |
font-weight | Graisse de police | Oui |
translate, scale, rotation-css, rotation-degrees, transform-origin | Transformations | Oui |
uv-coordinate | Un point [x, y] normalisé sur l'élément | Oui |
svg-path | Données de chemin SVG | Oui |
remotion-captions | Données Caption[] | Non |
hidden | Une 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
...
