Communitygithub.com

AlexGit92s/Remotion2.0

Remotion-Markup für Interaktivität strukturieren

Was ist Remotion2.0?

Dieses Skill beschreibt, wie Remotion-Markup strukturiert werden muss, damit das Remotion Studio interaktiv wird. Es ermöglicht das Auswählen von Elementen per Klick, Drag & Drop, Größenänderung, Rotation sowie die Bearbeitung von CSS-Stilen und Keyframes. Das Skill unterstützt die Plattformen Remotion Studio und Code-Editoren wie VS Code. Es erklärt die Verwendung von `Interactive.withSchema({wrapInSequence: true})` für eigene Szenen und Komponenten, die Registrierung wiederverwendbarer Komponenten als verbundene Kompositionen, die direkte Übergabe von Timing-Eigenschaften an Komponenten und die Erstellung interaktiver HTML-Elemente mit `Interactive`. Zudem werden bewährte Praktiken wie die Verwendung von Inline-Stilen, deskriptiven Namen für interaktive Elemente und die Animation mit `interpolate()` direkt im Markup empfohlen.

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

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Vorschau

Aus dem Skill-README

Remotion2.0 preview

Dokumentation

Durch das Schreiben von Remotion-Markup in einer bestimmten Weise erkennt das Remotion Studio die Struktur des Codes und macht ihn interaktiv:

  • Ermöglicht das Auswählen von Elementen durch Klicken
  • Ermöglicht Drag & Drop, Größenänderung und Rotation
  • Bearbeitung der CSS-Stile
  • Macht Keyframes und Easing-Werte bearbeitbar

Wenn das Markup zu komplex für das Studio ist, um es interaktiv zu machen, werden die Werte ausgegraut.

Interaktive Komponenten mit eigenen Zeitleisten bevorzugen

Verwenden Sie Interactive.withSchema({wrapInSequence: true}) für benutzerdefinierte Szenen, Karten, Titel und andere visuelle Komponenten, deren Props pro Instanz bearbeitbar sein sollen. Machen Sie sinnvolle Inhalts- und Darstellungssteuerungen in einem InteractivitySchema verfügbar. Halten Sie dekorative Implementierungsdetails innerhalb der Komponente.

Die Komponente muss style akzeptieren und an eine visuelle Wurzel weiterleiten. Behalten Sie eine gemeinsame Wurzel bei, wenn Transformationen, Zuschnitt oder Deckkraft alle Ebenen betreffen sollen. Reduzieren Sie redundante innere Wrapper, wenn deren Stile auf ein vorhandenes Element verschoben werden können, ohne Layout oder Animation zu ändern.

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: 'Text'},
  accentColor: {
    type: 'color',
    default: '#0b84f3',
    description: 'Akzentfarbe',
  },
} as const satisfies InteractivitySchema;

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

Das Weiterleiten des injizierten style innerhalb der Komponente ist erforderlich; halten Sie bearbeitbare Stile inline an der Aufrufstelle der Komponente.

Schemafelder auswählen

Jeder Schlüssel im Schema ist ein Prop, das Studio an der Aufrufstelle lesen und bearbeiten kann. Props, die nicht im Schema sind, funktionieren weiterhin, sind aber im Studio nicht bearbeitbar. Schlüssel können Punktnotation verwenden, z. B. style.color.

TypVerwendung fürKeyframable
text-contentText, z. B. ein TitelNein
numberZahlen, mit optionalen min, max, step, integerJa
booleanEin/Aus-SchalterJa (halten)
colorCSS-FarbstringsJa
enumEine Auswahl zwischen variants, jede mit eigenem SchemaOptional (halten)
arrayListen von Zahlen, Farben, Enums und mehrNein
assetMedienquellen, mit optionalem assetTypeNein
font-familyCSS-SchriftfamilieNein
font-weightSchriftstärkeJa
translate, scale, rotation-css, rotation-degrees, transform-originTransformationenJa
uv-coordinateEin normalisierter [x, y]-Punkt auf dem ElementJa
svg-pathSVG-PfaddatenJa
remotion-captionsCaption[]-DatenNein
hiddenEin Wert, der in den Steuerelementen ausgeblendet bleibt—

Jedes Feld benötigt einen default-Wert und sollte eine description haben, die Studio als Beschriftung anzeigt. Setzen Sie keyframable: false, um ein statisches Steuerelement anzuzeigen.

Machen Sie Inhalt und Darstellung pro Instanz verfügbar, z. B. den Text und eine Akzentfarbe. Fügen Sie keine Felder für style.translate, style.scale, style.rotate, style.transformOrigin und style.opacity hinzu: wrapInSequence: true fügt sie bereits hinzu.

Um CSS-Eigenschaften der Wurzel pro Instanz bearbeitbar zu machen, breiten Sie die integrierten Schemafragmente aus:

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 Untertitel akzeptieren. Siehe InteractivitySchema für alle Optionen.

Wiederverwendbare Komponenten als verbundene Kompositionen registrieren

Registrieren Sie umfangreiche Szenen und wiederverwendbare Komponenten mit eigenen Ebenen oder Animationen als eigenständige Kompositionen. Studio nennt diese verbundene Kompositionen: Sie können in ihrer eigenen Zeitleiste geöffnet werden, während sie dieselbe Komponentenimplementierung wie das übergeordnete Video teilen.

Definieren Sie erforderliche Stile und laden Sie Schriftarten innerhalb der Komponente, damit sie ohne ihr übergeordnetes Element funktioniert. Siehe Elternunabhängigkeit.

