VidTSX 2D-Videogenerator
Erzeugen Sie produktionsreife 2D-TSX-Videodateien für VidTSX aus einer Beschreibung einer Einstellung oder eines Videos. Die Dateien sind Remotion-Kompositionen, die VidTSX Frame für Frame rendert. Korrektheit ist daher wichtiger als Cleverness: Ein einziger nicht-monotoner interpolate-Bereich oder ein versehentliches useState bringt den Render zum Absturz.
Dieses Skill deckt 2D-Bewegungsgrafiken ab. 3D-Arbeiten (@remotion/three / React Three Fiber) sind nicht enthalten.
Verwendung dieses Skills
- Klare Einzeleinstellung → direkt die
.tsx-Datei generieren. - Komplexe, mehrfache oder visuell unklare Anfrage → zuerst die Einstellungsaufteilung oder visuelle Richtung in einer kurzen Nachricht bestätigen, dann generieren. Nicht überfragen; eine einzeilige Bestätigung reicht.
- Als tatsächliche
.tsx-Datei ausliefern, nicht als Inline-Code. Diese TSX-Komponenten überschreiten immer 20 Zeilen, und der Benutzer bearbeitet diese Dateien direkt. Standardmäßig eine Einstellung pro Datei (atomar, einfach zu bearbeiten), es sei denn, der Benutzer wünscht eine einzige kombinierte Ausgabe. - Die Datei enthält nur den Komponentencode – die unten stehenden Abschnittskommentare sind willkommen, aber keine Markdown-Umrandungen, kein erklärender Text innerhalb der Datei.
- Render und schau es dir an, bevor du es als erledigt betrachtest – siehe Render überprüfen. Eine Einstellung, über die du nur nachgedacht hast, ist nicht fertig; ein Standbild (und bei Enthüllungen/Scrollen Frames an jedem Cue) ist der Maßstab.
Ausgabespezifikation
Formatvorlagen
| Format | Breite | Höhe | Verwendung |
|---|---|---|---|
| horizontal | 1920 | 1080 | YouTube, Präsentationen |
| vertikal | 1080 | 1920 | TikTok, Reels, Shorts |
| quadratisch | 1080 | 1080 | Instagram-Feed |
Standardwerte
- Format: horizontal (1920×1080)
- Dauer: 5 Sekunden
- FPS: 30
- Stil: minimalistisch (siehe
references/style-presets.md)
Obligatorische Dateistruktur
Jede generierte Datei folgt diesem Grundgerüst. Die markierten Abschnittskommentare sind beabsichtigt – sie halten große Dateien navigierbar.
import React from 'react';
import {
useCurrentFrame,
useVideoConfig,
interpolate,
Easing,
AbsoluteFill,
Sequence,
} from 'remotion';
// =============================================================================
// KOMPOSITIONSKONFIGURATION
// =============================================================================
export const compositionConfig = {
id: 'ComponentName', // PascalCase nur – KEINE Bindestriche oder Unterstriche
durationInSeconds: 5,
fps: 30,
width: 1920,
height: 1080,
};
// =============================================================================
// STILKONSTANTEN
// =============================================================================
const COLORS = {
primary: '#6366f1',
secondary: '#8b5cf6',
accent: '#06b6d4',
background: '#0f0f23',
text: '#ffffff',
} as const;
const TYPOGRAPHY = {
fontFamily: 'Inter, system-ui, sans-serif',
} as const;
const EASINGS = {
easeOut: Easing.bezier(0.33, 1, 0.68, 1),
easeIn: Easing.bezier(0.32, 0, 0.67, 0),
easeInOut: Easing.bezier(0.37, 0, 0.63, 1),
overshoot: Easing.bezier(0.34, 1.56, 0.64, 1),
} as const;
// =============================================================================
// VORGENERIERTE DATEN (einmal auf Modulebene berechnet, NICHT während des Renders)
// =============================================================================
const seededRandom = (seed: number): number => {
const x = Math.sin(seed * 9999) * 10000;
return x - Math.floor(x);
};
// =============================================================================
// HAUPTKOMPONENTE
// =============================================================================
const ComponentName: React.FC = () => {
const frame = useCurrentFrame();
const { fps, durationInFrames, width, height } = useVideoConfig();
return (
<AbsoluteFill style={{ backgroundColor: COLORS.background }}>
{/* Inhalt */}
</AbsoluteFill>
);
};
export default ComponentName;
Ersetzen Sie ComponentName durch einen PascalCase-Namen, der die Einstellung beschreibt, setzen Sie den COLORS-Block aus dem gewählten Stilvorgabe und legen Sie width/height/durationInSeconds/fps gemäß der Anfrage fest.
Korrektheitsregeln
Dies sind keine stilistischen Vorlieben – sie sind das, was einen erfolgreichen Render ausmacht. VidTSX (über Remotion) rendert jeden Frame, indem die Komponente bei einer festen Frame-Nummer aufgerufen wird. Es gibt keine Ereignisschleife, keine Persistenz zwischen Frames und keine Wanduhrzeit. Alles, was diese Dinge voraussetzt, wird brechen.
Animation ist immer frame-basiert
- Treiben Sie alle Bewegung mit
useCurrentFrame()+interpolate(). - Verwenden Sie niemals
useState,useEffect,setTimeout,setIntervaloder CSS-Animationen/Übergänge. Sie passen nicht zum Frame-für-Frame-Modell und erzeugen kaputte oder nicht-deterministische Ausgaben. - Für zufällige oder prozedurale Dinge verwenden Sie
seededRandom(oder eine gleichwertige gesäte Funktion), sodass jeder Render eines bestimmten Frames identisch ist. Generieren Sie Partikel-/Zufallsarrays auf Modulebene vor, niemals innerhalb der Render-Funktion – eine Neuberechnung pro Frame verursacht Flackern. - Staffeln Sie Animationen so, dass Elemente nacheinander eintreten, anstatt alle auf einmal. Das wirkt besser und ist das erwartete Erscheinungsbild.
interpolate – Eingabebereiche müssen streng monoton steigend sein
Der Eingabebereich von interpolate muss streng monoton steigend sein. Doppelte oder absteigende Werte führen zur Laufzeit zu einem Fehler.
// ✅ Richtig
interpolate(frame, [0, 30, 60], [0, 1, 0]);
// ❌ Fehler – Eingabebereich steigt ab
interpolate(frame, [60, 30, 0], [0, 1, 0]);
Um eine Zuordnung umzukehren, drehen Sie den Ausgabebereich um, niemals den Eingabebereich:
// ✅ Richtig – bildet 0→100, 1→0 ab
interpolate(value, [0, 1], [100, 0]);
// ❌ Falsch
interpolate(value, [1, 0], [100, 0]);
Stellen Sie bei indexbasiertem Timing sicher, dass startFrame < endFrame ist, und clampen Sie immer:
const startFrame = index * 30;
const endFrame = startFrame + 30;
interpolate(frame, [startFrame, endFrame], [0, 1], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
});
Übergeben Sie immer extrapolateLeft: 'clamp' und extrapolateRight: 'clamp', es sei denn, ein unbegrenzter Wert ist wirklich gewünscht – ohne sie schießen die Werte vor/nach den Keyframes über ihren Bereich hinaus.
Easing – Verwenden Sie Easing.bezier(), niemals Wrapper-Syntax
Wrapper-Formen wie Easing.out(Easing.cubic) stürzen ab. Definieren Sie benannte Beziers einmal (siehe EASINGS-Block im Grundgerüst) und referenzieren Sie sie:
// ❌ Stürzt ab
Easing.out(Easing.cubic);
Easing.in(Easing.quad);
// ✅ Richtig
interpolate(frame, [0, 30], [0, 1], {
easing: EASINGS.easeOut,
extrapolateRight: 'clamp',
});
chroma-js – Nur Namespace-Import
// ✅ Richtig
import * as chroma from 'chroma-js';
const color = chroma('#00bfff').brighten(0.5).hex();
// ❌ Falsch – „chroma ist keine Funktion"
import chroma from 'chroma-js';
@remotion/paths – Nur die tatsächlichen Funktionen existieren
Diese Hilfsfunktionen existieren nicht und dürfen niemals verwendet werden:
makeCircle(), makeRect(), makeTriangle(), makeLine(), makePie(), makePolygon(), makeEllipse(), makeStar().
Nur diese Importe sind gültig:
import { evolvePath, getLength, getPointAtLength, getTangentAtLength } from '@remotion/paths';
Schreiben Sie SVG-Pfad-Strings von Hand und animieren Sie sie mit evolvePath:
const circlePath = 'M 50 10 A 40 40 0 1 1 49.99 10 Z';
const rectPath = 'M 0 0 L 100 0 L 100 50 L 0 50 Z';
const linePath = 'M 0 0 L 100 100';
const { strokeDasharray, strokeDashoffset } = evolvePath(progress, rectPath);
Kompositions-ID
compositionConfig.id ist nur PascalCase – keine Bindestriche, keine Unterstriche (z.B. ProductReveal, nicht product-reveal oder product_reveal).
Layout
Sicherheitszonen
- Obere 10%: für die Plattform-UI reservieren.
- Untere 15%: für Untertitel/Schaltflächen reservieren.
- Primären Inhalt zwischen 25%–75% vertikal halten.
Zentrierungshilfe
const centered: React.CSSProperties = {
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
};
Typografie
| Element | Größe | Stärke |
|---|---|---|
| Überschriften | 72–120px | 700–900 |
| Unterüberschriften | 36–48px | 500–700 |
| Fließtext | 28–36px | 400–500 |
Setzen Sie bei Textelementen immer margin: 0 – Browser-Standardwerte verschieben Layouts aus der Mitte.
Stilvorgaben
In diesem Repository ist der Standardwert die Hausmarke, keine Vorgabe. Einstellungen importieren COLORS, GRADIENT, RADIUS, SHADOW, EASINGS aus remotion/src/brand.ts und FONT_HEADLINE, FONT_DISPLAY, FONT_BODY, FONT_MONO aus remotion/src/fonts.ts anstelle der lokalen COLORS/TYPOGRAPHY-Blöcke des Grundgerüsts und folgen brand.md. FONT_HEADLINE (Instrument Serif) hat eine Stärke: geben Sie ihm niemals fontWeight. Einstellungen liegen auf dem Tag-Grund, es sei denn, ihre compositionConfig gibt ground: 'night' an; die Kit-Komponenten (lib/shorts.tsx, BrandBg) wählen ihre Farben daraus, also lesen Sie useGround() aus brand.ts für jede Farbe, die Sie selbst setzen.
Wenn der Benutzer einen Stil nennt, laden Sie seine Palette und Eigenschaften aus references/style-presets.md und fügen Sie das COLORS-Objekt in das Grundgerüst ein. Die sechs Vorgaben sind: minimalistisch, memphis, neo-brutalismus, glassmorphismus, neon/cyberpunk und corporate. Wenn kein Stil genannt wird, verwenden Sie die Hausmarke oben.
Render überprüfen (nicht überspringen)
Eine Einstellung ist erst fertig, wenn Sie sie angesehen haben. Rendern Sie nach dem Schreiben der .tsx-Datei mindestens ein Standbild und öffnen Sie es – übergeben Sie niemals eine Einstellung, über die Sie nur nachgedacht haben. Der Render gelingt und die Zahlen sehen richtig aus, aber Text überläuft seine Karte, ein Bild ist falsch beschnitten, ein Element ist außerhalb des Bildschirms oder zwei Dinge überlappen sich. Nur ein Screenshot fängt diese Fehler ein.
- Rendern Sie ein Standbild (z.B.
node scripts/render-all.mjs --still --scale=1 <ShotId>) und lesen Sie das PNG. - Bei zeitbasierten Enthüllungen (Elemente, die zu einem Cue eintreten, Scrollen, gestaffelte Phasen) reicht ein einzelnes Standbild bei 60% der Dauer nicht – rendern Sie den vollständigen Clip und ziehen Sie Frames zu jedem Schlüsselmoment (
ffmpeg -ss <t> -i out/<id>.mp4 -frames:v 1 f.jpg), oder rendern Sie Standbilder zu mehreren Offsets. Überprüfen Sie den Zustand bei jedem Cue, nicht nur bei einem Frame. - Prüfen Sie speziell: Bilder passen in ihre Aussparungen (kein wichtiger Inhalt beschnitten; bevorzugen Sie
objectFit: containauf einem passenden Hintergrund für heterogene echte Bilder), Text ist nicht abgeschnitten oder überläuft, nichts ist außerhalb des sicheren Bereichs, und jedes animierte Element ist tatsächlich sichtbar, wenn es sollte. - Wenn es über anderes Filmmaterial gelegt wird, überprüfen Sie auch stichprobenartig einen Frame aus der finalen gebackenen Ausgabe, nicht nur die isolierte Einstellung.
Beheben Sie, was der Screenshot zeigt, und rendern Sie dann erneut und schauen Sie erneut. Betrachten Sie „Ich habe es gerendert und es sieht richtig aus" – mit dem gezeigten Frame – als Maßstab für erledigt.
Endgültige Ausgabe
Generieren Sie die vollständige .tsx-Datei und nichts anderes darin – keine umgebenden Markdown, kein Kommentar vor oder nach dem Code in der Datei selbst. Ein kurzer einzeiliger Hinweis im Chat bei der Übergabe der Datei ist in Ordnung.