/** * DocDoe Cinematic Video Engine — Strict Type System * * These types form the contract between the AI script generator and the * Remotion-based visual renderer. Keep them narrow and explicit — avoid `string` * wherever a union works. * * NO framer-motion in any component that imports from this file. * All animation must use Remotion's interpolate() / spring() / useCurrentFrame(). */ // --------------------------------------------------------------------------- // Scene type union — maps every AI-generated scene to a visual template // --------------------------------------------------------------------------- export type SceneType = | "hook" // Opening attention grab — large, bold, dramatic | "explain" // Core teaching content — hologram board, keywords, body text | "keyword" // Vocabulary/definition spotlight — big term + meaning chips | "pyq" // Past year question — exam paper style, marks badge, answer reveal | "quiz" // Interactive check — question + choices or blank fill | "recap" // Summary cards — numbered key points | "mentor"; // Direct-to-camera personal coaching tone — warm, close framing // --------------------------------------------------------------------------- // Supporting value types // --------------------------------------------------------------------------- export type MentorEmotion = | "explaining" | "excited" | "thinking" | "serious" | "recap" | "doubt" | "study"; export type CameraMotion = "dolly_in" | "dolly_out" | "pan_left" | "pan_right" | "static"; export type VisualHintType = "diagram" | "equation" | "list" | "comparison" | "none"; export type VisualHint = { type: VisualHintType; label?: string; items?: string[]; }; export type SubtitleSegment = { /** Seconds from scene start */ start: number; end: number; text: string; }; export type ExamFocusData = { question: string; answer: string; marks: number; exam_year?: number; /** How many times asked in past papers */ frequency?: number; }; // --------------------------------------------------------------------------- // Core scene and plan types // --------------------------------------------------------------------------- export type VideoScene = { scene_id: number; type: SceneType; duration_seconds: number; /** Headline text — short, displayed large at top of board */ title: string; /** Body explanation text — 1-3 sentences */ body: string; /** TTS narration text — may differ from body */ voice_text: string; /** Max 6 keyword chips shown as staggered tags */ keywords: string[]; visual_hint: VisualHint; subtitle_segments?: SubtitleSegment[]; mentor_emotion?: MentorEmotion; camera_motion?: CameraMotion; /** PYQ scene data — used when type === "pyq" */ exam_focus?: ExamFocusData; audio_src?: string; is_mock_audio?: boolean; }; export type VideoPlan = { /** Stable plan identifier (used as Remotion composition key) */ id: string; title: string; subject: string; chapter?: string; language: string; duration_minutes: number; /** Override computed total when provided by backend */ total_duration_seconds?: number; scenes: VideoScene[]; /** Whether the Nila teacher character is shown */ show_mentor: boolean; /** Shows "Preview" watermark in top-right corner */ show_preview_watermark?: boolean; }; // --------------------------------------------------------------------------- // Engine configuration // --------------------------------------------------------------------------- export type VideoEngineConfig = { fps: number; width: number; height: number; format: "16:9" | "9:16"; }; export const VIDEO_ENGINE_FPS = 30 as const; export const DEFAULT_CONFIG: VideoEngineConfig = { fps: VIDEO_ENGINE_FPS, width: 1920, height: 1080, format: "16:9", } as const; export const VERTICAL_CONFIG: VideoEngineConfig = { fps: VIDEO_ENGINE_FPS, width: 1080, height: 1920, format: "9:16", } as const; // --------------------------------------------------------------------------- // Interop helpers — adapt existing ExplainerScene → VideoScene // --------------------------------------------------------------------------- /** Minimal ExplainerScene fields needed by the interop adapter */ export type LegacySceneInput = { scene_id: number; type: string; duration_seconds: number; screen_text: string; voice_text: string; keywords: string[]; visual_hint: string; subtitle_segments?: Array<{ start: number; end: number; text: string }>; mascot_expression?: string | null; };