// ───────────────────────────────────────────────────────────────────────────── // Screencast capture data model — the metadata track that rides alongside a screen // recording so the editor can render a polished "explainer" camera (auto zoom/pan, // cursor, click ripples) over the raw footage, Screen-Studio style. // // ALL coordinates are normalized 0..1 fractions of the recorded FRAME (x = fraction // of width, y = fraction of height). That makes everything resolution-independent: // the same data drives a 720p preview and a 4K export identically. // // ALL times are SOURCE-time in milliseconds — time measured from the start of the // source recording, NOT the timeline. The renderer adds the clip's sourceInMs, so // trimming the clip keeps the camera locked to the right moment. // ───────────────────────────────────────────────────────────────────────────── // One cursor sample. Captured ~30–60Hz during recording, then smoothed. export interface ScreencastPoint { t: number; // source-time ms x: number; // 0..1 fraction of frame width y: number; // 0..1 fraction of frame height } // A click/press event. Carries the target element's bounding rect + label when the // recording is of THIS web app (same DOM) — that's what enables element-perfect // framing instead of point-guessing. export interface ScreencastClick { t: number; // source-time ms x: number; y: number; // click point, 0..1 of frame kind?: "click" | "dblclick" | "contextmenu"; // default "click" rect?: ScreencastRect; // target element's bounds (0..1), if known label?: string; // human label for the target (aria-label / text / tag), if known } // A normalized rectangle (0..1 fractions of the frame). export interface ScreencastRect { x: number; y: number; w: number; h: number } // One camera keyframe. The camera reaches state {z, focus} at time t, easing in // from the previous keyframe with `ease`. autoZoom() emits these; the user can edit. export interface ScreencastZoomKey { t: number; // source-time ms when this state is reached z: number; // zoom level (1 = full frame; 1.5–2.2 typical) x: number; y: number; // focus point, 0..1 of frame (camera centers here when it can) ease?: ScreencastEase; // transition feel INTO this keyframe (default "drift") } // Camera transition curves (map to motion.ts EASE presets in the renderer). export type ScreencastEase = "drift" | "cine" | "backOut" | "snap" | "linear"; // The full metadata bundle stored on a VideoItem (VideoItem.screencast). export interface ScreencastData { cursor?: ScreencastPoint[]; // smoothed cursor track (for the cursor sprite + pan hints) clicks?: ScreencastClick[]; // click events (for ripples + auto-zoom triggers) cam?: ScreencastZoomKey[]; // the camera track — autoZoom output, user-editable fps?: number; // capture frame rate (informational) source?: "tab" | "window" | "screen"; // what getDisplayMedia captured (informational) drawCursor?: boolean; // render the animated cursor sprite (true when the OS cursor was suppressed at capture; false = keep the real recorded cursor). default true camScale?: number; // AUTO-ZOOM INTENSITY 0..1 applied over the baked `cam` at render time (1 = full baked zoom, 0.5 = half, 0 = OFF/no zoom → shows the whole recording). Lets the user dial back an over-zoomed camera without re-capturing. default 1 } // Resolved camera state at an instant: zoom + a translate (fractions of frame) so a // content point c maps to screen point c*z + t (origin top-left). See screencastZoom. export interface CameraState { z: number; tx: number; ty: number; fx: number; fy: number }