/**
* 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)}
);
}