Durch die spezifische Strukturierung von Remotion-Markup kann das Remotion Studio die Code-Struktur erkennen und macht es interaktiv:
- Ermöglicht die Auswahl von Elementen durch Klicken
- Ermöglicht Drag-and-Drop, Größenänderung und Rotation
- Bearbeitung der CSS-Stile
- Macht Keyframes und Easing-Werte editierbar
Wenn das Markup für das Studio zu komplex ist, um es interaktiv zu machen, werden die Werte ausgegraut.
Interaktive Komponenten mit eigenen Zeitachsen bevorzugen
Erstelle neue Kompositionen mit Track, verbundenen Kompositionen und Interactive.create().
Setze layout explizit auf 'absolute-fill' für Szenen oder 'none' für begrenzte Elemente. Registriere dieselben exportierten Szenen- und wiederverwendbaren Elementkomponenten mit Composition.
Beginne mit dem vollständigen Track + verbundene Kompositionen Beispiel. Es enthält das Element, die Szene, die übergeordnete Zeitachse und die Root-Registrierungen.
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>
);
};
Füge Hintergrund- und Ausrichtungsstile auf jeder Szeneninstanz hinzu, wie im vollständigen Beispiel gezeigt. Behalte reine Layout-Container als einfaches HTML.
Schema-Felder auswählen
Jeder Schlüssel im Schema ist ein Prop, den das Studio an der Aufrufstelle lesen und bearbeiten kann. Props, die nicht im Schema sind, funktionieren trotzdem, sind aber im Studio nicht bearbeitbar. Schlüssel können Punktnotation verwenden, wie z. B. style.color.
| Typ | Verwendung für | Keyframable |
|---|---|---|
string | Zeichenketten, wie Titel, Eingabeaufforderung oder Code-Snippet | Nein |
number | Zahlen, optional mit min, max, step, integer | Ja |
boolean | Ein/Aus-Schalter | Ja (halten) |
color | CSS-Farbzeichenketten | Ja |
enum | Eine Auswahl zwischen variants, jede mit eigenem verschachteltem Schema | Opt-in (halten) |
array | Listen von Zahlen, Farben, Enums und mehr | Nein |
asset | Medienquellen, optional mit assetType | Nein |
font-family | CSS-Schriftfamilie | Nein |
font-weight | Schriftstärke | Ja |
translate, scale, rotation-css, rotation-degrees, transform-origin | Transformationen | Ja |
uv-coordinate | Ein normalisierter [x, y] Punkt auf dem Element | Ja |
svg-path | SVG-Pfaddaten | Ja |
remotion-captions | Caption[]-Daten | Nein |
hidden | Ein Wert, der außerhalb der Steuerelemente gehalten wird | — |
Jedes Feld benötigt einen default-Wert und sollte eine description haben, die das Studio als Label anzeigt. Setze keyframable: false, um ein statisches Steuerelement anzuzeigen.
Gib Inhalt und Erscheinungsbild pro Instanz frei, wie den Text und eine Akzentfarbe. Füge keine Felder für style.translate, style.scale, style.rotate, style.transformOrigin und style.opacity hinzu: Interactive.create() fügt sie automatisch hinzu.
Um CSS-Eigenschaften des Roots pro Instanz bearbeitbar zu machen, verteile die integrierten Schema-Fragmente:
const cardSchema = {
...Interactive.textSchema, // style.color, style.fontSize, style.fontWeight, ...
...Interactive.backgroundSchema, // style.backgroundColor
...Interactive.borderRadiusSchema, // style.borderRadius, ...
} as const satisfies InteractivitySchema;
Ebenfalls verfügbar: Interactive.borderSchema und Interactive.captionsSchema für Komponenten, die Captions akzeptieren.
Für Komponenten, die React.ReactNode-Kinder akzeptieren, füge ...Interactive.childrenSchema hinzu.
Es bietet Steuerelemente für Kinderinhalte und kann sich weiterentwickeln, um reichhaltigere Inhalte zu unterstützen.
Derzeit wird ein Zeichenkettenfeld mit der Bezeichnung "Text" und einem Standardwert von '' verwendet.
Wenn eine Komponente nur Zeichenketten als Kinder erfordert, deklariere stattdessen ein explizites children-Feld mit type: 'string'.
Interactive.textSchema steuert Typografiestile; childrenSchema steuert Inhalte.
Das Kinder-Fragment ist nicht in baseSchema enthalten oder wird automatisch zu benutzerdefinierten Komponenten hinzugefügt.
Verschachteltes Markup und berechnete Kinder sind derzeit schreibgeschützt.
text-content ist ein veralteter Alias für den Feldtyp string.
Siehe InteractivitySchema für alle Optionen.
Wiederverwendbare Komponenten als verbundene Kompositionen registrieren
Registriere Szenen und wiederverwendbare Elemente als eigenständige Kompositionen. Das Studio nennt diese verbundene Kompositionen: Sie können in ihrer eigenen Zeitachse geöffnet werden, während sie dieselbe Komponentenimplementierung mit dem übergeordneten Video teilen.
Definiere erforderliche Stile und lade Schriftarten innerhalb der Komponente, damit sie ohne ihr übergeordnetes Element funktioniert. Siehe übergeordnete Unabhängigkeit.
Registriere dieselbe exportierte Komponentenreferenz, die das übergeordnete Element rendert. Für das obige Beispiel verwende component={Chapter}, nicht ChapterInner oder einen Inline-Wrapper.
Interactive.create() stellt die Sequenz bereit, sodass kein zusätzliches <Sequence> für die Verbindung benötigt wird.
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',
},
}}
/>
);
Wähle eine eindeutige ID, repräsentative Inline-Standardwerte sowie geeignete Abmessungen, fps und Dauer für die Vorschau der Komponente. Registrierungsstandardwerte kopieren nicht automatisch Props von einer übergeordneten Instanz. Siehe verbundene Kompositionen für Details zur Registrierung und Extraktion.
Timing direkt auf die Komponente setzen
Vermeide ein separates <Sequence> um eine Komponente, die bereits Timing-Props akzeptiert. Integrierte interaktive Komponenten und benutzerdefinierte Komponenten, die mit Interactive.create() erstellt wurden, können name, from, durationInFrames, trimBefore und playbackRate direkt empfangen.
<Chapter
name="Opening scene"
from={30}
durationInFrames={90}
style={{opacity: 0.9}}
title="A new perspective"
/>
Für gemeinsames Szenen-Timing gruppiere den Inhalt in einer mit Interactive.create() erstellten Komponente und timeframe diese Instanz. Verwaltete Roots akzeptieren auch width und height für useVideoConfig().
Verwende <Track>, um Elemente in dieselbe Studio-Zeitachsenzeile zu setzen.
Verwende <TransitionSeries>, wenn Szenen sequenziell sind.
Gib jedem unabhängig bearbeitbaren Element einen eigenen JSX-Knoten
Das Studio bearbeitet den JSX-Quellknoten, der ein Element erstellt hat. Wenn mehrere Laufzeitelemente vom selben JSX-Knoten stammen, teilen sie sich ein gemeinsames Quellbearbeitungsziel.
Für jede Kompositionsregistrierung, Clip, Szene, Ebene oder Sequenz, die eigenständig bearbeitbar sein soll, schreibe einen separaten JSX-Knoten und behalte seine bearbeitbaren Props auf diesem Knoten. Dies gilt für <Composition>, <Still>, integrierte Medienkomponenten, <Sequence>, <TransitionSeries.Sequence> und benutzerdefinierte Komponenten.
Erstelle zum Beispiel eine bearbeitbare Zeitachse wie folgt:
import { Track } from "remotion";
<Track name="Scenes">
<Introduction name="Introduction" durationInFrames={90} />
<Demo name="Demo" from={90} durationInFrames={150} />
</Track>
Ein .map() oder eine andere programmatische Schleife würde mehrere Laufzeitelemente aus einem JSX-Quellknoten erstellen. Das ist für wiederholte Ausgaben geeignet, die absichtlich als eine Vorlage gesteuert werden, wie Visualisierungsbalken oder Partikel. Es ist nicht geeignet, wenn die Instanzen unabhängige IDs oder Namen, Props, Metadaten, Timing, Reihenfolge, Löschung oder Duplizierung im Studio benötigen.
Ein HTML-Element mit Interactive interaktiv machen
Jedes HTML- und SVG-Element (außer <Img>, es ist bereits interaktiv) wie <div> kann mit Interactive interaktiv gemacht werden:
<Interactive.Div
name="Greeting card"
style={{fontSize: 80, padding: 24}}
>
Hello
</Interactive.Div>
Dies ermöglicht das Festlegen von Stilen und Keyframes im Studio. Sei vernünftig: Wenn eine Komponente viele Elemente hat, könnte die Zeitachse unübersichtlich werden.
Inline-Text bevorzugen
Wenn Text fest ist und nur einmal verwendet wird, schreibe ihn direkt in das interaktive Element, anstatt ihn in eine Konstante zu extrahieren.
// 👍 Fester Kopie bleibt bearbeitbar
<Interactive.Div name="Title">
Remotion Best Practices
</Interactive.Div>
Verwende ein Prop oder eine Variable nur, wenn der Text dynamisch oder wiederverwendet wird.
Gib interaktiven Elementen einen beschreibenden Namen
Füge ein name-Prop zu Elementen hinzu, um sie leicht identifizierbar zu machen.
Vermeide berechnete Namen, hardcodiere sie.
<>
<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>
</>
Alle CSS-Stile inline halten
Der beste Weg ist, einfach ein einfaches Objekt an style zu übergeben – ohne Verweis auf Konstanten, ohne Objekt-Spreading, ohne Mathematik.
<Interactive.Div
style={{
fontSize: 80,
color: 'red',
}}
>
Hello World!
</Interactive.Div>
const baseStyle = useMemo(() => {
return {
fontSize: 12 // ❌ Nicht-Inline-Stile werden nicht unterstützt
}
}, []);
<Interactive.Div
style={{
...baseStyle, // ❌ Spread wird nicht unterstützt
color: RED, // ❌ Verweis auf Konstanten wird nicht unterstützt
scale: frame * 10 // ❌ Mathematik wird nicht unterstützt
}}
>
Hello World!
</Interactive.Div>
Mit interpolate() animieren
Schreibe Animationen als Inline-interpolate()-Aufrufe auf der Eigenschaft, die sich ändert.
Der Ausgabebereich, das Easing, die Extrapolation und die output-Eigenschaft sollten hartcodierte Werte verwenden.
Der Eingabebereich kann zusätzlich durationInFrames, fps, width und height verwenden, die direkt aus useVideoConfig() destrukturiert wurden. Bloße Bezeichner wie durationInFrames, Multiplikation mit einer Zahl wie 2 * fps oder fps * 2 und Subtraktion einer Zahl wie durationInFrames - 1 werden unterstützt.
const {fps, durationInFrames} = useVideoConfig();
// 👍 Inline-Werte können standardisiert und keyframed werden
<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]); // ❌ Mathematik sollte direkt im Markup sein
<Interactive.Div
name="Product card"
style={{
translate: translateY, // ❌ Nur Inline-interpolate()-Aufrufe werden unterstützt,
rotate: interpolate(frame, [start, start + 10], [0, Math.PI]), // ❌ Mathematik mit beliebigen Variablen nicht möglich, keine Konstanten erlaubt
scale: interpolate(anyVariable, [0, 30], [0, 1]) // ❌ Kann nur die `frame`-Variable interpretieren.
}}
/>
SVG-Pfade mit Interactive.Path bearbeitbar halten
Verwende <Interactive.Path> aus remotion anstelle von <path> innerhalb eines SVG, um den Pfad visuell bearbeitbar zu machen.
Installiere @remotion/paths für Pfadinterpolation und Studio-Pfad-Keyframes:
bunx remotion add @remotion/paths
Wenn die Geometrie statisch sein soll, setze die Pfadzeichenkette direkt in das d-Prop. Extrahiere sie nicht in eine Konstante.
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>
Pfade mit Inline interpolieren lassen
… [für die Übersetzung abgeschnitten]
