/** * Lipsync closure protocol — the bilabial seal map (Joey 3.0 Cinema Director). * * Lipsync reads as fake for a diagnosable reason: the lyric was handed to the * model as an abstract instruction ("she sings the line") instead of as a score * of mouth mechanics. What the eye actually reads as real sync is the **lip * seal** — the moment both lips press fully together on a bilabial consonant. * Miss those and the mouth flaps plausibly but syncs to nothing. * * So this module turns a line of lyric or dialogue into a COUNTED, positioned * map of seals, which the prompt then states as a directive block. A count the * model can check itself against beats a paragraph of adjectives. * * Pure and deterministic — no I/O. */ /** * `hard` — a full bilabial seal: both lips press flat together and part again. * B, P (plosives) and M (nasal) all require complete closure, so all three * count. These are what the eye reads. * * `soft` — labiodental: the upper teeth touch the lower lip (F, V). Visible and * worth describing, but NOT a lip seal, so it is deliberately excluded from the * count. Counting it inflates the number and the model starts inventing * closures that the audio does not contain. */ export type ClosureKind = 'hard' | 'soft'; export type ClosurePosition = 'initial' | 'medial' | 'final'; export interface LipsyncClosure { /** The letter producing the closure, uppercased. */ letter: string; kind: ClosureKind; /** The word it falls in, uppercased — the prompt names the word, not the index. */ word: string; /** Where in the word the closure lands; drives the "M ending X" phrasing. */ position: ClosurePosition; } /** * Scan one line into its ordered closure map. * * Known limits, stated rather than silently wrong: this is orthographic, not * phonetic. It handles the three traps that actually change the count in * practice (silent final `mb`, silent initial `p`, and `ph` as an F sound) and * does not attempt full grapheme-to-phoneme conversion — a homograph like * "read" is not disambiguated, though neither pronunciation changes a seal. * Verify the count against a hand-count before a paid render. */ export declare function buildClosureMap(line: string): LipsyncClosure[]; /** The hard seals only — the number the prompt actually states. */ export declare function hardClosures(map: LipsyncClosure[]): LipsyncClosure[]; /** * THE PATTERN OF CLOSURES — the counted seal directive. * * The count is the load-bearing part. "Sing the line clearly" is unfalsifiable; * "there are four complete lip seals and here is where each one lands" is * something the model can hold itself to. */ export declare function closureCountBlock(map: LipsyncClosure[]): string; /** * The singing-is-the-subject directive. Promoted high because lipsync competes * with every other directive block for attention, and loses by default. */ export declare function singingPrimaryBlock(subjectHandle: string, seconds: number): string; /** * Mouth-visibility lock. Pairs with the closure map: a perfectly scored seal * that happens behind a hand or a hair fall reads as no seal at all. */ export declare function mouthVisibilityBlock(): string; /** * Sole-audio-source lock for a submitted vocal reference. * * The reference SHAPE matters as much as the lock: a bare MP3/WAV drifts to a * generic accent, while the same audio as the track of a black-frame video * holds the voice (this is what `vclaw video voice-clone` builds). Passing no * vocal reference at all means the take can never sync, however well the * closures are scored — so this block assumes one is attached and says so. */ export declare function soleAudioSourceBlock(referenceSlot: string): string; export interface LipsyncBlocksInput { /** Visual descriptor of the performer — never a proper name. */ subjectHandle: string; /** The sung or spoken line, verbatim. */ line: string; durationSeconds: number; /** Reference slot carrying the vocal, e.g. `@video1`. Omit for no audio lock. */ audioReferenceSlot?: string; } /** * The full protocol as an ordered block list, ready to prepend to a packet. * Ordering is the protocol: singing first (it out-competes everything else), * then the counted seals, then the visibility lock that makes them readable. */ export declare function lipsyncBlocks(input: LipsyncBlocksInput): string[]; //# sourceMappingURL=lipsync-closure.d.ts.map