/**
 * Engine Configuration
 *
 * Typed configuration for the rendering pipeline. Replaces the PRODUCER_*
 * env var sprawl with a structured interface. Env vars still work as
 * fallbacks for backward compatibility during migration.
 */
/**
 * Full engine configuration. All fields are wired through the config
 * object; env vars serve as backward-compatible fallbacks resolved
 * in `resolveConfig()`.
 */
export interface EngineConfig {
    fps: 24 | 30 | 60;
    quality: "draft" | "standard" | "high";
    format: "jpeg" | "png";
    jpegQuality: number;
    /** Max worker count. "auto" uses CPU-based heuristic. */
    concurrency: number | "auto";
    /** CPU cores allocated per worker. */
    coresPerWorker: number;
    /** Minimum frames before parallel workers are used. */
    minParallelFrames: number;
    /** Frame count threshold for "large render" heuristics. */
    largeRenderThreshold: number;
    chromePath?: string;
    disableGpu: boolean;
    /**
     * Chrome/WebGL rendering backend.
     * - "software": SwiftShader (CPU-only). Always works; ~5-50× slower than GPU.
     * - "hardware": host GPU via platform-native ANGLE backend (Metal/D3D11/EGL).
     *   Errors if no usable GPU is reachable from Chrome.
     * - "auto": probe Chrome for WebGL availability on first launch in this
     *   process; fall back to software if hardware-mode WebGL is unavailable.
     *   Cost: one extra Chrome launch (~1-2 s) per process; result cached.
     */
    browserGpuMode: "software" | "hardware" | "auto";
    enableBrowserPool: boolean;
    browserTimeout: number;
    protocolTimeout: number;
    /** Expected Chromium major version (optional validation). */
    expectedChromiumMajor?: number;
    /** Force screenshot capture mode (skip BeginFrame even on Linux). */
    forceScreenshot: boolean;
    /**
     * Static-frame dedup: reuse byte-identical frames instead of re-seeking +
     * re-screenshotting (anchor-verified at init). Default ON; disable via
     * `HF_STATIC_DEDUP` in {false,0,off}. Only arms in screenshot capture mode.
     */
    staticFrameDedup: boolean;
    /**
     * Use drawElementImage for frame capture (requires the CanvasDrawElement
     * Chrome flag, added globally in buildChromeArgs). Default ON, clamped in
     * `resolveConfig` to hosts where it can actually engage (macOS or Windows +
     * hardware-GPU browser); compile/init gates and the runtime self-verification net route
     * incompatible or damaged renders back to screenshot capture.
     * Kill switch: `PRODUCER_EXPERIMENTAL_FAST_CAPTURE=false` (or the CLI
     * `--experimental-fast-capture=false`).
     */
    useDrawElement: boolean;
    /**
     * Pipeline JPEG encode into an in-page OffscreenCanvas Worker for the
     * drawElement fast-capture path (macOS hardware GPU only). The worker
     * encodes frame N while the main thread seeks+paints frame N+1
     * (~1.65–1.96× wall-time speedup). No-op unless `useDrawElement` is also
     * true. Kill switch: `HF_DE_WORKER_ENCODE=false`.
     */
    enableDrawElementWorkerEncode: boolean;
    /**
     * INTERNAL. Set by resolveConfig when it disabled enablePageSideCompositing
     * solely because drawElement was on. Lets the producer's compile-time gates
     * restore page-side compositing without overriding an explicit caller/env
     * opt-out. Not intended to be set by callers.
     */
    pageSideCompositingAutoDisabled?: boolean;
    /**
     * INTERNAL. Set to `true` by `resolveConfig` when the caller explicitly
     * opted out of the software-GPU→screenshot clamp — either via env
     * `PRODUCER_FORCE_SCREENSHOT=false` or programmatic
     * `overrides.forceScreenshot === false`. The concrete-resolved-GPU helper
     * (`shouldClampToScreenshotForConcreteGpu`) reads this so the
     * `browserGpuMode:"auto"` → software probe path preserves the same
     * escape hatch as literal `browserGpuMode:"software"` (the boolean
     * `forceScreenshot === false` at that point is otherwise ambiguous —
     * default vs explicit opt-out — because the config resolves before
     * the runtime probe fires). Not intended to be set by callers.
     */
    forceScreenshotExplicitlyOptedOut?: boolean;
    /**
     * Low-memory render profile. When `true`, the orchestrator collapses the
     * pipeline to its cheapest shape on memory-constrained hosts: it skips the
     * throwaway auto-worker calibration browser, pins capture to a single
     * worker (unless the user passed an explicit `--workers`), and prefers
     * screenshot capture over BeginFrame. Resolved automatically from total
     * RAM (`isLowMemorySystem()`); force on/off via `PRODUCER_LOW_MEMORY_MODE`
     * or the `--low-memory-mode` CLI flag.
     */
    lowMemoryMode: boolean;
    /**
     * Opt-in: page-side shader-transition compositing.
     *
     * When `true`, shader transitions for SDR compositions run their blend
     * inside Chrome via WebGL on a page-side compositor canvas instead of
     * Node-side per-pixel blending (the hf#677 layered pipeline). The engine
     * then captures ONE opaque RGB frame per output frame via the streaming
     * capture path, skipping per-scene transparent screenshots and the
     * Node-side shader-blend worker pool entirely.
     *
     * The feature stacks on top of the hf#677 chain — it does not undo it.
     * When this flag is OFF (the default), behaviour is byte-identical to the
     * current path. When ON and the composition has no shader transitions or
     * has HDR content (which forces the layered path regardless), this flag
     * is a no-op.
     *
     * Mac viability: Chrome on Mac accelerates page-side WebGL canvases via
     * Metal/CoreAnimation natively. This is the lever for Mac users who
     * cannot use `--enable-begin-frame-control` (Chromium structural limit,
     * crbug.com/40656275).
     *
     * Determinism: page-side WebGL is f32, not f64. Byte-equality fixture
     * pins are NOT compatible with this path; the new path's correctness
     * pin is PSNR-based. Default OFF preserves the existing pins for the
     * hf#677 chain.
     *
     * Env fallback: `HF_PAGE_SIDE_COMPOSITING=true`.
     */
    enablePageSideCompositing: boolean;
    /**
     * libvpx-vp9 speed/quality tradeoff. Higher values encode faster with a
     * larger quality/size tradeoff. FFmpeg accepts integer values from -8 to 8.
     */
    vp9CpuUsed: number;
    enableChunkedEncode: boolean;
    chunkSizeFrames: number;
    enableStreamingEncode: boolean;
    /**
     * INTERNAL. Set by `resolveConfig` when the Windows software-GPU compound
     * heuristic (`shouldAutoDisableStreamingEncodeOnWin32Compound`) turned
     * `enableStreamingEncode` off on the caller's behalf. Not intended to be
     * set by callers; surfaces the auto-decision for downstream observability
     * (log lines, telemetry) so operators can tell an auto-disable apart from
     * an explicit user opt-out.
     */
    streamingEncodeAutoDisabledOnWin32Compound?: boolean;
    /**
     * Max composition duration eligible for streaming encode (seconds).
     * Mirrors GSAP rendering's 4-minute streaming guard: production has seen
     * ffmpeg's streaming pipe hit FFMPEG_STREAMING_TIMEOUT_MS on longer videos.
     */
    streamingEncodeMaxDurationSeconds: number;
    /** Timeout for FFmpeg frame encoding (ms). Default: 600_000 */
    ffmpegEncodeTimeout: number;
    /** Timeout for FFmpeg mux/faststart processes (ms). Default: 300_000 */
    ffmpegProcessTimeout: number;
    /**
     * Inactivity timeout for FFmpeg streaming encode (ms). The timer resets on
     * every successful `writeFrame` call, so this caps the duration of a
     * single "no frame arrived" gap (capture hang, dead Chrome), not the total
     * render time. Default: 600_000 (10 minutes without any frame = dead).
     */
    ffmpegStreamingTimeout: number;
    /** HDR output transfer function. false = SDR output (default). */
    hdr: {
        transfer: "hlg" | "pq";
    } | false;
    /** Auto-detect HDR from video sources when hdr is not explicitly set. */
    hdrAutoDetect: boolean;
    audioGain: number;
    /**
     * Hard upper bound on entries kept in the video frame data URI cache.
     * Acts as a sanity cap; the byte budget below normally fires first on
     * high-resolution renders. At 1080p with ~6 MB per JPEG frame the default
     * 256 entries fit inside ~1.5 GB. At 4K the byte budget evicts long
     * before this cap is reached.
     */
    frameDataUriCacheLimit: number;
    /**
     * Memory budget for the cache, in megabytes. Eviction kicks in once the
     * sum of cached data-URI string lengths exceeds this. Sized so a worker
     * stays comfortably under a few GB even at 4K (where each PNG frame is
     * ~25 MB and the base64 data URI is ~33 MB).
     */
    frameDataUriCacheBytesLimitMb: number;
    playerReadyTimeout: number;
    renderReadyTimeout: number;
    /**
     * Puppeteer `page.goto()` navigation timeout for the entry HTML, in ms.
     * The browser must reach `domcontentloaded` within this budget — heavy
     * compositions (many videos, large fonts, hundreds of asset requests)
     * can blow past the default 60s on cold cache. Default: 60_000.
     *
     * Env fallback: `PRODUCER_PAGE_NAVIGATION_TIMEOUT_MS`.
     * CLI flag: `--browser-timeout <seconds>`.
     */
    pageNavigationTimeout: number;
    /** Verify Hyperframe runtime SHA256 checksums. */
    verifyRuntime: boolean;
    /** Custom manifest path for Hyperframe runtime. */
    runtimeManifestPath?: string;
    /**
     * Directory where the content-addressed extraction cache persists frame
     * bundles keyed on (path, mtime, size, mediaStart, duration, fps, format).
     * Defaults on under the OS temp directory:
     * `<tmpdir>/hyperframes-extract-cache-<uid>`.
     *
     * New entries publish atomically: frames are extracted into a unique
     * partial directory, the `.hf-complete` sentinel is written there, and the
     * partial directory is renamed into the final key directory. Concurrent
     * renders against the same cache are safe; at worst, two renders duplicate
     * ffmpeg work and one rehydrates from the winner.
     *
     * Set `HYPERFRAMES_EXTRACT_CACHE_DIR` to a path to override the default, or
     * to `off`, `none`, `false`, or `0` to disable caching for the process.
     * When disabled, extraction runs into the render's workDir and cleanup
     * removes it when the render ends, preserving the pre-cache behaviour.
     *
     * **Network filesystems.** `mtime` resolution on NFS/SMB mounts can be
     * coarser than expected (seconds rather than nanoseconds), which may
     * produce spurious cache hits if a source file is overwritten within the
     * same mtime tick. Local filesystems are the intended deployment target.
     *
     * Env fallback: `HYPERFRAMES_EXTRACT_CACHE_DIR`.
     */
    extractCacheDir?: string;
    /**
     * Soft disk budget for `extractCacheDir`, in bytes. The renderer runs a
     * best-effort LRU sweep after extraction and evicts oldest sentineled
     * entries until the cache is under this cap, while protecting young entries
     * that may belong to live renders.
     *
     * Env fallback: `HYPERFRAMES_EXTRACT_CACHE_MAX_MB` (megabytes).
     */
    extractCacheMaxBytes: number;
    debug: boolean;
}
/** Default configuration — sensible for Hyperframes compositions. */
export declare const DEFAULT_CONFIG: EngineConfig;
/**
 * Validate a complete EngineConfig crossing a JSON wire boundary.
 *
 * `resolveConfig()` intentionally accepts partial programmatic overrides, but
 * a serialized render request stores a resolved snapshot. Accepting a partial
 * snapshot would skip the orchestrator's `resolveConfig()` fallback entirely.
 */
