eldouma-graphics / src /lib /screencast.ts
Moeeldouma's picture
Sync export fidelity fixes + more AI providers
2cd103d verified
Raw
History Blame Contribute Delete
4.03 kB
// ─────────────────────────────────────────────────────────────────────────────
// 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 }