/** * Hook analysis — does the first 3 seconds of a video earn the * scroll-stop? * * Platform algorithms (TikTok / Reels / Shorts / YouTube) treat the * first 2-3 seconds as the algorithmic checkpoint. Videos with strong * 3-second retention get pushed to larger audiences; videos that lose * viewers immediately get buried. This module bundles the four checks * every retention guide preaches: * * 1. Speech in the first 0.5s — silent openings = scroll death. * 2. On-screen text — sound-off mobile is the default. * 3. Visual motion — static openers fail (sample two frames). * 4. Clear subject (face/etc.) — abstract intro cards underperform. * * #1 is a silencedetect probe (deterministic, free). * #2-#4 are folded into ONE vision call against an early-frame sample. * * Returns a structured score plus a short list of issues the agent can * surface verbatim. The agent's job is to drop a red marker if the * score is below a threshold and propose a stronger opener. */ export interface HookAnalysisFinding { /** Stable id for this issue. */ id: "silent_open" | "no_on_screen_text" | "static_first_frame" | "no_clear_subject" | "weak_emotional_hook"; severity: "info" | "warn" | "block"; /** One-line human description. */ message: string; } export interface HookAnalysisResult { /** 0-100. ≥70 = solid hook, 40-69 = weak, <40 = will tank retention. */ score: number; /** True if score >= passThreshold (default 70). */ passes: boolean; /** Sub-scores (0-1). */ speechAt0_5s: number; onScreenText: number; motion: number; subjectClarity: number; emotionalIntensity: number; findings: HookAnalysisFinding[]; /** ≤120 char overall verdict from the vision pass. */ why: string; } /** * Compute the speech-at-0.5s score from a list of silence ranges * within the first `windowSec` seconds. * * 1.0 = speech is active throughout the first 500ms. * 0.0 = totally silent for the entire first 500ms. * Linear in between. Used both by the live tool and the unit tests. */ export declare function speechAt0_5sScore(silences: Array<{ startSec: number; endSec: number; }>, windowSec?: number): number; export interface HookVisionResponse { onScreenText: number; motion: number; subjectClarity: number; emotionalIntensity: number; why: string; } export declare function parseHookVisionResponse(content: string): HookVisionResponse; export interface HookVisionOptions { apiKey?: string; model?: string; detail?: "low" | "high"; signal?: AbortSignal; } export declare function runHookVision(earlyFramePath: string, laterFramePath: string, opts?: HookVisionOptions): Promise; export interface ScoreOptions { /** Pass threshold (default 70). */ passThreshold?: number; /** Component weights (sum doesn't have to equal 1). */ weights?: { speech?: number; onScreenText?: number; motion?: number; subjectClarity?: number; emotionalIntensity?: number; }; } /** * Combine the deterministic speech score and the vision response into * an overall HookAnalysisResult. Pure function — easy to unit-test the * scoring rubric without booting ffmpeg or OpenAI. */ export declare function buildHookResult(speech: number, vision: HookVisionResponse, opts?: ScoreOptions): HookAnalysisResult; //# sourceMappingURL=hook-analysis.d.ts.map