/**
 * @module _shared/scene-html-emit
 *
 * Pure HTML emitters for `vibe scene add`. Each preset produces a self-contained
 * Hyperframes-compatible scene composition: a `<template>`-wrapped `<div
 * data-composition-id>` with scoped CSS, optional audio/image, and a paused
 * GSAP timeline registered on `window.__timelines`.
 *
 * Also exposes helpers that mutate the root index.html:
 * - `nextSceneStart()` — sum existing clip end-times to choose the new start
 * - `insertClipIntoRoot()` — splice a `<div class="clip">` reference before the
 *   root's closing div, preserving the user's hand-edited markup
 * - `slugifySceneName()` — name → kebab-case scene id
 *
 * Pure functions only — no I/O. The orchestrating command (`scene add`) wires
 * these to the filesystem.
 */
export type ScenePreset = "simple" | "announcement" | "explainer" | "kinetic-type" | "product-shot";
export declare const SCENE_PRESETS: readonly ScenePreset[];
/**
 * One word from a Whisper word-level transcript. Mirrors
 * {@link import("@vibeframe/ai-providers").TranscriptWord} but is duplicated
 * here so this module stays pure (no provider package import).
 */
export interface SceneTranscriptWord {
    text: string;
    start: number;
    end: number;
}
/**
 * Position value for Lottie overlays. Mirrors the vocabulary used by
 * `vibe edit motion-overlay --position`.
 */
export type LottiePosition = "full" | "center" | "top-left" | "top-right" | "bottom-left" | "bottom-right";
export declare const LOTTIE_POSITIONS: readonly LottiePosition[];
export interface LottieOverlayInput {
    /** Project-relative path to the `.json` or `.lottie` file (e.g. "assets/logo.lottie"). */
    src: string;
    /** Overlay position. Defaults to "full". */
    position?: LottiePosition;
    /** Scale factor (0.01-2). Defaults to 1. */
    scale?: number;
    /** Opacity (0-1). Defaults to 1. */
    opacity?: number;
    /** Whether the animation loops. Defaults to true. */
    loop?: boolean;
}
export interface EmitSceneInput {
    /** Kebab-case scene id; appears in `data-composition-id` and template id. */
    id: string;
    preset: ScenePreset;
    /** Canvas width in px (must match the root composition). */
    width: number;
    /** Canvas height in px (must match the root composition). */
    height: number;
    /** Visible composition duration in seconds. */
    duration: number;
    /** Headline text — required for non-simple presets; defaulted from id. */
    headline?: string;
    /** Secondary text (subhead/caption). Often the narration. */
    subhead?: string;
    /** Optional small label above the headline (explainer / product-shot). */
    kicker?: string;
    /** Project-relative image path (e.g. "assets/scene-intro.png"). */
    imagePath?: string;
    /** Project-relative narration audio path (e.g. "assets/narration-intro.mp3"). */
    audioPath?: string;
    /**
     * Word-level timings (Whisper output) for narration sync. When supplied, the
     * `simple`, `explainer`, and `kinetic-type` presets render each word as its
     * own `<span class="word">` and animate them at their absolute audio start
     * times via GSAP. `announcement` and `product-shot` ignore this field —
     * their headlines are intentionally static.
     */
    transcript?: SceneTranscriptWord[];
    /**
     * Optional Lottie animation overlay. When supplied, a `<dotlottie-wc>`
     * element is layered on top of the preset's content. Uses the same
     * position/scale/opacity vocabulary as `vibe edit motion-overlay`.
     */
    lottie?: LottieOverlayInput;
}
/**
 * Slugify a free-form scene name to a kebab-case id usable in HTML attributes
 * and filenames. Strips diacritics, collapses whitespace, lowercases.
 */
export declare function slugifySceneName(name: string): string;
/**
 * Render a transcript as `<span class="word" data-i="N">…</span>` markup,
 * separated by literal whitespace so kerning and wrapping behave naturally.
 * Returns the empty string when there's nothing to render.
 */
export declare function renderTranscriptSpans(transcript: SceneTranscriptWord[]): string;
/**
 * Build absolute-timing GSAP tweens that fade each transcript word in at its
 * narration `start` time. The `targetSelector` parametrises the scope so the
 * same routine can drive `simple` (`.caption .word`), `explainer`
 * (`#subtitle .word`), or `kinetic-type` (`.kinetic .word`).
 *
 * Each tween is `tl.fromTo(sel, {opacity:0,y:10}, {opacity:1,y:0,duration:0.18}, start)`
 * — short enough to feel responsive at any speech rate, long enough to avoid
 * popping at 30fps. Words clamp to non-negative starts.
 */
export declare function buildTranscriptTweens(transcript: SceneTranscriptWord[], targetSelector: string): string;
/**
 * Length of the scope opacity fade-in / fade-out applied at every scene's
 * boundaries. When two adjacent clips overlap by this amount in the parent
 * timeline (`scene.ts` and `segments-to-scenes.ts` lay them out that way),
 * the outgoing scene's last `SCENE_OVERLAP_SECONDS` fades to opacity 0
 * while the incoming scene's first `SCENE_OVERLAP_SECONDS` fades from 0,
 * yielding a smooth crossfade instead of the hard cut the previous
 * architecture produced.
 *
 * Tuned at 0.4 s — long enough that the eye perceives a soft transition,
 * short enough that the text content of the next scene is fully present
 * by the time the entrance animation finishes (entrance starts at 0.05 s).
 */
export declare const SCENE_OVERLAP_SECONDS = 0.4;
/**
 * Emit the full per-scene HTML. Returns a complete `<template>`-wrapped
 * composition ready to write to `compositions/scene-<id>.html`.
 */
export declare function emitSceneHtml(input: EmitSceneInput): string;
/**
 * Sum existing `<div class="clip">` end-times to find where the next scene
 * should start. Returns 0 for an empty root.
 *
 * `overlap` (default 0) is subtracted from the max end-time so callers can
 * place the new clip to overlap with the previous one — used by the
 * crossfade architecture (`vibe scene add` and `segments-to-scenes.ts`
 * pass `SCENE_OVERLAP_SECONDS` here so each new scene's first
 * `SCENE_OVERLAP_SECONDS` blend with the previous scene's last).
 */
export declare function nextSceneStart(rootHtml: string, overlap?: number): number;
export interface ClipReferenceInput {
    /** Scene id — used to derive the composition src path. */
    id: string;
    start: number;
    duration: number;
    trackIndex?: number;
    /** Override the default `compositions/scene-<id>.html` src. */
    src?: string;
}
/** Build the `<div class="clip" data-composition-id=... data-composition-src=...>` reference string. */
export declare function buildClipReference(opts: ClipReferenceInput): string;
/**
 * Insert a clip reference inside the root composition's `#root` div, just
 * before its closing `</div>`. Throws if the expected closing tag isn't
 * found — callers should surface this as a structured error so users know
 * to inspect a hand-edited root.
 *
 * Also grows the root's `data-duration` to fit the new clip's end-time.
 */
export declare function insertClipIntoRoot(rootHtml: string, clip: ClipReferenceInput): string;
/**
 * Read the root composition's canvas dims by parsing `data-width`/`data-height`
 * on the `#root` div. Returns null if either is missing — caller should fall
 * back to the project's aspect config.
 */
export declare function readRootDims(rootHtml: string): {
    width: number;
    height: number;
} | null;
