import { type MotifMoment } from './motifs.js'; /** One caption: the spoken text and its absolute window in the source clip. */ export interface LocalCaption { text: string; start: number; end: number; } /** * The three card looks, ported from the source skill's style catalog so * `--render local --style X` actually changes the rendered overlay (previously * only the V2V *prompt* varied by style; the local card was fixed). * - `apple-clean` — rounded dark frosted glass, clean sans-serif sentence case. * - `editorial-dark` — squared solid-black poster panel, bold condensed UPPERCASE. * - `knowledge-tool` — soft cool-dark card, editorial serif, calm lavender accent. */ export type CardVariant = 'apple-clean' | 'editorial-dark' | 'knowledge-tool'; /** Visual config for the lower-third (accent hex + small kicker label + style). */ export interface LocalRenderStyle { accent: string; /** Optional small kicker label above the caption (e.g. a brand). Omitted when blank. */ kicker?: string; /** Lowercased words that get the accent colour (e.g. brand/anchor words). */ accentWords?: string[]; /** Which card look to render (default `apple-clean`). */ variant?: CardVariant; /** * Word-by-word reveal: only the first N words of the caption are visible; the rest * render transparent (so the panel keeps its full size — no per-frame reflow). The * animated renderer drives this with `revealWordCount(t)`. Omitted → all words. */ visibleWords?: number; } /** Escape the five XML entities so arbitrary transcript text is SVG-safe. Pure. */ export declare function xmlEscape(text: string): string; /** * Word-wrap `text` to at most `maxChars` per line (greedy by words). Pure — used * to size the panel and lay out tspans. */ export declare function wrapWords(text: string, maxChars: number): string[]; /** * Build the lower-third SVG for one caption. Pure & deterministic. `style.variant` * selects a **structurally distinct** card per the source skill's catalog — a * floating inset frosted card (apple-clean), a full-bleed near-black poster bar with * an accent top rule and a solid accent tag (editorial-dark), or a left-anchored cool * study card with a `[[ MONO ]]` bracket label and serif body (knowledge-tool). */ export declare function lowerThirdSvg(caption: Pick, dims: { width: number; height: number; }, style: LocalRenderStyle): string; /** * Build the giant **anchor-headline** SVG — a single dominant keyword centred in * the upper-middle of the frame, with the accent asterisk beat-marker after it * (the source skill's signature kinetic-typography moment). Pure & deterministic. */ export declare function anchorHeadlineSvg(word: string, dims: { width: number; height: number; }, style: LocalRenderStyle): string; /** Rasterise a lower-third SVG to a PNG buffer via sharp. Side effect (sharp). */ export declare function rasteriseCaption(svg: string): Promise; /** * Build the ffmpeg `-filter_complex` graph compositing N pre-rendered full-frame * card PNGs (inputs 1..N; input 0 is the source video) onto the source — each * card fades in/out and slides up 36px on entrance over its [start,end] window. * Pure (string only). */ export declare function buildLocalFiltergraph(cards: Array<{ start: number; end: number; }>): string; /** * Build the ffmpeg argv for the overlay composite. Pure — the source is input 0, * each card PNG is a looped image input, the graph maps [vout] + the source audio. */ export declare function buildLocalRenderArgs(sourceVideo: string, cardPngPaths: string[], filtergraph: string, outputPath: string): string[]; /** Runs ffmpeg with the given argv. Injectable so the orchestrator tests offline. */ export type FfmpegRunner = (args: string[]) => Promise; export interface RenderLocalDeps { ffmpeg: FfmpegRunner; /** Override the rasteriser (tests). Defaults to the live sharp path. */ rasterise?: (svg: string) => Promise; } /** A giant anchor-headline moment: the word + the short window it pulses on. */ export interface HeadlineMoment { word: string; start: number; end: number; } export interface RenderLocalOptions { sourceVideo: string; captions: LocalCaption[]; dims: { width: number; height: number; }; style: LocalRenderStyle; /** Optional giant anchor-headline overlays, composited above the lower-thirds. */ headlines?: HeadlineMoment[]; /** Optional concept icons / stat callouts, composited in the upper third. */ motifs?: MotifMoment[]; /** Dir for the intermediate card PNGs. */ cardDir: string; outputPath: string; } /** Resolve a motif into its full-frame SVG using the active style. Pure. */ export declare function motifSvg(m: MotifMoment, dims: { width: number; height: number; }, style: LocalRenderStyle): string; /** * Render the local overlay reel: rasterise one lower-third per caption (plus any * giant anchor-headline moments), then composite all elements onto the source with * the fade/slide filtergraph, sorted by start time. Returns the list of card PNG * paths written (for provenance / tests). */ export declare function renderLocalOverlay(opts: RenderLocalOptions, deps: RenderLocalDeps): Promise; //# sourceMappingURL=render-local.d.ts.map