Registrieren Sie dieselbe exportierte Komponentenreferenz, die das übergeordnete Element rendert. Verwenden Sie für das obige Beispiel component={LowerThird}, nicht LowerThirdInner oder einen Inline-Wrapper. Bei wrapInSequence: true ist kein zusätzliches <Sequence> für die Verbindung erforderlich.

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, Product Designer',
      accentColor: '#0b84f3',
    }}
  />
);

Wählen Sie eine eindeutige ID, repräsentative Inline-Standardwerte sowie Maße, fps und Dauer, die für die Vorschau der Komponente geeignet sind. 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

Vermeiden Sie ein separates <Sequence> um eine Komponente, die bereits Timing-Props akzeptiert. Integrierte interaktive Komponenten und benutzerdefinierte Komponenten, die mit wrapInSequence: true erstellt wurden, können name, from, durationInFrames, trimBefore, playbackRate und premountFor direkt erhalten.

<LowerThird
  name="Lower third"
  from={30}
  durationInFrames={90}
  accentColor="#0b84f3"
>
  Jane Doe, Product Designer
</LowerThird>

Wenn Sie eine redundante Sequenz entfernen, verschieben Sie deren Timing und Namen auf das Kind. Bewahren Sie vorhandenes Timing des Kinds; überschreiben oder verdoppeln Sie keine Offsets. Ein useCurrentFrame()-Aufruf innerhalb der Komponente liest ihren lokalen Frame, während ein Stil-Ausdruck an der Aufrufstelle den Frame des Aufrufers verwendet. Bewahren Sie diese Unterscheidung beim Verschieben von Animationsstilen.

Behalten Sie einen <Sequence> bei, wenn er gemeinsames Timing für mehrere Geschwister bereitstellt, Abmessungen für useVideoConfig() überschreibt oder eine Komponente umschließt, die kein Timing verarbeitet. Behalten Sie <Series.Sequence> für sequentielle Layouts und <TransitionSeries.Sequence> für Übergänge bei; direkte from-Props ersetzen diese Verhaltensweisen nicht.

Jedes unabhängig bearbeitbare Element erhält seinen 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 Quellbearbeitungsziel.

Schreiben Sie für jede Kompositionsregistrierung, jeden Clip, jede Szene, Ebene oder Sequenz, die eigenständig bearbeitbar sein soll, einen separaten JSX-Knoten und behalten Sie deren bearbeitbare Props auf diesem Knoten. Dies gilt für <Composition>, <Still>, integrierte Medienkomponenten, <Sequence>, <Series.Sequence>, <TransitionSeries.Sequence> und benutzerdefinierte Komponenten.

Erstellen Sie beispielsweise eine bearbeitbare Zeitleiste wie folgt:

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

Ein .map() oder eine andere programmatische Schleife würde mehrere Laufzeitelemente aus einem JSX-Quellknoten erstellen. Dies ist für wiederholte Ausgaben geeignet, die absichtlich als eine Vorlage gesteuert werden, z. B. 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="Grußkarte"
  style={{fontSize: 80, padding: 24}}
>
  Hallo
</Interactive.Div>

Dadurch können Stile und Keyframes im Studio festgelegt werden. Seien Sie vernünftig; wenn eine Komponente viele Elemente hat, könnte die Zeitleiste unübersichtlich werden.

Inline-Text bevorzugen

Wenn Text fest und nur einmal verwendet wird, schreiben Sie ihn direkt innerhalb des interaktiven Elements, anstatt ihn in eine Konstante zu extrahieren.

// 👍 Fester Text bleibt bearbeitbar
<Interactive.Div name="Titel">
  Remotion Best Practices
</Interactive.Div>

Verwenden Sie ein Prop oder eine Variable nur, wenn der Text dynamisch ist oder wiederverwendet wird.

Interaktiven Elementen einen beschreibenden Namen geben

Fügen Sie ein name-Prop zu Elementen hinzu, um sie leicht identifizierbar zu machen. Vermeiden Sie berechnete Namen, hardcoden Sie sie.

<>
  <Interactive.Div name="Helden-Titel" style={{fontSize: 80}}>
    Launch-Tag
  </Interactive.Div>
  <Img name="Avatar" src="https://remotion.media/image.jpeg" />
  <Video name="Hintergrund" src="https://remotion.media/video.mp4" />
  <Interactive.Div name="Titel">
    Launch-Tag
  </Interactive.Div>
</>

Alle CSS-Stile inline halten

Der beste Weg ist, ein einfaches Objekt an style zu übergeben – ohne Verweise auf Konstanten, ohne Objekt-Spreading, ohne Mathematik.

<Interactive.Div
  style={{
    fontSize: 80,
    color: 'red',
  }}
>
  Hallo Welt!
</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, // ❌ Verweise auf Konstanten werden nicht unterstützt
    scale: frame * 10 // ❌ Mathematik wird nicht unterstützt
  }}
>
  Hallo Welt!
</Interactive.Div>

Mit interpolate() animieren

Schreiben Sie Animationen als Inline-interpolate()-Aufrufe auf der Eigenschaft, die sich ändert. Der Ausgabebereich, das Easing, die Extrapolation und die output-Eigenschaft sollten fest codierte 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="Produktkarte"
  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="Produktkarte"
  style={{
    translate: translateY, // ❌ Nur Inline-interpolate()-Aufrufe werden unterstützt,
    rotate: interpolate(frame, [start, start + 10], [0, Math.PI]), // ❌ Kann keine Mathematik mit beliebigen Variablen verwenden, kann keine Konstanten verwenden
    scale

…

Individual skills in this repo

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

Verwandte Skills