export declare function validateEngineConfigSnapshot(value: unknown): asserts value is EngineConfig;
/**
 * Scale a base `protocolTimeout` up for oversized compositions.
 *
 * Scales by output pixel area (`width*height / reference`) — where width/height
 * are the *device-scaled output* dimensions (the pixels a single CDP call
 * actually renders/serializes), not the CSS composition size. Clamped to
 * `[baseTimeout, max(baseTimeout, MAX_SCALED_PROTOCOL_TIMEOUT_MS)]`: never
 * scales DOWN (a small composition — or a base already above the ceiling —
 * keeps the configured base), and only ever raises. Pure function; exported
 * for tests.
 */
export declare function scaleProtocolTimeoutForComposition(baseTimeoutMs: number, dims: {
    width: number;
    height: number;
}): number;
/**
 * Auto-disable `enableStreamingEncode` on Windows software-GPU compound.
 *
 * Field signal (`ts=1784131903`, win32/x64, CLI 0.7.58, 156s UI-heavy
 * composition): the render was stable ONLY with FOUR flags together —
 * `--workers 1 --no-browser-gpu --low-memory-mode` + explicit
 * `PRODUCER_ENABLE_STREAMING_ENCODE=false`. Every recent Windows-related
 * fix (#2359, #2245, #2298, #2331) already shipped in 0.7.58; the residual
 * failure is screenshot streaming-encode via CDP `Page.captureScreenshot`
 * on Windows even after software fallback. Since `--low-memory-mode` and
 * `--no-browser-gpu` already imply screenshot capture, three of the four
 * flags are structurally coupled — auto-detect the compound and disable
 * streaming-encode automatically so callers don't have to memorize the
 * four-flag combination.
 *
 * Conservative gates (all must hold):
 *   1. `platform === "win32"` — the failure is Windows-specific to CDP's
 *      screenshot streaming path.
 *   2. `softwareGpuForced` — the render is already on the SwiftShader /
 *      forced-screenshot path (from `--no-browser-gpu`, `disableGpu`, or
 *      `--low-memory-mode` implying screenshot capture).
 *   3. `workers === 1` — the field signal reproduces on single-worker
 *      captures; parallel workers have a different failure surface
 *      (missing media frames) already handled by the worker-count route.
 *   4. Composition duration >120s WHEN KNOWN. When unknown at the config
 *      layer (composition duration is parsed downstream), the guard
 *      reduces to the three-condition compound. Trade-off documented in
 *      the PR body: false positives possible for short (~<120s) Windows
 *      software-GPU single-worker renders. Mitigation: the explicit
 *      opt-in escape hatch (`PRODUCER_ENABLE_STREAMING_ENCODE=true` or
 *      `overrides.enableStreamingEncode !== undefined`) always wins.
 *
 * Pure function; exported for tests.
 */
