Playback clock hook that advances through pre-built `StreamFrame` arrays like a live stream, holding each frame for its configured delay before revealing the next, then parking on the final frame. ## Key Components - **`useScriptedStream(frames, resetKey, enabled)`** — Core hook. Returns the currently active `StreamFrame` based on elapsed playback. - `frames` — Ordered array of `StreamFrame` objects (built externally via `buildStreamFrames`). - `resetKey` — Restarts playback from frame 0 on identity change (new conversation). Preserves index when the same conversation grows (e.g. an appended continuation resumes seamlessly). - `enabled` — When `false`, skips to the final frame immediately. - **`EMPTY_FRAME`** — Sentinel idle frame returned when no frames are available. - **`prefersReducedMotion()`** — Detects `prefers-reduced-motion: reduce` media query; bypasses animation and jumps straight to the last frame. ## Behavior Details | Condition | Result | |---|---| | `enabled === false` or reduced motion | Jumps to last frame immediately | | `frames` grows mid-playback | Effect re-runs, resumes from current index into new frames | | `frames` shrinks before reset lands | Index is clamped to prevent out-of-bounds access | | `frames.length === 0` | Returns `EMPTY_FRAME` | ## Usage Example ```typescript import { useScriptedStream } from './use-scripted-stream' import { buildStreamFrames } from '../utils/scripted-stream' function ChatPreview({ conversation }: { conversation: Conversation }) { const frames = buildStreamFrames(conversation.messages) // resetKey changes when a new conversation is selected const frame = useScriptedStream(frames, conversation.id) return ( ) } ``` ## Source [`use-scripted-stream.ts`](https://github.com/flamingo-stack/openframe-oss-lib/blob/main/use-scripted-stream.ts)