import { AbsoluteFill, Audio, Sequence, interpolate, spring, useCurrentFrame, useVideoConfig } from "remotion"; import { FPS, type ExplainerLongProps } from "../schema"; import { theme } from "../theme"; import { Captions, Logo, ProgressBar, SceneCard } from "./shared"; import { Starfield } from "./Starfield"; const TITLE_S = 3; export function explainerDuration(props: ExplainerLongProps): number { return Math.round((TITLE_S + props.scenes.reduce((s, sc) => s + sc.durationS, 0)) * FPS); } function TitleCard({ title, accent, name }: { title: string; accent: string; name?: string }) { const frame = useCurrentFrame(); const { fps } = useVideoConfig(); const s = spring({ frame, fps, config: { damping: 16 } }); const line = interpolate(frame, [10, 40], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" }); return (

{title}

{name && (

{name}

)} ); } /** 16:9 explainer: a title card, then one card per storyboard scene over narration with captions. */ export function ExplainerLong(props: ExplainerLongProps) { const accent = props.brand.accent ?? theme.blue; let cursor = TITLE_S * FPS; return ( {props.scenes.map((scene, i) => { const from = cursor; const dur = Math.round(scene.durationS * FPS); cursor += dur; return ( ); })} {props.audioUrl && ); }