export declare function shouldAutoDisableStreamingEncodeOnWin32Compound(opts: {
    platform: NodeJS.Platform;
    softwareGpuForced: boolean;
    workers: number;
    compositionDurationSec: number | undefined;
    userExplicitlySet: boolean;
}): boolean;
/**
 * Result of resolving the extract cache directory from the env, decoupled from
 * the wider {@link resolveConfig} pipeline so `hyperframes doctor` (and any
 * other diagnostic surface) can report the exact same effective value the
 * renderer will use — including whether the user has explicitly disabled the
 * cache via `off`/`none`/`false`/`0`.
 *
 * - `dir: string` + `disabled: false`  → renderer will use this directory.
 *   `source` reports whether the value came from the env or the OS default.
 * - `dir: undefined` + `disabled: true` → user explicitly turned caching off;
 *   frames extract into the per-render workDir (auto-cleaned when the render
 *   ends). `rawValue` carries the exact string the user set.
 */
export type ExtractCacheDirResolution = {
    dir: string;
    disabled: false;
    source: "env" | "default";
    rawValue?: string;
} | {
    dir: undefined;
    disabled: true;
    source: "env";
    rawValue: string;
};
/**
 * Env-var values that disable the extract cache entirely. Case-insensitive;
 * whitespace-trimmed. Kept as an exported constant so the CLI can echo the
 * accepted alias set in `--frames-cache-dir` help text without drift.
 */
