Erklär-Animation
Ein Video ist eine geordnete Liste von Szenen in src/timeline.ts. Drei Arten:
intro: die Hook-Karte. Ihre erste Zeile ist der Hook, groß dargestellt, deren Wörter beim Sprechen aufleuchten (sie dient gleichzeitig als eigene Untertitel).anim: eine Animationskomponente aus der Registrierung, synchronisiert mit den Erzählzeilen der Szene.outro: die Schlusskarte mit dem AGILabs-Logo,javieraguilar.aiund dem Artikeltitel ausSETTINGS.articleTitle.
Die Timeline schreiben
import type { Cuts } from './types.ts';
import { L, anim, intro, outro, say, videos } from './narrate.ts';
const build = (): Cuts => ({
main: [
intro('hook', [say(0.4, 'EN hook line.', 'ES hook line.')]),
anim(
'result',
'BarCompare',
{ bars: [{ label: L('With the reason', 'Con el porqué'), value: 14, display: '14/20', highlight: true },
{ label: L('Without it', 'Sin él'), value: 4, display: '4/20' }], max: 20 },
[say(0.3, 'First line.', 'Primera línea.'), say(0, 'Second line.', 'Segunda línea.')],
{ min: 4 },
),
outro('outro', [say(0.4, 'More at javieraguilar.ai.', 'Más en javieraguilar.ai.')]),
],
});
export const VIDEOS = videos(build);
export const TIMELINE = VIDEOS.en.main;
say(at, en, es, spoken?): eine Erzählzeile.atist die früheste Sekunde der Szene, in der sie beginnen kann; Zeilen überlappen sich nie (0,35 s Abstand), und die Szene dauert bis zum Ende der letzten Zeile plus 0,8 s odermin.spoken({ en?, es? }) ist das, was die TTS liest, wenn es sich vom Untertiteltext unterscheidet (siehenarration).- Beats. Die Startzeit jeder Zeile in einer Szene ist ein Beat. Komponenten spielen Schritt i auf Beat i (Balken i wächst, Knoten i erscheint, Kachel i poppt auf), also schreiben Sie eine Zeile pro Schritt, den Sie enthüllen möchten. Vor der TTS stammen die Beats aus einer Längenschätzung; nach
npm run ttsstammen sie aus dem echten Audio, also überprüfen Sie die Standbilder nach der Erzählung erneut. L(en, es): ein zweisprachiges Bildschirm-Label. Ein einfacher String wird für beide Sprachen verwendet.- Szenen-IDs müssen eindeutig sein: Zeilen-Schlüssel (
<szenen>-01, ...) benennen die Audiodateien. opts.chapteraufanimwird in der Szene gespeichert, aber noch von keiner Komponente gezeichnet.- Führen Sie nach jeder Änderung
npm run lintaus: Länge gegentargetSeconds(±20 %), Untertitel-Cues unter 0,8 s oder über 17 Zeichen/s, und Komponentennamen, die in der Registrierung fehlen.
Komponentenkatalog
Alle Komponenten erhalten t, beats, dur, lang und vertical von der Szene; die Props unten stammen aus der Timeline. Zahlen auf dem Bildschirm verwenden die exakte Form des Artikels: bevorzugen Sie display / String-value gegenüber berechnetem Text, wenn der Artikel „14/20”, „0.0018” oder „83 %” schreibt.
| Komponente | Verwendung für | Props |
|---|---|---|
Counter | Eine Überschrift-Zahl, die hochzählt, Label darunter | value: number, label: Label, prefix?, suffix?, decimals? (0-8), beat? (Index des Beats, an dem das Zählen beginnt, Standard 0) |
BarCompare | 2-5 horizontale Balken, die pro Beat wachsen; der hervorgehobene im Akzentverlauf | bars: { label: Label; value: number; display?: string; highlight?: boolean; at?: number }[], max? (Skalengrenze, Standard der größte Wert), unit? (angefügt, wenn es kein display gibt) |
FlowDiagram | Boxen und Pfeile, die in Reihenfolge erscheinen; eine broken-Kante ist gestrichelt und dezent, mit einer Lücke | nodes: { id; label: Label; at?: number }[], edges: { from; to; label?: Label; broken?: boolean }[], layout: 'vertical' | 'horizontal' (verwenden Sie vertical für den 9:16-Cut) |
KeyQuote | Der Schlüsselsatz, Wort für Wort; betonte Wörter im Akzent mit Unterstreichung | text: Label, emphasis?: string[] (Wörter oder Phrasen, abgeglichen ohne Berücksichtigung von Groß-/Kleinschreibung und Interpunktion), beat? |
StatGrid | 2-4 Zahlenkacheln, die pro Beat einpoppen | stats: { value: string; label: Label; at?: number }[] |
at auf einem Balken, Knoten oder einer Kachel pinnt es an eine Szenen-Sekunde anstelle seines eigenen Beats. Schritte ohne Beat oder at folgen 0,6 s nach dem vorherigen. Jede Komponente wird so angepasst, dass sie bis zum Szenenende abgeschlossen ist: Der letzte Frame zeigt immer den Endzustand.
Um die gesamte Bibliothek zu sehen: npm run studio und öffnen Sie Gallery-vertical, oder rendern Sie Standbilder davon.
Hinzufügen einer maßgeschneiderten Komponente
Wenn das Skript eine Szene als „bespoke” kennzeichnet:
- Zuerst den Zustand, mit einem Test. Schreiben Sie
src/anim/<Name>.state.tsmit dem Props-Typ und einem reinenframeState(props, t, beats, dur), das einfache Zahlen und Strings zurückgibt. Keine Remotion- oder React-Importe dort. Bauen Sie es aufsrc/anim/steps.tsauf (sceneTime,stepTimes,fit,progress,beatAt,easeOutCubic), sodass es total ist: endliche Werte bei jedemt, Fortschrittsfelder innerhalb [0, 1], nichts sichtbar vor seinem ersten Beat, der Endzustand beit = dur. - Fügen Sie einen Fall zu
CASESintest/anim.test.tshinzu (und einen Test seines eigenen Verhaltens), dann führen Sienpm testaus. Es prüft den Zustand übert < 0, jeden Beat,durund überdurhinaus, mit fehlenden, späten und sehr kurzen Beats. - Zeichnen Sie es in
src/anim/<Name>.tsx: Rufen SieframeStateauf, zeichnen Sie innerhalb von<Stage vertical={...}>, verwenden Sie die Marken-Tokens aussrc/brand.ts(C,GRADIENT,alpha) und Inter. Keine neuen Farben oder Schriftarten. - Registrieren Sie es in
ANIMSinsrc/anim/index.ts. Halten SieANIMSein einfaches Objektliteral von Namen:npm run lintliest sie aus dem Quellcode. - Fügen Sie optional ein Beispiel zu
src/Gallery.tsxhinzu. Wenn es wiederverwendbar ist, gehört es zurück in die Plugin-Vorlage.
Generierte Bilder. Die meisten Szenen sollten im Code gezeichnet werden (SVG und CSS aus den Marken-Tokens). Wenn eine Szene wirklich ein generiertes Bild benötigt (einen Hintergrund, ein Basisbild, einen texturierten Moment), kann ein Bildmodell es erstellen, zum Beispiel die Bildgenerierung der Codex CLI. Speichern Sie es unter public/, laden Sie es mit staticFile(), halten Sie es innerhalb der Markenpalette und überprüfen Sie das Standbild.
Vertikaler Sicherheitsbereich (1080x1920)
- Die Plattform-UI bedeckt die oberen ~220 px und die unteren ~380 px; halten Sie 72 px an den Seiten.
- Animationen zeichnen nur innerhalb der Bühne: von y = 280 (unter dem AGILabs-Logo) bis y = 1280 (über den zwei Untertitelzeilen), 936 px breit.
Stage/stageOf()geben Ihnen diese Box. - Untertitel sitzen unterhalb der Bühne, maximal zwei Zeilen mit ~32 Zeichen, innerhalb von ~900 px.
Standbilder: Schauen Sie sie an
Rendern Sie Standbilder und Lesen Sie jedes PNG, bevor Sie das Video rendern. Ein sauberer Lint oder Build zeigt keinen Überlauf, abgeschnittenen Text oder eine falsche Zahl.
npx remotion still src/index.ts Main-EN-vertical out/stills/f0150.png --frame=150
Nehmen Sie ein Standbild pro Szene, sobald ihr letzter Schritt abgespielt wurde, plus eines alle ~3 s (alle 90 Frames bei 30 fps). Überprüfen Sie: AGILabs-Logo und nichts anderes als Branding, nichts außerhalb des Sicherheitsbereichs, kein Text, der über seine Box hinausläuft, jede Zahl gleich dem Artikel, und der Untertitel auf dem Bildschirm stimmt mit dem überein, was die Animation zu diesem Zeitpunkt zeigt.