export type StoryPlaybackPhase = 'timer' | 'narration' | 'media' | null; export type StoryPlaybackState = { currentTime: number; duration: number; playState: 'playing' | 'paused' | 'idle'; isBuffering: boolean; phase: StoryPlaybackPhase; }; type PlaybackClockDeps = { now?: () => number; setIntervalFn?: typeof setInterval; clearIntervalFn?: typeof clearInterval; tickMs?: number; }; type TimerPhaseConfig = { kind: 'timer'; offsetSec?: number; durationSec: number; onComplete?: () => void; }; type ExternalPhaseConfig = { kind: 'narration' | 'media'; offsetSec?: number; durationSec: number; sourceStartSec: number; getCurrentTime: () => number | null | undefined; onComplete?: () => void; }; type StateListener = (state: StoryPlaybackState) => void; export declare class StoryPlaybackClock { state: StoryPlaybackState; private readonly now; private readonly setIntervalFn; private readonly clearIntervalFn; private readonly tickMs; private timerId; private phase; private phaseStartedAtMs; private phaseElapsedAtStartSec; private listeners; constructor(deps?: PlaybackClockDeps); getState(): StoryPlaybackState; /** * Returns the current presentation time recomputed from the wall clock at the * moment of the call, without mutating state or notifying listeners. The * ticking loop only updates `state.currentTime` ~20×/s; a render loop can call * this every animation frame to drive the camera at the display refresh rate. */ getLiveCurrentTime(): number; subscribe(listener: StateListener): () => void; destroy(): void; loadChapter(durationSec: number): void; setBuffering(isBuffering: boolean): void; startTimerPhase(config: Omit): void; startNarrationPhase(config: Omit): void; startMediaPhase(config: Omit): void; play(): void; pause(): void; stop(): void; private setPhase; private startTickLoop; private stopTickLoop; private tick; private computePhaseElapsedSec; private applyState; } export declare const createStoryPlaybackClock: (deps?: PlaybackClockDeps) => StoryPlaybackClock; export {};