/** * Keyword-highlighted captions — the CapCut "active word" style that * defines viral short-form aesthetics in 2025-2026. * * Plain word-by-word burned captions show every word in the same * style. Keyword highlighting picks the 1-2 most content-bearing words * per phrase and renders them in a stronger color / scale, so the eye * locks onto the meaning even when the viewer is half-scrolling. * * No POS tagger needed — a small heuristic gets us 90% of the way: * - Numbers and ALL-CAPS tokens are always keywords. * - Words ≥ minKeywordLen and NOT in the stoplist are keywords. * - Words in the stoplist (articles / prepositions / fillers) are * never keywords. * - We cap to N keywords per phrase to keep emphasis meaningful. * * Output: AssCue list with two styles ("Default" + "Keyword"). The * caller passes them straight into buildAss(); ffmpeg's `subtitles` * filter renders the result. */ import type { AssCue, AssStyle } from "./ass.js"; import type { TranscriptWord } from "./whisper.js"; export interface KeywordCaptionOptions { /** Words per cue. Default 3 — readable at fast speech rates. */ groupSize?: number; /** Min gap (sec) at which we force a new cue. Default 0.4. */ gapSec?: number; /** Min letters to consider a word a keyword by length. Default 5. */ minKeywordLen?: number; /** Max keywords per cue. Default 1. Clamped to ≥0. */ maxKeywordsPerCue?: number; /** Stoplist override (case-insensitive). Defaults to DEFAULT_STOPLIST. */ stoplist?: readonly string[]; /** * Per-cue display duration cushion (sec) — extends each cue's end * past the last word's end so the caption doesn't pop off mid-syllable. * Default 0.08s. */ endPaddingSec?: number; } /** * The function-words / discourse markers we strip from keyword * candidates. Lowercase, no punctuation. */ export declare const DEFAULT_STOPLIST: readonly ["a", "an", "the", "i", "me", "my", "mine", "you", "your", "yours", "he", "him", "his", "she", "her", "hers", "it", "its", "we", "us", "our", "ours", "they", "them", "their", "theirs", "this", "that", "these", "those", "is", "are", "was", "were", "be", "been", "being", "am", "do", "does", "did", "doing", "have", "has", "had", "having", "will", "would", "shall", "should", "may", "might", "must", "can", "could", "of", "in", "on", "at", "by", "to", "for", "with", "from", "as", "into", "onto", "out", "off", "up", "down", "over", "under", "and", "or", "but", "so", "if", "then", "than", "because", "while", "when", "where", "who", "which", "what", "why", "how", "not", "no", "yes", "okay", "ok", "well", "just", "really", "very", "much", "more", "most", "some", "any", "all", "each", "every", "um", "uh", "uhm", "like", "you know", "i mean"]; /** * Build the cues + styles for a keyword-highlighted caption track. * * Returns: * - styles: pass directly into AssOptions.styles (always 2 styles). * - cues: one cue per N words OR per gap boundary. Cues with a * keyword embed the keyword via an inline `{\rKeyword}` ... * `{\rDefault}` reset so a single cue can mix both styles. * * The caller controls font/size/colors by overriding fields on the * returned styles before passing them to buildAss. */ export declare function buildKeywordCaptions(words: TranscriptWord[], opts?: KeywordCaptionOptions): { cues: AssCue[]; styles: AssStyle[]; }; /** * Decide whether a single token (already normalized) is a keyword. * Exported for unit testing. */ export declare function isKeywordToken(raw: string, stoplist: Set, minLen: number): boolean; /** * Sensible defaults that look right for vertical / 9:16 shorts: * - Default style: large white sans-serif with thick outline. * - Keyword style: punchy yellow, slightly larger, same font. * * Override via the returned array before passing into buildAss(). */ export declare function defaultKeywordStyles(): AssStyle[]; //# sourceMappingURL=keyword-captions.d.ts.map