/** * DocDoe Cinematic Video Engine — VideoSceneRenderer * * Dispatches to the correct scene component based on `scene.type`. * Wraps with SceneCamera and cross-dissolve opacity. * * This is the single entry point for rendering one scene inside a * Remotion Series.Sequence. Frame is already local (0-based) here. * * NO framer-motion. All motion via Remotion interpolate() / spring(). */ import { AbsoluteFill, useCurrentFrame } from "remotion"; import type { VideoPlan, VideoScene } from "../types"; import { SceneCamera } from "../motion/camera"; import { sceneDissolve } from "../motion/animations"; import { ExplainScene } from "../scenes/ExplainScene"; import { HookScene } from "../scenes/HookScene"; import { KeywordScene } from "../scenes/KeywordScene"; import { RecapScene } from "../scenes/RecapScene"; // ── Shared prop type for all scene components ───────────────────────────── export type SceneComponentProps = { plan: VideoPlan; scene: VideoScene; sceneIndex: number; totalScenes: number; durationInFrames: number; }; // ── Scene dispatcher ────────────────────────────────────────────────────── /** * Renders the correct scene component for a given scene.type. * All unimplemented types fall through to ExplainScene until their * dedicated component is built. * * TODO: Replace each TODO comment with its dedicated scene component. */ function renderSceneComponent(props: SceneComponentProps) { switch (props.scene.type) { case "explain": return ; case "hook": return ; case "keyword": return ; case "pyq": // TODO: PYQScene — exam paper style, marks badge, answer reveal return ; case "quiz": // TODO: QuizScene — question + multiple choice or fill-in-blank return ; case "recap": return ; case "mentor": // TODO: MentorScene — warm close framing, personal coaching tone return ; default: return ; } } // ── Main renderer ───────────────────────────────────────────────────────── /** * VideoSceneRenderer — renders one scene with camera motion and transitions. * * Mount inside a Remotion Series.Sequence. The frame passed to child * components is automatically local (reset to 0 at sequence start). * * @example * * * */ export function VideoSceneRenderer(props: SceneComponentProps) { const frame = useCurrentFrame(); // First scene fades in without a leading black frame. // All subsequent scenes cross-dissolve for a smooth cut. const opacity = props.sceneIndex === 0 ? sceneDissolve(frame, props.durationInFrames, 4, 6) : sceneDissolve(frame, props.durationInFrames, 8, 6); return ( {renderSceneComponent(props)} ); }