scoreHookPatterns
Analyze video openings to identify engaging hook patterns by scoring the first 30 seconds across multiple videos, helping creators optimize content retention.
Instructions
Heuristically score first-30-second hooks across one or more videos.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| videoIdsOrUrls | Yes | ||
| hookWindowSec | No | ||
| dryRun | No |
Implementation Reference
- src/lib/analysis.ts:348-414 (handler)The core logic for scoring hook patterns based on the transcript's first 30 seconds.
export function scoreHookPattern(videoId: string, transcript: TranscriptRecord, hookWindowSec = 30): HookPatternResult { const firstWindow = transcript.segments.filter((segment) => segment.tStartSec <= hookWindowSec); const text = firstWindow.map((segment) => segment.text).join(" ").trim() || transcript.transcriptText.slice(0, 500); const summary = summarizeText(text, 2); const lower = text.toLowerCase(); let hookType: HookPatternResult["hookType"] = "other"; let score = 40; const weakSignals: string[] = []; const improvements: string[] = []; if (lower.includes("?")) { hookType = "question"; score += 14; } if (/(how to|i'll show|we're going to|today you'll learn|by the end)/.test(lower)) { hookType = hookType === "other" ? "promise" : hookType; score += 18; } if (/(story|when i|last week|once|years ago)/.test(lower)) { hookType = hookType === "other" ? "story" : hookType; score += 12; } if (/(proof|results|tested|data|case study|examples)/.test(lower)) { hookType = hookType === "other" ? "proof" : hookType; score += 12; } if (/(crazy|shocking|nobody tells you|mistake|secret|warning)/.test(lower)) { hookType = "shock"; score += 10; } if (/\d/.test(lower)) { score += 6; } if (text.length < 80) { weakSignals.push("The opening is very short and may not frame the payoff clearly."); improvements.push("State the promise, result, or problem in the first 1-2 sentences."); score -= 8; } if (!/[?!.]/.test(text)) { weakSignals.push("Low rhetorical energy in the opening copy."); improvements.push("Use a sharper question, claim, or proof point to create tension."); score -= 6; } if (!(lower.includes("you") || lower.includes("your"))) { weakSignals.push("Limited audience-facing framing."); improvements.push("Address the viewer directly so the hook feels relevant."); score -= 4; } score = Math.max(0, Math.min(100, score)); if (improvements.length === 0) { improvements.push("Keep the opening tight and move into proof quickly."); } if (weakSignals.length === 0) { weakSignals.push("No major hook weakness detected from transcript alone."); } return { hookScore: score, hookType, first30SecSummary: summary || `Opening transcript unavailable for ${videoId}`, weakSignals, improvements, }; }