export declare const EXTRACT_CACHE_DIR_DISABLED_ALIASES: readonly string[];
/**
 * Compute the default extract-cache directory when the user has NOT set
 * `HYPERFRAMES_EXTRACT_CACHE_DIR`. Exported so downstream tests can reproduce
 * the exact path without duplicating the uid-suffix idiom.
 */
export declare function defaultExtractCacheDir(): string;
/**
 * Resolve the extract-cache directory from an environment (defaults to
 * `process.env`). Mirrors the internal helper used by {@link resolveConfig},
 * but returns a rich resolution object so callers can distinguish "disabled by
 * user" from "default location" without re-parsing the env value.
 *
 * See {@link ExtractCacheDirResolution} for the shape and its two states.
 */
export declare function resolveExtractCacheDir(env?: Record<string, string | undefined>): ExtractCacheDirResolution;
/**
 * Default-on drawElement host clamp. An explicit opt-in always wins (attempt
 * DE, let the init-time gates route away — debugging relies on it). Otherwise
 * DE stays on only where it can actually engage — a supported platform with a
 * non-software-GPU browser — AND with worker-encode enabled: the runtime
 * self-verification net lives in the worker-encode drain (the serial path has
 * only the blank guard), so a default-on session without it would ship
 * unverified drawElement frames. Pure; exported for tests.
 */
