import React from "react"; import { loadFont } from "@remotion/google-fonts/SpaceGrotesk"; import { AbsoluteFill, Audio, CalculateMetadataFunction, OffthreadVideo, Sequence, interpolate, spring, useCurrentFrame, useVideoConfig, } from "remotion"; import { CinematicRendererProps, CinematicTone, CinematicVideoScene } from "./cinematic/types"; const FPS = 30; const { fontFamily } = loadFont("normal", { weights: ["400", "500", "700"], subsets: ["latin"], }); const toneGradient = (tone: CinematicTone) => { switch (tone) { case "steel": return "linear-gradient(180deg, rgba(6,12,18,0.18) 0%, rgba(2,4,8,0.48) 100%)"; case "void": return "linear-gradient(180deg, rgba(2,4,8,0.14) 0%, rgba(0,0,0,0.56) 100%)"; case "neutral": return "linear-gradient(180deg, rgba(10,10,12,0.16) 0%, rgba(0,0,0,0.42) 100%)"; case "cold": default: return "linear-gradient(180deg, rgba(8,16,24,0.18) 0%, rgba(2,4,8,0.42) 100%)"; } }; const SceneVideo: React.FC<{ scene: CinematicVideoScene }> = ({ scene }) => { const frame = useCurrentFrame(); const { durationInFrames, fps } = useVideoConfig(); const fadeInFrames = scene.fadeInFrames ?? 10; const fadeOutFrames = scene.fadeOutFrames ?? 10; const fadeOutStart = Math.max(fadeInFrames, durationInFrames - fadeOutFrames); const fadeInOpacity = fadeInFrames === 0 ? 1 : interpolate(frame, [0, fadeInFrames], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp", }); const fadeOutOpacity = fadeOutFrames === 0 ? 1 : interpolate(frame, [fadeOutStart, durationInFrames], [1, 0], { extrapolateLeft: "clamp", extrapolateRight: "clamp", }); const opacity = Math.min(fadeInOpacity, fadeOutOpacity); const scale = interpolate(frame, [0, durationInFrames], [1.015, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp", }); const trimBefore = scene.trimBeforeSeconds !== undefined ? Math.round(scene.trimBeforeSeconds * fps) : undefined; const trimAfter = scene.trimAfterSeconds !== undefined ? Math.round(scene.trimAfterSeconds * fps) : undefined; return ( ); }; const SignalTexture: React.FC<{ accent: string; intensity: number; lineCount: number; }> = ({ accent, intensity, lineCount }) => { const frame = useCurrentFrame(); return ( {new Array(lineCount).fill(true).map((_, index) => { const pulse = Math.max(0, Math.sin(frame * 0.06 + index * 0.85)); const opacity = (0.025 + pulse * 0.07) * intensity; const width = 18 + ((index * 37) % 56); const top = 140 + index * 42; const left = index % 2 === 0 ? 0 : 1920 - width; return (
); })}
); }; const TitleCard: React.FC<{ text: string; accent: string; intensity: number; titleFontSize: number; titleWidth: number; signalLineCount: number; }> = ({ text, accent, intensity, titleFontSize, titleWidth, signalLineCount, }) => { const frame = useCurrentFrame(); const { fps, durationInFrames } = useVideoConfig(); const reveal = spring({ fps, frame, config: { damping: 18, stiffness: 90 }, }); const exit = interpolate( frame, [durationInFrames - 12, durationInFrames], [1, 0], { extrapolateLeft: "clamp", extrapolateRight: "clamp", }, ); const y = interpolate(reveal, [0, 1], [18, 0]); const letterSpacing = interpolate(reveal, [0, 1], [0.3, 0.18]); const flareOpacity = 0.18 + Math.max(0, Math.sin(frame * 0.08)) * 0.14 * intensity; return (
{text}
); }; const Soundtrack: React.FC<{ src: string; volume: number; trimBeforeSeconds?: number; trimAfterSeconds?: number; fadeInSeconds: number; fadeOutSeconds: number; }> = ({ src, volume, trimBeforeSeconds, trimAfterSeconds, fadeInSeconds, fadeOutSeconds, }) => { const frame = useCurrentFrame(); const { durationInFrames, fps } = useVideoConfig(); const fadeInFrames = Math.max(1, Math.round(fadeInSeconds * fps)); const fadeOutFrames = Math.max(1, Math.round(fadeOutSeconds * fps)); const trimBefore = trimBeforeSeconds !== undefined ? Math.round(trimBeforeSeconds * fps) : undefined; const trimAfter = trimAfterSeconds !== undefined ? Math.round(trimAfterSeconds * fps) : undefined; const fadeIn = interpolate(frame, [0, fadeInFrames], [0, volume], { extrapolateLeft: "clamp", extrapolateRight: "clamp", }); const fadeOut = interpolate( frame, [durationInFrames - fadeOutFrames, durationInFrames], [volume, 0], { extrapolateLeft: "clamp", extrapolateRight: "clamp", }, ); return (