export declare function resolveDefaultDrawElement(args: {
    useDrawElement: boolean;
    explicitOptIn: boolean;
    platform: NodeJS.Platform;
    browserGpuMode: EngineConfig["browserGpuMode"];
    workerEncode: boolean;
}): boolean;
/**
 * Why {@link resolveDefaultDrawElement} said no. Call ONLY when the resolved
 * `useDrawElement` is false — the branches mirror that resolver's, in order.
 *
 * Every branch there returns a bare `false` and records nothing, so a render
 * that never became a drawElement candidate reaches telemetry with no
 * `de_compile_gate`, no `de_clamp_reason` and no `de_gate_reason`. Those land
 * in the "Why not drawElement" dashboard's catch-all `other` bucket, which
 * measured 56,507 renders over 14 days — its second-largest bar, explaining
 * nothing. The orchestrator's own clamp only fires while `useDrawElement` is
 * still true, so it cannot cover a config-time refusal by construction.
 *
 * Takes only the environmental inputs on purpose: the caller holds the
 * POST-resolution `useDrawElement`, from which the pre-resolution request is
 * no longer recoverable. So "none of these three explain it" is itself the
 * answer — the feature was switched off explicitly.
 *
 * Kept separate from the resolver rather than widening its return type: it sits
 * on the config hot path and several call sites want a plain boolean. Mirror
 * any branch change in both.
 */
export declare function explainDrawElementDisabled(args: {
    platform: NodeJS.Platform;
    browserGpuMode: EngineConfig["browserGpuMode"];
    workerEncode: boolean;
}): "unsupported_platform" | "software_gpu" | "worker_encode_off" | "disabled";
export declare function resolveConfig(overrides?: Partial<EngineConfig>): EngineConfig;
/**
 * Runtime-resolved companion to the software-GPU screenshot clamp in
 * `resolveConfig`. Returns `true` iff callers should treat this render as
 * `forceScreenshot=true` even though the config's stored `forceScreenshot`
 * is `false`. Fires when the concrete resolved GPU is software AND neither
 * the env opt-out (`PRODUCER_FORCE_SCREENSHOT=false`) nor the programmatic
 * opt-out (`overrides.forceScreenshot === false`, carried via
 * `cfg.forceScreenshotExplicitlyOptedOut`) is set.
 *
 * `resolveConfig`'s clamp only sees `browserGpuMode` as a string, so
 * `"auto"` that runtime-probes to software slips through. This helper
 * closes that gap at the concrete-resolution points (`frameCapture` and
 * `renderOrchestrator`). Same invariant, same escape hatches, one predicate.
 *
 * Callers should skip when the invariant is already satisfied
 * (`currentForceScreenshot === true`) to avoid redundant work. Pass
 * `cfg.forceScreenshotExplicitlyOptedOut` via `opts.programmaticOptOut` so
 * the `browserGpuMode:"auto"` → software probe path honors the same
 * programmatic escape hatch as literal `browserGpuMode:"software"`.
 */
export declare function shouldClampToScreenshotForConcreteGpu(resolvedGpuMode: "software" | "hardware", currentForceScreenshot: boolean, env?: NodeJS.ProcessEnv, opts?: {
    programmaticOptOut?: boolean;
}): boolean;
/**
 * Caller-facing pair to `shouldClampToScreenshotForConcreteGpu`: computes the
 * value the *authoritative* `forceScreenshot` local should hold after the
 * concrete-resolved-GPU decision fires. Returns the (possibly-promoted) new
 * boolean, so the caller can assign it back to its local — driving both
 * routing AND telemetry from one source of truth.
 *
 * Reads the programmatic opt-out from `cfg.forceScreenshotExplicitlyOptedOut`
 * (set by `resolveConfig` when EITHER env `PRODUCER_FORCE_SCREENSHOT=false`
 * OR programmatic `overrides.forceScreenshot === false` was present).
 *
 * Idempotent: `applyConcreteGpuScreenshotClamp(true, ...)` returns `true`
 * without consulting anything else.
 */
export declare function applyConcreteGpuScreenshotClamp(currentForceScreenshot: boolean, resolvedGpuMode: "software" | "hardware", cfg: Pick<EngineConfig, "forceScreenshotExplicitlyOptedOut"> | undefined, env?: NodeJS.ProcessEnv): boolean;
//# sourceMappingURL=config.d.ts.map